Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
@@ -1,6 +1,7 @@
"use client";

import { useEffect, useState, useRef } from "react";
import { useIntersection } from "@/lib/hooks/useIntersection";
import { DashboardColumn, TaskCardList } from "@/lib/types";
import { fetchTaskCardList } from "@/lib/apis/cardsApi";
import { TOKEN_1 } from "@/lib/constants/tokens";
Expand Down Expand Up @@ -50,26 +51,11 @@ export default function Column({ id, title }: DashboardColumn) {
handleLoad();
}, []);

useEffect(() => {
if (isLast) return;

const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
handleLoad();
}
},
{ threshold: 0.5 }
);

const current = observerRef.current;
if (current) observer.observe(current);

return () => {
if (current) observer.unobserve(current);
observer.disconnect();
};
}, [cursorId, isLoading, isLast]);
useIntersection({
target: observerRef,
onIntersect: handleLoad,
disabled: isLast,
});

return (
<div className="h-full py-4 border-b border-gray-300 tablet:px-5 tablet:pt-[22px] tablet:pb-5 pc:border-b-0 pc:border-r">
Expand Down
9 changes: 7 additions & 2 deletions src/app/(after-login)/mydashboard/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ import { TOKEN_1 } from "@/lib/constants/tokens";
import DashboardMenu from "@/components/layout/navbar/DashboardMenu";
import UserMenu from "@/components/layout/navbar/UserMenu";

const PAGE_SIZE = 15;

export default async function Layout({
children,
}: {
children: React.ReactNode;
}) {
// 가장 첫 번째 페이지 리스트 불러오도록 나중에 수정
const { dashboards } = await fetchDashboardList(TOKEN_1);
const { dashboards } = await fetchDashboardList({
token: TOKEN_1,
page: 1,
size: PAGE_SIZE,
});

const firstDashboardId = dashboards[0]?.id;

Expand Down
9 changes: 7 additions & 2 deletions src/app/(after-login)/mypage/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ import { TOKEN_1 } from "@/lib/constants/tokens";
import DashboardMenu from "@/components/layout/navbar/DashboardMenu";
import UserMenu from "@/components/layout/navbar/UserMenu";

const PAGE_SIZE = 15;

export default async function Layout({
children,
}: {
children: React.ReactNode;
}) {
// 가장 첫 번째 페이지 리스트 불러오도록 나중에 수정
const { dashboards } = await fetchDashboardList(TOKEN_1);
const { dashboards } = await fetchDashboardList({
token: TOKEN_1,
page: 1,
size: PAGE_SIZE,
});

const firstDashboardId = dashboards[0]?.id;

Expand Down
4 changes: 1 addition & 3 deletions src/components/layout/sidebar/SideMenuItem.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
"use client";

import { useIsMobile } from "@/lib/hooks/useCheckViewport";
import { useDashboardStore } from "@/lib/store/useDashboardStore";
import { useRouter } from "next/navigation";
Expand All @@ -26,7 +24,7 @@ export default function SideMenuItem({
onClick={() => {
router.push(`/dashboard/${id}`);
}}
className="flex items-center p-4 rounded hover:bg-violet-8 tablet:px-[10px] tablet:py-2 pc:p-3"
className="flex items-center w-full p-4 rounded hover:bg-violet-8 tablet:px-[10px] tablet:py-2 pc:p-3"
style={isCurrent ? { background: "#f1effd" } : {}}
disabled={isCurrent}
>
Expand Down
61 changes: 51 additions & 10 deletions src/components/layout/sidebar/SideMenuList.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,62 @@
"use client";

import { useEffect, useState, useRef } from "react";
import { useIntersection } from "@/lib/hooks/useIntersection";
import { DashboardList } from "@/lib/types";
import { fetchDashboardList } from "@/lib/apis/dashboardsApi";
import { TOKEN_1 } from "@/lib/constants/tokens";
import SideMenuItem from "./SideMenuItem";

export default async function SideMenuList() {
const { dashboards, totalCount, cursorId } =
await fetchDashboardList(TOKEN_1);
const items: DashboardList[] = dashboards;
const PAGE_SIZE = 15;

export default function SideMenuList() {
const [items, setItems] = useState<DashboardList[]>([]);
const [page, setPage] = useState(1);
const [isLoading, setIsLoading] = useState(false);
const [isLast, setIsLast] = useState(false);
const observerRef = useRef<HTMLDivElement | null>(null);

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

try {
const { dashboards: newDashboards } = await fetchDashboardList({
token: TOKEN_1,
size: PAGE_SIZE,
page,
});

if (newDashboards.length === 0) {
setIsLast(true);
} else {
setItems((prev) => [...prev, ...newDashboards]);
setPage((prev) => prev + 1);
}
} finally {
setIsLoading(false);
}
};

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

// 해당 값들 사용하게 되면 지울 테스트 코드들
console.log(totalCount);
console.log(cursorId);
useIntersection({
target: observerRef,
onIntersect: handleLoad,
disabled: isLast,
});

return (
<div className="flex flex-col gap-[14px] tablet:gap-[2px] pc:gap-2">
{items.map((item) => (
<SideMenuItem key={item.id} {...item} />
<div className="flex flex-col gap-[14px] flex-grow min-h-0 overflow-y-auto whitespace-nowrap scrollbar-hide tablet:gap-[2px] pc:gap-2">
{items.map((item, index) => (
<div
key={item.id}
ref={index === items.length - 1 ? observerRef : null}
>
<SideMenuItem {...item} />
</div>
))}
</div>
);
Expand Down
4 changes: 2 additions & 2 deletions src/components/layout/sidebar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import SideMenuList from "./SideMenuList";

export default function Sidebar() {
return (
<div className="flex flex-col gap-[39px] tablet:gap-[57px] pc:gap-14">
<div className="flex flex-col gap-[39px] h-full tablet:gap-[57px] pc:gap-14">
<div className="flex justify-center items-center tablet:justify-start">
<LogoButton variant={"purple"} />
</div>
<div className="flex flex-col items-center gap-[22px] tablet:gap-[15px] tablet:items-stretch pc:gap-[16px]">
<div className="flex flex-col items-center gap-[22px] flex-grow min-h-0 tablet:gap-[15px] tablet:items-stretch pc:gap-[16px]">
<div className="flex justify-between">
<SideMenuHeader />
<AddButton />
Expand Down
12 changes: 10 additions & 2 deletions src/lib/apis/dashboardsApi.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import { BASE_URL } from "@/lib/constants/urls";

export async function fetchDashboardList(token: string) {
export async function fetchDashboardList({
token,
page,
size,
}: {
token: string;
page: number;
size: number;
}) {
const res = await fetch(
`${BASE_URL}/dashboards?navigationMethod=pagination&page=1&size=10`,
`${BASE_URL}/dashboards?navigationMethod=pagination&page=${page}&size=${size}`,
{
headers: {
Accept: "application/json",
Expand Down
38 changes: 38 additions & 0 deletions src/lib/hooks/useIntersection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"use client";

import { useEffect } from "react";

interface UseIntersectionProps {
target: React.RefObject<Element>;
onIntersect: () => void;
disabled?: boolean;
threshold?: number;
}

export function useIntersection({
target,
onIntersect,
disabled,
threshold = 0.5,
}: UseIntersectionProps) {
useEffect(() => {
if (disabled) return;

const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
onIntersect();
}
},
{ threshold: threshold }
);

const current = target.current;
if (current) observer.observe(current);

return () => {
if (current) observer.unobserve(current);
observer.disconnect();
};
}, [target, onIntersect, disabled]);
}