import type { DragEvent, RefObject } from "react";
import { useRef, useState } from "react";
import type { RecordType } from "../../api/types";
import { recordTypes, RECORD_LIMITS } from "../../logic/records";
import { Button, Callout, cn, fieldClass, Icon, labelClass, Tag } from "../kit";
export type Pending = { key: string; file: File | null; text: string | null; title: string; type: RecordType; place: string; recordDate: string; origin: "upload" | "camera" | "pasted"; error: string | null };
/** REC-1 to REC-3: drop, choose, photograph or paste records, name each one, then add them all. */
export function AddRecords({
pending,
notice,
busy,
chooseRef,
onChoose,
onPaste,
onUpdate,
onRemove,
onClear,
onAddAll,
}: {
pending: Pending[];
notice: string;
busy: boolean;
chooseRef: RefObject<HTMLButtonElement | null>;
onChoose: (files: FileList | File[], origin: "upload" | "camera") => void;
onPaste: () => void;
onUpdate: (key: string, change: Partial<Pending>) => void;
onRemove: (key: string) => void;
onClear: () => void;
onAddAll: () => void;
}) {
const [drag, setDrag] = useState(false);
const fileInput = useRef<HTMLInputElement>(null);
const cameraInput = useRef<HTMLInputElement>(null);
const ready = pending.filter((p) => !p.error).length;
const onDrop = (e: DragEvent) => {
e.preventDefault();
setDrag(false);
if (e.dataTransfer.files.length) onChoose(e.dataTransfer.files, "upload");
};
return (
<section aria-label="Add records" data-add-records="" className="flex scroll-mt-20 flex-col gap-4 rounded-2xl bg-page p-5 shadow-card max-sm:p-4">
<div className="flex flex-wrap items-center justify-between gap-2">
<h2 className="m-0 flex items-center gap-2 text-[15px] leading-5 font-semibold tracking-[-0.01em] text-ink">
<Icon name="upload-cloud-2-line" size={17} className="text-muted" />
Add records
</h2>
<span className="font-mono text-[11.5px] text-muted">TXT, PDF, JPG, PNG, HEIC · 15 MB each</span>
</div>
<div
className={cn(
"flex flex-col items-center gap-3 rounded-xl border border-dashed px-4 py-7 text-center transition-colors duration-150",
drag ? "border-brand bg-green-fill" : "border-line bg-tile",
)}
onDragOver={(e) => {
e.preventDefault();
setDrag(true);
}}
onDragLeave={() => setDrag(false)}
onDrop={onDrop}
>
<Icon name="upload-2-line" size={22} className="text-muted" />
<p className="m-0 text-[13.5px] text-cell">Drag files here, or</p>
<div className="flex flex-wrap justify-center gap-2">
<Button ref={chooseRef} variant="quiet" className="bg-page shadow-chip hover:bg-page hover:shadow-card-hover" onClick={() => fileInput.current?.click()}>
Choose files
</Button>
<Button variant="quiet" className="bg-page shadow-chip hover:bg-page hover:shadow-card-hover" onClick={() => cameraInput.current?.click()}>
Take a photo
</Button>
<Button variant="quiet" className="bg-page shadow-chip hover:bg-page hover:shadow-card-hover" onClick={onPaste}>
Paste or type a note
</Button>
</div>
<input ref={fileInput} hidden type="file" multiple accept=".txt,.pdf,.jpg,.jpeg,.png,.heic,text/plain,application/pdf,image/jpeg,image/png,image/heic" onChange={(e) => { if (e.target.files) onChoose(e.target.files, "upload"); e.target.value = ""; }} />
<input ref={cameraInput} hidden type="file" accept="image/*" capture="environment" onChange={(e) => { if (e.target.files) onChoose(e.target.files, "camera"); e.target.value = ""; }} />
<small className="max-w-md text-[12px] leading-[18px] text-muted">
Up to {RECORD_LIMITS.perCheck} records per check and {RECORD_LIMITS.pagesPerDocument} pages per document. Scans and photos are read on MARMAR's servers.
</small>
</div>
{notice && (
<Callout tone="amber" role="status">
{notice}
</Callout>
)}
{pending.length > 0 && (
<div className="flex flex-col gap-3">
{pending.map((p) => (
<fieldset key={p.key} className={cn("m-0 flex min-w-0 flex-col gap-3 rounded-xl border-0 p-4", p.error ? "bg-red-fill/50 shadow-[inset_0_0_0_1px_var(--color-red-line)]" : "bg-tile")}>
<legend className="sr-only">{p.file ? p.file.name : "Pasted note"}</legend>
<div className="flex min-w-0 items-center justify-between gap-3">
<span aria-hidden="true" className="flex min-w-0">
<Tag lead={p.file ? "file-text-line" : "edit-line"} className="min-w-0 truncate">
{p.file ? p.file.name : "Pasted note"}
</Tag>
</span>
<Button variant="ghost" size="sm" onClick={() => onRemove(p.key)}>
Remove
</Button>
</div>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<label className={labelClass}>
Title
<input className={fieldClass} value={p.title} maxLength={120} onChange={(e) => onUpdate(p.key, { title: e.target.value })} />
</label>
<label className={labelClass}>
Type
<select className={cn(fieldClass, "pr-8")} value={p.type} onChange={(e) => onUpdate(p.key, { type: e.target.value as RecordType })}>
{Object.entries(recordTypes).map(([v, l]) => (
<option key={v} value={v}>
{l}
</option>
))}
</select>
</label>
<label className={labelClass}>
Where it came from
<input className={fieldClass} value={p.place} placeholder="Clinic, lab or hospital" maxLength={120} onChange={(e) => onUpdate(p.key, { place: e.target.value })} />
</label>
<label className={labelClass}>
Date on the record
<input className={fieldClass} type="date" value={p.recordDate} onChange={(e) => onUpdate(p.key, { recordDate: e.target.value })} />
</label>
</div>
{p.error && (
<p className="m-0 text-[12.5px] font-medium text-red-text" role="alert">
{p.error}
</p>
)}
</fieldset>
))}
<div className="flex flex-wrap justify-end gap-2">
<Button variant="ghost" onClick={onClear}>
Clear
</Button>
<Button variant="primary" disabled={busy || pending.every((p) => p.error)} onClick={onAddAll}>
{busy ? "Adding…" : `Add ${ready} ${ready === 1 ? "record" : "records"}`}
</Button>
</div>
</div>
)}
</section>
);
}