159 lines
5.6 KiB
JavaScript
159 lines
5.6 KiB
JavaScript
import React, { useState } from "react";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Label } from "@/components/ui/label";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Card, CardContent } from "@/components/ui/card";
|
|
import { Upload, FileText, CheckCircle, X } from "lucide-react";
|
|
import { base44 } from "@/api/base44Client";
|
|
import { useToast } from "@/components/ui/use-toast";
|
|
|
|
const requiredDocuments = [
|
|
{ id: 'id', name: 'Government ID', required: true, description: 'Driver\'s license or passport' },
|
|
{ id: 'certification', name: 'Certifications', required: false, description: 'Food handler, TIPS, etc.' },
|
|
{ id: 'background_check', name: 'Background Check', required: false, description: 'If available' },
|
|
];
|
|
|
|
export default function DocumentUploadStep({ data, onNext, onBack }) {
|
|
const [documents, setDocuments] = useState(data || []);
|
|
const [uploading, setUploading] = useState({});
|
|
const { toast } = useToast();
|
|
|
|
const handleFileUpload = async (docType, file) => {
|
|
if (!file) return;
|
|
|
|
setUploading(prev => ({ ...prev, [docType]: true }));
|
|
|
|
try {
|
|
const { file_url } = await base44.integrations.Core.UploadFile({ file });
|
|
|
|
const newDoc = {
|
|
type: docType,
|
|
name: file.name,
|
|
url: file_url,
|
|
uploaded_at: new Date().toISOString(),
|
|
};
|
|
|
|
setDocuments(prev => {
|
|
const filtered = prev.filter(d => d.type !== docType);
|
|
return [...filtered, newDoc];
|
|
});
|
|
|
|
toast({
|
|
title: "✅ Document Uploaded",
|
|
description: `${file.name} uploaded successfully`,
|
|
});
|
|
} catch (error) {
|
|
toast({
|
|
title: "❌ Upload Failed",
|
|
description: error.message,
|
|
variant: "destructive",
|
|
});
|
|
} finally {
|
|
setUploading(prev => ({ ...prev, [docType]: false }));
|
|
}
|
|
};
|
|
|
|
const handleRemoveDocument = (docType) => {
|
|
setDocuments(prev => prev.filter(d => d.type !== docType));
|
|
};
|
|
|
|
const handleNext = () => {
|
|
const hasRequiredDocs = requiredDocuments
|
|
.filter(doc => doc.required)
|
|
.every(doc => documents.some(d => d.type === doc.id));
|
|
|
|
if (!hasRequiredDocs) {
|
|
toast({
|
|
title: "⚠️ Missing Required Documents",
|
|
description: "Please upload all required documents before continuing",
|
|
variant: "destructive",
|
|
});
|
|
return;
|
|
}
|
|
|
|
onNext({ type: 'documents', data: documents });
|
|
};
|
|
|
|
const getUploadedDoc = (docType) => documents.find(d => d.type === docType);
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div>
|
|
<h2 className="text-xl font-bold text-slate-900 mb-2">Document Upload</h2>
|
|
<p className="text-sm text-slate-500">Upload required documents for compliance</p>
|
|
</div>
|
|
|
|
<div className="space-y-4">
|
|
{requiredDocuments.map(doc => {
|
|
const uploadedDoc = getUploadedDoc(doc.id);
|
|
const isUploading = uploading[doc.id];
|
|
|
|
return (
|
|
<Card key={doc.id} className={uploadedDoc ? "border-green-500 bg-green-50" : ""}>
|
|
<CardContent className="p-4">
|
|
<div className="flex items-start justify-between">
|
|
<div className="flex-1">
|
|
<div className="flex items-center gap-2 mb-1">
|
|
<Label className="font-semibold">
|
|
{doc.name}
|
|
{doc.required && <span className="text-red-500 ml-1">*</span>}
|
|
</Label>
|
|
{uploadedDoc && (
|
|
<CheckCircle className="w-5 h-5 text-green-600" />
|
|
)}
|
|
</div>
|
|
<p className="text-sm text-slate-500">{doc.description}</p>
|
|
|
|
{uploadedDoc && (
|
|
<div className="mt-2 flex items-center gap-2">
|
|
<FileText className="w-4 h-4 text-slate-500" />
|
|
<span className="text-sm text-slate-700">{uploadedDoc.name}</span>
|
|
<button
|
|
onClick={() => handleRemoveDocument(doc.id)}
|
|
className="ml-2 text-red-500 hover:text-red-700"
|
|
>
|
|
<X className="w-4 h-4" />
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div>
|
|
<label
|
|
htmlFor={`upload-${doc.id}`}
|
|
className={`cursor-pointer inline-flex items-center px-4 py-2 rounded-lg ${
|
|
uploadedDoc
|
|
? "bg-green-100 text-green-700 hover:bg-green-200"
|
|
: "bg-blue-100 text-blue-700 hover:bg-blue-200"
|
|
} transition-colors`}
|
|
>
|
|
<Upload className="w-4 h-4 mr-2" />
|
|
{isUploading ? "Uploading..." : uploadedDoc ? "Replace" : "Upload"}
|
|
</label>
|
|
<input
|
|
id={`upload-${doc.id}`}
|
|
type="file"
|
|
className="hidden"
|
|
accept=".pdf,.jpg,.jpeg,.png"
|
|
onChange={(e) => handleFileUpload(doc.id, e.target.files[0])}
|
|
disabled={isUploading}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
<div className="flex justify-between pt-4">
|
|
<Button variant="outline" onClick={onBack}>
|
|
Back
|
|
</Button>
|
|
<Button onClick={handleNext} className="bg-[#0A39DF]">
|
|
Continue to Training
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |