"use client"; import { useEffect, useRef } from "react"; import { CameraIcon, FolderIcon, PlayIcon, PlusIcon, SparklesIcon } from "@/components/icons"; import { Button } from "@/components/ui"; import { DOCUMENT_ACCEPT_ATTR, documentsToText, type ExtractedDocument, } from "@/lib/documents"; import type { HomeworkMode, HomeworkRecord } from "@/lib/schemas"; import { ACCEPTED_TYPES, formatBytes, imageFilesFromDataTransfer } from "@/lib/image"; import { useI18n } from "@/lib/i18n"; import type { useNotesIntake } from "@/lib/use-notes-intake"; import { openSettings } from "@/lib/ui-events"; import { cn } from "@/lib/utils"; import { HomeworkHistory } from "./HomeworkHistory"; /** Same wording the create screen uses for an extracted document. */ function describeExtraction( document: ExtractedDocument, tr: (key: string, vars?: Record) => string, pl: (n: number, base: string, vars?: Record) => string, ): string { const parts = [ pl(document.words, "upload.words", { n: document.words.toLocaleString() }), document.pages ? pl(document.pages, "upload.pages") : "", document.images.length ? pl(document.images.length, "upload.pageImages") : "", document.truncated ? tr("upload.truncated") : "", ]; return parts.filter(Boolean).join(" · "); } const MODES: Array<{ id: HomeworkMode; icon: React.ReactNode; titleKey: string; subtitleKey: string }> = [ { id: "make", icon: , titleKey: "homework.mode.make.title", subtitleKey: "homework.mode.make.subtitle" }, { id: "guide", icon: , titleKey: "homework.mode.guide.title", subtitleKey: "homework.mode.guide.subtitle" }, ]; export function HomeworkInput({ mode, onModeChange, text, onTextChange, intake, onSubmit, error, history, onOpen, onDelete, }: { mode: HomeworkMode; onModeChange: (mode: HomeworkMode) => void; text: string; onTextChange: (text: string) => void; intake: ReturnType; onSubmit: () => void; error: { message: string; kind?: string } | null; history: HomeworkRecord[]; onOpen: (record: HomeworkRecord) => void; onDelete: (id: string) => void; }) { const { t, plural } = useI18n(); const fileInputRef = useRef(null); const cameraInputRef = useRef(null); // Clipboard: screenshots become photos, long copied text becomes the assignment. useEffect(() => { const onPaste = (event: ClipboardEvent) => { const target = event.target as HTMLElement | null; const isTextField = target && /^(INPUT|TEXTAREA)$/.test(target.tagName); const files = imageFilesFromDataTransfer(event.clipboardData); if (files.length > 0) { event.preventDefault(); void intake.addFiles(files); return; } if (!isTextField) { const pasted = event.clipboardData?.getData("text/plain")?.trim(); if (pasted && pasted.length > 40) { event.preventDefault(); onTextChange(text ? `${text}\n${pasted}` : pasted); } } }; window.addEventListener("paste", onPaste); return () => window.removeEventListener("paste", onPaste); }, [intake, onTextChange, text]); const readyDocuments = intake.documents.filter((entry) => entry.status === "ready" && entry.extracted); const documentsBusy = intake.documents.some((entry) => entry.status === "extracting"); const documentImages = readyDocuments.flatMap((entry) => entry.extracted!.images); const documentText = documentsToText(readyDocuments.map((entry) => entry.extracted!)); const totalBytes = intake.images.reduce((sum, image) => sum + image.bytes, 0); const hasContent = intake.images.length > 0 || documentImages.length > 0 || text.trim().length > 0 || documentText.trim().length > 0; const canSubmit = hasContent && !intake.busy && !documentsBusy; const keyError = error?.kind === "needs_key" || error?.kind === "auth"; return (

{t("homework.title")}

{t("homework.subtitle")}

{error ? (

{keyError ? t("upload.errAuth") : t("homework.error.title")}

{error.message || t("homework.error.body")}

{keyError ? ( ) : null}
) : null} {/* ------------------------------------------------ the assignment */}

{t("homework.source.title")}

{t("homework.source.help")}

{ void intake.addFiles(Array.from(event.target.files ?? [])); event.target.value = ""; }} /> { void intake.addFiles(Array.from(event.target.files ?? [])); event.target.value = ""; }} /> {intake.images.length === 0 && intake.documents.length === 0 ? ( ) : (
{intake.images.length > 0 ? (
{intake.images.map((image) => ( {/* eslint-disable-next-line @next/next/no-img-element -- local thumbnail, no optimisation needed */} ))}
) : null} {intake.documents.length > 0 ? (
    {intake.documents.map((entry) => (
  • {entry.name.split(".").pop()?.slice(0, 4) ?? "doc"} {entry.name} {entry.status === "extracting" ? (entry.progress ?? t("upload.reading")) : entry.status === "error" ? entry.error : entry.extracted ? describeExtraction(entry.extracted, t, plural) : ""}
  • ))}
) : null}
)}