diff --git a/packages/web-domains/package.json b/packages/web-domains/package.json index b24f0b4d..4e6d142a 100644 --- a/packages/web-domains/package.json +++ b/packages/web-domains/package.json @@ -24,6 +24,7 @@ "@tanstack/react-query": "^5.50.1", "@toss/use-overlay": "^1.4.0", "axios": "^1.7.2", + "react-canvas-confetti": "^2.0.7", "react-copy-to-clipboard": "^5.1.0", "react-countdown": "^2.3.5", "react-hook-form": "^7.52.1" diff --git a/packages/web-domains/src/common/animates/Confetti.tsx b/packages/web-domains/src/common/animates/Confetti.tsx new file mode 100644 index 00000000..af396407 --- /dev/null +++ b/packages/web-domains/src/common/animates/Confetti.tsx @@ -0,0 +1,52 @@ +import { colors } from '@sds/theme'; +import { CSSProperties } from 'react'; +import Fireworks from 'react-canvas-confetti/dist/presets/fireworks'; + +interface ConfettiProps { + position: { + top: number; + left: number; + }; + width?: number; + height?: number; +} + +export const Confetti = (props: ConfettiProps) => { + const { + position: { top, left }, + width, + height, + } = props; + + const canvasStyles: CSSProperties = { + width: width ?? '100%', + height: height ?? '100%', + zIndex: '3', + position: 'absolute', + top, + left, + }; + + const decorateOptions = (originalOptions: any) => { + return { + ...originalOptions, + particleCount: 100, // 조각 개수 설정 + spread: 100, // 퍼짐 정도 설정 + startVelocity: 50, // 초기 속도 설정 + ticks: 200, // 애니메이션 지속 시간 설정 + origin: { x: 0.5, y: 0.7 }, // 발사 위치 설정 + shapes: ['square', 'circle', 'square'], // 이미지 배열을 shapes로 설정 + gravity: 0.8, // 중력 설정 + scalar: 1.5, // 색종이 크기 + colors: [colors.primary500, colors.quaternary500, colors.secondary500, colors.tertiary500], + }; + }; + + return ( + + ); +}; diff --git a/packages/web-domains/src/common/animates/index.ts b/packages/web-domains/src/common/animates/index.ts new file mode 100644 index 00000000..56463932 --- /dev/null +++ b/packages/web-domains/src/common/animates/index.ts @@ -0,0 +1 @@ +export { Confetti } from './Confetti'; diff --git a/packages/web-domains/src/common/index.ts b/packages/web-domains/src/common/index.ts index 88e81a3d..22ed6e9f 100644 --- a/packages/web-domains/src/common/index.ts +++ b/packages/web-domains/src/common/index.ts @@ -5,3 +5,4 @@ export { RootLayout } from './layout/RootLayout'; export { GlobalStyle } from './styles/GlobalStyles'; export { getWebDomain } from './utils/getWebDomain'; export * from './components/Error'; +export * from './animates'; diff --git a/packages/web-domains/src/new-meeting/features/new-meeting-closing/components/ClosingMessage.tsx b/packages/web-domains/src/new-meeting/features/new-meeting-closing/components/ClosingMessage.tsx index 04f7fb3d..8240b672 100644 --- a/packages/web-domains/src/new-meeting/features/new-meeting-closing/components/ClosingMessage.tsx +++ b/packages/web-domains/src/new-meeting/features/new-meeting-closing/components/ClosingMessage.tsx @@ -1,63 +1,60 @@ -import { Txt } from '@sambad/sds/components'; +import { If } from '@sambad/react-utils'; +import { Skeleton, Txt } from '@sambad/sds/components'; import { colors, size } from '@sambad/sds/theme'; -import Image from 'next/image'; -import ClosingBackground from '../../../common/assets/images/closing-background.png'; +import { Confetti } from '@/common'; + +import { useGetMeetingNameService } from '../services/useGetMeetingNameService'; interface ClosingMessageProps { - name?: string; + inviteCode: string; } -const ClosingMessage = (props: ClosingMessageProps) => { - const { name } = props; +export const ClosingMessage = (props: ClosingMessageProps) => { + const { inviteCode } = props; - if (!name) { - null; - } + const { data, isLoading, isSuccess } = useGetMeetingNameService({ inviteCode }); return ( -
-
- {name && ( - - {name} - - )} - - 모임을 만들었어요! - - - 이제 모임원을 초대해보세요! - -
- + <> + + +
- background-image +
+ + + + + {data?.name && ( + + {data.name} + + )} + + + 모임을 만들었어요! + + + 이제 모임원을 초대해보세요! + +
-
+ ); }; - -export default ClosingMessage; diff --git a/packages/web-domains/src/new-meeting/features/new-meeting-closing/containers/NewMeetingClosingContainer.tsx b/packages/web-domains/src/new-meeting/features/new-meeting-closing/containers/NewMeetingClosingContainer.tsx index 49c1bc17..203e6572 100644 --- a/packages/web-domains/src/new-meeting/features/new-meeting-closing/containers/NewMeetingClosingContainer.tsx +++ b/packages/web-domains/src/new-meeting/features/new-meeting-closing/containers/NewMeetingClosingContainer.tsx @@ -6,8 +6,7 @@ import Image from 'next/image'; import Character from '../../../common/assets/images/meeting-character.png'; import { InviteCodeShareButton } from '../components/Button/InviteCodeShareButton'; -import ClosingMessage from '../components/ClosingMessage'; -import { useGetMeetingNameService } from '../services/useGetMeetingNameService'; +import { ClosingMessage } from '../components/ClosingMessage'; interface NewMeetingClosingContainerProps { inviteCode: string; @@ -16,8 +15,6 @@ interface NewMeetingClosingContainerProps { const NewMeetingClosingContainer = (props: NewMeetingClosingContainerProps) => { const { inviteCode } = props; - const { data } = useGetMeetingNameService({ inviteCode }); - return (
{ justifyContent: 'center', }} > - +
{ const { inviteCode } = props; - const { data } = useGetMeetingName({ inviteCode }); + const { data, isLoading, isSuccess } = useGetMeetingName({ inviteCode }); return ( -
-
+ + + +
- {data?.name && ( - - {data?.name} +
+ + + + + {data?.name && ( + + {data?.name} + + )} + + + 가입이 완료되었어요! - )} - - 가입이 완료되었어요! - +
background -
- character -
+ + ); }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 646dea32..cb946801 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -335,6 +335,9 @@ importers: axios: specifier: ^1.7.2 version: 1.7.2 + react-canvas-confetti: + specifier: ^2.0.7 + version: 2.0.7(react@18.2.0) react-copy-to-clipboard: specifier: ^5.1.0 version: 5.1.0(react@18.2.0) @@ -4331,6 +4334,10 @@ packages: '@types/node': 20.14.10 dev: true + /@types/canvas-confetti@1.6.4: + resolution: {integrity: sha512-fNyZ/Fdw/Y92X0vv7B+BD6ysHL4xVU5dJcgzgxLdGbn8O3PezZNIJpml44lKM0nsGur+o/6+NZbZeNTt00U1uA==} + dev: false + /@types/connect@3.4.38: resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} dependencies: @@ -5885,6 +5892,10 @@ packages: /caniuse-lite@1.0.30001642: resolution: {integrity: sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==} + /canvas-confetti@1.9.3: + resolution: {integrity: sha512-rFfTURMvmVEX1gyXFgn5QMn81bYk70qa0HLzcIOSVEyl57n6o9ItHeBtUSWdvKAPY0xlvBHno4/v3QPrT83q9g==} + dev: false + /case-sensitive-paths-webpack-plugin@2.4.0: resolution: {integrity: sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==} engines: {node: '>=4'} @@ -10585,6 +10596,16 @@ packages: strip-json-comments: 2.0.1 dev: true + /react-canvas-confetti@2.0.7(react@18.2.0): + resolution: {integrity: sha512-DIj44O35TPAwJkUSIZqWdVsgAMHtVf8h7YNmnr3jF3bn5mG+d7Rh9gEcRmdJfYgRzh6K+MAGujwUoIqQyLnMJw==} + peerDependencies: + react: '*' + dependencies: + '@types/canvas-confetti': 1.6.4 + canvas-confetti: 1.9.3 + react: 18.2.0 + dev: false + /react-colorful@5.6.1(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==} peerDependencies: