import React from "react"; import { useState, useRef, useEffect } from "react"; import styles from "@/styles/modules/ArticleEditor.module.scss"; import { Prisma, Category } from "@prisma/client"; import Select from "react-select"; import { useRouter } from "next/navigation"; import urlJoin from "url-join"; import { IContentTableEntry } from "@/types/contentTable"; import { CreateArticle, UpdateArticle } from "@/types/api"; import { formatTextToUrlName } from "@/utils"; import { isValidText } from "@/validators"; import { apiUrl } from "@/global"; import Markdown from "@/components/Markdown"; import prisma, { ArticleWithIncludes, CategoryWithIncludes } from "@/lib/prisma"; import { CLIENT_RENEG_LIMIT } from "tls"; export default function AdminArticlesEditorPage({ article, categories }: { article: ArticleWithIncludes | null; categories: CategoryWithIncludes[] }) { const router = useRouter(); const [title, setTitle] = useState(article?.title ?? ""); const [selectCategoriesOptions, setSelectCategoriesOptions] = useState<{ value: string; label: string }[]>( categories?.map((c: CategoryWithIncludes) => ({ value: c.id, label: c.title })) ); const [introduction, setIntroduction] = useState(article?.introduction ?? ""); const [markdown, setMarkdown] = useState(article?.markdown ?? ""); const [contentTable, setContentTable] = useState(article?.contentTable ?? []); const titleRef = useRef(null); const categorySelectRef = useRef(null); const introductionRef = useRef(null); const markdownTextAreaRef = useRef(null); const errorTextRef = useRef(null); function changeContentTableEntryAnchor(index: number, newAnchor: string) { setContentTable((prevArray: any) => { let newArray = [...prevArray]; newArray[index].anchor = newAnchor; return newArray; }); } function changeContentTableEntryTitle(index: number, newTitle: string) { setContentTable((prevArray: any) => { let newArray = [...prevArray]; newArray[index].anchor = newTitle; return newArray; }); } function removeEntry(index: number) { let newArray = [...contentTable]; newArray.splice(index, 1); setContentTable(newArray); } // Create or update article async function handleResponse(res: Response) { const json = await res.json(); if (errorTextRef?.current) { errorTextRef.current.innerText = json.error ?? ""; } if (json.success) { const newArticle: ArticleWithIncludes = json.data; router.push(urlJoin(`/articles/`, newArticle.category.name, newArticle.name)); } } async function updateArticle() { console.log("Update article"); const payload: UpdateArticle = { title: titleRef?.current?.value, introduction: introductionRef?.current?.value, markdown: markdown, categoryId: categorySelectRef?.current?.getValue()[0]?.value, contentTable: contentTable, }; console.log(payload); await fetch(`/api/articles/${article?.id.toString()}`, { method: "PUT", headers: { Accept: "application/json", "Content-Type": "application/json", }, cache: "no-cache", body: JSON.stringify(payload), }) .then(handleResponse) .catch(console.error); } async function createArticle() { console.log("Create article"); const payload: CreateArticle = { title: titleRef?.current?.value ?? "", introduction: introductionRef?.current?.value ?? "", markdown: markdown, categoryId: categorySelectRef?.current?.getValue()[0]?.value, contentTable: contentTable, }; console.log(payload); await fetch("/api/articles/", { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json", }, cache: "no-cache", body: JSON.stringify(payload), }) .then(handleResponse) .catch(console.error); } return (

{article ? "Update article" : "Create new article"}

) => { setTitle(e.target.value); }} className={!isValidText(title) && title ? "error" : ""} type="text" name="title" placeholder="title" ref={titleRef} defaultValue={title} />
) => { setIntroduction(e.target.value); }} className={!isValidText(introduction) && introduction ? "error" : ""} type="text" name="introduction" placeholder="Introduction" ref={introductionRef} defaultValue={introduction} />
{contentTable?.map((entry: IContentTableEntry, i: number) => { return (
{ changeContentTableEntryAnchor(i, e.target.value); }} type="text" placeholder={"Anchor"} defaultValue={entry.anchor} /> { changeContentTableEntryTitle(i, e.target.value); }} type="text" placeholder={"Title"} defaultValue={entry.title} />{" "}
); })}
); } export async function getServerSideProps(context: any) { let article: ArticleWithIncludes | null = null; let categories: CategoryWithIncludes[] = []; const articleId: string = context.params.articleId.toString(); if (articleId != "0") { await prisma.article.findUnique({ where: { id: articleId }, include: { category: true } }).then( (result: ArticleWithIncludes | null) => { if (result) { article = JSON.parse(JSON.stringify(result)); console.log(article); } else { // TODO redirect to /0 } }, (reason: any) => { console.log(reason); } ); } await prisma.category.findMany({ include: { svg: true, articles: true } }).then( (result: CategoryWithIncludes[]) => { if (result) { categories = JSON.parse(JSON.stringify(result)); } else { // TODO redirect to /0 } }, (reason: any) => { console.log(reason); } ); return { props: { article: article, categories: categories }, // will be passed to the page component as props }; }