@@ -16,12 +16,14 @@ import {
1616 useToast ,
1717} from '@/components/ui' ;
1818import { useWallet } from '@/hooks/use-wallet' ;
19+ import { useDraftPersistence } from '@/hooks/use-draft-persistence' ;
1920import { ClaimAPI } from '@/lib/api/claim' ;
2021
2122import { AmountStep } from './steps/AmountStep' ;
2223import { EvidenceStep } from './steps/EvidenceStep' ;
2324import { NarrativeStep } from './steps/NarrativeStep' ;
2425import { ReviewStep } from './steps/ReviewStep' ;
26+ import { DraftResumeBanner } from './DraftResumeBanner' ;
2527
2628interface ClaimWizardProps {
2729 policyId : string ;
@@ -35,6 +37,8 @@ const STEPS = [
3537 { id : '4' , title : 'Review' , description : 'Confirm & Sign' } ,
3638] ;
3739
40+ const CLAIM_DRAFT_SCHEMA_VERSION = 1 ;
41+
3842export function ClaimWizard ( { policyId, maxCoverage } : ClaimWizardProps ) {
3943 const router = useRouter ( ) ;
4044 const { toast } = useToast ( ) ;
@@ -43,6 +47,7 @@ export function ClaimWizard({ policyId, maxCoverage }: ClaimWizardProps) {
4347 const [ isSubmitting , setIsSubmitting ] = useState ( false ) ;
4448 const [ isSuccess , setIsSuccess ] = useState ( false ) ;
4549 const [ txStatus , setTxStatus ] = useState < string > ( '' ) ;
50+ const [ showBanner , setShowBanner ] = useState ( true ) ;
4651 const stepHeadingRef = useRef < HTMLHeadingElement > ( null ) ;
4752
4853 const [ formData , setFormData ] = useState ( {
@@ -51,6 +56,44 @@ export function ClaimWizard({ policyId, maxCoverage }: ClaimWizardProps) {
5156 evidence : [ ] as { url : string ; contentSha256Hex : string } [ ] ,
5257 } ) ;
5358
59+ const { hasDraft, saveDraft, loadDraft, clearDraft } = useDraftPersistence (
60+ `claim-${ policyId } ` ,
61+ CLAIM_DRAFT_SCHEMA_VERSION
62+ ) ;
63+
64+ // Sync draft on form changes (excluding files/IPFS handled by hook sanitize)
65+ useEffect ( ( ) => {
66+ if ( activeStep > 0 || formData . amount || formData . details ) {
67+ saveDraft ( { ...formData , _step : activeStep } ) ;
68+ }
69+ } , [ formData , activeStep , saveDraft ] ) ;
70+
71+ const handleResumeDraft = ( ) => {
72+ const draft = loadDraft ( ) ;
73+ if ( draft ) {
74+ const { _step, ...data } = draft as any ;
75+ setFormData ( prev => ( { ...prev , ...data } ) ) ;
76+ if ( typeof _step === 'number' ) {
77+ setActiveStep ( _step ) ;
78+ }
79+ toast ( {
80+ title : 'Draft Restored' ,
81+ description : 'You are continuing where you left off.' ,
82+ } ) ;
83+ }
84+ setShowBanner ( false ) ;
85+ } ;
86+
87+ const handleDismissBanner = ( ) => {
88+ clearDraft ( ) ; // Clearing explicitly if they choose to start over?
89+ // Actually, maybe not clearing immediately, but just hiding banner?
90+ // Requirements say "Resume draft banner when a valid draft is detected".
91+ // If they dismiss, we should probably stop showing it but maybe keep draft until new data overwrites?
92+ // Let's clear it to be safe and avoid confusion.
93+ clearDraft ( ) ;
94+ setShowBanner ( false ) ;
95+ } ;
96+
5497 // Move focus to step heading when step changes
5598 useEffect ( ( ) => {
5699 if ( stepHeadingRef . current ) {
@@ -103,6 +146,10 @@ export function ClaimWizard({ policyId, maxCoverage }: ClaimWizardProps) {
103146
104147 setTxStatus ( 'Claim submitted successfully.' ) ;
105148 setIsSuccess ( true ) ;
149+
150+ // EXTREMELY IMPORTANT: Clear draft on success (Issue #229)
151+ clearDraft ( ) ;
152+
106153 toast ( {
107154 title : 'Claim Submitted!' ,
108155 description : 'Your claim has been successfully filed on-chain.' ,
@@ -173,6 +220,11 @@ export function ClaimWizard({ policyId, maxCoverage }: ClaimWizardProps) {
173220 </ div >
174221 </ CardHeader >
175222 < CardContent className = "space-y-6" >
223+ { /* Banner for resuming draft (Requirement: Resume draft banner detected on wizard mount) */ }
224+ { hasDraft && showBanner && (
225+ < DraftResumeBanner onConfirm = { handleResumeDraft } onDismiss = { handleDismissBanner } />
226+ ) }
227+
176228 { /* Visually hidden heading receives focus on step change */ }
177229 < h2
178230 ref = { stepHeadingRef }
@@ -205,9 +257,14 @@ export function ClaimWizard({ policyId, maxCoverage }: ClaimWizardProps) {
205257 </ StepContent >
206258
207259 < StepContent title = { STEPS [ 3 ] . title } isActive = { activeStep === 3 } isCompleted = { activeStep > 3 } >
208- < ReviewStep data = { formData } policyId = { policyId } />
260+ < ReviewStep
261+ data = { formData }
262+ policyId = { policyId }
263+ onEdit = { ( step ) => setActiveStep ( step ) }
264+ />
209265 </ StepContent >
210266
267+
211268 < div className = "flex justify-between pt-4 border-t" >
212269 < Button
213270 variant = "ghost"
0 commit comments