"use client"; import { Message } from "@/lib/types"; import axios from "axios"; import { AnimatePresence, motion } from "framer-motion"; import Link from "next/link"; import { redirect } from "next/navigation"; import { Dispatch, SetStateAction, useCallback, useEffect, useRef, useState, } from "react"; import { FileRejection, useDropzone } from "react-dropzone"; import { MdClose } from "react-icons/md"; import Button from "../components/ui/Button"; import Card from "../components/ui/Card"; import Field from "../components/ui/Field"; import PageHeading from "../components/ui/PageHeading"; import Toast, { ToastRef } from "../components/ui/Toast"; import { useSupabase } from "../supabase-provider"; export default function UploadPage() { const [message, setMessage] = useState(null); const [isPending, setIsPending] = useState(false); const [files, setFiles] = useState([]); const [pendingFileIndex, setPendingFileIndex] = useState(0); const urlInputRef = useRef(null); const { session } = useSupabase(); if (session === null) { redirect("/login"); } const messageToast = useRef(null); useEffect(() => { if (!message) return; messageToast.current?.publish({ variant: message.type === "error" ? "danger" : message.type === "warning" ? "neutral" : "success", text: message.text, }); }, [message]); const crawlWebsite = useCallback(async () => { // Validate URL const url = urlInputRef.current ? urlInputRef.current.value : null; if (!url || !isValidUrl(url)) { // Assuming you have a function to validate URLs setMessage({ type: "error", text: "Invalid URL", }); return; } // Configure parameters const config = { url: url, js: false, depth: 1, max_pages: 100, max_time: 60, }; try { const response = await axios.post( `${process.env.NEXT_PUBLIC_BACKEND_URL}/crawl`, config, { headers: { Authorization: `Bearer ${session.access_token}`, }, } ); setMessage({ type: response.data.type, text: response.data.message, }); } catch (error: unknown) { setMessage({ type: "error", text: "Failed to crawl website: " + JSON.stringify(error), }); } }, [session.access_token]); const upload = useCallback( async (file: File) => { const formData = new FormData(); formData.append("file", file); try { const response = await axios.post( `${process.env.NEXT_PUBLIC_BACKEND_URL}/upload`, formData, { headers: { Authorization: `Bearer ${session.access_token}`, }, } ); setMessage({ type: response.data.type, text: (response.data.type === "success" ? "File uploaded successfully: " : "") + JSON.stringify(response.data.message), }); } catch (error: unknown) { setMessage({ type: "error", text: "Failed to upload file: " + JSON.stringify(error), }); } }, [session.access_token] ); const onDrop = (acceptedFiles: File[], fileRejections: FileRejection[]) => { if (fileRejections.length > 0) { setMessage({ type: "error", text: "File too big." }); return; } setMessage(null); for (let i = 0; i < acceptedFiles.length; i++) { const file = acceptedFiles[i]; const isAlreadyInFiles = files.filter((f) => f.name === file.name && f.size === file.size) .length > 0; if (isAlreadyInFiles) { setMessage({ type: "warning", text: `${file.name} was already added` }); acceptedFiles.splice(i, 1); } } setFiles((files) => [...files, ...acceptedFiles]); }; const uploadAllFiles = async () => { setIsPending(true); setMessage(null); // files.forEach((file) => upload(file)); for (const file of files) { await upload(file); setPendingFileIndex((i) => i + 1); } setPendingFileIndex(0); setIsPending(false); }; const { getRootProps, getInputProps, isDragActive, open } = useDropzone({ onDrop, noClick: true, maxSize: 100000000, // 1 MB }); return (
{/* Wrap the cards in a flex container */}
{/* Assign a width of 50% to each card */}
{files.length > 0 ? ( {files.map((file) => ( ))} ) : null} {isDragActive ? (

Drop the files here...

) : ( )}
{/* Assign a width of 50% to each card */}
); } const FileComponent = ({ file, setFiles, }: { file: File; setFiles: Dispatch>; }) => { return (
{file.name} {(file.size / 1000).toFixed(3)} kb
); }; function isValidUrl(string: string) { try { new URL(string); return true; } catch (_) { return false; } }