Skip to content

Commit

Permalink
RSVP
Browse files Browse the repository at this point in the history
  • Loading branch information
hhhello0507 committed Jan 19, 2025
1 parent c911a1a commit fec9643
Show file tree
Hide file tree
Showing 13 changed files with 363 additions and 14 deletions.
2 changes: 1 addition & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ function App() {
<Route path={'wedding/:url'} element={<WeddingPage/>}/>
<Route path={'sample'} element={(
<div style={{display: 'flex', justifyContent: 'center'}}>
<TemplateComponent wedding={dummyWedding}/>
<TemplateComponent wedding={dummyWedding} isPreview={true}/>
</div>
)}/>
</Routes>
Expand Down
38 changes: 35 additions & 3 deletions src/component/template/TemplateComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useRef} from 'react';
import React, {useRef, useState} from 'react';
import Wedding from "@remote/value/Wedding";
import * as S from '@src/component/template/TemplateComponent.style';
import MoneyInfoTemplate from "@src/component/template/component/MoneyInfoTemplate";
Expand All @@ -16,24 +16,34 @@ import {DDayStyle} from "@src/component/template/component/weddingday/DDay";
import InvitationLetterTemplate, {
InvitationLetterStyle
} from "@src/component/template/component/InvitationLetterTemplate";
import RsvpDialog from "@src/component/template/dialog/rsvp/RsvpDialog";
import Cookies from "js-cookie";
import CreateRsvpDialog from "@src/component/template/dialog/rsvp/CreateRsvpDialog";

interface Template1Props {
wedding: Wedding;
isPreview?: boolean;
onRefresh?: () => void;
}

