mirror of
https://github.com/IliesAllali/parenthese.git
synced 2026-11-15 16:32:03 +00:00
fix(entree): connexion visible, porte qui reconnaît le compte, libellés
- Démo : le bouton « Se connecter » ouvre la connexion, plus l'inscription - Porte de l'arbre : quand la personne est connectée, un bandeau dit quel compte est ouvert et qu'il faut taper une fois le mot de passe reçu avec le lien. Il reste affiché au retour d'une connexion faite depuis la porte. - Landing : lien « Se connecter » dans la navigation et le pied de page (vers ?account=login, sans source, le rendu au build n'a pas de window) - Libellés de la porte et de l'inscription, en français et en anglais Vérifié : vitest 154/154, eslint frontend, vite build, landing (test et build). La landing n'a pas de configuration eslint dans le dépôt. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f8d4b4113d
commit
f1ecb3951c
8 files changed
+56
-15
No files matched your search
@@ -2751,6 +2751,8 @@ function App() {
|
||||
treeNotFound={treeNotFound}
|
||||
loading={tree.gateLoading}
|
||||
errorMessage={tree.gateError}
|
||||
connected={Boolean(auth.userAuth.token)}
|
||||
connectedName={accountUser?.firstName || ''}
|
||||
onSubmit={handleGateUnlock}
|
||||
onUseDemo={handleUseDemo}
|
||||
onUseAccount={handleUseAccount}
|
||||
|
||||
@@ -23,6 +23,8 @@ const AccessGate = ({
|
||||
treeNotFound = false,
|
||||
loading,
|
||||
errorMessage,
|
||||
connected = false,
|
||||
connectedName = '',
|
||||
onSubmit,
|
||||
onUseAccount,
|
||||
}) => {
|
||||
@@ -86,6 +88,21 @@ const AccessGate = ({
|
||||
|
||||
{!treeNotFound && (
|
||||
<div className="pz-auth-form">
|
||||
{connected && (
|
||||
<div className="access-gate-session" role="status">
|
||||
{connectedName ? (
|
||||
/^[aeiouyàâäéèêëîïôöùûüh]/i.test(connectedName)
|
||||
? t("Vous êtes sur le compte d'{name}", { name: connectedName })
|
||||
: t('Vous êtes sur le compte de {name}', { name: connectedName })
|
||||
) : (
|
||||
t('Vous êtes sur votre compte.')
|
||||
)}
|
||||
<span className="access-gate-session-step">
|
||||
{t("Tapez une fois le mot de passe reçu avec le lien. Ensuite, l'arbre s'ouvrira directement.")}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!initialTreeId && (
|
||||
<div className="pz-field">
|
||||
<label htmlFor="treeId">{t("Code de l'arbre")}</label>
|
||||
@@ -103,7 +120,7 @@ const AccessGate = ({
|
||||
)}
|
||||
|
||||
<div className="pz-field">
|
||||
<label htmlFor="visitorFirstName">{t('Votre prénom')}</label>
|
||||
<label htmlFor="visitorFirstName">{t('Votre prénom (facultatif)')}</label>
|
||||
<input
|
||||
id="visitorFirstName"
|
||||
type="text"
|
||||
@@ -113,11 +130,11 @@ const AccessGate = ({
|
||||
autoComplete="given-name"
|
||||
maxLength={60}
|
||||
/>
|
||||
<p className="pz-hint">{t("Facultatif. Il sert à savoir qui est venu voir l'arbre.")}</p>
|
||||
<p className="pz-hint">{t("Il sert à savoir qui est venu voir l'arbre.")}</p>
|
||||
</div>
|
||||
|
||||
<div className="pz-field">
|
||||
<label htmlFor="sharePassword">{t('Mot de passe de partage')}</label>
|
||||
<label htmlFor="sharePassword">{t('Mot de passe reçu avec le lien')}</label>
|
||||
<input
|
||||
id="sharePassword"
|
||||
type="password"
|
||||
@@ -135,13 +152,13 @@ const AccessGate = ({
|
||||
|
||||
{!treeNotFound && (
|
||||
<button type="submit" className="pz-btn pz-btn--primary pz-btn--block" disabled={loading}>
|
||||
<PzBusy busy={loading} busyLabel={t("Ouverture de l'arbre")}>{t("Ouvrir l'arbre")}</PzBusy>
|
||||
<PzBusy busy={loading} busyLabel={t("Ouverture de l'arbre")}>{t("Voir l'arbre")}</PzBusy>
|
||||
</button>
|
||||
)}
|
||||
|
||||
{treeNotFound && onUseAccount && (
|
||||
<button type="button" className="pz-btn pz-btn--primary pz-btn--block" onClick={() => onUseAccount('register')} disabled={loading}>
|
||||
{t('Créer mon arbre')}
|
||||
{t('Créer mon propre arbre')}
|
||||
</button>
|
||||
)}
|
||||
</form>
|
||||
@@ -149,10 +166,10 @@ const AccessGate = ({
|
||||
{onUseAccount && !treeNotFound && (
|
||||
<div className="pz-account-foot">
|
||||
<button type="button" className="pz-btn pz-btn--ghost pz-btn--sm" onClick={() => onUseAccount('login')} disabled={loading}>
|
||||
{t('Se connecter avec un compte')}
|
||||
{t("J'ai déjà un compte")}
|
||||
</button>
|
||||
<button type="button" className="pz-btn pz-btn--ghost pz-btn--sm" onClick={() => onUseAccount('register')} disabled={loading}>
|
||||
{t('Créer un compte')}
|
||||
{t("Je n'ai pas de compte")}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -203,19 +203,19 @@ const AccountDashboard = ({
|
||||
disabled={loading}
|
||||
>
|
||||
<KeyRound size={16} aria-hidden="true" />
|
||||
{t('Ouvrir un arbre partagé avec moi')}
|
||||
{t("J'ai reçu un lien de famille")}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p className="pz-auth-switch pz-small">
|
||||
{isRegister ? t('Vous avez déjà un compte ?') : t('Pas encore de compte ?')}{' '}
|
||||
{isRegister ? t('Déjà inscrit ?') : t('Pas encore de compte ?')}{' '}
|
||||
<button
|
||||
type="button"
|
||||
className="pz-link account-signup-toggle"
|
||||
onClick={() => setMode(isRegister ? 'login' : 'register')}
|
||||
disabled={loading}
|
||||
>
|
||||
{isRegister ? t('Me connecter') : t('Créer un compte')}
|
||||
{isRegister ? t('Se connecter') : t('Créer un compte')}
|
||||
</button>
|
||||
</p>
|
||||
|
||||
|
||||
@@ -41,6 +41,10 @@
|
||||
.pz-gate-owner-text { display: grid; gap: 2px; min-width: 0; }
|
||||
.pz-gate-owner-text strong { color: var(--pz-ink); font-weight: 500; }
|
||||
|
||||
/* Porte, personne déjà connectée : dit quel compte est ouvert et ce qu'il faut faire une fois */
|
||||
.access-gate-session { display: grid; gap: 4px; padding: 12px 14px; border-radius: var(--pz-r-m); background: var(--pz-a50); border: 1px solid var(--pz-a100); color: var(--pz-ink); font: 400 14px/1.45 var(--pz-sans); }
|
||||
.access-gate-session-step { color: var(--pz-ink-2); }
|
||||
|
||||
/* Fenêtre « Mon compte » (personne liée) */
|
||||
.ap-linked { display: flex; gap: 12px; align-items: center; padding: 12px 14px; border-radius: var(--pz-r-m); background: var(--pz-a50); border: 1px solid var(--pz-a100); }
|
||||
.ap-avatar { width: 44px; height: 44px; flex: none; display: grid; place-items: center; overflow: hidden; border-radius: 50%; background: var(--pz-a100); color: var(--pz-a700); font: 400 20px/1 var(--pz-serif); }
|
||||
|
||||
@@ -307,7 +307,7 @@ function ContextualNavbar({
|
||||
<NavButton
|
||||
icon={<User size={20} strokeWidth={2} />}
|
||||
label={authenticated ? t('Mon compte') : t('Se connecter')}
|
||||
onClick={() => onProfileClick?.(authenticated ? 'login' : 'register')}
|
||||
onClick={() => onProfileClick?.('login')}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -205,4 +205,16 @@ export default {
|
||||
"Visiteur": "Visitor",
|
||||
"Exemple": "Example",
|
||||
"Arbre exemple": "Sample tree",
|
||||
"Votre prénom (facultatif)": "Your first name (optional)",
|
||||
"Il sert à savoir qui est venu voir l'arbre.": "It shows who came to see the tree.",
|
||||
"Mot de passe reçu avec le lien": "Password received with the link",
|
||||
"Créer mon propre arbre": "Create my own tree",
|
||||
"J'ai déjà un compte": "I already have an account",
|
||||
"Je n'ai pas de compte": "I don't have an account",
|
||||
"J'ai reçu un lien de famille": "I received a family link",
|
||||
"Déjà inscrit ?": "Already signed up?",
|
||||
"Vous êtes sur le compte d'{name}": "You are signed in as {name}",
|
||||
"Vous êtes sur le compte de {name}": "You are signed in as {name}",
|
||||
"Vous êtes sur votre compte.": "You are signed in to your account.",
|
||||
"Tapez une fois le mot de passe reçu avec le lien. Ensuite, l'arbre s'ouvrira directement.": "Enter the password you received with the link once. After that, the tree opens directly.",
|
||||
}
|
||||
+6
-2
@@ -769,7 +769,7 @@ function HeroGraph({ className = '', label }) {
|
||||
|
||||
// ─── Header ───────────────────────────────────────────────────────────────────
|
||||
|
||||
function Header({ t, onCta, elevated }) {
|
||||
function Header({ t, onCta, loginHref, elevated }) {
|
||||
return (
|
||||
<header className={`site-nav${elevated ? ' is-elevated' : ''}`}>
|
||||
<div className="wrap nav-in">
|
||||
@@ -778,6 +778,7 @@ function Header({ t, onCta, elevated }) {
|
||||
<a href="#comment">{t.nav.how}</a>
|
||||
<a href="#demo">{t.nav.demo}</a>
|
||||
{t.nav.privacy && <a href={t.privacyHref}>{t.nav.privacy}</a>}
|
||||
<a href={loginHref}>{t.nav.login}</a>
|
||||
</nav>
|
||||
<button type="button" onClick={onCta} className="btn p sm">{t.cta}</button>
|
||||
</div>
|
||||
@@ -910,6 +911,8 @@ const appSource = () => {
|
||||
|
||||
// Les CTA mènent à la création de compte dans l'app
|
||||
const appSignupUrl = () => `https://app.parenthese.io/?account=register&source=${appSource()}`
|
||||
// Un compte déjà créé : la connexion, pas l'inscription (sans source : rendu au build, pas de window)
|
||||
const appLoginUrl = () => 'https://app.parenthese.io/?account=login'
|
||||
|
||||
export default function App({ locale = 'fr' }) {
|
||||
const t = COPY[locale]
|
||||
@@ -985,7 +988,7 @@ export default function App({ locale = 'fr' }) {
|
||||
return (
|
||||
<div className="min-h-screen">
|
||||
|
||||
<Header t={t} onCta={() => goToSignup('header')} elevated={headerElevated} />
|
||||
<Header t={t} onCta={() => goToSignup('header')} loginHref={withAppQuery(appLoginUrl(), locale)} elevated={headerElevated} />
|
||||
<main>
|
||||
|
||||
{/* ─── HERO ────────────────────────────────────────────────────── */}
|
||||
@@ -1122,6 +1125,7 @@ export default function App({ locale = 'fr' }) {
|
||||
<Logo height={18} />
|
||||
<nav aria-label={t.footer.label}>
|
||||
{t.footer.guides && <a href="#guides">{t.footer.guides}</a>}
|
||||
<a href={withAppQuery(appLoginUrl(), locale)}>{t.footer.login}</a>
|
||||
<a href={t.privacyHref}>{t.footer.privacy}</a>
|
||||
<a href="https://github.com/IliesAllali/parenthese" rel="noopener noreferrer">{t.footer.source}</a>
|
||||
<a href="https://iliesallali.design/">{t.footer.madeBy}</a>
|
||||
|
||||
+4
-2
@@ -29,7 +29,7 @@ export const COPY = {
|
||||
appQuery: '',
|
||||
otherLang: { href: '/en/', hrefLang: 'en', label: 'EN', title: 'English version' },
|
||||
logoHome: 'Parenthèse, accueil',
|
||||
nav: { how: 'Comment ça marche', demo: 'Un exemple', privacy: 'Vie privée' },
|
||||
nav: { how: 'Comment ça marche', demo: 'Un exemple', privacy: 'Vie privée', login: 'Se connecter' },
|
||||
privacyHref: '/donnees-et-vie-privee/',
|
||||
cta: 'Créer mon arbre',
|
||||
heroCanvas: 'Arbre de famille animé',
|
||||
@@ -116,6 +116,7 @@ export const COPY = {
|
||||
footer: {
|
||||
label: 'Pied de page',
|
||||
guides: 'Guides',
|
||||
login: 'Se connecter',
|
||||
privacy: 'Vie privée',
|
||||
source: 'Code source',
|
||||
madeBy: 'Fait par Ilies Allali',
|
||||
@@ -138,7 +139,7 @@ export const COPY = {
|
||||
appQuery: 'lang=en',
|
||||
otherLang: { href: '/', hrefLang: 'fr', label: 'FR', title: 'Version française' },
|
||||
logoHome: 'Parenthèse, home',
|
||||
nav: { how: 'How it works', demo: 'An example', privacy: 'Privacy' },
|
||||
nav: { how: 'How it works', demo: 'An example', privacy: 'Privacy', login: 'Sign in' },
|
||||
privacyHref: '/en/privacy/',
|
||||
cta: 'Start your tree',
|
||||
heroCanvas: 'Animated family tree',
|
||||
@@ -225,6 +226,7 @@ export const COPY = {
|
||||
footer: {
|
||||
label: 'Footer',
|
||||
guides: 'Guides',
|
||||
login: 'Sign in',
|
||||
privacy: 'Privacy',
|
||||
source: 'Source code',
|
||||
madeBy: 'Made by Ilies Allali',
|
||||
|
||||
Reference in new issue
Block a user