Add guidelines

This commit is contained in:
2025-12-27 12:59:42 +01:00
parent 13685d100c
commit 9d18b6da02
7 changed files with 186 additions and 1 deletions

View File

@ -0,0 +1,13 @@
-- CreateTable
CREATE TABLE "CommissionGuidelines" (
"id" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"markdown" TEXT NOT NULL,
"isActive" BOOLEAN NOT NULL DEFAULT true,
CONSTRAINT "CommissionGuidelines_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "CommissionGuidelines_isActive_idx" ON "CommissionGuidelines"("isActive");

View File

@ -355,11 +355,22 @@ model CommissionRequest {
sortIndex Int @default(0) sortIndex Int @default(0)
} }
model CommissionGuidelines {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
markdown String
isActive Boolean @default(true)
@@index([isActive])
}
model TermsOfService { model TermsOfService {
id String @id @default(cuid()) id String @id @default(cuid())
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
version Int @default(autoincrement())
markdown String markdown String
version Int @default(autoincrement())
} }

View File

@ -0,0 +1,11 @@
'use server';
import { prisma } from "@/lib/prisma";
export async function getActiveGuidelines(): Promise<string | null> {
const guidelines = await prisma.commissionGuidelines.findFirst({
where: { isActive: true },
orderBy: { createdAt: 'desc' },
});
return guidelines?.markdown ?? null;
}

View File

@ -0,0 +1,16 @@
'use server';
import { prisma } from "@/lib/prisma";
export async function saveGuidelines(markdown: string) {
await prisma.commissionGuidelines.updateMany({
where: { isActive: true },
data: { isActive: false },
});
await prisma.commissionGuidelines.create({
data: {
markdown,
},
});
}

View File

@ -0,0 +1,17 @@
import { getActiveGuidelines } from "@/actions/commissions/guidelines/getGuidelines";
import GuidelinesEditor from "@/components/commissions/guidelines/Editor";
export default async function CommissionGuidelinesPage() {
const markdown = await getActiveGuidelines();
return (
<div>
<div className="flex gap-4 justify-between pb-8">
<h1 className="text-2xl font-bold mb-4">Terms of Service</h1>
</div>
<div className="space-y-4 p-1 border rounded-xl bg-muted/20">
<GuidelinesEditor markdown={markdown} />
</div>
</div>
);
}

View File

@ -0,0 +1,113 @@
"use client"
import type { Value } from 'platejs';
import { saveGuidelines } from '@/actions/commissions/guidelines/saveGuidelines';
import { BasicBlocksKit } from '@/components/editor/plugins/basic-blocks-kit';
import { BasicMarksKit } from '@/components/editor/plugins/basic-marks-kit';
import { CodeBlockKit } from '@/components/editor/plugins/code-block-kit';
import { ListKit } from '@/components/editor/plugins/list-kit';
import { MarkdownKit } from '@/components/editor/plugins/markdown-kit';
import { Editor, EditorContainer } from '@/components/ui/editor';
import { FixedToolbar } from '@/components/ui/fixed-toolbar';
import { BulletedListToolbarButton, NumberedListToolbarButton } from '@/components/ui/list-toolbar-button';
import { MarkToolbarButton } from '@/components/ui/mark-toolbar-button';
import { ToolbarButton } from '@/components/ui/toolbar';
import {
Bold,
Braces,
Code,
Heading1,
Heading2,
Heading3,
Italic,
Quote,
Save,
Strikethrough,
Underline
} from "lucide-react";
import { Plate, usePlateEditor } from 'platejs/react';
import { useEffect } from 'react';
const initialValue: Value = [
];
export default function GuidelinesEditor({ markdown }: { markdown: string | null }) {
// const [isSaving, setIsSaving] = useState(false);
const editor = usePlateEditor({
plugins: [
...BasicBlocksKit,
...CodeBlockKit,
...ListKit,
...BasicMarksKit,
...MarkdownKit,
],
value: initialValue,
});
useEffect(() => {
if (markdown && editor.api.markdown.deserialize) {
const markdownValue = editor.api.markdown.deserialize(markdown);
// console.log(markdownValue);
editor.children = markdownValue;
}
}, [editor, markdown]);
const handleSave = async () => {
// console.log(editor);
if (!editor.api.markdown.serialize) return;
// setIsSaving(true);
const markdown = editor.api.markdown.serialize();
await saveGuidelines(markdown);
// setIsSaving(false);
};
return (
<Plate editor={editor}> {/* Provides editor context */}
<FixedToolbar className="justify-start rounded-t-lg">
{/* Blocks */}
<ToolbarButton onClick={() => editor.tf.h1.toggle()} tooltip="Heading 1">
<Heading1 className="w-4 h-4" />
</ToolbarButton>
<ToolbarButton onClick={() => editor.tf.h2.toggle()} tooltip="Heading 2">
<Heading2 className="w-4 h-4" />
</ToolbarButton>
<ToolbarButton onClick={() => editor.tf.h3.toggle()} tooltip="Heading 3">
<Heading3 className="w-4 h-4" />
</ToolbarButton>
<ToolbarButton onClick={() => editor.tf.blockquote.toggle()} tooltip="Blockquote">
<Quote className="w-4 h-4" />
</ToolbarButton>
<ToolbarButton onClick={() => editor.tf.code_block.toggle()} tooltip="Code Block">
<Braces className="w-4 h-4" />
</ToolbarButton>
<BulletedListToolbarButton />
<NumberedListToolbarButton />
{/* Mark Toolbar Buttons */}
<MarkToolbarButton nodeType="bold" tooltip="Bold">
<Bold className="w-4 h-4" />
</MarkToolbarButton>
<MarkToolbarButton nodeType="italic" tooltip="Italic">
<Italic className="w-4 h-4" />
</MarkToolbarButton>
<MarkToolbarButton nodeType="underline" tooltip="Underline">
<Underline className="w-4 h-4" />
</MarkToolbarButton>
<MarkToolbarButton nodeType="strikethrough" tooltip="Strikethrough">
<Strikethrough className="w-4 h-4" />
</MarkToolbarButton>
<MarkToolbarButton nodeType="code" tooltip="Code">
<Code className="w-4 h-4" />
</MarkToolbarButton>
{/* Save Button */}
<ToolbarButton onClick={handleSave} tooltip="Save">
<Save className="w-4 h-4" />
</ToolbarButton>
</FixedToolbar>
<EditorContainer> {/* Styles the editor area */}
<Editor placeholder="Type your amazing content here..." />
</EditorContainer>
</Plate>
);
}

View File

@ -33,6 +33,10 @@ const commissionItems = [
{ {
title: "Types", title: "Types",
href: "/commissions/types", href: "/commissions/types",
},
{
title: "Guidelines",
href: "/commissions/guidelines",
} }
] ]