diff --git a/src/api/upload/types/upload.ts b/src/api/upload/types/upload.ts new file mode 100644 index 0000000..addd929 --- /dev/null +++ b/src/api/upload/types/upload.ts @@ -0,0 +1,5 @@ +export interface IFormInfo { + title: string; + body: string; + files: File[]; +} diff --git a/src/api/upload/upload.ts b/src/api/upload/upload.ts new file mode 100644 index 0000000..d4528ea --- /dev/null +++ b/src/api/upload/upload.ts @@ -0,0 +1,20 @@ +import { client } from 'api'; +import { IFormInfo } from './types/upload'; +import { CONSTANTS } from 'constants/api'; + +export const uploadForm = async ({ formInfo, API_PATH }: { formInfo: IFormInfo; API_PATH: string }) => { + const token = localStorage.getItem(CONSTANTS.atk_key); + + try { + const data = await client.post(API_PATH, formInfo, { + headers: { + Authorization: `Bearer ${token}`, + 'Content-Type': 'multipart/form-data', + }, + }); + + return data; + } catch (e) { + console.log(e); + } +}; diff --git a/src/assets/images/organization-01.jpg b/src/assets/images/organization-01.jpg new file mode 100644 index 0000000..1a424cc Binary files /dev/null and b/src/assets/images/organization-01.jpg differ diff --git a/src/assets/images/organization-02.jpg b/src/assets/images/organization-02.jpg new file mode 100644 index 0000000..43c6ae6 Binary files /dev/null and b/src/assets/images/organization-02.jpg differ diff --git a/src/components/common/board/index.tsx b/src/components/common/board/index.tsx index 99d1781..e1f6092 100644 --- a/src/components/common/board/index.tsx +++ b/src/components/common/board/index.tsx @@ -48,7 +48,9 @@ Board.Cell = function Cell({ children, className, ...props }: CellProps) { return (
  • {children} diff --git a/src/components/common/carousel/index.tsx b/src/components/common/carousel/index.tsx index 98e2868..c09c470 100644 --- a/src/components/common/carousel/index.tsx +++ b/src/components/common/carousel/index.tsx @@ -6,7 +6,7 @@ export default function Carousel({ data }: { data: string[] }) { const [index, setIndex] = useState(0); return ( -
    +
    diff --git a/src/components/common/gnh/index.tsx b/src/components/common/gnh/index.tsx index 7c75f78..95097a8 100644 --- a/src/components/common/gnh/index.tsx +++ b/src/components/common/gnh/index.tsx @@ -10,7 +10,12 @@ interface GnhProps { const Gnh = ({ heading, subHeading, headingStyle, headingText, subHeadingText }: GnhProps) => (
    -

    {heading}

    +

    + {heading} +

    {subHeading &&

    {subHeading}

    }
    ); diff --git a/src/components/main/menu.tsx b/src/components/main/menu.tsx index cf7f2fc..0b18f9a 100644 --- a/src/components/main/menu.tsx +++ b/src/components/main/menu.tsx @@ -15,8 +15,8 @@ export default function Menu() { { title: '조직도', path: ROUTES.COUNCIL.ORGANIZATION }, { title: '오시는 길', path: ROUTES.COUNCIL.LOCATION }, { title: '공지', path: ROUTES.NOTICE.ROOT }, - { title: '회의록', path: ROUTES.NOTICE.ROOT }, - { title: '회칙', path: ROUTES.NOTICE.ROOT }, + { title: '회의록', path: ROUTES.CONFERENCE.ROOT }, + { title: '회칙', path: ROUTES.RULE.ROOT }, { title: '청원게시판', path: ROUTES.PETITION.ROOT }, ], }, diff --git a/src/components/main/post.tsx b/src/components/main/post.tsx index f8cc370..5eff81d 100644 --- a/src/components/main/post.tsx +++ b/src/components/main/post.tsx @@ -1,12 +1,11 @@ -import React, { ReactNode, useEffect } from 'react'; +import React, { ReactNode } from 'react'; import TextEditor from 'components/common/editor/index'; import { ImageProps } from 'hooks/useImageUpload'; -import { IFormInfo } from 'hooks/useFormUpload'; import FloatingButton from 'components/ui/button/FloatingButton'; -import { useNavigate } from 'react-router-dom'; import PostBox from 'components/ui/box/PostBox'; import Title from 'components/ui/text/board'; import { FaCamera } from 'react-icons/fa'; +import { IFormInfo } from 'api/upload/types/upload'; interface PostProps { formInfo: IFormInfo; @@ -29,13 +28,7 @@ export default function Post({ addImage, deleteImage, pageTitle, - navigateUrl, }: PostProps) { - const navigate = useNavigate(); - useEffect(() => { - console.log(imageList); - }, [imageList]); - return (
    @@ -45,7 +38,7 @@ export default function Post({ id='title' name='title' value={formInfo.title} - placeholder='청원 제목을 입력해주세요' + placeholder='제목을 입력해주세요' className='w-full focus:outline-0' onChange={(e: React.ChangeEvent) => { setFormInfo((prev) => { @@ -87,11 +80,7 @@ export default function Post({
    ))} - { - navigate(navigateUrl); - }} - > + {}}>

    Upload

    diff --git a/src/components/ui/box/PostBox.tsx b/src/components/ui/box/PostBox.tsx index 1a83846..8227cfe 100644 --- a/src/components/ui/box/PostBox.tsx +++ b/src/components/ui/box/PostBox.tsx @@ -1,5 +1,5 @@ import React, { ComponentProps } from 'react'; -import { LuPaperclip } from 'react-icons/lu'; +import { PiPaperclipFill } from 'react-icons/pi'; import { IWithReactChildren } from 'shared/interfaces/default-interfaces'; interface IPostBox { shadow?: boolean; @@ -12,7 +12,7 @@ export default function PostBox({ }: IPostBox & IWithReactChildren & ComponentProps<'div'>) { return (
    ) { return (
    - + {file.originalName} diff --git a/src/components/ui/box/index.tsx b/src/components/ui/box/index.tsx index 04da35d..971af04 100644 --- a/src/components/ui/box/index.tsx +++ b/src/components/ui/box/index.tsx @@ -1,12 +1,23 @@ -import React, { ComponentProps } from 'react'; -import { IWithReactChildren } from 'shared/interfaces/default-interfaces'; +import React from 'react'; + +interface BoxProps extends React.HTMLAttributes { + type?: 'shadow' | 'shadowImage'; + padding?: string; + border?: string; +} + +export default function Box({ children, className, type, padding, border, ...props }: BoxProps) { + const boxType = { + shadow: { boxShadow: '1px 1px 3px 0px rgba(0, 0, 0, 0.1)', border: 'none' }, + shadowImage: { padding: '0', boxShadow: '1px 1px 3px 0px rgba(0, 0, 0, 0.1)' }, + }; -export default function Box({ children, className, ...props }: IWithReactChildren & ComponentProps<'div'>) { return (
    {children} diff --git a/src/components/ui/chart/PetitionChartList.tsx b/src/components/ui/chart/PetitionChartList.tsx index 5c62c2b..77de1d7 100644 --- a/src/components/ui/chart/PetitionChartList.tsx +++ b/src/components/ui/chart/PetitionChartList.tsx @@ -15,7 +15,7 @@ export default function PetitionChartList({ {idx + 1}. {item.department} - ({(item.agreeCount / sum) * 100}%) + ({Math.floor((item.agreeCount / sum) * 100)}%)
  • ))} diff --git a/src/constants/heading.ts b/src/constants/heading.ts index a816d12..a5cfcdd 100644 --- a/src/constants/heading.ts +++ b/src/constants/heading.ts @@ -4,4 +4,9 @@ export const HeadingStyle = { headingStyle: 'mb-[3px] text-center', subHeadingStyle: 'text-center font-normal text-[11px]', }, + default: { + header: 'mt-4 py-5 px-7', + heading: 'text-xl mb-1', + subHeading: 'font-semibold', + }, }; diff --git a/src/hooks/query/upload/mutation.ts b/src/hooks/query/upload/mutation.ts new file mode 100644 index 0000000..da4b319 --- /dev/null +++ b/src/hooks/query/upload/mutation.ts @@ -0,0 +1,19 @@ +import { useMutation } from 'react-query'; +import { useAlert } from 'hooks/useAlert'; +import { uploadForm } from 'api/upload/upload'; +import { useNavigate } from 'react-router-dom'; + +export const usePostFormUpload = (NAVIGATE_PATH: string) => { + const { alert } = useAlert(); + const navigate = useNavigate(); + + return useMutation({ + mutationFn: uploadForm, + onSuccess: (data) => { + if (data !== undefined && data.status === 200) { + navigate(NAVIGATE_PATH); + alert('완료'); + } + }, + }); +}; diff --git a/src/hooks/useFormUpload.ts b/src/hooks/useFormUpload.ts index 393970e..9fec8d0 100644 --- a/src/hooks/useFormUpload.ts +++ b/src/hooks/useFormUpload.ts @@ -1,14 +1,20 @@ -import React, { useEffect } from 'react'; -import { useApi } from './useApi'; +import React from 'react'; +import { IFormInfo } from 'api/upload/types/upload'; +import { usePostFormUpload } from './query/upload/mutation'; +import { useAlert } from './useAlert'; -export interface IFormInfo { - title: string; - body: string; - files: File[]; -} - -export const useFormUpload = (initFormInfo: IFormInfo, apiPath: string) => { +export const useFormUpload = ({ + initFormInfo, + API_PATH, + NAVIGATE_PATH, +}: { + initFormInfo: IFormInfo; + API_PATH: string; + NAVIGATE_PATH: string; +}) => { const [formInfo, setFormInfo] = React.useState(initFormInfo); + const { mutate } = usePostFormUpload(NAVIGATE_PATH); + const { alert } = useAlert(); const handleUpdate = (value: string) => { const cleanedValue = value.replaceAll(/<\/?p[^>]*>/g, '').replace(/
    /g, ''); @@ -17,9 +23,8 @@ export const useFormUpload = (initFormInfo: IFormInfo, apiPath: string) => { body: cleanedValue, }); }; - const { post } = useApi(); - const handleSubmit = (e: React.FormEvent) => { + const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); const formData = new FormData(); formData.append('title', formInfo.title); @@ -29,17 +34,13 @@ export const useFormUpload = (initFormInfo: IFormInfo, apiPath: string) => { formData.append('files', file); } } - post(apiPath, formInfo, { - authenticate: true, - contentType: 'multipart/form-data', - log: true, - }); + if (formInfo.title.length > 0 && formInfo.body.length > 0) { + mutate({ formInfo, API_PATH }); + } else { + alert('제목과 내용을 입력해주세요'); + } }; - useEffect(() => { - console.log(initFormInfo); - }, [initFormInfo]); - return { formInfo, setFormInfo, diff --git a/src/hooks/useImageUpload.tsx b/src/hooks/useImageUpload.tsx index 2a7301c..256c967 100644 --- a/src/hooks/useImageUpload.tsx +++ b/src/hooks/useImageUpload.tsx @@ -1,5 +1,5 @@ +import { IFormInfo } from 'api/upload/types/upload'; import React, { useEffect } from 'react'; -import { IFormInfo } from './useFormUpload'; export interface ImageProps { add: { diff --git a/src/layouts/BoardLayout.tsx b/src/layouts/BoardLayout.tsx index 5c03b15..c876eb9 100644 --- a/src/layouts/BoardLayout.tsx +++ b/src/layouts/BoardLayout.tsx @@ -16,6 +16,7 @@ export interface IBoardList { expiresAt?: string; agreeCount?: string; blinded: string; + images?: [{ id: number; url: string; originalName: string; mimeType: string; thumbnailUrl: string }]; } export default function BoardLayout({ diff --git a/src/layouts/PostDetailLayout.tsx b/src/layouts/PostDetailLayout.tsx new file mode 100644 index 0000000..d0a4669 --- /dev/null +++ b/src/layouts/PostDetailLayout.tsx @@ -0,0 +1,10 @@ +import React, { ComponentProps } from 'react'; +import { IWithReactChildren } from 'shared/interfaces/default-interfaces'; + +export default function PostDetailLayout({ children, ...props }: IWithReactChildren & ComponentProps<'div'>) { + return ( +
    + {children} +
    + ); +} diff --git a/src/layouts/SinglePageLayout.tsx b/src/layouts/SinglePageLayout.tsx new file mode 100644 index 0000000..e3e1491 --- /dev/null +++ b/src/layouts/SinglePageLayout.tsx @@ -0,0 +1,10 @@ +import React, { ComponentProps } from 'react'; +import { IWithReactChildren } from 'shared/interfaces/default-interfaces'; + +export default function SinglePageLayout({ children, ...props }: IWithReactChildren & ComponentProps<'div'>) { + return ( +
    + {children} +
    + ); +} diff --git a/src/pages/conference/index.tsx b/src/pages/conference/index.tsx index afd71e2..c637064 100644 --- a/src/pages/conference/index.tsx +++ b/src/pages/conference/index.tsx @@ -1,13 +1,34 @@ import Title, { Date } from 'components/ui/text/board'; import { API_PATH, CONSTANTS } from 'constants/api'; +import { HeadingStyle } from 'constants/heading'; +import { useEffectOnce } from 'hooks/useEffectOnce'; +import { useLayout } from 'hooks/useLayout'; import BoardLayout, { IBoardList } from 'layouts/BoardLayout'; import React from 'react'; export default function ConferenceBoard() { + const { setLayout } = useLayout(); + + useEffectOnce(() => { + setLayout({ + title: '총학생회', + backButton: true, + isMain: false, + fullscreen: false, + heading: '총학생회', + subHeading: '회의록', + headingStyle: HeadingStyle.default.header, + headingText: HeadingStyle.default.heading, + subHeadingText: HeadingStyle.default.subHeading, + margin: '', + rounded: true, + }); + }); + const Cell = ({ data }: { data: IBoardList }) => ( -
    +
    - <Date content={data.createdAt} /> + <Date content={data.createdAt} className='font-semibold' /> </div> ); return ( diff --git a/src/pages/council/index.tsx b/src/pages/council/index.tsx index 1804ed8..ad74eaa 100644 --- a/src/pages/council/index.tsx +++ b/src/pages/council/index.tsx @@ -2,13 +2,12 @@ import React from 'react'; import Box from 'components/ui/box'; import { useLayout } from 'hooks/useLayout'; import { useEffectOnce } from 'hooks/useEffectOnce'; +import { HeadingStyle } from 'constants/heading'; +import SinglePageLayout from 'layouts/SinglePageLayout'; export default function Greeting() { const { setLayout } = useLayout(); - const headingStyle = 'mt-[38px] mb-[5px] ml-[29px]'; - const subHeadingStyle = 'ml-[29px] mb-[30px] font-semibold'; - useEffectOnce(() => { setLayout({ title: '총학생회', @@ -17,34 +16,36 @@ export default function Greeting() { fullscreen: false, heading: '총학생회', subHeading: '인사말', - headingStyle: headingStyle, - headingText: '', - subHeadingText: subHeadingStyle, + headingStyle: HeadingStyle.default.header, + headingText: HeadingStyle.default.heading, + subHeadingText: HeadingStyle.default.subHeading, margin: '', rounded: true, }); }); return ( - <Box> - <header> - <h1>그대의 청춘에 단국을 담다,</h1> - </header> - <section> - <p> - 안녕하십니까 단국대학교 죽전 캠퍼스 학우 여러분, <br /> - <strong>55대 담다 총학생회</strong>입니다. <br /> - </p> - <p> - 2023년, 우리 단국은 코로나19로부터 벗어나 제약 없는 대면 - <br /> - 학교생활을 맞이하게 됩니다. <br /> - 저희 담다 총학생회는 학우 여러분의 청춘의 한 페이지에 <br /> - 단국을 담을 수 있도록, - </p> - <p>학우 여러분의 다양한 목소리를 담아 더 나은 학교를 만들기 위해 노력하겠습니다.</p> - <span>감사합니다.</span> - </section> - </Box> + <SinglePageLayout> + <Box className='overflow-hidden' type='shadowImage'> + <img className='w-full h-[calc(100vw*0.2)] border-none bg-neutral-300' src={''} /> + </Box> + <Box className='text-sm leading-5 flex flex-col gap-5' type='shadow'> + <header> + <h1>그대의 청춘에 단국을 담다,</h1> + </header> + <section className='flex flex-col gap-5'> + <p> + 안녕하십니까 단국대학교 죽전 캠퍼스 학우 여러분, <br /> + <strong>55대 담다 총학생회</strong>입니다. <br /> + </p> + <p> + 2023년, 우리 단국은 코로나19로부터 벗어나 제약 없는 대면 학교생활을 맞이하게 됩니다. <br /> + 저희 담다 총학생회는 학우 여러분의 청춘의 한 페이지에 단국을 담을 수 있도록, + </p> + <p>학우 여러분의 다양한 목소리를 담아 더 나은 학교를 만들기 위해 노력하겠습니다.</p> + <span>감사합니다.</span> + </section> + </Box> + </SinglePageLayout> ); } diff --git a/src/pages/council/location.tsx b/src/pages/council/location.tsx index 17429ea..8c7a26e 100644 --- a/src/pages/council/location.tsx +++ b/src/pages/council/location.tsx @@ -2,6 +2,8 @@ import React from 'react'; import { useEffectOnce } from 'hooks/useEffectOnce'; import { useLayout } from 'hooks/useLayout'; import map from '../../assets/images/map.png'; +import { HeadingStyle } from 'constants/heading'; +import SinglePageLayout from 'layouts/SinglePageLayout'; export default function Location() { const { setLayout } = useLayout(); @@ -14,18 +16,18 @@ export default function Location() { fullscreen: false, heading: '총학생회', subHeading: '오시는 길', - headingStyle: '', - headingText: '', - subHeadingText: '', + headingStyle: HeadingStyle.default.header, + headingText: HeadingStyle.default.heading, + subHeadingText: HeadingStyle.default.subHeading, margin: '', rounded: true, }); }); return ( - <> + <SinglePageLayout> <img className='w-[366px] h-[240px] mx-auto' src={map} /> - <ul> + <ul className='flex flex-col gap-4'> <li> <h2 className='font-semibold'>위치</h2> <span>혜당관 406호 총학생회실</span> @@ -47,6 +49,6 @@ export default function Location() { <span>@dku_damda</span> </li> </ul> - </> + </SinglePageLayout> ); } diff --git a/src/pages/council/organization.tsx b/src/pages/council/organization.tsx index 9774f9d..db1c4a0 100644 --- a/src/pages/council/organization.tsx +++ b/src/pages/council/organization.tsx @@ -1,13 +1,15 @@ import React from 'react'; import { useEffectOnce } from 'hooks/useEffectOnce'; import { useLayout } from 'hooks/useLayout'; +import { HeadingStyle } from 'constants/heading'; +import SinglePageLayout from 'layouts/SinglePageLayout'; +import Box from 'components/ui/box'; +import Organization01 from '../../assets/images/organization-01.jpg'; +import Organization02 from '../../assets/images/organization-02.jpg'; export default function Organization() { const { setLayout } = useLayout(); - const headingStyle = 'mt-[38px] mb-[5px] ml-[29px]'; - const subHeadingStyle = 'ml-[29px] mb-[30px] font-semibold'; - useEffectOnce(() => { setLayout({ title: '총학생회', @@ -16,17 +18,20 @@ export default function Organization() { fullscreen: false, heading: '총학생회', subHeading: '조직도', - headingStyle: headingStyle, - headingText: '', - subHeadingText: subHeadingStyle, + headingStyle: HeadingStyle.default.header, + headingText: HeadingStyle.default.heading, + subHeadingText: HeadingStyle.default.subHeading, margin: '', rounded: true, }); }); return ( - <> - <h1>조직도입니다</h1> - </> + <SinglePageLayout> + <Box type='shadow' className='flex flex-col gap-5'> + <img className='rounded-md' src={Organization01} /> + <img className='rounded-md' src={Organization02} /> + </Box> + </SinglePageLayout> ); } diff --git a/src/pages/council/recruitment.tsx b/src/pages/council/recruitment.tsx index 838c109..226c8cd 100644 --- a/src/pages/council/recruitment.tsx +++ b/src/pages/council/recruitment.tsx @@ -2,7 +2,9 @@ import React from 'react'; import { useEffectOnce } from 'hooks/useEffectOnce'; import { useLayout } from 'hooks/useLayout'; import Box from 'components/ui/box'; -import SvgIcon from 'components/common/icon/SvgIcon'; +import { HeadingStyle } from 'constants/heading'; +import SinglePageLayout from 'layouts/SinglePageLayout'; +import { FileBox } from 'components/ui/box/PostBox'; export default function Recruitment() { const { setLayout } = useLayout(); @@ -15,22 +17,17 @@ export default function Recruitment() { fullscreen: false, heading: '부원모집', subHeading: '모집요강', - headingStyle: '', - headingText: '', - subHeadingText: '', + headingStyle: HeadingStyle.default.header, + headingText: HeadingStyle.default.heading, + subHeadingText: HeadingStyle.default.subHeading, margin: '', rounded: true, }); }); - const fileList = [ - { name: '파일1.pdf', type: 'pdf' }, - { name: '파일2.doc', type: 'doc' }, - ]; - return ( - <> - <Box> + <SinglePageLayout> + <Box type='shadow' className='text-sm'> <h3>[55대 담다 총학생회 재학생 집행부 모집 ]</h3> <br></br> <p> @@ -52,18 +49,7 @@ export default function Recruitment() { 부탁드립니다. </span> </Box> - <Box> - <ul> - {fileList.map((file, index) => ( - <li key={index} className='flex'> - <SvgIcon id='document' width={18.93} height={18} /> - <a href={`${file.name}`} download={file.name}> - {file.name} ({file.type}) - </a> - </li> - ))} - </ul> - </Box> - </> + <FileBox files={[{ id: 0, url: '', originalName: '지원서.pdf', mimeType: 'pdf' }]} /> + </SinglePageLayout> ); } diff --git a/src/pages/notice/[id].tsx b/src/pages/notice/[id].tsx index 12b67ef..33c96b3 100644 --- a/src/pages/notice/[id].tsx +++ b/src/pages/notice/[id].tsx @@ -4,11 +4,12 @@ import { API_PATH } from 'constants/api'; import React from 'react'; import Collapse from 'components/ui/collapse'; import { useFetchPost } from 'hooks/useFetchPost'; +import PostDetailLayout from 'layouts/PostDetailLayout'; export default function NoticeDetail() { const { post, images } = useFetchPost<INotice>({ api: API_PATH.POST.NOTICE.ROOT, isCarousel: true }); return ( - <> + <PostDetailLayout> {images!.length > 0 && ( <PostBox> <Collapse status={true}> @@ -22,7 +23,7 @@ export default function NoticeDetail() { <p>{post?.body}</p> </PostBox> {post !== undefined && post.files.length > 0 && <FileBox files={post?.files} />} - </> + </PostDetailLayout> ); } diff --git a/src/pages/notice/index.tsx b/src/pages/notice/index.tsx index 54f6701..994f19e 100644 --- a/src/pages/notice/index.tsx +++ b/src/pages/notice/index.tsx @@ -1,14 +1,46 @@ import Title, { Date } from 'components/ui/text/board'; import { API_PATH, CONSTANTS } from 'constants/api'; +import { HeadingStyle } from 'constants/heading'; +import { useEffectOnce } from 'hooks/useEffectOnce'; +import { useLayout } from 'hooks/useLayout'; import BoardLayout, { IBoardList } from 'layouts/BoardLayout'; import React from 'react'; export default function NoticeBoard() { + const { setLayout } = useLayout(); + + useEffectOnce(() => { + setLayout({ + title: '총학생회', + backButton: true, + isMain: false, + fullscreen: false, + heading: '총학생회', + subHeading: '공지', + headingStyle: HeadingStyle.default.header, + headingText: HeadingStyle.default.heading, + subHeadingText: HeadingStyle.default.subHeading, + margin: '', + rounded: true, + }); + }); + const Cell = ({ data }: { data: IBoardList }) => ( - <> - <Title content={data.title} className='text-xl font-bold' /> - <Date content={data.createdAt} className='text-gray-400' /> - </> + <div className='flex gap-4 overflow-hidden '> + <div + className='w-[40%] h-[100px] overflow-hidden' + style={{ background: 'linear-gradient(131.53deg, #01060B 0%, #084287 100%)' }} + > + <img + className='w-full' + src={data.images !== undefined && data.images.length > 0 ? data.images[0].url : ''} + /> + </div> + <div className='w-[60%] h-[100px] flex flex-col gap-3 justify-center'> + <Title content={data.title} className=' font-bold text-base line-clamp-2' /> + <Date content={data.createdAt} className='text-gray-400 text-xs' /> + </div> + </div> ); return ( diff --git a/src/pages/notice/post.tsx b/src/pages/notice/post.tsx index ab21d7a..4923715 100644 --- a/src/pages/notice/post.tsx +++ b/src/pages/notice/post.tsx @@ -2,9 +2,9 @@ import React from 'react'; import { API_PATH } from 'constants/api'; import { ROUTES } from 'constants/route'; import useImageUpload from 'hooks/useImageUpload'; -import { IFormInfo } from 'hooks/useFormUpload'; import { useFormUpload } from 'hooks/useFormUpload'; import Post from 'components/main/post'; +import { IFormInfo } from 'api/upload/types/upload'; export default function NoticePost() { const initFormInfo: IFormInfo = { @@ -13,10 +13,11 @@ export default function NoticePost() { files: [], }; - const { formInfo, setFormInfo, handleUpdate, handleSubmit } = useFormUpload( - initFormInfo, - API_PATH.POST.NOTICE.ROOT, - ); + const { formInfo, setFormInfo, handleUpdate, handleSubmit } = useFormUpload({ + initFormInfo: initFormInfo, + API_PATH: API_PATH.POST.NOTICE.ROOT, + NAVIGATE_PATH: ROUTES.NOTICE.ROOT, + }); const { imageList, addImage, deleteImage } = useImageUpload(); diff --git a/src/pages/petition/[id].tsx b/src/pages/petition/[id].tsx index 1e91147..6a57600 100644 --- a/src/pages/petition/[id].tsx +++ b/src/pages/petition/[id].tsx @@ -12,6 +12,7 @@ import { TbThumbUp, TbThumbUpFilled } from 'react-icons/tb'; import { useAlert } from 'hooks/useAlert'; import { useApi } from 'hooks/useApi'; import FloatingButton from 'components/ui/button/FloatingButton'; +import PostDetailLayout from 'layouts/PostDetailLayout'; export default function PetitionDetail() { const [updatePost, setUpdatePost] = useState(false); @@ -75,12 +76,16 @@ export default function PetitionDetail() { return ( <> {petition !== undefined && ( - <div className='min-h-screen flex flex-col gap-2'> + <PostDetailLayout> {/* 청원글 */} <Box> <div className='flex gap-4 text-gray-400'> <span>{petitionStatus}</span> - <span>{`D-${remainingDays}`}</span> + <span> + {remainingDays !== undefined && remainingDays > 0 + ? `D-${remainingDays}` + : '기간 만료'} + </span> <span>{`${petition.agreeCount}/150`}</span> </div> <Title>{petition.title} @@ -122,7 +127,7 @@ export default function PetitionDetail() { )} -
    + )} ); diff --git a/src/pages/petition/index.tsx b/src/pages/petition/index.tsx index af3d282..46959c0 100644 --- a/src/pages/petition/index.tsx +++ b/src/pages/petition/index.tsx @@ -6,6 +6,9 @@ import { ROUTES } from 'constants/route'; import BoardLayout, { IBoardList } from 'layouts/BoardLayout'; import { useNavigate } from 'react-router-dom'; import React from 'react'; +import { useLayout } from 'hooks/useLayout'; +import { useEffectOnce } from 'hooks/useEffectOnce'; +import { HeadingStyle } from 'constants/heading'; export const getDaysBetween = (expiresAt: string) => { const startDate = new Date(); @@ -23,12 +26,29 @@ export const getPetitionStatus = (status: string) => { export default function PetitionBoard() { const navigate = useNavigate(); + const { setLayout } = useLayout(); + + useEffectOnce(() => { + setLayout({ + title: '', + backButton: true, + isMain: false, + fullscreen: false, + heading: '청원게시판', + headingStyle: `${HeadingStyle.default.header} mb-2`, + headingText: HeadingStyle.default.heading, + margin: '', + rounded: true, + }); + }); const Cell = ({ data }: { data: IBoardList }) => ( -
    +
    {getPetitionStatus(data.status!)} - <Text length={4}>{`D-${getDaysBetween(data.expiresAt!)}`}</Text> + <Text length={4}> + {getDaysBetween(data.expiresAt!) > 0 ? `D-${getDaysBetween(data.expiresAt!)}` : '만료'} + </Text> </div> ); diff --git a/src/pages/petition/post.tsx b/src/pages/petition/post.tsx index 3a50657..881d874 100644 --- a/src/pages/petition/post.tsx +++ b/src/pages/petition/post.tsx @@ -2,9 +2,9 @@ import React from 'react'; import { API_PATH } from 'constants/api'; import { ROUTES } from 'constants/route'; import useImageUpload from 'hooks/useImageUpload'; -import { IFormInfo } from 'hooks/useFormUpload'; import { useFormUpload } from 'hooks/useFormUpload'; import Post from 'components/main/post'; +import { IFormInfo } from 'api/upload/types/upload'; export default function PetitionForm() { const initFormInfo: IFormInfo = { @@ -13,17 +13,18 @@ export default function PetitionForm() { files: [], }; - const { formInfo, setFormInfo, handleUpdate, handleSubmit } = useFormUpload( - initFormInfo, - API_PATH.POST.PETITION.ROOT, - ); + const { formInfo, setFormInfo, handleUpdate, handleSubmit } = useFormUpload({ + initFormInfo: initFormInfo, + API_PATH: API_PATH.POST.PETITION.ROOT, + NAVIGATE_PATH: ROUTES.PETITION.ROOT, + }); const { imageList, addImage, deleteImage } = useImageUpload(); return ( <Post pageTitle='청원' - navigateUrl={ROUTES.PETITION.POST} + navigateUrl={ROUTES.PETITION.ROOT} formInfo={formInfo} setFormInfo={setFormInfo} handleUpdate={handleUpdate} diff --git a/src/pages/rule/index.tsx b/src/pages/rule/index.tsx index f89cdb3..da2e908 100644 --- a/src/pages/rule/index.tsx +++ b/src/pages/rule/index.tsx @@ -1,11 +1,32 @@ import Title, { Date } from 'components/ui/text/board'; import { API_PATH, CONSTANTS } from 'constants/api'; +import { HeadingStyle } from 'constants/heading'; +import { useEffectOnce } from 'hooks/useEffectOnce'; +import { useLayout } from 'hooks/useLayout'; import BoardLayout, { IBoardList } from 'layouts/BoardLayout'; import React from 'react'; export default function RuleBoard() { + const { setLayout } = useLayout(); + + useEffectOnce(() => { + setLayout({ + title: '총학생회', + backButton: true, + isMain: false, + fullscreen: false, + heading: '총학생회', + subHeading: '회칙', + headingStyle: HeadingStyle.default.header, + headingText: HeadingStyle.default.heading, + subHeadingText: HeadingStyle.default.subHeading, + margin: '', + rounded: true, + }); + }); + const Cell = ({ data }: { data: IBoardList }) => ( - <div className='flex gap-2'> + <div className='flex gap-2 p-3'> <Title content={data.title} className='grow text-center truncate' /> <Date content={data.createdAt} /> </div>