diff --git a/src/actions/cms/articleSections/destroy.ts b/src/actions/cms/articleSections/destroy.ts new file mode 100644 index 000000000..38e630a7a --- /dev/null +++ b/src/actions/cms/articleSections/destroy.ts @@ -0,0 +1,16 @@ +'use server' +import prisma from '@/prisma' +import errorHandler from '@/prisma/errorHandler' +import { ActionReturn } from '@/actions/type' +import { ArticleSection } from '@prisma/client' + +export default async function destroy(name: string) : Promise> { + try { + const articleSection = await prisma.articleSection.delete({ + where: { name }, + }) + return { success: true, data: articleSection } + } catch (error) { + return errorHandler(error) + } +} diff --git a/src/actions/cms/articleSections/update.ts b/src/actions/cms/articleSections/update.ts index c13cfb3f1..d2b10a6c5 100644 --- a/src/actions/cms/articleSections/update.ts +++ b/src/actions/cms/articleSections/update.ts @@ -1,5 +1,6 @@ 'use server' import { maxImageSize, minImageSize } from './ConfigVars' +import destroy from './destroy' import prisma from '@/prisma' import errorHandler from '@/prisma/errorHandler' import { default as createCmsImage } from '@/actions/cms/images/create' @@ -130,37 +131,50 @@ export async function removePart(name: string, part: Part) : Promise> { +export default async function read(id: number): Promise> { try { const article = await prisma.article.findUnique({ where: { - name + id }, include: { articleSections: { diff --git a/src/actions/cms/articles/update.ts b/src/actions/cms/articles/update.ts index 93a3a509d..1a737d6fc 100644 --- a/src/actions/cms/articles/update.ts +++ b/src/actions/cms/articles/update.ts @@ -1,19 +1,37 @@ 'use server' +import { maxSections } from './ConfigVars' import prisma from '@/prisma' import errorHandler from '@/prisma/errorHandler' import { ActionReturn } from '@/actions/type' +import { addPart } from '@/cms/articleSections/update' +import { ArticleSection } from '@prisma/client' +import { z } from 'zod' +import type { Part } from '@/cms/articleSections/update' import type { ReturnType } from './ReturnType' -export default async function update(id: number, config: { - name?: string, -}) : Promise> { +export default async function update(id: number, rawData: FormData) : Promise> { + const schema = z.object({ + name: z.string().min(2).max(20) + }) + const parse = schema.safeParse({ + name: rawData.get('name'), + }) + + if (!parse.success) { + return { + success: false, + error: parse.error.issues + } + } + const data = parse.data + try { const article = await prisma.article.update({ where: { id, }, data: { - ...config, + ...data, }, include: { coverImage: true, @@ -31,3 +49,180 @@ export default async function update(id: number, config: { return errorHandler(error) } } + +export async function addSectionToArticle( + id: number, + include: Partial> +) : Promise> { + try { + const article = await prisma.article.findUnique({ + where: { + id, + }, + }) + + if (!article) { + return { + success: false, + error: [{ + message: 'Artikkel ikke funnet', + }], + } + } + + const highestOrderSection = await prisma.articleSection.findMany({ + where: { + articleId: id, + }, + orderBy: { + order: 'desc', + }, + take: 1, + }) + + // Get the order of the highest order section, or 0 if there are no sections + const nextOreder = highestOrderSection.length > 0 ? highestOrderSection[0].order + 1 : 0 + + + const numberOfSections = await prisma.articleSection.count({ + where: { + articleId: id, + }, + }) + if (numberOfSections >= maxSections) { + return { + success: false, + error: [{ + message: `The maximum number of sections is ${maxSections}`, + }], + } + } + + const newSectionName = `${article.name} section ${nextOreder}` + + const updatedArticle = await prisma.article.update({ + where: { + id, + }, + data: { + articleSections: { + create: { + name: newSectionName, + order: nextOreder, + }, + }, + }, + include: { + coverImage: true, + articleSections: { + include: { + cmsImage: true, + cmsParagraph: true, + cmsLink: true, + } + } + } + }) + + for (const part of ['cmsParagraph', 'cmsLink', 'cmsImage'] as const) { + if (include[part]) { + await addPart(newSectionName, part) + } + } + + return { success: true, data: updatedArticle } + } catch (error) { + return errorHandler(error) + } +} + +export async function moveSectionOrder( + id: number, + sectionId: number, + direction: 'UP' | 'DOWN' +) : Promise> { + try { + //get section to move + const section = await prisma.articleSection.findUnique({ + where: { + articleId: id, + id: sectionId, + }, + }) + if (!section) { + return { + success: false, + error: [{ + message: 'Seksjon ikke funnet', + }], + } + } + + //find the section with the order one higher/lower than the current section + const otherSection = await prisma.articleSection.findMany({ + where: { + articleId: id, + order: direction === 'UP' ? { + lt: section.order, + } : { + gt: section.order, + }, + }, + orderBy: { + order: direction === 'UP' ? 'desc' : 'asc', + }, + take: 1, + }).then(sections => sections[0]) + if (!otherSection) { + return { + success: false, + error: [{ + message: 'Seksjon kan ikke flyttes opp/ned', + }], + } + } + + + //flip thir order numbers + const tempOrder = -1 // Or any other value that won't violate the unique constraint + + // First, set the order of the section to the temporary value + await prisma.articleSection.update({ + where: { + articleId: id, + id: section.id + }, + data: { order: tempOrder }, + }) + const updatedOtherSection = await prisma.articleSection.update({ + where: { + articleId: id, + id: otherSection.id + }, + data: { order: section.order }, + }) + // Finally, set the order of the section to the otherSection's original order + const updatedSection = await prisma.articleSection.update({ + where: { + articleId: id, + id: section.id + }, + data: { order: otherSection.order }, + }) + + + if (!updatedSection || !updatedOtherSection) { + return { + success: false, + error: [{ + message: 'Noe uventet skjedde under flytting av seksjonen', + }], + } + } + + return { success: true, data: updatedSection } + } catch (error) { + console.log(error) + return errorHandler(error) + } +} diff --git a/src/app/(home)/page.tsx b/src/app/(home)/page.tsx index fa82f37a9..ed6235948 100644 --- a/src/app/(home)/page.tsx +++ b/src/app/(home)/page.tsx @@ -5,26 +5,19 @@ import SocialIcons from '@/components/SocialIcons/SocialIcons' import CmsImage from '@/components/Cms/CmsImage/CmsImage' import GoogleMap from '@/components/GoogleMap/GoogleMap' import YouTube from '@/components/YouTube/YouTube' -import { getUser } from '@/auth' import { faAngleDown } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import Link from 'next/link' export default async function Home() { - const user = await getUser() - - console.log(user) - return (
- {user === null && <> - Logg inn - Ny student - } + Logg inn + Ny student
diff --git a/src/app/components/Cms/AddParts.module.scss b/src/app/components/Cms/AddParts.module.scss new file mode 100644 index 000000000..17a47a80c --- /dev/null +++ b/src/app/components/Cms/AddParts.module.scss @@ -0,0 +1,15 @@ +@use '@/styles/ohma'; + + +.AddParts { + z-index: 1; + display: flex; + button { + display: flex; + align-items: center; + justify-content: center; + &:hover { + cursor: pointer; + } + } +} \ No newline at end of file diff --git a/src/app/components/Cms/AddParts.tsx b/src/app/components/Cms/AddParts.tsx new file mode 100644 index 000000000..57e9a89b0 --- /dev/null +++ b/src/app/components/Cms/AddParts.tsx @@ -0,0 +1,63 @@ +import styles from './AddParts.module.scss' +import BorderButton from '@/components/UI/BorderButton' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faPlus } from '@fortawesome/free-solid-svg-icons' +import type { Part } from '@/cms/articleSections/update' + +/** + * Component for adding parts to an article and article section. + * Used by two wrapper components: AddSection and AddPartToArticleSection for atricle and article section respectively. + */ + +export type PropTypes = { + showParagraphAdd: boolean, + showImageAdd: boolean, + showLinkAdd: boolean + onClick: (part: Part) => Promise +} + +export default function AddParts({ + showImageAdd, + showLinkAdd, + showParagraphAdd, + onClick +}: PropTypes) { + const parts : { + shouldShow: boolean, + part: Part + text: string + }[] = [ + { + shouldShow: showParagraphAdd, + part: 'cmsParagraph', + text: 'paragraf' + }, + { + shouldShow: showImageAdd, + part: 'cmsImage', + text: 'bilde' + }, + { + shouldShow: showLinkAdd, + part: 'cmsLink', + text: 'link' + } + ] + + return ( +
+ { + parts.map((part, i) => part.shouldShow && ( + onClick(part.part)} + color="secondary" + > + + {part.text} + + )) + } +
+ ) +} diff --git a/src/app/components/Cms/Article/AddSection.module.scss b/src/app/components/Cms/Article/AddSection.module.scss new file mode 100644 index 000000000..3d4d8b15b --- /dev/null +++ b/src/app/components/Cms/Article/AddSection.module.scss @@ -0,0 +1,8 @@ +@use '@/styles/ohma'; + +.maxLength { + width: 100%; + display: flex; + justify-content: center; + margin-bottom: ohma.$gap; +} \ No newline at end of file diff --git a/src/app/components/Cms/Article/AddSection.tsx b/src/app/components/Cms/Article/AddSection.tsx new file mode 100644 index 000000000..bf1e0b429 --- /dev/null +++ b/src/app/components/Cms/Article/AddSection.tsx @@ -0,0 +1,44 @@ +'use client' + +import styles from './AddSection.module.scss' +import AddParts from '@/cms/AddParts' +import { addSectionToArticle } from '@/cms/articles/update' +import { maxSections } from '@/cms/articles/ConfigVars' +import { EditModeContext } from '@/context/EditMode' +import { useRouter } from 'next/navigation' +import { useContext } from 'react' +import type { Part } from '@/cms/articleSections/update' + +type PropTypes = { + articleId: number, + currentNumberSections: number, +} + +export default function AddSection({ articleId, currentNumberSections }: PropTypes) { + const { refresh } = useRouter() + const editMode = useContext(EditModeContext) + if (!editMode?.editMode) return null + + const handleAdd = async (part: Part) => { + addSectionToArticle(articleId, { + [part]: true, + }) + refresh() + } + return ( + + { + currentNumberSections >= maxSections ? ( +

Maksimal lengde på {maxSections} nådd

+ ) : ( + + ) + } +
+ ) +} diff --git a/src/app/components/Cms/Article/Article.module.scss b/src/app/components/Cms/Article/Article.module.scss index 86f277ba1..eb44ca97a 100644 --- a/src/app/components/Cms/Article/Article.module.scss +++ b/src/app/components/Cms/Article/Article.module.scss @@ -57,10 +57,44 @@ $cover-height: min(300px, 40vh); } article { + isolation: isolate; > * { margin: 2em $padding; isolation: isolate; + position: relative; + &:last-child { + margin-bottom: 1em; + } + } + + //This makes sure the the confirmation for deletion does not lay underneath section + @for $i from 1 through 15 { + > *:nth-child(#{$i}) { + z-index: calc(15 - $i); + } } + + .moveSection { + position: relative; + display: block; + > .moverComponent { + position: absolute; + bottom: 0; + left: 50%; + transform: translate(-50%, 40%); + z-index: 2; + } + } + } + .addSection { + margin: 0 $padding; + } + + .submitNameButton { + position: absolute; + top: 0; + left: 0; + transform: translate(0, -100%); } } diff --git a/src/app/components/Cms/Article/Article.tsx b/src/app/components/Cms/Article/Article.tsx index 86f02fde5..cffbd17a5 100644 --- a/src/app/components/Cms/Article/Article.tsx +++ b/src/app/components/Cms/Article/Article.tsx @@ -1,7 +1,11 @@ import styles from './Article.module.scss' +import AddSection from './AddSection' +import SectionMover from './SectionMover' import CmsImage from '@/cms/CmsImage/CmsImage' import SlideInOnView from '@/components/SlideInOnView/SlideInOnView' import ArticleSection from '@/cms/ArticleSection/ArticleSection' +import EditableTextField from '@/components/EditableTextField/EditableTextField' +import update from '@/actions/cms/articles/update' import type { ReturnType } from '@/cms/articles/ReturnType' type PropTypes = { @@ -14,19 +18,44 @@ export default function Article({ article } : PropTypes) { -

{article.name}

+ +

{article.name}

+
- { - article.articleSections.sort((a, b) => (a.order - b.order)).map(section => ( + article.articleSections.sort((a, b) => (a.order - b.order)).map((section, i) => ( - + + + + )) }
+
+ +
) } diff --git a/src/app/components/Cms/Article/SectionMover.module.scss b/src/app/components/Cms/Article/SectionMover.module.scss new file mode 100644 index 000000000..ccbc8770b --- /dev/null +++ b/src/app/components/Cms/Article/SectionMover.module.scss @@ -0,0 +1,17 @@ +@use '@/styles/ohma'; + +.SectionMover { + display: flex; + width: 100%; + justify-content: center; + button { + @include ohma.btn(ohma.$colors-primary); + border-radius: 50%; + padding: 1em; + width: 2em; + height: 2em; + display: flex; + align-items: center; + justify-content: center; + } +} \ No newline at end of file diff --git a/src/app/components/Cms/Article/SectionMover.tsx b/src/app/components/Cms/Article/SectionMover.tsx new file mode 100644 index 000000000..d1e3dd0bf --- /dev/null +++ b/src/app/components/Cms/Article/SectionMover.tsx @@ -0,0 +1,45 @@ +'use client' +import styles from './SectionMover.module.scss' +import { moveSectionOrder } from '@/actions/cms/articles/update' +import { EditModeContext } from '@/context/EditMode' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faArrowDown, faArrowUp } from '@fortawesome/free-solid-svg-icons' +import { useContext, useCallback } from 'react' +import { useRouter } from 'next/navigation' + +type PropTypes = { + articleId: number + sectionId: number + className?: string + showUp: boolean + showDown: boolean +} + +export default function SectionMover({ articleId, sectionId, className, showUp, showDown }: PropTypes) { + const editMode = useContext(EditModeContext) + const { refresh } = useRouter() + const handleMove = useCallback(async (direction: 'UP' | 'DOWN') => { + const res = (await moveSectionOrder(articleId, sectionId, direction)) + if (!res.success) { + const m = res.error ? res?.error[0].message : 'dd' + console.error(m) + } + refresh() + }, [sectionId, articleId, refresh]) + if (!editMode?.editMode) return null + + return ( +
+ { + showUp && + } + { + showDown && + } +
+ ) +} diff --git a/src/app/components/Cms/ArticleSection/AddParts.module.scss b/src/app/components/Cms/ArticleSection/AddPartToArticleSection.module.scss similarity index 66% rename from src/app/components/Cms/ArticleSection/AddParts.module.scss rename to src/app/components/Cms/ArticleSection/AddPartToArticleSection.module.scss index 91c02dac9..cfd31d2a6 100644 --- a/src/app/components/Cms/ArticleSection/AddParts.module.scss +++ b/src/app/components/Cms/ArticleSection/AddPartToArticleSection.module.scss @@ -1,26 +1,24 @@ @use '@/styles/ohma'; -.AddParts { +.AddPartToArticleSection { padding: ohma.$gap; - max-width: calc(100% - 2 * ohma.$gap); + max-width: 100%; > .wrapper { position: relative; border: ohma.$colors-secondary 3px solid; border-radius: ohma.$rounding; min-height: 100px; - > .addControls { - position: absolute; - bottom: 3px; - right: 3px; - z-index: 1; - display: flex; - button { - display: flex; - } - } + padding: 2*ohma.$gap; &.paddingBottom { padding-bottom: 60px; } - } + + //buttons + >*:last-child { + position: absolute; + bottom: 3px; + right: 3px; + } + } } \ No newline at end of file diff --git a/src/app/components/Cms/ArticleSection/AddPartToArticleSection.tsx b/src/app/components/Cms/ArticleSection/AddPartToArticleSection.tsx new file mode 100644 index 000000000..e0832964a --- /dev/null +++ b/src/app/components/Cms/ArticleSection/AddPartToArticleSection.tsx @@ -0,0 +1,40 @@ +'use client' +import styles from './AddPartToArticleSection.module.scss' +import { addPart } from '@/cms/articleSections/update' +import AddParts from '@/cms/AddParts' +import { EditModeContext } from '@/context/EditMode' +import { useCallback, useContext } from 'react' +import { useRouter } from 'next/navigation' +import type { PropTypes as AddPartsPropTypes } from '@/cms/AddParts' +import type { Part } from '@/cms/articleSections/update' +import type { ReactNode } from 'react' + +type PropTypes = Omit & { + articleSectionName: string + children: ReactNode +} + +export default function AddPartToArticleSection({ articleSectionName, children, ...props }: PropTypes) { + const { refresh } = useRouter() + const editMode = useContext(EditModeContext) + const handleAdd = useCallback(async (part: Part) => { + await addPart(articleSectionName, part) + refresh() + }, [articleSectionName]) + if (!editMode?.editMode) return children + + return ( +
+
+ {children} + +
+
+ ) +} + diff --git a/src/app/components/Cms/ArticleSection/AddParts.tsx b/src/app/components/Cms/ArticleSection/AddParts.tsx deleted file mode 100644 index 48748d6fd..000000000 --- a/src/app/components/Cms/ArticleSection/AddParts.tsx +++ /dev/null @@ -1,84 +0,0 @@ -'use client' -import styles from './AddParts.module.scss' -import BorderButton from '@/components/UI/BorderButton' -import { EditModeContext } from '@/context/EditMode' -import { addPart } from '@/cms/articleSections/update' -import { useCallback, useContext } from 'react' -import { useRouter } from 'next/navigation' -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faPlus } from '@fortawesome/free-solid-svg-icons' -import type { Part } from '@/actions/cms/articleSections/update' -import type { ReactNode } from 'react' - -type PropTypes = { - articleSectionName: string, - children: ReactNode, - showParagraphAdd: boolean, - showImageAdd: boolean, - showLinkAdd: boolean -} - -export default function AddParts({ - articleSectionName, - children, - showImageAdd, - showLinkAdd, - showParagraphAdd -}: PropTypes) { - const { refresh } = useRouter() - const editContext = useContext(EditModeContext) - const handleAdd = useCallback(async (part: Part) => { - await addPart(articleSectionName, part) - refresh() - }, [articleSectionName]) - const parts : { - shouldShow: boolean, - part: Part - text: string - }[] = [ - { - shouldShow: showParagraphAdd, - part: 'cmsParagraph', - text: 'paragraph' - }, - { - shouldShow: showImageAdd, - part: 'cmsImage', - text: 'image' - }, - { - shouldShow: showLinkAdd, - part: 'cmsLink', - text: 'link' - } - ] - - if (!editContext?.editMode) return children - - return ( -
-
part.shouldShow) ? - `${styles.wrapper} ${styles.paddingBottom}` - : - styles.wrapper - }> - {children} -
- { - parts.map((part, i) => part.shouldShow && ( - handleAdd(part.part)} - color="secondary" - > - - {part.text} - - )) - } -
-
-
- ) -} diff --git a/src/app/components/Cms/ArticleSection/ArticleSection.module.scss b/src/app/components/Cms/ArticleSection/ArticleSection.module.scss index aa95dd317..37b2b9aef 100644 --- a/src/app/components/Cms/ArticleSection/ArticleSection.module.scss +++ b/src/app/components/Cms/ArticleSection/ArticleSection.module.scss @@ -2,6 +2,7 @@ .ArticleSection { isolation: isolate; + display: grid; .content { display: flex; flex-flow: row wrap; diff --git a/src/app/components/Cms/ArticleSection/ArticleSection.tsx b/src/app/components/Cms/ArticleSection/ArticleSection.tsx index 7fec2d40a..7b5cc1c1b 100644 --- a/src/app/components/Cms/ArticleSection/ArticleSection.tsx +++ b/src/app/components/Cms/ArticleSection/ArticleSection.tsx @@ -1,7 +1,7 @@ import styles from './ArticleSection.module.scss' import RemovePart from './RemovePart' -import AddParts from './AddParts' import ImageControls from './ImageControls' +import AddPartToArticleSection from './AddPartToArticleSection' import CmsLink from '@/cms/CmsLink/CmsLink' import CmsImage from '@/cms/CmsImage/CmsImage' import CmsParagraph from '@/cms/CmsParagraph/CmsParagraph' @@ -41,7 +41,7 @@ export default function ArticleSection({ articleSection }: PropTypes) { return (
- - +
) } diff --git a/src/app/components/Cms/CmsParagraph/CmsParagraph.module.scss b/src/app/components/Cms/CmsParagraph/CmsParagraph.module.scss index 9bd7eea25..16327ca88 100644 --- a/src/app/components/Cms/CmsParagraph/CmsParagraph.module.scss +++ b/src/app/components/Cms/CmsParagraph/CmsParagraph.module.scss @@ -3,6 +3,7 @@ .CmsParagraph { width: 100%; position: relative; + margin-bottom: 2*ohma.$gap; > .HTMLcontent { width: 100%; * { diff --git a/src/app/components/EditableTextField/EditableTextField.module.scss b/src/app/components/EditableTextField/EditableTextField.module.scss new file mode 100644 index 000000000..1a1b18cc2 --- /dev/null +++ b/src/app/components/EditableTextField/EditableTextField.module.scss @@ -0,0 +1,26 @@ +@use '@/styles/ohma'; + +.hiddenInput { + display: none; +} +$padding: 0.8rem; +$border: 1px; +.EditableTextField { + position: relative; + .icon { + position: absolute; + right: calc($padding / 2); + top: calc($padding / 2); + color: ohma.$colors-yellow; + } + .text { + position: relative; + padding: $padding; + border: $border solid ohma.$colors-yellow;; // Add this line + border-radius: ohma.$rounding; + &:focus { + outline: 2px solid ohma.$colors-primary; + } + } +} + diff --git a/src/app/components/EditableTextField/EditableTextField.tsx b/src/app/components/EditableTextField/EditableTextField.tsx new file mode 100644 index 000000000..e0676c39e --- /dev/null +++ b/src/app/components/EditableTextField/EditableTextField.tsx @@ -0,0 +1,77 @@ +'use client' +import styles from './EditableTextField.module.scss' +import Form from '@/components/Form/Form' +import { EditModeContext } from '@/context/EditMode' +import React, { useContext, useEffect, useState, useRef } from 'react' +import { useRouter } from 'next/navigation' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faPencil } from '@fortawesome/free-solid-svg-icons' +import type { PropTypes as FormPropTypes } from '@/components/Form/Form' + +type PropTypes = { + props?: Omit, 'children' | 'contentEditable'> + editable: boolean, + children: React.ReactNode, + formProps: Omit, 'title' | 'children' | 'submitText'> + submitButton: { + text?: string, + name: string, + className?: string, + } +} + +export default function EditableTextField({ + editable, + children, + formProps, + submitButton, + ...props +}: PropTypes +) { + const [value, setValue] = useState('') + const [noChange, setNoChange] = useState(true) + const editMode = useContext(EditModeContext) + const ref = useRef(null) + const { refresh } = useRouter() + + useEffect(() => { + setNoChange(true) + }, [editMode?.editMode]) + + const handleInput = (e: React.FormEvent) => { + setNoChange(false) + console.log(value) + setValue(e.currentTarget.textContent || '') + } + + useEffect(() => { + ref.current?.setAttribute('value', value) + }, [value]) + + if (!editMode?.editMode || !editable) return (children) + return ( +
+
+ {children} +
+ +
{ + setNoChange(true) + formProps.successCallback?.() + refresh() + }} + > + +
+
+ + ) +} diff --git a/src/app/components/Form/Form.tsx b/src/app/components/Form/Form.tsx index 9492c0440..4578ef87d 100644 --- a/src/app/components/Form/Form.tsx +++ b/src/app/components/Form/Form.tsx @@ -15,7 +15,7 @@ type Confirmation = { } type FormType = DetailedHTMLProps, HTMLFormElement> -type PropTypes = Omit & { +export type PropTypes = Omit & { children?: ReactNode, title?: string, submitText?: string, diff --git a/src/app/components/PagingWrappers/EndlessScroll.tsx b/src/app/components/PagingWrappers/EndlessScroll.tsx index 88e5d2aaa..8201861ae 100644 --- a/src/app/components/PagingWrappers/EndlessScroll.tsx +++ b/src/app/components/PagingWrappers/EndlessScroll.tsx @@ -10,9 +10,10 @@ type PropTypes = { renderer: (data: Data) => React.ReactNode, } -export default function EndlessScroll( - { pagingContext, renderer }: PropTypes -) { +export default function EndlessScroll({ + pagingContext, + renderer +}: PropTypes) { const context = useContext(pagingContext) //This component must be rendered inside ContextProvider diff --git a/src/app/news/page.tsx b/src/app/news/page.tsx index 691d8cd0e..881377750 100644 --- a/src/app/news/page.tsx +++ b/src/app/news/page.tsx @@ -3,7 +3,7 @@ import Article from '@/cms/Article/Article' import read from '@/cms/articles/read' export default async function Articles() { - const article = await read('om omega') + const article = await read(2) if (!article.success) return (
{article.error ? article.error[9].message : 'error'}
) return ( diff --git a/src/prisma/schema.prisma b/src/prisma/schema.prisma index 38b409830..f9184e56f 100644 --- a/src/prisma/schema.prisma +++ b/src/prisma/schema.prisma @@ -117,7 +117,7 @@ enum ImageSize { model CmsImage { id Int @id @default(autoincrement()) name String @unique - image Image? @relation(fields: [imageId], references: [id], onDelete: Cascade) + image Image? @relation(fields: [imageId], references: [id], onDelete: SetNull) imageId Int? createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") @@ -170,10 +170,13 @@ model ArticleSection { cmsParagraphId Int? @unique imagePosition Position @default(RIGHT) @map("image_position") imageSize Int @default(200) - article Article? @relation(fields: [articleId], references: [id]) + article Article? @relation(fields: [articleId], references: [id], onDelete: Cascade) articleId Int? order Int @default(autoincrement()) //The order "position" of the article section in the article + //If true, the article section will be deleted if it is empty, ie has no relation to paragraph, link or image + destroyOnEmpty Boolean @default(true) @map("distroy_on_empty") + @@unique([articleId, order]) //There can only be one article section with a given order in an article @@map("article_sections") }