uploading pdfs, including images now at claim
This commit is contained in:
@@ -172,12 +172,14 @@ export function ClaimForm({
|
||||
},
|
||||
});
|
||||
useEffect(() => {
|
||||
if (staffMembersRaw.length > 0 && !staff) {
|
||||
const kaiGao = staffMembersRaw.find((member) => member.name === "Kai Gao");
|
||||
const defaultStaff = kaiGao || staffMembersRaw[0];
|
||||
if (defaultStaff) setStaff(defaultStaff);
|
||||
}
|
||||
}, [staffMembersRaw, staff]);
|
||||
if (staffMembersRaw.length > 0 && !staff) {
|
||||
const kaiGao = staffMembersRaw.find(
|
||||
(member) => member.name === "Kai Gao"
|
||||
);
|
||||
const defaultStaff = kaiGao || staffMembersRaw[0];
|
||||
if (defaultStaff) setStaff(defaultStaff);
|
||||
}
|
||||
}, [staffMembersRaw, staff]);
|
||||
|
||||
// Service date state
|
||||
function parseLocalDate(dateInput: Date | string): Date {
|
||||
@@ -333,11 +335,30 @@ export function ClaimForm({
|
||||
const handleFileUpload = (files: File[]) => {
|
||||
setIsUploading(true);
|
||||
|
||||
const validFiles = files.filter((file) => file.type === "application/pdf");
|
||||
if (validFiles.length > 5) {
|
||||
const allowedTypes = [
|
||||
"application/pdf",
|
||||
"image/jpeg",
|
||||
"image/jpg",
|
||||
"image/png",
|
||||
"image/webp",
|
||||
];
|
||||
|
||||
const validFiles = files.filter((file) => allowedTypes.includes(file.type));
|
||||
|
||||
if (validFiles.length > 10) {
|
||||
toast({
|
||||
title: "Too Many Files",
|
||||
description: "You can only upload up to 5 PDFs.",
|
||||
description: "You can only upload up to 10 files (PDFs or images).",
|
||||
variant: "destructive",
|
||||
});
|
||||
setIsUploading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (validFiles.length === 0) {
|
||||
toast({
|
||||
title: "Invalid File Type",
|
||||
description: "Only PDF and image files are allowed.",
|
||||
variant: "destructive",
|
||||
});
|
||||
setIsUploading(false);
|
||||
@@ -351,7 +372,7 @@ export function ClaimForm({
|
||||
|
||||
toast({
|
||||
title: "Files Selected",
|
||||
description: `${validFiles.length} PDF file(s) ready for processing.`,
|
||||
description: `${validFiles.length} file(s) ready for processing.`,
|
||||
});
|
||||
|
||||
setIsUploading(false);
|
||||
@@ -711,34 +732,15 @@ export function ClaimForm({
|
||||
{/* File Upload Section */}
|
||||
<div className="mt-4 bg-gray-100 p-4 rounded-md space-y-4">
|
||||
<p className="text-sm text-gray-500">
|
||||
Only PDF files allowed. You can upload up to 5 files. File types
|
||||
with 4+ character extensions like .DOCX, .PPTX, or .XLSX are not
|
||||
allowed.
|
||||
You can upload up to 10 files. Allowed types: PDF, JPG, PNG,
|
||||
WEBP.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-wrap gap-4 items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<Label>Select Field:</Label>
|
||||
<Select defaultValue="supportData">
|
||||
<SelectTrigger className="w-60">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="supportData">
|
||||
Support Data for Claim
|
||||
</SelectItem>
|
||||
<SelectItem value="xrays">X-Ray Images</SelectItem>
|
||||
<SelectItem value="photos">Clinical Photos</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<MultipleFileUploadZone
|
||||
onFileUpload={handleFileUpload}
|
||||
isUploading={isUploading}
|
||||
acceptedFileTypes="application/pdf"
|
||||
maxFiles={5}
|
||||
acceptedFileTypes="application/pdf,image/jpeg,image/jpg,image/png,image/webp"
|
||||
maxFiles={10}
|
||||
/>
|
||||
|
||||
{form.uploadedFiles.length > 0 && (
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, { useState, useRef, useCallback } from 'react';
|
||||
import { Upload, File, X, FilePlus } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
import { cn } from '@/lib/utils';
|
||||
import React, { useState, useRef, useCallback } from "react";
|
||||
import { Upload, File, X, FilePlus } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface FileUploadZoneProps {
|
||||
onFileUpload: (files: File[]) => void;
|
||||
@@ -11,43 +11,25 @@ interface FileUploadZoneProps {
|
||||
maxFiles?: number;
|
||||
}
|
||||
|
||||
export function MultipleFileUploadZone({
|
||||
onFileUpload,
|
||||
isUploading,
|
||||
acceptedFileTypes = "application/pdf",
|
||||
maxFiles = 5,
|
||||
export function MultipleFileUploadZone({
|
||||
onFileUpload,
|
||||
isUploading,
|
||||
acceptedFileTypes = "application/pdf,image/jpeg,image/jpg,image/png,image/webp",
|
||||
maxFiles = 10,
|
||||
}: FileUploadZoneProps) {
|
||||
const { toast } = useToast();
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [uploadedFiles, setUploadedFiles] = useState<File[]>([]);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const handleDragEnter = useCallback((e: React.DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsDragging(true);
|
||||
}, []);
|
||||
|
||||
const handleDragLeave = useCallback((e: React.DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsDragging(false);
|
||||
}, []);
|
||||
|
||||
const handleDragOver = useCallback((e: React.DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (!isDragging) {
|
||||
setIsDragging(true);
|
||||
}
|
||||
}, [isDragging]);
|
||||
const allowedTypes = acceptedFileTypes.split(",").map((type) => type.trim());
|
||||
|
||||
const validateFile = (file: File) => {
|
||||
if (!file.type.match(acceptedFileTypes)) {
|
||||
if (!allowedTypes.includes(file.type)) {
|
||||
toast({
|
||||
title: "Invalid file type",
|
||||
description: "Please upload a PDF file.",
|
||||
variant: "destructive"
|
||||
description: "Only PDF and image files are allowed.",
|
||||
variant: "destructive",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
@@ -55,8 +37,8 @@ export function MultipleFileUploadZone({
|
||||
if (file.size > 5 * 1024 * 1024) {
|
||||
toast({
|
||||
title: "File too large",
|
||||
description: "File size should be less than 5MB.",
|
||||
variant: "destructive"
|
||||
description: "File size must be less than 5MB.",
|
||||
variant: "destructive",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
@@ -84,16 +66,45 @@ export function MultipleFileUploadZone({
|
||||
onFileUpload(updatedFiles);
|
||||
};
|
||||
|
||||
const handleDrop = useCallback((e: React.DragEvent<HTMLDivElement>) => {
|
||||
const handleDragEnter = useCallback((e: React.DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsDragging(true);
|
||||
}, []);
|
||||
|
||||
const handleDragLeave = useCallback((e: React.DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsDragging(false);
|
||||
handleFiles(e.dataTransfer.files);
|
||||
}, [uploadedFiles]);
|
||||
}, []);
|
||||
|
||||
const handleFileSelect = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
handleFiles(e.target.files);
|
||||
}, [uploadedFiles]);
|
||||
const handleDragOver = useCallback(
|
||||
(e: React.DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (!isDragging) {
|
||||
setIsDragging(true);
|
||||
}
|
||||
},
|
||||
[isDragging]
|
||||
);
|
||||
|
||||
const handleDrop = useCallback(
|
||||
(e: React.DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsDragging(false);
|
||||
handleFiles(e.dataTransfer.files);
|
||||
},
|
||||
[uploadedFiles]
|
||||
);
|
||||
|
||||
const handleFileSelect = useCallback(
|
||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
handleFiles(e.target.files);
|
||||
},
|
||||
[uploadedFiles]
|
||||
);
|
||||
|
||||
const handleBrowseClick = () => {
|
||||
if (fileInputRef.current) {
|
||||
@@ -118,11 +129,13 @@ export function MultipleFileUploadZone({
|
||||
accept={acceptedFileTypes}
|
||||
multiple
|
||||
/>
|
||||
|
||||
|
||||
<div
|
||||
className={cn(
|
||||
"border-2 border-dashed rounded-lg p-8 flex flex-col items-center justify-center text-center transition-colors",
|
||||
isDragging ? "border-primary bg-primary/5" : "border-muted-foreground/25",
|
||||
isDragging
|
||||
? "border-primary bg-primary/5"
|
||||
: "border-muted-foreground/25",
|
||||
isUploading && "opacity-50 cursor-not-allowed"
|
||||
)}
|
||||
onDragEnter={handleDragEnter}
|
||||
@@ -141,12 +154,17 @@ export function MultipleFileUploadZone({
|
||||
</div>
|
||||
) : uploadedFiles.length > 0 ? (
|
||||
<div className="flex flex-col items-center gap-4 w-full">
|
||||
<p className="font-medium text-primary">{uploadedFiles.length} file(s) uploaded</p>
|
||||
<p className="font-medium text-primary">
|
||||
{uploadedFiles.length} file(s) uploaded
|
||||
</p>
|
||||
<ul className="w-full text-left space-y-2">
|
||||
{uploadedFiles.map((file, index) => (
|
||||
<li key={index} className="flex justify-between items-center border-b pb-1">
|
||||
<li
|
||||
key={index}
|
||||
className="flex justify-between items-center border-b pb-1"
|
||||
>
|
||||
<span className="text-sm">{file.name}</span>
|
||||
<button
|
||||
<button
|
||||
className="ml-2 p-1 text-muted-foreground hover:text-red-500"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
@@ -163,16 +181,26 @@ export function MultipleFileUploadZone({
|
||||
<div className="flex flex-col items-center gap-4">
|
||||
<FilePlus className="h-12 w-12 text-primary/70" />
|
||||
<div>
|
||||
<p className="font-medium text-primary">Drag and drop PDF files here</p>
|
||||
<p className="text-sm text-muted-foreground mt-1">Or click to browse files</p>
|
||||
<p className="font-medium text-primary">
|
||||
Drag and drop PDF or Image files here
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
Or click to browse files
|
||||
</p>
|
||||
</div>
|
||||
<Button type="button" variant="secondary" onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleBrowseClick();
|
||||
}}>
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleBrowseClick();
|
||||
}}
|
||||
>
|
||||
Browse files
|
||||
</Button>
|
||||
<p className="text-xs text-muted-foreground">Up to {maxFiles} PDF files, 5MB each</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Allowed types: PDF, JPG, PNG — Max {maxFiles} files, 5MB each
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -219,7 +219,7 @@ export default function ClaimsPage() {
|
||||
const handleSeleniumPopup = async (actionType: string) => {
|
||||
try {
|
||||
if (!claimRes?.id) {
|
||||
throw new Error("Missing claimId");
|
||||
throw new Error("Missing claimId");
|
||||
}
|
||||
if (!selectedPatient) {
|
||||
throw new Error("Missing patientId");
|
||||
@@ -518,13 +518,16 @@ export default function ClaimsPage() {
|
||||
// handle selenium
|
||||
const handleSelenium = async (data: any) => {
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append("data", JSON.stringify(data));
|
||||
|
||||
const uploadedFiles: File[] = data.uploadedFiles ?? [];
|
||||
|
||||
uploadedFiles.forEach((file: File) => {
|
||||
formData.append("pdfs", file);
|
||||
if (file.type === "application/pdf") {
|
||||
formData.append("pdfs", file);
|
||||
} else if (file.type.startsWith("image/")) {
|
||||
formData.append("images", file);
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
@@ -537,7 +540,8 @@ export default function ClaimsPage() {
|
||||
|
||||
toast({
|
||||
title: "Selenium service notified",
|
||||
description: "Your claim data was successfully sent to Selenium.",
|
||||
description:
|
||||
"Your claim data was successfully sent to Selenium, Wait for its response.",
|
||||
variant: "default",
|
||||
});
|
||||
setIsMhPopupOpen(true);
|
||||
|
||||
Reference in New Issue
Block a user