Studio lot 8bis : présenter les personnages au visiteur
Écran d'entrée, une fois par session, 11 langues. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011VxSQeGQYUvPmSEoGdnidA
This commit is contained in:
parent
d21d794420
commit
81c807cd77
@ -3,6 +3,7 @@ import { getInstanceBySlug, getConfiguration, getSections } from '@/lib/api/clie
|
||||
import SectionList from '@/components/SectionList'
|
||||
import QRScannerButton from '@/components/QRScannerButton'
|
||||
import ProximitySuggestion from '@/components/ProximitySuggestion'
|
||||
import CastingIntro from '@/components/CastingIntro'
|
||||
|
||||
export default async function ConfigPage({
|
||||
params,
|
||||
@ -39,6 +40,7 @@ export default async function ConfigPage({
|
||||
configPrimaryColor={config.primaryColor}
|
||||
languages={config.languages ?? ['FR']}
|
||||
/>
|
||||
{config.casting && config.casting.length >= 2 && <CastingIntro casting={config.casting} configId={configId} />}
|
||||
{instance.isQRCodeEnabled !== false && <QRScannerButton slug={slug} configurationId={configId} />}
|
||||
<ProximitySuggestion sections={activeSections} slug={slug} configId={configId} />
|
||||
</>
|
||||
|
||||
73
src/components/CastingIntro.tsx
Normal file
73
src/components/CastingIntro.tsx
Normal file
@ -0,0 +1,73 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
import Image from 'next/image'
|
||||
import { useVisitor } from '@/context/VisitorContext'
|
||||
import { ui } from '@/lib/i18n'
|
||||
import type { CastingVisitorMemberDTO } from '@/lib/api/types'
|
||||
|
||||
/**
|
||||
* Écran d'entrée « les personnes que vous allez rencontrer » (plan Studio décision 25). Le serveur
|
||||
* ne l'envoie qu'avec l'interrupteur armé et au moins deux portraits. Montré une fois par visite :
|
||||
* le visiteur qui revient à la liste des sections ne le revoit pas.
|
||||
*/
|
||||
export default function CastingIntro({ casting, configId }: { casting: CastingVisitorMemberDTO[]; configId: string }) {
|
||||
const { language } = useVisitor()
|
||||
const [open, setOpen] = useState(false)
|
||||
const storageKey = `casting-seen-${configId}`
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
if (sessionStorage.getItem(storageKey)) return
|
||||
} catch {
|
||||
// Stockage indisponible (navigation privée) : on montre l'écran, sans mémoriser.
|
||||
}
|
||||
setOpen(true)
|
||||
}, [storageKey])
|
||||
|
||||
function close() {
|
||||
try {
|
||||
sessionStorage.setItem(storageKey, '1')
|
||||
} catch {
|
||||
// Idem : l'écran reviendra à la prochaine ouverture, ce n'est pas grave.
|
||||
}
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
if (!open) return null
|
||||
|
||||
return (
|
||||
<div
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
style={{ position: 'fixed', inset: 0, zIndex: 50, background: 'rgba(0,0,0,0.55)', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 16 }}
|
||||
>
|
||||
<div style={{ width: '100%', maxWidth: 420, background: 'var(--color-paper, #fff)', borderRadius: 22, padding: '24px 20px', boxShadow: '0 12px 32px rgba(0,0,0,0.25)' }}>
|
||||
<h2 style={{ fontSize: 18, fontWeight: 700, textAlign: 'center', margin: '0 0 20px', color: 'var(--color-ink, #1E2A33)' }}>
|
||||
{ui('castingTitle', language)}
|
||||
</h2>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(110px, 1fr))', gap: 16 }}>
|
||||
{casting.map((member, index) => (
|
||||
<div key={index} style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center', gap: 6 }}>
|
||||
<Image
|
||||
src={member.portraitUrl}
|
||||
alt=""
|
||||
width={88}
|
||||
height={88}
|
||||
style={{ width: 88, height: 88, borderRadius: '50%', objectFit: 'cover' }}
|
||||
/>
|
||||
<span style={{ fontSize: 14, fontWeight: 600, color: 'var(--color-ink, #1E2A33)' }}>{member.name}</span>
|
||||
{member.role && <span style={{ fontSize: 12, color: 'var(--color-ink-muted, #6B7B86)' }}>{member.role}</span>}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<button
|
||||
onClick={close}
|
||||
style={{ marginTop: 24, width: '100%', padding: '12px 16px', borderRadius: 14, border: 'none', cursor: 'pointer', background: 'var(--color-primary)', color: '#fff', fontSize: 15, fontWeight: 600 }}
|
||||
>
|
||||
{ui('castingStart', language)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -96,6 +96,14 @@ export interface ConfigurationDTO {
|
||||
isOffline?: boolean
|
||||
sectionIds?: string[]
|
||||
sections?: SectionDTO[]
|
||||
/** Casting montre au visiteur (decision 25). Absent tant que l'ecran d'entree ne doit pas s'afficher. */
|
||||
casting?: CastingVisitorMemberDTO[]
|
||||
}
|
||||
|
||||
export interface CastingVisitorMemberDTO {
|
||||
name: string
|
||||
role?: string
|
||||
portraitUrl: string
|
||||
}
|
||||
|
||||
export interface AppConfigurationLinkDTO {
|
||||
|
||||
@ -24,6 +24,32 @@ const UI_STRINGS: Record<string, Record<string, string>> = {
|
||||
UK: 'Зображення, створене ШІ',
|
||||
LB: 'Bild generéiert vun der KI',
|
||||
},
|
||||
castingTitle: {
|
||||
FR: 'Les personnes que vous allez rencontrer',
|
||||
NL: 'De personen die u zult ontmoeten',
|
||||
EN: 'The people you will meet',
|
||||
DE: 'Die Menschen, denen Sie begegnen werden',
|
||||
ES: 'Las personas que va a conocer',
|
||||
IT: 'Le persone che incontrerete',
|
||||
PL: 'Osoby, które spotkasz',
|
||||
CN: '您将遇到的人物',
|
||||
AR: 'الشخصيات التي ستلتقيها',
|
||||
UK: 'Люди, яких ви зустрінете',
|
||||
LB: "D'Leit, déi Dir kenne léiert",
|
||||
},
|
||||
castingStart: {
|
||||
FR: 'Commencer la visite',
|
||||
NL: 'Het bezoek beginnen',
|
||||
EN: 'Start the visit',
|
||||
DE: 'Besuch beginnen',
|
||||
ES: 'Empezar la visita',
|
||||
IT: 'Inizia la visita',
|
||||
PL: 'Rozpocznij zwiedzanie',
|
||||
CN: '开始参观',
|
||||
AR: 'ابدأ الزيارة',
|
||||
UK: 'Почати відвідування',
|
||||
LB: 'Besuch ufänken',
|
||||
},
|
||||
noEventsThisMonth: {
|
||||
FR: 'Aucun événement ce mois-ci',
|
||||
NL: 'Geen evenementen deze maand',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user