import { ClientOnly } from 'remix-utils/client-only';
import { Header } from '~/components/header/Header';
import { Menu } from '~/components/sidebar/Menu.client';
import BackgroundRays from '~/components/ui/BackgroundRays';
import { TooltipProvider } from '@radix-ui/react-tooltip';
import { ToastContainerWrapper, Status, Keywords } from './problems';
import { toast } from 'react-toastify';
import { Suspense, useCallback, useEffect, useState } from 'react';
import { useParams } from '@remix-run/react';
import {
getProblem,
updateProblem as backendUpdateProblem,
deleteProblem as backendDeleteProblem,
getProblemsUsername,
BoltProblemStatus,
getNutIsAdmin,
} from '~/lib/replay/Problems';
import type { BoltProblem, BoltProblemComment } from '~/lib/replay/Problems';
function Comments({ comments }: { comments: BoltProblemComment[] }) {
return (
{comments.map((comment, index) => (
{comment.username ?? 'Anonymous'}
{new Date(comment.timestamp).toLocaleString()}
{comment.content}
))}
);
}
function ProblemViewer({ problem }: { problem: BoltProblem }) {
const { problemId, title, description, status = BoltProblemStatus.Pending, keywords = [], comments = [] } = problem;
return (
);
}
interface UpdateProblemFormProps {
handleSubmit: (content: string) => void;
updateText: string;
placeholder: string;
}
function UpdateProblemForm(props: UpdateProblemFormProps) {
const { handleSubmit, updateText, placeholder } = props;
const [value, setValue] = useState('');
const onSubmitClicked = (e: React.FormEvent) => {
e.preventDefault();
if (value.trim()) {
handleSubmit(value);
setValue('');
}
};
return (
);
}
type DoUpdateCallback = (problem: BoltProblem) => BoltProblem;
type UpdateProblemCallback = (doUpdate: DoUpdateCallback) => void;
type DeleteProblemCallback = () => void;
function UpdateProblemForms({
updateProblem,
deleteProblem,
}: {
updateProblem: UpdateProblemCallback;
deleteProblem: DeleteProblemCallback;
}) {
const handleAddComment = (content: string) => {
const newComment: BoltProblemComment = {
timestamp: Date.now(),
username: getProblemsUsername(),
content,
};
updateProblem((problem) => {
const comments = [...(problem.comments || []), newComment];
return {
...problem,
comments,
};
});
};
const handleSetTitle = (title: string) => {
updateProblem((problem) => ({
...problem,
title,
}));
};
const handleSetDescription = (description: string) => {
updateProblem((problem) => ({
...problem,
description,
}));
};
const handleSetStatus = (status: string) => {
const statusEnum = BoltProblemStatus[status as keyof typeof BoltProblemStatus];
if (!statusEnum) {
toast.error('Invalid status');
return;
}
updateProblem((problem) => ({
...problem,
status: statusEnum,
}));
};
const handleSetKeywords = (keywordString: string) => {
const keywords = keywordString
.split(' ')
.map((keyword) => keyword.trim())
.filter((keyword) => keyword.length > 0);
updateProblem((problem) => ({
...problem,
keywords,
}));
};
return (
<>
>
);
}
const Nothing = () => null;
function ViewProblemPage() {
const params = useParams();
const problemId = params.id;
if (typeof problemId !== 'string') {
throw new Error('Problem ID is required');
}
const [problemData, setProblemData] = useState(null);
const updateProblem = useCallback(
async (callback: DoUpdateCallback) => {
if (!problemData) {
toast.error('Problem data missing');
return;
}
const newProblem = callback(problemData);
setProblemData(newProblem);
console.log('BackendUpdateProblem', problemId, newProblem);
await backendUpdateProblem(problemId, newProblem);
},
[problemData],
);
const deleteProblem = useCallback(async () => {
console.log('BackendDeleteProblem', problemId);
await backendDeleteProblem(problemId);
toast.success('Problem deleted');
}, [problemData]);
useEffect(() => {
getProblem(problemId).then(setProblemData);
}, [problemId]);
return (
}>
{() => }
{problemData === null ? (
) : (
)}
{getNutIsAdmin() && problemData && (
)}
);
}
export default ViewProblemPage;