mirror of
https://github.com/R0m1k3/PleinR.git
synced 2026-10-22 14:48:04 +02:00
Affiche les coordonnées du référent aux visiteurs connectés
L'annuaire, les pages métier et la fiche adhérent montrent désormais la personne à joindre chez l'adhérent — nom, prénom, ligne directe — mais uniquement à un visiteur connecté. Trois colonnes sur `members` (`contact_first_name`, `contact_last_name`, `contact_phone`), saisies dans les deux formulaires de fiche via le composant partagé `MemberContactFields`. Le filtrage ne repose pas sur du CSS ni sur un rendu conditionnel tardif : aucune requête publique ne lit ces colonnes. Seules `getMemberContacts()` et `getMemberContact()` les rapatrient, et les pages ne les appellent qu'après un `getSession()` positif. Un visiteur anonyme ne reçoit donc rien — ni dans le HTML, ni dans le JSON-LD, ni dans les props du composant client de l'annuaire. `tests/security.test.ts` verrouille cette séparation. `src/lib/member-contact.ts` reste pur (composition du nom, lien `tel:`) et est couvert par `tests/member-contact.test.ts`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012TAK3c4jAUqxVMzy746wWQ
This commit is contained in:
20 files changed
+1854
-7
No files matched your search
@@ -1,6 +1,7 @@
|
||||
import Link from "next/link";
|
||||
import { VitrineImage } from "@/components/VitrineImage";
|
||||
import { memberPath } from "@/lib/seo";
|
||||
import type { MemberContact } from "@/lib/member-contact";
|
||||
|
||||
export type MemberCardData = {
|
||||
id: number;
|
||||
@@ -44,8 +45,21 @@ const clampLines = (lines: number) =>
|
||||
/**
|
||||
* Carte d'un adhérent dans une grille (annuaire, page métier). Composant sans
|
||||
* état : il se rend aussi bien côté serveur que dans le filtre client.
|
||||
*
|
||||
* `contact` (nom du référent, ligne directe) n'est passé qu'aux visiteurs
|
||||
* connectés : la page ne le rapatrie pas du tout pour un visiteur anonyme, il
|
||||
* n'y a donc rien à masquer en CSS. Le numéro reste en texte simple — un
|
||||
* `tel:` imbriqué dans le lien de la carte serait un lien dans un lien.
|
||||
*/
|
||||
export function MemberCard({ m, index = 0 }: { m: MemberCardData; index?: number }) {
|
||||
export function MemberCard({
|
||||
m,
|
||||
index = 0,
|
||||
contact = null,
|
||||
}: {
|
||||
m: MemberCardData;
|
||||
index?: number;
|
||||
contact?: MemberContact | null;
|
||||
}) {
|
||||
const location = [m.address, m.city].filter(Boolean).join(" · ");
|
||||
return (
|
||||
<Link
|
||||
@@ -87,6 +101,21 @@ export function MemberCard({ m, index = 0 }: { m: MemberCardData; index?: number
|
||||
<span style={{ width: 7, height: 7, borderRadius: "50%", background: m.accent ?? "#E0A63C", flex: "0 0 auto" }} />
|
||||
<span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{location}</span>
|
||||
</div>
|
||||
{contact && (
|
||||
<div style={{ marginTop: 10, borderTop: "1px dashed #e6dcc6", paddingTop: 10 }}>
|
||||
<div style={{ fontSize: 10.5, letterSpacing: "0.1em", textTransform: "uppercase", fontWeight: 800, color: "#9a8d72", marginBottom: 4 }}>
|
||||
Contact adhérent
|
||||
</div>
|
||||
{contact.name && (
|
||||
<div style={{ fontSize: 13, fontWeight: 700, color: "#3c3322", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
|
||||
{contact.name}
|
||||
</div>
|
||||
)}
|
||||
{contact.phone && (
|
||||
<div style={{ fontSize: 12.5, color: "#6c6150", marginTop: 2 }}>{contact.phone}</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user