aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app.js52
-rw-r--r--src/features/names.js2
-rw-r--r--src/i18n.js8
3 files changed, 61 insertions, 1 deletions
diff --git a/src/app.js b/src/app.js
index 9830800..4eeae3f 100644
--- a/src/app.js
+++ b/src/app.js
@@ -2035,7 +2035,7 @@ function onboardScreen() {
const o = ui.onb;
// steps that were waiting on something advance the moment it exists
if ((o.step === 'nostr' || o.step === 'signin') && ui.screen === 'wallet' && activeAccount()) {
- o.step = 'username';
+ o.step = 'legacy';
o.enterAddr = featureHook('namesAddress') || null;
}
if (o.step === 'username') {
@@ -2049,6 +2049,27 @@ function onboardScreen() {
const page = (kids) => h('div', { class: 'col onb', style: 'gap:20px' }, ...kids);
const title = (txt) => h('h2', { class: 'onb-title' }, txt);
+ if (o.step === 'legacy') {
+ const addr = featureHook('namesAddress');
+ const url = addr
+ ? `https://coinos.io/migrate?to=${encodeURIComponent(addr)}&back=${encodeURIComponent(location.origin + '/')}`
+ : null;
+ return page([
+ title(t('onbLegacyTitle')),
+ h('p', { class: 'muted', style: 'margin:0' }, t('onbLegacyBody')),
+ url
+ ? h('a', {
+ class: 'btn btn-primary btn-block', href: url,
+ style: 'text-align:center;display:block;text-decoration:none;padding:14px',
+ onClick: () => { o.wentToLegacy = true; },
+ }, t('onbLegacyGo'))
+ : h('div', { class: 'row gap6', style: 'align-items:center' },
+ h('span', { class: 'spinner sm' }), h('span', { class: 'small muted' }, t('onbNameWait'))),
+ h('button', { class: 'btn-block', style: 'padding:14px', onClick: () => { o.step = 'username'; render(); } },
+ o.wentToLegacy ? t('onbLegacyDone') : t('onbLegacyNo')),
+ h('button', { class: 'linklike small', onClick: () => { o.step = 'nostr'; render(); } }, t('back')),
+ ]);
+ }
if (o.step === 'welcome') {
return page([
h('div', { class: 'onb-hero' }, brandHeader(false)),
@@ -2153,6 +2174,34 @@ function onboardScreen() {
]);
}
+// Returning from the legacy migration: coinos.io sends ?migrated=<username>
+// once it has swept the balance and released the name. Claim it here — the
+// registrar's "is this a legacy user?" guard now passes.
+function claimMigratedName() {
+ let name = null;
+ try {
+ const u = new URL(location.href);
+ name = u.searchParams.get('migrated');
+ if (name) { u.searchParams.delete('migrated'); history.replaceState(null, '', u.pathname + u.search); }
+ } catch {}
+ if (!name) return;
+ ui.migrating = name;
+ render();
+ let tries = 0;
+ const attempt = () => {
+ featureHook('namesClaimName', name)
+ .then(() => { ui.migrating = null; toast(t('migrateClaimed', { name })); render(); })
+ .catch(() => {
+ // DNS/registrar caches the legacy lookup briefly; give it a minute
+ if (++tries < 12) return setTimeout(attempt, 5000);
+ ui.migrating = null;
+ toast(t('migrateClaimFailed', { name }));
+ render();
+ });
+ };
+ attempt();
+}
+
// ---- the coach-mark tour: three stops, measured against the live DOM ----
const TOUR = [
{ sel: '.header-avatar', key: 'tourAvatar' },
@@ -3450,6 +3499,7 @@ document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') onAppHidden();
else onAppVisible();
});
+window.addEventListener('load', () => setTimeout(() => { if (activeAccount()) claimMigratedName(); }, 1500));
loadLocale(getLang()).finally(() => {
applyBootAutoLogout(); // clear an overdue session before we read it for claim targets
if (featureHook('bootUrl')) return; // a feature consumed the URL (e.g. a gift claim)
diff --git a/src/features/names.js b/src/features/names.js
index 788c944..edc3be1 100644
--- a/src/features/names.js
+++ b/src/features/names.js
@@ -385,6 +385,8 @@ export function namesFeature(ctx) {
namesAddress() { const st = load(); return st.name ? `${st.name}@${st.domain || DOMAIN}` : null; },
// the onboarding wizard renders the same claim form on its username step
namesClaimForm() { return claimForm(true); },
+ // claim a specific name (the migration flow, after coinos.io released it)
+ namesClaimName(name) { return claim(String(name).toLowerCase()); },
stop() { clearTimeout(retryTimer); clearTimeout(deadline); deadline = null; },
receiveModes() {
if (!available()) return [];
diff --git a/src/i18n.js b/src/i18n.js
index e87f097..4474b63 100644
--- a/src/i18n.js
+++ b/src/i18n.js
@@ -493,6 +493,14 @@ const STR = {
onbNostrYes: 'Yes — sign me in',
onbNostrNo: 'No — create my wallet',
onbSigninTitle: 'Sign in with Nostr',
+ onbLegacyTitle: 'Do you have an account on coinos.io?',
+ onbLegacyBody: 'The original coinos. We can move your balance over and bring your username with you — your old account gets renamed and stops receiving.',
+ onbLegacyGo: 'Move my coinos.io account',
+ onbLegacyDone: "I'm done — continue",
+ onbLegacyNo: "No, I'm new here",
+ migrateClaimed: 'Welcome back — {name} is yours here now.',
+ migrateClaimFailed: "Your balance moved, but {name} isn't free yet. Try claiming it in a minute.",
+ migrateWorking: 'Claiming {name}…',
onbNameTitle: 'Claim your username',
onbNameBody: 'Your payment address — people can send you bitcoin with just this.',
onbNameWait: 'Getting things ready…',