-
Notifications
You must be signed in to change notification settings - Fork 1
[feat] mydashboard main page #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
b470a1a
9f64b32
588ae13
21ab0f9
136716c
1059439
06fdab7
207cc80
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| .dashboardCard.dashboardCard { | ||
| padding: 15px 20px; | ||
| background: var(--white); | ||
| border: 1px solid var(--gray-300); | ||
| border-radius: 8px; | ||
| transition: background-color 0.3s ease; | ||
| } | ||
|
|
||
| .dashboardCard.dashboardCard:hover { | ||
| background: var(--violet-light); | ||
| } | ||
|
|
||
| .titleContainer { | ||
| display: flex; | ||
| width: 100%; | ||
| justify-content: space-between; | ||
| align-items: center; | ||
| gap: 12px; | ||
| } | ||
|
|
||
| .dot { | ||
| width: 8px; | ||
| height: 8px; | ||
| border-radius: 999px; | ||
| } | ||
|
|
||
| .title, | ||
| .crown { | ||
| font-size: 18px; | ||
| font-weight: 500; | ||
| } | ||
|
|
||
| .title { | ||
| color: var(--black-100); | ||
| font-size: 14px; | ||
| font-weight: 600; | ||
| } | ||
|
|
||
| .arrowWrapper { | ||
| flex: 1; | ||
| text-align: right; | ||
| } | ||
|
|
||
| @media screen and (min-width: 768px) { | ||
| .title { | ||
| font-size: 16px; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import type { Dashboard } from '@/app/(with-header-sidebar)/mydashboard/_types/dashboards'; | ||
| import Image from 'next/image'; | ||
| import { useRouter } from 'next/navigation'; | ||
| import Button from '@/components/Button'; | ||
| import styles from './DashboardCard.module.css'; | ||
|
|
||
| export default function DashboardCard({ | ||
| id, | ||
| color, | ||
| title, | ||
| createdByMe, | ||
| }: Dashboard) { | ||
| const router = useRouter(); | ||
|
|
||
| return ( | ||
| <Button | ||
| className={styles.dashboardCard} | ||
| onClick={() => router.push(`/dashboard/${id}`)} | ||
| > | ||
| <div className={styles.titleContainer}> | ||
| <div style={{ background: color }} className={styles.dot}></div> | ||
| <span className={styles.title}>{title}</span> | ||
| {createdByMe && ( | ||
| <span className={styles.crown}> | ||
| <Image src="/icons/crown.svg" alt="μκ΄" width={15} height={12} /> | ||
| </span> | ||
| )} | ||
| <div className={styles.arrowWrapper}> | ||
| <Image | ||
| src="/icons/arrow_right.svg" | ||
| alt="μ€λ₯Έμͺ½ νμ΄ν" | ||
| width={18} | ||
| height={18} | ||
| /> | ||
| </div> | ||
| </div> | ||
| </Button> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| .dashboardsWrapper { | ||
| display: grid; | ||
| grid-template-rows: repeat(6, 1fr); | ||
| grid-template-columns: 1fr; | ||
| gap: 8px; | ||
| } | ||
|
|
||
| .addDashboard.addDashboard { | ||
| background: var(--white); | ||
| color: var(--black-100); | ||
| font-size: 14px; | ||
| font-weight: 600; | ||
| padding: 15px 20px; | ||
| background: var(--white); | ||
| border: 1px solid var(--gray-300); | ||
| border-radius: 8px; | ||
| display: flex; | ||
| justify-content: center; | ||
| align-items: center; | ||
| gap: 12px; | ||
| transition: background-color 0.3s ease; | ||
| } | ||
|
|
||
| .addDashboard.addDashboard:hover { | ||
| background-color: var(--violet-light); | ||
| } | ||
|
|
||
| .addIconWrapper { | ||
| border-radius: 4px; | ||
| background: var(--violet-light); | ||
| display: inline-flex; | ||
| justify-content: center; | ||
| align-items: center; | ||
| } | ||
|
|
||
| @media screen and (min-width: 768px) { | ||
| .dashboardsWrapper { | ||
| grid-template-rows: repeat(3, 1fr); | ||
| grid-template-columns: repeat(2, 1fr); | ||
| gap: 10px; | ||
| } | ||
|
|
||
| .addDashboard.addDashboard { | ||
| font-size: 16px; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| 'use client'; | ||
|
|
||
| import useDashboards from '../../_hooks/useDashboards'; | ||
| import Pagination from './Pagination'; | ||
| import DashboardCard from './DashboardCard'; | ||
| import Button from '@/components/Button'; | ||
| import Image from 'next/image'; | ||
| import styles from './Dashboards.module.css'; | ||
|
|
||
| const PAGE_SIZE = 5; | ||
|
|
||
| export default function Dashboards() { | ||
| const { page, dashboards, totalPages, handlePageChange } = useDashboards({ | ||
| pageSize: PAGE_SIZE, | ||
| }); | ||
|
|
||
| return ( | ||
| <div> | ||
| <section className={styles.dashboardsWrapper}> | ||
| <Button className={styles.addDashboard}> | ||
| <span>μλ‘μ΄ λμ보λ</span> | ||
| <span className={styles.addIconWrapper}> | ||
| <Image | ||
| src="/icons/add.svg" | ||
| alt="μλ‘μ΄ λμ보λ μΆκ°" | ||
| width={16} | ||
| height={16} | ||
| /> | ||
| </span> | ||
| </Button> | ||
| {dashboards.map((board) => ( | ||
| <DashboardCard key={board.id} {...board} /> | ||
| ))} | ||
| </section> | ||
| {dashboards.length > 0 && ( | ||
| <Pagination | ||
| currentPage={page} | ||
| totalPages={totalPages} | ||
| onPageChange={handlePageChange} | ||
| /> | ||
| )} | ||
| </div> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| .pagination { | ||
| display: flex; | ||
| justify-content: flex-end; | ||
| align-items: center; | ||
| gap: 16px; | ||
| margin-top: 16px; | ||
| } | ||
|
|
||
| .pageNavigation { | ||
| color: var(--black-100); | ||
| font-size: 14px; | ||
| font-weight: 400; | ||
| } | ||
|
|
||
| .arrowLeft.arrowLeft, | ||
| .arrowRight.arrowRight { | ||
| border: 1px solid var(--gray-300); | ||
| background: var(--white); | ||
| width: 40px; | ||
| height: 40px; | ||
| transition: background-color 0.3s ease; | ||
| } | ||
|
|
||
| .arrowLeft.arrowLeft { | ||
| border-radius: 4px 0px 0px 4px; | ||
| } | ||
|
|
||
| .arrowRight.arrowRight { | ||
| border-radius: 0px 4px 4px 0px; | ||
| border-left: none; | ||
| } | ||
|
|
||
| .arrowLeft.arrowLeft:hover, | ||
| .arrowRight.arrowRight:hover { | ||
| background: var(--violet-light); | ||
| } | ||
|
|
||
| .arrowLeft.arrowLeft:disabled, | ||
| .arrowRight.arrowRight:disabled { | ||
| background: var(--white); | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,58 @@ | ||||||||
| import Image from 'next/image'; | ||||||||
| import Button from '@/components/Button'; | ||||||||
| import styles from './Pagination.module.css'; | ||||||||
|
|
||||||||
| export default function Pagination({ | ||||||||
| currentPage, | ||||||||
| totalPages, | ||||||||
| onPageChange, | ||||||||
| }: { | ||||||||
| currentPage: number; | ||||||||
| totalPages: number; | ||||||||
| onPageChange: (direction: 'next' | 'prev') => void; | ||||||||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. νμ μ λΆλ¦¬ν΄μ£Όμλ©΄ κ°λ μ±μ λ μ’μ κ² κ°μ΅λλ€!
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. μ next | prevλ§ λ°λ‘μ..?
Suggested change
μλ°λλ λ§μνμλκ±° λ§μκΉμ? |
||||||||
| }) { | ||||||||
| const isFirstPage = currentPage === 1; | ||||||||
| const isLastPage = currentPage >= totalPages; | ||||||||
|
|
||||||||
| return ( | ||||||||
| <div className={styles.pagination}> | ||||||||
| <span | ||||||||
| className={styles.pageNavigation} | ||||||||
| >{`${totalPages} νμ΄μ§ μ€ ${currentPage}`}</span> | ||||||||
| <div className={styles.arrowWrapper}> | ||||||||
| <Button | ||||||||
| className={styles.arrowLeft} | ||||||||
| onClick={() => onPageChange('prev')} | ||||||||
| disabled={isFirstPage} | ||||||||
| > | ||||||||
| <Image | ||||||||
| src={ | ||||||||
| isFirstPage | ||||||||
| ? '/icons/arrow_left_light.svg' | ||||||||
| : '/icons/arrow_left.svg' | ||||||||
|
||||||||
| } | ||||||||
| alt="μΌμͺ½μΌλ‘ μ΄λ" | ||||||||
| width={16} | ||||||||
| height={16} | ||||||||
| /> | ||||||||
| </Button> | ||||||||
| <Button | ||||||||
| className={styles.arrowRight} | ||||||||
| onClick={() => onPageChange('next')} | ||||||||
| disabled={isLastPage} | ||||||||
| > | ||||||||
| <Image | ||||||||
| src={ | ||||||||
| isLastPage | ||||||||
| ? '/icons/arrow_right_light.svg' | ||||||||
| : '/icons/arrow_right.svg' | ||||||||
| } | ||||||||
| alt="μ€λ₯Έμͺ½μΌλ‘ μ΄λ" | ||||||||
| width={16} | ||||||||
| height={16} | ||||||||
| /> | ||||||||
| </Button> | ||||||||
| </div> | ||||||||
| </div> | ||||||||
| ); | ||||||||
| } | ||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| .invitations { | ||
| background-color: var(--white); | ||
| border-radius: 8px; | ||
| min-height: 260px; | ||
| margin-top: 16px; | ||
| padding: 24px 20px 80px 20px; | ||
| } | ||
|
|
||
| .title { | ||
| color: var(--black-100); | ||
| font-size: 14px; | ||
| font-weight: 700; | ||
| } | ||
|
|
||
| .descriptionWrapper { | ||
| text-align: center; | ||
| margin-top: 60px; | ||
| } | ||
|
|
||
| .description { | ||
| color: var(--gray-400); | ||
| font-size: 12px; | ||
| font-weight: 400; | ||
| } | ||
|
|
||
| @media screen and (min-width: 768px) { | ||
| .invitations { | ||
| margin-top: 40px; | ||
| } | ||
|
|
||
| .title { | ||
| font-size: 24px; | ||
| } | ||
|
|
||
| .descriptionWrapper { | ||
| text-align: center; | ||
| margin-top: 64px; | ||
| } | ||
|
|
||
| .description { | ||
| font-size: 18px; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import Image from 'next/image'; | ||
| import styles from './Invitations.module.css'; | ||
|
|
||
| export default function Invitations() { | ||
| return ( | ||
| <section className={styles.invitations}> | ||
| <h2 className={styles.title}>μ΄λλ°μ λμ보λ</h2> | ||
| <div className={styles.descriptionWrapper}> | ||
| <Image | ||
| src="/images/unsubscribe.svg" | ||
| alt="λ©μΌμμ μ΄λ―Έμ§" | ||
| width={100} | ||
| height={100} | ||
| /> | ||
| <p className={styles.description}>μμ§ μ΄λλ°μ λμ보λκ° μμ΄μ</p> | ||
| </div> | ||
| </section> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| import { useState } from 'react'; | ||
| import useApi from '@/app/(with-header-sidebar)/mydashboard/_hooks/useApi'; | ||
| import type { GetDashboardsResponse } from '@/app/(with-header-sidebar)/mydashboard/_types/dashboards'; | ||
|
|
||
| interface UseDashboardsParams { | ||
| pageSize: number; | ||
| } | ||
|
|
||
| export default function useDashboards({ pageSize }: UseDashboardsParams) { | ||
| const [page, setPage] = useState(1); | ||
| const { data } = useApi<GetDashboardsResponse>('/dashboards', { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. λμ€μ isLoading λ κ°μ΄ λ°μμ€λ©΄ μ’μ κ±° κ°μ΅λλ€~
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ν μλ ΈνΈπ«‘ |
||
| method: 'GET', | ||
| params: { navigationMethod: 'pagination', page, size: pageSize }, | ||
| }); | ||
|
|
||
| const dashboards = data?.dashboards ?? []; | ||
| const totalCount = data?.totalCount ?? 0; | ||
| const totalPages = Math.ceil(totalCount / pageSize); | ||
|
|
||
| const handlePageChange = (direction: 'next' | 'prev') => { | ||
| setPage((prevPage) => { | ||
| if (direction === 'next' && prevPage < totalPages) return prevPage + 1; | ||
| if (direction === 'prev' && prevPage > 1) return prevPage - 1; | ||
| return prevPage; | ||
| }); | ||
| }; | ||
|
|
||
| return { page, dashboards, totalPages, handlePageChange }; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
μ¬κΈ°μ totalPages λ³μλ₯Ό μ΄μ©ν΄λ λ κ² κ°μ΅λλ€.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
λͺ¬κ°.. λμ보λκ° μμΌλ©΄~~ μ΄λ° μ¬κ³ νλ¦μΌλ‘ dashboards.length κ° μ’ λ μ§κ΄μ μ΄μ§ μμκΉ? μΆμ΅λλ€!