diff --git a/src/ui/components/ExtractorDialog.tsx b/src/ui/components/ExtractorDialog.tsx index cc41273..e8625a6 100644 --- a/src/ui/components/ExtractorDialog.tsx +++ b/src/ui/components/ExtractorDialog.tsx @@ -1,3 +1,4 @@ +import { Loader2, Play, RefreshCw, Sparkles } from 'lucide-react' import React, { useEffect, useRef, useState } from 'react' import { toast } from 'sonner' import { client } from '../client' @@ -6,7 +7,8 @@ import { AnalyzeStage } from './extractor/AnalyzeStage' import { RefineStage } from './extractor/RefineStage' import { SelectionStage } from './extractor/SelectionStage' import { UploadStage } from './extractor/UploadStage' -import { Dialog, DialogContent, DialogTitle } from './ui/dialog' +import { Button } from './ui/button' +import { Dialog, DialogContent, DialogFooter, DialogTitle } from './ui/dialog' interface ExtractorDialogProps { open: boolean @@ -54,8 +56,6 @@ export const ExtractorDialog: React.FC = ({ useEffect(() => { if (!open) { // Small delay to allow animation to finish if needed, or just reset immediately - // resetting immediately might flash content if closing animation plays - // But for now, we reset on close to ensure fresh state next open const t = setTimeout(resetState, 300) return () => clearTimeout(t) } @@ -105,7 +105,9 @@ export const ExtractorDialog: React.FC = ({ if (event === 'status') { setStatusMessage(data.message) } else if (event === 'complete') { - setCandidates(data.assets as CandidateAsset[]) + const newCandidates = data.assets as CandidateAsset[] + setCandidates(newCandidates) + setSelectedIndices(newCandidates.map((_, i) => i)) setStage('selection') } else if (event === 'error') { throw new Error(data.message) @@ -122,10 +124,16 @@ export const ExtractorDialog: React.FC = ({ } } - const handleRefineConfirm = (indices: number[]) => { - setSelectedIndices(indices) + const toggleSelection = (index: number) => { + setSelectedIndices((prev) => + prev.includes(index) ? prev.filter((i) => i !== index) : [...prev, index], + ) + } + + const handleRefineConfirm = () => { + if (selectedIndices.length === 0) return setStage('refine') - handleRefine(indices) + handleRefine(selectedIndices) } const handleRefine = async (indices: number[]) => { @@ -170,7 +178,6 @@ export const ExtractorDialog: React.FC = ({ setResults((prev) => [...prev, data.asset]) } else if (event === 'complete') { setIsRefineComplete(true) - onSuccess(data.assets) } else if (event === 'error') { throw new Error(data.message) } @@ -182,18 +189,24 @@ export const ExtractorDialog: React.FC = ({ console.error(e) const err = e instanceof Error ? e : new Error(String(e)) toast.error(err.message || 'Refinement failed') - // Don't change stage automatically on error here, let user see what happened or retry? - // For now, staying on refine stage allows them to see partial results. - // But we might want a 'retry' button or back. } } + const handleClose = () => onOpenChange(false) + + const handleDone = () => { + onSuccess(results) + handleClose() + } + + const isAnalyzing = stage === 'analyze' && !!statusMessage + return ( Extractor - {/* Top Navigation / Branding Bar (Optional, matches App feel) */} + {/* Top Navigation / Branding Bar */}

Extractor

@@ -201,23 +214,18 @@ export const ExtractorDialog: React.FC = ({
{/* Content Area */} -
+
{stage === 'upload' && } {stage === 'analyze' && preview && ( - + )} {stage === 'selection' && ( setStage('upload')} + selectedIndices={selectedIndices} + onToggleSelection={toggleSelection} /> )} @@ -226,10 +234,74 @@ export const ExtractorDialog: React.FC = ({ selectedCandidates={candidates.filter((_, i) => selectedIndices.includes(i))} results={results} isComplete={isRefineComplete} - onDone={resetState} /> )}
+ + {/* Footer */} + + {stage === 'upload' && ( + + )} + + {stage === 'analyze' && ( + <> + + + + )} + + {stage === 'selection' && ( + <> + + + + )} + + {stage === 'refine' && ( + <> + {isRefineComplete ? ( + <> + + + + ) : ( + + )} + + )} +
) diff --git a/src/ui/components/extractor/AnalyzeStage.tsx b/src/ui/components/extractor/AnalyzeStage.tsx index 3c1d857..af3a926 100644 --- a/src/ui/components/extractor/AnalyzeStage.tsx +++ b/src/ui/components/extractor/AnalyzeStage.tsx @@ -1,20 +1,11 @@ -import { BrainCircuit, Play } from 'lucide-react' import React from 'react' -import { Button } from '../ui/button' interface AnalyzeStageProps { imageSrc: string - statusMessage: string isAnalyzing: boolean - onStart: () => void } -export const AnalyzeStage: React.FC = ({ - imageSrc, - statusMessage, - isAnalyzing, - onStart, -}) => { +export const AnalyzeStage: React.FC = ({ imageSrc, isAnalyzing }) => { return (
{/* Background Frosted Glass Layer */} @@ -49,30 +40,6 @@ export const AnalyzeStage: React.FC = ({
- - {/* Status Text or Action Button */} -
- {isAnalyzing ? ( -
- - {statusMessage} -
-
-
-
-
-
- ) : ( - - )} -