diff --git a/Layout/LayoutProvider.tsx b/Layout/LayoutProvider.tsx index 6a20df4d7..af257cdcc 100644 --- a/Layout/LayoutProvider.tsx +++ b/Layout/LayoutProvider.tsx @@ -18,7 +18,7 @@ const LayoutProvider = ({ children }: LayoutProviderProps) => { // case "admin" : // return {children}; default: - return <>{children}; + return {children}; } }; diff --git a/components/agenda/Home/AgendaTitle.tsx b/components/agenda/Home/AgendaTitle.tsx index 3f196bd29..09bdc6b9b 100644 --- a/components/agenda/Home/AgendaTitle.tsx +++ b/components/agenda/Home/AgendaTitle.tsx @@ -5,21 +5,37 @@ import styles from 'styles/agenda/Home/AgendaTitle.module.scss'; const AgendaTitle = () => { return (
-
AGENDA
- - - +
AGENDA
+
+ + + + + + +
); }; diff --git a/components/agenda/Ticket/Ticket.tsx b/components/agenda/Ticket/Ticket.tsx new file mode 100644 index 000000000..a55a0cfc7 --- /dev/null +++ b/components/agenda/Ticket/Ticket.tsx @@ -0,0 +1,83 @@ +import Link from 'next/link'; +import { instanceInAgenda } from 'utils/axios'; +import useFetchGet from 'hooks/agenda/useFetchGet'; +import styles from 'styles/agenda/Ticket/Ticket.module.scss'; +interface TicketProps { + ticketCount: number; + setupTicket: boolean; +} + +const Ticket = ({ type }: { type: string }) => { + const { data } = useFetchGet('/ticket'); + return type === 'page' ? ( +
+

내 티켓

+
+
+

{data && data.ticketCount}

+
+

+
+
+

발급 방법

+
+

발급 시작 누르기

+
+

+ 평가 포인트 기부하기 +
+ {`(최대 2개까지 반영)`} +

+
+

현재 페이지로 돌아와 발급완료 누르기

+
+ {data && data.setupTicket ? ( + + ) : ( + + )} + + + +
+ ) : ( +
+

내 티켓

+
+ + + +
+
+

{data && data.ticketCount}

+
+

+
+
+
+ ); +}; + +export default Ticket; diff --git a/components/agenda/Ticket/TicketHistory.tsx b/components/agenda/Ticket/TicketHistory.tsx new file mode 100644 index 000000000..45664803f --- /dev/null +++ b/components/agenda/Ticket/TicketHistory.tsx @@ -0,0 +1,55 @@ +import { + TableCell, + TableRow, + Table, + TableHead, + TableBody, +} from '@mui/material'; +import { TicketHistoryProps } from 'types/aganda/ticketTypes'; +import styles from 'styles/agenda/Ticket/Ticket.module.scss'; + +const TicketHistory = ({ data }: { data: TicketHistoryProps[] | null }) => { + return ( +
+

티켓 발급 내역

+ + + + idx + 발급요청일 + 승인여부 + 승인일 + 사용여부 + 사용처 + + + + {data && + data.map((d, index) => { + return ( + + + {d.idx} + + {d.createdAt} + + {d.approved ? '✔︎' : '✕'} + + {d.approvedAt} + {d.isUsed ? '✔︎' : '✕'} + + {d.usedAt ? d.usedAt : ''} + + + ); + })} + +
+
+ ); +}; + +export default TicketHistory; diff --git a/components/agenda/utils/PageController.tsx b/components/agenda/utils/PageController.tsx new file mode 100644 index 000000000..bceca8f22 --- /dev/null +++ b/components/agenda/utils/PageController.tsx @@ -0,0 +1,114 @@ +import { useEffect, useState } from 'react'; +import { AgendaDataProps } from 'types/agenda/agendaDetail/agendaTypes'; +import { instanceInAgenda } from 'utils/axios'; +import styles from 'styles/agenda/utils/PageController.module.scss'; +import AgendaInfo from '../Home/AgendaInfo'; + +interface PageControllerNavigatorProps { + currentPage: number; + maxPage: number; + onClick: (page: number) => void; +} + +const PageControllerNavigator = ({ + currentPage, + maxPage, + onClick, +}: PageControllerNavigatorProps) => { + const buttons = []; + for (let i = 0; i < maxPage; i++) { + if (i === currentPage) + buttons.push( + + + + + +
+ ); +}; + +export default PageController; diff --git a/hooks/agenda/usePageNation.ts b/hooks/agenda/usePageNation.ts new file mode 100644 index 000000000..b8fea902c --- /dev/null +++ b/hooks/agenda/usePageNation.ts @@ -0,0 +1,58 @@ +import { useEffect, useRef, useState } from 'react'; +import { instanceInAgenda } from 'utils/axios'; + +const usePageNation = ({ + url, + size, + useIdx, +}: { + url: string; + size?: number; // 페이지 사이즈 + useIdx?: boolean; // 인덱싱 추가 여부 : 해당 데이터 타입에 idx?: number; 추가 필요 +}) => { + if (!size) size = 20; + const getData = async (page: number) => { + const res = await instanceInAgenda.get(`${url}?page=${page}&size=${size}`); + res.data.totalSize ? res.data.totalSize : 0; + res.data.content ? res.data.content : []; + if (useIdx) { + res.data.content = res.data.content.map((c: T, idx: number) => { + const temp = c as T & { idx: number }; + temp.idx = idx + 1 + size * (page - 1); + return temp; + }); + } + return res.data as { totalSize: number; content: T[] }; + }; + // const data = getData(0); + const [currentPage, setCurrentPage] = useState(1); + const [content, setContent] = useState(null); + const totalPages = useRef(1); + + const pageChangeHandler = async (pageNumber: number) => { + if (pageNumber < 1 || pageNumber > totalPages.current) return; + await getData(pageNumber).then((res) => { + setCurrentPage(pageNumber); + setContent(res.content); + }); + }; + + useEffect(() => { + const fetchData = async () => { + const data = await getData(currentPage); + totalPages.current = Math.ceil(data.totalSize / size); + setContent(data.content); + }; + fetchData(); + }); + + const PagaNationElementProps = { + curPage: currentPage, + totalPages: totalPages.current, + pageChangeHandler: pageChangeHandler, + }; + + return { content, PagaNationElementProps }; +}; + +export default usePageNation; diff --git a/pages/agenda/profile/[intraId]/index.tsx b/pages/agenda/profile/[intraId]/index.tsx new file mode 100644 index 000000000..f5aaa6abf --- /dev/null +++ b/pages/agenda/profile/[intraId]/index.tsx @@ -0,0 +1,99 @@ +import { AgendaHistoryItemProps } from 'types/agenda/profile/agendaHistoryTypes'; +import { CurrentTeamItemProps } from 'types/agenda/profile/currentTeamTypes'; +import { ProfileDataProps } from 'types/agenda/profile/profileDataTypes'; +import AgendaHistory from 'components/agenda/Profile/AgendaHistory'; +import AgendaUserSearchBar from 'components/agenda/Profile/AgendaUserSearchBar'; +import CurrentTeam from 'components/agenda/Profile/CurrentTeam'; +import ProfileCard from 'components/agenda/Profile/ProfileCard'; +import Ticket from 'components/agenda/Ticket/Ticket'; +import useFetchGet from 'hooks/agenda/useFetchGet'; +import styles from 'styles/agenda/Profile/AgendaProfile.module.scss'; + +//intraid 받아오는 페이지로 세팅 필요 +export default function AgendaProfile() { + const { data: profileData, getData: getProfileData } = + useFetchGet('/profile'); + + const currentTeamData = useFetchGet( + '/profile/current/list' + ).data; + + const agendaHistory = useFetchGet( + '/profile/history/list', + { + page: 1, + size: 20, + } + ).data; + + // currentTeam MOCK DATA + const currentTeamMockData: CurrentTeamItemProps[] = [ + { + agendaId: '123', + agendaTitle: 'PUSH SWAP CONTEST', + agendaLocation: 'SEOUL', + teamKey: 'TEAMKEY1', + isOfficial: true, + teamName: 'jeongrol', + }, + { + agendaId: '1234', + agendaTitle: 'League Of Legend 42', + agendaLocation: 'SEOUL', + teamKey: 'TEAMKEY2', + isOfficial: true, + teamName: '7-8기 멤버단', + }, + ]; + // history MOCK DATA + const historyMockData: AgendaHistoryItemProps[] = [ + { + agendaId: 'agendaId1', + agendaTitle: '아젠다 타이틀1', + agendaStartTime: new Date(), + agendaEndTime: new Date(), + agendaCurrentTeam: 8, + agendaLocation: 'seoul', + teamKey: 'team1', + isOfficial: false, + agendaMaxPeople: 100, + teamName: 'team Name', + teamMates: [ + { + intraId: 'intraId1', + coalition: 'GUN', + }, + { + intraId: 'intraId2', + coalition: 'GON', + }, + { + intraId: 'intraId3', + coalition: 'LEE', + }, + ], + }, + ]; + + return ( + <> +
+
+ +
+ {profileData && ( + + )} + + {currentTeamData && } + {agendaHistory && } +
+ + ); +} diff --git a/pages/agenda/profile/index.tsx b/pages/agenda/profile/index.tsx index 0eeb8119d..522fcf62f 100644 --- a/pages/agenda/profile/index.tsx +++ b/pages/agenda/profile/index.tsx @@ -1,96 +1,10 @@ -import { AgendaHistoryItemProps } from 'types/agenda/profile/agendaHistoryTypes'; -import { CurrentTeamItemProps } from 'types/agenda/profile/currentTeamTypes'; -import { ProfileDataProps } from 'types/agenda/profile/profileDataTypes'; -import AgendaHistory from 'components/agenda/Profile/AgendaHistory'; -import AgendaUserSearchBar from 'components/agenda/Profile/AgendaUserSearchBar'; -import CurrentTeam from 'components/agenda/Profile/CurrentTeam'; -import ProfileCard from 'components/agenda/Profile/ProfileCard'; -import useFetchGet from 'hooks/agenda/useFetchGet'; -import styles from 'styles/agenda/Profile/AgendaProfile.module.scss'; +import { useRouter } from 'next/router'; +import { useUser } from 'hooks/agenda/Layout/useUser'; -export default function AgendaProfile() { - const { data: profileData, getData: getProfileData } = - useFetchGet('/profile'); +const Index = () => { + const router = useRouter(); + const { intraId } = useUser() || {}; + router.push('/agenda/profile/' + intraId); +}; - const currentTeamData = useFetchGet( - '/profile/current/list' - ).data; - - const agendaHistory = useFetchGet( - '/profile/history/list', - { - page: 1, - size: 20, - } - ).data; - - // currentTeam MOCK DATA - const currentTeamMockData: CurrentTeamItemProps[] = [ - { - agendaId: '123', - agendaTitle: 'PUSH SWAP CONTEST', - agendaLocation: 'SEOUL', - teamKey: 'TEAMKEY1', - isOfficial: true, - teamName: 'jeongrol', - }, - { - agendaId: '1234', - agendaTitle: 'League Of Legend 42', - agendaLocation: 'SEOUL', - teamKey: 'TEAMKEY2', - isOfficial: true, - teamName: '7-8기 멤버단', - }, - ]; - // history MOCK DATA - const historyMockData: AgendaHistoryItemProps[] = [ - { - agendaId: 'agendaId1', - agendaTitle: '아젠다 타이틀1', - agendaStartTime: new Date(), - agendaEndTime: new Date(), - agendaCurrentTeam: 8, - agendaLocation: 'seoul', - teamKey: 'team1', - isOfficial: false, - agendaMaxPeople: 100, - teamName: 'team Name', - teamMates: [ - { - intraId: 'intraId1', - coalition: 'GUN', - }, - { - intraId: 'intraId2', - coalition: 'GON', - }, - { - intraId: 'intraId3', - coalition: 'LEE', - }, - ], - }, - ]; - - return ( - <> -
-
- -
- {profileData && ( - - )} - {currentTeamData && } - {agendaHistory && } -
- - ); -} +export default Index; diff --git a/pages/agenda/ticket/history.tsx b/pages/agenda/ticket/history.tsx new file mode 100644 index 000000000..1e32e34ad --- /dev/null +++ b/pages/agenda/ticket/history.tsx @@ -0,0 +1,24 @@ +import { TicketHistoryProps } from 'types/aganda/ticketTypes'; +import TicketHistory from 'components/agenda/Ticket/TicketHistory'; +import PageNation from 'components/Pagination'; +import usePageNation from 'hooks/agenda/usePageNation'; + +const TicketHistoryPage = () => { + const size = 5; + const { PagaNationElementProps, content } = usePageNation( + { + url: '/ticket/history', + size: size, + useIdx: true, + } + ); + + return ( +
+ + +
+ ); +}; + +export default TicketHistoryPage; diff --git a/pages/agenda/ticket/index.tsx b/pages/agenda/ticket/index.tsx new file mode 100644 index 000000000..29e8baf52 --- /dev/null +++ b/pages/agenda/ticket/index.tsx @@ -0,0 +1,7 @@ +import Ticket from 'components/agenda/Ticket/Ticket'; + +const ticket = () => { + return ; +}; + +export default ticket; diff --git a/pages/index.tsx b/pages/index.tsx index 7b66a8f75..5dda91a8f 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,25 +1,45 @@ +import Image from 'next/image'; import { useRouter } from 'next/router'; import type { NextPage } from 'next'; +import PageController from 'components/agenda/utils/PageController'; +import PingpongIcon from 'public/image/takgu/ping-pong.svg'; import styles from 'styles/index.module.scss'; + const Index: NextPage = () => { const router = useRouter(); - const handleNavigation = (path: string) => { router.push(path); }; return (
+

handleNavigation('/agenda')}> + Agenda +

+ +

Ticket & PingPong

-
GG
-
다른거
+ +
- - - +
); }; diff --git a/public/image/ticket.png b/public/image/ticket.png new file mode 100644 index 000000000..2ccf0d00d Binary files /dev/null and b/public/image/ticket.png differ diff --git a/stories/agenda/agendaDetail/AgendaInfo.stories.tsx b/stories/agenda/agendaDetail/AgendaInfo.stories.tsx index b210f36ec..be5d2778f 100644 --- a/stories/agenda/agendaDetail/AgendaInfo.stories.tsx +++ b/stories/agenda/agendaDetail/AgendaInfo.stories.tsx @@ -11,7 +11,7 @@ import AgendaInfo from 'components/agenda/agendaDetail/AgendaInfo'; const baseMockData = { agendaTitle: '아 기다리고 기다리던 대회', agendaHost: 'iamgroot', - agendaStatus: AgendaStatus.ON_GOING, + agendaStatus: AgendaStatus.OPEN, agendaDeadLine: new Date('2024-07-20'), agendaStartTime: new Date('2024-07-25'), agendaEndTime: new Date('2024-07-30'), diff --git a/styles/agenda/Home/AgendaList.module.scss b/styles/agenda/Home/AgendaList.module.scss index 9ef279177..5b7630978 100644 --- a/styles/agenda/Home/AgendaList.module.scss +++ b/styles/agenda/Home/AgendaList.module.scss @@ -46,7 +46,6 @@ position: relative; display: flex; width: 100%; - min-width: 352px; max-width: 750px; height: calc(150px + (100vw - 352px) * ((600 - 150) / (750 - 352))); min-height: 180px; diff --git a/styles/agenda/Home/AgendaTitle.module.scss b/styles/agenda/Home/AgendaTitle.module.scss index 01f51a71f..6d4d8b985 100644 --- a/styles/agenda/Home/AgendaTitle.module.scss +++ b/styles/agenda/Home/AgendaTitle.module.scss @@ -3,11 +3,18 @@ .agendaTitleContainer { display: flex; justify-content: space-between; - align-items: center; + align-items: flex-start; width: 100%; padding: 0 1rem; @include text(main-menu); + .agendaTitleButtonContainer { + display: flex; + flex-direction: column; + gap: 1rem; + align-items: flex-end; + } + .agendaCreateBtn { display: flex; cursor: pointer; diff --git a/styles/agenda/Home/MyAgendaBtn.module.scss b/styles/agenda/Home/MyAgendaBtn.module.scss index cc089aa7e..f155729d8 100644 --- a/styles/agenda/Home/MyAgendaBtn.module.scss +++ b/styles/agenda/Home/MyAgendaBtn.module.scss @@ -2,6 +2,7 @@ .myAgendaContainer { display: flex; + align-self: flex-end; width: 12.5rem; height: 3rem; flex-direction: column; @@ -9,9 +10,9 @@ overflow: hidden; background-color: var(--box-bg-2); border: var(--default-border); - border-left-style: none; - border-top-right-radius: $radius-big; - border-bottom-right-radius: $radius-big; + border-right-style: none; + border-top-left-radius: $radius-big; + border-bottom-left-radius: $radius-big; box-shadow: var(--default-box-shadow); transition: width 0.15s ease, height 0.15s ease; gap: 1rem; diff --git a/styles/agenda/Ticket/Ticket.module.scss b/styles/agenda/Ticket/Ticket.module.scss new file mode 100644 index 000000000..d454b98e4 --- /dev/null +++ b/styles/agenda/Ticket/Ticket.module.scss @@ -0,0 +1,69 @@ +@import 'styles/agenda/common.scss'; + +.container { + @include container(1); + flex-direction: column; + gap: 1.5rem; +} + +.h1 { + @include text(sub-title); + width: 100%; +} + +.section { + justify-content: center; + align-items: center; + display: flex; + flex-direction: column; + > p { + text-align: center; + } +} + +.ticketSection { + display: flex; + justify-content: flex-end; + > h1 { + align-self: center; + @include text(sub-title); + margin-left: 0.5rem; + } +} +.ticketFrame { + width: 5rem; + height: 5rem; + background: var(--highlight-violet); + border: 2px solid var(--color-text); + border-radius: 3rem; + box-shadow: 0 0.3rem 0 0 var(--color-text); + justify-content: flex-end; + align-items: center; + > h1 { + font-size: $font-size-xxxl; + text-align: center; + } +} + +.line { + width: 100%; + height: 1px; + border-bottom: 1px solid var(--color-text); +} + +.arrowDown { + padding: 0; + margin: 0; + border-top: 0.6rem solid var(--highlight-violet); + border-right: 0.4rem solid transparent; + border-bottom: 0.6rem solid transparent; + border-left: 0.4rem solid transparent; +} + +.submitButton { + @include textButton(text, highlight); +} + +.logButton { + @include textButton(text, primary); +} diff --git a/styles/agenda/common.scss b/styles/agenda/common.scss index fe65c3be1..88f3e18b3 100644 --- a/styles/agenda/common.scss +++ b/styles/agenda/common.scss @@ -44,6 +44,7 @@ $font-pretendard: 'Pretendard', sans-serif; $font-logo: 'Overgrow', sans-serif; /* font-size */ +$font-size-xxxl: 4rem; // $ticket bold $font-size-xxl: 2.1rem; // $giant-big-font $font-size-xl: 1.8rem; // $big-giant-font $font-size-l: 1.5rem; // $giant-font @@ -110,15 +111,14 @@ $font-size-xs: 0.8rem; // $small-font border-radius: $radius-small; box-shadow: var(--default-box-shadow); - @if ($type == 'submit') { - width: 3rem; - height: 1.5rem; + @if ($type == 'text') { + width: 100%; + height: max-content; } @else if ($type == 'delete') { background: url('/buttons/delete.svg') no-repeat center; } @else { - // default - width: 3rem; - height: 1.5rem; + // default width: 100%; + height: max-content; } @if ($style == 'highlight') { diff --git a/styles/agenda/utils/PageController.module.scss b/styles/agenda/utils/PageController.module.scss new file mode 100644 index 000000000..8827076fc --- /dev/null +++ b/styles/agenda/utils/PageController.module.scss @@ -0,0 +1,113 @@ +@import 'styles/agenda/common.scss'; + +.container { + width: 100%; + height: max-content; +} + +.agendaInfoContainer { + @include container(1); + position: relative; + z-index: 0; + display: flex; + min-width: 352px; + max-width: 750px; + height: calc(150px + (100vw - 352px) * ((600 - 150) / (750 - 352))); + min-height: 180px; + max-height: 600px; + padding: 0.7rem 1.2rem; + cursor: pointer; + background: $agenda-list-bg; // poster img url 변수로 변경 예정 + border: var(--default-border); + border-radius: $radius-medium; + box-shadow: var(--default-box-shadow); + justify-content: flex-start; + align-items: flex-start; +} + +.rest, +.current { + margin: 0; + background-color: var(--color-text-reverse); + border: none; + border-radius: 100%; + box-shadow: var(--default-box-shadow); +} +.current { + width: 0.6rem; + height: 0.6rem; + padding: 0; +} + +.rest { + width: 0.4rem; + height: 0.4rem; + padding: 0.2rem; + opacity: 0.5; +} + +.navContainer { + display: flex; + width: max-content; + max-width: 50%; + padding: 0.4rem; + margin: 0.5rem auto; + background: rgba(0, 0, 0, 0.01); + border-radius: 1rem; + box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25) inset; + gap: 0.8rem; + justify-content: center; + align-items: center; +} + +.moveButtonPrev, +.moveButtonNext { + position: absolute; + top: 0; + z-index: 1000; + width: 20%; + height: 100%; + background-color: transparent; + border: none; + border-radius: $radius-medium; +} + +.moveButtonPrev { + left: 0; +} + +.moveButtonNext { + right: 0; +} +.moveButtonPrev:hover, +.moveButtonNext:hover { + background-color: rgba(255, 255, 255, 0.4); + .prev { + border-right: 1rem solid white; + } + .next { + border-left: 1rem solid white; + } +} + +.prev, +.next { + position: relative; + background: transparent; +} + +.prev { + left: 0rem; + border-top: 1rem solid transparent; + border-right: 2rem solid transparent; + border-bottom: 1rem solid transparent; + border-left: 2rem solid transparent; +} + +.next { + right: 0rem; + border-top: 1rem solid transparent; + border-right: 2rem solid transparent; + border-bottom: 1rem solid transparent; + border-left: 1rem solid transparent; +} diff --git a/styles/index.module.scss b/styles/index.module.scss index fae953707..616546ea0 100644 --- a/styles/index.module.scss +++ b/styles/index.module.scss @@ -1,4 +1,13 @@ @import 'styles/agenda/common.scss'; +.layout { + max-width: 100%; +} + +.title { + @include text(main-menu); + margin: 1rem 0 0 1.5rem; + font-size: $font-size-l; +} .container { @include container(1); diff --git a/types/aganda/ticketTypes.ts b/types/aganda/ticketTypes.ts new file mode 100644 index 000000000..f2508befe --- /dev/null +++ b/types/aganda/ticketTypes.ts @@ -0,0 +1,19 @@ +// ticketType : +export interface TicketHistoryAPIProps { + totalSize: number; + content: TicketHistoryProps[] | null; +} + +export interface TicketHistoryProps { + createdAt: string; // 발급 시작한 시 + issuedFrom: string; // Agenda 이름 or 42Intra + issuedFromKey: string | null; // AgendaKey UUID or null + usedTo: string; // Agenda 이름 or NotUsed or NotApporve + usedToKey: string | null; // AgendaKey UUID or null + approved: boolean; // true 발급완료, false 발급대기 + approvedAt: string | null; // 발급된 시간 or null + isUsed: boolean; // true 사용된 티켓, false 사용하지 않음 + usedAt: string | null; //} + + idx?: number; +}