spb/groupe-ka Public
Groupe KA — site du holding + KA ID (compte unique & SSO des 7 plateformes). Next.js 16, SQLite, Google & Apple login.
TypeScript 93.9%
CSS 6%
1// Auteur : Simon-Pierre Boucher — contact@spboucher.ai2"use client";34import { useState } from "react";5import { ROLES } from "@/lib/roles";67export default function RolePicker({ current }: { current: string | null }) {8 const [busy, setBusy] = useState<string | null>(null);9 const [error, setError] = useState<string | null>(null);1011 async function pick(role: string) {12 setBusy(role);13 setError(null);14 const res = await fetch("/api/profile/role", {15 method: "POST",16 headers: { "Content-Type": "application/json" },17 body: JSON.stringify({ role }),18 });19 if (res.ok) window.location.reload();20 else {21 setError("Impossible d'enregistrer — réessayez.");22 setBusy(null);23 }24 }2526 return (27 <div>28 <div className="grid gap-2 sm:grid-cols-3">29 {Object.entries(ROLES).map(([value, r]) => (30 <button31 key={value}32 type="button"33 disabled={busy !== null}34 onClick={() => pick(value)}35 className={`rounded-md border-[1.5px] px-4 py-3 text-left transition-all ${36 current === value37 ? "border-ink bg-lime-soft shadow-[3px_3px_0_rgba(20,24,20,0.15)]"38 : "border-[rgba(20,24,20,0.3)] bg-surface hover:border-ink"39 }`}40 >41 <span className="gk-display block text-[13.5px] font-bold">42 {busy === value ? "Un instant…" : r.label}43 </span>44 <span className="mt-[2px] block text-[11.5px] leading-snug text-ink-2">45 {r.desc}46 </span>47 </button>48 ))}49 </div>50 {error && (51 <p className="mt-2 rounded-md border-[1.5px] border-[#b3423a] bg-[#fbe9e7] px-3 py-2 text-[12.5px] font-medium text-[#7c2f2a]">52 {error}53 </p>54 )}55 </div>56 );57}58