function TemplateComponent(
{
wedding,
isPreview = false,
onRefresh
}: Template1Props
) {
const [showRsvpDialog, setShowRsvpDialog] = useState(
isPreview ? false : Cookies.get(`hide_RsvpDialog_${wedding.url}`) === undefined
);
const [showCreateRsvpDialog, setShowCreateRsvpDialog] = useState(false);
const {templateColor, templateFont, templateFontSize} = wedding.template;
const rootRef = useRef<HTMLDivElement>(null);

(() => {
const addFontSize = templateFontSizeRecord[templateFontSize].addFontSize;
increaseFontSize(rootRef, addFontSize);
Cookies.remove('hide_RsvpDialog')
})();

const slideStyle: Record<TemplateName, GallerySlideStyle | undefined> = {
Expand All @@ -53,7 +63,7 @@ function TemplateComponent(
템플릿5: 'style2',
템플릿6: 'style1',
}

const invitationLetterStyle: Record<TemplateName, InvitationLetterStyle> = {
템플릿1: 'style1',
템플릿2: 'style1',
Expand Down Expand Up @@ -105,9 +115,31 @@ function TemplateComponent(
baseInfo={wedding.baseInfo}
guestComments={wedding.guestCommentList}
guestComment={wedding.guestComment}
onRefresh={onRefresh ?? (() => {})}
onRefresh={onRefresh ?? (() => {
})}
/>
<FooterTemplate background={templateColor}/>
{showRsvpDialog && (
<RsvpDialog
url={wedding.url}
baseInfo={wedding.baseInfo}
weddingSchedule={wedding.weddingSchedule}
weddingPlace={wedding.weddingPlace}
rsvp={wedding.rsvp}
onConfirm={() => {
setShowRsvpDialog(false);
setShowCreateRsvpDialog(true);
}}
dismiss={() => setShowRsvpDialog(false)}
/>
)}
{showCreateRsvpDialog && (
<CreateRsvpDialog
url={wedding.url}
rsvp={wedding.rsvp}
dismiss={() => setShowCreateRsvpDialog(false)}
/>
)}
</S.container>
);
}
Expand Down
6 changes: 3 additions & 3 deletions src/component/template/component/GuestCommentsTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import {trimString} from "@util/string.util";
import Button from "@designsystem/component/button";
import BaseInfo from "@remote/value/BaseInfo";
import GuestComment from "@remote/value/GuestComment";
import RemoveGuestCommentDialog from "@src/component/template/dialog/RemoveGuestCommentDialog";
import GuestCommentsDetailDialog from "@src/component/template/dialog/GuestCommentsDetailDialog";
import CreateGuestCommentDialog from "@src/component/template/dialog/CreateGuestCommentDialog";
import RemoveGuestCommentDialog from "@src/component/template/dialog/guestcomment/RemoveGuestCommentDialog";
import GuestCommentsDetailDialog from "@src/component/template/dialog/guestcomment/GuestCommentsDetailDialog";
import CreateGuestCommentDialog from "@src/component/template/dialog/guestcomment/CreateGuestCommentDialog";

interface GuestCommentsTemplateProps {
templateColor: string;
Expand Down
51 changes: 51 additions & 0 deletions src/component/template/dialog/rsvp/ConfirmCreateRsvpDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import styled from "styled-components";
import BaseDialog, {applyBaseDialogContent} from "@designsystem/component/dialog/baseDialog";
import colors from "@designsystem/foundation/colors";
import {Column, Row} from "@designsystem/component/flexLayout";
import Text from "@designsystem/component/text";
import Button from "@designsystem/component/button";

interface ConfirmRsvpDialogProps {
dismiss: () => void;
onConfirm: () => void;
}

function ConfirmCreateRsvpDialog(
{
dismiss,
onConfirm
}: ConfirmRsvpDialogProps
) {
return (
<BaseDialog dismiss={dismiss}>
<S.container>
<Column gap={4} $alignItems={'center'}>
<Text type={'h6'}>참석의사 전달</Text>
<Text type={'caption1'}>참석의사 전달시 수정이 불가능합니다</Text>
</Column>
<Row gap={12} $alignSelf={'stretch'}>
<Button text={'취소'} role={'assistive'} onClick={dismiss} style={{flex: 1}}/>
<Button text={'확인'} onClick={onConfirm} style={{flex: 1}}/>
</Row>
</S.container>
</BaseDialog>
);
}

const S = {
container: styled.div`
display: flex;
flex-direction: column;
gap: 48px;
${applyBaseDialogContent()};
border-radius: 12px;
padding: 44px 36px;
align-items: center;
background: ${colors.white};
max-width: 388px;
width: 90vw;
`
}

export default ConfirmCreateRsvpDialog;
175 changes: 175 additions & 0 deletions src/component/template/dialog/rsvp/CreateRsvpDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import React, {useRef, useState} from 'react';
import BaseDialog, {applyBaseDialogContent} from "@designsystem/component/dialog/baseDialog";
import styled from "styled-components";
import colors from "@designsystem/foundation/colors";
import {Column, Row} from "@designsystem/component/flexLayout";
import Spacer from "@designsystem/component/spacer";
import Text from "@designsystem/component/text";
import Icon, {IconType} from "@designsystem/foundation/icon";
import Button from "@designsystem/component/button";
import OptionSegmentedButton from "@page/invitation/design/component/OptionSegmentedButton";
import OptionTextField from "@page/invitation/design/component/OptionTextField";
import weddingApi from "@remote/api/WeddingApi";
import GuestType from "@remote/enumeration/GuestType";
import Rsvp from "@remote/value/Rsvp";
import ConfirmCreateRsvpDialog from "@src/component/template/dialog/rsvp/ConfirmCreateRsvpDialog";

interface CreateRsvpDialogProps {
url: string;
rsvp: Rsvp;
dismiss: () => void;
}

function CreateRsvpDialog(
{
url,
rsvp,
dismiss
}: CreateRsvpDialogProps
) {
const [guestType, setGuestType] = useState(0);
const [isAttend, setIsAttend] = useState(0);
const [isMeal, setIsMeal] = useState(0);
const [showConfirmCreateRsvpDialog, setShowConfirmCreateRsvpDialog] = useState(false);

const guestNameRef = useRef<HTMLInputElement>(null);
const guestPhoneRef = useRef<HTMLInputElement>(null);
const guestCntRef = useRef<HTMLInputElement>(null);
const guestCommentRef = useRef<HTMLInputElement>(null);

const createRsvp = async () => {
const guestName = guestNameRef.current!!;
const guestPhone = guestPhoneRef.current!!;
const guestCnt = guestCntRef.current!!;
const guestComment = guestCommentRef.current!!;

if (guestName.value === '') {
alert('참석자 성함을 입력해 주세요');
return;
}

if (guestPhone.value === '' && rsvp.attendPhoneStatus) {
alert('연락처를 입력해 주세요');
return;
}

if (guestCnt.value === '' && rsvp.attendGuestCntStatus) {
alert('동행 인원을 입력해 주세요');
return;
}

await weddingApi.createRsvp({
url,
guestType: guestType === 0 ? GuestType.GROOM : GuestType.BRIDE,
isAttend: isAttend === 0,
isMeal: isMeal === 0,
guestName: guestName.value,
guestPhone: guestPhone.value,
guestCnt: Number(guestCnt.value),
guestComment: guestComment.value,
});
dismiss();
};

return (
<BaseDialog dismiss={dismiss}>
<S.container>
<Row $alignItems={'center'} padding={'24px 0'} style={{position: 'relative'}}>
<Spacer/>
<Text type={'p2'}>참석 의사 전달</Text>
<Spacer/>
<Icon
type={IconType.CrossLine}
tint={colors.g600}
size={20}
style={{
cursor: 'pointer',
right: 32,
position: 'absolute'
}}
onClick={dismiss}
/>
</Row>
<Column gap={36} padding={'36px 40px 0 40px'} $alignItems={'stretch'}>
<Column gap={28} $alignItems={'stretch'}>
<Column gap={4} $alignItems={'stretch'}>
<Text type={'p5'}>어느 분의 하객인가요?</Text>
<OptionSegmentedButton selectedIndex={guestType} items={['신랑', '신부']}
onClickItem={index => {
setGuestType(index);
}}/>
</Column>
<Column gap={4} $alignItems={'stretch'}>
<Text type={'p5'}>참석 여부를 선택해 주세요.</Text>
<OptionSegmentedButton selectedIndex={isAttend} items={['참석할게요', '참석이 어려워요']}
onClickItem={index => {
setIsAttend(index);
}}/>
</Column>
{rsvp.attendMealStatus && (
<Column gap={4} $alignItems={'stretch'}>
<Text type={'p5'}>식사 여부를 선택해 주세요.</Text>
<OptionSegmentedButton
selectedIndex={isMeal} items={['식사함', '식사안함']}
onClickItem={index => {
setIsMeal(index);
}}
/>
</Column>
)}
<Row gap={18} $alignItems={'center'}>
<Text type={'p5'} style={{width: 75}}>참석자 성함</Text>
<OptionTextField ref={guestNameRef} placeholder={'참석자 본인 성함'} style={{flex: 1}}/>
</Row>
{rsvp.attendPhoneStatus && (
<Row gap={18} $alignItems={'center'}>
<Text type={'p5'} style={{width: 75}}>연락처</Text>
<OptionTextField ref={guestPhoneRef} placeholder={'- 없이 입력'} style={{flex: 1}}/>
</Row>
)}
{rsvp.attendGuestCntStatus && (
<Row gap={18} $alignItems={'center'}>
<Text type={'p5'} style={{width: 75}}>동행 인원</Text>
<OptionTextField ref={guestCntRef} placeholder={'본인 제외한 추가 참석 인원'} fieldProps={{
defaultValue: 0,
type: 'number'
}} style={{flex: 1}}/>
</Row>
)}
{rsvp.attendEtcStatus && (
<Column gap={4} $alignItems={'stretch'}>
<Text type={'p5'}>추가로 전달할 내용을 입력해 주세요.</Text>
<OptionTextField ref={guestCommentRef} autoWidth={false} placeholder={'내용 입력'}/>
</Column>
)}
</Column>
<Button text={'참석의사 전달하기'} onClick={() => setShowConfirmCreateRsvpDialog(true)}/>
</Column>
</S.container>
{showConfirmCreateRsvpDialog && (
<ConfirmCreateRsvpDialog
dismiss={() => setShowConfirmCreateRsvpDialog(false)}
onConfirm={createRsvp}
/>
)}
</BaseDialog>
);
}

const S = {
container: styled.div`
display: flex;
flex-direction: column;
max-width: 436px;
width: 100vw;
max-height: 100vh;
overflow-y: hidden;
align-items: stretch;
background: ${colors.white};
padding-bottom: 36px;
border-radius: 4px;
${applyBaseDialogContent()};
`
}

export default CreateRsvpDialog;
Loading

0 comments on commit fec9643

Please sign in to comment.