Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

홈 팝업 Dialog 작업 #263

Merged
merged 7 commits into from
Jan 15, 2025
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
@@ -0,0 +1,54 @@
import styled from '@emotion/styled';
import { mq_lg } from '@boolti/ui';

interface PopupImageProps {
hasDetail: boolean;
}

const HomePopupContent = styled.div`
margin: 0 -24px;
${mq_lg} {
margin: 0;
width: 500px;
}
`;

const PopupImage = styled.img<PopupImageProps>`
border-top-left-radius: 8px;
border-top-right-radius: 8px;
cursor: ${({ hasDetail }) => (hasDetail ? 'pointer' : 'default')};

${mq_lg} {
width: 500px;
height: 578px;
}
`;

const PopupFooter = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
`;

const CheckLabel = styled.label`
display: flex;
align-items: center;
gap: 8px;
padding: 16px 20px;
color: ${({ theme }) => theme.palette.grey.g60};
cursor: pointer;
`;

const CloseButton = styled.button`
padding: 16px 20px;
color: ${({ theme }) => theme.palette.grey.g100};
cursor: pointer;
`;

export default {
HomePopupContent,
CheckLabel,
PopupImage,
PopupFooter,
CloseButton,
};
55 changes: 55 additions & 0 deletions apps/admin/src/components/EventPopupContent/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Checkbox } from '@boolti/ui';
import Styled from './EventPopupContent.styles';
import { useState } from 'react';
import { useBodyScrollLock } from '~/hooks/useBodyScrollLock';
import { useNavigate } from 'react-router-dom';
import useCookie from '~/hooks/useCookie';

interface HomePopupContentProps {
id: number;
imagePath: string;
detailPath: string | null;
onClose: () => void;
}
const EventPopupContent = ({ id, imagePath, detailPath, onClose }: HomePopupContentProps) => {
const [checked, setChecked] = useState(false);
const navigate = useNavigate();
useBodyScrollLock();
const { setCookie } = useCookie();

const onChange = () => {
setChecked((checked) => !checked);
};

const closeDialog = () => {
if (checked) {
const midnight = new Date();
midnight.setHours(24, 0, 0, 0);
setCookie('popup', `${id}`, { expires: midnight.toUTCString() });
}
onClose();
};

const onClickImage = () => {
if (!detailPath) {
return;
}
navigate(detailPath);
onClose();
};

return (
<Styled.HomePopupContent>
<Styled.PopupImage src={imagePath} onClick={onClickImage} hasDetail={!!detailPath} />
<Styled.PopupFooter>
<Styled.CheckLabel>
<Checkbox variant="main" checked={checked} onChange={onChange} />
오늘 하루 그만보기
</Styled.CheckLabel>
<Styled.CloseButton onClick={closeDialog}>닫기</Styled.CloseButton>
</Styled.PopupFooter>
</Styled.HomePopupContent>
);
};

export default EventPopupContent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import styled from '@emotion/styled';
import { Button, mq_lg } from '@boolti/ui';

const Container = styled.div`
display: flex;
flex-direction: column;
align-items: center;

${mq_lg} {
width: 410px;
padding: 0 20px 20px 20px;
}
`;

const Header = styled.div`
width: 100%;
display: flex;
justify-content: flex-end;
align-items: center;
padding: 12px 0;
`;

const CloseButton = styled.button`
width: 24px;
height: 24px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
color: ${({ theme }) => theme.palette.grey.g70};

