feat(native): device-lock i18n keys + devices store type extensions

- Add auth.device_locked_* keys (DE/EN/FR): headline, body, countdown,
  email_hint, use_original CTA, back link
- Add devices.bound_badge + devices.release_* keys (DE/EN/FR) for the
  bound-device / release-flow in the Devices page
- Extend UserDevice interface with boundToPlan and releaseRequestedAt
- Add requestRelease + cancelRelease store actions calling the new
  POST /api/devices/:id/request-release|cancel-release endpoints

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
chahinebrini 2026-05-16 00:37:12 +02:00
parent ab9472b976
commit edf047eacf
4 changed files with 74 additions and 6 deletions

View File

@ -76,7 +76,13 @@
"toLogin": "Zur Anmeldung",
"oauthFailed": "Anmeldung fehlgeschlagen",
"loginFailed": "Anmeldung fehlgeschlagen",
"registerFailed": "Registrierung fehlgeschlagen"
"registerFailed": "Registrierung fehlgeschlagen",
"device_locked_headline": "Dieses Gerät ist gesperrt",
"device_locked_body": "Du hast versucht, dich mit diesem Gerät anzumelden. Es ist aber an einen anderen Rebreak-Account gebunden. Diese Sperre schützt dich davor, im Drang-Moment dein eigenes Schutz-Setup zu umgehen.",
"device_locked_countdown": "Freigabe läuft — noch %{remaining}",
"device_locked_email_hint": "Wenn du dein Original-Konto nicht mehr kennst: Schau in deinem E-Mail-Postfach nach 'Rebreak Gerät gesperrt' — wir haben dir eine Mail geschickt.",
"device_locked_use_original": "Mit Original-Account anmelden",
"device_locked_back": "Zurück zur Anmeldung"
},
"landing": {
"appName": "Rebreak",
@ -926,7 +932,16 @@
"windows_download_button": "Datei auf Windows-PC herunterladen",
"windows_success_title": "Windows-PC geschützt!",
"windows_success_body": "Du kannst weitere Geräte hinzufügen wenn du willst.",
"windows_remove_warning_body": "Wir können die Registrierung nicht aus der Ferne löschen. Auf dem PC: Regedit → HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DoHSvc → Schlüssel entfernen."
"windows_remove_warning_body": "Wir können die Registrierung nicht aus der Ferne löschen. Auf dem PC: Regedit → HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DoHSvc → Schlüssel entfernen.",
"bound_badge": "Gebunden",
"release_request_title": "Gerät freigeben?",
"release_request_body": "Das Gerät wird nach 24 Stunden freigegeben. Du kannst die Freigabe vorher jederzeit widerrufen.",
"release_request_confirm": "Freigabe starten",
"release_countdown": "Freigabe in %{remaining}",
"release_cancel": "Freigabe abbrechen",
"release_cancel_confirm": "Freigabe wirklich abbrechen?",
"release_cancel_body": "Das Gerät bleibt weiterhin an deinen Account gebunden.",
"release_cancel_cta": "Ja, abbrechen"
},
"plan": {
"change": {

View File

@ -76,7 +76,13 @@
"toLogin": "Back to sign in",
"oauthFailed": "Sign in failed",
"loginFailed": "Sign in failed",
"registerFailed": "Registration failed"
"registerFailed": "Registration failed",
"device_locked_headline": "This device is locked",
"device_locked_body": "You tried to sign in on this device. It is bound to a different Rebreak account. This lock protects you from bypassing your own protection setup in a moment of urge.",
"device_locked_countdown": "Release in progress — %{remaining} left",
"device_locked_email_hint": "If you no longer know your original account: check your email inbox for 'Rebreak device locked' — we sent you a message.",
"device_locked_use_original": "Sign in with original account",
"device_locked_back": "Back to sign in"
},
"landing": {
"appName": "Rebreak",
@ -926,7 +932,16 @@
"windows_download_button": "Download file to Windows PC",
"windows_success_title": "Windows PC protected!",
"windows_success_body": "You can add more devices whenever you like.",
"windows_remove_warning_body": "We can't delete the registry entry remotely. On the PC: Regedit → HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DoHSvc → remove the key."
"windows_remove_warning_body": "We can't delete the registry entry remotely. On the PC: Regedit → HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DoHSvc → remove the key.",
"bound_badge": "Bound",
"release_request_title": "Release device?",
"release_request_body": "The device will be released after 24 hours. You can cancel the release at any time before that.",
"release_request_confirm": "Start release",
"release_countdown": "Release in %{remaining}",
"release_cancel": "Cancel release",
"release_cancel_confirm": "Really cancel the release?",
"release_cancel_body": "The device will remain bound to your account.",
"release_cancel_cta": "Yes, cancel"
},
"plan": {
"change": {

View File

@ -76,7 +76,13 @@
"toLogin": "Retour à la connexion",
"oauthFailed": "Connexion échouée",
"loginFailed": "Connexion échouée",
"registerFailed": "Inscription échouée"
"registerFailed": "Inscription échouée",
"device_locked_headline": "Cet appareil est verrouillé",
"device_locked_body": "Vous avez tenté de vous connecter sur cet appareil. Il est lié à un autre compte Rebreak. Ce verrou vous protège contre le contournement de votre propre configuration de protection.",
"device_locked_countdown": "Libération en cours — encore %{remaining}",
"device_locked_email_hint": "Si vous ne connaissez plus votre compte d'origine : vérifiez votre boîte e-mail pour 'Rebreak appareil verrouillé' — nous vous avons envoyé un message.",
"device_locked_use_original": "Se connecter avec le compte d'origine",
"device_locked_back": "Retour à la connexion"
},
"landing": {
"appName": "Rebreak",
@ -923,7 +929,16 @@
"windows_download_button": "Télécharger le fichier sur le PC Windows",
"windows_success_title": "PC Windows protégé !",
"windows_success_body": "Vous pouvez ajouter d'autres appareils quand vous le souhaitez.",
"windows_remove_warning_body": "Nous ne pouvons pas supprimer l'entrée de registre à distance. Sur le PC : Regedit → HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DoHSvc → supprimer la clé."
"windows_remove_warning_body": "Nous ne pouvons pas supprimer l'entrée de registre à distance. Sur le PC : Regedit → HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DoHSvc → supprimer la clé.",
"bound_badge": "Lié",
"release_request_title": "Libérer l'appareil ?",
"release_request_body": "L'appareil sera libéré après 24 heures. Vous pouvez annuler la libération à tout moment avant cela.",
"release_request_confirm": "Démarrer la libération",
"release_countdown": "Libération dans %{remaining}",
"release_cancel": "Annuler la libération",
"release_cancel_confirm": "Vraiment annuler la libération ?",
"release_cancel_body": "L'appareil restera lié à votre compte.",
"release_cancel_cta": "Oui, annuler"
},
"plan": {
"change": {

View File

@ -11,6 +11,8 @@ export interface UserDevice {
lastSeenAt: string;
createdAt: string;
isCurrent?: boolean;
boundToPlan: 'free' | 'pro' | 'legend' | 'standard' | 'premium' | null;
releaseRequestedAt: string | null;
}
type DevicesState = {
@ -22,6 +24,8 @@ type DevicesState = {
ensureRegistered: () => Promise<void>;
loadDevices: () => Promise<void>;
removeDevice: (id: string) => Promise<void>;
requestRelease: (id: string) => Promise<void>;
cancelRelease: (id: string) => Promise<void>;
};
export const useDevicesStore = create<DevicesState>((set) => ({
@ -67,4 +71,23 @@ export const useDevicesStore = create<DevicesState>((set) => ({
await apiFetch(`/api/devices/${id}`, { method: 'DELETE' });
set((s) => ({ devices: s.devices.filter((d) => d.id !== id) }));
},
requestRelease: async (id: string) => {
await apiFetch(`/api/devices/${id}/request-release`, { method: 'POST' });
const now = new Date().toISOString();
set((s) => ({
devices: s.devices.map((d) =>
d.id === id ? { ...d, releaseRequestedAt: now } : d
),
}));
},
cancelRelease: async (id: string) => {
await apiFetch(`/api/devices/${id}/cancel-release`, { method: 'POST' });
set((s) => ({
devices: s.devices.map((d) =>
d.id === id ? { ...d, releaseRequestedAt: null } : d
),
}));
},
}));