11"use client" ;
22
3- import { useState } from "react" ;
3+ import { useEffect , useRef , useState } from "react" ;
44import Link from "next/link" ;
5- import { useRouter } from "next/navigation" ;
5+ import { useRouter , useSearchParams } from "next/navigation" ;
66import {
77 ArrowLeft ,
88 Plus ,
@@ -19,6 +19,11 @@ import {
1919 Upload ,
2020} from "lucide-react" ;
2121import { CANONICAL_TAGS , normalizeProblemTag , normalizeTagList } from "@/lib/problem-tags" ;
22+ import {
23+ clearJsonImportDraft ,
24+ loadJsonImportDraft ,
25+ type ImportIssue ,
26+ } from "@/lib/import/json-draft-storage" ;
2227import { LatexStatement } from "@/app/problem-sets/[slug]/latex-statement" ;
2328
2429/* ── Types ─────────────────────────────────────────────── */
@@ -125,6 +130,9 @@ function hasTag(csv: string, tag: string): boolean {
125130
126131export default function CreateSetPage ( ) {
127132 const router = useRouter ( ) ;
133+ const searchParams = useSearchParams ( ) ;
134+ const importDraftKey = searchParams . get ( "importDraft" ) ;
135+ const draftLoaded = useRef ( false ) ;
128136
129137 // Set metadata
130138 const [ title , setTitle ] = useState ( "" ) ;
@@ -133,7 +141,7 @@ export default function CreateSetPage() {
133141 const [ description , setDescription ] = useState ( "" ) ;
134142 const [ order , setOrder ] = useState ( "1" ) ;
135143 const [ difficulty , setDifficulty ] = useState ( 1 ) ;
136- const [ status , setStatus ] = useState < "DRAFT" | "PUBLISHED" > ( "DRAFT" ) ;
144+ const [ status , setStatus ] = useState < "DRAFT" | "PUBLISHED" | "ARCHIVED" > ( "DRAFT" ) ;
137145 const [ topicTags , setTopicTags ] = useState ( "" ) ;
138146 const [ videoUrl , setVideoUrl ] = useState ( "" ) ;
139147 const [ problemPdf , setProblemPdf ] = useState < { name : string ; dataUrl : string } | null > ( null ) ;
@@ -146,8 +154,55 @@ export default function CreateSetPage() {
146154 const [ saving , setSaving ] = useState ( false ) ;
147155 const [ error , setError ] = useState < string | null > ( null ) ;
148156 const [ success , setSuccess ] = useState < string | null > ( null ) ;
157+ const [ draftIssues , setDraftIssues ] = useState < ImportIssue [ ] > ( [ ] ) ;
158+ const [ draftFileName , setDraftFileName ] = useState < string | null > ( null ) ;
149159 const effectiveSlug = slugManual ? slug : slugify ( title ) ;
150160
161+ /* eslint-disable react-hooks/set-state-in-effect */
162+ useEffect ( ( ) => {
163+ if ( ! importDraftKey || draftLoaded . current ) {
164+ return ;
165+ }
166+
167+ const draft = loadJsonImportDraft ( importDraftKey ) ;
168+ draftLoaded . current = true ;
169+
170+ if ( ! draft ) {
171+ queueMicrotask ( ( ) => {
172+ setError ( "That import draft is missing or expired. Run the dry run again and reopen it." ) ;
173+ } ) ;
174+ return ;
175+ }
176+
177+ setTitle ( draft . title ) ;
178+ setSlug ( draft . slug ) ;
179+ setSlugManual ( true ) ;
180+ setDescription ( draft . description ) ;
181+ setOrder ( draft . order ) ;
182+ setDifficulty ( draft . difficulty ) ;
183+ setStatus ( draft . status ) ;
184+ setTopicTags ( draft . topicTags . join ( ", " ) ) ;
185+ setVideoUrl ( draft . videoUrl ?? "" ) ;
186+ setProblems (
187+ draft . problems . length > 0
188+ ? draft . problems . map ( ( problem ) => ( {
189+ id : uid ( ) ,
190+ number : problem . number ,
191+ statement : problem . statement ,
192+ contentFormat : problem . contentFormat ,
193+ answerType : problem . answerType ,
194+ answerKey : problem . answerKey ,
195+ topicTags : problem . topicTags . join ( ", " ) ,
196+ points : problem . points ,
197+ explanationNote : problem . explanationNote ?? "" ,
198+ } ) )
199+ : [ emptyProblem ( 1 ) ] ,
200+ ) ;
201+ setDraftIssues ( draft . issues ) ;
202+ setDraftFileName ( draft . fileName ) ;
203+ } , [ importDraftKey ] ) ;
204+ /* eslint-enable react-hooks/set-state-in-effect */
205+
151206 function addProblem ( ) {
152207 setProblems ( ( prev ) => [ ...prev , emptyProblem ( prev . length + 1 ) ] ) ;
153208 }
@@ -269,7 +324,10 @@ export default function CreateSetPage() {
269324 }
270325
271326 setSuccess ( `Problem set "${ title } " created successfully!` ) ;
272- setTimeout ( ( ) => router . push ( "/admin/sets" ) , 1500 ) ;
327+ if ( importDraftKey ) {
328+ clearJsonImportDraft ( importDraftKey ) ;
329+ }
330+ setTimeout ( ( ) => router . push ( `/admin/sets/${ data . problemSet . id } ` ) , 1500 ) ;
273331 } catch {
274332 setError ( "Network error. Please try again." ) ;
275333 } finally {
@@ -284,7 +342,7 @@ export default function CreateSetPage() {
284342 < header className = "create-set-header" >
285343 < div >
286344 < p className = "eyebrow" > Admin</ p >
287- < h1 > Create Problem Set</ h1 >
345+ < h1 > { importDraftKey ? "Fix JSON Draft" : " Create Problem Set" } </ h1 >
288346 </ div >
289347 < div className = "create-set-header-actions" >
290348 < Link className = "secondary-action" href = "/dashboard" >
@@ -314,6 +372,33 @@ export default function CreateSetPage() {
314372 < span > { success } </ span >
315373 </ div >
316374 ) }
375+ { importDraftKey && draftFileName ? (
376+ < div className = "create-set-alert" >
377+ < CheckCircle2 size = { 18 } />
378+ < span > Loaded import draft from { draftFileName } . Fix the issues below, then save.</ span >
379+ </ div >
380+ ) : null }
381+ { draftIssues . length > 0 ? (
382+ < div className = "dry-run-result" aria-live = "polite" >
383+ < div className = "preview-card" >
384+ < div className = "preview-heading" >
385+ < span className = "status-dot status-review" />
386+ < div >
387+ < strong > Import issues to fix</ strong >
388+ < small > These came from the original JSON dry run.</ small >
389+ </ div >
390+ </ div >
391+ </ div >
392+ < div className = "issue-list" >
393+ { draftIssues . map ( ( issue ) => (
394+ < div className = { `issue-row ${ issue . level } ` } key = { issue . message } >
395+ { issue . level === "error" ? < AlertCircle size = { 16 } /> : < CheckCircle2 size = { 16 } /> }
396+ < span > { issue . message } </ span >
397+ </ div >
398+ ) ) }
399+ </ div >
400+ </ div >
401+ ) : null }
317402
318403 { /* ── Metadata section ──────────────────────────── */ }
319404 < section className = "create-set-meta" >
@@ -399,10 +484,11 @@ export default function CreateSetPage() {
399484 < select
400485 id = "set-status"
401486 value = { status }
402- onChange = { ( e ) => setStatus ( e . target . value as "DRAFT" | "PUBLISHED" ) }
487+ onChange = { ( e ) => setStatus ( e . target . value as "DRAFT" | "PUBLISHED" | "ARCHIVED" ) }
403488 >
404489 < option value = "DRAFT" > Draft</ option >
405490 < option value = "PUBLISHED" > Published</ option >
491+ < option value = "ARCHIVED" > Archived</ option >
406492 </ select >
407493 </ div >
408494
0 commit comments