feat(ui): one-tap confirm deeplink screen + client language
Add the /confirm/<token> SPA route and Confirm screen: a prefetch-safe button POSTs the token via a new confirmEmailLink RPC (client/transport/mock/codec + ConfirmLinkResult model). A login adopts the minted session and enters the app; a link shows confirmed / merge-in-the-app; an invalid or expired token asks for a new code. Exempt /confirm from the no-session /login redirect. Forward the client locale on the email request (authEmailRequest gains language → app.locale) so a fresh web login email is localised. Handle the new 'profile' live-event sub-kind by re-fetching the profile, so a link confirmed in another browser reflects in-app at once. i18n en+ru.
This commit is contained in:
+22
-1
@@ -31,6 +31,7 @@ import type {
|
||||
Invitation,
|
||||
InvitationInvitee,
|
||||
InvitationSettings,
|
||||
ConfirmLinkResult,
|
||||
LinkResult,
|
||||
MatchResult,
|
||||
MoveRecord,
|
||||
@@ -212,13 +213,15 @@ export function encodeGuestLogin(locale: string, browserTz: string): Uint8Array
|
||||
return finish(b, fb.GuestLoginRequest.endGuestLoginRequest(b));
|
||||
}
|
||||
|
||||
export function encodeEmailRequest(email: string, browserTz: string): Uint8Array {
|
||||
export function encodeEmailRequest(email: string, browserTz: string, language: string): Uint8Array {
|
||||
const b = new Builder(128);
|
||||
const e = b.createString(email);
|
||||
const tz = b.createString(browserTz);
|
||||
const l = b.createString(language);
|
||||
fb.EmailRequestRequest.startEmailRequestRequest(b);
|
||||
fb.EmailRequestRequest.addEmail(b, e);
|
||||
fb.EmailRequestRequest.addBrowserTz(b, tz);
|
||||
fb.EmailRequestRequest.addLanguage(b, l);
|
||||
return finish(b, fb.EmailRequestRequest.endEmailRequestRequest(b));
|
||||
}
|
||||
|
||||
@@ -232,6 +235,14 @@ export function encodeEmailLogin(email: string, code: string): Uint8Array {
|
||||
return finish(b, fb.EmailLoginRequest.endEmailLoginRequest(b));
|
||||
}
|
||||
|
||||
export function encodeEmailConfirmLink(token: string): Uint8Array {
|
||||
const b = new Builder(128);
|
||||
const t = b.createString(token);
|
||||
fb.EmailConfirmLinkRequest.startEmailConfirmLinkRequest(b);
|
||||
fb.EmailConfirmLinkRequest.addToken(b, t);
|
||||
return finish(b, fb.EmailConfirmLinkRequest.endEmailConfirmLinkRequest(b));
|
||||
}
|
||||
|
||||
// --- response decoders ---
|
||||
|
||||
function s(v: string | null): string {
|
||||
@@ -730,6 +741,16 @@ export function decodeLinkResult(buf: Uint8Array): LinkResult {
|
||||
};
|
||||
}
|
||||
|
||||
export function decodeConfirmLinkResult(buf: Uint8Array): ConfirmLinkResult {
|
||||
const r = fb.EmailConfirmLinkResult.getRootAsEmailConfirmLinkResult(new ByteBuffer(buf));
|
||||
const sess = r.session();
|
||||
return {
|
||||
purpose: (s(r.purpose()) || 'link') as ConfirmLinkResult['purpose'],
|
||||
status: (s(r.status()) || 'confirmed') as ConfirmLinkResult['status'],
|
||||
session: sess ? sessionFromTable(sess) : null,
|
||||
};
|
||||
}
|
||||
|
||||
// --- social decoders ---
|
||||
|
||||
function decodeAccountRef(r: fb.AccountRef): AccountRef {
|
||||
|
||||
Reference in New Issue
Block a user