// Auteur : Simon-Pierre Boucher — contact@spboucher.ai // Mon compte — la carte de membre Groupe KA (même gabarit que sur Lou·Ka : // carte KA-ID, grille d'informations, plateformes, actions). import type { Metadata } from "next"; import { redirect } from "next/navigation"; import QRCode from "qrcode"; import { getSessionUser } from "@/lib/auth"; import { ensureKaId } from "@/lib/db"; import { SSO_CLIENTS } from "@/lib/sso"; import { roleLabel, roleCard } from "@/lib/roles"; import { db, parseSocials, favoritesOf, type UserRow, type FavoriteRow, } from "@/lib/db"; import RemoveFavorite from "./RemoveFavorite"; import LogoutButton from "./LogoutButton"; import CopyKaId from "./CopyKaId"; import AvatarEditor from "./AvatarEditor"; import RolePicker from "./RolePicker"; import ProfileForm from "./ProfileForm"; import CopyText from "./CopyText"; export const metadata: Metadata = { title: "Mon KA ID | Groupe KA", description: "Votre compte unique pour les plateformes du Groupe KA.", }; export const dynamic = "force-dynamic"; const PLATFORM_URLS: Record = { "lou-ka": "https://www.lou-ka.com", "immo-ka": "https://www.immo-ka.com", "vrai-prix": "https://www.vrai-prix.com", valoplex: "https://www.valoplex.com", "auto-ka": "https://www.auto-ka.com", "fabri-ka": "https://www.fabri-ka.com", "food-ka": "https://www.food-ka.com", "ora-ka": "https://www.ora-ka.com", }; function fmtDate(iso: string | null): string { if (!iso) return "—"; const d = new Date(iso.includes("T") ? iso : iso.replace(" ", "T") + "Z"); if (Number.isNaN(d.getTime())) return "—"; return d .toLocaleDateString("fr-CA", { day: "numeric", month: "long", year: "numeric", }) .replace(/^1 /, "1ᵉʳ "); } const APP_ACCENTS: Record = { "lou-ka": "#d9f26b", "immo-ka": "#e23744", "vrai-prix": "#ff5148", valoplex: "#ff9f45", "auto-ka": "#ff5a2a", "fabri-ka": "#C4532E", "food-ka": "#d9f26b", "ora-ka": "#d9f26b", }; function UniversSection({ userId }: { userId: number }) { const favs = favoritesOf(userId); const byApp = new Map(); for (const f of favs) { if (!byApp.has(f.app)) byApp.set(f.app, []); byApp.get(f.app)!.push(f); } return (

Mon univers Ka · tous mes coups de cœur

Ce que j'ai sauvegardé, partout

{favs.length === 0 ? (

Vos coups de cœur des plateformes ·Ka apparaîtront ici — tapez ♥ sur un logement (Lou·Ka), une propriété (Immo·Ka), une auto (Auto·Ka), un produit d'ici (Fabri·Ka) ou une aubaine d'épicerie (Food·Ka).

) : (
{[...byApp.entries()].map(([app, items]) => (

    {items.map((f) => (
  • {f.image_url ? ( // eslint-disable-next-line @next/next/no-img-element ) : ( )}
    {f.title} {f.subtitle && (

    {f.subtitle}

    )} {f.price_label && (

    {f.price_label}

    )}
  • ))}
))}
)}
); } function ProfileSection({ userId, kaId }: { userId: number; kaId: string }) { const row = db .prepare("SELECT * FROM users WHERE id = ?") .get(userId) as UserRow; return (

Mon profil · une saisie, sept plateformes

Personnaliser mon profil

); } export default async function Compte() { const user = await getSessionUser(); if (!user) redirect("/connexion?next=%2Fcompte"); const kaId = user.kaId ?? ensureKaId(user.id); // Code QR de la carte → page de vérification publique du KA-ID const qr = await QRCode.toDataURL(`https://www.groupe-ka.com/m/${kaId}`, { margin: 0, width: 220, color: { dark: "#141814", light: "#ffffff" }, }); const infos: [string, React.ReactNode][] = [ ["Nom", user.name || "—"], ["Courriel", user.email], [ "Identifiant membre", {kaId}, ], ["Type de compte", roleLabel(user.role) ?? "À choisir ci-dessous"], [ "Connexion", (() => { const modes = [ user.hasGoogle && "Google", user.hasApple && "Apple", user.hasPassword && "mot de passe", ].filter(Boolean) as string[]; return modes.length ? modes.join(" + ") : "Courriel et mot de passe"; })(), ], ["Membre depuis", fmtDate(user.createdAt)], ["Dernière connexion", fmtDate(user.lastLogin)], ]; return (

Mon compte · KA ID

Salut, {user.name.split(" ")[0]}.

{/* ——— Carte de membre Groupe KA ——— */}
Groupe KA Carte de membre · Groupe KA
KA-ID {kaId}
{/* eslint-disable-next-line @next/next/no-img-element */} {`Code
{user.name || user.email} {roleCard(user.role) && ( {roleCard(user.role)} )} Membre depuis le {fmtDate(user.createdAt)}
{user.avatarUrl ? ( // eslint-disable-next-line @next/next/no-img-element ) : ( {(user.name || user.email).charAt(0).toUpperCase()} )}
{process.env.KA_PASS_DIR && process.env.KA_PASS_TYPE_ID && ( Ajouter à Apple Wallet )}
{/* ——— Type de compte (obligatoire — les comptes Google le choisissent ici) ——— */} {!user.role && (

Une dernière chose · vous êtes…

Choisissez votre type de compte — il sera affiché sur votre carte de membre.

)} {/* ——— Photo de profil ——— */}
{user.avatarUrl ? ( // eslint-disable-next-line @next/next/no-img-element ) : ( {(user.name || user.email).charAt(0).toUpperCase()} )}

Photo de profil

{/* ——— Mon univers Ka (favoris unifiés) ——— */} {/* ——— Mon profil (source de vérité pour toutes les plateformes) ——— */} {/* ——— Informations ——— */}
{infos.map(([label, value], i) => (

{label}

{value}

))}

Votre KA-ID est votre identifiant unique dans tout l'écosystème Groupe KA — il vous suit sur chaque plateforme. Le hub ne conserve que ce profil : rien d'autre, et jamais revendu.

{/* ——— Carte physique & NFC ——— */}

Carte physique · NFC

Votre carte, en vrai

Imprimez votre carte au format carte bancaire et collez-y un autocollant NFC (NTAG215, ~1 $) : un simple tap sur un iPhone ou un Android ouvre votre page d'identification — comme le code QR, sans appli.

    {[ <>Procurez-vous des autocollants NTAG215 (Amazon, ~10 $ les 10)., <>Installez l'appli gratuite NFC Tools (iPhone ou Android)., <>Onglet Écrire → Ajouter un enregistrement → URL → collez le lien ci-dessus → Écrire, en tenant la puce contre le téléphone., <>Optionnel : Verrouiller le tag pour le rendre non modifiable (irréversible)., <>Collez la puce au dos de la carte imprimée, dans la zone « NFC »., ].map((step, i) => (
  1. 0{i + 1} {step}
  2. ))}
{/* ——— Plateformes ——— */}

Un compte · sept portes

Votre KA ID fonctionne ici

Sur chaque plateforme, choisissez « Se connecter avec KA ID » : vous arrivez déjà connecté, avec le même profil et le même KA-ID.

{/* ——— Actions ——— */}
); }