fix(sdk): Prevent auto-save from overwriting completed profile status
Some checks failed
CI/CD / go-lint (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Successful in 41s
CI/CD / test-python-backend-compliance (push) Successful in 39s
CI/CD / test-python-document-crawler (push) Successful in 25s
CI/CD / test-python-dsms-gateway (push) Successful in 21s
CI/CD / deploy-hetzner (push) Failing after 1s
Some checks failed
CI/CD / go-lint (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Successful in 41s
CI/CD / test-python-backend-compliance (push) Successful in 39s
CI/CD / test-python-document-crawler (push) Successful in 25s
CI/CD / test-python-dsms-gateway (push) Successful in 21s
CI/CD / deploy-hetzner (push) Failing after 1s
The auto-save timers (SDK context + backend) were firing after completeAndSaveProfile(), resetting isComplete back to false. Fix: skip auto-save when currentStep===99 (completed), cancel pending timers before completing, and await backend save before updating SDK context. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2486,6 +2486,9 @@ export default function CompanyProfilePage() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't auto-save drafts if profile is already completed (step 99)
|
||||||
|
if (currentStep === 99) return
|
||||||
|
|
||||||
// Debounce: sync to SDK context after 500ms of inactivity
|
// Debounce: sync to SDK context after 500ms of inactivity
|
||||||
if (autoSaveRef.current) clearTimeout(autoSaveRef.current)
|
if (autoSaveRef.current) clearTimeout(autoSaveRef.current)
|
||||||
autoSaveRef.current = setTimeout(() => {
|
autoSaveRef.current = setTimeout(() => {
|
||||||
@@ -2500,7 +2503,7 @@ export default function CompanyProfilePage() {
|
|||||||
if (autoSaveRef.current) clearTimeout(autoSaveRef.current)
|
if (autoSaveRef.current) clearTimeout(autoSaveRef.current)
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [formData])
|
}, [formData, currentStep])
|
||||||
|
|
||||||
// Shared payload builder for draft saves and final save (DRY)
|
// Shared payload builder for draft saves and final save (DRY)
|
||||||
const buildProfilePayload = (isComplete: boolean) => ({
|
const buildProfilePayload = (isComplete: boolean) => ({
|
||||||
@@ -2578,6 +2581,9 @@ export default function CompanyProfilePage() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!initialLoadDone.current) return
|
if (!initialLoadDone.current) return
|
||||||
|
|
||||||
|
// Don't auto-save drafts if profile is already completed
|
||||||
|
if (currentStep === 99) return
|
||||||
|
|
||||||
const hasData = formData.companyName || (formData.industry && formData.industry.length > 0)
|
const hasData = formData.companyName || (formData.industry && formData.industry.length > 0)
|
||||||
if (!hasData) return
|
if (!hasData) return
|
||||||
|
|
||||||
@@ -2601,7 +2607,7 @@ export default function CompanyProfilePage() {
|
|||||||
if (backendAutoSaveRef.current) clearTimeout(backendAutoSaveRef.current)
|
if (backendAutoSaveRef.current) clearTimeout(backendAutoSaveRef.current)
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [formData])
|
}, [formData, currentStep])
|
||||||
|
|
||||||
const [draftSaveStatus, setDraftSaveStatus] = useState<'idle' | 'saving' | 'saved' | 'error'>('idle')
|
const [draftSaveStatus, setDraftSaveStatus] = useState<'idle' | 'saving' | 'saved' | 'error'>('idle')
|
||||||
const draftSaveTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(null)
|
const draftSaveTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||||
@@ -2646,17 +2652,17 @@ export default function CompanyProfilePage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const completeAndSaveProfile = async () => {
|
const completeAndSaveProfile = async () => {
|
||||||
|
// Cancel any pending auto-save timers to prevent them from overwriting isComplete
|
||||||
|
if (autoSaveRef.current) clearTimeout(autoSaveRef.current)
|
||||||
|
if (backendAutoSaveRef.current) clearTimeout(backendAutoSaveRef.current)
|
||||||
|
|
||||||
const completeProfile: CompanyProfile = {
|
const completeProfile: CompanyProfile = {
|
||||||
...formData,
|
...formData,
|
||||||
isComplete: true,
|
isComplete: true,
|
||||||
completedAt: new Date(),
|
completedAt: new Date(),
|
||||||
} as CompanyProfile
|
} as CompanyProfile
|
||||||
|
|
||||||
setCompanyProfile(completeProfile)
|
// Persist to backend FIRST (with isComplete=true)
|
||||||
dispatch({ type: 'COMPLETE_STEP', payload: 'company-profile' })
|
|
||||||
dispatch({ type: 'SET_STATE', payload: { projectVersion: (state.projectVersion || 0) + 1 } })
|
|
||||||
|
|
||||||
// Also persist to dedicated backend endpoint
|
|
||||||
try {
|
try {
|
||||||
await fetch(profileApiUrl(), {
|
await fetch(profileApiUrl(), {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -2667,6 +2673,11 @@ export default function CompanyProfilePage() {
|
|||||||
console.error('Failed to save company profile to backend:', err)
|
console.error('Failed to save company profile to backend:', err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Then update SDK context (after backend is done, no race condition)
|
||||||
|
setCompanyProfile(completeProfile)
|
||||||
|
dispatch({ type: 'COMPLETE_STEP', payload: 'company-profile' })
|
||||||
|
dispatch({ type: 'SET_STATE', payload: { projectVersion: (state.projectVersion || 0) + 1 } })
|
||||||
|
|
||||||
setCurrentStep(99) // Show summary
|
setCurrentStep(99) // Show summary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user