diff --git a/src/components/pages/group-list/index.tsx b/src/components/pages/group-list/index.tsx
index dec1e6d7..d7945028 100644
--- a/src/components/pages/group-list/index.tsx
+++ b/src/components/pages/group-list/index.tsx
@@ -17,7 +17,7 @@ import { GroupListItemResponse } from '@/types/service/group';
import { GroupListContent } from './group-list-content';
import { GroupListEmpty } from './group-list-empty';
import { GroupListInfiniteScroll } from './group-list-infinite-scroll';
-import { GroupListLoading } from './group-list-loading';
+import { GroupListSkeleton } from './group-list-loading';
import { GroupListSearchEmpty } from './group-list-search-empty';
const SearchResultCount = ({ keyword, count }: { keyword: string; count: number }) => (
@@ -81,7 +81,7 @@ export default function GroupList() {
const hasItems = items.length > 0;
if (isLoading) {
- return
;
+ return
;
}
return (
diff --git a/src/components/pages/pending/pending-members/constants.tsx b/src/components/pages/pending/pending-members/constants.tsx
new file mode 100644
index 00000000..281e7926
--- /dev/null
+++ b/src/components/pages/pending/pending-members/constants.tsx
@@ -0,0 +1 @@
+export const PENDING_MEMBERS_MIN_HEIGHT = 'h-[calc(100vh-192px)]' as const;
diff --git a/src/components/pages/pending/pending-members/index.tsx b/src/components/pages/pending/pending-members/index.tsx
index cb5f0ca9..51fe1169 100644
--- a/src/components/pages/pending/pending-members/index.tsx
+++ b/src/components/pages/pending/pending-members/index.tsx
@@ -2,7 +2,7 @@
import { useRouter } from 'next/navigation';
-import { useCallback, useEffect } from 'react';
+import { useCallback, useEffect, useMemo } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
@@ -13,7 +13,9 @@ import { useToast } from '@/components/ui/toast/core';
import { groupKeys } from '@/lib/query-key/query-key-group';
import { GetJoinRequestsResponse } from '@/types/service/group';
+import { PENDING_MEMBERS_MIN_HEIGHT } from './constants';
import { PendingMemberCard } from './pending-member-card';
+import { PendingMembersSkeleton } from './pending-members-loading';
interface Props {
groupId: string;
@@ -29,8 +31,10 @@ export const GroupPendingMembers = ({ groupId }: Props) => {
queryFn: () => API.groupService.getJoinRequests({ groupId }, 'PENDING'),
});
- const isForbidden =
- error && typeof error === 'object' && 'status' in error && error.status === 403;
+ const isForbidden = useMemo(
+ () => error && typeof error === 'object' && 'status' in error && error.status === 403,
+ [error],
+ );
useEffect(() => {
if (isForbidden) {
@@ -42,13 +46,10 @@ export const GroupPendingMembers = ({ groupId }: Props) => {
mutationFn: (targetUserId: string) =>
API.groupService.approveJoinRequest({ groupId, targetUserId }),
onSuccess: async () => {
- // 가입 신청 목록 캐시 무효화 및 자동 refetch
- // GroupPendingSummary의 count도 자동으로 업데이트됨
await queryClient.invalidateQueries({
queryKey: groupKeys.joinRequests(groupId, 'PENDING'),
- refetchType: 'active', // 활성화된 모든 쿼리 자동 refetch
+ refetchType: 'active',
});
- // 모임 상세 정보도 갱신
await queryClient.invalidateQueries({ queryKey: groupKeys.detail(groupId) });
run(
모임 신청이 수락되었습니다.);
},
@@ -58,11 +59,9 @@ export const GroupPendingMembers = ({ groupId }: Props) => {
mutationFn: (targetUserId: string) =>
API.groupService.rejectJoinRequest({ groupId, targetUserId }),
onSuccess: async () => {
- // 가입 신청 목록 캐시 무효화 및 모든 활성 쿼리 refetch
- // GroupPendingSummary의 count도 자동으로 업데이트됨
await queryClient.invalidateQueries({
queryKey: groupKeys.joinRequests(groupId, 'PENDING'),
- refetchType: 'active', // 활성화된 모든 쿼리 자동 refetch
+ refetchType: 'active',
});
run(
모임 신청이 거절되었습니다.);
},
@@ -82,12 +81,8 @@ export const GroupPendingMembers = ({ groupId }: Props) => {
[rejectMutation],
);
- if (isLoading) {
- return (
-
- );
+ if (isLoading && !data && !error) {
+ return
;
}
if (isForbidden) {
@@ -96,7 +91,7 @@ export const GroupPendingMembers = ({ groupId }: Props) => {
if (error && (!('status' in error) || error.status !== 403)) {
return (
-
+
);
@@ -104,7 +99,7 @@ export const GroupPendingMembers = ({ groupId }: Props) => {
if (!data || data.items.length === 0) {
return (
-
+
);
diff --git a/src/components/pages/pending/pending-members/pending-members-loading/index.tsx b/src/components/pages/pending/pending-members/pending-members-loading/index.tsx
new file mode 100644
index 00000000..77cd95a9
--- /dev/null
+++ b/src/components/pages/pending/pending-members/pending-members-loading/index.tsx
@@ -0,0 +1,33 @@
+import { PENDING_MEMBERS_MIN_HEIGHT } from '../constants';
+
+const SKELETON_ITEMS_COUNT = 3;
+
+export const PendingMembersSkeleton = () => {
+ const skeletons = Array.from({ length: SKELETON_ITEMS_COUNT });
+
+ return (
+
+
+ {skeletons.map((_, index) => (
+ -
+
+
+ ))}
+
+
+ );
+};
diff --git a/src/components/shared/card/card-skeleton/index.tsx b/src/components/shared/card/card-skeleton/index.tsx
index 0271dfb8..fde7eaa3 100644
--- a/src/components/shared/card/card-skeleton/index.tsx
+++ b/src/components/shared/card/card-skeleton/index.tsx
@@ -1,4 +1,8 @@
-export const CardSkeleton = () => {
+interface CardSkeletonProps {
+ showButtons?: boolean;
+}
+
+export const CardSkeleton = ({ showButtons = false }: CardSkeletonProps = {}) => {
return (
@@ -8,6 +12,7 @@ export const CardSkeleton = () => {
+ {showButtons &&
}
@@ -32,6 +37,8 @@ export const CardSkeleton = () => {
+
+ {showButtons && }