Skip to content

Commit b497ee3

Browse files
authored
Merge pull request #207 from adobecom/revert-203-fix/event-form-wizard-step-reset
Revert "fix(event-form): stop page-3 sub-resource 403s from resetting the wizard to step 1"
2 parents 31e06aa + 8c150cb commit b497ee3

14 files changed

Lines changed: 88 additions & 208 deletions

web-src/src/components/shared/FormWizard.tsx

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* <license header>
33
*/
44

5-
import React, { useState, useCallback, useEffect } from 'react'
5+
import React, { useState, useCallback } from 'react'
66
import { AlertDialog, Badge, Button, DialogTrigger, Heading, ProgressBar, StatusLight, Text } from '@react-spectrum/s2'
77
import { style, iconStyle } from '@react-spectrum/s2/style' with { type: 'macro' }
88
import { useNavigate } from 'react-router-dom'
@@ -19,7 +19,6 @@ import {
1919
TYPOGRAPHY
2020
} from '../../styles/designSystem'
2121
import { formatEventFormStatusLabel, getEventFormStatusLightVariant } from './eventFormStatusBadge'
22-
import { loadFormStep, saveFormStep } from '../../utils/formPersistence'
2322

2423
export interface WizardStep {
2524
id: string
@@ -81,8 +80,6 @@ interface FormWizardProps {
8180
sessionContent?: React.ReactNode
8281
/** True when an inline session form (add or edit) is currently open */
8382
sessionHasOpenForm?: boolean
84-
/** Key to persist the current step under (sessionStorage) so it survives a remount. Omit to disable persistence. */
85-
stepPersistKey?: string
8683
}
8784

8885
/** Side nav: Dashboard row hover */
@@ -115,18 +112,8 @@ export const FormWizard: React.FC<FormWizardProps> = ({
115112
testIds,
116113
sessionContent,
117114
sessionHasOpenForm = false,
118-
stepPersistKey,
119115
}) => {
120-
const [currentStepIndex, setCurrentStepIndex] = useState(() => {
121-
if (!stepPersistKey) return 0
122-
const persisted = loadFormStep(stepPersistKey)
123-
if (persisted === null) return 0
124-
// Never restore past a step the user has actually unlocked — a stale
125-
// persisted step (e.g. from an abandoned draft under a shared "new
126-
// event" key) must not open an inaccessible step with no data.
127-
const highestUnlocked = hasEventId ? maxStepReached : 0
128-
return Math.min(persisted, highestUnlocked, steps.length - 1)
129-
})
116+
const [currentStepIndex, setCurrentStepIndex] = useState(0)
130117
const [isNavigating, setIsNavigating] = useState(false)
131118
const [showSessionView, setShowSessionView] = useState(false)
132119
const [pendingAction, setPendingAction] = useState<'save' | 'publish' | 'next' | null>(null)
@@ -140,14 +127,6 @@ export const FormWizard: React.FC<FormWizardProps> = ({
140127
const isFirstStep = currentStepIndex === 0
141128
const progress = ((currentStepIndex + 1) / steps.length) * 100
142129

143-
// Persist the current step so it survives a remount of the wizard
144-
// (e.g. a background auth/group refresh) instead of resetting to step 1.
145-
useEffect(() => {
146-
if (stepPersistKey) {
147-
saveFormStep(stepPersistKey, currentStepIndex)
148-
}
149-
}, [stepPersistKey, currentStepIndex])
150-
151130
// Determine if a step is accessible
152131
const isStepAccessible = useCallback((stepIndex: number): boolean => {
153132
if (stepIndex === 0) return true

web-src/src/contexts/EventFormContext.tsx

Lines changed: 17 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,6 @@ export interface EventFormContextValue {
171171
getRegisteredComponents: () => RegisteredComponent[]
172172

173173
// Persistence
174-
/** Draft storage key for this form instance (eventId, or `new-<eventType>-<seriesId>`) */
175-
storageKey: string
176174
persistToStorage: () => void
177175
loadFromStorage: () => boolean
178176
clearStorage: () => void
@@ -238,39 +236,22 @@ export const createDefaultFormData = (): EventFormData => ({
238236
sponsors: []
239237
})
240238

241-
interface InitialStateSeed extends Partial<EventFormData> {
242-
eventId?: string | null
243-
}
244-
245-
/**
246-
* Seeds eventId/seriesId/isEditMode synchronously from the provider's initial
247-
* props (rather than only via a post-mount effect), so that on a remount —
248-
* e.g. a background auth/group refresh — dependents like the form's
249-
* sessionStorage key are correct from the very first render instead of
250-
* transiently pointing at the "new event" key for one render pass.
251-
*/
252-
const createInitialState = (initialData?: InitialStateSeed): EventFormState => {
253-
const { eventId, ...formDataSeed } = initialData ?? {}
254-
return {
255-
eventId: eventId ?? null,
256-
seriesId: formDataSeed?.seriesId ?? '',
257-
isEditMode: !!eventId,
258-
locale: DEFAULT_LOCALE,
259-
eventDataResp: null,
260-
formData: { ...createDefaultFormData(), ...formDataSeed },
261-
isDirty: false,
262-
saveStatus: 'idle',
263-
saveError: null,
264-
isLoading: false,
265-
loadError: null,
266-
isPublished: false,
267-
// loadEvent() unconditionally unlocks all steps (maxStepReached: 3) for any
268-
// existing event; seed the same value synchronously so a remount doesn't
269-
// transiently re-lock the wizard down to step 1 while loadEvent re-fetches.
270-
maxStepReached: eventId ? 3 : 0,
271-
isFormatConfirmed: false,
272-
}
273-
}
239+
const createInitialState = (initialData?: Partial<EventFormData>): EventFormState => ({
240+
eventId: null,
241+
seriesId: '',
242+
isEditMode: false,
243+
locale: DEFAULT_LOCALE,
244+
eventDataResp: null,
245+
formData: { ...createDefaultFormData(), ...initialData },
246+
isDirty: false,
247+
saveStatus: 'idle',
248+
saveError: null,
249+
isLoading: false,
250+
loadError: null,
251+
isPublished: false,
252+
maxStepReached: 0,
253+
isFormatConfirmed: false,
254+
})
274255

275256
// ============================================================================
276257
// REDUCER
@@ -421,7 +402,7 @@ export const EventFormProvider: React.FC<EventFormProviderProps> = ({
421402
// Initialize state
422403
const [state, dispatch] = useReducer(
423404
eventFormReducer,
424-
{ eventType: initialEventType, seriesId: initialSeriesId, eventId: initialEventId },
405+
{ eventType: initialEventType, seriesId: initialSeriesId },
425406
createInitialState
426407
)
427408

@@ -647,7 +628,6 @@ export const EventFormProvider: React.FC<EventFormProviderProps> = ({
647628
getRegisteredComponents,
648629

649630
// Persistence
650-
storageKey,
651631
persistToStorage,
652632
loadFromStorage,
653633
clearStorage,
@@ -688,7 +668,6 @@ export const EventFormProvider: React.FC<EventFormProviderProps> = ({
688668
registerComponent,
689669
unregisterComponent,
690670
getRegisteredComponents,
691-
storageKey,
692671
persistToStorage,
693672
loadFromStorage,
694673
clearStorage,

web-src/src/pages/EventForm/CustomAttributesComponent.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ export const CustomAttributesComponent: React.FC = () => {
154154
const load = async () => {
155155
setLoading(true)
156156
try {
157-
const result = await cachedApi.getEventConfigs(eventId, undefined, { skipStaleGroupRecovery: true })
157+
const result = await cachedApi.getEventConfigs(eventId)
158158
if (cancelled) return
159159
if (!('error' in result)) {
160160
const config = result.find(c => hasAttributesSlice(c)) ?? null

web-src/src/pages/EventForm/EventForm.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,6 @@ const EventFormInner: React.FC<EventFormInnerProps> = ({ ims: _ims }) => {
496496
setSeriesCustomTagsUrl,
497497
loadFromStorage,
498498
persistToStorage,
499-
storageKey,
500499
state,
501500
scopeLocales,
502501
} = useEventFormContext()
@@ -1111,7 +1110,6 @@ const EventFormInner: React.FC<EventFormInnerProps> = ({ ims: _ims }) => {
11111110
testIds={EVENT_FORM_WIZARD_TEST_IDS}
11121111
sessionContent={sessionManagementComponent}
11131112
sessionHasOpenForm={sessionHasOpenForm}
1114-
stepPersistKey={storageKey}
11151113
/>
11161114

11171115
{/* Format Selection Overlay — frosted glass + dialog */}

web-src/src/pages/EventForm/EventInfoComponent.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ export const EventInfoComponent: React.FC = () => {
165165
const load = async () => {
166166
try {
167167
if (eventId) {
168-
const result = await cachedApi.getEventConfigs(eventId, undefined, { skipStaleGroupRecovery: true })
168+
const result = await cachedApi.getEventConfigs(eventId)
169169
if (cancelled) return
170170
if ('error' in result) {
171171
setLocaleOptions(DEFAULT_LOCALE_PICKER_OPTIONS)
@@ -174,7 +174,7 @@ export const EventInfoComponent: React.FC = () => {
174174
}
175175
applyLocales(result.find((c) => hasLocalesSlice(c)) ?? null)
176176
} else if (scopeId) {
177-
const result = await cachedApi.getConfig(scopeId, { skipStaleGroupRecovery: true })
177+
const result = await cachedApi.getConfig(scopeId)
178178
if (cancelled) return
179179
if (result === null || 'error' in result) {
180180
setLocaleOptions(DEFAULT_LOCALE_PICKER_OPTIONS)

web-src/src/pages/EventForm/PageMetadataComponent.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ export const PageMetadataComponent: React.FC = () => {
147147
if (!eventResponse?.eventId) return
148148

149149
try {
150-
const profileResponse = await cachedApi.getEventPublishingProfile(eventResponse.eventId, { skipStaleGroupRecovery: true })
150+
const profileResponse = await cachedApi.getEventPublishingProfile(eventResponse.eventId)
151151

152152
// Response could be an array or single object
153153
const profiles = Array.isArray(profileResponse) ? profileResponse : [profileResponse]
@@ -268,7 +268,7 @@ export const PageMetadataComponent: React.FC = () => {
268268
if (!targetEventId) return
269269

270270
try {
271-
const profileResponse = await cachedApi.getEventPublishingProfile(targetEventId, { skipStaleGroupRecovery: true })
271+
const profileResponse = await cachedApi.getEventPublishingProfile(targetEventId)
272272

273273
// Response could be an array or single object
274274
const profiles = Array.isArray(profileResponse) ? profileResponse : [profileResponse]

web-src/src/pages/EventForm/RegistrationFieldsComponent.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ export const RegistrationFieldsComponent: React.FC<RegistrationFieldsComponentPr
9999
let mode: RsvpFieldSourceMode = 'legacy'
100100

101101
if (eventId) {
102-
const result = await cachedApi.getEventConfigs(eventId, undefined, { skipStaleGroupRecovery: true })
102+
const result = await cachedApi.getEventConfigs(eventId)
103103
if (cancelled) return
104104
if (!('error' in result)) {
105105
const config = result.find(c => hasRsvpSlice(c)) ?? null

web-src/src/pages/EventForm/SessionManagement/SessionForm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ export const SessionForm: React.FC<SessionFormProps> = ({
265265
useEffect(() => {
266266
if (!session?.id) return;
267267
let cancelled = false;
268-
apiService.getSessionSpeakers(session.id, { skipStaleGroupRecovery: true }).then((res) => {
268+
apiService.getSessionSpeakers(session.id).then((res) => {
269269
if (cancelled) return;
270270
if (res && !("error" in res)) {
271271
const list = (res as any)?.speakers ?? [];
@@ -312,7 +312,7 @@ export const SessionForm: React.FC<SessionFormProps> = ({
312312
setDetailError(null);
313313

314314
// Only fetch session detail — session-time data is already cached on session.sessionTime
315-
apiService.getSingleSession(session.id, { skipStaleGroupRecovery: true }).then((res) => {
315+
apiService.getSingleSession(session.id).then((res) => {
316316
if (cancelled) return;
317317
setLoadingDetails(false);
318318
if (res && "error" in res) {

web-src/src/pages/EventForm/SessionManagement/Sessions.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ function sortSessionsByDate(sessions: Session[]): Session[] {
127127
}
128128

129129
async function hydrateSessionWithTime(session: Session): Promise<Session> {
130-
const timesRes = await apiService.getSessionTimes(session.id, { skipStaleGroupRecovery: true });
130+
const timesRes = await apiService.getSessionTimes(session.id);
131131
if (timesRes && "error" in timesRes) return session;
132132

133133
const times = Array.isArray((timesRes as any)?.sessionTimes)
@@ -278,7 +278,7 @@ export const Sessions: React.FC<SessionsProps> = ({ onOpenFormChange }) => {
278278
if (!seriesId) return;
279279
if (seriesSpeakers.length > 0) return;
280280
try {
281-
const response = await cachedApi.getSpeakers(seriesId, { skipStaleGroupRecovery: true });
281+
const response = await cachedApi.getSpeakers(seriesId);
282282
if (response && !("error" in response)) {
283283
const speakers = response.speakers || response || [];
284284
setSeriesSpeakers(Array.isArray(speakers) ? speakers : []);
@@ -291,9 +291,9 @@ export const Sessions: React.FC<SessionsProps> = ({ onOpenFormChange }) => {
291291
const loadVenueLocationsIfNeeded = useCallback(async () => {
292292
if (!eventId || venueLocations.length > 0) return
293293
try {
294-
const venueRes = await apiService.getEventVenue(eventId, { skipStaleGroupRecovery: true })
294+
const venueRes = await apiService.getEventVenue(eventId)
295295
if (!venueRes || 'error' in venueRes || !venueRes.venueId) return
296-
const locRes = await apiService.listVenueLocations(venueRes.venueId, { skipStaleGroupRecovery: true })
296+
const locRes = await apiService.listVenueLocations(venueRes.venueId)
297297
if (locRes && !('error' in locRes)) {
298298
const list = (locRes as any).locations ?? locRes ?? []
299299
setVenueLocations(Array.isArray(list) ? list : [])
@@ -306,7 +306,7 @@ export const Sessions: React.FC<SessionsProps> = ({ onOpenFormChange }) => {
306306
const refreshSeriesSpeakers = useCallback(async () => {
307307
if (!seriesId) return;
308308
try {
309-
const response = await cachedApi.getSpeakers(seriesId, { skipStaleGroupRecovery: true });
309+
const response = await cachedApi.getSpeakers(seriesId);
310310
if (response && !("error" in response)) {
311311
const speakers = response.speakers || response || [];
312312
setSeriesSpeakers(Array.isArray(speakers) ? speakers : []);
@@ -323,7 +323,7 @@ export const Sessions: React.FC<SessionsProps> = ({ onOpenFormChange }) => {
323323
}
324324
setIsLoading(true);
325325
try {
326-
const response = await apiService.getAllEventSessions(eventId, { skipStaleGroupRecovery: true });
326+
const response = await apiService.getAllEventSessions(eventId);
327327
if (response && "error" in response) {
328328
toast.error(response.error?.message || String(response.error), { duration: 8000 });
329329
setSessions([]);

web-src/src/pages/EventForm/SpeakersComponent.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export const SpeakersComponent: React.FC = () => {
117117

118118
let savedSpeakers: any[] = []
119119
try {
120-
const speakersResponse = await cachedApi.getEventSpeakers(savedEventId, { skipStaleGroupRecovery: true })
120+
const speakersResponse = await cachedApi.getEventSpeakers(savedEventId)
121121
if (speakersResponse && !('error' in speakersResponse)) {
122122
savedSpeakers = speakersResponse.speakers || speakersResponse || []
123123
if (!Array.isArray(savedSpeakers)) {
@@ -265,7 +265,7 @@ export const SpeakersComponent: React.FC = () => {
265265
const loadSeriesSpeakers = async () => {
266266
setIsLoadingSpeakers(true)
267267
try {
268-
const response = await cachedApi.getSpeakers(seriesId, { skipStaleGroupRecovery: true })
268+
const response = await cachedApi.getSpeakers(seriesId)
269269
if (isMounted && response && !('error' in response)) {
270270
const speakers = response.speakers || response || []
271271
setSeriesSpeakers(Array.isArray(speakers) ? speakers : [])
@@ -290,7 +290,7 @@ export const SpeakersComponent: React.FC = () => {
290290

291291
const refreshSeriesSpeakers = useCallback(async () => {
292292
if (!seriesId) return
293-
const response = await cachedApi.getSpeakers(seriesId, { skipStaleGroupRecovery: true })
293+
const response = await cachedApi.getSpeakers(seriesId)
294294
if (response && !('error' in response)) {
295295
const speakers = response.speakers || response || []
296296
setSeriesSpeakers(Array.isArray(speakers) ? speakers : [])

0 commit comments

Comments
 (0)