diff --git a/src/components/PatchNote.jsx b/src/components/PatchNote.jsx new file mode 100644 index 0000000..3878bcc --- /dev/null +++ b/src/components/PatchNote.jsx @@ -0,0 +1,45 @@ +import { MarkdownViewer } from '@/components/MarkdownViewer'; +import React from 'react'; +import { useState } from 'react'; + +export function PatchNote({description, date, title, version}) { + const [dropDown, setDropDown] = useState(false); + const [readMoreBtn, setReadMoreBtn] = useState(false); + + + return ( + <> +
+
setDropDown(!(dropDown) ) + }> +
+
+

+ {version} +

{title}

+ +
+
+

{date}

+
+
+
+ + {!dropDown ?
+
+ + {description.length>190 && ( + + ) + } +
+
:
+ } + + + +
+ + ); +} diff --git a/src/pages/moderation.jsx b/src/pages/moderation.jsx index 34abc99..d0d92a7 100644 --- a/src/pages/moderation.jsx +++ b/src/pages/moderation.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { ArrowRightIcon, QuestionMarkCircleIcon, @@ -13,20 +13,40 @@ import request from '@/utils/request'; import { MyTable } from '@/components/Table'; import { TableHead, TableRow, TableHeader, TableCell, TableBody, Table } from "@/components/ui/table" import ViewChallenge from '@/components/moderation/ViewChallenge'; +import { MarkdownViewer } from '@/components/MarkdownViewer'; + + export default function Competitions() { const [selectedChallenges, setSelectedChallenges] = useState([]); const [selectedId, setSelectedId] = useState(null); const [pendingChallenges, setPendingChallenges] = useState([]); const [challengeIsOpen, setChallengeIsOpen] = useState(false); - + const [contentPreview, setContentPreview] = useState(''); + const textRef = useRef(null); const [reports, setReports] = useState([]); const [bonusPoints, setBonusPoints] = useState(0); - + const insertText = (text) => { + const textarea = textRef.current; + const startPos = textarea.selectionStart; + const endPos = textarea.selectionEnd; + const newValue = + textarea.value.substring(0, startPos) + + text + + textarea.value.substring(endPos, textarea.value.length); + setContentPreview(newValue); + textarea.focus(); + textarea.selectionEnd = startPos + text.length; + }; + const magicSnippet = () => { + const id = Math.random().toString(36).substring(7); + insertText(`[Click to run: ${id}](https://ctfguide.com/magic/)`); + }; + // get reports useEffect(() => { const fetchReports = async () => { @@ -157,6 +177,31 @@ export default function Competitions() { } }; + const handleUploadPatchnote = async () => { + const title = document.getElementById('titleInput').value; + const version = document.getElementById('versionInput').value; + const content = document.getElementById('content').value; + const author = "CTFGuide"; + + if (!title || !version || !content) { + alert("Please fill in all fields."); + return; + } + + try{ + const response = await request(`${process.env.NEXT_PUBLIC_API_URL}/admin/createPatchNote`, "POST", {title, version, content}); + if(response.success){ + alert("Patchnote uploaded successfully!"); + }else { + alert("Failed to upload the patchnote."); + } + + }catch(err){ + console.log(err); + alert("An error occurred while uploading the patchnote."); + } + }; + return ( <> @@ -261,9 +306,90 @@ export default function Competitions() { +
+ +
+
+

+ Create a Patchnote +

+ + + + +
+
+ + + + + + + + + + +
+ +
+ + + + +
+ +
+

+ Patchnote Content Preview +

+
+ +
+
+
+
+
diff --git a/src/pages/patch-notes.jsx b/src/pages/patch-notes.jsx new file mode 100644 index 0000000..b62e024 --- /dev/null +++ b/src/pages/patch-notes.jsx @@ -0,0 +1,70 @@ +import Head from 'next/head'; +import { Footer } from '@/components/Footer'; +import { StandardNav } from '@/components/StandardNav'; +import { useEffect, useState } from 'react'; +import {PatchNote} from '@/components/PatchNote'; +import request from '@/utils/request'; + +export default function PatchNotes() { + const[patchNotes, setPatchNotes] = useState([{ + description: "Description of the patch note", + date: "8/4/2024", + title: "CTFGuide Release", + version: "Version 1.0.0" + },{ + description: "# ALLAHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx `sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss`", + date: "8/4/2024", + title: "CTFGuide Release", + version: "Version 1.0.0" + }]); + + async function getPatchNotes() { + //fetch patch notes + const response = await request(`${process.env.NEXT_PUBLIC_API_URL}/patchNotes`, 'GET', null); + if(!response.error) { + setPatchNotes(response); + } + } + + useEffect(() => { + getPatchNotes(); + }, []); + + console.log('patchNotes:', patchNotes); + +return ( + <> + + Patch Notes - CTFGuide + + + + + +
+

+ Patch Notes +

+

+ A changelog of updates to the CTFGuide platform +

+ {patchNotes && + patchNotes.map((patchNote) => { + return ( + + ); + }) + } + +
+
+