From 055c48a3fe5442800788faa0406efcaa636e17bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 8 Oct 2026 18:24:04 +0200 Subject: [PATCH] fix(handover): show the link holder display names only The claim preview is anonymous: whoever holds the link has proved nothing yet. It listed each guardian's grant id and fell back to their login name. It now carries the display name alone, null when there is none, and the page says "a guardian" for that. The notifications to the guardians fell back to the new owner's login name when the record had no display name. They now use sentences about the person the guardian looked after instead. --- docs/api/openapi.yaml | 9 +-- messages/de.json | 13 +++- messages/en.json | 13 +++- messages/es.json | 13 +++- messages/fr.json | 13 +++- messages/it.json | 13 +++- messages/ko.json | 13 +++- messages/pl.json | 13 +++- .../api/account/handover-decision/route.ts | 4 +- src/app/api/auth/claim/route.ts | 6 +- src/components/auth/claim-profile.tsx | 6 +- src/lib/managed-profiles/handover-notify.ts | 54 ++++++++++---- src/lib/managed-profiles/handover.ts | 17 +++-- src/lib/openapi/routes/auth.ts | 8 ++- src/lib/queries/use-profile-claim.ts | 3 +- .../managed-profile-handover.test.ts | 70 ++++++++++++++++++- 16 files changed, 221 insertions(+), 47 deletions(-) diff --git a/docs/api/openapi.yaml b/docs/api/openapi.yaml index fa165cf0b..4a48e3c31 100644 --- a/docs/api/openapi.yaml +++ b/docs/api/openapi.yaml @@ -41806,14 +41806,15 @@ components: items: type: object properties: - grantId: - type: string displayName: - type: string + anyOf: + - type: string + - type: "null" + description: "The guardian's display name; null when they set none. Never a login name or an id: the holder of the link + has proved nothing yet." proposal: $ref: "#/components/schemas/ProfileClaimGuardianAccess" required: - - grantId - displayName - proposal additionalProperties: false diff --git a/messages/de.json b/messages/de.json index e6ed49f5a..8734261e1 100644 --- a/messages/de.json +++ b/messages/de.json @@ -531,6 +531,7 @@ "signOut": "Abmelden und weiter", "guardiansTitle": "Wer vorerst Zugriff behält", "guardiansHint": "Vorgeschlagen von den Personen, die deine Akte geführt haben. Du entscheidest direkt nach der Anmeldung.", + "guardianUnnamed": "Eine betreuende Person", "usernameHint": "3 bis 30 Buchstaben, Ziffern, _ oder -.", "usernameReserved": "Benutzernamen, die mit managed- beginnen, sind reserviert.", "emailHint": "Pflicht, damit du wieder hineinkommst, wenn du dein Passwort vergisst.", @@ -8445,7 +8446,17 @@ "changedTitle": "{name} hat deinen Zugriff geändert", "changedEnd": "Dein Zugriff auf die Gesundheitsakte von {name} ist beendet.", "changedRead": "Du kannst die Gesundheitsakte von {name} jetzt ansehen, aber nicht ändern.", - "changedManage": "Du kannst die Gesundheitsakte von {name} verwalten." + "changedManage": "Du kannst die Gesundheitsakte von {name} verwalten.", + "unnamed": { + "claimedTitle": "Die Person, die du betreut hast, hat jetzt ein eigenes Konto", + "claimedEnd": "Die Person, die du betreut hast, hat die eigene Gesundheitsakte übernommen. Dein Zugriff ist beendet.", + "claimedRead": "Die Person, die du betreut hast, hat die eigene Gesundheitsakte übernommen. Du kannst sie weiter ansehen, aber nicht mehr ändern.", + "claimedManage": "Die Person, die du betreut hast, hat die eigene Gesundheitsakte übernommen. Du kannst sie weiter verwalten, bis sie anders entscheidet.", + "changedTitle": "Dein Zugriff auf eine Gesundheitsakte hat sich geändert", + "changedEnd": "Dein Zugriff auf die Gesundheitsakte der Person, die du betreut hast, ist beendet.", + "changedRead": "Du kannst die Gesundheitsakte der Person, die du betreut hast, jetzt ansehen, aber nicht ändern.", + "changedManage": "Du kannst die Gesundheitsakte der Person, die du betreut hast, verwalten." + } } }, "i18n": { diff --git a/messages/en.json b/messages/en.json index 80768ae02..f71d021e0 100644 --- a/messages/en.json +++ b/messages/en.json @@ -531,6 +531,7 @@ "signOut": "Sign out and continue", "guardiansTitle": "Who keeps access for now", "guardiansHint": "Proposed by the people who looked after your record. You decide right after signing in.", + "guardianUnnamed": "A guardian", "usernameHint": "3 to 30 letters, numbers, _ or -.", "usernameReserved": "Usernames starting with managed- are reserved.", "emailHint": "Required, so you can get back in if you forget your password.", @@ -8445,7 +8446,17 @@ "changedTitle": "{name} changed your access", "changedEnd": "Your access to the health record of {name} has ended.", "changedRead": "You can now view the health record of {name}, but not change it.", - "changedManage": "You can manage the health record of {name}." + "changedManage": "You can manage the health record of {name}.", + "unnamed": { + "claimedTitle": "The person you looked after now has their own account", + "claimedEnd": "The person you looked after took over their health record. Your access has ended.", + "claimedRead": "The person you looked after took over their health record. You can still view it, but no longer change it.", + "claimedManage": "The person you looked after took over their health record. You can still manage it until they decide otherwise.", + "changedTitle": "Your access to a health record changed", + "changedEnd": "Your access to the health record of the person you looked after has ended.", + "changedRead": "You can now view the health record of the person you looked after, but not change it.", + "changedManage": "You can manage the health record of the person you looked after." + } } }, "i18n": { diff --git a/messages/es.json b/messages/es.json index 850b1a3d5..5f319854a 100644 --- a/messages/es.json +++ b/messages/es.json @@ -531,6 +531,7 @@ "signOut": "Cerrar sesión y continuar", "guardiansTitle": "Quién conserva el acceso por ahora", "guardiansHint": "Lo proponen las personas que llevaron tu historial. Tú decides justo después de iniciar sesión.", + "guardianUnnamed": "Una persona tutora", "usernameHint": "De 3 a 30 letras, números, _ o -.", "usernameReserved": "Los nombres de usuario que empiezan por managed- están reservados.", "emailHint": "Obligatorio, para que puedas volver a entrar si olvidas tu contraseña.", @@ -8445,7 +8446,17 @@ "changedTitle": "{name} ha cambiado tu acceso", "changedEnd": "Tu acceso al historial de salud de {name} ha terminado.", "changedRead": "Ahora puedes ver el historial de salud de {name}, pero no cambiarlo.", - "changedManage": "Puedes gestionar el historial de salud de {name}." + "changedManage": "Puedes gestionar el historial de salud de {name}.", + "unnamed": { + "claimedTitle": "La persona a la que cuidabas ya tiene su propia cuenta", + "claimedEnd": "La persona a la que cuidabas ha asumido su historial de salud. Tu acceso ha terminado.", + "claimedRead": "La persona a la que cuidabas ha asumido su historial de salud. Puedes seguir viéndolo, pero ya no modificarlo.", + "claimedManage": "La persona a la que cuidabas ha asumido su historial de salud. Puedes seguir gestionándolo hasta que decida otra cosa.", + "changedTitle": "Tu acceso a un historial de salud ha cambiado", + "changedEnd": "Tu acceso al historial de salud de la persona a la que cuidabas ha terminado.", + "changedRead": "Ahora puedes ver el historial de salud de la persona a la que cuidabas, pero no modificarlo.", + "changedManage": "Puedes gestionar el historial de salud de la persona a la que cuidabas." + } } }, "i18n": { diff --git a/messages/fr.json b/messages/fr.json index bf868b356..8b23e5da4 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -531,6 +531,7 @@ "signOut": "Se déconnecter et continuer", "guardiansTitle": "Qui garde l'accès pour l'instant", "guardiansHint": "Proposé par les personnes qui ont tenu votre dossier. Vous décidez juste après la connexion.", + "guardianUnnamed": "Un tuteur", "usernameHint": "3 à 30 lettres, chiffres, _ ou -.", "usernameReserved": "Les noms d'utilisateur commençant par managed- sont réservés.", "emailHint": "Obligatoire, pour pouvoir revenir si vous oubliez votre mot de passe.", @@ -8445,7 +8446,17 @@ "changedTitle": "{name} a modifié votre accès", "changedEnd": "Votre accès au dossier de santé de {name} a pris fin.", "changedRead": "Vous pouvez désormais consulter le dossier de santé de {name}, sans le modifier.", - "changedManage": "Vous pouvez gérer le dossier de santé de {name}." + "changedManage": "Vous pouvez gérer le dossier de santé de {name}.", + "unnamed": { + "claimedTitle": "La personne dont vous vous occupiez a maintenant son propre compte", + "claimedEnd": "La personne dont vous vous occupiez a repris son dossier de santé. Votre accès a pris fin.", + "claimedRead": "La personne dont vous vous occupiez a repris son dossier de santé. Vous pouvez toujours le consulter, mais plus le modifier.", + "claimedManage": "La personne dont vous vous occupiez a repris son dossier de santé. Vous pouvez toujours le gérer jusqu'à ce qu'elle en décide autrement.", + "changedTitle": "Votre accès à un dossier de santé a changé", + "changedEnd": "Votre accès au dossier de santé de la personne dont vous vous occupiez a pris fin.", + "changedRead": "Vous pouvez désormais consulter le dossier de santé de la personne dont vous vous occupiez, mais pas le modifier.", + "changedManage": "Vous pouvez gérer le dossier de santé de la personne dont vous vous occupiez." + } } }, "i18n": { diff --git a/messages/it.json b/messages/it.json index 027d66121..a6eacb8d0 100644 --- a/messages/it.json +++ b/messages/it.json @@ -531,6 +531,7 @@ "signOut": "Esci e continua", "guardiansTitle": "Chi mantiene l'accesso per ora", "guardiansHint": "Proposto dalle persone che hanno tenuto la tua cartella. Decidi subito dopo l'accesso.", + "guardianUnnamed": "Un tutore", "usernameHint": "Da 3 a 30 lettere, numeri, _ o -.", "usernameReserved": "I nomi utente che iniziano con managed- sono riservati.", "emailHint": "Obbligatorio, così puoi rientrare se dimentichi la password.", @@ -8445,7 +8446,17 @@ "changedTitle": "{name} ha cambiato il tuo accesso", "changedEnd": "Il tuo accesso alla cartella sanitaria di {name} è terminato.", "changedRead": "Ora puoi vedere la cartella sanitaria di {name}, ma non modificarla.", - "changedManage": "Puoi gestire la cartella sanitaria di {name}." + "changedManage": "Puoi gestire la cartella sanitaria di {name}.", + "unnamed": { + "claimedTitle": "La persona di cui ti occupavi ora ha un proprio account", + "claimedEnd": "La persona di cui ti occupavi ha preso in carico la propria cartella sanitaria. Il tuo accesso è terminato.", + "claimedRead": "La persona di cui ti occupavi ha preso in carico la propria cartella sanitaria. Puoi ancora consultarla, ma non più modificarla.", + "claimedManage": "La persona di cui ti occupavi ha preso in carico la propria cartella sanitaria. Puoi ancora gestirla finché non deciderà diversamente.", + "changedTitle": "Il tuo accesso a una cartella sanitaria è cambiato", + "changedEnd": "Il tuo accesso alla cartella sanitaria della persona di cui ti occupavi è terminato.", + "changedRead": "Ora puoi consultare la cartella sanitaria della persona di cui ti occupavi, ma non modificarla.", + "changedManage": "Puoi gestire la cartella sanitaria della persona di cui ti occupavi." + } } }, "i18n": { diff --git a/messages/ko.json b/messages/ko.json index 876e78ced..2510e0b3d 100644 --- a/messages/ko.json +++ b/messages/ko.json @@ -531,6 +531,7 @@ "signOut": "로그아웃하고 계속", "guardiansTitle": "당분간 접근 권한을 유지하는 사람", "guardiansHint": "기록을 관리해 온 사람들이 제안한 내용입니다. 로그인한 직후에 직접 결정합니다.", + "guardianUnnamed": "보호자", "usernameHint": "영문자, 숫자, _ 또는 - 로 3~30자.", "usernameReserved": "managed- 로 시작하는 사용자 이름은 예약되어 있습니다.", "emailHint": "비밀번호를 잊었을 때 다시 들어올 수 있도록 필요합니다.", @@ -8445,7 +8446,17 @@ "changedTitle": "{name} 님이 내 접근 권한을 바꿨습니다", "changedEnd": "{name} 님의 건강 기록에 대한 내 접근 권한이 종료되었습니다.", "changedRead": "이제 {name} 님의 건강 기록을 볼 수는 있지만 변경할 수는 없습니다.", - "changedManage": "{name} 님의 건강 기록을 관리할 수 있습니다." + "changedManage": "{name} 님의 건강 기록을 관리할 수 있습니다.", + "unnamed": { + "claimedTitle": "돌보던 분이 이제 자신의 계정을 갖게 되었어요", + "claimedEnd": "돌보던 분이 자신의 건강 기록을 넘겨받았어요. 내 접근 권한은 종료되었어요.", + "claimedRead": "돌보던 분이 자신의 건강 기록을 넘겨받았어요. 계속 볼 수는 있지만 더 이상 변경할 수 없어요.", + "claimedManage": "돌보던 분이 자신의 건강 기록을 넘겨받았어요. 그분이 다르게 결정할 때까지 계속 관리할 수 있어요.", + "changedTitle": "건강 기록에 대한 접근 권한이 변경되었어요", + "changedEnd": "돌보던 분의 건강 기록에 대한 접근 권한이 종료되었어요.", + "changedRead": "이제 돌보던 분의 건강 기록을 볼 수 있지만 변경할 수는 없어요.", + "changedManage": "돌보던 분의 건강 기록을 관리할 수 있어요." + } } }, "i18n": { diff --git a/messages/pl.json b/messages/pl.json index 3686c9349..e6536a5bc 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -531,6 +531,7 @@ "signOut": "Wyloguj i kontynuuj", "guardiansTitle": "Kto na razie zachowuje dostęp", "guardiansHint": "Zaproponowane przez osoby, które prowadziły Twoją kartę. Zdecydujesz zaraz po zalogowaniu.", + "guardianUnnamed": "Opiekun", "usernameHint": "Od 3 do 30 liter, cyfr, _ lub -.", "usernameReserved": "Nazwy użytkownika zaczynające się od managed- są zarezerwowane.", "emailHint": "Wymagany, żebyś mógł wrócić, jeśli zapomnisz hasła.", @@ -8445,7 +8446,17 @@ "changedTitle": "{name} zmienia Twój dostęp", "changedEnd": "Twój dostęp do karty zdrowia osoby {name} się zakończył.", "changedRead": "Możesz teraz oglądać kartę zdrowia osoby {name}, ale nie zmieniać jej.", - "changedManage": "Możesz zarządzać kartą zdrowia osoby {name}." + "changedManage": "Możesz zarządzać kartą zdrowia osoby {name}.", + "unnamed": { + "claimedTitle": "Osoba pod Twoją opieką ma teraz własne konto", + "claimedEnd": "Osoba pod Twoją opieką przejęła swoją dokumentację zdrowotną. Twój dostęp wygasł.", + "claimedRead": "Osoba pod Twoją opieką przejęła swoją dokumentację zdrowotną. Nadal możesz ją przeglądać, ale nie możesz już jej zmieniać.", + "claimedManage": "Osoba pod Twoją opieką przejęła swoją dokumentację zdrowotną. Nadal możesz nią zarządzać, dopóki nie zdecyduje inaczej.", + "changedTitle": "Twój dostęp do dokumentacji zdrowotnej się zmienił", + "changedEnd": "Twój dostęp do dokumentacji zdrowotnej osoby pod Twoją opieką wygasł.", + "changedRead": "Możesz teraz przeglądać dokumentację zdrowotną osoby pod Twoją opieką, ale nie możesz jej zmieniać.", + "changedManage": "Możesz zarządzać dokumentacją zdrowotną osoby pod Twoją opieką." + } } }, "i18n": { diff --git a/src/app/api/account/handover-decision/route.ts b/src/app/api/account/handover-decision/route.ts index 5cb55276c..0824d3ab2 100644 --- a/src/app/api/account/handover-decision/route.ts +++ b/src/app/api/account/handover-decision/route.ts @@ -92,11 +92,11 @@ export const POST = apiHandler(async (request: NextRequest) => { if (result.changed.length > 0) { const self = await prisma.user.findUnique({ where: { id: user.id }, - select: { displayName: true, username: true }, + select: { displayName: true }, }); notifyGuardiansOfHandover( "changed", - self?.displayName?.trim() || self?.username || user.username, + self?.displayName ?? null, result.changed, ); } diff --git a/src/app/api/auth/claim/route.ts b/src/app/api/auth/claim/route.ts index d432ce20b..82bba356d 100644 --- a/src/app/api/auth/claim/route.ts +++ b/src/app/api/auth/claim/route.ts @@ -138,11 +138,7 @@ export const POST = apiHandler(async (request: NextRequest) => { details: { method: "password" }, }); - notifyGuardiansOfHandover( - "claimed", - claimed.displayName ?? claimed.username, - claimed.guardians, - ); + notifyGuardiansOfHandover("claimed", claimed.displayName, claimed.guardians); annotate({ action: { name: "profile_claim.complete" }, diff --git a/src/components/auth/claim-profile.tsx b/src/components/auth/claim-profile.tsx index c19b25d1b..1b9713839 100644 --- a/src/components/auth/claim-profile.tsx +++ b/src/components/auth/claim-profile.tsx @@ -219,15 +219,15 @@ export function ClaimProfile({ token }: { token: string | null }) { {data.guardians.length > 0 ? (