Files
RedditBot/apps/dashboard/src/features/settings/access-panel.tsx
T

68 lines
3.6 KiB
TypeScript

import { useRef } from 'react';
import { RedditUsernameLink } from '../../components/reddit-username-link.js';
import { useImportRedditSessionMutation, useLoginStatusQuery } from './settings-queries.js';
function errorMessage(error: Error | null): string {
return error?.message ?? 'Something went wrong.';
}
function sessionLabel(status: ReturnType<typeof useLoginStatusQuery>['data']): string {
if (!status) return 'Unknown';
if (!status.ready) return 'Browser unavailable';
if ('error' in status) return 'Check failed';
return {
unknown: 'Unknown',
authenticated: 'Authenticated',
'login-required': 'Login required',
unreachable: 'Reddit unreachable',
}[status.status];
}
export function AccessPanel() {
const statusQuery = useLoginStatusQuery();
const importMutation = useImportRedditSessionMutation();
const importInput = useRef<HTMLInputElement>(null);
async function importSession(file: File | undefined) {
if (!file) return;
try {
const exported: unknown = JSON.parse(await file.text());
importMutation.mutate(exported);
} catch {
importMutation.reset();
importMutation.mutate({});
}
}
if (statusQuery.isPending) {
return <section aria-label="Loading access" className="panel panel-loading" role="status"><span className="spinner" />Loading Reddit access…</section>;
}
if (statusQuery.isError) {
return (
<section className="panel error-panel" role="alert">
<strong>Reddit access unavailable</strong><span>{errorMessage(statusQuery.error)}</span>
<button className="button secondary" onClick={() => void statusQuery.refetch()} type="button">Retry access</button>
</section>
);
}
const session = statusQuery.data;
const username = session.ready && 'loggedIn' in session && session.loggedIn ? session.username ?? null : null;
return (
<section aria-labelledby="access-heading" className="panel settings-section">
<div className="panel-heading"><div><span className="eyebrow">Reddit session</span><h2 id="access-heading">Access</h2></div><span className={session.ready && 'status' in session && session.loggedIn ? 'pill success' : 'pill warning'}>{sessionLabel(session)}</span></div>
<p className="settings-copy">When Reddit is logged out, account work is paused and waiting for a fresh session dump from the extension.</p>
{username ? <p className="settings-copy">Signed in as <strong><RedditUsernameLink username={username} /></strong>.</p> : null}
<div className="access-actions">
<input accept="application/json" aria-label="Reddit session export" className="sr-only" onChange={(event) => void importSession(event.target.files?.[0])} ref={importInput} type="file" />
<button className="button primary" disabled={importMutation.isPending} onClick={() => importInput.current?.click()} type="button">{importMutation.isPending ? 'Importing session…' : 'Import Reddit session'}</button>
<button className="button secondary" disabled={statusQuery.isFetching} onClick={() => void statusQuery.refetch()} type="button">{statusQuery.isFetching ? 'Checking session…' : 'Recheck session'}</button>
</div>
<p className="settings-copy">Open Reddit Chat in Chrome, wait for the extension badge to show OK, then upload its JSON dump here. It contains login credentials; do not share it.</p>
{importMutation.isSuccess ? <div className="settings-notice success" role="status">Reddit session imported and verified.</div> : null}
{importMutation.isError ? <div className="settings-notice error" role="alert">{errorMessage(importMutation.error)}</div> : null}
</section>
);
}