-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(fe): implement notice create and detail page (#2248)
* feat(fe): add create notice gql mutation * feat(fe): implement notice create page * feat(fe): add simple notice detail page * fix(fe): replace sanitize with KatexContent * chore(fe): route to detail page after creating notice
- Loading branch information
Showing
11 changed files
with
244 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
'use client' | ||
|
||
import KatexContent from '@/components/KatexContent' | ||
import { ScrollArea, ScrollBar } from '@/components/shadcn/scroll-area' | ||
import { GET_NOTICE } from '@/graphql/notice/queries' | ||
import { useQuery } from '@apollo/client' | ||
import Link from 'next/link' | ||
import { FaAngleLeft } from 'react-icons/fa6' | ||
|
||
export default function Page({ params }: { params: { noticeId: string } }) { | ||
const { noticeId } = params | ||
|
||
const noticeData = useQuery(GET_NOTICE, { | ||
variables: { | ||
groupId: 1, | ||
noticeId: Number(noticeId) | ||
} | ||
}).data?.getNotice | ||
|
||
return ( | ||
<ScrollArea className="shrink-0"> | ||
<main className="flex flex-col gap-6 px-20 py-16"> | ||
<div className="flex items-center justify-between"> | ||
<div className="flex items-center gap-4"> | ||
<Link href="/admin/notice"> | ||
<FaAngleLeft className="h-12 hover:text-gray-700/80" /> | ||
</Link> | ||
<span className="text-4xl font-bold">{noticeData?.title}</span> | ||
</div> | ||
</div> | ||
<KatexContent | ||
content={noticeData?.content} | ||
classname="prose mb-12 w-full max-w-full border-y-2 border-y-gray-300 p-5 py-12" | ||
/> | ||
</main> | ||
<ScrollBar orientation="horizontal" /> | ||
</ScrollArea> | ||
) | ||
} |
58 changes: 58 additions & 0 deletions
58
apps/frontend/app/admin/notice/_components/CreateNoticeForm.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
'use client' | ||
|
||
import { CREATE_NOTICE } from '@/graphql/notice/mutation' | ||
import { useMutation } from '@apollo/client' | ||
import type { CreateNoticeInput } from '@generated/graphql' | ||
import { zodResolver } from '@hookform/resolvers/zod' | ||
import { useRouter } from 'next/navigation' | ||
import type { ReactNode } from 'react' | ||
import { FormProvider, useForm } from 'react-hook-form' | ||
import { toast } from 'sonner' | ||
import { createSchema } from '../_libs/schemas' | ||
|
||
interface CreateNoticeFormProps { | ||
children: ReactNode | ||
} | ||
|
||
export default function CreateNoticeForm({ children }: CreateNoticeFormProps) { | ||
const methods = useForm<CreateNoticeInput>({ | ||
resolver: zodResolver(createSchema), | ||
defaultValues: { | ||
title: '', | ||
content: '', | ||
isFixed: false, | ||
isVisible: true | ||
} | ||
}) | ||
const router = useRouter() | ||
|
||
const [createNotice] = useMutation(CREATE_NOTICE, { | ||
onError: () => { | ||
toast.error('Failed to create problem') | ||
}, | ||
onCompleted: (data) => { | ||
const noticeId = data.createNotice.id | ||
toast.success('Notice created successfully') | ||
router.push(`/admin/notice/${noticeId}`) | ||
router.refresh() | ||
} | ||
}) | ||
|
||
const onSubmit = methods.handleSubmit(async () => { | ||
const noticeInput = methods.getValues() | ||
await createNotice({ | ||
variables: { | ||
groupId: 1, | ||
noticeInput | ||
} | ||
}) | ||
}) | ||
|
||
return ( | ||
<> | ||
<form className="flex w-[760px] flex-col gap-6" onSubmit={onSubmit}> | ||
<FormProvider {...methods}>{children}</FormProvider> | ||
</form> | ||
</> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
'use client' | ||
|
||
import { useFormContext, useController } from 'react-hook-form' | ||
import { TbPinned, TbPinnedOff } from 'react-icons/tb' | ||
import ErrorMessage from '../../_components/ErrorMessage' | ||
|
||
export default function FixedForm({ | ||
blockEdit = false | ||
}: { | ||
blockEdit?: boolean | ||
}) { | ||
const { | ||
control, | ||
formState: { errors } | ||
} = useFormContext() | ||
|
||
const { field: isFixedField } = useController({ | ||
name: 'isFixed', | ||
control, | ||
defaultValue: true | ||
}) | ||
|
||
return ( | ||
<> | ||
<div className="mt-3 flex items-center gap-2"> | ||
<div className="flex gap-14"> | ||
<label className="flex gap-2"> | ||
<input | ||
type="radio" | ||
onBlur={isFixedField.onBlur} | ||
onChange={() => isFixedField.onChange(true)} | ||
checked={isFixedField.value === true} | ||
className="text-primary-light" | ||
disabled={blockEdit} | ||
/> | ||
<TbPinned className="text-gray-400" size={20} /> | ||
</label> | ||
<label className="flex gap-2"> | ||
<input | ||
type="radio" | ||
onBlur={isFixedField.onBlur} | ||
onChange={() => isFixedField.onChange(false)} | ||
checked={isFixedField.value === false} | ||
className="text-primary-light" | ||
disabled={blockEdit} | ||
/> | ||
<TbPinnedOff className="text-gray-400" size={20} /> | ||
</label> | ||
</div> | ||
</div> | ||
{errors.isFixed && <ErrorMessage message="required" />} | ||
</> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { z } from 'zod' | ||
|
||
export const createSchema = z.object({ | ||
title: z.string().min(1), | ||
content: z.string().min(1), | ||
isFixed: z.boolean(), | ||
isVisible: z.boolean() | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { Button } from '@/components/shadcn/button' | ||
import { ScrollArea, ScrollBar } from '@/components/shadcn/scroll-area' | ||
import Link from 'next/link' | ||
import { FaAngleLeft } from 'react-icons/fa6' | ||
import { IoMdCheckmarkCircleOutline } from 'react-icons/io' | ||
import DescriptionForm from '../../_components/DescriptionForm' | ||
import FormSection from '../../_components/FormSection' | ||
import TitleForm from '../../_components/TitleForm' | ||
import VisibleForm from '../../_components/VisibleForm' | ||
import CreateNoticeForm from '../_components/CreateNoticeForm' | ||
import FixedForm from '../_components/FixedForm' | ||
|
||
export default function Page() { | ||
return ( | ||
<ScrollArea className="shrink-0"> | ||
<main className="flex flex-col gap-6 px-20 py-16"> | ||
<div className="-ml-8 flex items-center gap-4"> | ||
<Link href="/admin/problem"> | ||
<FaAngleLeft className="h-12 hover:text-gray-700/80" /> | ||
</Link> | ||
<span className="text-4xl font-bold">Create Notice</span> | ||
</div> | ||
|
||
<CreateNoticeForm> | ||
<div className="flex gap-32"> | ||
<FormSection title="Visible"> | ||
<VisibleForm /> | ||
</FormSection> | ||
|
||
<FormSection title="Fixed"> | ||
<FixedForm /> | ||
</FormSection> | ||
</div> | ||
|
||
<FormSection title="Title"> | ||
<TitleForm placeholder="Enter a notice title" /> | ||
</FormSection> | ||
|
||
<FormSection title="Content"> | ||
<DescriptionForm name="content" /> | ||
</FormSection> | ||
|
||
<Button | ||
type="submit" | ||
className="flex h-[36px] w-[100px] items-center gap-2 px-0" | ||
> | ||
<IoMdCheckmarkCircleOutline fontSize={20} /> | ||
<div className="mb-[2px] text-base">Create</div> | ||
</Button> | ||
</CreateNoticeForm> | ||
</main> | ||
<ScrollBar orientation="horizontal" /> | ||
</ScrollArea> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { gql } from '@generated' | ||
|
||
const CREATE_NOTICE = gql(` | ||
mutation CreateNotice($groupId: Int!, $noticeInput: CreateNoticeInput!) { | ||
createNotice(groupId: $groupId, input: $noticeInput) { | ||
id | ||
} | ||
} | ||
`) | ||
|
||
export { CREATE_NOTICE } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { gql } from '@apollo/client' | ||
|
||
const GET_NOTICE = gql(` | ||
query GetNotice($groupId: Int!, $noticeId: Int!) { | ||
getNotice(groupId: $groupId, noticeId: $noticeId) { | ||
title | ||
content | ||
} | ||
} | ||
`) | ||
|
||
export { GET_NOTICE } |