svg {
width: 24px;
height: 24px;
}
`;

const Title = styled.h1`
font-size: 18px;
color: ${({ theme }) => theme.palette.grey.g70};
margin-bottom: 24px;
`;

const Emphasized = styled.div`
width: 100%;
border-radius: 4px;
padding: 16px;
background-color: ${({ theme }) => theme.palette.grey.g00};
color: ${({ theme }) => theme.palette.red.main};
font-size: 15px;
text-align: center;
margin-bottom: 16px;
`;

const Description = styled.p`
color: ${({ theme }) => theme.palette.grey.g60};
font-size: 14px;
margin-bottom: 28px;
`;

const ConfirmButton = styled(Button)`
width: 100%;
`;

export default {
Container,
Header,
CloseButton,
Title,
Emphasized,
Description,
ConfirmButton,
};
50 changes: 50 additions & 0 deletions apps/admin/src/components/NoticePopupContent/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { CloseIcon } from '@boolti/icon';
import Styled from './NoticePopupContent.styles';
import { useMemo } from 'react';

interface NoticePopupContentProps {
title: string;
description: string;
onClose: () => void;
}

const NoticePopupContent = ({ title, description, onClose }: NoticePopupContentProps) => {
const dividedDescription = useMemo(() => {
const regex = /`([^`]*)`|([^`]+)/g;
let match;
const result: { emphasized: string[]; normal: string[] } = {
emphasized: [],
normal: [],
};

while ((match = regex.exec(description)) !== null) {
if (match[1] !== undefined) {
result.emphasized.push(match[1]);
} else if (match[2] !== undefined) {
result.normal.push(match[2].trim());
}
}

return result;
}, [description]);

return (
<Styled.Container>
<Styled.Header>
<Styled.CloseButton onClick={onClose}>
<CloseIcon />
</Styled.CloseButton>
</Styled.Header>
<Styled.Title>{title}</Styled.Title>
{dividedDescription.emphasized.length ? (
<Styled.Emphasized>{dividedDescription.emphasized}</Styled.Emphasized>
) : null}
<Styled.Description>{dividedDescription.normal}</Styled.Description>
<Styled.ConfirmButton colorTheme="primary" size="medium" onClick={onClose}>
확인
</Styled.ConfirmButton>
</Styled.Container>
);
};

export default NoticePopupContent;
54 changes: 54 additions & 0 deletions apps/admin/src/hooks/useCookie.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
interface CookieOptions {
path?: string;
'max-age'?: number;
domain?: string;
secure?: boolean;
[key: string]: unknown;
}

const uscCookie = () => {
const setCookie = (name: string, value: string, options: CookieOptions = {}) => {
options.path = options.path || '/';

let updatedCookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;

for (const [key, optionValue] of Object.entries(options)) {
updatedCookie += `; ${key}`;
if (optionValue !== true) {
updatedCookie += `=${optionValue}`;
}
}

console.log(`updatedCookie: ${updatedCookie}`);

document.cookie = updatedCookie;
};

const getCookie = (name: string) => {
const cookieString = document.cookie;
const cookies = cookieString.split('; ');

for (const cookie of cookies) {
const [key, value] = cookie.split('=');
if (decodeURIComponent(key) === name) {
return decodeURIComponent(value);
}
}

return null;
};

const deleteCookie = (name: string) => {
setCookie(name, '', {
'max-age': -1,
});
};

return {
setCookie,
getCookie,
deleteCookie,
};
};

export default uscCookie;
62 changes: 62 additions & 0 deletions apps/admin/src/hooks/usePopupDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { useEffect } from 'react';
import useCookie from './useCookie';
import { useDialog } from '@boolti/ui';
import { Popup } from '@boolti/api';
import NoticePopupContent from '~/components/NoticePopupContent';
import EventPopupContent from '~/components/EventPopupContent';

const usePopupDialog = (popupData?: Popup) => {
const eventPopupDialog = useDialog();
const noticePopupDialog = useDialog();
const { getCookie } = useCookie();

useEffect(() => {
if (!popupData) {
return;
}
const today = new Date();
const startDate = new Date(popupData.startDate);
const endDate = new Date(popupData.endDate);
if (!(startDate <= today && today <= endDate)) {
return;
}
const hasCookie = !!getCookie('popup');

switch (popupData.type) {
case 'EVENT':
if (hasCookie) {
return;
}
eventPopupDialog.open({
content: (
<EventPopupContent
id={popupData.id}
imagePath={popupData.description}
detailPath={popupData.eventUrl}
onClose={eventPopupDialog.close}
/>
),
mobileType: 'centerPopup',
isAuto: true,
contentPadding: '0',
});
return;
case 'NOTICE':
noticePopupDialog.open({
content: (
<NoticePopupContent
title={popupData.noticeTitle as string}
description={popupData.description}
onClose={noticePopupDialog.close}
/>
),
mobileType: 'centerPopup',
isAuto: true,
contentPadding: '0',
});
return;
}
}, [popupData]);

Check warning on line 59 in apps/admin/src/hooks/usePopupDialog.tsx

View workflow job for this annotation

GitHub Actions / Build and Test

React Hook useEffect has missing dependencies: 'eventPopupDialog', 'getCookie', and 'noticePopupDialog'. Either include them or remove the dependency array
};

export default usePopupDialog;
4 changes: 4 additions & 0 deletions apps/admin/src/pages/HomePage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
queryKeys,
useLogout,
usePopup,
useQueryClient,
useSettlementBanners,
useShowList,
Expand All @@ -21,6 +22,7 @@ import { useAuthAtom } from '~/atoms/useAuthAtom';
import SettingDialogContent from '~/components/SettingDialogContent';
import { useNavigate } from 'react-router-dom';
import { useState } from 'react';
import usePopupDialog from '~/hooks/usePopupDialog';

const bannerDescription = {
REQUIRED: '공연의 정산 내역서가 도착했어요. 내역을 확인한 후 정산을 요청해 주세요.',
Expand All @@ -42,6 +44,8 @@ const HomePage = () => {
const { data: userProfileData, isLoading: isUserProfileLoading } = useUserProfile();
const { data: showList = [], isLoading: isShowListLoading } = useShowList();
const { data: settlementBanners } = useSettlementBanners();
const { data: popupData } = usePopup();
usePopupDialog(popupData);

const { imgPath, nickname = '', userCode } = userProfileData ?? {};

Expand Down
2 changes: 2 additions & 0 deletions packages/api/src/queries/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import useCastTeamList from './useCastTeamList';
import useAdminTicketList from './useAdminTicketList';
import useAdminSalesTicketList from './useAdminSalesTicketList';
import useAdminReservationSummaryV2 from './useAdminReservationSummaryV2';
import usePopup from './usePopup';
import useSuperAdminShowSettlementStatement from './useSuperAdminShowSettlementStatement';

export {
Expand Down Expand Up @@ -85,5 +86,6 @@ export {
useSuperAdminSalesTicketList,
useSuperAdminInvitationTicketList,
useSuperAdminInvitationCodeList,
usePopup,
useSuperAdminShowSettlementStatement,
};
Loading
Loading