92 lines
2.7 KiB
TypeScript
92 lines
2.7 KiB
TypeScript
"use client";
|
|
|
|
import React, { useRef, useState } from "react";
|
|
import Button from "@/app/ui/Button";
|
|
|
|
/**
|
|
* File upload tab for importing `.ics` calendar files.
|
|
*
|
|
* Supports both file picker selection and drag-and-drop.
|
|
* Sends the file content to `/api/calendar/parse` for server-side ICS parsing.
|
|
*/
|
|
type FileTabProps = {
|
|
onLoadCalendar: (file: File) => Promise<void>;
|
|
loading: boolean;
|
|
error: string | null;
|
|
className?: string;
|
|
};
|
|
|
|
const FileTab: React.FC<FileTabProps> = ({ onLoadCalendar, loading, error, className = "" }) => {
|
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
const [dragging, setDragging] = useState(false);
|
|
|
|
const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const file = e.target.files?.[0];
|
|
if (file) {
|
|
handleFileUpload(file);
|
|
}
|
|
};
|
|
|
|
const handleFileUpload = async (file: File) => {
|
|
try {
|
|
await onLoadCalendar(file);
|
|
if (fileInputRef.current) {
|
|
fileInputRef.current.value = "";
|
|
}
|
|
} catch (err) {
|
|
console.error("Error uploading file:", err);
|
|
}
|
|
};
|
|
|
|
const handleDragEnter = (e: React.DragEvent) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
setDragging(true);
|
|
};
|
|
|
|
const handleDragLeave = (e: React.DragEvent) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
setDragging(false);
|
|
};
|
|
|
|
const handleDragOver = (e: React.DragEvent) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
setDragging(true);
|
|
};
|
|
|
|
const handleDrop = (e: React.DragEvent) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
setDragging(false);
|
|
|
|
const files = e.dataTransfer.files;
|
|
if (files.length > 0) {
|
|
handleFileUpload(files[0]);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className={`p-1 ${className}`}>
|
|
<div
|
|
className={`mb-4 cursor-pointer rounded-2xl border border-dashed p-8 text-center text-sm transition-colors ${dragging ? "border-[#D946EF] bg-[#B23CFF]/12 text-white" : "border-white/20 bg-white/[0.04] text-[#F4F1EA]/68 hover:border-[#D946EF]/50 hover:bg-white/[0.06]"}`}
|
|
onDragEnter={handleDragEnter}
|
|
onDragLeave={handleDragLeave}
|
|
onDragOver={handleDragOver}
|
|
onDrop={handleDrop}
|
|
onClick={() => fileInputRef.current?.click()}
|
|
>
|
|
<input type="file" ref={fileInputRef} onChange={handleFileSelect} accept=".ics" className="hidden" />
|
|
{loading ? <>Loading calendar...</> : <>Click to upload or drag and drop an .ics file here</>}
|
|
</div>
|
|
{error && <div className="mb-4 text-sm text-[#FF2D8D]">{error}</div>}
|
|
<Button onClick={() => fileInputRef.current?.click()} disabled={loading}>
|
|
{loading ? <>Select File</> : <>Select File</>}
|
|
</Button>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default FileTab;
|