diff --git a/src/components/ReviewResult/ReviewResult.module.scss b/src/components/ReviewResult/ReviewResult.module.scss index 45fa96d..24b5190 100644 --- a/src/components/ReviewResult/ReviewResult.module.scss +++ b/src/components/ReviewResult/ReviewResult.module.scss @@ -34,6 +34,12 @@ } .Bottom { + display: flex; + flex-direction: column; + gap: 1.25rem; +} + +.ButtonBox { align-items: center; gap: 0.875rem; z-index: 1; diff --git a/src/components/ReviewResult/ReviewResult.tsx b/src/components/ReviewResult/ReviewResult.tsx index 14df758..a065e78 100644 --- a/src/components/ReviewResult/ReviewResult.tsx +++ b/src/components/ReviewResult/ReviewResult.tsx @@ -7,13 +7,23 @@ import styles from "@/components/ReviewResult/ReviewResult.module.scss"; import Button from "@/components/ui/Button/Button"; import IconButton from "@/components/ui/IconButton/IconButton"; import Text from "@/components/ui/Text/Text"; +import Toast from "@/components/ui/Toast/Toast"; import { useOverlay } from "@/hooks/common/useOverlay"; +import useToast from "@/hooks/common/useToast"; import type { Options as ConfettiOptions } from "canvas-confetti"; const ReviewResult = () => { const { isOpen, handleClose, handleOpen } = useOverlay(); + const { isToast, showToast } = useToast(1000); + + const reviewText = `오늘 처음으로 청담커피 앤 토스트에서 주문했어요.. 매장도 깔끔하고 직원들도 친절해요! + 음료랑 토스트 세트 시켰는데 가성비가 좋네요… 맛도 좋고 양도 많아요!! 다음에도 또 시켜먹을 거예요.`; + + const handleCopy = () => { + showToast(); + }; const handleConfetti = () => { const setting: ConfettiOptions = { @@ -24,9 +34,7 @@ const ReviewResult = () => { ticks: 50, }; - confetti({ - ...setting, - }); + confetti(setting); }; useEffect(() => { @@ -46,17 +54,19 @@ const ReviewResult = () => { - 오늘 처음으로 청담커피 앤 토스트에서 주문했어요.. 매장도 깔끔하고 직원들도 친절해요! - 음료랑 토스트 세트 시켰는데 가성비가 좋네요… 맛도 좋고 양도 많아요!! 다음에도 또 시켜먹을 - 거예요. + {reviewText}
- +
+
-
diff --git a/src/components/ui/Toast/Toast.module.scss b/src/components/ui/Toast/Toast.module.scss new file mode 100644 index 0000000..52576ab --- /dev/null +++ b/src/components/ui/Toast/Toast.module.scss @@ -0,0 +1,39 @@ +.ToastStory { + display: flex; + align-items: center; + gap: 4rem; + + .Wrapper { + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; + + .InnerWrapper { + width: 1.5rem; + height: 1.5rem; + display: flex; + justify-content: center; + align-items: center; + } + } +} + +.Toast { + width: 100%; + height: 3.25rem; + z-index: 1; + border-radius: 0.75rem; + background-color: white; + padding: 0.875rem 1.125rem; + + transform: translateY(-20px); + transition: + opacity 0.3s, + transform 0.3s; +} + +.show { + opacity: 1; + transform: translateY(0); +} diff --git a/src/components/ui/Toast/Toast.stories.tsx b/src/components/ui/Toast/Toast.stories.tsx new file mode 100644 index 0000000..2578950 --- /dev/null +++ b/src/components/ui/Toast/Toast.stories.tsx @@ -0,0 +1,20 @@ +import Toast from "@/components/ui/Toast/Toast"; + +import type { Meta, StoryObj } from "@storybook/react"; + +type ToastProps = { + text: string; +}; + +const meta: Meta = { + title: "Example/Toast", + component: Toast, +}; + +export default meta; + +export const Primary: StoryObj = { + args: { + text: "링크가 복사되었어요.", + }, +}; diff --git a/src/components/ui/Toast/Toast.tsx b/src/components/ui/Toast/Toast.tsx new file mode 100644 index 0000000..6b9aebe --- /dev/null +++ b/src/components/ui/Toast/Toast.tsx @@ -0,0 +1,20 @@ +import { forwardRef } from "react"; + +import classNames from "classnames"; + +import Text from "@/components/ui/Text/Text"; +import styles from "@/components/ui/Toast/Toast.module.scss"; + +export interface ToastProps extends React.HTMLAttributes { + text: string; +} + +const Toast = forwardRef(({ text, className, ...props }, ref) => { + return ( +
+ {text} +
+ ); +}); + +export default Toast; diff --git a/src/hooks/common/useToast.ts b/src/hooks/common/useToast.ts new file mode 100644 index 0000000..ffe0ed3 --- /dev/null +++ b/src/hooks/common/useToast.ts @@ -0,0 +1,21 @@ +import { useState } from "react"; + +interface UseToastReturn { + isToast: boolean; + showToast: () => void; +} + +const useToast = (duration: number = 1000): UseToastReturn => { + const [isToast, setIsToast] = useState(false); + + const showToast = () => { + setIsToast(true); + setTimeout(() => { + setIsToast(false); + }, duration); + }; + + return { isToast, showToast }; +}; + +export default useToast;