From 8db151470ce1f0aac128e1756a46795365b22830 Mon Sep 17 00:00:00 2001
From: joonhyong
Date: Mon, 23 Mar 2026 06:26:57 +0900
Subject: [PATCH 1/9] =?UTF-8?q?[HSC-412]=20feat:=20=EC=8A=A4=EC=BC=88?=
=?UTF-8?q?=EB=A0=88=ED=86=A4=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20?=
=?UTF-8?q?=EC=83=9D=EC=84=B1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../common/skeletons/ChartCardSkeleton.tsx | 75 +++++++++++++++++++
.../common/skeletons/FeedCardSkeleton.tsx | 27 +++++++
src/components/common/skeletons/Skeleton.tsx | 9 +++
.../common/skeletons/TableCardSkeleton.tsx | 58 ++++++++++++++
4 files changed, 169 insertions(+)
create mode 100644 src/components/common/skeletons/ChartCardSkeleton.tsx
create mode 100644 src/components/common/skeletons/FeedCardSkeleton.tsx
create mode 100644 src/components/common/skeletons/Skeleton.tsx
create mode 100644 src/components/common/skeletons/TableCardSkeleton.tsx
diff --git a/src/components/common/skeletons/ChartCardSkeleton.tsx b/src/components/common/skeletons/ChartCardSkeleton.tsx
new file mode 100644
index 0000000..1e9eb92
--- /dev/null
+++ b/src/components/common/skeletons/ChartCardSkeleton.tsx
@@ -0,0 +1,75 @@
+import { Skeleton } from "./Skeleton";
+
+type ChartCardSkeletonProps = {
+ titleWidth?: string;
+ subtitleWidth?: string;
+ controls?: boolean;
+ variant?: "line" | "donut" | "bars";
+};
+
+export function ChartCardSkeleton({
+ titleWidth = "w-40",
+ subtitleWidth = "w-28",
+ controls = false,
+ variant = "line",
+}: ChartCardSkeletonProps) {
+ return (
+
+
+
+
+
+
+
+ {controls ? (
+
+
+
+
+ ) : null}
+
+
+ {variant === "donut" ? (
+
+
+
+ {Array.from({ length: 3 }).map((_, index) => (
+
+
+
+
+
+ ))}
+
+
+ ) : (
+
+
+ {(variant === "bars" ? Array.from({ length: 10 }) : Array.from({ length: 12 })).map(
+ (_, index) => (
+
+ ),
+ )}
+
+
+ )}
+
+ );
+}
diff --git a/src/components/common/skeletons/FeedCardSkeleton.tsx b/src/components/common/skeletons/FeedCardSkeleton.tsx
new file mode 100644
index 0000000..b992e9f
--- /dev/null
+++ b/src/components/common/skeletons/FeedCardSkeleton.tsx
@@ -0,0 +1,27 @@
+import { Skeleton } from "./Skeleton";
+
+type FeedCardSkeletonProps = {
+ itemCount?: number;
+};
+
+export function FeedCardSkeleton({ itemCount = 6 }: FeedCardSkeletonProps) {
+ return (
+
+
+
+
+
+
+
+ {Array.from({ length: itemCount }).map((_, index) => (
+
+
+
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/components/common/skeletons/Skeleton.tsx b/src/components/common/skeletons/Skeleton.tsx
new file mode 100644
index 0000000..6033ef8
--- /dev/null
+++ b/src/components/common/skeletons/Skeleton.tsx
@@ -0,0 +1,9 @@
+import { cn } from "@/lib/utils";
+
+type SkeletonProps = {
+ className?: string;
+};
+
+export function Skeleton({ className }: SkeletonProps) {
+ return ;
+}
diff --git a/src/components/common/skeletons/TableCardSkeleton.tsx b/src/components/common/skeletons/TableCardSkeleton.tsx
new file mode 100644
index 0000000..8a53522
--- /dev/null
+++ b/src/components/common/skeletons/TableCardSkeleton.tsx
@@ -0,0 +1,58 @@
+import { Skeleton } from "./Skeleton";
+
+type TableCardSkeletonProps = {
+ rowCount?: number;
+ columnCount?: number;
+};
+
+export function TableCardSkeleton({ rowCount = 10, columnCount = 10 }: TableCardSkeletonProps) {
+ return (
+
+
+
+
+
+
+
+
+
+ {Array.from({ length: columnCount }).map((_, index) => (
+
+
+
+ ))}
+
+
+
+ {Array.from({ length: rowCount }).map((_, rowIndex) => (
+
+ {Array.from({ length: columnCount }).map((__, cellIndex) => (
+
+
+
+ ))}
+
+ ))}
+
+
+
+
+
+
+ );
+}
From 2d8ca76f9dcc729077f2088b7cc868d9824a2edc Mon Sep 17 00:00:00 2001
From: joonhyong
Date: Mon, 23 Mar 2026 07:02:42 +0900
Subject: [PATCH 2/9] =?UTF-8?q?[HSC-412]=20feat:=20=EA=B3=A0=EA=B0=9D=20?=
=?UTF-8?q?=EA=B4=80=EB=A6=AC/=EC=9D=B4=ED=83=88=20=EA=B0=90=EC=A7=80=20?=
=?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90=20=EC=8A=A4=EC=BC=88?=
=?UTF-8?q?=EB=A0=88=ED=86=A4=20=EC=A0=81=EC=9A=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/components/domain/churn/ChurnDelta.tsx | 37 +++----
src/components/domain/churn/ChurnTotal.tsx | 25 ++---
.../domain/churn/feed/ChurnFeed.tsx | 9 +-
.../domain/churn/list/ChurnList.tsx | 54 ++++------
.../domain/customers/CustomersList.tsx | 98 +++++++------------
.../domain/customers/MembershipChart.tsx | 16 ++-
.../domain/customers/MonthlyMembersChart.tsx | 29 ++----
7 files changed, 103 insertions(+), 165 deletions(-)
diff --git a/src/components/domain/churn/ChurnDelta.tsx b/src/components/domain/churn/ChurnDelta.tsx
index d300397..1e57daa 100644
--- a/src/components/domain/churn/ChurnDelta.tsx
+++ b/src/components/domain/churn/ChurnDelta.tsx
@@ -14,6 +14,7 @@ import {
YAxis,
} from "recharts";
+import { ChartCardSkeleton } from "@/components/common/skeletons/ChartCardSkeleton";
import { useChurnTrend } from "@/lib/tanstack/query/churn/useChurnTrend";
const COLOR_POS = "var(--danger-500)";
@@ -22,22 +23,16 @@ const COLOR_ZERO = "var(--neutral-400)";
export function ChurnDelta() {
const { data, isLoading, isError } = useChurnTrend();
-
const [range, setRange] = useState<9 | 31>(9);
const rawData = data?.data.data ?? [];
-
- const chartData = rawData.slice(-range).map((d) => ({
- date: d.date,
- delta: d.delta,
+ const chartData = rawData.slice(-range).map((item) => ({
+ date: item.date,
+ delta: item.delta,
}));
if (isLoading) {
- return (
-
- );
+ return ;
}
if (isError) {
@@ -58,7 +53,6 @@ export function ChurnDelta() {
- {/* 기간 선택 */}
- {/* 기간 선택 */}
+ onClick={handleClose}
+ type="button">
취소
@@ -250,7 +254,7 @@ export function CustomerModal({ open, onOpenChange, memberId }: ModalProps) {
open={updateOpen}
onOpenChange={setUpdateOpen}
memberId={memberId}
- memberName={member?.name ?? ""}
+ memberName={member.name}
currentStatus={currentStatus}
currentMembership={currentMembership}
pendingStatus={effectiveStatus}
diff --git a/src/components/domain/customers/modals/CustomerModalSkeleton.tsx b/src/components/domain/customers/modals/CustomerModalSkeleton.tsx
new file mode 100644
index 0000000..9ffadb8
--- /dev/null
+++ b/src/components/domain/customers/modals/CustomerModalSkeleton.tsx
@@ -0,0 +1,120 @@
+import { X } from "lucide-react";
+
+import { Skeleton } from "@/components/common/skeletons/Skeleton";
+
+function SkeletonInfoRow({ interactive = false }: { interactive?: boolean }) {
+ return (
+
+
+
+
+
+ {interactive ? (
+
+ ) : (
+
+ )}
+
+
+ );
+}
+
+function SkeletonSection({
+ titleWidth = "w-32",
+ leftRows = 3,
+ rightRows = 3,
+ interactiveRows = [],
+}: {
+ titleWidth?: string;
+ leftRows?: number;
+ rightRows?: number;
+ interactiveRows?: Array<"left" | "right">;
+}) {
+ return (
+ <>
+
+
+
+
+ {Array.from({ length: leftRows }).map((_, index) => (
+
+ ))}
+
+
+
+ {Array.from({ length: rightRows }).map((_, index) => (
+
+ ))}
+
+
+
+
+ >
+ );
+}
+
+export function CustomerModalSkeleton() {
+ return (
+
+ );
+}
From 9716fb370d800e2e9482d89c394c3f39ec39864b Mon Sep 17 00:00:00 2001
From: joonhyong
Date: Mon, 23 Mar 2026 15:58:14 +0900
Subject: [PATCH 4/9] =?UTF-8?q?[HSC-412]=20fix:=20console.log=20=EC=A0=9C?=
=?UTF-8?q?=EA=B1=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/components/domain/customers/CustomersList.tsx | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/components/domain/customers/CustomersList.tsx b/src/components/domain/customers/CustomersList.tsx
index 88a7630..2d8152d 100644
--- a/src/components/domain/customers/CustomersList.tsx
+++ b/src/components/domain/customers/CustomersList.tsx
@@ -106,14 +106,12 @@ export function CustomersList({
const queryClient = useQueryClient();
const statusMutation = useAdminMembersStatus({
- onSuccess: (response) => {
- console.log("[STATUS PATCH SUCCESS]", response);
+ onSuccess: () => {
toast.success("상태를 변경하였습니다.");
onRowSelectionChange({});
queryClient.invalidateQueries({ queryKey: ["adminMembers"] });
},
- onError: (error) => {
- console.log("[STATUS PATCH ERROR]", error);
+ onError: () => {
toast.error("상태 변경에 실패했습니다.");
},
});
From 79852b021eeb6b04b34d3349c711f30c578eb55a Mon Sep 17 00:00:00 2001
From: joonhyong
Date: Mon, 23 Mar 2026 15:59:18 +0900
Subject: [PATCH 5/9] =?UTF-8?q?[HSC-412]=20fix:=20=ED=86=A0=EC=8A=A4?=
=?UTF-8?q?=ED=8A=B8=20=EC=9C=84=EC=B9=98=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/app/layout.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 6a73432..f77c30c 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -19,7 +19,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
{children}
-
+