fix: improved discord & signal comms

This commit is contained in:
lewis
2026-02-05 16:13:45 +00:00
committed by Tangled
parent b104dc938a
commit cd7400bc8b
71 changed files with 1596 additions and 514 deletions
@@ -18,16 +18,18 @@
let preferredChannel = $state('email')
let availableCommsChannels = $state<string[]>(['email'])
let telegramBotUsername = $state<string | undefined>(undefined)
let discordBotUsername = $state<string | undefined>(undefined)
let discordAppId = $state<string | undefined>(undefined)
let email = $state('')
let discordId = $state('')
let discordUsername = $state('')
let discordVerified = $state(false)
let telegramUsername = $state('')
let telegramVerified = $state(false)
let signalNumber = $state('')
let signalUsername = $state('')
let signalVerified = $state(false)
let savedDiscordId = $state('')
let savedDiscordUsername = $state('')
let savedTelegramUsername = $state('')
let savedSignalNumber = $state('')
let savedSignalUsername = $state('')
let verifyingChannel = $state<string | null>(null)
let verificationCode = $state('')
let historyLoading = $state(true)
@@ -57,17 +59,19 @@
])
preferredChannel = prefs.preferredChannel
email = prefs.email
discordId = prefs.discordId ?? ''
discordUsername = prefs.discordUsername ?? ''
discordVerified = prefs.discordVerified
telegramUsername = prefs.telegramUsername ?? ''
telegramVerified = prefs.telegramVerified
signalNumber = prefs.signalNumber ?? ''
signalUsername = prefs.signalUsername ?? ''
signalVerified = prefs.signalVerified
savedDiscordId = discordId
savedDiscordUsername = discordUsername
savedTelegramUsername = telegramUsername
savedSignalNumber = signalNumber
savedSignalUsername = signalUsername
availableCommsChannels = serverInfo.availableCommsChannels ?? ['email']
telegramBotUsername = serverInfo.telegramBotUsername
discordBotUsername = serverInfo.discordBotUsername
discordAppId = serverInfo.discordAppId
} catch (e) {
toast.error(e instanceof ApiError ? e.message : $_('comms.failedToLoad'))
} finally {
@@ -81,15 +85,15 @@
try {
const result = await api.updateNotificationPrefs(session.accessJwt, {
preferredChannel,
discordId: discordId !== savedDiscordId ? discordId : undefined,
discordUsername: discordUsername !== savedDiscordUsername ? discordUsername : undefined,
telegramUsername: telegramUsername !== savedTelegramUsername ? telegramUsername : undefined,
signalNumber: signalNumber !== savedSignalNumber ? signalNumber : undefined,
signalUsername: signalUsername !== savedSignalUsername ? signalUsername : undefined,
})
await refreshSession()
toast.success($_('comms.preferencesSaved'))
savedDiscordId = discordId
savedDiscordUsername = discordUsername
savedTelegramUsername = telegramUsername
savedSignalNumber = signalNumber
savedSignalUsername = signalUsername
const channelToVerify = result.verificationRequired?.find(
(ch: string) => ch === 'discord' || ch === 'telegram' || ch === 'signal'
)
@@ -108,9 +112,9 @@
if (!verificationCode) return
const identifierMap: Record<string, string> = {
discord: discordId,
discord: discordUsername,
telegram: telegramUsername,
signal: signalNumber
signal: signalUsername
}
const identifier = identifierMap[channel]
if (!identifier) return
@@ -190,9 +194,9 @@
if (!isChannelAvailableOnServer(channelId)) return false
if (channelId === 'email') return true
const hasIdentifier: Record<string, boolean> = {
discord: !!discordId,
discord: !!discordUsername,
telegram: !!telegramUsername,
signal: !!signalNumber
signal: !!signalUsername
}
return hasIdentifier[channelId] ?? false
}
@@ -245,8 +249,8 @@
{#if isChannelAvailableOnServer('discord')}
<div class="config-item">
<div class="config-header">
<label for="discord">{$_('register.discordId')}</label>
{#if discordId}
<label for="discord">{$_('register.discordUsername')}</label>
{#if discordUsername}
<span class="status" class:verified={discordVerified} class:unverified={!discordVerified}>
{preferredChannel === 'discord' && discordVerified ? $_('comms.primary') : discordVerified ? $_('comms.verified') : $_('comms.notVerified')}
</span>
@@ -256,23 +260,22 @@
<input
id="discord"
type="text"
bind:value={discordId}
onblur={() => checkChannelInUse('discord', discordId)}
placeholder={$_('register.discordIdPlaceholder')}
bind:value={discordUsername}
onblur={() => checkChannelInUse('discord', discordUsername)}
placeholder={$_('register.discordUsernamePlaceholder')}
disabled={saving}
/>
{#if discordId && discordId === savedDiscordId && !discordVerified}
<button type="button" class="verify-btn" onclick={() => verifyingChannel = 'discord'}>{$_('comms.verifyButton')}</button>
{/if}
</div>
{#if discordInUse}
<p class="hint warning">{$_('comms.discordInUseWarning')}</p>
{/if}
{#if verifyingChannel === 'discord'}
<div class="verify-form">
<input type="text" bind:value={verificationCode} placeholder={$_('comms.verifyCodePlaceholder')} maxlength="128" />
<button type="button" onclick={() => handleVerify('discord')}>{$_('comms.submit')}</button>
<button type="button" class="cancel" onclick={() => { verifyingChannel = null; verificationCode = '' }}>{$_('common.cancel')}</button>
{#if discordUsername && discordUsername === savedDiscordUsername && !discordVerified && discordBotUsername}
{@const encodedHandle = session.handle.replaceAll('.', '_')}
<div class="discord-verify-prompt">
{#if discordAppId}
<a href="https://discord.com/users/{discordAppId}" target="_blank" rel="noopener">{$_('comms.discordOpenLink')}</a>
{/if}
<span class="manual-hint">{$_('comms.discordStartBot', { values: { botUsername: discordBotUsername, handle: session.handle } })}</span>
</div>
{/if}
</div>
@@ -314,8 +317,8 @@
{#if isChannelAvailableOnServer('signal')}
<div class="config-item">
<div class="config-header">
<label for="signal">{$_('register.signalNumber')}</label>
{#if signalNumber}
<label for="signal">{$_('register.signalUsername')}</label>
{#if signalUsername}
<span class="status" class:verified={signalVerified} class:unverified={!signalVerified}>
{preferredChannel === 'signal' && signalVerified ? $_('comms.primary') : signalVerified ? $_('comms.verified') : $_('comms.notVerified')}
</span>
@@ -324,13 +327,13 @@
<div class="config-input">
<input
id="signal"
type="tel"
bind:value={signalNumber}
onblur={() => checkChannelInUse('signal', signalNumber)}
placeholder={$_('register.signalNumberPlaceholder')}
type="text"
bind:value={signalUsername}
onblur={() => checkChannelInUse('signal', signalUsername)}
placeholder={$_('register.signalUsernamePlaceholder')}
disabled={saving}
/>
{#if signalNumber && signalNumber === savedSignalNumber && !signalVerified}
{#if signalUsername && signalUsername === savedSignalUsername && !signalVerified}
<button type="button" class="verify-btn" onclick={() => verifyingChannel = 'signal'}>{$_('comms.verifyButton')}</button>
{/if}
</div>
@@ -533,6 +536,18 @@
color: var(--text-primary);
}
.discord-verify-prompt {
display: flex;
flex-direction: column;
gap: var(--space-2);
padding: var(--space-3) var(--space-4);
background: var(--accent-bg, var(--bg-card));
border: 1px solid var(--accent, var(--border-color));
border-radius: var(--radius-md);
font-size: var(--text-sm);
color: var(--text-primary);
}
.manual-hint {
font-size: var(--text-xs);
color: var(--text-secondary);
+8 -8
View File
@@ -404,9 +404,9 @@ export const api = {
did: params.did,
signingKey: params.signingKey,
verificationChannel: params.verificationChannel,
discordId: params.discordId,
discordUsername: params.discordUsername,
telegramUsername: params.telegramUsername,
signalNumber: params.signalNumber,
signalUsername: params.signalUsername,
}),
});
const data = await response.json();
@@ -656,9 +656,9 @@ export const api = {
updateNotificationPrefs(token: AccessToken, prefs: {
preferredChannel?: string;
discordId?: string;
discordUsername?: string;
telegramUsername?: string;
signalNumber?: string;
signalUsername?: string;
}): Promise<UpdateNotificationPrefsResponse> {
return xrpc("_account.updateNotificationPrefs", {
method: "POST",
@@ -1133,9 +1133,9 @@ export const api = {
did?: Did;
signingKey?: string;
verificationChannel?: VerificationChannel;
discordId?: string;
discordUsername?: string;
telegramUsername?: string;
signalNumber?: string;
signalUsername?: string;
}, byodToken?: string): Promise<PasskeyAccountCreateResponse> {
const url = `${API_BASE}/_account.createPasskeyAccount`;
const headers: Record<string, string> = {
@@ -1854,9 +1854,9 @@ export const typedApi = {
token: AccessToken,
prefs: {
preferredChannel?: string;
discordId?: string;
discordUsername?: string;
telegramUsername?: string;
signalNumber?: string;
signalUsername?: string;
},
): Promise<Result<UpdateNotificationPrefsResponse, ApiError>> {
return xrpcResult("_account.updateNotificationPrefs", {
@@ -14,25 +14,31 @@
let resending = $state(false)
let resendMessage = $state<string | null>(null)
let telegramBotUsername = $state<string | undefined>(undefined)
let discordBotUsername = $state<string | undefined>(undefined)
let discordAppId = $state<string | undefined>(undefined)
let pollingInterval: ReturnType<typeof setInterval> | null = null
const isTelegram = $derived(flow.info.verificationChannel === 'telegram')
const isDiscord = $derived(flow.info.verificationChannel === 'discord')
const isBotVerified = $derived(isTelegram || isDiscord)
onMount(async () => {
if (isTelegram) {
if (isTelegram || isDiscord) {
try {
const serverInfo = await api.describeServer()
telegramBotUsername = serverInfo.telegramBotUsername
discordBotUsername = serverInfo.discordBotUsername
discordAppId = serverInfo.discordAppId
} catch {
}
}
})
$effect(() => {
if (flow.state.step === 'verify' && flow.account && (isTelegram || !verificationCode.trim())) {
if (flow.state.step === 'verify' && flow.account && (isBotVerified || !verificationCode.trim())) {
pollingInterval = setInterval(async () => {
if (!isTelegram && verificationCode.trim()) return
if (!isBotVerified && verificationCode.trim()) return
const advanced = await flow.checkAndAdvanceIfVerified()
if (advanced && pollingInterval) {
clearInterval(pollingInterval)
@@ -105,6 +111,13 @@
or send <code>/start {handle}</code> to <code>@{telegramBotUsername}</code> manually.
</p>
<p class="info-text waiting">Waiting for verification...</p>
{:else if isDiscord && discordAppId}
{@const handle = flow.account?.handle ?? `${flow.info.handle.trim()}.${flow.state.pdsHostname}`}
<p class="info-text">
<a href="https://discord.com/users/{discordAppId}" target="_blank" rel="noopener">Open Discord to verify</a>,
or send <code>/start {handle}</code> to <strong>{discordBotUsername ?? 'the bot'}</strong> manually.
</p>
<p class="info-text waiting">Waiting for verification...</p>
{:else}
<p class="info-text">
We've sent a verification code to your {channelLabel(flow.info.verificationChannel)}.
+6 -6
View File
@@ -56,9 +56,9 @@ export function createRegistrationFlow(
didType: "plc",
externalDid: "",
verificationChannel: "email",
discordId: "",
discordUsername: "",
telegramUsername: "",
signalNumber: "",
signalUsername: "",
},
externalDidWeb: {
keyMode: "reserved",
@@ -252,9 +252,9 @@ export function createRegistrationFlow(
? state.externalDidWeb.reservedSigningKey
: undefined,
verificationChannel: state.info.verificationChannel,
discordId: state.info.discordId?.trim() || undefined,
discordUsername: state.info.discordUsername?.trim() || undefined,
telegramUsername: state.info.telegramUsername?.trim() || undefined,
signalNumber: state.info.signalNumber?.trim() || undefined,
signalUsername: state.info.signalUsername?.trim() || undefined,
}, byodToken);
state.account = {
@@ -305,9 +305,9 @@ export function createRegistrationFlow(
? state.externalDidWeb.reservedSigningKey
: undefined,
verificationChannel: state.info.verificationChannel,
discordId: state.info.discordId?.trim() || undefined,
discordUsername: state.info.discordUsername?.trim() || undefined,
telegramUsername: state.info.telegramUsername?.trim() || undefined,
signalNumber: state.info.signalNumber?.trim() || undefined,
signalUsername: state.info.signalUsername?.trim() || undefined,
}, byodToken);
state.account = {
+2 -2
View File
@@ -28,9 +28,9 @@ export interface RegistrationInfo {
didType: DidType;
externalDid?: string;
verificationChannel: VerificationChannel;
discordId?: string;
discordUsername?: string;
telegramUsername?: string;
signalNumber?: string;
signalUsername?: string;
}
export interface ExternalDidWebState {
+4 -4
View File
@@ -185,9 +185,9 @@ export interface CreateAccountParams {
did?: string;
signingKey?: string;
verificationChannel?: VerificationChannel;
discordId?: string;
discordUsername?: string;
telegramUsername?: string;
signalNumber?: string;
signalUsername?: string;
}
export interface CreateAccountResult {
@@ -254,11 +254,11 @@ export interface ListReposResponse {
export interface NotificationPrefs {
preferredChannel: VerificationChannel;
email: EmailAddress;
discordId: string | null;
discordUsername: string | null;
discordVerified: boolean;
telegramUsername: string | null;
telegramVerified: boolean;
signalNumber: string | null;
signalUsername: string | null;
signalVerified: boolean;
}
+2 -2
View File
@@ -173,11 +173,11 @@ export const reauthResponseSchema = z.object({
export const notificationPrefsSchema = z.object({
preferredChannel: verificationChannel,
email: email,
discordId: z.string().nullable(),
discordUsername: z.string().nullable(),
discordVerified: z.boolean(),
telegramUsername: z.string().nullable(),
telegramVerified: z.boolean(),
signalNumber: z.string().nullable(),
signalUsername: z.string().nullable(),
signalVerified: z.boolean(),
});
+15 -15
View File
@@ -84,19 +84,17 @@
"emailAddress": "Email Address",
"emailPlaceholder": "you@example.com",
"discord": "Discord",
"discordId": "Discord User ID",
"discordIdPlaceholder": "123456789012345678",
"discordIdHint": "Enable Developer Mode to find your ID",
"discordInUseWarning": "Discord ID in use by another account",
"discordUsername": "Discord Username",
"discordUsernamePlaceholder": "yourusername",
"discordInUseWarning": "Discord username in use by another account",
"telegram": "Telegram",
"telegramUsername": "Telegram Username",
"telegramUsernamePlaceholder": "@yourusername",
"telegramInUseWarning": "Telegram username in use by another account",
"signal": "Signal",
"signalNumber": "Signal Phone Number",
"signalNumberPlaceholder": "+1234567890",
"signalNumberHint": "Include country code",
"signalInUseWarning": "Signal number in use by another account",
"signalUsername": "Signal Username",
"signalUsernamePlaceholder": "username.01",
"signalInUseWarning": "Signal username in use by another account",
"notConfigured": "not configured",
"inviteCode": "Invite Code",
"inviteCodePlaceholder": "Enter your invite code",
@@ -118,9 +116,9 @@
"externalDidRequired": "External did:web is required",
"externalDidFormat": "External DID must start with did:web:",
"emailRequired": "Email is required for email verification",
"discordIdRequired": "Discord ID is required for Discord verification",
"discordUsernameRequired": "Discord username is required for Discord verification",
"telegramRequired": "Telegram username is required for Telegram verification",
"signalRequired": "Phone number is required for Signal verification"
"signalRequired": "Signal username is required for Signal verification"
}
},
"dashboard": {
@@ -437,11 +435,13 @@
"verifiedSuccess": "{channel} verified successfully",
"messageHistory": "Message History",
"noMessages": "No messages found.",
"discordInUseWarning": "This Discord ID is already associated with another account.",
"discordInUseWarning": "This Discord username is already associated with another account.",
"telegramInUseWarning": "This Telegram username is already associated with another account.",
"signalInUseWarning": "This Signal number is already associated with another account.",
"signalInUseWarning": "This Signal username is already associated with another account.",
"telegramStartBot": "Or send /start {handle} to @{botUsername} manually",
"telegramOpenLink": "Open Telegram to verify"
"telegramOpenLink": "Open Telegram to verify",
"discordStartBot": "DM @{botUsername} on Discord and send /start {handle}",
"discordOpenLink": "Open Discord to verify"
},
"repoExplorer": {
"collections": "Collections",
@@ -779,9 +779,9 @@
"externalDidRequired": "External did:web is required",
"externalDidFormat": "External DID must start with did:web:",
"emailRequired": "Email is required for email verification",
"discordRequired": "Discord ID is required for Discord verification",
"discordRequired": "Discord username is required for Discord verification",
"telegramRequired": "Telegram username is required for Telegram verification",
"signalRequired": "Phone number required",
"signalRequired": "Signal username required",
"passkeysNotSupported": "Passkeys not supported in this browser",
"passkeyCancelled": "Cancelled",
"passkeyFailed": "Passkey registration failed"
+14 -14
View File
@@ -84,19 +84,17 @@
"emailAddress": "Sähköpostiosoite",
"emailPlaceholder": "sinä@esimerkki.fi",
"discord": "Discord",
"discordId": "Discord-käyttäjätunnus",
"discordIdPlaceholder": "Discord-käyttäjätunnuksesi",
"discordIdHint": "Numeerinen Discord-käyttäjätunnuksesi (ota Kehittäjätila käyttöön löytääksesi sen)",
"discordInUseWarning": "Tämä Discord-tunnus on jo yhdistetty toiseen tiliin.",
"discordUsername": "Discord-käyttäjänimi",
"discordUsernamePlaceholder": "käyttäjänimesi",
"discordInUseWarning": "Tämä Discord-käyttäjänimi on jo yhdistetty toiseen tiliin.",
"telegram": "Telegram",
"telegramUsername": "Telegram-käyttäjänimi",
"telegramUsernamePlaceholder": "@käyttäjänimesi",
"telegramInUseWarning": "Tämä Telegram-käyttäjänimi on jo yhdistetty toiseen tiliin.",
"signal": "Signal",
"signalNumber": "Signal-puhelinnumero",
"signalNumberPlaceholder": "+358401234567",
"signalNumberHint": "Sisällytä maakoodi (esim. +358 Suomelle)",
"signalInUseWarning": "Tämä Signal-numero on jo yhdistetty toiseen tiliin.",
"signalUsername": "Signal-käyttäjänimi",
"signalUsernamePlaceholder": "käyttäjänimi.01",
"signalInUseWarning": "Tämä Signal-käyttäjänimi on jo yhdistetty toiseen tiliin.",
"notConfigured": "ei määritetty",
"inviteCode": "Kutsukoodi",
"inviteCodePlaceholder": "Syötä kutsukoodisi",
@@ -118,9 +116,9 @@
"externalDidRequired": "Ulkoinen did:web vaaditaan",
"externalDidFormat": "Ulkoisen DID:n on alettava did:web:",
"emailRequired": "Sähköposti vaaditaan sähköpostivahvistukseen",
"discordIdRequired": "Discord-tunnus vaaditaan Discord-vahvistukseen",
"discordUsernameRequired": "Discord-käyttäjänimi vaaditaan Discord-vahvistukseen",
"telegramRequired": "Telegram-käyttäjänimi vaaditaan Telegram-vahvistukseen",
"signalRequired": "Puhelinnumero vaaditaan Signal-vahvistukseen"
"signalRequired": "Signal-käyttäjänimi vaaditaan Signal-vahvistukseen"
}
},
"dashboard": {
@@ -433,11 +431,13 @@
"verifiedSuccess": "{channel} vahvistettu",
"messageHistory": "Viestihistoria",
"noMessages": "Viestejä ei löytynyt.",
"discordInUseWarning": "Tämä Discord-tunnus on jo yhdistetty toiseen tiliin.",
"discordInUseWarning": "Tämä Discord-käyttäjänimi on jo yhdistetty toiseen tiliin.",
"telegramInUseWarning": "Tämä Telegram-käyttäjänimi on jo yhdistetty toiseen tiliin.",
"signalInUseWarning": "Tämä Signal-numero on jo yhdistetty toiseen tiliin.",
"signalInUseWarning": "Tämä Signal-käyttäjänimi on jo yhdistetty toiseen tiliin.",
"telegramStartBot": "Tai lähetä /start {handle} käyttäjälle @{botUsername} manuaalisesti",
"telegramOpenLink": "Avaa Telegram vahvistaaksesi",
"discordStartBot": "Lähetä @{botUsername}-botille viesti /start {handle} Discordissa",
"discordOpenLink": "Avaa Discord vahvistaaksesi",
"failedToLoad": "Asetusten lataus epäonnistui",
"failedToSave": "Asetusten tallennus epäonnistui",
"failedToVerify": "Vahvistus epäonnistui",
@@ -751,13 +751,13 @@
"passkeysNotSupported": "Pääsyavaimia ei tueta tässä selaimessa. Luo salasanapohjainen tili tai käytä selainta, joka tukee pääsyavaimia.",
"passkeyCancelled": "Pääsyavaimen luominen peruutettu",
"passkeyFailed": "Pääsyavaimen rekisteröinti epäonnistui",
"signalRequired": "Puhelinnumero vaaditaan Signal-vahvistukseen",
"signalRequired": "Signal-käyttäjänimi vaaditaan Signal-vahvistukseen",
"inviteRequired": "Kutsukoodi vaaditaan",
"externalDidRequired": "Ulkoinen did:web vaaditaan",
"emailRequired": "Sähköposti vaaditaan sähköpostivahvistukseen",
"telegramRequired": "Telegram-käyttäjänimi vaaditaan Telegram-vahvistukseen",
"externalDidFormat": "Ulkoisen DID:n on alettava did:web:",
"discordRequired": "Discord-tunnus vaaditaan Discord-vahvistukseen"
"discordRequired": "Discord-käyttäjänimi vaaditaan Discord-vahvistukseen"
},
"identityType": "Identiteettityyppi",
"identityTypeHint": "Valitse, miten hajautettua identiteettiäsi hallitaan.",
+14 -14
View File
@@ -84,19 +84,17 @@
"emailAddress": "メールアドレス",
"emailPlaceholder": "you@example.com",
"discord": "Discord",
"discordId": "Discord ユーザー ID",
"discordIdPlaceholder": "Discord ユーザー ID",
"discordIdHint": "数値の Discord ユーザー ID(開発者モードを有効にして確認)",
"discordInUseWarning": "この Discord ID は既に別のアカウントに関連付けられています。",
"discordUsername": "Discord ユーザー",
"discordUsernamePlaceholder": "yourusername",
"discordInUseWarning": "の Discord ユーザー名は既に別のアカウントに関連付けられています。",
"telegram": "Telegram",
"telegramUsername": "Telegram ユーザー名",
"telegramUsernamePlaceholder": "@yourusername",
"telegramInUseWarning": "この Telegram ユーザー名は既に別のアカウントに関連付けられています。",
"signal": "Signal",
"signalNumber": "Signal 電話番号",
"signalNumberPlaceholder": "+81XXXXXXXXXX",
"signalNumberHint": "国番号を含めてください(例: 日本は +81)",
"signalInUseWarning": "この Signal 番号は既に別のアカウントに関連付けられています。",
"signalUsername": "Signal ユーザー名",
"signalUsernamePlaceholder": "username.01",
"signalInUseWarning": "この Signal ユーザー名は既に別のアカウントに使用されています。",
"notConfigured": "未設定",
"inviteCode": "招待コード",
"inviteCodePlaceholder": "招待コードを入力",
@@ -118,9 +116,9 @@
"externalDidRequired": "外部 did:web は必須です",
"externalDidFormat": "外部 DID は did:web: で始まる必要があります",
"emailRequired": "メール認証にはメールアドレスが必要です",
"discordIdRequired": "Discord 認証には Discord ID が必要です",
"discordUsernameRequired": "Discord 認証には Discord ユーザー名が必要です",
"telegramRequired": "Telegram 認証には Telegram ユーザー名が必要です",
"signalRequired": "Signal 認証には電話番号が必要です"
"signalRequired": "Signal 認証にはユーザー名が必要です"
}
},
"dashboard": {
@@ -433,11 +431,13 @@
"verifiedSuccess": "{channel} を確認しました",
"messageHistory": "メッセージ履歴",
"noMessages": "メッセージが見つかりません。",
"discordInUseWarning": "この Discord ID は既に別のアカウントに関連付けられています。",
"discordInUseWarning": "この Discord ユーザー名は既に別のアカウントに関連付けられています。",
"telegramInUseWarning": "この Telegram ユーザー名は既に別のアカウントに関連付けられています。",
"signalInUseWarning": "この Signal 番号は既に別のアカウントに関連付けられています。",
"signalInUseWarning": "この Signal ユーザー名は既に別のアカウントに使用されています。",
"telegramStartBot": "または @{botUsername} に /start {handle} を手動で送信",
"telegramOpenLink": "Telegram で確認する",
"discordStartBot": "Discordで @{botUsername} にDMして /start {handle} を送信",
"discordOpenLink": "Discordで認証",
"failedToLoad": "設定の読み込みに失敗しました",
"failedToSave": "設定の保存に失敗しました",
"failedToVerify": "確認に失敗しました",
@@ -751,13 +751,13 @@
"passkeysNotSupported": "このブラウザではパスキーがサポートされていません。パスワードベースのアカウントを作成するか、パスキーをサポートするブラウザを使用してください。",
"passkeyCancelled": "パスキーの作成がキャンセルされました",
"passkeyFailed": "パスキーの登録に失敗しました",
"signalRequired": "Signal認証には電話番号が必要です",
"signalRequired": "Signal認証にはユーザー名が必要です",
"inviteRequired": "招待コードが必要です",
"externalDidRequired": "外部did:webが必要です",
"emailRequired": "メール認証にはメールアドレスが必要です",
"telegramRequired": "Telegram認証にはTelegramユーザー名が必要です",
"externalDidFormat": "外部DIDはdid:web:で始まる必要があります",
"discordRequired": "Discord認証にはDiscord IDが必要です"
"discordRequired": "Discord認証にはDiscordユーザー名が必要です"
},
"identityType": "アイデンティティタイプ",
"identityTypeHint": "分散型アイデンティティの管理方法を選択してください。",
+14 -14
View File
@@ -84,19 +84,17 @@
"emailAddress": "이메일 주소",
"emailPlaceholder": "you@example.com",
"discord": "Discord",
"discordId": "Discord 사용자 ID",
"discordIdPlaceholder": "Discord 사용자 ID",
"discordIdHint": "숫자 Discord 사용자 ID (개발자 모드를 활성화하여 찾기)",
"discordInUseWarning": "이 Discord ID는 이미 다른 계정과 연결되어 있습니다.",
"discordUsername": "Discord 사용자",
"discordUsernamePlaceholder": "yourusername",
"discordInUseWarning": " Discord 사용자명은 이미 다른 계정과 연결되어 있습니다.",
"telegram": "Telegram",
"telegramUsername": "Telegram 사용자 이름",
"telegramUsernamePlaceholder": "@yourusername",
"telegramInUseWarning": "이 Telegram 사용자 이름은 이미 다른 계정과 연결되어 있습니다.",
"signal": "Signal",
"signalNumber": "Signal 전화번호",
"signalNumberPlaceholder": "+821012345678",
"signalNumberHint": "국가 코드 포함 (예: 한국 +82)",
"signalInUseWarning": "이 Signal 번호는 이미 다른 계정과 연결되어 있습니다.",
"signalUsername": "Signal 사용자명",
"signalUsernamePlaceholder": "username.01",
"signalInUseWarning": "이 Signal 사용자명은 이미 다른 계정에서 사용 중입니다.",
"notConfigured": "구성되지 않음",
"inviteCode": "초대 코드",
"inviteCodePlaceholder": "초대 코드 입력",
@@ -118,9 +116,9 @@
"externalDidRequired": "외부 did:web은 필수입니다",
"externalDidFormat": "외부 DID는 did:web:으로 시작해야 합니다",
"emailRequired": "이메일 인증에는 이메일이 필요합니다",
"discordIdRequired": "Discord 인증에는 Discord ID가 필요합니다",
"discordUsernameRequired": "Discord 인증에는 Discord 사용자명이 필요합니다",
"telegramRequired": "Telegram 인증에는 Telegram 사용자 이름이 필요합니다",
"signalRequired": "Signal 인증에는 전화번호가 필요합니다"
"signalRequired": "Signal 인증에는 사용자명이 필요합니다"
}
},
"dashboard": {
@@ -433,11 +431,13 @@
"verifiedSuccess": "{channel} 인증 완료",
"messageHistory": "메시지 기록",
"noMessages": "메시지가 없습니다.",
"discordInUseWarning": "이 Discord ID는 이미 다른 계정과 연결되어 있습니다.",
"discordInUseWarning": "이 Discord 사용자명은 이미 다른 계정과 연결되어 있습니다.",
"telegramInUseWarning": "이 Telegram 사용자 이름은 이미 다른 계정과 연결되어 있습니다.",
"signalInUseWarning": "이 Signal 번호는 이미 다른 계정과 연결되어 있습니다.",
"signalInUseWarning": "이 Signal 사용자명은 이미 다른 계정에서 사용 중입니다.",
"telegramStartBot": "또는 @{botUsername}에게 /start {handle}을 직접 보내세요",
"telegramOpenLink": "Telegram에서 인증하기",
"discordStartBot": "Discord에서 @{botUsername}에게 DM으로 /start {handle} 보내기",
"discordOpenLink": "Discord에서 인증",
"failedToLoad": "설정 로딩 실패",
"failedToSave": "설정 저장 실패",
"failedToVerify": "인증 실패",
@@ -751,13 +751,13 @@
"passkeysNotSupported": "이 브라우저에서 패스키가 지원되지 않습니다. 비밀번호 기반 계정을 만들거나 패스키를 지원하는 브라우저를 사용하세요.",
"passkeyCancelled": "패스키 생성이 취소되었습니다",
"passkeyFailed": "패스키 등록에 실패했습니다",
"signalRequired": "Signal 인증에는 전화번호가 필요합니다",
"signalRequired": "Signal 인증에는 사용자명이 필요합니다",
"inviteRequired": "초대 코드가 필요합니다",
"externalDidRequired": "외부 did:web이 필요합니다",
"emailRequired": "이메일 인증에는 이메일이 필요합니다",
"telegramRequired": "Telegram 인증에는 Telegram 사용자 이름이 필요합니다",
"externalDidFormat": "외부 DID는 did:web:으로 시작해야 합니다",
"discordRequired": "Discord 인증에는 Discord ID가 필요합니다"
"discordRequired": "Discord 인증에는 Discord 사용자명이 필요합니다"
},
"identityType": "아이덴티티 유형",
"identityTypeHint": "분산 아이덴티티 관리 방법을 선택하세요.",
+14 -14
View File
@@ -84,19 +84,17 @@
"emailAddress": "E-postadress",
"emailPlaceholder": "du@exempel.se",
"discord": "Discord",
"discordId": "Discord användar-ID",
"discordIdPlaceholder": "Ditt Discord användar-ID",
"discordIdHint": "Ditt numeriska Discord användar-ID (aktivera Utvecklarläge för att hitta det)",
"discordInUseWarning": "Detta Discord-ID är redan kopplat till ett annat konto.",
"discordUsername": "Discord-användarnamn",
"discordUsernamePlaceholder": "dittanvändarnamn",
"discordInUseWarning": "Detta Discord-användarnamn är redan kopplat till ett annat konto.",
"telegram": "Telegram",
"telegramUsername": "Telegram-användarnamn",
"telegramUsernamePlaceholder": "@dittanvändarnamn",
"telegramInUseWarning": "Detta Telegram-användarnamn är redan kopplat till ett annat konto.",
"signal": "Signal",
"signalNumber": "Signal-telefonnummer",
"signalNumberPlaceholder": "+46701234567",
"signalNumberHint": "Inkludera landskod (t.ex. +46 för Sverige)",
"signalInUseWarning": "Detta Signal-nummer är redan kopplat till ett annat konto.",
"signalUsername": "Signal-användarnamn",
"signalUsernamePlaceholder": "användarnamn.01",
"signalInUseWarning": "Detta Signal-användarnamn är redan kopplat till ett annat konto.",
"notConfigured": "ej konfigurerad",
"inviteCode": "Inbjudningskod",
"inviteCodePlaceholder": "Ange din inbjudningskod",
@@ -118,9 +116,9 @@
"externalDidRequired": "Extern did:web krävs",
"externalDidFormat": "Extern DID måste börja med did:web:",
"emailRequired": "E-post krävs för e-postverifiering",
"discordIdRequired": "Discord-ID krävs för Discord-verifiering",
"discordUsernameRequired": "Discord-användarnamn krävs för Discord-verifiering",
"telegramRequired": "Telegram-användarnamn krävs för Telegram-verifiering",
"signalRequired": "Telefonnummer krävs för Signal-verifiering"
"signalRequired": "Signal-användarnamn krävs för Signal-verifiering"
}
},
"dashboard": {
@@ -433,11 +431,13 @@
"verifiedSuccess": "{channel} verifierad",
"messageHistory": "Meddelandehistorik",
"noMessages": "Inga meddelanden hittades.",
"discordInUseWarning": "Detta Discord-ID är redan kopplat till ett annat konto.",
"discordInUseWarning": "Detta Discord-användarnamn är redan kopplat till ett annat konto.",
"telegramInUseWarning": "Detta Telegram-användarnamn är redan kopplat till ett annat konto.",
"signalInUseWarning": "Detta Signal-nummer är redan kopplat till ett annat konto.",
"signalInUseWarning": "Detta Signal-användarnamn är redan kopplat till ett annat konto.",
"telegramStartBot": "Eller skicka /start {handle} till @{botUsername} manuellt",
"telegramOpenLink": "Öppna Telegram för att verifiera",
"discordStartBot": "DM:a @{botUsername} på Discord och skicka /start {handle}",
"discordOpenLink": "Öppna Discord för att verifiera",
"failedToLoad": "Kunde inte ladda inställningar",
"failedToSave": "Kunde inte spara inställningar",
"failedToVerify": "Verifiering misslyckades",
@@ -751,13 +751,13 @@
"passkeysNotSupported": "Nycklar stöds inte i denna webbläsare. Skapa ett lösenordsbaserat konto eller använd en webbläsare som stöder nycklar.",
"passkeyCancelled": "Nyckelskapande avbröts",
"passkeyFailed": "Nyckelregistrering misslyckades",
"signalRequired": "Telefonnummer krävs för Signal-verifiering",
"signalRequired": "Signal-användarnamn krävs för Signal-verifiering",
"inviteRequired": "Inbjudningskod krävs",
"externalDidRequired": "Extern did:web krävs",
"emailRequired": "E-post krävs för e-postverifiering",
"telegramRequired": "Telegram-användarnamn krävs för Telegram-verifiering",
"externalDidFormat": "Extern DID måste börja med did:web:",
"discordRequired": "Discord-ID krävs för Discord-verifiering"
"discordRequired": "Discord-användarnamn krävs för Discord-verifiering"
},
"identityType": "Identitetstyp",
"identityTypeHint": "Välj hur din decentraliserade identitet ska hanteras.",
+14 -14
View File
@@ -84,19 +84,17 @@
"emailAddress": "电子邮件地址",
"emailPlaceholder": "you@example.com",
"discord": "Discord",
"discordId": "Discord 用户 ID",
"discordIdPlaceholder": "您的 Discord 用户 ID",
"discordIdHint": "您的 Discord 数字用户 ID(开启开发者模式后可以复制)",
"discordInUseWarning": "此 Discord ID 已与另一个账户关联。",
"discordUsername": "Discord 用户",
"discordUsernamePlaceholder": "yourusername",
"discordInUseWarning": " Discord 用户名已与另一个账户关联。",
"telegram": "Telegram",
"telegramUsername": "Telegram 用户名",
"telegramUsernamePlaceholder": "@yourusername",
"telegramInUseWarning": "此 Telegram 用户名已与另一个账户关联。",
"signal": "Signal",
"signalNumber": "Signal 电话号码",
"signalNumberPlaceholder": "+1234567890",
"signalNumberHint": "包含国家代码(例如中国为 +86",
"signalInUseWarning": "此 Signal 号码已与另一个账户关联。",
"signalUsername": "Signal 用户名",
"signalUsernamePlaceholder": "username.01",
"signalInUseWarning": "此 Signal 用户名已被其他账户使用。",
"notConfigured": "未配置",
"inviteCode": "邀请码",
"inviteCodePlaceholder": "输入您的邀请码",
@@ -118,9 +116,9 @@
"externalDidRequired": "请输入您的 did:web",
"externalDidFormat": "DID 必须以 did:web: 开头",
"emailRequired": "使用邮箱验证需要填写邮箱地址",
"discordIdRequired": "使用 Discord 验证需要填写 Discord ID",
"discordUsernameRequired": "使用 Discord 验证需要填写 Discord 用户名",
"telegramRequired": "使用 Telegram 验证需要填写用户名",
"signalRequired": "使用 Signal 验证需要填写电话号码"
"signalRequired": "使用 Signal 验证需要填写用户名"
}
},
"dashboard": {
@@ -433,11 +431,13 @@
"verifiedSuccess": "{channel} 验证成功",
"messageHistory": "消息历史",
"noMessages": "暂无消息记录",
"discordInUseWarning": "此 Discord ID 已与另一个账户关联。",
"discordInUseWarning": "此 Discord 用户名已与另一个账户关联。",
"telegramInUseWarning": "此 Telegram 用户名已与另一个账户关联。",
"signalInUseWarning": "此 Signal 号码已与另一个账户关联。",
"signalInUseWarning": "此 Signal 用户名已与另一个账户关联。",
"telegramStartBot": "或手动向 @{botUsername} 发送 /start {handle}",
"telegramOpenLink": "打开 Telegram 验证",
"discordStartBot": "在 Discord 上私信 @{botUsername} 并发送 /start {handle}",
"discordOpenLink": "打开 Discord 验证",
"failedToLoad": "加载偏好设置失败",
"failedToSave": "保存偏好设置失败",
"failedToVerify": "验证失败",
@@ -774,9 +774,9 @@
"externalDidRequired": "请输入您的 did:web",
"externalDidFormat": "DID 必须以 did:web: 开头",
"emailRequired": "使用邮箱验证需要填写邮箱地址",
"discordRequired": "使用 Discord 验证需要填写 Discord ID",
"discordRequired": "使用 Discord 验证需要填写 Discord 用户名",
"telegramRequired": "使用 Telegram 验证需要填写用户名",
"signalRequired": "使用 Signal 验证需要填写电话号码",
"signalRequired": "使用 Signal 验证需要填写用户名",
"passkeysNotSupported": "此浏览器不支持通行密钥。请使用其他浏览器或使用密码注册。",
"passkeyCancelled": "通行密钥创建已取消",
"passkeyFailed": "通行密钥注册失败"
+10 -11
View File
@@ -123,13 +123,13 @@
if (!info.email.trim()) return $_('registerPasskey.errors.emailRequired')
break
case 'discord':
if (!info.discordId?.trim()) return $_('registerPasskey.errors.discordRequired')
if (!info.discordUsername?.trim()) return $_('registerPasskey.errors.discordRequired')
break
case 'telegram':
if (!info.telegramUsername?.trim()) return $_('registerPasskey.errors.telegramRequired')
break
case 'signal':
if (!info.signalNumber?.trim()) return $_('registerPasskey.errors.signalRequired')
if (!info.signalUsername?.trim()) return $_('registerPasskey.errors.signalRequired')
break
}
return null
@@ -389,16 +389,15 @@
</div>
{:else if flow.info.verificationChannel === 'discord'}
<div class="field">
<label for="discord-id">{$_('register.discordId')}</label>
<label for="discord-username">{$_('register.discordUsername')}</label>
<input
id="discord-id"
id="discord-username"
type="text"
bind:value={flow.info.discordId}
placeholder={$_('register.discordIdPlaceholder')}
bind:value={flow.info.discordUsername}
placeholder={$_('register.discordUsernamePlaceholder')}
disabled={flow.state.submitting}
required
/>
<p class="hint">{$_('register.discordIdHint')}</p>
</div>
{:else if flow.info.verificationChannel === 'telegram'}
<div class="field">
@@ -414,16 +413,16 @@
</div>
{:else if flow.info.verificationChannel === 'signal'}
<div class="field">
<label for="signal-number">{$_('register.signalNumber')}</label>
<label for="signal-number">{$_('register.signalUsername')}</label>
<input
id="signal-number"
type="tel"
bind:value={flow.info.signalNumber}
placeholder={$_('register.signalNumberPlaceholder')}
bind:value={flow.info.signalUsername}
placeholder={$_('register.signalUsernamePlaceholder')}
disabled={flow.state.submitting}
required
/>
<p class="hint">{$_('register.signalNumberHint')}</p>
<p class="hint">{$_('register.signalUsernameHint')}</p>
</div>
{/if}
</div>
+14 -15
View File
@@ -30,9 +30,9 @@
let providerEmailOriginal = $state<string | null>(null)
let inviteCode = $state('')
let verificationChannel = $state('email')
let discordId = $state('')
let discordUsername = $state('')
let telegramUsername = $state('')
let signalNumber = $state('')
let signalUsername = $state('')
let handleAvailable = $state<boolean | null>(null)
let checkingHandle = $state(false)
@@ -189,11 +189,11 @@
case 'email':
return !!email.trim()
case 'discord':
return !!discordId.trim()
return !!discordUsername.trim()
case 'telegram':
return !!telegramUsername.trim()
case 'signal':
return !!signalNumber.trim()
return !!signalUsername.trim()
default:
return false
}
@@ -234,9 +234,9 @@
email: email || null,
invite_code: inviteCode || null,
verification_channel: verificationChannel,
discord_id: discordId || null,
discord_username: discordUsername || null,
telegram_username: telegramUsername || null,
signal_number: signalNumber || null,
signal_username: signalUsername || null,
did_type: didType,
did: didType === 'web-external' ? externalDid.trim() : null,
}),
@@ -379,16 +379,15 @@
</div>
{:else if verificationChannel === 'discord'}
<div class="field">
<label for="discord-id">{$_('register.discordId')}</label>
<label for="discord-username">{$_('register.discordUsername')}</label>
<input
id="discord-id"
id="discord-username"
type="text"
bind:value={discordId}
placeholder={$_('register.discordIdPlaceholder')}
bind:value={discordUsername}
placeholder={$_('register.discordUsernamePlaceholder')}
disabled={submitting}
required
/>
<p class="hint">{$_('register.discordIdHint')}</p>
</div>
{:else if verificationChannel === 'telegram'}
<div class="field">
@@ -404,16 +403,16 @@
</div>
{:else if verificationChannel === 'signal'}
<div class="field">
<label for="signal-number">{$_('register.signalNumber')}</label>
<label for="signal-number">{$_('register.signalUsername')}</label>
<input
id="signal-number"
type="tel"
bind:value={signalNumber}
placeholder={$_('register.signalNumberPlaceholder')}
bind:value={signalUsername}
placeholder={$_('register.signalUsernamePlaceholder')}
disabled={submitting}
required
/>
<p class="hint">{$_('register.signalNumberHint')}</p>
<p class="hint">{$_('register.signalUsernameHint')}</p>
</div>
{/if}
</div>
+10 -11
View File
@@ -136,13 +136,13 @@
if (!info.email.trim()) return $_('registerPasskey.errors.emailRequired')
break
case 'discord':
if (!info.discordId?.trim()) return $_('registerPasskey.errors.discordRequired')
if (!info.discordUsername?.trim()) return $_('registerPasskey.errors.discordRequired')
break
case 'telegram':
if (!info.telegramUsername?.trim()) return $_('registerPasskey.errors.telegramRequired')
break
case 'signal':
if (!info.signalNumber?.trim()) return $_('registerPasskey.errors.signalRequired')
if (!info.signalUsername?.trim()) return $_('registerPasskey.errors.signalRequired')
break
}
return null
@@ -409,16 +409,15 @@
</div>
{:else if flow.info.verificationChannel === 'discord'}
<div class="field">
<label for="discord-id">{$_('register.discordId')}</label>
<label for="discord-username">{$_('register.discordUsername')}</label>
<input
id="discord-id"
id="discord-username"
type="text"
bind:value={flow.info.discordId}
placeholder={$_('register.discordIdPlaceholder')}
bind:value={flow.info.discordUsername}
placeholder={$_('register.discordUsernamePlaceholder')}
disabled={flow.state.submitting}
required
/>
<p class="hint">{$_('register.discordIdHint')}</p>
</div>
{:else if flow.info.verificationChannel === 'telegram'}
<div class="field">
@@ -434,16 +433,16 @@
</div>
{:else if flow.info.verificationChannel === 'signal'}
<div class="field">
<label for="signal-number">{$_('register.signalNumber')}</label>
<label for="signal-number">{$_('register.signalUsername')}</label>
<input
id="signal-number"
type="tel"
bind:value={flow.info.signalNumber}
placeholder={$_('register.signalNumberPlaceholder')}
bind:value={flow.info.signalUsername}
placeholder={$_('register.signalUsernamePlaceholder')}
disabled={flow.state.submitting}
required
/>
<p class="hint">{$_('register.signalNumberHint')}</p>
<p class="hint">{$_('register.signalUsernameHint')}</p>
</div>
{/if}
+12 -13
View File
@@ -133,13 +133,13 @@
if (!info.email.trim()) return $_('register.validation.emailRequired')
break
case 'discord':
if (!info.discordId?.trim()) return $_('register.validation.discordIdRequired')
if (!info.discordUsername?.trim()) return $_('register.validation.discordUsernameRequired')
break
case 'telegram':
if (!info.telegramUsername?.trim()) return $_('register.validation.telegramRequired')
break
case 'signal':
if (!info.signalNumber?.trim()) return $_('register.validation.signalRequired')
if (!info.signalUsername?.trim()) return $_('register.validation.signalRequired')
break
}
return null
@@ -381,17 +381,16 @@
</div>
{:else if flow.info.verificationChannel === 'discord'}
<div class="field">
<label for="discord-id">{$_('register.discordId')}</label>
<label for="discord-username">{$_('register.discordUsername')}</label>
<input
id="discord-id"
id="discord-username"
type="text"
bind:value={flow.info.discordId}
onblur={() => flow?.checkCommsChannelInUse('discord', flow.info.discordId ?? '')}
placeholder={$_('register.discordIdPlaceholder')}
bind:value={flow.info.discordUsername}
onblur={() => flow?.checkCommsChannelInUse('discord', flow.info.discordUsername ?? '')}
placeholder={$_('register.discordUsernamePlaceholder')}
disabled={flow.state.submitting}
required
/>
<p class="hint">{$_('register.discordIdHint')}</p>
{#if flow.state.discordInUse}
<p class="hint warning">{$_('register.discordInUseWarning')}</p>
{/if}
@@ -414,17 +413,17 @@
</div>
{:else if flow.info.verificationChannel === 'signal'}
<div class="field">
<label for="signal-number">{$_('register.signalNumber')}</label>
<label for="signal-number">{$_('register.signalUsername')}</label>
<input
id="signal-number"
type="tel"
bind:value={flow.info.signalNumber}
onblur={() => flow?.checkCommsChannelInUse('signal', flow.info.signalNumber ?? '')}
placeholder={$_('register.signalNumberPlaceholder')}
bind:value={flow.info.signalUsername}
onblur={() => flow?.checkCommsChannelInUse('signal', flow.info.signalUsername ?? '')}
placeholder={$_('register.signalUsernamePlaceholder')}
disabled={flow.state.submitting}
required
/>
<p class="hint">{$_('register.signalNumberHint')}</p>
<p class="hint">{$_('register.signalUsernameHint')}</p>
{#if flow.state.signalInUse}
<p class="hint warning">{$_('register.signalInUseWarning')}</p>
{/if}
+14 -15
View File
@@ -40,9 +40,9 @@
let providerEmailOriginal = $state<string | null>(null)
let inviteCode = $state('')
let verificationChannel = $state('email')
let discordId = $state('')
let discordUsername = $state('')
let telegramUsername = $state('')
let signalNumber = $state('')
let signalUsername = $state('')
let handleAvailable = $state<boolean | null>(null)
let checkingHandle = $state(false)
@@ -204,11 +204,11 @@
case 'email':
return !!email.trim()
case 'discord':
return !!discordId.trim()
return !!discordUsername.trim()
case 'telegram':
return !!telegramUsername.trim()
case 'signal':
return !!signalNumber.trim()
return !!signalUsername.trim()
default:
return false
}
@@ -281,9 +281,9 @@
email: email || null,
invite_code: inviteCode || null,
verification_channel: verificationChannel,
discord_id: discordId || null,
discord_username: discordUsername || null,
telegram_username: telegramUsername || null,
signal_number: signalNumber || null,
signal_username: signalUsername || null,
did_type: didType,
did: didType === 'web-external' ? externalDid.trim() : null,
}),
@@ -452,16 +452,15 @@
</div>
{:else if verificationChannel === 'discord'}
<div class="field">
<label for="discord-id">{$_('register.discordId')}</label>
<label for="discord-username">{$_('register.discordUsername')}</label>
<input
id="discord-id"
id="discord-username"
type="text"
bind:value={discordId}
placeholder={$_('register.discordIdPlaceholder')}
bind:value={discordUsername}
placeholder={$_('register.discordUsernamePlaceholder')}
disabled={submitting}
required
/>
<p class="hint">{$_('register.discordIdHint')}</p>
</div>
{:else if verificationChannel === 'telegram'}
<div class="field">
@@ -477,16 +476,16 @@
</div>
{:else if verificationChannel === 'signal'}
<div class="field">
<label for="signal-number">{$_('register.signalNumber')}</label>
<label for="signal-number">{$_('register.signalUsername')}</label>
<input
id="signal-number"
type="tel"
bind:value={signalNumber}
placeholder={$_('register.signalNumberPlaceholder')}
bind:value={signalUsername}
placeholder={$_('register.signalUsernamePlaceholder')}
disabled={submitting}
required
/>
<p class="hint">{$_('register.signalNumberHint')}</p>
<p class="hint">{$_('register.signalUsernameHint')}</p>
</div>
{/if}
</div>
+24 -8
View File
@@ -33,6 +33,8 @@
let tokenFromUrl = $state(false)
let oauthRequestUri = $state<string | null>(null)
let telegramBotUsername = $state<string | undefined>(undefined)
let discordBotUsername = $state<string | undefined>(undefined)
let discordAppId = $state<string | undefined>(undefined)
const auth = $derived(getAuthState())
@@ -42,6 +44,8 @@
const session = $derived(getSession())
const isTelegram = $derived(pendingVerification?.channel === 'telegram')
const isDiscord = $derived(pendingVerification?.channel === 'discord')
const isBotVerified = $derived(isTelegram || isDiscord)
function parseQueryParams(): Record<string, string> {
return Object.fromEntries(new URLSearchParams(window.location.search))
@@ -102,10 +106,12 @@
}))
}
if (pendingVerification?.channel === 'telegram') {
if (pendingVerification?.channel === 'telegram' || pendingVerification?.channel === 'discord') {
try {
const serverInfo = await api.describeServer()
telegramBotUsername = serverInfo.telegramBotUsername
discordBotUsername = serverInfo.discordBotUsername
discordAppId = serverInfo.discordAppId
} catch {
}
}
@@ -121,10 +127,10 @@
let pollingVerification = false
$effect(() => {
if (mode === 'signup' && pendingVerification && (isTelegram || !verificationCode.trim())) {
if (mode === 'signup' && pendingVerification && (isBotVerified || !verificationCode.trim())) {
const currentPending = pendingVerification
const interval = setInterval(async () => {
if (pollingVerification || (!isTelegram && verificationCode.trim())) return
if (pollingVerification || (!isBotVerified && verificationCode.trim())) return
pollingVerification = true
try {
const result = await api.checkChannelVerified(currentPending.did, currentPending.channel)
@@ -447,7 +453,7 @@
{#if isTelegram && telegramBotUsername}
{@const encodedHandle = pendingVerification.handle.replaceAll('.', '_')}
<div class="telegram-hint">
<div class="bot-hint">
<p>
<a href="https://t.me/{telegramBotUsername}?start={encodedHandle}" target="_blank" rel="noopener">{$_('comms.telegramOpenLink')}</a>
</p>
@@ -456,6 +462,16 @@
</p>
<p class="waiting-text">{$_('verify.pleaseWait')}</p>
</div>
{:else if isDiscord && discordAppId}
<div class="bot-hint">
<p>
<a href="https://discord.com/users/{discordAppId}" target="_blank" rel="noopener">{$_('comms.discordOpenLink')}</a>
</p>
<p class="manual-text">
{$_('comms.discordStartBot', { values: { botUsername: discordBotUsername ?? 'the bot', handle: pendingVerification.handle } })}
</p>
<p class="waiting-text">{$_('verify.pleaseWait')}</p>
</div>
{:else}
<form onsubmit={(e) => { e.preventDefault(); handleSignupVerification(e); }}>
<div class="field">
@@ -610,23 +626,23 @@
padding: var(--space-4) var(--space-8);
}
.telegram-hint {
.bot-hint {
padding: var(--space-4);
background: var(--bg-secondary);
border-radius: var(--radius-md);
}
.telegram-hint p {
.bot-hint p {
margin: 0;
}
.telegram-hint .manual-text {
.bot-hint .manual-text {
font-size: var(--text-sm);
color: var(--text-secondary);
margin-top: var(--space-1);
}
.telegram-hint .waiting-text {
.bot-hint .waiting-text {
font-size: var(--text-sm);
color: var(--text-secondary);
margin-top: var(--space-2);
+2 -2
View File
@@ -254,11 +254,11 @@ export const mockData = {
notificationPrefs: (overrides?: Record<string, unknown>) => ({
preferredChannel: "email",
email: "test@example.com",
discordId: null,
discordUsername: null,
discordVerified: false,
telegramUsername: null,
telegramVerified: false,
signalNumber: null,
signalUsername: null,
signalVerified: false,
...overrides,
}),