215 lines
5.9 KiB
TypeScript
215 lines
5.9 KiB
TypeScript
import {
|
|
Alert,
|
|
AlertIcon,
|
|
Button,
|
|
Card,
|
|
Container,
|
|
Flex,
|
|
FormControl,
|
|
FormLabel,
|
|
Heading,
|
|
Link,
|
|
Radio,
|
|
RadioGroup,
|
|
Spacer,
|
|
Stack,
|
|
Text,
|
|
useToast,
|
|
VStack,
|
|
} from "@chakra-ui/react";
|
|
import { lazy, useState } from "react";
|
|
import { useLoaderData } from "@remix-run/react";
|
|
const DataRequestFormChunkPurchases = lazy(
|
|
() => import("../../components/DataRequestFormChunkPurchases.js"),
|
|
);
|
|
const DataRequestFormChunkTransfers = lazy(
|
|
() => import("../../components/DataRequestFormChunkTransfers.js"),
|
|
);
|
|
|
|
export async function loader({ context }: { context: RequestContext }) {
|
|
const cookies = context.request.headers.get("cookie")?.split(/; */);
|
|
const dtSession = cookies?.find((c) => c.startsWith("dt-auth="));
|
|
|
|
if (!cookies || !dtSession)
|
|
throw Response.redirect("/data-request/auth", 303);
|
|
|
|
const sessionId = dtSession.replace("dr-auth=", "");
|
|
const sessionData = await context.env.DATA.get(
|
|
`data_request_session_${sessionId}`,
|
|
);
|
|
|
|
if (!sessionData) throw Response.redirect("/data-request/auth", 303);
|
|
|
|
return JSON.parse(sessionData) as { id: number; username: string };
|
|
}
|
|
|
|
export function meta() {
|
|
return [
|
|
{
|
|
title: "Data Request - Car Crushers",
|
|
},
|
|
];
|
|
}
|
|
|
|
export default function () {
|
|
const sessionData = useLoaderData<typeof loader>();
|
|
const [requestType, setRequestType] = useState("purchase");
|
|
const [files, setFiles] = useState<FileList | null>(null);
|
|
const [oldIsTerminated, setOldIsTerminated] = useState(false);
|
|
const [processingState, setProcessingState] = useState<string | null>(null);
|
|
const [authUrl, setAuthUrl] = useState("");
|
|
const toast = useToast();
|
|
|
|
async function startRequest() {
|
|
const body = new FormData();
|
|
|
|
body.append("type", requestType);
|
|
|
|
if (files instanceof FileList) {
|
|
for (const file of files) {
|
|
body.append("file", file);
|
|
}
|
|
}
|
|
|
|
const requestStartResponse = await fetch("/api/data-requests/start", {
|
|
body,
|
|
method: "POST",
|
|
redirect: "manual",
|
|
});
|
|
|
|
if (!requestStartResponse.ok) {
|
|
let error = "An unknown error has occurred";
|
|
|
|
try {
|
|
error = ((await requestStartResponse.json()) as { error: string })
|
|
.error;
|
|
} catch {}
|
|
|
|
toast({
|
|
description: error,
|
|
status: "error",
|
|
title: "Failed to create request",
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
const { url } = (await requestStartResponse.json()) as { url?: string };
|
|
|
|
if (url) {
|
|
setAuthUrl(url);
|
|
setProcessingState("auth");
|
|
} else {
|
|
setProcessingState("complete");
|
|
}
|
|
}
|
|
|
|
switch (processingState) {
|
|
case "auth":
|
|
return (
|
|
<Container pt="16vh">
|
|
<Card borderRadius="32px" p="4vh">
|
|
<VStack alignContent="center" gap="2vh">
|
|
<Heading>Verify Old Account</Heading>
|
|
<br />
|
|
<Text>
|
|
In order to process your transfer request, you must sign in to
|
|
your old Roblox account to verify account ownership. Remember to
|
|
switch to the correct account at the prompt.
|
|
</Text>
|
|
<br />
|
|
<Button
|
|
as="a"
|
|
borderRadius="24px"
|
|
colorScheme="blue"
|
|
href={authUrl}
|
|
>
|
|
Verify Old Account
|
|
</Button>
|
|
</VStack>
|
|
</Card>
|
|
</Container>
|
|
);
|
|
|
|
case "complete":
|
|
return (
|
|
<Container
|
|
left="50%"
|
|
maxW="container.md"
|
|
pos="absolute"
|
|
top="50%"
|
|
transform="translate(-50%, -50%)"
|
|
>
|
|
<Flex>
|
|
<Spacer />
|
|
<svg
|
|
width="128"
|
|
height="128"
|
|
fill="currentColor"
|
|
viewBox="0 0 16 16"
|
|
>
|
|
<path d="M2.5 8a5.5 5.5 0 0 1 8.25-4.764.5.5 0 0 0 .5-.866A6.5 6.5 0 1 0 14.5 8a.5.5 0 0 0-1 0 5.5 5.5 0 1 1-11 0z" />
|
|
<path d="M15.354 3.354a.5.5 0 0 0-.708-.708L8 9.293 5.354 6.646a.5.5 0 1 0-.708.708l3 3a.5.5 0 0 0 .708 0l7-7z" />
|
|
</svg>
|
|
<Spacer />
|
|
</Flex>
|
|
<br />
|
|
<Heading textAlign="center">Request Submitted</Heading>
|
|
<br />
|
|
<Text textAlign="center">
|
|
We have received your request and will begin processing it shortly.
|
|
</Text>
|
|
</Container>
|
|
);
|
|
|
|
default:
|
|
return (
|
|
<Container maxW="container.lg">
|
|
<Heading pb="32px" size="xl">
|
|
Data Requests
|
|
</Heading>
|
|
<Alert status="info">
|
|
<AlertIcon />
|
|
You are signed in to {sessionData.username}.{" "}
|
|
<Link
|
|
onClick={async () => {
|
|
await fetch("/api/data-requests/session", {
|
|
method: "DELETE",
|
|
});
|
|
|
|
location.assign("/data-request/auth");
|
|
}}
|
|
textDecor="underline"
|
|
>
|
|
Wrong account?
|
|
</Link>
|
|
</Alert>
|
|
<VStack alignItems="start" spacing={12}>
|
|
<FormControl isRequired>
|
|
<FormLabel>Request Type</FormLabel>
|
|
<RadioGroup onChange={setRequestType} value={requestType}>
|
|
<Stack>
|
|
<Radio value="purchase">Missing Purchase</Radio>
|
|
<Radio value="transfer">
|
|
Transfer Save Data to New Account
|
|
</Radio>
|
|
<Radio value="reset">Reset Save Data</Radio>
|
|
</Stack>
|
|
</RadioGroup>
|
|
</FormControl>
|
|
{requestType === "purchase" ? (
|
|
<DataRequestFormChunkPurchases fileStateSet={setFiles} />
|
|
) : null}
|
|
{requestType === "transfer" ? (
|
|
<DataRequestFormChunkTransfers
|
|
fileStateSet={setFiles}
|
|
isTerminated={oldIsTerminated}
|
|
setIsTerminated={setOldIsTerminated}
|
|
/>
|
|
) : null}
|
|
</VStack>
|
|
</Container>
|
|
);
|
|
}
|
|
}
|