import { Button, CircularProgress, CircularProgressLabel, Container, FormControl, FormLabel, Heading, HStack, Input, Link, Text, useToast, } from "@chakra-ui/react"; import { useEffect, useState } from "react"; import Login from "../components/Login"; import Success from "../components/Success"; export function Page(pageProps: { [p: string]: any }) { if (!pageProps.logged_in) return ; const [fileProgress, setFileProgress] = useState(0); const [showSuccess, setShowSuccess] = useState(false); const [supportsRequestStreams, setSupportsRequestStreams] = useState(false); const toast = useToast(); const [uploading, setUploading] = useState(false); useEffect(() => { if (sessionStorage.getItem("REPORT_SUCCESS")) { sessionStorage.removeItem("REPORT_SUCCESS"); return setShowSuccess(true); } setSupportsRequestStreams( (() => { let duplexAccessed = false; const hasContentType = new Request("", { body: new ReadableStream(), method: "POST", // @ts-ignore get duplex() { duplexAccessed = true; return "half"; }, }).headers.has("Content-Type"); return duplexAccessed && !hasContentType; })() ); }, []); async function submit() { const usernames = ( document.getElementById("usernames") as HTMLInputElement ).value .replaceAll(" ", "") .split(","); const file = ( document.getElementById("evidence") as HTMLInputElement ).files?.item(0); if (!usernames.length) return toast({ description: "Must provide at least one username", isClosable: true, status: "error", title: "Error", }); if (!file) return toast({ description: "Must attach a file", isClosable: true, status: "error", title: "Error", }); if (usernames.length > 20) return toast({ description: "Only up to twenty users can be reported at a time", isClosable: true, status: "error", title: "Too Many Usernames", }); const submitReq = await fetch("/api/reports/submit", { body: JSON.stringify({ filename: file.name, filesize: file.size, usernames, }), headers: { "content-type": "application/json", }, method: "POST", }); if (!submitReq.ok) return toast({ description: ((await submitReq.json()) as { error: string }).error, isClosable: true, status: "error", title: "Error", }); const { id, upload_url }: { id: string; upload_url: string } = await submitReq.json(); setUploading(true); const reader = file.stream().getReader(); let bytesRead = 0; const uploadReq = await fetch(upload_url, { body: supportsRequestStreams ? new ReadableStream({ async pull(controller) { const chunk = await reader.read(); if (chunk.done) { controller.close(); setUploading(false); return; } controller.enqueue(chunk.value); bytesRead += chunk.value.length; setFileProgress(Math.floor((bytesRead / file.size) * 100)); }, }) : file, // @ts-expect-error duplex: supportsRequestStreams ? "half" : undefined, headers: { "content-type": file.type, }, method: "PUT", }).catch(console.error); if (!uploadReq?.ok) { await fetch("/api/reports/recall", { body: JSON.stringify({ id }), headers: { "content-type": "application/json", }, method: "POST", }); return toast({ description: "Failed to upload file", isClosable: true, status: "error", title: "Error", }); } await fetch("/api/reports/complete", { body: JSON.stringify({ id }), headers: { "content-type": "application/json", }, method: "POST", }); sessionStorage.setItem("REPORT_SUCCESS", "1"); } return showSuccess ? ( ) : ( Report an Exploiter
Username(s) - To specify more than one, provide a comma-delimited list (User1, User2, User3...)
Your Evidence (Max Size: 512MB)

By submitting this form, you agree to the{" "} Terms of Service {" "} and{" "} Privacy Policy .
{supportsRequestStreams ? ( {fileProgress}% ) : null}
); }