Skip to content

Commit

Permalink
Merge pull request #918 from 42organization/GGFE-164-구매-선물-모달
Browse files Browse the repository at this point in the history
[GGFE-164] 구매 선물 모달
  • Loading branch information
hyobb109 authored Aug 7, 2023
2 parents 9726144 + 4549ac7 commit d7aeca7
Show file tree
Hide file tree
Showing 12 changed files with 319 additions and 14 deletions.
7 changes: 5 additions & 2 deletions components/modal/ModalProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import AdminEditItemModal from './admin/AdminEditItem';
import AdminEditCoinPolicyModal from './admin/AdminEditCoinPolicy';
import BuyModal from './store/purchase/BuyModal';
import GiftModal from './store/purchase/GiftModal';
import NoCoinModal from './store/purchase/NoCoinModal';

export default function ModalProvider() {
const [
Expand All @@ -45,6 +46,7 @@ export default function ModalProvider() {
penaltyId,
ISeason,
ModifyScore,
priceTag,
megaphoneInfo,
profileInfo,
itemInfo,
Expand Down Expand Up @@ -85,6 +87,9 @@ export default function ModalProvider() {
<AdminModifyScoreModal {...ModifyScore} />
) : null,
'USER-KAKAO_EDIT': <KakaoEditModal />,
'PURCHASE-BUY': priceTag ? <BuyModal {...priceTag} /> : null,
'PURCHASE-GIFT': priceTag ? <GiftModal {...priceTag} /> : null,
'PURCHASE-NO_COIN': <NoCoinModal />,
'ADMIN-MEGAPHONE_DELETE': megaphoneInfo ? (
<AdminDeleteMegaphoneModal {...megaphoneInfo} />
) : null,
Expand All @@ -98,8 +103,6 @@ export default function ModalProvider() {
'ADMIN-COINPOLICY_EDIT': coinPolicy ? (
<AdminEditCoinPolicyModal {...coinPolicy} />
) : null,
'PURCHASE-BUY': <BuyModal />,
'PURCHASE-GIFT': <GiftModal />,
};

useEffect(() => {
Expand Down
22 changes: 18 additions & 4 deletions components/modal/store/purchase/BuyModal.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,35 @@
import useBuyModal from 'hooks/modal/store/purchase/useBuyModal';
import styles from 'styles/modal/store/BuyModal.module.scss';
import { PriceTag } from 'types/modalTypes';

export default function BuyModal() {
export default function BuyModal({ product, price }: PriceTag) {
const { onPurchase, onCancel } = useBuyModal();

return (
<div className={styles.container}>
<div className={styles.phrase}>
<div className={styles.emoji}>🏓</div>
<div className={styles.emoji}>🛍️</div>
<div className={styles.message}>구매하시겠습니까?</div>
<div className={styles.itemInfo}>
<div className={styles.itemName}>
<div>아이템:</div>
<div>{product}</div>
</div>
<div className={styles.itemPrice}>
<div>가격:</div>
<div>{price}</div>
</div>
</div>
<div className={styles.warning}>
<p>⚠ 구매한 아이템은 환불이 불가합니다 ⚠</p>
</div>
</div>
<div className={styles.buttons}>
<div className={styles.negative}>
<input onClick={onCancel} type='button' value='취소' />
<input onClick={onCancel} type='button' value='아니오' />
</div>
<div className={styles.positive}>
<input onClick={onPurchase} type='button' value='확인' />
<input onClick={onPurchase} type='button' value='' />
</div>
</div>
</div>
Expand Down
37 changes: 33 additions & 4 deletions components/modal/store/purchase/GiftModal.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,50 @@
import GiftSearchBar from 'components/shop/GiftSearchBar';
import useGiftModal from 'hooks/modal/store/purchase/useGiftModal';
import { useEffect, useState } from 'react';
import styles from 'styles/modal/store/GiftModal.module.scss';
import { PriceTag } from 'types/modalTypes';

export default function GiftModal() {
// TODO: itemId도 받아오기
export default function GiftModal({ product, price }: PriceTag) {
const { onPurchase, onCancel } = useGiftModal();
const [recipient, setRecipient] = useState<string>(''); // TODO: recipient를 GiftSearchBar에서 받아오기

useEffect(() => {
console.log('recipient: ', recipient);
}, [recipient]);

return (
<div className={styles.container}>
<div className={styles.phrase}>
<div className={styles.emoji}>🏓</div>
<div className={styles.message}>선물하시겠습니까?</div>
<div className={styles.emoji}>🎁</div>
<div className={styles.message}>선물하기</div>
<div className={styles.itemInfo}>
<div className={styles.itemName}>
<div>아이템:</div>
<div>{product}</div>
</div>
<div className={styles.itemPrice}>
<div>가격:</div>
<div>{price}</div>
</div>
</div>
<GiftSearchBar recipient={recipient} setRecipient={setRecipient} />
{recipient !== '' && (
<div className={styles.recipient}>
{recipient}님에게 선물하시겠습니까?
</div>
)}
<div className={styles.warning}>
<p>⚠ 선물한 아이템은 환불 및 취소가 불가합니다 ⚠</p>
</div>
</div>
<div className={styles.buttons}>
<div className={styles.negative}>
<input onClick={onCancel} type='button' value='취소' />
</div>
{/* TODO: 보내기 버튼 클릭 시 POST */}
<div className={styles.positive}>
<input onClick={onPurchase} type='button' value='확인' />
<input onClick={onPurchase} type='button' value='보내기' />
</div>
</div>
</div>
Expand Down
26 changes: 26 additions & 0 deletions components/modal/store/purchase/NoCoinModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import useNoCoinModal from 'hooks/modal/store/purchase/useNoCoinModal';
import styles from 'styles/modal/store/NoCoinModal.module.scss';

export default function NoCoinModal() {
const { onPlay, onCancel } = useNoCoinModal();

return (
<div className={styles.container}>
<div className={styles.phrase}>
<div className={styles.emoji}>😥</div>
<div className={styles.message}>보유 코인이 부족합니다</div>
<div className={styles.details}>
💸게임에 참여하여 코인을 획득해보세요💸
</div>
</div>
<div className={styles.buttons}>
<div className={styles.negative}>
<input onClick={onCancel} type='button' value='취소' />
</div>
<div className={styles.positive}>
<input onClick={onPlay} type='button' value='게임 참여' />
</div>
</div>
</div>
);
}
72 changes: 72 additions & 0 deletions components/shop/GiftSearchBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { GoSearch } from 'react-icons/go';
import { useEffect, Dispatch, SetStateAction } from 'react';
import { IoIosCloseCircle } from 'react-icons/io';
import styles from 'styles/main/SearchBar.module.scss';
import useSearchBar from 'hooks/useSearchBar';

export default function GiftSearchBar({
recipient,
setRecipient,
}: {
recipient: string;
setRecipient: Dispatch<SetStateAction<string>>;
}) {
const {
keyword,
setKeyword,
keywordHandler,
showDropDown,
setShowDropDown,
searchResult,
searchBarRef,
handleKeyDown,
} = useSearchBar();

const handleClick = (
event: React.MouseEvent<HTMLDivElement, MouseEvent>,
intraId: string
) => {
setKeyword(intraId);
setRecipient(intraId);
setShowDropDown(false);
};

return (
<div id={styles.gift} className={styles.searchBar} ref={searchBarRef}>
<input
type='text'
onChange={keywordHandler}
onKeyDown={handleKeyDown}
onFocus={() => setShowDropDown(true)}
placeholder='선물할 유저 검색하기'
maxLength={15}
value={keyword}
/>
<div className={styles.icons}>
{keyword ? (
<span className={styles.reset} onClick={() => setKeyword('')}>
<IoIosCloseCircle />
</span>
) : (
<span>
<GoSearch />
</span>
)}
</div>
{showDropDown && keyword && (
<div className={styles.dropdown}>
{searchResult.length ? (
searchResult.map((intraId: string) => (
// TODO: 선택한 유저 아이디를 FOR '검색한 사람 아이디' 부분에 넣어주기
<div key={intraId} onClick={(e) => handleClick(e, intraId)}>
{intraId}
</div>
))
) : (
<div>검색 결과가 없습니다.</div>
)}
</div>
)}
</div>
);
}
28 changes: 26 additions & 2 deletions components/shop/ItemCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,32 @@ import { modalState } from 'utils/recoil/modal';
export default function ItemCard({ item }: { item: Item }) {
const setModal = useSetRecoilState<Modal>(modalState);

// TODO: 상점 페이지에서 코인 정보 받아오기
const coin = 1000;

const handleGift = () => {
setModal({
modalName: 'PURCHASE-GIFT',
priceTag: {
product: item.itemName,
price: item.salePrice,
},
});
};

const handleBuying = () => {
setModal({
modalName: 'PURCHASE-BUY',
priceTag: {
product: item.itemName,
price: item.salePrice,
},
});
};

const handleNoCoin = () => {
setModal({
modalName: 'PURCHASE-NO_COIN',
});
};

Expand Down Expand Up @@ -49,10 +67,16 @@ export default function ItemCard({ item }: { item: Item }) {
<p>{item.content}</p>
</div>
<div className={styles.buttons}>
<button className={styles.gift} onClick={handleGift}>
<button
className={styles.gift}
onClick={item.salePrice < coin ? handleGift : handleNoCoin}
>
선물하기
</button>
<button className={styles.buy} onClick={handleBuying}>
<button
className={styles.buy}
onClick={item.salePrice < coin ? handleBuying : handleNoCoin}
>
구매하기
</button>
</div>
Expand Down
20 changes: 20 additions & 0 deletions hooks/modal/store/purchase/useNoCoinModal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useSetRecoilState } from 'recoil';
import { modalState } from 'utils/recoil/modal';
import router from 'next/router';

const useNoCoinModal = () => {
const setModal = useSetRecoilState(modalState);

const onPlay = () => {
setModal({ modalName: null });
router.push(`/match`);
};

const onCancel = () => {
setModal({ modalName: null });
};

return { onPlay, onCancel };
};

export default useNoCoinModal;
11 changes: 11 additions & 0 deletions styles/main/SearchBar.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,14 @@
border-radius: 0 0 $mini-radius $mini-radius;
}
}

#gift {
input {
width: calc(100% - 1.5rem);
}
.icons {
span {
font-size: 0.9rem;
}
}
}
31 changes: 30 additions & 1 deletion styles/modal/store/BuyModal.module.scss
Original file line number Diff line number Diff line change
@@ -1,19 +1,48 @@
@import 'styles/common.scss';

.container {
@include modalContainer('SKYPINK');
@include modalContainer('PINKVIOLET');
}

.phrase {
@include modal-phrase;
color: rgba(49, 47, 49, 1);
margin-bottom: 0.875rem;
.message {
font-size: 1.125rem;
font-family: 'NanumSquare_acR', sans-serif;
font-weight: 700;
letter-spacing: 0.04rem;
line-height: 200%;
}
.itemInfo {
width: 80%;
margin-left: 10%;
margin-top: 0.875rem;
font-size: 0.875rem;
font-family: 'NanumSquare_acR', sans-serif;
font-weight: 700;
letter-spacing: 0.04rem;
line-height: 150%;
color: #666666;
.itemName {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.itemPrice {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
}
.warning {
font-size: 0.875rem;
font-family: 'NanumSquare_acR', sans-serif;
font-weight: 700;
letter-spacing: 0.04rem;
color: #ff0000;
}
}

.buttons {
Expand Down
Loading

0 comments on commit d7aeca7

Please sign in to comment.