Re_Figma_Code/components/modals/DealerDocumentModal.tsx
2025-10-22 10:27:06 +05:30

311 lines
12 KiB
TypeScript

import React, { useState } from 'react';
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '../ui/dialog';
import { Button } from '../ui/button';
import { Label } from '../ui/label';
import { Textarea } from '../ui/textarea';
import { Badge } from '../ui/badge';
import { Upload, FileText, X, CheckCircle, AlertCircle } from 'lucide-react';
import { toast } from 'sonner@2.0.3';
interface DealerDocumentModalProps {
isOpen: boolean;
onClose: () => void;
onSubmit: (data: {
proposalDocument: File | null;
costBreakup: File | null;
timeline: File | null;
otherDocuments: File[];
dealerComments: string;
}) => Promise<void>;
dealerName: string;
activityName: string;
}
export function DealerDocumentModal({
isOpen,
onClose,
onSubmit,
dealerName,
activityName
}: DealerDocumentModalProps) {
const [proposalDocument, setProposalDocument] = useState<File | null>(null);
const [costBreakup, setCostBreakup] = useState<File | null>(null);
const [timeline, setTimeline] = useState<File | null>(null);
const [otherDocuments, setOtherDocuments] = useState<File[]>([]);
const [dealerComments, setDealerComments] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const handleFileUpload = (field: 'proposal' | 'cost' | 'timeline', file: File | null) => {
if (field === 'proposal') setProposalDocument(file);
if (field === 'cost') setCostBreakup(file);
if (field === 'timeline') setTimeline(file);
};
const handleMultipleFileUpload = (files: FileList | null) => {
if (files) {
const fileArray = Array.from(files);
setOtherDocuments(prev => [...prev, ...fileArray]);
}
};
const removeOtherDocument = (index: number) => {
setOtherDocuments(prev => prev.filter((_, i) => i !== index));
};
const handleSubmit = async () => {
// Validation
if (!proposalDocument) {
toast.error('Proposal document is required');
return;
}
if (!costBreakup) {
toast.error('Cost breakup document is required');
return;
}
if (!timeline) {
toast.error('Timeline document is required');
return;
}
if (!dealerComments.trim()) {
toast.error('Please add dealer comments');
return;
}
setIsSubmitting(true);
try {
await onSubmit({
proposalDocument,
costBreakup,
timeline,
otherDocuments,
dealerComments
});
// Reset form
setProposalDocument(null);
setCostBreakup(null);
setTimeline(null);
setOtherDocuments([]);
setDealerComments('');
onClose();
} catch (error) {
console.error('Error submitting dealer documents:', error);
} finally {
setIsSubmitting(false);
}
};
return (
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent className="max-w-3xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle className="flex items-center gap-2 text-2xl">
<Upload className="w-6 h-6 text-[--re-green]" />
Dealer Document Upload
</DialogTitle>
<DialogDescription className="text-base">
<div className="space-y-1 mt-2">
<p><strong>Dealer:</strong> {dealerName}</p>
<p><strong>Activity:</strong> {activityName}</p>
<p className="text-sm text-gray-600 mt-2">
Please upload all required documents and provide detailed comments about this claim request.
</p>
</div>
</DialogDescription>
</DialogHeader>
<div className="space-y-6 py-4">
{/* Required Documents Section */}
<div className="space-y-4">
<div className="flex items-center gap-2">
<h3 className="font-semibold text-lg">Required Documents</h3>
<Badge variant="destructive" className="text-xs">All Required</Badge>
</div>
{/* Proposal Document */}
<div>
<Label className="text-base font-semibold flex items-center gap-2">
Proposal Document *
{proposalDocument && <CheckCircle className="w-4 h-4 text-green-600" />}
</Label>
<p className="text-sm text-gray-600 mb-2">
Detailed proposal with activity details and requested information
</p>
<div className="border-2 border-dashed border-gray-300 rounded-lg p-4 hover:border-blue-500 transition-colors">
<input
type="file"
accept=".pdf,.doc,.docx"
onChange={(e) => handleFileUpload('proposal', e.target.files?.[0] || null)}
className="hidden"
id="proposalDoc"
/>
<label htmlFor="proposalDoc" className="cursor-pointer flex flex-col items-center gap-2">
<Upload className="w-8 h-8 text-gray-400" />
<span className="text-sm text-gray-600">Click to upload proposal (PDF, DOC, DOCX)</span>
{proposalDocument && (
<Badge variant="secondary" className="mt-2 flex items-center gap-1">
<FileText className="w-3 h-3" />
{proposalDocument.name}
</Badge>
)}
</label>
</div>
</div>
{/* Cost Breakup */}
<div>
<Label className="text-base font-semibold flex items-center gap-2">
Cost Breakup *
{costBreakup && <CheckCircle className="w-4 h-4 text-green-600" />}
</Label>
<p className="text-sm text-gray-600 mb-2">
Detailed cost analysis and breakdown
</p>
<div className="border-2 border-dashed border-gray-300 rounded-lg p-4 hover:border-blue-500 transition-colors">
<input
type="file"
accept=".pdf,.xlsx,.xls,.csv"
onChange={(e) => handleFileUpload('cost', e.target.files?.[0] || null)}
className="hidden"
id="costDoc"
/>
<label htmlFor="costDoc" className="cursor-pointer flex flex-col items-center gap-2">
<Upload className="w-8 h-8 text-gray-400" />
<span className="text-sm text-gray-600">Click to upload cost breakup (Excel, PDF, CSV)</span>
{costBreakup && (
<Badge variant="secondary" className="mt-2 flex items-center gap-1">
<FileText className="w-3 h-3" />
{costBreakup.name}
</Badge>
)}
</label>
</div>
</div>
{/* Timeline for Closure */}
<div>
<Label className="text-base font-semibold flex items-center gap-2">
Timeline for Closure *
{timeline && <CheckCircle className="w-4 h-4 text-green-600" />}
</Label>
<p className="text-sm text-gray-600 mb-2">
Project timeline and milestone details
</p>
<div className="border-2 border-dashed border-gray-300 rounded-lg p-4 hover:border-blue-500 transition-colors">
<input
type="file"
accept=".pdf,.doc,.docx,.xlsx,.xls"
onChange={(e) => handleFileUpload('timeline', e.target.files?.[0] || null)}
className="hidden"
id="timelineDoc"
/>
<label htmlFor="timelineDoc" className="cursor-pointer flex flex-col items-center gap-2">
<Upload className="w-8 h-8 text-gray-400" />
<span className="text-sm text-gray-600">Click to upload timeline (PDF, DOC, Excel)</span>
{timeline && (
<Badge variant="secondary" className="mt-2 flex items-center gap-1">
<FileText className="w-3 h-3" />
{timeline.name}
</Badge>
)}
</label>
</div>
</div>
</div>
{/* Optional Documents */}
<div className="space-y-4">
<div className="flex items-center gap-2">
<h3 className="font-semibold text-lg">Other Supporting Documents</h3>
<Badge variant="secondary" className="text-xs">Optional</Badge>
</div>
<div>
<Label className="text-base font-semibold">Additional Documents</Label>
<p className="text-sm text-gray-600 mb-2">
Any other supporting documents (invoices, receipts, photos, etc.)
</p>
<div className="border-2 border-dashed border-gray-300 rounded-lg p-4 hover:border-blue-500 transition-colors">
<input
type="file"
multiple
onChange={(e) => handleMultipleFileUpload(e.target.files)}
className="hidden"
id="otherDocs"
/>
<label htmlFor="otherDocs" className="cursor-pointer flex flex-col items-center gap-2">
<Upload className="w-8 h-8 text-gray-400" />
<span className="text-sm text-gray-600">Click to upload additional documents (multiple files allowed)</span>
</label>
</div>
{otherDocuments.length > 0 && (
<div className="mt-3 space-y-2">
{otherDocuments.map((file, index) => (
<div key={index} className="flex items-center justify-between p-2 bg-gray-50 rounded border">
<div className="flex items-center gap-2">
<FileText className="w-4 h-4 text-gray-600" />
<span className="text-sm">{file.name}</span>
<span className="text-xs text-gray-500">({(file.size / 1024).toFixed(1)} KB)</span>
</div>
<Button
variant="ghost"
size="sm"
onClick={() => removeOtherDocument(index)}
>
<X className="w-4 h-4" />
</Button>
</div>
))}
</div>
)}
</div>
</div>
{/* Dealer Comments */}
<div className="space-y-2">
<Label htmlFor="dealerComments" className="text-base font-semibold flex items-center gap-2">
Dealer Comments / Details *
{dealerComments.trim() && <CheckCircle className="w-4 h-4 text-green-600" />}
</Label>
<Textarea
id="dealerComments"
placeholder="Provide detailed comments about this claim request, including any special considerations, execution details, or additional information..."
value={dealerComments}
onChange={(e) => setDealerComments(e.target.value)}
className="min-h-[120px]"
/>
<p className="text-xs text-gray-500">
{dealerComments.length} characters
</p>
</div>
{/* Validation Alert */}
{(!proposalDocument || !costBreakup || !timeline || !dealerComments.trim()) && (
<div className="bg-amber-50 border border-amber-200 rounded-lg p-4 flex items-start gap-3">
<AlertCircle className="w-5 h-5 text-amber-600 flex-shrink-0 mt-0.5" />
<div className="text-sm text-amber-800">
<p className="font-semibold mb-1">Missing Required Information</p>
<p>Please ensure all required documents are uploaded and dealer comments are provided before submitting.</p>
</div>
</div>
)}
</div>
<DialogFooter>
<Button variant="outline" onClick={onClose} disabled={isSubmitting}>
Cancel
</Button>
<Button
onClick={handleSubmit}
disabled={isSubmitting || !proposalDocument || !costBreakup || !timeline || !dealerComments.trim()}
className="bg-[--re-green] hover:bg-[--re-green-dark]"
>
{isSubmitting ? 'Submitting...' : 'Submit Documents'}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}