feat(12-05): preserve Instance fields across Back navigation (gap 4)
- Lift appUrl/oidcIssuer/oidcClientId/vapidPublicKey into SetupPage so Step2 unmount preserves them - Step2Config now reads/writes these via fields/setFields props - Fastmail app password stays in Step3 local state, never lifted/persisted, cleared on unmount (T-12-15) - Tests: Back from Calendar restores all four Instance values; password not persisted across nav
This commit is contained in:
@@ -430,17 +430,28 @@ function Step1Welcome({ onContinue, stepHeadingRef }: Step1Props) {
|
||||
|
||||
// ── Step 2: Instance Configuration ───────────────────────────────────────────
|
||||
|
||||
interface InstanceFields {
|
||||
appUrl: string;
|
||||
oidcIssuer: string;
|
||||
oidcClientId: string;
|
||||
vapidPublicKey: string;
|
||||
}
|
||||
|
||||
interface Step2Props {
|
||||
onBack: () => void;
|
||||
onSuccess: () => void;
|
||||
stepHeadingRef: React.RefObject<HTMLHeadingElement | null>;
|
||||
/** Lifted to SetupPage so values survive step unmount (gap 4: Back preserves entries). */
|
||||
fields: InstanceFields;
|
||||
setFields: React.Dispatch<React.SetStateAction<InstanceFields>>;
|
||||
}
|
||||
|
||||
function Step2Config({ onBack, onSuccess, stepHeadingRef }: Step2Props) {
|
||||
const [appUrl, setAppUrl] = useState('');
|
||||
const [oidcIssuer, setOidcIssuer] = useState('');
|
||||
const [oidcClientId, setOidcClientId] = useState('');
|
||||
const [vapidPublicKey, setVapidPublicKey] = useState('');
|
||||
function Step2Config({ onBack, onSuccess, stepHeadingRef, fields, setFields }: Step2Props) {
|
||||
const { appUrl, oidcIssuer, oidcClientId, vapidPublicKey } = fields;
|
||||
const setAppUrl = (v: string) => setFields((f) => ({ ...f, appUrl: v }));
|
||||
const setOidcIssuer = (v: string) => setFields((f) => ({ ...f, oidcIssuer: v }));
|
||||
const setOidcClientId = (v: string) => setFields((f) => ({ ...f, oidcClientId: v }));
|
||||
const setVapidPublicKey = (v: string) => setFields((f) => ({ ...f, vapidPublicKey: v }));
|
||||
const [fieldError, setFieldError] = useState<string | null>(null);
|
||||
|
||||
// Gap 3 (frontend): fetch the env-derived, non-secret DB name so the
|
||||
@@ -1072,6 +1083,16 @@ export function SetupPage({ alreadyLocked = false }: SetupPageProps) {
|
||||
const [terminal, setTerminal] = useState<TerminalState>(alreadyLocked ? 'locked' : null);
|
||||
const stepHeadingRef = useRef<HTMLHeadingElement>(null);
|
||||
|
||||
// Gap 4: Instance-step field values are lifted here so they survive Step2 unmount.
|
||||
// The Fastmail app password (Step 3) is deliberately NOT lifted — it stays in
|
||||
// Step3Credential local state and is cleared on unmount (T-12-15 preserved).
|
||||
const [instanceFields, setInstanceFields] = useState<InstanceFields>({
|
||||
appUrl: '',
|
||||
oidcIssuer: '',
|
||||
oidcClientId: '',
|
||||
vapidPublicKey: '',
|
||||
});
|
||||
|
||||
// Focus the step heading on step change for a11y (D-04 focus management)
|
||||
useEffect(() => {
|
||||
if (stepHeadingRef.current) {
|
||||
@@ -1166,6 +1187,8 @@ export function SetupPage({ alreadyLocked = false }: SetupPageProps) {
|
||||
onBack={() => setStep(1)}
|
||||
onSuccess={() => setStep(3)}
|
||||
stepHeadingRef={stepHeadingRef}
|
||||
fields={instanceFields}
|
||||
setFields={setInstanceFields}
|
||||
/>
|
||||
)}
|
||||
{step === 3 && (
|
||||
|
||||
Reference in New Issue
Block a user