kemono2/client/src/pages/importer/importer_status.tsx
2025-04-02 16:32:47 +02:00

139 lines
4.1 KiB
TypeScript

import {
LoaderFunctionArgs,
useLoaderData,
} from "react-router";
import { createAccountDMsReviewPageURL } from "#lib/urls";
import { fetchHasPendingDMs } from "#api/dms";
import { fetchImportLogs } from "#api/imports";
import { getLocalStorageItem, setLocalStorageItem } from "#storage/local";
import { PageSkeleton } from "#components/pages";
import { LoadingIcon } from "#components/loading";
import * as styles from "./importer_status.module.scss";
import { KemonoLink } from "#components/links";
import { useEffect, useState } from "react";
interface IProps {
importId: string;
isDMS?: boolean;
}
export function ImporterStatusPage() {
const { importId, isDMS } = useLoaderData() as IProps;
const title = `Import "${importId}" logs`;
const heading = `Importer Logs for ${importId}`;
const cooldown = 15_000;
const [reverse, setReverse] = useState(false);
const [logs, setLogs] = useState<Array<string> | null>(null);
const [finished, setFinished] = useState(false);
useEffect(() => {
if (finished) return;
async function fetchLogs() {
try {
let resp = await fetchImportLogs(importId);
setLogs(reverse ? [...resp].reverse() : [...resp]);
if (resp?.[resp?.length - 1]?.match(/Finished/i)) {
setFinished(true);
} else {
setFinished(false);
}
} catch (error) {
console.log(error)
}
}
fetchLogs();
const id = setInterval(fetchLogs, cooldown);
return () => clearInterval(id);
}, [reverse, finished]);
function toggleReverse() {
setReverse(!reverse);
setLogs(logs?.reverse() ?? []);
}
return (
<PageSkeleton name="importer-status" title={title} heading={heading}>
{!logs ? (
<p>
<LoadingIcon /> <span>Wait until logs load...</span>
</p>
) : logs.length ? (
<>
{isDMS && (
<div className="jumbo no-posts">
<strong>Hey!</strong>
<p>
You gave the importer permission to access your messages. To protect your anonymity, you must manually approve each one. Wait until <em>after</em> the importer says <code>Done importing DMs</code>, then go go{" "}
<KemonoLink url={String(createAccountDMsReviewPageURL())}>
here
</KemonoLink>{" "}
to choose which ones you wish to import. to choose which ones you wish to import.
</p>
</div>
)}
<div className="import__info">
<div className="import__stats">
<span>Status: {finished ? "Completed" : "In Progress"}</span>
<span>Total: {logs?.length}</span>
</div>
<button className="button" onClick={toggleReverse}>Reverse order</button>
</div>
<ol className={styles.importList}>
{logs?.map((message, index) => (
<li key={index}>{message}</li>
))}
</ol>
</>
) : (
<p>No logs found!</p>
)}
</PageSkeleton>
);
}
async function initPendingReviewDms(
forceReload = false,
minutesForRecheck = 30
) {
let hasPendingReviewDms = getLocalStorageItem("has_pending_review_dms") === "true";
const lastCheckedHasPendingReviewDms = parseInt(
getLocalStorageItem("last_checked_has_pending_review_dms") ?? "0",
10
);
if (
forceReload ||
!lastCheckedHasPendingReviewDms ||
lastCheckedHasPendingReviewDms < Date.now() - minutesForRecheck * 60 * 1000
) {
hasPendingReviewDms = await fetchHasPendingDMs();
setLocalStorageItem("has_pending_review_dms", String(hasPendingReviewDms));
localStorage.setItem(
"last_checked_has_pending_review_dms",
Date.now().toString()
);
}
}
export async function loader({
params,
request,
}: LoaderFunctionArgs): Promise<IProps> {
const importId = params.import_id?.trim();
if (!importId) {
throw new Error("Import ID is required.");
}
const searchparams = new URL(request.url).searchParams;
let isDMS = Boolean(searchparams.get("dms")?.trim());
return {
importId,
isDMS,
};
}