Skip to content
Merged
3 changes: 3 additions & 0 deletions public/icon/search_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/mydashboardPage/empty_invitation.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { useCallback, useEffect, useState, useRef } from "react";
import { useEffect, useState, useRef } from "react";
import { useIntersection } from "@/lib/hooks/useIntersection";
import { DashboardColumn, TaskCardList } from "@/lib/types";
import { fetchTaskCardList } from "@/lib/apis/cardsApi";
Expand All @@ -19,7 +19,7 @@ export default function Column({ id, title }: DashboardColumn) {
const observerRef = useRef<HTMLDivElement | null>(null);
const accessToken = localStorage.getItem("accessToken") ?? "";

const handleLoad = useCallback(async () => {
const handleLoad = async () => {
if (isLoading || isLast) return;
setIsLoading(true);

Expand All @@ -45,11 +45,11 @@ export default function Column({ id, title }: DashboardColumn) {
} finally {
setIsLoading(false);
}
}, [accessToken, isLoading, isLast, cursorId, id]);
};

useEffect(() => {
handleLoad();
}, [handleLoad]);
}, []);

useIntersection({
target: observerRef,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default function DeleteButton({
<button
type="button"
onClick={handleDeleteClick}
className="max-w-[320px] rounded-lg border border-gray-400 bg-gray-200 font-medium text-lg text-gray-800 tablet:h-[62px] tablet:text-2lg hover:bg-gray-300"
className="max-w-[320px] h-[52px] rounded-lg border border-gray-400 bg-gray-200 font-medium text-lg text-gray-800 tablet:h-[62px] tablet:text-2lg hover:bg-gray-300"
>
대시보드 삭제하기
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { useEffect, useState } from "react";
import { Invitation } from "@/lib/types";
import { fetchInvitationList } from "@/lib/apis/dashboardsApi";
import Pagination from "@/components/common/pagenation-button/PagenationButton";
import Pagination from "@/components/common/pagination-button/PaginationButton";
import InvitationCard from "./InvitationCard";
import InviteModalButton from "./InviteModalButton";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import { useEffect, useState } from "react";
import Pagination from "@/components/common/pagenation-button/PagenationButton";
import Pagination from "@/components/common/pagination-button/PaginationButton";
import { DashboardMember } from "@/lib/types";
import Button from "@/components/common/button/Button";
import UserIcon from "@/components/common/user-icon/UserIcon";
Expand Down Expand Up @@ -64,7 +64,6 @@ export default function MemberSection({
setIsLoading(true);
await deleteDashboardMember({
token,
dashboardId: id,
memberId,
});

Expand Down Expand Up @@ -126,7 +125,7 @@ export default function MemberSection({
img={item.profileImageUrl}
size="md"
/>
<span>{item.email}</span>
<span>{item.nickname}</span>
</div>
<Button
variant="whiteViolet"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,50 @@
import { useEffect, useState } from "react";
import { fetchDashboardList } from "@/lib/apis/dashboardsApi";
import { DashboardList } from "@/lib/types";
import Pagination from "@/components/common/pagination-button/PaginationButton";

const PAGE_SIZE = 6;

export default function DashboardListSection({ token }: { token: string }) {
const [myDashboards, setMyDashboards] = useState<DashboardList[]>([]);
const [page, setPage] = useState(1);

setPage(1); // vercel 배포 때문에 임시로 넣은 코드라 삭제하시면 됩니다.

const [loading, setLoading] = useState(true);
const [totalPages, setTotalPages] = useState(1);
const [loading, setLoading] = useState(false);

useEffect(() => {
async function loadDashboards() {
setLoading(true);
try {
const { dashboards }: { dashboards: DashboardList[] } =
const {
dashboards,
total,
}: { dashboards: DashboardList[]; total: number } =
await fetchDashboardList({
token: token,
page: page,
token,
page,
size: PAGE_SIZE,
});

setMyDashboards(
dashboards.filter((dashboard) => dashboard.createdByMe)
);
setMyDashboards(dashboards.filter((d) => d.createdByMe));
setTotalPages(Math.ceil(total / PAGE_SIZE));
} catch (error) {
console.error("대시보드를 불러오는 중 오류 발생:", error);
} finally {
setLoading(false);
}
}
loadDashboards();
}, []);
}, [page, token]);

return (
<>
<div className="max-w-[1022px]">
<button className="px-4 py-2 bg-blue-500 text-white rounded-lg flex items-center">
새로운 대시보드 +
</button>

<div>
<h2 className="text-lg font-semibold">내 대시보드</h2>
{loading ? (
<p>로딩 중...</p>
) : myDashboards.length > 0 ? (
{myDashboards.length > 0 ? (
<ul className="mt-4 space-y-2">
{myDashboards.map((dashboard) => (
<li key={dashboard.id} className="p-4 bg-white shadow rounded-lg">
Expand All @@ -55,11 +55,30 @@ export default function DashboardListSection({ token }: { token: string }) {
))}
</ul>
) : (
<div className="p-6 bg-gray-100 text-center rounded-lg">
<p className="text-gray-500">아직 생성한 대시보드가 없어요.</p>
!loading && (
<div className="p-6 bg-gray-100 text-center rounded-lg">
<p className="text-gray-500">아직 생성한 대시보드가 없어요.</p>
</div>
)
)}

{loading && (
<div className="flex justify-center mt-4">
<div className="w-6 h-6 border-4 border-blue-500 border-t-transparent rounded-full animate-spin"></div>
</div>
)}

<div className="flex justify-center mt-4">
<Pagination
currentPage={page}
totalPages={totalPages}
onPrevClick={() => setPage((prev) => Math.max(prev - 1, 1))}
onNextClick={() =>
setPage((prev) => Math.min(prev + 1, totalPages))
}
/>
</div>
</div>
</>
</div>
);
}
82 changes: 82 additions & 0 deletions src/app/(after-login)/mydashboard/_components/InvitationCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { useRouter } from "next/navigation";
import { useDashboardStore } from "@/lib/store/useDashboardStore";
import { Invitation } from "@/lib/types";
import { putInvitation } from "@/lib/apis/invitationsApi";
import Button from "@/components/common/button/Button";

type InvitationCardProps = Invitation & {
token: string;
};

export default function InvitationCard({
id,
inviter,
dashboard,
token,
}: InvitationCardProps) {
const newDashboardId = String(dashboard.id);
const router = useRouter();
const setDashboardId = useDashboardStore((state) => state.setDashboardId);

const handleApproveInvite = async () => {
await putInvitation({
token,
invitationId: id,
inviteAccepted: true,
});

router.push(`/dashboard/${newDashboardId}`);
setDashboardId(newDashboardId);
};

const handleRejectInvite = async () => {
await putInvitation({
token,
invitationId: id,
inviteAccepted: false,
});

window.location.reload();
};

return (
<div className="flex flex-col gap-[14px] border-b border-gray-400 py-[14px] tablet:flex-row tablet:gap-0 tablet:justify-between tablet:py-5 pc:pl-12 ">
<div className="flex flex-col tablet:flex-row tablet:justify-between tablet:flex-grow">
<div className="flex gap-6 tablet:w-1/2">
<div className="w-[38px] font-normal text-md text-gray-500 tablet:hidden">
이름
</div>
<div className="font-normal text-md text-gray-800 tablet:text-lg">
{dashboard.title}
</div>
</div>
<div className="flex gap-6 tablet:w-1/2">
<div className="w-[38px] font-normal text-md text-gray-500 tablet:hidden">
초대자
</div>
<div className="font-normal text-md text-gray-800 tablet:text-lg">
{inviter.nickname}
</div>
</div>
</div>
<div className="flex justify-between gap-[10px] tablet:justify-start tablet:tablet:w-1/3 tablet:relative tablet:left-[-44px] pc:left-[-56px]">
<Button
variant="purple"
onClick={handleApproveInvite}
radius="sm"
className="flex-1 max-h-[32px] tablet:max-w-[72px] pc:max-w-[84px]"
>
<div className="font-medium text-xs tablet:text-md">수락</div>
</Button>
<Button
variant="whiteViolet"
onClick={handleRejectInvite}
radius="sm"
className="flex-1 max-h-[32px] tablet:max-w-[72px] pc:max-w-[84px]"
>
<div className="font-medium text-xs tablet:text-md">거절</div>
</Button>
</div>
</div>
);
}
Loading