Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 && (
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{dashboards.length > 0 && (
{totalPages > 0 && (

여기에 totalPages λ³€μˆ˜λ₯Ό μ΄μš©ν•΄λ„ 될 것 κ°™μŠ΅λ‹ˆλ‹€.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

λͺ¬κ°€.. λŒ€μ‹œλ³΄λ“œκ°€ 있으면~~ 이런 사고 νλ¦„μœΌλ‘œ dashboards.length κ°€ μ’€ 더 직관적이지 μ•Šμ„κΉŒ? μ‹ΆμŠ΅λ‹ˆλ‹€!

<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;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

νƒ€μž…μ„ λΆ„λ¦¬ν•΄μ£Όμ‹œλ©΄ 가독성에 더 쒋을 것 κ°™μŠ΅λ‹ˆλ‹€!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

μ € next | prev만 λ”°λ‘œμš”..?

Suggested change
onPageChange: (direction: 'next' | 'prev') => void;
type PageChangeDirection = 'next' | 'prev';
onPageChange: (direction: PageChangeDirection) => void;

μš”λŸ°λŠλ‚Œ λ§μ”€ν•˜μ‹œλŠ”κ±° λ§žμ„κΉŒμš”?
μ—¬κΈ°μ„œλ°–μ— μ•ˆμ¨κ°€μ§€κ΅¬ λ°”λ‘œ 보기 νŽΈν•œλŠλ‚Œμ΄ μ—†μ§€μ•Šμ•„ μžˆμŠ΅λ‹ˆλ‹€...γ…Žγ…Žγ…Žγ…Ž

}) {
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'
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

λ³„λ„λ‘œ λ³€μˆ˜λ‘œ λΆ„λ¦¬ν•˜λ©΄ μ–΄λ–¨κΉŒμš”??

const leftArrowSrc = isFirstPage
  ? '/icons/arrow_left_light.svg'
  : '/icons/arrow_left.svg';

const rightArrowSrc = isLastPage
  ? '/icons/arrow_right_light.svg'
  : '/icons/arrow_right.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>
);
}
2 changes: 1 addition & 1 deletion src/app/(with-header-sidebar)/mydashboard/_hooks/useApi.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState, useEffect, useCallback } from 'react';
import { AxiosResponse, AxiosError } from 'axios';
import axiosInstance from '../_utils/axiosInstance';
import axiosInstance from '../_lib/axiosInstance';

type UseApiFetchReturnType<T> = {
data: T | null;
Expand Down
29 changes: 29 additions & 0 deletions src/app/(with-header-sidebar)/mydashboard/_hooks/useDashboards.ts
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', {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

λ‚˜μ€‘μ— isLoading 도 같이 λ°›μ•„μ˜€λ©΄ 쒋을 κ±° κ°™μŠ΅λ‹ˆλ‹€~

Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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 };
}
Loading