From e409f0628c8e3b77290bda03689b7353fdef4767 Mon Sep 17 00:00:00 2001 From: chunzhi23 <05.huanx10ng@gmail.com> Date: Tue, 13 Aug 2024 09:39:41 +0900 Subject: [PATCH 01/14] [FEAT] sub-heading navigation bar --- .../Noticeboard/elements/NoticeContainer.tsx | 2 +- .../Noticeboard/elements/NoticeItem.tsx | 8 +- .../common/SubHeadNavbar/NavList.ts | 128 ++++++++++++++++++ .../SubHeadNavbar/SubHeadNavbar.module.css | 42 ++++++ .../SubHeadNavbar/SubHeadNavbar.story.tsx | 24 ++++ .../SubHeadNavbar/SubHeadNavbar.test.tsx | 14 ++ .../common/SubHeadNavbar/SubHeadNavbar.tsx | 36 +++++ 7 files changed, 251 insertions(+), 3 deletions(-) create mode 100644 src/components/common/SubHeadNavbar/NavList.ts create mode 100644 src/components/common/SubHeadNavbar/SubHeadNavbar.module.css create mode 100644 src/components/common/SubHeadNavbar/SubHeadNavbar.story.tsx create mode 100644 src/components/common/SubHeadNavbar/SubHeadNavbar.test.tsx create mode 100644 src/components/common/SubHeadNavbar/SubHeadNavbar.tsx diff --git a/src/components/common/Noticeboard/elements/NoticeContainer.tsx b/src/components/common/Noticeboard/elements/NoticeContainer.tsx index 8bf92e95..255cf706 100644 --- a/src/components/common/Noticeboard/elements/NoticeContainer.tsx +++ b/src/components/common/Noticeboard/elements/NoticeContainer.tsx @@ -6,7 +6,7 @@ export function NoticeContainer({ items }: IBoardContentProps) { return (
- +
{/* Pagination */}
diff --git a/src/components/common/Noticeboard/elements/NoticeItem.tsx b/src/components/common/Noticeboard/elements/NoticeItem.tsx index 0824625a..1e77dc2c 100644 --- a/src/components/common/Noticeboard/elements/NoticeItem.tsx +++ b/src/components/common/Noticeboard/elements/NoticeItem.tsx @@ -4,7 +4,11 @@ import { Group } from "@mantine/core"; import { IconPinFilled } from "@tabler/icons-react"; import { IBoardItem } from "../Noticeboard"; -export function NoticeItem({ title, number, author, date, view, pinned, href }: IBoardItem) { +type INoticeItem = IBoardItem & { + key: number; +}; + +export function NoticeItem({ key, title, number, author, date, view, pinned, href }: INoticeItem) { const formattedDate = new Intl.DateTimeFormat("ko-KR", { year: "numeric", month: "2-digit", @@ -12,7 +16,7 @@ export function NoticeItem({ title, number, author, date, view, pinned, href }: }).format(date); return ( -
  • +
  • {pinned ? : null} diff --git a/src/components/common/SubHeadNavbar/NavList.ts b/src/components/common/SubHeadNavbar/NavList.ts new file mode 100644 index 00000000..49d301fe --- /dev/null +++ b/src/components/common/SubHeadNavbar/NavList.ts @@ -0,0 +1,128 @@ +type NavItemType = { + name: string; + link: string; +}; + +type NavListType = { + title: string; + items: NavItemType[]; +}[]; + +export const NavList: NavListType = [ + { + title: "Projects", + items: [ + { + name: "전체보기", + link: "#", + }, + { + name: "AI/머신러닝", + link: "#", + }, + { + name: "인터랙션/증강현실", + link: "#", + }, + { + name: "컴퓨터 비전", + link: "#", + }, + { + name: "보안/SW공학", + link: "#", + }, + { + name: "시스템/네트워크", + link: "#", + }, + { + name: "자연어 처리", + link: "#", + }, + { + name: "빅데이터 분석", + link: "#", + }, + { + name: "웹/어플리케이션", + link: "#", + }, + ], + }, + { + title: "Interviews", + items: [ + { + name: "대담 영상", + link: "#", + }, + { + name: "퀴즈 챌린지", + link: "#", + }, + ], + }, + { + title: "Job Fair", + items: [ + { + name: "잡페어 인터뷰", + link: "#", + }, + { + name: "채용 공고", + link: "#", + }, + ], + }, + { + title: "AI Hub", + items: [ + { + name: "AI Model", + link: "#", + }, + { + name: "AI Dataset", + link: "#", + }, + ], + }, + { + title: "Events", + items: [ + { + name: "갤러리", + link: "#", + }, + { + name: "이벤트 공지사항", + link: "#", + }, + ], + }, + { + title: "Info Desk", + items: [ + { + name: "S-TOP 소개", + link: "#", + }, + { + name: "산학협력프로젝트 소개", + link: "#", + }, + { + name: "산학협력 과제 제안", + link: "#", + }, + { + name: "프로젝트 QnA", + link: "#", + }, + ], + }, +]; + +export type NavNames = (typeof NavList)[number]["title"]; diff --git a/src/components/common/SubHeadNavbar/SubHeadNavbar.module.css b/src/components/common/SubHeadNavbar/SubHeadNavbar.module.css new file mode 100644 index 00000000..557ff5c3 --- /dev/null +++ b/src/components/common/SubHeadNavbar/SubHeadNavbar.module.css @@ -0,0 +1,42 @@ +.navbar { + background-color: var(--color-primary); + color: var(--color-onPrimary); +} + +.navtit { + margin: 0 30px; + + & > h3 { + margin: 0; + } +} + +.divider { + margin: 18px 0; +} + +.navlist { + & ul { + margin: 0; + padding: 0; + display: flex; + flex-direction: row; + list-style: none; + } +} + +.navitem { + cursor: pointer; + + a { + text-decoration: none; + color: var(--color-onPrimary); + } + + & > div { + padding: 0 40px; + height: 80px; + display: flex; + align-items: center; + } +} diff --git a/src/components/common/SubHeadNavbar/SubHeadNavbar.story.tsx b/src/components/common/SubHeadNavbar/SubHeadNavbar.story.tsx new file mode 100644 index 00000000..3ebed76f --- /dev/null +++ b/src/components/common/SubHeadNavbar/SubHeadNavbar.story.tsx @@ -0,0 +1,24 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { SubHeadNavbar } from "./SubHeadNavbar"; + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export +const meta = { + title: "SubHeadNavbar", + component: SubHeadNavbar, + parameters: { + // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout + layout: "fullscreen", + }, + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args +export const Usage: Story = { + args: { + title: "Info Desk", + }, +}; diff --git a/src/components/common/SubHeadNavbar/SubHeadNavbar.test.tsx b/src/components/common/SubHeadNavbar/SubHeadNavbar.test.tsx new file mode 100644 index 00000000..7608c457 --- /dev/null +++ b/src/components/common/SubHeadNavbar/SubHeadNavbar.test.tsx @@ -0,0 +1,14 @@ +import { render, screen } from "@/utils/test-utils"; +import "@testing-library/jest-dom"; +import { SubHeadNavbar } from "./SubHeadNavbar"; + +describe("Sub-Heading Navigation Bar Component", () => { + it("renders correctly with the given props", () => { + const props = { + title: "Info Desk", + }; + + render(); + expect(screen.getByRole("region", { name: "SubHeadNavbar" })).toBeInTheDocument(); + }); +}); diff --git a/src/components/common/SubHeadNavbar/SubHeadNavbar.tsx b/src/components/common/SubHeadNavbar/SubHeadNavbar.tsx new file mode 100644 index 00000000..ce0c6314 --- /dev/null +++ b/src/components/common/SubHeadNavbar/SubHeadNavbar.tsx @@ -0,0 +1,36 @@ +import { Divider, Group } from "@mantine/core"; +import styles from "./SubHeadNavbar.module.css"; +import { NavList, NavNames } from "./NavList"; +import Link from "next/link"; + +interface ISubHeadNavbar { + title: NavNames; +} + +export function SubHeadNavbar({ title }: ISubHeadNavbar) { + const NavTitList = NavList.find((item) => item.title === title)!.items; + + return ( + <> +
    + +
    +

    {title}

    +
    + +
    +
      + {NavTitList.map((item, idx) => ( +
    • +
      + {item.name} +
      +
    • + ))} +
    +
    +
    +
    + + ); +} From 89c0defb17e841019bde8aa2325da9cc465e436b Mon Sep 17 00:00:00 2001 From: chunzhi23 <05.huanx10ng@gmail.com> Date: Wed, 14 Aug 2024 16:26:54 +0900 Subject: [PATCH 02/14] export sharing types n navlist --- src/components/common/Header/NavList.ts | 41 ---------------- .../UserNavigations.ts} | 15 +++--- src/types/MantineTypes.ts | 15 ++++++ src/types/PageBoardTypes.ts | 49 +++++++++++++++++++ 4 files changed, 71 insertions(+), 49 deletions(-) delete mode 100644 src/components/common/Header/NavList.ts rename src/{components/common/SubHeadNavbar/NavList.ts => constants/UserNavigations.ts} (91%) create mode 100644 src/types/MantineTypes.ts create mode 100644 src/types/PageBoardTypes.ts diff --git a/src/components/common/Header/NavList.ts b/src/components/common/Header/NavList.ts deleted file mode 100644 index 0d7d5ab0..00000000 --- a/src/components/common/Header/NavList.ts +++ /dev/null @@ -1,41 +0,0 @@ -type NavListType = { - name: string; - items: string[]; -}[]; - -export const NavList: NavListType = [ - { - name: "Projects", - items: [ - "전체보기", - "AI/머신러닝", - "인터랙션/증강현실", - "컴퓨터 비전", - "보안/SW공학", - "시스템/네트워크", - "자연어 처리", - "빅데이터 분석", - "웹/어플리케이션", - ], - }, - { - name: "Interviews", - items: ["대담 영상", "퀴즈 챌린지"], - }, - { - name: "Job Fair", - items: ["잡페어 인터뷰", "채용 공고"], - }, - { - name: "AI Hub", - items: ["AI Model", "AI Dataset"], - }, - { - name: "Events", - items: ["갤러리", "이벤트 공지사항"], - }, - { - name: "Info Desk", - items: ["S-TOP 소개", "산학협력프로젝트 소개", "산학협력 과제 제안", "프로젝트 QnA"], - }, -]; diff --git a/src/components/common/SubHeadNavbar/NavList.ts b/src/constants/UserNavigations.ts similarity index 91% rename from src/components/common/SubHeadNavbar/NavList.ts rename to src/constants/UserNavigations.ts index 49d301fe..f415578f 100644 --- a/src/components/common/SubHeadNavbar/NavList.ts +++ b/src/constants/UserNavigations.ts @@ -1,14 +1,15 @@ -type NavItemType = { +interface INavItem { name: string; link: string; -}; +} -type NavListType = { +interface INavList { title: string; - items: NavItemType[]; -}[]; + items: INavItem[]; +} -export const NavList: NavListType = [ +export type USER_NAV_NAMES = (typeof USER_NAVS)[number]["title"]; +export const USER_NAVS: INavList[] = [ { title: "Projects", items: [ @@ -124,5 +125,3 @@ export const NavList: NavListType = [ ], }, ]; - -export type NavNames = (typeof NavList)[number]["title"]; diff --git a/src/types/MantineTypes.ts b/src/types/MantineTypes.ts new file mode 100644 index 00000000..911a0cf5 --- /dev/null +++ b/src/types/MantineTypes.ts @@ -0,0 +1,15 @@ +export interface MantineSelectOption { + value: string; + label: string; +} + +export interface MantineSelectGroupedOption { + group: string; + items: MantineSelectOption[]; +} + +export type MantineSelectData = + | string[] + | MantineSelectOption[] + | { group: string; items: string[] }[] + | MantineSelectGroupedOption[]; diff --git a/src/types/PageBoardTypes.ts b/src/types/PageBoardTypes.ts new file mode 100644 index 00000000..600f8d1b --- /dev/null +++ b/src/types/PageBoardTypes.ts @@ -0,0 +1,49 @@ +import { ComboboxItem } from "@mantine/core"; +import { ChangeEvent, KeyboardEvent, MouseEvent } from "react"; + +interface INoticeClassifierItem { + value: string; + label: string; +} + +export interface INoticeClassifier { + data: INoticeClassifierItem[]; + defaultLabel: number; + searchPlaceholder?: string; +} + +export interface INoticeAllItem { + title: string; + number: number; + author: string; + date: Date; + view: number; + pinned: boolean; + href: string; + contentTxt: string; +} + +export interface INoticeHeading { + heading: string; + classifier: INoticeClassifier; +} + +export interface INoticeContent { + items: INoticeAllItem[]; +} + +export interface INoticeHandler { + inputValue: string; + handleInput: (event: MouseEvent | ChangeEvent, payload?: unknown) => void; + handleKeyDown: (event: KeyboardEvent, payload?: unknown) => void; + handleSelect: (value: string | null, option?: ComboboxItem) => void; + handleSubmit: (event: MouseEvent, payload?: unknown) => void; +} + +type justifyAlign = "start" | "center" | "end"; + +export interface IBoardPagin { + paginShow: number; + paginJustify: justifyAlign; + paginMarginTop: string; +} From fc9e7226b64ee1d1ef1f38ea36ad26cfb2c63920 Mon Sep 17 00:00:00 2001 From: chunzhi23 <05.huanx10ng@gmail.com> Date: Wed, 14 Aug 2024 16:30:10 +0900 Subject: [PATCH 03/14] link types n constants exported --- src/components/common/Header/Header.module.css | 18 +++++++++++++----- .../common/Header/elements/HandoutOverview.tsx | 13 ++++++++----- .../common/Header/elements/HeaderTopNav.tsx | 13 ++++++++----- .../common/SubHeadNavbar/SubHeadNavbar.tsx | 11 +++++------ src/components/common/SubHeadNavbar/index.ts | 1 + 5 files changed, 35 insertions(+), 21 deletions(-) create mode 100644 src/components/common/SubHeadNavbar/index.ts diff --git a/src/components/common/Header/Header.module.css b/src/components/common/Header/Header.module.css index f4aa399f..769bdb0e 100644 --- a/src/components/common/Header/Header.module.css +++ b/src/components/common/Header/Header.module.css @@ -118,16 +118,19 @@ display: block; } - & > ul > li > ul > li { - padding: 12px 24px; - white-space: nowrap; - cursor: pointer; - } & > ul > li > ul > li:hover { /* background-color: var(--color-coverHover); */ background-color: var(--color-surfaceVariant); } + & > ul > li > ul > li > a { + display: block; + padding: 12px 24px; + white-space: nowrap; + text-decoration: none; + color: var(--mantine-color-text); + } + @media screen and (max-width: 1023px) { display: none; } @@ -271,6 +274,11 @@ visibility 0.2s, opacity 0.2s ease-in-out; + & a { + text-decoration: none; + color: var(--mantine-color-text); + } + @media screen and (min-width: 1198px) { padding: 100px 180px; } diff --git a/src/components/common/Header/elements/HandoutOverview.tsx b/src/components/common/Header/elements/HandoutOverview.tsx index 933d7160..670ea374 100644 --- a/src/components/common/Header/elements/HandoutOverview.tsx +++ b/src/components/common/Header/elements/HandoutOverview.tsx @@ -1,15 +1,18 @@ +import { USER_NAVS } from "@/constants/UserNavigations"; import styles from "../Header.module.css"; -import { NavList } from "../NavList"; +import Link from "next/link"; export function HandoutOverview() { return (
    - {NavList.map((topic) => ( -
    - {topic.name} + {USER_NAVS.map((topic) => ( +
    + {topic.title}
      {topic.items.map((item, idx) => ( -
    • {item}
    • +
    • + {item.name} +
    • ))}
    diff --git a/src/components/common/Header/elements/HeaderTopNav.tsx b/src/components/common/Header/elements/HeaderTopNav.tsx index 2a18e9ff..082afacd 100644 --- a/src/components/common/Header/elements/HeaderTopNav.tsx +++ b/src/components/common/Header/elements/HeaderTopNav.tsx @@ -1,16 +1,19 @@ -import { NavList } from "../NavList"; +import { USER_NAVS } from "@/constants/UserNavigations"; import styles from "../Header.module.css"; +import Link from "next/link"; export function HeaderTopNav() { return (
      - {NavList.map((topic) => ( -
    • -
      {topic.name}
      + {USER_NAVS.map((topic, idx) => ( +
    • +
      {topic.title}
        {topic.items.map((item, idx) => ( -
      • {item}
      • +
      • + {item.name} +
      • ))}
    • diff --git a/src/components/common/SubHeadNavbar/SubHeadNavbar.tsx b/src/components/common/SubHeadNavbar/SubHeadNavbar.tsx index ce0c6314..a4694199 100644 --- a/src/components/common/SubHeadNavbar/SubHeadNavbar.tsx +++ b/src/components/common/SubHeadNavbar/SubHeadNavbar.tsx @@ -1,14 +1,14 @@ -import { Divider, Group } from "@mantine/core"; -import styles from "./SubHeadNavbar.module.css"; -import { NavList, NavNames } from "./NavList"; +import { USER_NAV_NAMES, USER_NAVS } from "@/constants/UserNavigations"; +import { Group } from "@mantine/core"; import Link from "next/link"; +import styles from "./SubHeadNavbar.module.css"; interface ISubHeadNavbar { - title: NavNames; + title: USER_NAV_NAMES; } export function SubHeadNavbar({ title }: ISubHeadNavbar) { - const NavTitList = NavList.find((item) => item.title === title)!.items; + const NavTitList = USER_NAVS.find((item) => item.title === title)!.items; return ( <> @@ -17,7 +17,6 @@ export function SubHeadNavbar({ title }: ISubHeadNavbar) {

      {title}

      -
        {NavTitList.map((item, idx) => ( diff --git a/src/components/common/SubHeadNavbar/index.ts b/src/components/common/SubHeadNavbar/index.ts new file mode 100644 index 00000000..beb1a65e --- /dev/null +++ b/src/components/common/SubHeadNavbar/index.ts @@ -0,0 +1 @@ +export { SubHeadNavbar } from "./SubHeadNavbar"; From 73e3bdafc76a56137a300fe82380d2b704ec3edf Mon Sep 17 00:00:00 2001 From: chunzhi23 <05.huanx10ng@gmail.com> Date: Wed, 14 Aug 2024 16:31:16 +0900 Subject: [PATCH 04/14] =?UTF-8?q?[FIX]=20#44=20=ED=8E=98=EC=9D=B4=EC=A7=80?= =?UTF-8?q?=EB=84=A4=EC=9D=B4=EC=85=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/Pagination/Pagination.stories.tsx | 4 +++- .../common/Pagination/Pagination.test.tsx | 2 +- .../common/Pagination/Pagination.tsx | 20 +++++++++++++++---- src/components/common/Pagination/index.ts | 1 + 4 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 src/components/common/Pagination/index.ts diff --git a/src/components/common/Pagination/Pagination.stories.tsx b/src/components/common/Pagination/Pagination.stories.tsx index ad4538e3..7c62a5db 100644 --- a/src/components/common/Pagination/Pagination.stories.tsx +++ b/src/components/common/Pagination/Pagination.stories.tsx @@ -22,7 +22,9 @@ for (let i = 0; i < 127; i++) { } export const Default: Story = { args: { - show: 3, data: data, + paginShow: 3, + paginJustify: "center", + paginMarginTop: "40px", }, }; diff --git a/src/components/common/Pagination/Pagination.test.tsx b/src/components/common/Pagination/Pagination.test.tsx index 9b286a0a..8ee8057f 100644 --- a/src/components/common/Pagination/Pagination.test.tsx +++ b/src/components/common/Pagination/Pagination.test.tsx @@ -4,7 +4,7 @@ import "@testing-library/jest-dom"; describe("Pagenation component", () => { it("renders correctly with the given label", () => { - render(); + render(); // More on screen queries: https://testing-library.com/docs/queries/about // More on jest expect Api: https://jestjs.io/docs/expect expect(screen.getByRole("button", { name: "Button" })).toBeInTheDocument(); diff --git a/src/components/common/Pagination/Pagination.tsx b/src/components/common/Pagination/Pagination.tsx index f7d9d182..fab980d5 100644 --- a/src/components/common/Pagination/Pagination.tsx +++ b/src/components/common/Pagination/Pagination.tsx @@ -7,9 +7,20 @@ import { PaginationRoot, } from "@mantine/core"; import classes from "./Pagination.module.css"; -import { useState } from "react"; +import { ReactNode, useState } from "react"; +import { IBoardPagin } from "@/types/PageBoardTypes"; -export function Paginations({ show, data, ...props }: { show: number; data: Array }) { +type PaginationProps = IBoardPagin & { + data: Array; +}; + +export function Paginations({ + data, + paginShow: show, + paginJustify: justify, + paginMarginTop: marginTop, + ...props +}: PaginationProps) { const [page, setPage] = useState(1); const pages = data.slice((page - 1) * show, page * show); return ( @@ -18,8 +29,9 @@ export function Paginations({ show, data, ...props }: { show: number; data: Arra - + diff --git a/src/components/common/Pagination/index.ts b/src/components/common/Pagination/index.ts new file mode 100644 index 00000000..1f7d0b7b --- /dev/null +++ b/src/components/common/Pagination/index.ts @@ -0,0 +1 @@ +export { Paginations } from "./Pagination"; From 981c3aeff600075432751572a1cc147d7a42b98f Mon Sep 17 00:00:00 2001 From: chunzhi23 <05.huanx10ng@gmail.com> Date: Wed, 14 Aug 2024 16:32:43 +0900 Subject: [PATCH 05/14] =?UTF-8?q?[FIX]=20#44=20=EA=B3=B5=EC=A7=80=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EC=A0=84=EC=B2=B4=EB=B3=B4=EA=B8=B0=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/Noticeboard/Noticeboard.story.tsx | 16 ++++- .../common/Noticeboard/Noticeboard.test.tsx | 24 ++++++- .../common/Noticeboard/Noticeboard.tsx | 63 +++++++++---------- .../Noticeboard/elements/NoticeContainer.tsx | 24 +++++-- .../Noticeboard/elements/NoticeHeading.tsx | 37 ++++++----- .../Noticeboard/elements/NoticeItem.tsx | 14 ++--- 6 files changed, 111 insertions(+), 67 deletions(-) diff --git a/src/components/common/Noticeboard/Noticeboard.story.tsx b/src/components/common/Noticeboard/Noticeboard.story.tsx index d8c11a69..70b2cef7 100644 --- a/src/components/common/Noticeboard/Noticeboard.story.tsx +++ b/src/components/common/Noticeboard/Noticeboard.story.tsx @@ -22,7 +22,11 @@ type Story = StoryObj; // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args const classifier = { - labels: ["Label 1", "Label 2", "Label 3"], + data: [ + { value: "0", label: "label 1" }, + { value: "1", label: "label 2" }, + { value: "2", label: "label 3" }, + ], defaultLabel: 0, searchPlaceholder: "Input here to search...", }; @@ -35,6 +39,7 @@ const items = [ view: 123, pinned: true, href: "/1", + contentTxt: "this is important!", }, { title: "Content", @@ -44,13 +49,22 @@ const items = [ view: 456, pinned: false, href: "/2", + contentTxt: "This is a content.", }, ]; export const Usage: Story = { args: { + inputValue: "", + handleInput: () => {}, + handleKeyDown: () => {}, + handleSelect: () => {}, + handleSubmit: () => {}, heading: "Board", classifier, items, + paginShow: 10, + paginJustify: "end", + paginMarginTop: "20px", }, }; diff --git a/src/components/common/Noticeboard/Noticeboard.test.tsx b/src/components/common/Noticeboard/Noticeboard.test.tsx index cf6b9c41..1a3ea900 100644 --- a/src/components/common/Noticeboard/Noticeboard.test.tsx +++ b/src/components/common/Noticeboard/Noticeboard.test.tsx @@ -5,7 +5,11 @@ import "@testing-library/jest-dom"; describe("Noticeboard component", () => { it("renders correctly with the given heading, classifier, and items", () => { const classifier = { - labels: ["Label 1", "Label 2", "Label 3"], + data: [ + { value: "0", label: "label 1" }, + { value: "1", label: "label 2" }, + { value: "2", label: "label 3" }, + ], defaultLabel: 0, searchPlaceholder: "Input here to search...", }; @@ -18,6 +22,7 @@ describe("Noticeboard component", () => { view: 123, pinned: true, href: "/1", + contentTxt: "this is important!", }, { title: "Content", @@ -27,10 +32,25 @@ describe("Noticeboard component", () => { view: 456, pinned: false, href: "/2", + contentTxt: "this is a content.", }, ]; - render(); + render( + {}} + handleKeyDown={() => {}} + handleSelect={() => {}} + handleSubmit={() => {}} + heading="Board" + classifier={classifier} + items={items} + paginShow={10} + paginJustify="end" + paginMarginTop="20px" + /> + ); expect(screen.getByRole("region", { name: "Noticeboard" })).toBeInTheDocument(); }); }); diff --git a/src/components/common/Noticeboard/Noticeboard.tsx b/src/components/common/Noticeboard/Noticeboard.tsx index d4c9c771..16260111 100644 --- a/src/components/common/Noticeboard/Noticeboard.tsx +++ b/src/components/common/Noticeboard/Noticeboard.tsx @@ -1,51 +1,46 @@ -"use client"; - -import { useState } from "react"; -import styles from "./Noticeboard.module.css"; -import { NoticeHeading } from "./elements/NoticeHeading"; +import { + INoticeHeading, + INoticeContent, + INoticeHandler, + IBoardPagin, +} from "@/types/PageBoardTypes"; import { NoticeContainer } from "./elements/NoticeContainer"; +import { NoticeHeading } from "./elements/NoticeHeading"; +import styles from "./Noticeboard.module.css"; -interface IBoardClassifier { - labels: string[]; - defaultLabel: number; - searchPlaceholder?: string; -} - -export interface IBoardItem { - title: string; - number: number; - author: string; - date: Date; - view: number; - pinned: boolean; - href: string; -} - -export interface IBoardHeadingProps { - heading: string; - classifier: IBoardClassifier; -} - -export interface IBoardContentProps { - items: IBoardItem[]; -} +type NoticeboardProps = INoticeHeading & INoticeContent & INoticeHandler & IBoardPagin; export function Noticeboard({ + inputValue, + handleInput, + handleKeyDown, + handleSelect, + handleSubmit, heading, classifier, items, -}: IBoardHeadingProps & IBoardContentProps) { - const [value, setValue] = useState(""); + paginShow, + paginJustify, + paginMarginTop, +}: NoticeboardProps) { return ( <>
        - +
        ); diff --git a/src/components/common/Noticeboard/elements/NoticeContainer.tsx b/src/components/common/Noticeboard/elements/NoticeContainer.tsx index 255cf706..3f716288 100644 --- a/src/components/common/Noticeboard/elements/NoticeContainer.tsx +++ b/src/components/common/Noticeboard/elements/NoticeContainer.tsx @@ -1,14 +1,30 @@ -import { IBoardContentProps } from "../Noticeboard"; +import { IBoardPagin, INoticeContent } from "@/types/PageBoardTypes"; +import { Paginations } from "../../Pagination"; import styles from "../Noticeboard.module.css"; import { NoticeItem } from "./NoticeItem"; -export function NoticeContainer({ items }: IBoardContentProps) { +type NoticeContainerProps = INoticeContent & IBoardPagin; + +export function NoticeContainer({ + items, + paginShow, + paginJustify, + paginMarginTop, +}: NoticeContainerProps) { return (
        -
          {items.map((item, key) => NoticeItem({ ...item, key }))}
        +
          + ( + + ))} + paginShow={paginShow} + paginJustify={paginJustify} + paginMarginTop={paginMarginTop} + /> +
        - {/* Pagination */}
        ); } diff --git a/src/components/common/Noticeboard/elements/NoticeHeading.tsx b/src/components/common/Noticeboard/elements/NoticeHeading.tsx index 35619cba..a03bfb09 100644 --- a/src/components/common/Noticeboard/elements/NoticeHeading.tsx +++ b/src/components/common/Noticeboard/elements/NoticeHeading.tsx @@ -1,19 +1,19 @@ -import { Button, CloseButton, Group, Input, Select } from "@mantine/core"; -import styles from "../Noticeboard.module.css"; +import { INoticeHeading, INoticeHandler } from "@/types/PageBoardTypes"; +import { Group, Select, Input, CloseButton, Button } from "@mantine/core"; import { IconSearch } from "@tabler/icons-react"; -import { IBoardHeadingProps } from "../Noticeboard"; +import styles from "../Noticeboard.module.css"; -interface IBoardSelectState { - value: string; - setValue: (value: string) => void; -} +type NoticeHeadingProps = INoticeHeading & INoticeHandler; export function NoticeHeading({ - value, - setValue, + inputValue, + handleInput, + handleKeyDown, + handleSelect, + handleSubmit, heading, - classifier: { labels, defaultLabel, searchPlaceholder }, -}: IBoardSelectState & IBoardHeadingProps) { + classifier: { data, defaultLabel, searchPlaceholder }, +}: NoticeHeadingProps) { return (

        {heading}

        @@ -21,8 +21,8 @@ export function NoticeHeading({ setValue(event.currentTarget.value)} + // onChange={(event) => setValue(event.currentTarget.value)} + onChange={handleInput} + onKeyDown={handleKeyDown} rightSectionPointerEvents="all" mt="md" rightSection={ setValue("")} - style={{ display: value ? undefined : "none" }} + onClick={(e) => handleInput(e, "CLEAR")} + style={{ display: inputValue ? undefined : "none" }} /> } /> - diff --git a/src/components/common/Noticeboard/elements/NoticeItem.tsx b/src/components/common/Noticeboard/elements/NoticeItem.tsx index 1e77dc2c..9d73ef7a 100644 --- a/src/components/common/Noticeboard/elements/NoticeItem.tsx +++ b/src/components/common/Noticeboard/elements/NoticeItem.tsx @@ -1,14 +1,10 @@ -import Link from "next/link"; -import styles from "../Noticeboard.module.css"; +import { INoticeAllItem } from "@/types/PageBoardTypes"; import { Group } from "@mantine/core"; import { IconPinFilled } from "@tabler/icons-react"; -import { IBoardItem } from "../Noticeboard"; - -type INoticeItem = IBoardItem & { - key: number; -}; +import Link from "next/link"; +import styles from "../Noticeboard.module.css"; -export function NoticeItem({ key, title, number, author, date, view, pinned, href }: INoticeItem) { +export function NoticeItem({ title, number, author, date, view, pinned, href }: INoticeAllItem) { const formattedDate = new Intl.DateTimeFormat("ko-KR", { year: "numeric", month: "2-digit", @@ -16,7 +12,7 @@ export function NoticeItem({ key, title, number, author, date, view, pinned, hre }).format(date); return ( -
      • +
      • {pinned ? : null} From 96f67732ac193db4f9959ae80c542214e51be655 Mon Sep 17 00:00:00 2001 From: chunzhi23 <05.huanx10ng@gmail.com> Date: Wed, 14 Aug 2024 16:33:29 +0900 Subject: [PATCH 06/14] =?UTF-8?q?[FEAT]=20#44=20=EA=B3=B5=EC=A7=80?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=ED=8E=98=EC=9D=B4=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infodesk/notices/getUserNoticeItems.tsx | 93 ++++++++++++++++ src/app/(user)/infodesk/notices/page.tsx | 102 +++++++++++++++++- .../(user)/infodesk/notices/styles.module.css | 22 ++++ 3 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 src/app/(user)/infodesk/notices/getUserNoticeItems.tsx create mode 100644 src/app/(user)/infodesk/notices/styles.module.css diff --git a/src/app/(user)/infodesk/notices/getUserNoticeItems.tsx b/src/app/(user)/infodesk/notices/getUserNoticeItems.tsx new file mode 100644 index 00000000..73f4f37a --- /dev/null +++ b/src/app/(user)/infodesk/notices/getUserNoticeItems.tsx @@ -0,0 +1,93 @@ +import { INoticeAllItem } from "@/types/PageBoardTypes"; +import { ReadonlyURLSearchParams } from "next/navigation"; + +export function getUserNoticeItems(params: ReadonlyURLSearchParams) { + const queryParams = params.get("query"); + const categoryIdParams = params.get("categoryId"); + + const items = [ + { + title: "Important Notice", + number: 1, + author: "admin", + date: new Date(), + view: 123, + pinned: true, + href: "#", + contentTxt: "안녕하세요 이건 아주 중요한 공지입니다. 꼭 확인해주세요.", + }, + { + title: "Content Update", + number: 2, + author: "admin", + date: new Date(), + view: 456, + pinned: false, + href: "#", + contentTxt: "우리 동아리는 SCG. 중요한 업데이트가 있습니다.", + }, + { + title: "Reminder", + number: 3, + author: "admin", + date: new Date(), + view: 789, + pinned: false, + href: "#", + contentTxt: "이 공지사항을 꼭 확인해 주세요.", + }, + { + title: "Important Announcement", + number: 4, + author: "admin", + date: new Date(), + view: 321, + pinned: true, + href: "#", + contentTxt: "중요한 발표가 있습니다. 확인해 주세요.", + }, + ]; + + const filteredItems = filterItems({ items, queryParams, categoryIdParams }); + const sortedItems = arrangeItems(filteredItems); + return sortedItems; +} + +interface IFilterItems { + items: INoticeAllItem[]; + queryParams: string | null; + categoryIdParams: string | null; +} + +function filterItems({ items, queryParams, categoryIdParams }: IFilterItems) { + if (!queryParams || !categoryIdParams) { + return items; + } + const categoryId = Number(categoryIdParams); + + return items.filter((item) => { + const titleLower = item.title.toLowerCase(); + const contentLower = item.contentTxt.toLowerCase(); + const queryLower = queryParams.toLowerCase(); + switch (categoryId) { + case 0: + return titleLower.includes(queryLower) || contentLower.includes(queryLower); + case 1: + return titleLower.includes(queryLower); + case 2: + return contentLower.includes(queryLower); + default: + return false; + } + }); +} + +function arrangeItems(items: INoticeAllItem[]) { + const pinnedItems = items.filter((item) => item.pinned); + const unpinnedItems = items.filter((item) => !item.pinned); + + pinnedItems.sort((a, b) => +b.date - +a.date); + unpinnedItems.sort((a, b) => +b.date - +a.date); + + return [...pinnedItems, ...unpinnedItems]; +} diff --git a/src/app/(user)/infodesk/notices/page.tsx b/src/app/(user)/infodesk/notices/page.tsx index 240ff5f6..472a25d6 100644 --- a/src/app/(user)/infodesk/notices/page.tsx +++ b/src/app/(user)/infodesk/notices/page.tsx @@ -1,3 +1,103 @@ +"use client"; + +import { Noticeboard } from "@/components/common/Noticeboard"; +import { SubHeadNavbar } from "@/components/common/SubHeadNavbar"; +import { MantineSelectData } from "@/types/MantineTypes"; +import { usePathname, useRouter, useSearchParams } from "next/navigation"; +import { ChangeEvent, FormEvent, KeyboardEvent, MouseEvent, useState } from "react"; +import { getUserNoticeItems } from "./getUserNoticeItems"; +import styles from "./styles.module.css"; +import { INoticeClassifier } from "@/types/PageBoardTypes"; + export default function NoticesPage() { - return
        Hello, world!
        ; + const pathname = usePathname(); + const params = useSearchParams(); + + const [inputValue, setInputValue] = useState(""); + const [selectValue, setSelectValue] = useState("0"); + const router = useRouter(); + + // Event Handlers + // Handles input changes and clear actions + const handleInput = (e: MouseEvent | ChangeEvent, payload?: unknown) => { + if (e.type === "change") { + const target = e.target as HTMLInputElement; + setInputValue(() => target.value); + } else if (payload) { + if (payload === "CLEAR") { + setInputValue(() => ""); + } + } + }; + + // Handles select value changes + const handleSelect = (value: string | null) => { + setSelectValue(() => value!); + }; + + // Handles "Enter" key press for search + const handleKeyDown = (e: KeyboardEvent) => { + if (e.code === "Enter") onSearch(); + }; + + // Handles form submission + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + onSearch(); + }; + + // Utility Functions + // Performs the search operation + const onSearch = () => { + if (inputValue) { + const queryParams = new URLSearchParams({ + query: inputValue, + categoryId: selectValue, + }); + const url = `${pathname}?${queryParams}`; + router.push(url); + } + }; + + const userNoticeData: MantineSelectData = [ + { + value: "0", + label: "전체", + }, + { + value: "1", + label: "제목", + }, + { + value: "2", + label: "내용", + }, + ]; + + const userNoticeClassifier: INoticeClassifier = { + data: userNoticeData, + defaultLabel: 0, + searchPlaceholder: "검색어를 입력하세요.", + }; + + return ( + <> + +
        + +
        + + ); } diff --git a/src/app/(user)/infodesk/notices/styles.module.css b/src/app/(user)/infodesk/notices/styles.module.css new file mode 100644 index 00000000..ebd27cb1 --- /dev/null +++ b/src/app/(user)/infodesk/notices/styles.module.css @@ -0,0 +1,22 @@ +.container { + margin: 0 auto; + padding-top: 100px; + padding-bottom: 40px; + width: 1024px; +} + +@media screen and (max-width: 480px) { + /** 모바일 세로 */ +} + +@media screen and (max-width: 768px) { + /** 모바일 가로, 태블릿 세로 */ +} + +@media screen and (max-width: 1024px) { + /** 태블릿 가로 */ +} + +@media screen and (max-width: 1280px) { + /** 태블릿 가로, 노트북 */ +} From 2525b4cef187091a11643ada5e97c8c80c71fefb Mon Sep 17 00:00:00 2001 From: chunzhi23 <05.huanx10ng@gmail.com> Date: Wed, 14 Aug 2024 16:45:27 +0900 Subject: [PATCH 07/14] [FEAT] #44 wrap NoticesPage Suspense --- .../(user)/infodesk/notices/NoticesPage.tsx | 103 +++++++++++++++++ src/app/(user)/infodesk/notices/page.tsx | 105 +----------------- 2 files changed, 109 insertions(+), 99 deletions(-) create mode 100644 src/app/(user)/infodesk/notices/NoticesPage.tsx diff --git a/src/app/(user)/infodesk/notices/NoticesPage.tsx b/src/app/(user)/infodesk/notices/NoticesPage.tsx new file mode 100644 index 00000000..472a25d6 --- /dev/null +++ b/src/app/(user)/infodesk/notices/NoticesPage.tsx @@ -0,0 +1,103 @@ +"use client"; + +import { Noticeboard } from "@/components/common/Noticeboard"; +import { SubHeadNavbar } from "@/components/common/SubHeadNavbar"; +import { MantineSelectData } from "@/types/MantineTypes"; +import { usePathname, useRouter, useSearchParams } from "next/navigation"; +import { ChangeEvent, FormEvent, KeyboardEvent, MouseEvent, useState } from "react"; +import { getUserNoticeItems } from "./getUserNoticeItems"; +import styles from "./styles.module.css"; +import { INoticeClassifier } from "@/types/PageBoardTypes"; + +export default function NoticesPage() { + const pathname = usePathname(); + const params = useSearchParams(); + + const [inputValue, setInputValue] = useState(""); + const [selectValue, setSelectValue] = useState("0"); + const router = useRouter(); + + // Event Handlers + // Handles input changes and clear actions + const handleInput = (e: MouseEvent | ChangeEvent, payload?: unknown) => { + if (e.type === "change") { + const target = e.target as HTMLInputElement; + setInputValue(() => target.value); + } else if (payload) { + if (payload === "CLEAR") { + setInputValue(() => ""); + } + } + }; + + // Handles select value changes + const handleSelect = (value: string | null) => { + setSelectValue(() => value!); + }; + + // Handles "Enter" key press for search + const handleKeyDown = (e: KeyboardEvent) => { + if (e.code === "Enter") onSearch(); + }; + + // Handles form submission + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + onSearch(); + }; + + // Utility Functions + // Performs the search operation + const onSearch = () => { + if (inputValue) { + const queryParams = new URLSearchParams({ + query: inputValue, + categoryId: selectValue, + }); + const url = `${pathname}?${queryParams}`; + router.push(url); + } + }; + + const userNoticeData: MantineSelectData = [ + { + value: "0", + label: "전체", + }, + { + value: "1", + label: "제목", + }, + { + value: "2", + label: "내용", + }, + ]; + + const userNoticeClassifier: INoticeClassifier = { + data: userNoticeData, + defaultLabel: 0, + searchPlaceholder: "검색어를 입력하세요.", + }; + + return ( + <> + +
        + +
        + + ); +} diff --git a/src/app/(user)/infodesk/notices/page.tsx b/src/app/(user)/infodesk/notices/page.tsx index 472a25d6..9672fc03 100644 --- a/src/app/(user)/infodesk/notices/page.tsx +++ b/src/app/(user)/infodesk/notices/page.tsx @@ -1,103 +1,10 @@ -"use client"; - -import { Noticeboard } from "@/components/common/Noticeboard"; -import { SubHeadNavbar } from "@/components/common/SubHeadNavbar"; -import { MantineSelectData } from "@/types/MantineTypes"; -import { usePathname, useRouter, useSearchParams } from "next/navigation"; -import { ChangeEvent, FormEvent, KeyboardEvent, MouseEvent, useState } from "react"; -import { getUserNoticeItems } from "./getUserNoticeItems"; -import styles from "./styles.module.css"; -import { INoticeClassifier } from "@/types/PageBoardTypes"; - -export default function NoticesPage() { - const pathname = usePathname(); - const params = useSearchParams(); - - const [inputValue, setInputValue] = useState(""); - const [selectValue, setSelectValue] = useState("0"); - const router = useRouter(); - - // Event Handlers - // Handles input changes and clear actions - const handleInput = (e: MouseEvent | ChangeEvent, payload?: unknown) => { - if (e.type === "change") { - const target = e.target as HTMLInputElement; - setInputValue(() => target.value); - } else if (payload) { - if (payload === "CLEAR") { - setInputValue(() => ""); - } - } - }; - - // Handles select value changes - const handleSelect = (value: string | null) => { - setSelectValue(() => value!); - }; - - // Handles "Enter" key press for search - const handleKeyDown = (e: KeyboardEvent) => { - if (e.code === "Enter") onSearch(); - }; - - // Handles form submission - const handleSubmit = (e: FormEvent) => { - e.preventDefault(); - onSearch(); - }; - - // Utility Functions - // Performs the search operation - const onSearch = () => { - if (inputValue) { - const queryParams = new URLSearchParams({ - query: inputValue, - categoryId: selectValue, - }); - const url = `${pathname}?${queryParams}`; - router.push(url); - } - }; - - const userNoticeData: MantineSelectData = [ - { - value: "0", - label: "전체", - }, - { - value: "1", - label: "제목", - }, - { - value: "2", - label: "내용", - }, - ]; - - const userNoticeClassifier: INoticeClassifier = { - data: userNoticeData, - defaultLabel: 0, - searchPlaceholder: "검색어를 입력하세요.", - }; +import { Suspense } from "react"; +import NoticesPage from "./NoticesPage"; +export default function Page() { return ( - <> - -
        - -
        - + Wait...}> + + ); } From 358f031c30d6457ad00bacfaf15d4f0f4b04f4bd Mon Sep 17 00:00:00 2001 From: chunzhi23 <05.huanx10ng@gmail.com> Date: Thu, 15 Aug 2024 10:10:38 +0900 Subject: [PATCH 08/14] =?UTF-8?q?[FEAT]=20#44=20=EA=B3=B5=EC=A7=80?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EC=84=B8=EB=B6=80=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notices/[id]/GetUserNoticeDetail.tsx | 29 +++++++++++++++++++ src/app/(user)/infodesk/notices/[id]/page.tsx | 23 ++++++++++++++- .../infodesk/notices/[id]/styles.module.css | 22 ++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/app/(user)/infodesk/notices/[id]/GetUserNoticeDetail.tsx create mode 100644 src/app/(user)/infodesk/notices/[id]/styles.module.css diff --git a/src/app/(user)/infodesk/notices/[id]/GetUserNoticeDetail.tsx b/src/app/(user)/infodesk/notices/[id]/GetUserNoticeDetail.tsx new file mode 100644 index 00000000..9b6f52aa --- /dev/null +++ b/src/app/(user)/infodesk/notices/[id]/GetUserNoticeDetail.tsx @@ -0,0 +1,29 @@ +type DynamicSegmentType = string | null; + +export function getUserNoticeDetail(id: DynamicSegmentType) { + console.log(id); + const item = { + title: "Title", + author: "admin", + created_date: new Date(), + edited_date: new Date(), + attachment: [ + { + name: "File 1", + url: "/#", + }, + { + name: "File 2", + url: "/#", + }, + ], + pinned: true, + prev_page: undefined, + next_page: { + title: "Next", + url: "/2", + }, + children:

        Content

        , + }; + return item; +} diff --git a/src/app/(user)/infodesk/notices/[id]/page.tsx b/src/app/(user)/infodesk/notices/[id]/page.tsx index 63a33459..8dd4d299 100644 --- a/src/app/(user)/infodesk/notices/[id]/page.tsx +++ b/src/app/(user)/infodesk/notices/[id]/page.tsx @@ -1,3 +1,24 @@ +"use client"; + +import { SubHeadNavbar } from "@/components/common/SubHeadNavbar"; +import styles from "./styles.module.css"; +import { NoticeDetail } from "@/components/common/NoticeDetail"; +import { getUserNoticeDetail } from "./GetUserNoticeDetail"; +import { useSelectedLayoutSegment } from "next/navigation"; + export default function NoticeDetailPage() { - return
        Hello, world!
        ; + const segment = useSelectedLayoutSegment(); + + const { children, ...othersDetailProps } = getUserNoticeDetail(segment); + + return ( + <> + +
        + + {children} + +
        + + ); } diff --git a/src/app/(user)/infodesk/notices/[id]/styles.module.css b/src/app/(user)/infodesk/notices/[id]/styles.module.css new file mode 100644 index 00000000..ebd27cb1 --- /dev/null +++ b/src/app/(user)/infodesk/notices/[id]/styles.module.css @@ -0,0 +1,22 @@ +.container { + margin: 0 auto; + padding-top: 100px; + padding-bottom: 40px; + width: 1024px; +} + +@media screen and (max-width: 480px) { + /** 모바일 세로 */ +} + +@media screen and (max-width: 768px) { + /** 모바일 가로, 태블릿 세로 */ +} + +@media screen and (max-width: 1024px) { + /** 태블릿 가로 */ +} + +@media screen and (max-width: 1280px) { + /** 태블릿 가로, 노트북 */ +} From 4482b4676b997a17f86ebe79bf44580a14bf546d Mon Sep 17 00:00:00 2001 From: chunzhi23 <05.huanx10ng@gmail.com> Date: Fri, 16 Aug 2024 12:45:31 +0900 Subject: [PATCH 09/14] NoticeDetail types modularization --- .../common/NoticeDetail/NoticeDetail.tsx | 20 +++++------ .../elements/FileDropdownMenu.tsx | 6 ++-- .../elements/NoticeDetailHead.tsx | 13 ++----- .../elements/NoticeDetailSprint.tsx | 15 ++------ .../elements/NoticeDetailStage.tsx | 16 ++------- .../elements/NoticeDetailToolbar.tsx | 2 +- src/types/PageBoardTypes.ts | 35 ++++++++++++++++++- 7 files changed, 55 insertions(+), 52 deletions(-) diff --git a/src/components/common/NoticeDetail/NoticeDetail.tsx b/src/components/common/NoticeDetail/NoticeDetail.tsx index 3d4bdeec..7264a143 100644 --- a/src/components/common/NoticeDetail/NoticeDetail.tsx +++ b/src/components/common/NoticeDetail/NoticeDetail.tsx @@ -1,17 +1,13 @@ -import styles from "./NoticeDetail.module.css"; -import { IDetailHeadProps, NoticeDetailHead } from "./elements/NoticeDetailHead"; -import { IDetailStageProps, NoticeDetailStage } from "./elements/NoticeDetailStage"; -import { IDetailSprintProps, NoticeDetailSprint } from "./elements/NoticeDetailSprint"; +import { INoticeDetailItem } from "@/types/PageBoardTypes"; +import { NoticeDetailHead } from "./elements/NoticeDetailHead"; +import { NoticeDetailSprint } from "./elements/NoticeDetailSprint"; +import { NoticeDetailStage } from "./elements/NoticeDetailStage"; import { NoticeDetailToolbar } from "./elements/NoticeDetailToolbar"; +import styles from "./NoticeDetail.module.css"; -interface IDetailHeadingProps { +type NoticeDetailProps = INoticeDetailItem & { heading: string; -} - -type NoticeDetailPropsType = IDetailHeadingProps & - IDetailHeadProps & - IDetailStageProps & - IDetailSprintProps; +}; export function NoticeDetail({ heading, @@ -24,7 +20,7 @@ export function NoticeDetail({ prev_page, next_page, children, -}: NoticeDetailPropsType) { +}: NoticeDetailProps) { return ( <>
        diff --git a/src/components/common/NoticeDetail/elements/FileDropdownMenu.tsx b/src/components/common/NoticeDetail/elements/FileDropdownMenu.tsx index fa36cbc3..4fd831d1 100644 --- a/src/components/common/NoticeDetail/elements/FileDropdownMenu.tsx +++ b/src/components/common/NoticeDetail/elements/FileDropdownMenu.tsx @@ -1,9 +1,9 @@ -import styles from "../NoticeDetail.module.css"; +import { IBoardAttachment } from "@/types/PageBoardTypes"; import { Menu, Button, Group } from "@mantine/core"; import { IconPaperclip, IconDownload } from "@tabler/icons-react"; -import { IFileInfo } from "./NoticeDetailStage"; +import styles from "../NoticeDetail.module.css"; -export function FileDropdownMenu({ attachment }: { attachment?: IFileInfo[] }) { +export function FileDropdownMenu({ attachment }: { attachment?: IBoardAttachment[] }) { return ( diff --git a/src/components/common/NoticeDetail/elements/NoticeDetailHead.tsx b/src/components/common/NoticeDetail/elements/NoticeDetailHead.tsx index e1c5402b..fe0a1e9c 100644 --- a/src/components/common/NoticeDetail/elements/NoticeDetailHead.tsx +++ b/src/components/common/NoticeDetail/elements/NoticeDetailHead.tsx @@ -1,14 +1,7 @@ +import { INoticeDetailHead } from "@/types/PageBoardTypes"; import { Group } from "@mantine/core"; -import styles from "../NoticeDetail.module.css"; import { IconPinFilled } from "@tabler/icons-react"; - -export interface IDetailHeadProps { - title: string; - author: string; - created_date: Date; - edited_date: Date; - pinned: boolean; -} +import styles from "../NoticeDetail.module.css"; export function NoticeDetailHead({ title, @@ -16,7 +9,7 @@ export function NoticeDetailHead({ created_date, edited_date, pinned, -}: IDetailHeadProps) { +}: INoticeDetailHead) { const CreatedDate = formatDate(created_date); const EditedDate = formatDate(edited_date); diff --git a/src/components/common/NoticeDetail/elements/NoticeDetailSprint.tsx b/src/components/common/NoticeDetail/elements/NoticeDetailSprint.tsx index a0cc98f1..b86a1f43 100644 --- a/src/components/common/NoticeDetail/elements/NoticeDetailSprint.tsx +++ b/src/components/common/NoticeDetail/elements/NoticeDetailSprint.tsx @@ -1,19 +1,10 @@ -import styles from "../NoticeDetail.module.css"; +import { INoticeDetailNav } from "@/types/PageBoardTypes"; import { Group } from "@mantine/core"; import { IconChevronUp, IconChevronDown } from "@tabler/icons-react"; import Link from "next/link"; +import styles from "../NoticeDetail.module.css"; -export interface IPageInfo { - title: string; - url: string; -} - -export interface IDetailSprintProps { - prev_page?: IPageInfo; - next_page?: IPageInfo; -} - -export function NoticeDetailSprint({ prev_page, next_page }: IDetailSprintProps) { +export function NoticeDetailSprint({ prev_page, next_page }: INoticeDetailNav) { return (
        diff --git a/src/components/common/NoticeDetail/elements/NoticeDetailStage.tsx b/src/components/common/NoticeDetail/elements/NoticeDetailStage.tsx index d2866b02..8d52b2b1 100644 --- a/src/components/common/NoticeDetail/elements/NoticeDetailStage.tsx +++ b/src/components/common/NoticeDetail/elements/NoticeDetailStage.tsx @@ -1,20 +1,10 @@ -import styles from "../NoticeDetail.module.css"; +import { INoticeDetailStage } from "@/types/PageBoardTypes"; import { Group, Input, Button, Divider } from "@mantine/core"; import { IconPlus, IconMinus, IconShare, IconPrinter } from "@tabler/icons-react"; -import { ReactNode } from "react"; +import styles from "../NoticeDetail.module.css"; import { FileDropdownMenu } from "./FileDropdownMenu"; -export interface IFileInfo { - name: string; - url: string; -} - -export interface IDetailStageProps { - attachment?: IFileInfo[]; - children?: ReactNode; -} - -export function NoticeDetailStage({ attachment, children }: IDetailStageProps) { +export function NoticeDetailStage({ attachment, children }: INoticeDetailStage) { return (
        diff --git a/src/components/common/NoticeDetail/elements/NoticeDetailToolbar.tsx b/src/components/common/NoticeDetail/elements/NoticeDetailToolbar.tsx index 8492608c..6f4433cf 100644 --- a/src/components/common/NoticeDetail/elements/NoticeDetailToolbar.tsx +++ b/src/components/common/NoticeDetail/elements/NoticeDetailToolbar.tsx @@ -1,6 +1,6 @@ -import styles from "../NoticeDetail.module.css"; import { Group, Button } from "@mantine/core"; import { IconMenu2, IconPencil, IconTrash } from "@tabler/icons-react"; +import styles from "../NoticeDetail.module.css"; export function NoticeDetailToolbar() { return ( diff --git a/src/types/PageBoardTypes.ts b/src/types/PageBoardTypes.ts index 600f8d1b..4ba11b7c 100644 --- a/src/types/PageBoardTypes.ts +++ b/src/types/PageBoardTypes.ts @@ -1,6 +1,7 @@ import { ComboboxItem } from "@mantine/core"; -import { ChangeEvent, KeyboardEvent, MouseEvent } from "react"; +import { ChangeEvent, KeyboardEvent, MouseEvent, ReactNode } from "react"; +/** Noticeboard Types */ interface INoticeClassifierItem { value: string; label: string; @@ -40,6 +41,38 @@ export interface INoticeHandler { handleSubmit: (event: MouseEvent, payload?: unknown) => void; } +/** Noticeboard Detail Types */ +export interface IBoardAttachment { + name: string; + url: string; +} + +interface INavigationPage { + title: string; + url: string; +} + +export type INoticeDetailItem = INoticeDetailHead & INoticeDetailStage & INoticeDetailNav; + +export interface INoticeDetailHead { + title: string; + author: string; + created_date: Date; + edited_date: Date; + pinned: boolean; +} + +export interface INoticeDetailStage { + attachment?: IBoardAttachment[]; + children?: ReactNode; +} + +export interface INoticeDetailNav { + prev_page?: INavigationPage; + next_page?: INavigationPage; +} + +/** Board Pagination Types */ type justifyAlign = "start" | "center" | "end"; export interface IBoardPagin { From c32011810a848a7939b41063bb82ce85fe1e11ba Mon Sep 17 00:00:00 2001 From: chunzhi23 <05.huanx10ng@gmail.com> Date: Fri, 16 Aug 2024 15:07:19 +0900 Subject: [PATCH 10/14] =?UTF-8?q?[FEAT]=20Board=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20n=20?= =?UTF-8?q?=EC=8A=A4=ED=83=80=EC=9D=BC=EC=8B=9C=ED=8A=B8=20=EB=AA=A8?= =?UTF-8?q?=EB=93=88=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notices/[id]/GetUserNoticeDetail.tsx | 2 +- src/app/(user)/infodesk/notices/[id]/page.tsx | 4 +- src/app/(user)/infodesk/notices/page.tsx | 71 +++++++++++++++++-- .../(user)/infodesk/notices/styles.module.css | 22 ------ .../pages/UserBoard/UserBoard.story.tsx | 68 ++++++++++++++++++ .../pages/UserBoard/UserBoard.tsx} | 60 ++++++++-------- src/components/pages/UserBoard/index.ts | 1 + .../UserBoard.module.css} | 0 .../UserBoard/GetUserBoardItems.ts} | 56 ++++----------- 9 files changed, 178 insertions(+), 106 deletions(-) delete mode 100644 src/app/(user)/infodesk/notices/styles.module.css create mode 100644 src/components/pages/UserBoard/UserBoard.story.tsx rename src/{app/(user)/infodesk/notices/NoticesPage.tsx => components/pages/UserBoard/UserBoard.tsx} (58%) create mode 100644 src/components/pages/UserBoard/index.ts rename src/{app/(user)/infodesk/notices/[id]/styles.module.css => styles/UserBoard.module.css} (100%) rename src/{app/(user)/infodesk/notices/getUserNoticeItems.tsx => utils/UserBoard/GetUserBoardItems.ts} (54%) diff --git a/src/app/(user)/infodesk/notices/[id]/GetUserNoticeDetail.tsx b/src/app/(user)/infodesk/notices/[id]/GetUserNoticeDetail.tsx index 9b6f52aa..a649a170 100644 --- a/src/app/(user)/infodesk/notices/[id]/GetUserNoticeDetail.tsx +++ b/src/app/(user)/infodesk/notices/[id]/GetUserNoticeDetail.tsx @@ -23,7 +23,7 @@ export function getUserNoticeDetail(id: DynamicSegmentType) { title: "Next", url: "/2", }, - children:

        Content

        , + children: "Content", }; return item; } diff --git a/src/app/(user)/infodesk/notices/[id]/page.tsx b/src/app/(user)/infodesk/notices/[id]/page.tsx index 8dd4d299..3efc753b 100644 --- a/src/app/(user)/infodesk/notices/[id]/page.tsx +++ b/src/app/(user)/infodesk/notices/[id]/page.tsx @@ -1,7 +1,7 @@ "use client"; import { SubHeadNavbar } from "@/components/common/SubHeadNavbar"; -import styles from "./styles.module.css"; +import styles from "@/styles/UserBoard.module.css"; import { NoticeDetail } from "@/components/common/NoticeDetail"; import { getUserNoticeDetail } from "./GetUserNoticeDetail"; import { useSelectedLayoutSegment } from "next/navigation"; @@ -16,7 +16,7 @@ export default function NoticeDetailPage() {
        - {children} +
        {children}
        diff --git a/src/app/(user)/infodesk/notices/page.tsx b/src/app/(user)/infodesk/notices/page.tsx index 9672fc03..a0114d81 100644 --- a/src/app/(user)/infodesk/notices/page.tsx +++ b/src/app/(user)/infodesk/notices/page.tsx @@ -1,10 +1,69 @@ -import { Suspense } from "react"; -import NoticesPage from "./NoticesPage"; +"use client"; + +import { UserBoard } from "@/components/pages/UserBoard"; +import { useSearchParams } from "next/navigation"; +import { SubHeadNavbar } from "@/components/common/SubHeadNavbar"; +import styles from "@/styles/UserBoard.module.css"; +import { getUserBoardItems } from "@/utils/UserBoard/GetUserBoardItems"; + +export default function NoticesPage() { + const params = useSearchParams(); + + const items = [ + { + title: "Important Notice", + number: 1, + author: "admin", + date: new Date(), + view: 123, + pinned: true, + href: "#", + contentTxt: "안녕하세요 이건 아주 중요한 공지입니다. 꼭 확인해주세요.", + }, + { + title: "Content Update", + number: 2, + author: "admin", + date: new Date(), + view: 456, + pinned: false, + href: "#", + contentTxt: "우리 동아리는 SCG. 중요한 업데이트가 있습니다.", + }, + { + title: "Reminder", + number: 3, + author: "admin", + date: new Date(), + view: 789, + pinned: false, + href: "#", + contentTxt: "이 공지사항을 꼭 확인해 주세요.", + }, + { + title: "Important Announcement", + number: 4, + author: "admin", + date: new Date(), + view: 321, + pinned: true, + href: "#", + contentTxt: "중요한 발표가 있습니다. 확인해 주세요.", + }, + ]; -export default function Page() { return ( - Wait...}> - - + <> + +
        + +
        + ); } diff --git a/src/app/(user)/infodesk/notices/styles.module.css b/src/app/(user)/infodesk/notices/styles.module.css deleted file mode 100644 index ebd27cb1..00000000 --- a/src/app/(user)/infodesk/notices/styles.module.css +++ /dev/null @@ -1,22 +0,0 @@ -.container { - margin: 0 auto; - padding-top: 100px; - padding-bottom: 40px; - width: 1024px; -} - -@media screen and (max-width: 480px) { - /** 모바일 세로 */ -} - -@media screen and (max-width: 768px) { - /** 모바일 가로, 태블릿 세로 */ -} - -@media screen and (max-width: 1024px) { - /** 태블릿 가로 */ -} - -@media screen and (max-width: 1280px) { - /** 태블릿 가로, 노트북 */ -} diff --git a/src/components/pages/UserBoard/UserBoard.story.tsx b/src/components/pages/UserBoard/UserBoard.story.tsx new file mode 100644 index 00000000..dd011dea --- /dev/null +++ b/src/components/pages/UserBoard/UserBoard.story.tsx @@ -0,0 +1,68 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { UserBoard } from "./UserBoard"; + +const meta = { + title: "User Board", + component: UserBoard, + parameters: { layout: "centered" }, + tags: ["autodocs"], + argTypes: {}, + args: {}, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +const items = [ + { + title: "Important Notice", + number: 1, + author: "admin", + date: new Date(), + view: 123, + pinned: true, + href: "#", + contentTxt: "안녕하세요 이건 아주 중요한 공지입니다. 꼭 확인해주세요.", + }, + { + title: "Content Update", + number: 2, + author: "admin", + date: new Date(), + view: 456, + pinned: false, + href: "#", + contentTxt: "우리 동아리는 SCG. 중요한 업데이트가 있습니다.", + }, + { + title: "Reminder", + number: 3, + author: "admin", + date: new Date(), + view: 789, + pinned: false, + href: "#", + contentTxt: "이 공지사항을 꼭 확인해 주세요.", + }, + { + title: "Important Announcement", + number: 4, + author: "admin", + date: new Date(), + view: 321, + pinned: true, + href: "#", + contentTxt: "중요한 발표가 있습니다. 확인해 주세요.", + }, +]; + +export const Usage: Story = { + args: { + heading: "Info Desk", + items, + paginShow: 20, + paginJustify: "end", + paginMarginTop: "20px", + }, +}; diff --git a/src/app/(user)/infodesk/notices/NoticesPage.tsx b/src/components/pages/UserBoard/UserBoard.tsx similarity index 58% rename from src/app/(user)/infodesk/notices/NoticesPage.tsx rename to src/components/pages/UserBoard/UserBoard.tsx index 472a25d6..1b5a834b 100644 --- a/src/app/(user)/infodesk/notices/NoticesPage.tsx +++ b/src/components/pages/UserBoard/UserBoard.tsx @@ -1,17 +1,16 @@ -"use client"; - import { Noticeboard } from "@/components/common/Noticeboard"; -import { SubHeadNavbar } from "@/components/common/SubHeadNavbar"; import { MantineSelectData } from "@/types/MantineTypes"; -import { usePathname, useRouter, useSearchParams } from "next/navigation"; -import { ChangeEvent, FormEvent, KeyboardEvent, MouseEvent, useState } from "react"; -import { getUserNoticeItems } from "./getUserNoticeItems"; -import styles from "./styles.module.css"; -import { INoticeClassifier } from "@/types/PageBoardTypes"; +import { IBoardPagin, INoticeAllItem, INoticeClassifier } from "@/types/PageBoardTypes"; +import { usePathname, useRouter } from "next/navigation"; +import { useState, ChangeEvent, FormEvent, MouseEvent, KeyboardEvent } from "react"; + +type UserBoardProps = { + heading: string; + items: INoticeAllItem[]; +} & IBoardPagin; -export default function NoticesPage() { +export function UserBoard({ heading, items }: UserBoardProps) { const pathname = usePathname(); - const params = useSearchParams(); const [inputValue, setInputValue] = useState(""); const [selectValue, setSelectValue] = useState("0"); @@ -59,7 +58,7 @@ export default function NoticesPage() { } }; - const userNoticeData: MantineSelectData = [ + const data: MantineSelectData = [ { value: "0", label: "전체", @@ -72,32 +71,31 @@ export default function NoticesPage() { value: "2", label: "내용", }, + { + value: "3", + label: "작성자", + }, ]; - const userNoticeClassifier: INoticeClassifier = { - data: userNoticeData, + const classifier: INoticeClassifier = { + data, defaultLabel: 0, searchPlaceholder: "검색어를 입력하세요.", }; return ( - <> - -
        - -
        - + ); } diff --git a/src/components/pages/UserBoard/index.ts b/src/components/pages/UserBoard/index.ts new file mode 100644 index 00000000..7446c38b --- /dev/null +++ b/src/components/pages/UserBoard/index.ts @@ -0,0 +1 @@ +export { UserBoard } from "./UserBoard"; diff --git a/src/app/(user)/infodesk/notices/[id]/styles.module.css b/src/styles/UserBoard.module.css similarity index 100% rename from src/app/(user)/infodesk/notices/[id]/styles.module.css rename to src/styles/UserBoard.module.css diff --git a/src/app/(user)/infodesk/notices/getUserNoticeItems.tsx b/src/utils/UserBoard/GetUserBoardItems.ts similarity index 54% rename from src/app/(user)/infodesk/notices/getUserNoticeItems.tsx rename to src/utils/UserBoard/GetUserBoardItems.ts index 73f4f37a..9a2036aa 100644 --- a/src/app/(user)/infodesk/notices/getUserNoticeItems.tsx +++ b/src/utils/UserBoard/GetUserBoardItems.ts @@ -1,52 +1,12 @@ import { INoticeAllItem } from "@/types/PageBoardTypes"; import { ReadonlyURLSearchParams } from "next/navigation"; -export function getUserNoticeItems(params: ReadonlyURLSearchParams) { +export function getUserBoardItems(api: string | INoticeAllItem[], params: ReadonlyURLSearchParams) { const queryParams = params.get("query"); const categoryIdParams = params.get("categoryId"); - const items = [ - { - title: "Important Notice", - number: 1, - author: "admin", - date: new Date(), - view: 123, - pinned: true, - href: "#", - contentTxt: "안녕하세요 이건 아주 중요한 공지입니다. 꼭 확인해주세요.", - }, - { - title: "Content Update", - number: 2, - author: "admin", - date: new Date(), - view: 456, - pinned: false, - href: "#", - contentTxt: "우리 동아리는 SCG. 중요한 업데이트가 있습니다.", - }, - { - title: "Reminder", - number: 3, - author: "admin", - date: new Date(), - view: 789, - pinned: false, - href: "#", - contentTxt: "이 공지사항을 꼭 확인해 주세요.", - }, - { - title: "Important Announcement", - number: 4, - author: "admin", - date: new Date(), - view: 321, - pinned: true, - href: "#", - contentTxt: "중요한 발표가 있습니다. 확인해 주세요.", - }, - ]; + // api 연결 후 수정 필요 + const items = api as INoticeAllItem[]; const filteredItems = filterItems({ items, queryParams, categoryIdParams }); const sortedItems = arrangeItems(filteredItems); @@ -68,14 +28,22 @@ function filterItems({ items, queryParams, categoryIdParams }: IFilterItems) { return items.filter((item) => { const titleLower = item.title.toLowerCase(); const contentLower = item.contentTxt.toLowerCase(); + const authorLower = item.author.toLowerCase(); const queryLower = queryParams.toLowerCase(); + switch (categoryId) { case 0: - return titleLower.includes(queryLower) || contentLower.includes(queryLower); + return ( + titleLower.includes(queryLower) || + contentLower.includes(queryLower) || + authorLower.includes(queryLower) + ); case 1: return titleLower.includes(queryLower); case 2: return contentLower.includes(queryLower); + case 3: + return authorLower.includes(queryLower); default: return false; } From a4dd630747daaabaad4306dab351c2544834a654 Mon Sep 17 00:00:00 2001 From: chunzhi23 <05.huanx10ng@gmail.com> Date: Fri, 16 Aug 2024 15:13:43 +0900 Subject: [PATCH 11/14] [FEAT] wrapped with suspense n utils into ts --- .../(user)/infodesk/notices/NoticesPage.tsx | 69 ++++++++++++++++++ ...oticeDetail.tsx => GetUserNoticeDetail.ts} | 0 src/app/(user)/infodesk/notices/page.tsx | 71 ++----------------- 3 files changed, 75 insertions(+), 65 deletions(-) create mode 100644 src/app/(user)/infodesk/notices/NoticesPage.tsx rename src/app/(user)/infodesk/notices/[id]/{GetUserNoticeDetail.tsx => GetUserNoticeDetail.ts} (100%) diff --git a/src/app/(user)/infodesk/notices/NoticesPage.tsx b/src/app/(user)/infodesk/notices/NoticesPage.tsx new file mode 100644 index 00000000..a0114d81 --- /dev/null +++ b/src/app/(user)/infodesk/notices/NoticesPage.tsx @@ -0,0 +1,69 @@ +"use client"; + +import { UserBoard } from "@/components/pages/UserBoard"; +import { useSearchParams } from "next/navigation"; +import { SubHeadNavbar } from "@/components/common/SubHeadNavbar"; +import styles from "@/styles/UserBoard.module.css"; +import { getUserBoardItems } from "@/utils/UserBoard/GetUserBoardItems"; + +export default function NoticesPage() { + const params = useSearchParams(); + + const items = [ + { + title: "Important Notice", + number: 1, + author: "admin", + date: new Date(), + view: 123, + pinned: true, + href: "#", + contentTxt: "안녕하세요 이건 아주 중요한 공지입니다. 꼭 확인해주세요.", + }, + { + title: "Content Update", + number: 2, + author: "admin", + date: new Date(), + view: 456, + pinned: false, + href: "#", + contentTxt: "우리 동아리는 SCG. 중요한 업데이트가 있습니다.", + }, + { + title: "Reminder", + number: 3, + author: "admin", + date: new Date(), + view: 789, + pinned: false, + href: "#", + contentTxt: "이 공지사항을 꼭 확인해 주세요.", + }, + { + title: "Important Announcement", + number: 4, + author: "admin", + date: new Date(), + view: 321, + pinned: true, + href: "#", + contentTxt: "중요한 발표가 있습니다. 확인해 주세요.", + }, + ]; + + return ( + <> + +
        + +
        + + ); +} diff --git a/src/app/(user)/infodesk/notices/[id]/GetUserNoticeDetail.tsx b/src/app/(user)/infodesk/notices/[id]/GetUserNoticeDetail.ts similarity index 100% rename from src/app/(user)/infodesk/notices/[id]/GetUserNoticeDetail.tsx rename to src/app/(user)/infodesk/notices/[id]/GetUserNoticeDetail.ts diff --git a/src/app/(user)/infodesk/notices/page.tsx b/src/app/(user)/infodesk/notices/page.tsx index a0114d81..99183ca9 100644 --- a/src/app/(user)/infodesk/notices/page.tsx +++ b/src/app/(user)/infodesk/notices/page.tsx @@ -1,69 +1,10 @@ -"use client"; - -import { UserBoard } from "@/components/pages/UserBoard"; -import { useSearchParams } from "next/navigation"; -import { SubHeadNavbar } from "@/components/common/SubHeadNavbar"; -import styles from "@/styles/UserBoard.module.css"; -import { getUserBoardItems } from "@/utils/UserBoard/GetUserBoardItems"; - -export default function NoticesPage() { - const params = useSearchParams(); - - const items = [ - { - title: "Important Notice", - number: 1, - author: "admin", - date: new Date(), - view: 123, - pinned: true, - href: "#", - contentTxt: "안녕하세요 이건 아주 중요한 공지입니다. 꼭 확인해주세요.", - }, - { - title: "Content Update", - number: 2, - author: "admin", - date: new Date(), - view: 456, - pinned: false, - href: "#", - contentTxt: "우리 동아리는 SCG. 중요한 업데이트가 있습니다.", - }, - { - title: "Reminder", - number: 3, - author: "admin", - date: new Date(), - view: 789, - pinned: false, - href: "#", - contentTxt: "이 공지사항을 꼭 확인해 주세요.", - }, - { - title: "Important Announcement", - number: 4, - author: "admin", - date: new Date(), - view: 321, - pinned: true, - href: "#", - contentTxt: "중요한 발표가 있습니다. 확인해 주세요.", - }, - ]; +import { Suspense } from "react"; +import NoticesPage from "./NoticesPage"; +export default function NoticesPageSuspense() { return ( - <> - -
        - -
        - + + + ); } From 8b1c09cf664182ffce81bc1a221a09b52a360709 Mon Sep 17 00:00:00 2001 From: chunzhi23 <05.huanx10ng@gmail.com> Date: Fri, 16 Aug 2024 15:15:24 +0900 Subject: [PATCH 12/14] =?UTF-8?q?[FEAT]=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20?= =?UTF-8?q?=EA=B3=B5=EC=A7=80=EC=82=AC=ED=95=AD=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(user)/event/notices/EventNoticesPage.tsx | 69 +++++++++++++++++++ .../event/notices/[id]/GetUserEventDetail.ts | 29 ++++++++ src/app/(user)/event/notices/[id]/page.tsx | 23 ++++++- src/app/(user)/event/notices/page.tsx | 11 ++- 4 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 src/app/(user)/event/notices/EventNoticesPage.tsx create mode 100644 src/app/(user)/event/notices/[id]/GetUserEventDetail.ts diff --git a/src/app/(user)/event/notices/EventNoticesPage.tsx b/src/app/(user)/event/notices/EventNoticesPage.tsx new file mode 100644 index 00000000..fa770973 --- /dev/null +++ b/src/app/(user)/event/notices/EventNoticesPage.tsx @@ -0,0 +1,69 @@ +"use client"; + +import { SubHeadNavbar } from "@/components/common/SubHeadNavbar"; +import { useSearchParams } from "next/navigation"; +import styles from "@/styles/UserBoard.module.css"; +import { UserBoard } from "@/components/pages/UserBoard"; +import { getUserBoardItems } from "@/utils/UserBoard/GetUserBoardItems"; + +export default function EventNoticesPage() { + const params = useSearchParams(); + + const items = [ + { + title: "Important Notice", + number: 1, + author: "admin", + date: new Date(), + view: 123, + pinned: true, + href: "#", + contentTxt: "안녕하세요 이건 아주 중요한 공지입니다. 꼭 확인해주세요.", + }, + { + title: "Content Update", + number: 2, + author: "admin", + date: new Date(), + view: 456, + pinned: false, + href: "#", + contentTxt: "우리 동아리는 SCG. 중요한 업데이트가 있습니다.", + }, + { + title: "Reminder", + number: 3, + author: "admin", + date: new Date(), + view: 789, + pinned: false, + href: "#", + contentTxt: "이 공지사항을 꼭 확인해 주세요.", + }, + { + title: "Important Announcement", + number: 4, + author: "admin", + date: new Date(), + view: 321, + pinned: true, + href: "#", + contentTxt: "중요한 발표가 있습니다. 확인해 주세요.", + }, + ]; + + return ( + <> + +
        + +
        + + ); +} diff --git a/src/app/(user)/event/notices/[id]/GetUserEventDetail.ts b/src/app/(user)/event/notices/[id]/GetUserEventDetail.ts new file mode 100644 index 00000000..2b8db0ac --- /dev/null +++ b/src/app/(user)/event/notices/[id]/GetUserEventDetail.ts @@ -0,0 +1,29 @@ +type DynamicSegmentType = string | null; + +export function getUserEventDetail(id: DynamicSegmentType) { + console.log(id); + const item = { + title: "Title", + author: "admin", + created_date: new Date(), + edited_date: new Date(), + attachment: [ + { + name: "File 1", + url: "/#", + }, + { + name: "File 2", + url: "/#", + }, + ], + pinned: true, + prev_page: undefined, + next_page: { + title: "Next", + url: "/2", + }, + children: "Content", + }; + return item; +} diff --git a/src/app/(user)/event/notices/[id]/page.tsx b/src/app/(user)/event/notices/[id]/page.tsx index ecca6d35..68dc8adc 100644 --- a/src/app/(user)/event/notices/[id]/page.tsx +++ b/src/app/(user)/event/notices/[id]/page.tsx @@ -1,3 +1,24 @@ +"use client"; + +import { NoticeDetail } from "@/components/common/NoticeDetail"; +import { SubHeadNavbar } from "@/components/common/SubHeadNavbar"; +import styles from "@/styles/UserBoard.module.css"; +import { useSelectedLayoutSegment } from "next/navigation"; +import { getUserEventDetail } from "./GetUserEventDetail"; + export default function EventNoticeDetailPage() { - return
        Hello, world!
        ; + const segment = useSelectedLayoutSegment(); + + const { children, ...othersDetailProps } = getUserEventDetail(segment); + + return ( + <> + +
        + +
        {children}
        +
        +
        + + ); } diff --git a/src/app/(user)/event/notices/page.tsx b/src/app/(user)/event/notices/page.tsx index 10cd11a2..40f17018 100644 --- a/src/app/(user)/event/notices/page.tsx +++ b/src/app/(user)/event/notices/page.tsx @@ -1,3 +1,10 @@ -export default function EventNoticesPage() { - return
        Hello, world!
        ; +import { Suspense } from "react"; +import EventNoticesPage from "./EventNoticesPage"; + +export default function EventNoticesPageSuspense() { + return ( + + + + ); } From dc1d2112353454864d13e5592a1781c048675e66 Mon Sep 17 00:00:00 2001 From: chunzhi23 <05.huanx10ng@gmail.com> Date: Sat, 17 Aug 2024 12:20:01 +0900 Subject: [PATCH 13/14] =?UTF-8?q?[FIX]=20UserBoard=20Noticeboard=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=ED=8E=98=EC=9D=B4=EC=A7=80=EB=84=A4=EC=9D=B4?= =?UTF-8?q?=EC=85=98=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/UserBoard/UserBoard.module.css | 9 ++++ src/components/pages/UserBoard/UserBoard.tsx | 49 +++++++++++++------ 2 files changed, 43 insertions(+), 15 deletions(-) create mode 100644 src/components/pages/UserBoard/UserBoard.module.css diff --git a/src/components/pages/UserBoard/UserBoard.module.css b/src/components/pages/UserBoard/UserBoard.module.css new file mode 100644 index 00000000..71aeb95c --- /dev/null +++ b/src/components/pages/UserBoard/UserBoard.module.css @@ -0,0 +1,9 @@ +.container { + border-top: 1px solid var(--mantine-color-text); + + & ul { + margin: 0; + padding: 0; + list-style: none; + } +} diff --git a/src/components/pages/UserBoard/UserBoard.tsx b/src/components/pages/UserBoard/UserBoard.tsx index 1b5a834b..16342a74 100644 --- a/src/components/pages/UserBoard/UserBoard.tsx +++ b/src/components/pages/UserBoard/UserBoard.tsx @@ -1,15 +1,24 @@ -import { Noticeboard } from "@/components/common/Noticeboard"; +import { NoticeItem } from "@/components/common/Noticeboard/elements/NoticeItem"; +import { NoticeHeading } from "@/components/common/Noticeboard/elements/NoticeHeading"; +import { Paginations } from "@/components/common/Pagination"; import { MantineSelectData } from "@/types/MantineTypes"; import { IBoardPagin, INoticeAllItem, INoticeClassifier } from "@/types/PageBoardTypes"; import { usePathname, useRouter } from "next/navigation"; import { useState, ChangeEvent, FormEvent, MouseEvent, KeyboardEvent } from "react"; +import styles from "./UserBoard.module.css"; type UserBoardProps = { heading: string; items: INoticeAllItem[]; } & IBoardPagin; -export function UserBoard({ heading, items }: UserBoardProps) { +export function UserBoard({ + heading, + items, + paginShow, + paginJustify, + paginMarginTop, +}: UserBoardProps) { const pathname = usePathname(); const [inputValue, setInputValue] = useState(""); @@ -84,18 +93,28 @@ export function UserBoard({ heading, items }: UserBoardProps) { }; return ( - + <> + +
        +
          + ( + + ))} + paginShow={paginShow} + paginJustify={paginJustify} + paginMarginTop={paginMarginTop} + /> +
        +
        + ); } From e3b6abea01053adaa0908b25ed0e8335edbe0afe Mon Sep 17 00:00:00 2001 From: chunzhi23 <05.huanx10ng@gmail.com> Date: Sat, 17 Aug 2024 12:52:03 +0900 Subject: [PATCH 14/14] =?UTF-8?q?[FEAT]=20=EC=95=84=EB=9E=98=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EC=84=A0=ED=83=9D=20=EC=B6=94=EA=B0=80=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/Pagination/Pagination.tsx | 6 ++-- .../pages/UserBoard/UserBoard.story.tsx | 30 ++++++++++++++++++- src/components/pages/UserBoard/UserBoard.tsx | 17 +++++++---- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/components/common/Pagination/Pagination.tsx b/src/components/common/Pagination/Pagination.tsx index fab980d5..ca7aeb9c 100644 --- a/src/components/common/Pagination/Pagination.tsx +++ b/src/components/common/Pagination/Pagination.tsx @@ -6,12 +6,12 @@ import { PaginationPrevious, PaginationRoot, } from "@mantine/core"; -import classes from "./Pagination.module.css"; -import { ReactNode, useState } from "react"; import { IBoardPagin } from "@/types/PageBoardTypes"; +import { ReactElement, useState } from "react"; +import classes from "./Pagination.module.css"; type PaginationProps = IBoardPagin & { - data: Array; + data: ReactElement[]; }; export function Paginations({ diff --git a/src/components/pages/UserBoard/UserBoard.story.tsx b/src/components/pages/UserBoard/UserBoard.story.tsx index dd011dea..6f8478e1 100644 --- a/src/components/pages/UserBoard/UserBoard.story.tsx +++ b/src/components/pages/UserBoard/UserBoard.story.tsx @@ -1,8 +1,9 @@ import type { Meta, StoryObj } from "@storybook/react"; import { UserBoard } from "./UserBoard"; +import { Button, Group } from "@mantine/core"; const meta = { - title: "User Board", + title: "page/UserBoard", component: UserBoard, parameters: { layout: "centered" }, tags: ["autodocs"], @@ -57,10 +58,37 @@ const items = [ }, ]; +const bottomSection = ( + + + +); + export const Usage: Story = { + parameters: { + nextjs: { + appDirectory: true, + }, + }, + args: { + heading: "Info Desk", + items, + paginShow: 20, + paginJustify: "end", + paginMarginTop: "20px", + }, +}; + +export const BottomButton: Story = { + parameters: { + nextjs: { + appDirectory: true, + }, + }, args: { heading: "Info Desk", items, + bottomSection, paginShow: 20, paginJustify: "end", paginMarginTop: "20px", diff --git a/src/components/pages/UserBoard/UserBoard.tsx b/src/components/pages/UserBoard/UserBoard.tsx index 16342a74..010005b6 100644 --- a/src/components/pages/UserBoard/UserBoard.tsx +++ b/src/components/pages/UserBoard/UserBoard.tsx @@ -4,17 +4,19 @@ import { Paginations } from "@/components/common/Pagination"; import { MantineSelectData } from "@/types/MantineTypes"; import { IBoardPagin, INoticeAllItem, INoticeClassifier } from "@/types/PageBoardTypes"; import { usePathname, useRouter } from "next/navigation"; -import { useState, ChangeEvent, FormEvent, MouseEvent, KeyboardEvent } from "react"; +import { useState, ChangeEvent, FormEvent, MouseEvent, KeyboardEvent, ReactElement } from "react"; import styles from "./UserBoard.module.css"; type UserBoardProps = { heading: string; items: INoticeAllItem[]; + bottomSection?: ReactElement; } & IBoardPagin; export function UserBoard({ heading, items, + bottomSection, paginShow, paginJustify, paginMarginTop, @@ -67,7 +69,7 @@ export function UserBoard({ } }; - const data: MantineSelectData = [ + const classifierData: MantineSelectData = [ { value: "0", label: "전체", @@ -87,11 +89,16 @@ export function UserBoard({ ]; const classifier: INoticeClassifier = { - data, + data: classifierData, defaultLabel: 0, searchPlaceholder: "검색어를 입력하세요.", }; + const data = items.map((item, key) => ); + if (bottomSection !== undefined) { + data.push(bottomSection); + } + return ( <>
          ( - - ))} + data={data} paginShow={paginShow} paginJustify={paginJustify} paginMarginTop={paginMarginTop}