Skip to content

Commit

Permalink
Merge pull request #914 from 42organization/GGFE-141-CoinAnimation-CSS
Browse files Browse the repository at this point in the history
[GGFE-141] coin animation css
  • Loading branch information
parksangmin1543 authored Aug 7, 2023
2 parents d7aeca7 + 096b2a2 commit 074943b
Show file tree
Hide file tree
Showing 24 changed files with 561 additions and 42 deletions.
7 changes: 3 additions & 4 deletions components/Layout/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { useRouter } from 'next/router';
import { useEffect } from 'react';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { useRecoilValue } from 'recoil';
import { colorModeState } from 'utils/recoil/colorMode';
import { loginState } from 'utils/recoil/login';
import { userState } from 'utils/recoil/layout';
import { openCurrentMatchState } from 'utils/recoil/match';
import Statistics from 'pages/statistics';
Expand Down Expand Up @@ -34,10 +32,11 @@ export default function AppLayout({ children }: AppLayoutProps) {
const openCurrentMatch = useRecoilValue(openCurrentMatchState);

useAxiosResponse();
useGetUserSeason();
useGetUserSeason(presentPath);
useSetAfterGameModal();
useLiveCheck(presentPath);
useAnnouncementCheck(presentPath);

const onClickMatch = () => {
router.replace('/');
router.push(`/match`);
Expand Down
8 changes: 2 additions & 6 deletions components/LoginChecker.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Login from 'pages/login';
import WelcomeModal from './modal/event/WelcomeModal';
import styles from 'styles/Layout/Layout.module.scss';

import useLoginCheck from 'hooks/Login/useLoginCheck';
Expand All @@ -8,13 +7,10 @@ interface LoginCheckerProps {
}

export default function LoginChecker({ children }: LoginCheckerProps) {
const [isLoading, loggedIn, firstVisited] = useLoginCheck();
const [isLoading, loggedIn] = useLoginCheck();

return loggedIn ? (
<>
{firstVisited && <WelcomeModal />}
{children}
</>
<>{children}</>
) : (
<div className={styles.appContainer}>
<div className={styles.background}>{!isLoading && <Login />}</div>
Expand Down
38 changes: 38 additions & 0 deletions components/modal/CoinAnimation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';
import styles from 'styles/modal/CoinAnimation.module.scss';
import CoinIcon from './CoinIcon';

interface amountProps {
amount: number;
}

export default function CoinAnimation({ amount }: amountProps) {
const tilts = ['l', 'r', 'none'];

const moneyamount = Array.from({ length: amount }).map((_, index) => {
const randomTilt = tilts[Math.floor(Math.random() * 3)];
const stackStyle =
randomTilt === 'none'
? styles.stack
: randomTilt === 'l'
? styles.stackl
: styles.stackr;

return (
<div key={index} className={`${stackStyle} ${styles.fall}`}>
<svg className={`${styles.coin}`}>
<CoinIcon />
</svg>
</div>
);
});

return (
<div id='stage-coins' className={`${styles.stageCoins}`}>
<div className={`${styles.stage}`}>
<div className={`${styles.column}`}>{moneyamount}</div>
<div className={`${styles.appear}`}>+{amount}</div>
</div>
</div>
);
}
38 changes: 38 additions & 0 deletions components/modal/CoinIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';

const CoinIcon = () => (
<svg
xmlns='http://www.w3.org/2000/svg'
xmlnsXlink='http://www.w3.org/1999/xlink'
viewBox='0 0 194 120'
>
<defs>
<symbol viewBox='0 0 194 120' id='icon-coin'>
<g>
<g>
<path
fill='#ffdc00'
d='M188.5 43.2C185.4 23.3 145.6 7.6 97 7.6 46.4 7.6 5.3 24.7 5.3 45.7c0 0 0 20.3 0 28.6 0 21 41.1 38.1 91.7 38.1s91.7-17.1 91.7-38.1c0-9.2 0-31 0-31C188.6 43.3 188.6 43.3 188.5 43.2z'
/>
</g>
</g>
<path
fill='none'
stroke='#000000'
strokeWidth='0.5'
strokeMiterlimit='10'
d='M97 60'
/>
<g>
<path d='M87.8 35.1c0 1.1 0.5 2 1.6 2.7 0.9 0.6 2.4 1.2 4.6 1.9l0.8 0.2v-8.7l-0.7 0.1C89.9 31.7 87.8 33 87.8 35.1zM93.5 38.3c-1.6-0.5-2.8-1-3.5-1.5 -0.7-0.5-1-1-1-1.7 0-1.3 1.5-2.2 4.6-2.6V38.3z' />
<path d='M112.9 44.4c-2.4-1.1-6.5-2.4-12.1-3.9v-8c4.6 0.3 9.2 1.1 13.5 2.4l0.4 0.1 4.9-8.3 -0.7-0.2c-5.3-1.6-11.4-2.6-18.1-2.9v-4.6h-7.3v4.8c-5.8 0.5-10.5 1.6-13.8 3.6 -3.6 2-5.4 4.6-5.4 7.8 0 3.1 1.3 5.6 3.9 7.6 2.5 1.9 6.8 3.7 12.8 5.4l2.6 0.7v8.5c-2.7-0.2-5.7-0.6-9.1-1.2 -3.6-0.7-6.7-1.5-9.2-2.3l-0.8-0.3v9.5l0.4 0.1c5.4 1.7 11.7 2.6 18.7 2.7v6.2h7.3v-6.4c5.9-0.4 10.7-1.6 14.1-3.6 3.6-2.1 5.5-4.9 5.5-8.4 0-2-0.6-3.7-1.9-5.2C117.3 46.8 115.4 45.5 112.9 44.4zM114.3 60.8c-3.3 1.9-8.1 3.1-14.1 3.5l-0.6 0v6.3h-4.9v-6.2l-0.6 0c-6.9-0.1-13.2-0.9-18.5-2.5V55c2.4 0.8 5.3 1.5 8.6 2.1 3.7 0.7 7 1.1 9.9 1.2l0.6 0V47.7l-3.4-0.9c-5.8-1.6-10-3.3-12.3-5.1 -2.3-1.8-3.4-3.9-3.4-6.7 0-2.7 1.6-4.9 4.8-6.7 3.3-1.9 8-3 13.9-3.4l0.6 0V20h4.9v4.6l0.6 0c6.5 0.2 12.4 1.1 17.6 2.6l-3.6 6.2c-4.5-1.3-9.2-2-13.9-2.3l-0.6 0v10.2l0.4 0.1c5.8 1.5 9.9 2.9 12.3 4 2.4 1.1 4.1 2.3 5.2 3.6 1.1 1.3 1.6 2.7 1.6 4.4C119.2 56.5 117.6 58.9 114.3 60.8z' />
<path d='M105.2 51.2c-1-0.6-2.6-1.3-4.8-2L99.6 49v9.2l0.7-0.1c4.4-0.5 6.6-1.9 6.6-4.2C106.9 52.8 106.3 51.9 105.2 51.2zM100.8 56.9v-6.2c1.7 0.6 2.9 1.1 3.7 1.6 0.8 0.5 1.2 1 1.2 1.7C105.7 55.4 104.1 56.4 100.8 56.9z' />
<path d='M97 7C46.1 7 4.7 24.4 4.7 45.7v28.6C4.7 95.6 46.1 113 97 113s92.3-17.4 92.3-38.7V45.7C189.3 24.4 147.9 7 97 7zM19 93.7C10.7 88 5.9 81.4 5.9 74.3V51.9c2 5.3 6.6 10.1 13.1 14.5V93.7zM28.5 99c-3.1-1.4-5.8-3-8.3-4.6V67.1c2.5 1.6 5.4 3.1 8.4 4.5L28.5 99zM188.1 74.3c0 20.7-40.9 37.5-91.1 37.5 -26.6 0-50.6-4.7-67.3-12.3l0.1-27.4C46.7 79.7 70.5 84.4 97 84.4c45.9 0 84-14.1 91.1-32.5V74.3zM97 83.2c-50.2 0-91.1-16.8-91.1-37.5S46.8 8.2 97 8.2s91.1 16.8 91.1 37.5S147.2 83.2 97 83.2z' />
</g>
</symbol>
</defs>
<use xlinkHref='#icon-coin' />
</svg>
);

export default CoinIcon;
8 changes: 8 additions & 0 deletions components/modal/ModalProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import AdminSeasonEdit from './admin/SeasonEdit';
import FeedbackDetailModal from './admin/FeedbackDetailModal';
import DeletePenaltyModal from './admin/DeletePenaltyModal';
import AdminModifyScoreModal from './admin/AdminModifyScoreModal';
import CoinChangeModal from './statChange/CoinChangeModal';
import WelcomeModal from './event/WelcomeModal';

import styles from 'styles/modal/Modal.module.scss';
import AdminDeleteMegaphoneModal from './admin/AdminDeleteMegaphoneModal';
import AdminDeleteProfileModal from './admin/AdminDeleteProfile';
Expand All @@ -46,6 +49,7 @@ export default function ModalProvider() {
penaltyId,
ISeason,
ModifyScore,
CoinResult,
priceTag,
megaphoneInfo,
profileInfo,
Expand Down Expand Up @@ -87,6 +91,10 @@ export default function ModalProvider() {
<AdminModifyScoreModal {...ModifyScore} />
) : null,
'USER-KAKAO_EDIT': <KakaoEditModal />,
'COIN-ANIMATION': CoinResult ? <CoinChangeModal {...CoinResult} /> : null,
'EVENT-WELCOME': <WelcomeModal />,
'PURCHASE-BUY': <BuyModal />,
'PURCHASE-GIFT': <GiftModal />,
'PURCHASE-BUY': priceTag ? <BuyModal {...priceTag} /> : null,
'PURCHASE-GIFT': priceTag ? <GiftModal {...priceTag} /> : null,
'PURCHASE-NO_COIN': <NoCoinModal />,
Expand Down
76 changes: 60 additions & 16 deletions components/modal/event/WelcomeModal.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,82 @@
import { useSetRecoilState } from 'recoil';
import { firstVisitedState } from 'utils/recoil/modal';
import { Modal } from 'types/modalTypes';
import useAxiosGet from 'hooks/useAxiosGet';
import { useMockAxiosGet } from 'hooks/useAxiosGet';
import { useState, useEffect } from 'react';
import { instance } from 'utils/axios';
import { CoinResult } from 'types/coinTypes';
import { modalState } from 'utils/recoil/modal';
import { errorState } from 'utils/recoil/error';
import styles from 'styles/modal/event/WelcomeModal.module.scss';
import modalStyles from 'styles/modal/Modal.module.scss';

export default function WelcomeModal() {
const setFirstVisited = useSetRecoilState(firstVisitedState);
const setModal = useSetRecoilState<Modal>(modalState);
const [coin, setCoin] = useState<CoinResult>();
const setError = useSetRecoilState(errorState);

const content = {
title: 'Welcome!',
message:
'42GG에 오신걸 환영합니다.\n당신의 행복한 탁구 생활을\n응원합니다! 총총총...',
};

/* const postCoinHandler = async() => {
try {
const res = await instance.post(
`/pingpong/users/attendance`
);
setCoin(res.data);
} catch (error) {
setError('SM01');
}
};
useEffect(() => {
postCoinHandler();
}, []); */

const getCoinHandler = useMockAxiosGet({
url: `/users/attendance`,
setState: setCoin,
err: 'SM01',
type: 'setError',
});

useEffect(() => {
getCoinHandler();
}, []);

const openPageManual = () => {
window.open(
'https://github.com/42organization/42arcade.gg.client/wiki/42gg.kr--%ED%8E%98%EC%9D%B4%EC%A7%80-%EA%B0%80%EC%9D%B4%EB%93%9C'
);
};

const closeModalBackdropHandler = (e: React.MouseEvent) => {
if (e.target instanceof HTMLDivElement && e.target.id === 'modalOutside') {
setFirstVisited(false);
}
if (!coin) return null;

const openAttendanceCoin = () => {
setModal({
modalName: 'COIN-ANIMATION',
CoinResult: {
afterCoin: coin?.afterCoin,
beforeCoin: coin?.beforeCoin,
coinIncrement: coin?.coinIncrement,
},
});
};

const closeModalButtonHandler = () => {
setFirstVisited(false);
const openStatChangeModal = () => {
setModal({
modalName: 'FIXED-STAT',
exp: {
gameId: 0,
mode: 'RANK',
},
});
};

return (
<div
className={modalStyles.backdrop}
id='modalOutside'
onClick={closeModalBackdropHandler}
>
<div>
<div className={styles.container}>
<div className={styles.phrase}>
<div className={styles.emoji}></div>
Expand All @@ -49,9 +93,9 @@ export default function WelcomeModal() {
</div>
<div className={styles.positive}>
<input
onClick={closeModalButtonHandler}
onClick={openStatChangeModal}
type='button'
value='홈으로'
value='출석하기'
/>
</div>
</div>
Expand Down
30 changes: 30 additions & 0 deletions components/modal/statChange/CoinChangeModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { useSetRecoilState } from 'recoil';
import { modalState } from 'utils/recoil/modal';
import { reloadMatchState } from 'utils/recoil/match';
import { CoinResult } from 'types/coinTypes';
import CoinAnimation from '../CoinAnimation';
import CoinStat from 'components/modal/statChange/CoinStatChange';
import styles from 'styles/modal/CoinChangeModal.module.scss';

export default function CoinChangeModal(coin: CoinResult) {
const setModal = useSetRecoilState(modalState);

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

return (
<div>
<div
className={`${styles.fixedContainer} ${styles.front}`}
onClick={closeModal}
/>
<div className={styles.container}>
<div className={styles.emoji}>💲</div>
<CoinStat before={coin?.beforeCoin} after={coin?.afterCoin} />
<CoinAnimation amount={coin?.coinIncrement} />
<div className={styles.guide}>화면을 클릭해주세요!</div>
</div>
</div>
);
}
32 changes: 32 additions & 0 deletions components/modal/statChange/CoinStatChange.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { sleep } from 'utils/sleep';
import { useEffect, useState } from 'react';
import styles from 'styles/modal/CoinChangeAnimation.module.scss';

interface CoinChangeProps {
after: number;
before: number;
}

export default function CoinStatChange({ after, before }: CoinChangeProps) {
const [coin, setCoin] = useState<number>(before);

useEffect(() => {
CoinChangeAnimation();
}, []);

const CoinChangeAnimation = () => {
const toAdd = 1;
for (let i = before; i < after; i++) {
sleep(i * 500).then(() => setCoin((thisCoin) => thisCoin + toAdd));
}
};

return (
<div className={styles.coinWrap}>
<div className={styles.coin}>
<span>{coin}&nbsp;</span>
<span>[{(after >= 0 ? '+' : '') + (after - before)}]</span>
</div>
</div>
);
}
23 changes: 22 additions & 1 deletion components/modal/statChange/StatChangeModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { reloadMatchState } from 'utils/recoil/match';
import ExpStat from './ExpStat';
import PppStat from 'components/modal/statChange/PppStat';
import useAxiosGet from 'hooks/useAxiosGet';
import { useMockAxiosGet } from 'hooks/useAxiosGet';
import { CoinResult } from 'types/coinTypes';
import styles from 'styles/modal/afterGame/StatChangeModal.module.scss';

export default function StatChangeModal({ gameId, mode }: Exp) {
Expand All @@ -17,20 +19,39 @@ export default function StatChangeModal({ gameId, mode }: Exp) {
getExpHandler();
}, []);

const getExpHandler = useAxiosGet({
/* const getExpHandler = useAxiosGet({
url: `/pingpong/games/${gameId}/result/${mode?.toLowerCase()}`,
setState: setStat,
err: 'KP03',
type: 'setError',
}); */

const getExpHandler = useMockAxiosGet({
url: `/games/normal`,
setState: setStat,
err: 'KP03',
type: 'setError',
});

const closeModal = () => {
setReloadMatch(true);
setModal({ modalName: null });
openCoin();
};

if (!stat) return null;

const openCoin = () => {
setModal({
modalName: 'COIN-ANIMATION',
CoinResult: {
afterCoin: stat.afterCoin,
beforeCoin: stat.beforeCoin,
coinIncrement: stat.coinIncrement,
},
});
};

return (
<div>
<div
Expand Down
Loading

0 comments on commit 074943b

Please sign in to comment.