feat(page): wire image upload state, base64 conversion, and API integration into home page

This commit is contained in:
2026-04-07 11:58:10 -04:00
parent 5e888ce7ae
commit 95de6ae46a

View File

@@ -21,6 +21,14 @@ import { EventsList } from "@/components/events-list";
import { EventDialog } from "@/components/event-dialog"; import { EventDialog } from "@/components/event-dialog";
import { DragDropContainer } from "@/components/drag-drop-container"; import { DragDropContainer } from "@/components/drag-drop-container";
const fileToBase64 = (file: File): Promise<string> =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result as string);
reader.onerror = () => reject(new Error("Failed to read file"));
reader.readAsDataURL(file);
});
export default function HomePage() { export default function HomePage() {
const [events, setEvents] = useState<CalendarEvent[]>([]); const [events, setEvents] = useState<CalendarEvent[]>([]);
const [dialogOpen, setDialogOpen] = useState(false); const [dialogOpen, setDialogOpen] = useState(false);
@@ -45,6 +53,10 @@ export default function HomePage() {
const [summary, setSummary] = useState<string | null>(null); const [summary, setSummary] = useState<string | null>(null);
const [summaryUpdated, setSummaryUpdated] = useState<string | null>(null); const [summaryUpdated, setSummaryUpdated] = useState<string | null>(null);
// Image
const [imageBase64, setImageBase64] = useState<string | null>(null);
const [imagePreview, setImagePreview] = useState<string | null>(null);
useEffect(() => { useEffect(() => {
(async () => { (async () => {
const stored = await getAllEvents(); const stored = await getAllEvents();
@@ -66,6 +78,20 @@ export default function HomePage() {
setRecurrenceRule(undefined); setRecurrenceRule(undefined);
}; };
const handleImageSelect = async (file: File) => {
const base64 = await fileToBase64(file);
setImageBase64(base64);
setImagePreview(URL.createObjectURL(file));
};
const handleImageClear = () => {
if (imagePreview) {
URL.revokeObjectURL(imagePreview);
}
setImageBase64(null);
setImagePreview(null);
};
const handleSave = async () => { const handleSave = async () => {
const eventData: CalendarEvent = { const eventData: CalendarEvent = {
id: editingId || nanoid(), id: editingId || nanoid(),
@@ -130,7 +156,7 @@ export default function HomePage() {
// AI Create Event // AI Create Event
const handleAiCreate = async () => { const handleAiCreate = async () => {
if (!aiPrompt.trim()) return; if (!aiPrompt.trim() && !imageBase64) return;
setAiLoading(true); setAiLoading(true);
const promise = (): Promise<{ message: string }> => const promise = (): Promise<{ message: string }> =>
@@ -139,7 +165,10 @@ export default function HomePage() {
const res = await fetch("/api/ai-event", { const res = await fetch("/api/ai-event", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ prompt: aiPrompt }), body: JSON.stringify({
prompt: aiPrompt,
imageBase64: imageBase64 || undefined,
}),
}); });
if (res.status === 401) { if (res.status === 401) {
@@ -154,7 +183,6 @@ export default function HomePage() {
if (Array.isArray(data) && data.length > 0) { if (Array.isArray(data) && data.length > 0) {
if (data.length === 1) { if (data.length === 1) {
// Prefill dialog directly (same as before)
const ev = data[0]; const ev = data[0];
setTitle(ev.title || ""); setTitle(ev.title || "");
setDescription(ev.description || ""); setDescription(ev.description || "");
@@ -167,11 +195,11 @@ export default function HomePage() {
setAiPrompt(""); setAiPrompt("");
setDialogOpen(true); setDialogOpen(true);
setRecurrenceRule(ev.recurrenceRule || undefined); setRecurrenceRule(ev.recurrenceRule || undefined);
handleImageClear();
resolve({ resolve({
message: "Event has been created!", message: "Event has been created!",
}); });
} else { } else {
// Save them all directly to DB
for (const ev of data) { for (const ev of data) {
const newEvent = { const newEvent = {
id: nanoid(), id: nanoid(),
@@ -186,8 +214,9 @@ export default function HomePage() {
setAiPrompt(""); setAiPrompt("");
setSummary(`Added ${data.length} AI-generated events.`); setSummary(`Added ${data.length} AI-generated events.`);
setSummaryUpdated(new Date().toLocaleString()); setSummaryUpdated(new Date().toLocaleString());
handleImageClear();
resolve({ resolve({
message: "Event has been created!", message: "Events have been created!",
}); });
} }
} else { } else {
@@ -264,6 +293,7 @@ export default function HomePage() {
isDragOver={isDragOver} isDragOver={isDragOver}
setIsDragOver={setIsDragOver} setIsDragOver={setIsDragOver}
onImport={handleImport} onImport={handleImport}
onImageDrop={handleImageSelect}
> >
<AIToolbar <AIToolbar
isAuthenticated={!!session?.user} isAuthenticated={!!session?.user}
@@ -271,6 +301,9 @@ export default function HomePage() {
aiPrompt={aiPrompt} aiPrompt={aiPrompt}
setAiPrompt={setAiPrompt} setAiPrompt={setAiPrompt}
aiLoading={aiLoading} aiLoading={aiLoading}
imagePreview={imagePreview}
onImageSelect={handleImageSelect}
onImageClear={handleImageClear}
onAiCreate={handleAiCreate} onAiCreate={handleAiCreate}
onAiSummarize={handleAiSummarize} onAiSummarize={handleAiSummarize}
summary={summary} summary={summary}