fix(ui): per-bot invite caption + friendly self-redeem note
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 12s
CI / ui (pull_request) Successful in 47s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 57s

- The share caption is now in the bot's language: 'Давай играть в Эрудит!' (ru bot),
  "Let's play Scrabble!" (en bot) — picked by the session service language, not the
  interface language.
- Redeeming your own invite (deep link or manual) no longer shows the scary
  'can't do that to yourself' error; it shows a friendly neutral note instead.
This commit is contained in:
Ilia Denisov
2026-06-15 16:09:10 +02:00
parent 03eb8044ff
commit 01d2d1f368
4 changed files with 26 additions and 9 deletions
+6
View File
@@ -493,8 +493,14 @@ async function routeStartParam(param: string): Promise<void> {
showToast(t('friends.added', { name: friend.displayName }));
void refreshNotifications();
} catch (err) {
// Tapping your own invite link redeems your own code: show a friendly note, not
// the scary "can't do that to yourself" error.
if (err instanceof GatewayError && err.code === 'self_relation') {
showToast(t('friends.selfInvite'));
} else {
handleError(err);
}
}
return;
default:
navigate('/');
+2 -1
View File
@@ -234,8 +234,9 @@ export const en = {
'friends.copy': 'Copy',
'friends.codeCopied': 'Code copied.',
'friends.shareTelegram': 'Share via Telegram',
'friends.inviteText': "Let's be friends in Scrabble!",
'friends.inviteText': "Let's play Scrabble!",
'friends.linkCopied': 'Link copied.',
'friends.selfInvite': "Hopefully you've been friends with yourself for a while ☺️",
'friends.added': 'Added {name}.',
'friends.blockedList': 'Blocked players',
'friends.unblock': 'Unblock',
+2 -1
View File
@@ -235,8 +235,9 @@ export const ru: Record<MessageKey, string> = {
'friends.copy': 'Копировать',
'friends.codeCopied': 'Код скопирован.',
'friends.shareTelegram': 'Поделиться через Telegram',
'friends.inviteText': 'Давай дружить в Скрэббл!',
'friends.inviteText': 'Давай играть в Эрудит!',
'friends.linkCopied': 'Ссылка скопирована.',
'friends.selfInvite': 'Надеюсь, что с собой Вы уже давно дружите ☺️',
'friends.added': 'Добавлен(а) {name}.',
'friends.blockedList': 'Заблокированные',
'friends.unblock': 'Разблокировать',
+14 -5
View File
@@ -3,7 +3,9 @@
import { app, handleError, refreshNotifications, showToast } from '../lib/app.svelte';
import { connection } from '../lib/connection.svelte';
import { gateway } from '../lib/gateway';
import { t } from '../lib/i18n/index.svelte';
import { GatewayError } from '../lib/client';
import { localeFrom, t } from '../lib/i18n/index.svelte';
import { translate } from '../lib/i18n/catalog';
import { friendCodeParam, shareLink } from '../lib/deeplink';
import { shareTelegramLink } from '../lib/telegram';
import type { AccountRef, FriendCode } from '../lib/model';
@@ -62,9 +64,13 @@
showToast(t('friends.added', { name: friend.displayName }));
await load();
} catch (e) {
if (e instanceof GatewayError && e.code === 'self_relation') {
showToast(t('friends.selfInvite')); // redeeming your own code: a friendly, non-error note
} else {
handleError(e);
}
}
}
function codeTime(unix: number): string {
return new Date(unix * 1000).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
@@ -83,8 +89,10 @@
// shareInvite shares the friend-code deep link: inside Telegram via the native
// "share to chat" picker; on the web via the system share sheet; failing both, it
// copies the link to the clipboard.
async function shareInvite(url: string) {
const text = t('friends.inviteText');
async function shareInvite(url: string, lang: string) {
// The caption is in the bot's language (Эрудит for ru, Scrabble for en), not the
// interface language — the recipient lands in that bot.
const text = translate(localeFrom(lang), 'friends.inviteText');
if (shareTelegramLink(url, text)) return;
if (typeof navigator !== 'undefined' && navigator.share) {
try {
@@ -120,7 +128,8 @@
<button class="btn" onclick={redeem} disabled={!connection.online}>{t('friends.redeem')}</button>
</div>
{#if code}
{@const tg = shareLink(friendCodeParam(code.code), app.session?.serviceLanguage || app.locale)}
{@const lang = app.session?.serviceLanguage || app.locale}
{@const tg = shareLink(friendCodeParam(code.code), lang)}
<div class="code" data-testid="friend-code">
<div class="coderow">
<button class="codeval" onclick={copyCode}>{code.code}</button>
@@ -130,7 +139,7 @@
{t('friends.codeHint')} · {t('friends.codeExpires', { time: codeTime(code.expiresAtUnix) })}
</span>
{#if tg}
<button type="button" class="link tgshare" onclick={() => shareInvite(tg)}>{t('friends.shareTelegram')}</button>
<button type="button" class="link tgshare" onclick={() => shareInvite(tg, lang)}>{t('friends.shareTelegram')}</button>
{/if}
</div>
{:else}