support comments

This commit is contained in:
Jason Laster 2025-03-20 13:06:07 -07:00
parent dbd3ecf48e
commit fb6afd1926
4 changed files with 55 additions and 25 deletions

View File

@ -177,7 +177,10 @@ export async function deleteProblem(problemId: string): Promise<void | undefined
return undefined;
}
export async function updateProblem(problemId: string, problem: BoltProblemInput): Promise<void | undefined> {
export async function updateProblem(
problemId: string,
problem: BoltProblemInput,
): Promise<void | undefined | BoltProblem> {
if (shouldUseSupabase()) {
return supabaseUpdateProblem(problemId, problem);
}

View File

@ -98,7 +98,7 @@ export async function supabaseGetProblem(problemId: string): Promise<BoltProblem
username,
comments: data.problem_comments.map((comment: any) => ({
id: comment.id,
createdAt: comment.created_at,
timestamp: comment.created_at,
problemId: comment.problem_id,
content: comment.content,
username: comment.username,
@ -159,11 +159,11 @@ export async function supabaseDeleteProblem(problemId: string): Promise<void | u
}
}
export async function supabaseUpdateProblem(problemId: string, problem: BoltProblemInput): Promise<void | undefined> {
export async function supabaseUpdateProblem(problemId: string, problem: BoltProblemInput): Promise<BoltProblem | null> {
try {
if (!getNutIsAdmin()) {
toast.error('Admin user required');
return undefined;
return null;
}
// Extract comments to add separately if needed
@ -192,37 +192,53 @@ export async function supabaseUpdateProblem(problemId: string, problem: BoltProb
* Create a unique identifier for each comment based on content and timestamp.
* This allows us to use upsert with onConflict to avoid duplicates.
*/
const commentInserts = comments.map((comment) => ({
problem_id: problemId,
content: comment.content,
username: comment.username || getUsername() || 'Anonymous',
const commentInserts = comments.map((comment) => {
// Ensure timestamp is a valid number
const timestamp =
typeof comment.timestamp === 'number' && !isNaN(comment.timestamp) ? comment.timestamp : Date.now();
/**
* Use timestamp as a unique identifier for the comment.
* This assumes that comments with the same timestamp are the same comment.
*/
created_at: new Date(comment.timestamp).toISOString(),
}));
return {
problem_id: problemId,
content: comment.content,
username: comment.username || getUsername() || 'Anonymous',
/**
* Use timestamp as a unique identifier for the comment.
* This assumes that comments with the same timestamp are the same comment.
*/
created_at: new Date(timestamp).toISOString(),
};
});
/**
* Use upsert with onConflict to avoid duplicates.
* This will insert new comments and ignore existing ones based on created_at.
*/
const { error: commentsError } = await getSupabase().from('problem_comments').upsert(commentInserts, {
onConflict: 'created_at',
ignoreDuplicates: true,
});
const { error: commentsError, data: commentsData } = await getSupabase()
.from('problem_comments')
.upsert(commentInserts, {
onConflict: 'created_at',
ignoreDuplicates: true,
})
.select();
console.log('commentsData', commentsData);
if (commentsError) {
throw commentsError;
}
}
// Fetch the updated problem with comments to return to the caller
const updatedProblem = await supabaseGetProblem(problemId);
return updatedProblem;
} catch (error) {
console.error('Error updating problem', error);
toast.error('Failed to update problem');
}
return undefined;
return undefined;
}
}
export async function supabaseSubmitFeedback(feedback: any) {

View File

@ -24,7 +24,12 @@ function Comments({ comments }: { comments: BoltProblemComment[] }) {
<div key={index} className="bg-bolt-elements-background-depth-2 rounded-lg p-4 shadow-sm">
<div className="flex items-center justify-between mb-2">
<span className="font-medium text-bolt-text">{comment.username ?? 'Anonymous'}</span>
<span className="text-sm text-bolt-text-secondary">{new Date(comment.timestamp).toLocaleString()}</span>
<span className="text-sm text-bolt-text-secondary">
{(() => {
const date = new Date(comment.timestamp);
return date && !isNaN(date.getTime()) ? date.toLocaleString() : 'Unknown date';
})()}
</span>
</div>
<div className="text-bolt-text whitespace-pre-wrap">{comment.content}</div>
</div>
@ -247,7 +252,13 @@ function ViewProblemPage() {
const newProblem = callback(problemData);
setProblemData(newProblem);
console.log('BackendUpdateProblem', problemId, newProblem);
await backendUpdateProblem(problemId, newProblem);
const updatedProblem = await backendUpdateProblem(problemId, newProblem);
// If we got an updated problem back from the backend, use it to update the UI
if (updatedProblem && typeof updatedProblem !== 'undefined') {
setProblemData(updatedProblem);
}
},
[problemData],
);

View File

@ -9,9 +9,9 @@
"scripts": {
"deploy": "vercel deploy --prod",
"build": "npx remix vite:build",
"dev": "node pre-start.cjs && npx remix vite:dev",
"dev:supabase": "USE_SUPABASE=true node pre-start.cjs && npx remix vite:dev",
"dev:legacy": "USE_SUPABASE=false node pre-start.cjs && npx remix vite:dev",
"dev": "pnpm run dev:legacy",
"dev:supabase": "node pre-start.cjs && USE_SUPABASE=true npx remix vite:dev",
"dev:legacy": "node pre-start.cjs && USE_SUPABASE=false npx remix vite:dev",
"test": "vitest --run --exclude tests/e2e",
"test:watch": "vitest",
"test:e2e": "playwright test",