From eaf4c90cabdde01f9e640b834c54e3e05b0d71af Mon Sep 17 00:00:00 2001 From: jwinterm Date: Mon, 5 Oct 2026 19:33:04 -0400 Subject: [PATCH] fix(auth): sign in against the v0.3 backend v0.3 wallets register with the v0.3 backend, so a site built against the legacy backend answered every v0.3 sign-in with "User not found". The v0.3 backend resolves website sign-in by each coin's own key and adopts a legacy identity on first proof, so it serves both generations. The v0.3 backend has no social linking. Settings now loads linked accounts separately and hides that section when they are unavailable, instead of failing the whole page and taking username editing with it. The public user count and stats may come from a separate backend via NEXT_PUBLIC_STATS_API_URL; unset keeps today's behavior. --- .env.local.example | 4 + src/app/settings/page.tsx | 267 ++++++++++++++++++++------------------ src/lib/api.ts | 7 +- 3 files changed, 152 insertions(+), 126 deletions(-) diff --git a/.env.local.example b/.env.local.example index b21bb54..8dde6a9 100644 --- a/.env.local.example +++ b/.env.local.example @@ -2,3 +2,7 @@ # For local development: http://localhost:8080 # For production: https://api.smirk.cash (or your backend URL) NEXT_PUBLIC_API_URL=http://localhost:8080 + +# Optional: backend serving the public user count and stats, when it differs +# from the sign-in backend above. Unset means the same backend. +# NEXT_PUBLIC_STATS_API_URL=https://backend.smirk.cash diff --git a/src/app/settings/page.tsx b/src/app/settings/page.tsx index eb008ec..b4e8ab5 100644 --- a/src/app/settings/page.tsx +++ b/src/app/settings/page.tsx @@ -21,6 +21,7 @@ type LinkStep = 'idle' | 'linking' | 'waiting'; export default function SettingsPage() { const [user, setUser] = useState(null); const [socials, setSocials] = useState([]); + const [socialsAvailable, setSocialsAvailable] = useState(true); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -81,10 +82,16 @@ export default function SettingsPage() { return; } - Promise.all([getMe(token), getLinkedSocials(token), getMyUsername(token)]) - .then(([userData, socialsData, username]) => { + // Linked accounts are a legacy-backend feature; the v0.3 backend has no + // social linking. Load them separately so their absence hides that section + // instead of failing the whole page. + getLinkedSocials(token) + .then((socialsData) => setSocials(socialsData.socials)) + .catch(() => setSocialsAvailable(false)); + + Promise.all([getMe(token), getMyUsername(token)]) + .then(([userData, username]) => { setUser(userData); - setSocials(socialsData.socials); setSmirkUsername(username || ''); setUsernameInput(username || ''); }) @@ -320,139 +327,151 @@ export default function SettingsPage() {

Linked Accounts

- {/* Telegram */} -
-
-
-
- - - -
-
-

Telegram

+ {socialsAvailable ? ( + <> + {/* Telegram */} +
+
+
+
+ + + +
+
+

Telegram

+ {telegramSocial?.verified ? ( +

+ {telegramSocial.username ? `@${telegramSocial.username}` : telegramSocial.display_name || 'Linked'} +

+ ) : telegramSocial?.pending_verification ? ( +

Verification pending

+ ) : ( +

Not linked

+ )} +
+
+ {telegramSocial?.verified ? ( -

- {telegramSocial.username ? `@${telegramSocial.username}` : telegramSocial.display_name || 'Linked'} + + ) : linkStep === 'idle' ? ( + + ) : null} +

+ + {/* Link flow UI */} + {linkStep === 'linking' && ( +
+
+
+ Setting up link... +
+
+ )} + + {linkStep === 'waiting' && deepLink && ( +
+

+ Click the button below to open Telegram and link your account automatically:

- ) : telegramSocial?.pending_verification ? ( -

Verification pending

- ) : ( -

Not linked

- )} -
+ +
+ + + + + Open Telegram + + +
+ +
+
+ Waiting for verification... +
+ + {linkError &&

{linkError}

} +
+ )}
- {telegramSocial?.verified ? ( - - ) : linkStep === 'idle' ? ( - - ) : null} -
+ {/* Discord */} +
+
+
+
+ + + +
+
+

Discord

+ {discordSocial?.verified ? ( +

+ {discordSocial.display_name || discordSocial.username || 'Linked'} +

+ ) : discordLinking ? ( +

Linking...

+ ) : ( +

Not linked

+ )} +
+
- {/* Link flow UI */} - {linkStep === 'linking' && ( -
-
-
- Setting up link... -
-
- )} - - {linkStep === 'waiting' && deepLink && ( -
-

- Click the button below to open Telegram and link your account automatically: -

- -
- - - - - Open Telegram - - -
- -
-
- Waiting for verification... -
- - {linkError &&

{linkError}

} -
- )} -
- - {/* Discord */} -
-
-
-
- - - -
-
-

Discord

{discordSocial?.verified ? ( -

- {discordSocial.display_name || discordSocial.username || 'Linked'} -

- ) : discordLinking ? ( -

Linking...

+ ) : ( -

Not linked

+ )}
+ + {discordError && ( +
+

{discordError}

+
+ )}
- {discordSocial?.verified ? ( - - ) : ( - - )} + + ) : ( +
+

+ Linking Telegram and Discord isn't available for this wallet. Your Smirk + username above is how others find and tip you. +

- - {discordError && ( -
-

{discordError}

-
- )} -
+ )} {/* Future platforms */}
diff --git a/src/lib/api.ts b/src/lib/api.ts index afaeaac..f13f4b5 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -1,6 +1,9 @@ // API client for Smirk backend const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000'; +// Public counters (user count, stats) may live on a different backend than +// sign-in. Unset means the same backend. +const STATS_API_URL = process.env.NEXT_PUBLIC_STATS_API_URL || API_URL; export interface ChallengeResponse { challenge: string; @@ -398,7 +401,7 @@ export interface UserCountResponse { } export async function getUserCount(): Promise { - const res = await fetch(`${API_URL}/api/v1/users/count`); + const res = await fetch(`${STATS_API_URL}/api/v1/users/count`); if (!res.ok) { throw new Error('Failed to get user count'); @@ -419,7 +422,7 @@ export interface PublicStats { } export async function getPublicStats(): Promise { - const res = await fetch(`${API_URL}/api/v1/stats/public`); + const res = await fetch(`${STATS_API_URL}/api/v1/stats/public`); if (!res.ok) { throw new Error('Failed to get stats');