Skip to content

Commit 9e0c516

Browse files
committed
feat: 스켈레톤 추가
1 parent c4868bd commit 9e0c516

File tree

3 files changed

+168
-246
lines changed

3 files changed

+168
-246
lines changed
Lines changed: 80 additions & 235 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
'use client';
2+
13
import { useInfiniteQuery } from '@tanstack/react-query';
24
import Link from 'next/link';
35
import { useMemo } from 'react';
@@ -7,11 +9,15 @@ import { InviteCard } from '@/app/invite/meet/[meetId]/src/components/InviteMeet
79
import InviteCardFrame from '@/shared/components/InviteCardFrame';
810
import { useIntersectionObserver } from '@/shared/hooks/useIntersectionObserver';
911
import { useParam } from '@/shared/hooks/useParam';
12+
import { cn } from '@/shared/lib';
13+
14+
const CARD_W = 'w-[16.25rem]';
15+
const CARD_H = 'h-[23.125rem]';
1016

1117
const ReceiveInviteList = () => {
1218
const gatheringId = Number(useParam('gatheringId'));
1319

14-
const { data, hasNextPage, fetchNextPage, isFetchingNextPage } = useInfiniteQuery({
20+
const { data, hasNextPage, fetchNextPage, isFetchingNextPage, isLoading } = useInfiniteQuery({
1521
queryKey: ['getGatheringProposals', gatheringId, 'RECEIVED'],
1622
initialPageParam: 0,
1723
queryFn: ({ pageParam = 0 }) =>
@@ -35,252 +41,91 @@ const ReceiveInviteList = () => {
3541

3642
return (
3743
<div className="mb-[6.25rem] mt-[1.875rem] flex flex-col justify-center gap-10">
38-
{proposals.length === 0 ? (
44+
{isLoading ? (
45+
<SkeletonList count={3} />
46+
) : proposals.length === 0 ? (
3947
<div className="flex h-[16.25rem] items-center justify-center">
4048
<span className="pretendard-body-14-R text-gray-800">받은 초대장이 아직 없어요</span>
4149
</div>
4250
) : (
43-
proposals.map(proposal => (
44-
<div className="flex flex-col items-center gap-12" key={proposal.proposalId}>
45-
<Link href={`/gathering/${gatheringId}/invites/${proposal.proposalId}`}>
46-
<div className="relative flex justify-center">
47-
<InviteCardFrame proposal={proposal} />
51+
<>
52+
{proposals.map(proposal => (
53+
<div className="flex flex-col items-center gap-12" key={proposal.proposalId}>
54+
<Link href={`/gathering/${gatheringId}/invites/${proposal.proposalId}`}>
55+
<div className="relative flex justify-center">
56+
<InviteCardFrame proposal={proposal} />
4857

49-
<div className="absolute left-1/2 top-12 -translate-x-1/2">
50-
<InviteCard />
58+
<div className="absolute left-1/2 top-12 -translate-x-1/2">
59+
<InviteCard />
60+
</div>
5161
</div>
52-
</div>
53-
</Link>
62+
</Link>
5463

55-
<span className="pretendard-body-12-R text-gray-800">{proposal.relativeTime}</span>
56-
</div>
57-
))
64+
<span className="pretendard-body-12-R text-gray-800">{proposal.relativeTime}</span>
65+
</div>
66+
))}
67+
68+
{isFetchingNextPage && <SkeletonList count={1} compact />}
69+
</>
5870
)}
5971

60-
<div ref={targetRef} className="h-1" />
72+
<div ref={targetRef} className="h-1" aria-hidden />
6173
</div>
6274
);
6375
};
6476

6577
export default ReceiveInviteList;
6678

67-
// const GradientInviteCard = () => (
68-
// <svg
69-
// xmlns="http://www.w3.org/2000/svg"
70-
// width="348"
71-
// height="381"
72-
// viewBox="0 0 348 381"
73-
// fill="none"
74-
// >
75-
// <g filter="url(#filter0_d_1289_22773)">
76-
// <mask
77-
// id="mask0_1289_22773"
78-
// style={{ maskType: 'alpha' }}
79-
// maskUnits="userSpaceOnUse"
80-
// x="30"
81-
// y="34"
82-
// width="288"
83-
// height="322"
84-
// >
85-
// <mask id="path-1-inside-1_1289_22773" fill="white">
86-
// <path d="M308 34.999C313.523 34.999 318 39.4772 318 45V345.999C318 351.522 313.523 356 308 356H40C34.4772 356 30 351.522 30 345.999V45C30 39.4772 34.4772 34.999 40 34.999H138.218C143.716 34.999 148.008 39.5816 149.986 44.7113C153.958 55.0117 163.951 62.3193 175.652 62.3193C187.353 62.3193 197.346 55.0117 201.318 44.7113C203.296 39.5816 207.589 34.999 213.087 34.999H308Z" />
87-
// </mask>
88-
// <path
89-
// d="M308 34.999C313.523 34.999 318 39.4772 318 45V345.999C318 351.522 313.523 356 308 356H40C34.4772 356 30 351.522 30 345.999V45C30 39.4772 34.4772 34.999 40 34.999H138.218C143.716 34.999 148.008 39.5816 149.986 44.7113C153.958 55.0117 163.951 62.3193 175.652 62.3193C187.353 62.3193 197.346 55.0117 201.318 44.7113C203.296 39.5816 207.589 34.999 213.087 34.999H308Z"
90-
// fill="#F5F5F5"
91-
// />
92-
// <path
93-
// d="M308 356V357.5V356ZM40 34.999V33.499V34.999ZM149.986 44.7113L148.587 45.251L149.986 44.7113ZM308 34.999V36.499C312.694 36.499 316.5 40.3054 316.5 45H318H319.5C319.5 38.6489 314.351 33.499 308 33.499V34.999ZM318 45H316.5V345.999H318H319.5V45H318ZM318 345.999H316.5C316.5 350.694 312.694 354.5 308 354.5V356V357.5C314.351 357.5 319.5 352.35 319.5 345.999H318ZM308 356V354.5H40V356V357.5H308V356ZM40 356V354.5C35.3058 354.5 31.5 350.694 31.5 345.999H30H28.5C28.5 352.35 33.6485 357.5 40 357.5V356ZM30 345.999H31.5V45H30H28.5V345.999H30ZM30 45H31.5C31.5 40.3054 35.3058 36.499 40 36.499V34.999V33.499C33.6485 33.499 28.5 38.6489 28.5 45H30ZM40 34.999V36.499H138.218V34.999V33.499H40V34.999ZM149.986 44.7113L148.587 45.251C152.774 56.1107 163.311 63.8193 175.652 63.8193V62.3193V60.8193C164.592 60.8193 155.142 53.9127 151.386 44.1716L149.986 44.7113ZM175.652 62.3193V63.8193C187.994 63.8193 198.53 56.1107 202.718 45.251L201.318 44.7113L199.919 44.1716C196.163 53.9127 186.713 60.8193 175.652 60.8193V62.3193ZM213.087 34.999V36.499H308V34.999V33.499H213.087V34.999ZM201.318 44.7113L202.718 45.251C204.593 40.3896 208.486 36.499 213.087 36.499V34.999V33.499C206.692 33.499 202 38.7736 199.919 44.1716L201.318 44.7113ZM138.218 34.999V36.499C142.819 36.499 146.712 40.3896 148.587 45.251L149.986 44.7113L151.386 44.1716C149.304 38.7736 144.613 33.499 138.218 33.499V34.999Z"
94-
// fill="url(#paint0_linear_1289_22773)"
95-
// mask="url(#path-1-inside-1_1289_22773)"
96-
// />
97-
// </mask>
98-
// <g mask="url(#mask0_1289_22773)">
99-
// <mask
100-
// id="mask1_1289_22773"
101-
// style={{ maskType: 'alpha' }}
102-
// maskUnits="userSpaceOnUse"
103-
// x="11"
104-
// y="-15"
105-
// width="335"
106-
// height="478"
107-
// >
108-
// <path
109-
// d="M11 -4.00098C11 -9.52383 15.4772 -14.001 21 -14.001H336C341.523 -14.001 346 -9.52382 346 -4.00098V452.73C346 458.253 341.523 462.73 336 462.73H21C15.4771 462.73 11 458.253 11 452.73V-4.00098Z"
110-
// fill="#F0F1F3"
111-
// />
112-
// <path
113-
// d="M21 -13.501H336C341.247 -13.501 345.5 -9.24768 345.5 -4.00098V452.729C345.5 457.976 341.247 462.229 336 462.229H21C15.7533 462.229 11.5 457.976 11.5 452.729V-4.00098C11.5 -9.24768 15.7533 -13.501 21 -13.501Z"
114-
// stroke="black"
115-
// strokeOpacity="0.05"
116-
// />
117-
// </mask>
118-
// <g mask="url(#mask1_1289_22773)">
119-
// <mask
120-
// id="mask2_1289_22773"
121-
// style={{ maskType: 'alpha' }}
122-
// maskUnits="userSpaceOnUse"
123-
// x="-32"
124-
// y="-307"
125-
// width="532"
126-
// height="812"
127-
// >
128-
// <rect
129-
// x="-31.2383"
130-
// y="-306.349"
131-
// width="530.069"
132-
// height="809.934"
133-
// rx="19.5"
134-
// fill="#222222"
135-
// stroke="url(#paint1_linear_1289_22773)"
136-
// />
137-
// </mask>
138-
// <g mask="url(#mask2_1289_22773)">
139-
// <g filter="url(#filter1_f_1289_22773)">
140-
// <path
141-
// d="M141.215 613.322C60.8224 631.562 -136.321 258.442 -177.566 53.6864C-218.812 -151.069 -88.5426 -109.925 -8.15047 -128.164C72.2417 -146.404 170.849 4.7972 212.095 209.553C253.341 414.308 221.607 595.082 141.215 613.322Z"
142-
// fill="url(#paint2_linear_1289_22773)"
143-
// />
144-
// </g>
145-
// <g filter="url(#filter2_f_1289_22773)">
146-
// <path
147-
// d="M392.645 -28.3969C524.555 -7.02915 680.808 268.384 662.796 393.624C644.784 518.863 459.328 446.504 327.418 425.136C195.508 403.768 103.175 284.919 121.187 159.68C139.199 34.4402 260.735 -49.7646 392.645 -28.3969Z"
148-
// fill="url(#paint3_linear_1289_22773)"
149-
// />
150-
// </g>
151-
// <g filter="url(#filter3_f_1289_22773)">
152-
// <path
153-
// d="M331.015 227.462C417.787 241.518 519.617 429.335 507.279 515.125C494.941 600.915 373.107 552.191 286.334 538.135C199.562 524.079 139.221 443.138 151.559 357.348C163.897 271.558 244.242 213.406 331.015 227.462Z"
154-
// fill="url(#paint4_linear_1289_22773)"
155-
// />
156-
// </g>
157-
// </g>
158-
// </g>
159-
// </g>
160-
// </g>
161-
// <defs>
162-
// <filter
163-
// id="filter0_d_1289_22773"
164-
// x="0"
165-
// y="-0.000976562"
166-
// width="348"
167-
// height="381.001"
168-
// filterUnits="userSpaceOnUse"
169-
// colorInterpolationFilters="sRGB"
170-
// >
171-
// <feFlood floodOpacity="0" result="BackgroundImageFix" />
172-
// <feColorMatrix
173-
// in="SourceAlpha"
174-
// type="matrix"
175-
// values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
176-
// result="hardAlpha"
177-
// />
178-
// <feOffset dy="-5" />
179-
// <feGaussianBlur stdDeviation="15" />
180-
// <feComposite in2="hardAlpha" operator="out" />
181-
// <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0" />
182-
// <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1289_22773" />
183-
// <feBlend
184-
// mode="normal"
185-
// in="SourceGraphic"
186-
// in2="effect1_dropShadow_1289_22773"
187-
// result="shape"
188-
// />
189-
// </filter>
190-
// <filter
191-
// id="filter1_f_1289_22773"
192-
// x="-365.445"
193-
// y="-309.656"
194-
// width="775.613"
195-
// height="1103.62"
196-
// filterUnits="userSpaceOnUse"
197-
// colorInterpolationFilters="sRGB"
198-
// >
199-
// <feFlood floodOpacity="0" result="BackgroundImageFix" />
200-
// <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
201-
// <feGaussianBlur stdDeviation="90" result="effect1_foregroundBlur_1289_22773" />
202-
// </filter>
203-
// <filter
204-
// id="filter2_f_1289_22773"
205-
// x="-61.0586"
206-
// y="-211.711"
207-
// width="905.281"
208-
// height="857.063"
209-
// filterUnits="userSpaceOnUse"
210-
// colorInterpolationFilters="sRGB"
211-
// >
212-
// <feFlood floodOpacity="0" result="BackgroundImageFix" />
213-
// <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
214-
// <feGaussianBlur stdDeviation="90" result="effect1_foregroundBlur_1289_22773" />
215-
// </filter>
216-
// <filter
217-
// id="filter3_f_1289_22773"
218-
// x="29.957"
219-
// y="105.367"
220-
// width="598.344"
221-
// height="579.287"
222-
// filterUnits="userSpaceOnUse"
223-
// colorInterpolationFilters="sRGB"
224-
// >
225-
// <feFlood floodOpacity="0" result="BackgroundImageFix" />
226-
// <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
227-
// <feGaussianBlur stdDeviation="60" result="effect1_foregroundBlur_1289_22773" />
228-
// </filter>
229-
// <linearGradient
230-
// id="paint0_linear_1289_22773"
231-
// x1="30"
232-
// y1="34.998"
233-
// x2="318.002"
234-
// y2="403.638"
235-
// gradientUnits="userSpaceOnUse"
236-
// >
237-
// <stop stopColor="white" stopOpacity="0.4" />
238-
// <stop offset="1" stopColor="#999999" stopOpacity="0.2" />
239-
// </linearGradient>
240-
// <linearGradient
241-
// id="paint1_linear_1289_22773"
242-
// x1="-31.7383"
243-
// y1="-306.849"
244-
// x2="542.779"
245-
// y2="472.036"
246-
// gradientUnits="userSpaceOnUse"
247-
// >
248-
// <stop stopColor="white" />
249-
// <stop offset="1" stopColor="white" />
250-
// </linearGradient>
251-
// <linearGradient
252-
// id="paint2_linear_1289_22773"
253-
// x1="181.403"
254-
// y1="342.86"
255-
// x2="-110.699"
256-
// y2="283.011"
257-
// gradientUnits="userSpaceOnUse"
258-
// >
259-
// <stop stopColor="#DCC9F7" />
260-
// <stop offset="1" stopColor="#94C1D3" />
261-
// </linearGradient>
262-
// <linearGradient
263-
// id="paint3_linear_1289_22773"
264-
// x1="84.191"
265-
// y1="-11.3887"
266-
// x2="639.383"
267-
// y2="457.821"
268-
// gradientUnits="userSpaceOnUse"
269-
// >
270-
// <stop stopColor="#DCC9F7" />
271-
// <stop offset="1" stopColor="#94C1D3" />
272-
// </linearGradient>
273-
// <linearGradient
274-
// id="paint4_linear_1289_22773"
275-
// x1="392.558"
276-
// y1="293.916"
277-
// x2="427.131"
278-
// y2="539.856"
279-
// gradientUnits="userSpaceOnUse"
280-
// >
281-
// <stop stopColor="#DCC8F8" />
282-
// <stop offset="1" stopColor="white" />
283-
// </linearGradient>
284-
// </defs>
285-
// </svg>
286-
// );
79+
function SkeletonList({ count = 1, compact = false }: { count?: number; compact?: boolean }) {
80+
return (
81+
<>
82+
{Array.from({ length: count }).map((_, idx) => (
83+
<div className={cn('flex flex-col items-center gap-12', compact && 'gap-2.5')} key={idx}>
84+
<SkeletonCard />
85+
{!compact && <div className="h-3 w-24 rounded bg-gray-200/70" aria-hidden />}
86+
</div>
87+
))}
88+
</>
89+
);
90+
}
91+
92+
function SkeletonCard() {
93+
return (
94+
<div
95+
className={cn(
96+
'relative rounded-[0.625rem] bg-[#f0f1f3] px-4 py-3',
97+
CARD_W,
98+
CARD_H,
99+
'overflow-hidden'
100+
)}
101+
aria-busy="true"
102+
aria-label="Loading invitation"
103+
>
104+
<div className="animate-pulse">
105+
<div className="flex justify-end">
106+
<div className="flex flex-col items-end gap-2">
107+
<div className="h-3 w-32 rounded bg-gray-200" />
108+
<div className="h-3 w-40 rounded bg-gray-200" />
109+
</div>
110+
</div>
111+
112+
<div className="mt-[4.375rem]">
113+
<div className="size-5 rounded bg-gray-200" />
114+
<div className="mt-[0.8125rem] flex flex-col gap-[0.3125rem]">
115+
<div className="h-4 w-40 rounded bg-gray-200" />
116+
<div className="h-4 w-36 rounded bg-gray-200" />
117+
<div className="h-4 w-44 rounded bg-gray-200" />
118+
</div>
119+
<div className="serif-body-16-M mt-5 h-4 w-16 rounded bg-gray-200" />
120+
</div>
121+
122+
<div className="absolute bottom-0 left-0 flex w-full justify-between px-4 pb-4">
123+
<div className="h-3 w-10 rounded bg-gray-200" />
124+
<div className="h-3 w-16 rounded bg-gray-200" />
125+
</div>
126+
127+
<div className="pointer-events-none absolute inset-0 -skew-x-12 bg-gradient-to-r from-transparent via-[rgba(255,255,255,0.3)] to-transparent" />
128+
</div>
129+
</div>
130+
);
131+
}

0 commit comments

Comments
 (0)