Add guidelines
This commit is contained in:
13
prisma/migrations/20251227110121_com_2/migration.sql
Normal file
13
prisma/migrations/20251227110121_com_2/migration.sql
Normal 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");
|
||||||
@ -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())
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/actions/commissions/guidelines/getGuidelines.ts
Normal file
11
src/actions/commissions/guidelines/getGuidelines.ts
Normal 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;
|
||||||
|
}
|
||||||
16
src/actions/commissions/guidelines/saveGuidelines.ts
Normal file
16
src/actions/commissions/guidelines/saveGuidelines.ts
Normal 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,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
17
src/app/commissions/guidelines/page.tsx
Normal file
17
src/app/commissions/guidelines/page.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
113
src/components/commissions/guidelines/Editor.tsx
Normal file
113
src/components/commissions/guidelines/Editor.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -33,6 +33,10 @@ const commissionItems = [
|
|||||||
{
|
{
|
||||||
title: "Types",
|
title: "Types",
|
||||||
href: "/commissions/types",
|
href: "/commissions/types",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Guidelines",
|
||||||
|
href: "/commissions/guidelines",
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user