|
1 | 1 | import { useSuspenseQuery } from '@tanstack/react-query'; |
2 | | -import React, { useEffect, useState } from 'react'; |
| 2 | +import { useEffect, useState } from 'react'; |
3 | 3 |
|
4 | 4 | import { InviteCard } from '@/app/invite/meet/[meetId]/src/components/InviteProposal'; |
5 | 5 | import { proposalAPIService } from '@/app/invite/meet/[meetId]/src/service'; |
| 6 | +import AppInstallBanner from '@/shared/components/AppInstallBanner'; |
6 | 7 | import InviteCardFrame from '@/shared/components/InviteCardFrame'; |
7 | 8 | import { useParam } from '@/shared/hooks/useParam'; |
| 9 | +import { cn } from '@/shared/lib'; |
| 10 | + |
| 11 | +const BANNER_KEY = 'invite-banner-dismissed-at'; |
| 12 | +const BANNER_RESHOW_MINUTES = 30; |
8 | 13 |
|
9 | 14 | const InviteProposalContent = () => { |
10 | 15 | const proposalId = Number(useParam('meetId')); |
11 | 16 |
|
12 | 17 | const [animateCardIn, setAnimateCardIn] = useState(false); |
13 | 18 |
|
| 19 | + const [showBanner, setShowBanner] = useState(false); |
| 20 | + |
14 | 21 | const { data: proposalDetail } = useSuspenseQuery({ |
15 | 22 | queryKey: ['getProposalDetail', proposalId], |
16 | 23 | queryFn: () => proposalAPIService.getProposalDetail(proposalId), |
17 | 24 | }); |
18 | 25 |
|
| 26 | + const handleCloseBanner = () => { |
| 27 | + localStorage.setItem(BANNER_KEY, Date.now().toString()); |
| 28 | + setShowBanner(false); |
| 29 | + }; |
| 30 | + |
19 | 31 | useEffect(() => { |
| 32 | + const dismissedAt = localStorage.getItem(BANNER_KEY); |
| 33 | + const now = Date.now(); |
| 34 | + |
| 35 | + if (!dismissedAt) { |
| 36 | + setShowBanner(true); |
| 37 | + } else { |
| 38 | + const dismissedTime = parseInt(dismissedAt, 10); |
| 39 | + const thirtyMinutes = BANNER_RESHOW_MINUTES * 60 * 1000; |
| 40 | + if (now - dismissedTime > thirtyMinutes) { |
| 41 | + setShowBanner(true); |
| 42 | + } |
| 43 | + } |
20 | 44 | const timeout = setTimeout(() => setAnimateCardIn(true), 100); |
21 | 45 |
|
22 | 46 | return () => clearTimeout(timeout); |
23 | 47 | }, []); |
24 | 48 |
|
25 | 49 | return ( |
26 | | - <div className="relative mt-12 flex justify-center"> |
27 | | - <InviteCardFrame proposal={proposalDetail.data} animateCardIn={animateCardIn} /> |
| 50 | + <> |
| 51 | + {showBanner && <AppInstallBanner onClose={handleCloseBanner} />} |
| 52 | + |
| 53 | + <h2 |
| 54 | + className={cn( |
| 55 | + 'serif-title-22-M font-bold text-gray-900', |
| 56 | + showBanner ? 'mt-[6.875rem]' : 'mt-[1.875rem]' |
| 57 | + )} |
| 58 | + > |
| 59 | + 보고 싶은 마음이 |
| 60 | + <br /> |
| 61 | + 도착했어요 |
| 62 | + </h2> |
| 63 | + |
| 64 | + <div className="relative mt-12 flex justify-center"> |
| 65 | + <InviteCardFrame proposal={proposalDetail.data} animateCardIn={animateCardIn} /> |
28 | 66 |
|
29 | | - <div className="absolute left-1/2 top-12 -translate-x-1/2"> |
30 | | - <InviteCard /> |
| 67 | + <div className="absolute left-1/2 top-12 -translate-x-1/2"> |
| 68 | + <InviteCard /> |
| 69 | + </div> |
31 | 70 | </div> |
32 | | - </div> |
| 71 | + </> |
33 | 72 | ); |
34 | 73 | }; |
35 | 74 |
|
|
0 commit comments