diff --git a/src/domains/mypage/components/EditNickName.tsx b/src/domains/mypage/components/EditNickName.tsx index 0e92de87..05a7c419 100644 --- a/src/domains/mypage/components/EditNickName.tsx +++ b/src/domains/mypage/components/EditNickName.tsx @@ -4,11 +4,12 @@ import TextButton from '@/shared/components/button/TextButton'; import Input from '@/shared/components/Input-box/Input'; import ModalLayout from '@/shared/components/modal-pop/ModalLayout'; import { useToast } from '@/shared/hook/useToast'; -import { Dispatch, SetStateAction } from 'react'; +import { Dispatch, SetStateAction, useEffect, useState } from 'react'; interface Props { open: boolean; onClose: () => void; + nickname: string; setNickName: (v: string) => void; setIsOpen: Dispatch>; editNickName: string; @@ -18,14 +19,22 @@ interface Props { function EditNickName({ open, onClose, + nickname, setNickName, setIsOpen, editNickName, setEditNickName, }: Props) { - const { toastError } = useToast(); + const [defaultNickname, setDefaultNickname] = useState(nickname); + const { toastSuccess, toastError } = useToast(); + + useEffect(() => { + setEditNickName(nickname); + setDefaultNickname(nickname); + }, [nickname, setEditNickName]); + const handlesave = async () => { - if (editNickName.length <= 1) { + if (editNickName.length <= 1 || editNickName.length >= 8) { toastError('닉네임은 2글자 이상 입력해야합니다'); return; } @@ -43,16 +52,21 @@ function EditNickName({ }), }); await setIsOpen(false); + toastSuccess('닉네임이 저장되었습니다.'); }; const handleChange = (e: React.ChangeEvent) => { setEditNickName(e.target.value); }; + const handleDefaultNickname = () => { + setEditNickName(defaultNickname); + }; + return ( handleChange(e)} - placeholder="8글자 이내로 입력해주세요" + placeholder="닉네임을 2글자 이상 8글자 이내로 입력해주세요" id="editNickName" + value={editNickName} className="w-full" /> - 기존 이름으로 돌아가기 + 전 닉네임으로 돌아가기 ); diff --git a/src/domains/mypage/components/ToggleBtn.tsx b/src/domains/mypage/components/ToggleBtn.tsx index d6fda4a0..4443525c 100644 --- a/src/domains/mypage/components/ToggleBtn.tsx +++ b/src/domains/mypage/components/ToggleBtn.tsx @@ -1,12 +1,12 @@ 'use client'; import { getApi } from '@/app/api/config/appConfig'; -import { useToast } from '@/shared/hook/useToast'; import clsx from 'clsx'; import { useEffect, useState } from 'react'; +import AlarmConfirm from './pages/my-alarm/AlarmConfirm'; function ToggleBtn() { - const [isClick, setIsClick] = useState(null); - const { toastSuccess } = useToast(); + const [isAlarm, setIsAlarm] = useState(null); + const [isClick, setIsClick] = useState(false); useEffect(() => { const fetchToggle = async () => { @@ -16,7 +16,8 @@ function ToggleBtn() { credentials: 'include', }); const json = await res.json(); - setIsClick(json.data.enabled); + console.log(json); + setIsAlarm(json.data.enabled); } catch { console.error(); } @@ -25,36 +26,36 @@ function ToggleBtn() { }, []); const handleClick = async () => { - if (isClick === null) return; - const next = !isClick; - setIsClick(next); - - await fetch(`${getApi}/me/notification-setting`, { - method: 'PATCH', - credentials: 'include', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - enabled: next, - }), - }); - next ? toastSuccess('알림이 설정되었습니다.') : toastSuccess('알림이 해제되었습니다'); + setIsClick(true); }; return ( - + onClick={handleClick} + > +
+ + ); } export default ToggleBtn; diff --git a/src/domains/mypage/components/pages/my-alarm/AlarmConfirm.tsx b/src/domains/mypage/components/pages/my-alarm/AlarmConfirm.tsx new file mode 100644 index 00000000..0d875b9b --- /dev/null +++ b/src/domains/mypage/components/pages/my-alarm/AlarmConfirm.tsx @@ -0,0 +1,27 @@ +import { useConfirm } from '@/domains/mypage/hook/useConfirm'; +import ConfirmModal from '@/shared/components/modal-pop/ConfirmModal'; +import { Dispatch, SetStateAction } from 'react'; + +interface Props { + open: boolean; + onClose: () => void; + state: boolean | null; + cancle: () => void; + setIsAlarm: Dispatch>; + setIsClick: Dispatch>; +} + +function AlarmConfirm({ open, onClose, state, cancle, setIsAlarm, setIsClick }: Props) { + const { patchAlarm } = useConfirm(state, setIsAlarm, setIsClick); + + return ( + + ); +} +export default AlarmConfirm; diff --git a/src/domains/mypage/components/pages/my-bar/MyBar.tsx b/src/domains/mypage/components/pages/my-bar/MyBar.tsx index 6965048d..bb96e8b2 100644 --- a/src/domains/mypage/components/pages/my-bar/MyBar.tsx +++ b/src/domains/mypage/components/pages/my-bar/MyBar.tsx @@ -1,6 +1,7 @@ 'use client'; import { getApi } from '@/app/api/config/appConfig'; import CocktailCard from '@/domains/shared/components/cocktail-card/CocktailCard'; +import Link from 'next/link'; import { useEffect, useState } from 'react'; interface MyCocktail { @@ -37,14 +38,15 @@ function MyBar() { " > {myCocktail.map(({ cocktailId, cocktailName, imageUrl }) => ( - + + + ))} ) : ( diff --git a/src/domains/mypage/hook/useConfirm.ts b/src/domains/mypage/hook/useConfirm.ts new file mode 100644 index 00000000..8967fec6 --- /dev/null +++ b/src/domains/mypage/hook/useConfirm.ts @@ -0,0 +1,27 @@ +import { getApi } from '@/app/api/config/appConfig'; +import { useToast } from '@/shared/hook/useToast'; +import { Dispatch, SetStateAction } from 'react'; + +export function useConfirm( + state: boolean | null, + setIsAlarm: Dispatch>, + setIsClick: Dispatch> +) { + const { toastSuccess } = useToast(); + const next = !state; + const patchAlarm = async () => { + await fetch(`${getApi}/me/notification-setting`, { + method: 'PATCH', + credentials: 'include', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + enabled: next, + }), + }); + setIsAlarm(next); + setIsClick(false); + + (await next) ? toastSuccess('알림이 설정되었습니다.') : toastSuccess('알림이 해제되었습니다'); + }; + return { patchAlarm }; +} diff --git a/src/domains/mypage/main/MyAbv.tsx b/src/domains/mypage/main/MyAbv.tsx index 0b1d88b9..d07ac7bb 100644 --- a/src/domains/mypage/main/MyAbv.tsx +++ b/src/domains/mypage/main/MyAbv.tsx @@ -9,6 +9,18 @@ function MyAbv({ abv }: { abv: number }) { const viewPoint = isMd ? 'web' : 'mobileLongText'; const fixedAbv = abv.toFixed(1); + const t = Math.min(1, Math.max(0, abv / 100)); + + // HEX → RGB + const from = [255, 202, 141]; // FFCA8D + const to = [250, 36, 36]; // FA2424 + + // RGB + const r = Math.round(from[0] + (to[0] - from[0]) * t); + const g = Math.round(from[1] + (to[1] - from[1]) * t); + const b = Math.round(from[2] + (to[2] - from[2]) * t); + const color = `rgb(${r}, ${g}, ${b})`; + return (
@@ -22,8 +34,11 @@ function MyAbv({ abv }: { abv: number }) {
-
- {fixedAbv}% +
+ + {fixedAbv} + + %
); diff --git a/src/domains/mypage/main/MySetting.tsx b/src/domains/mypage/main/MySetting.tsx index 061b9fe0..f5d01c93 100644 --- a/src/domains/mypage/main/MySetting.tsx +++ b/src/domains/mypage/main/MySetting.tsx @@ -2,7 +2,6 @@ import EditNickName from '@/domains/mypage/components/EditNickName'; import ToggleBtn from '@/domains/mypage/components/ToggleBtn'; import WithdrawModal from '@/domains/mypage/components/WithdrawModal'; -import Button from '@/shared/components/button/Button'; import TextButton from '@/shared/components/button/TextButton'; import { useEffect, useState } from 'react'; import useFetchProfile from '../api/fetchProfile'; @@ -26,6 +25,7 @@ function MySetting() {
{isOpen && (

알람설정

+
-
+
setIsQuit(!isQuit)}>회원탈퇴 - -
- - -
); diff --git a/src/domains/recipe/details/DetailItem.tsx b/src/domains/recipe/details/DetailItem.tsx index 88c17c5f..64f10910 100644 --- a/src/domains/recipe/details/DetailItem.tsx +++ b/src/domains/recipe/details/DetailItem.tsx @@ -35,16 +35,16 @@ function DetailItem({ name, nameKo, story, src, abv, glassType }: Props) {
{alcoholTitle &&

- + {name} - + {nameKo}

-

+

{story}

diff --git a/src/domains/shared/components/abv-graph/AbvGraph.tsx b/src/domains/shared/components/abv-graph/AbvGraph.tsx index 31291b18..d93c4915 100644 --- a/src/domains/shared/components/abv-graph/AbvGraph.tsx +++ b/src/domains/shared/components/abv-graph/AbvGraph.tsx @@ -28,7 +28,7 @@ function AbvGraph({ max, abv, type = 'cocktail' }: Props) { const bandClass = clsx( 'h-full rounded-full transition-[width] duration-500', - 'bg-gradient-to-r from-amber-300 to-red-500', // 기본 그라데이션 + 'bg-gradient-to-r from-[#FFCA8D] to-[#FA2424]', // 기본 그라데이션 pct >= 80 && 'shadow-[0_0_12px_rgba(250,36,36,0.45)]' ); diff --git a/src/domains/shared/components/keep/Keep.tsx b/src/domains/shared/components/keep/Keep.tsx index 5c36cb86..bc306688 100644 --- a/src/domains/shared/components/keep/Keep.tsx +++ b/src/domains/shared/components/keep/Keep.tsx @@ -4,6 +4,7 @@ import KeepIcon from '@/shared/assets/icons/keep_36.svg'; import KeepIconActive from '@/shared/assets/icons/keep_active_36.svg'; import { useState } from 'react'; import { deleteKeep, postKeep } from '../../api/keep/keep'; +import { useToast } from '@/shared/hook/useToast'; interface Props { className?: string; @@ -13,6 +14,7 @@ interface Props { // 만약 타입 안맞는다면 그냥 두셔도 됩니다. function Keep({ className, cocktailId }: Props) { + const { toastSuccess } = useToast(); const [isClick, setIsClick] = useState(false); const handleClick = async (e: React.MouseEvent) => { @@ -25,8 +27,10 @@ function Keep({ className, cocktailId }: Props) { if (!cocktailId) return; if (!isClick) { await postKeep(cocktailId); + toastSuccess('저장에 성공하셨습니다.'); } else { await deleteKeep(cocktailId); + toastSuccess('저장을 취소하셨습니다.'); } } catch (err) { console.error(err); diff --git a/src/shared/components/select-box/SelectBox.tsx b/src/shared/components/select-box/SelectBox.tsx index 7a74b3d9..994d1897 100644 --- a/src/shared/components/select-box/SelectBox.tsx +++ b/src/shared/components/select-box/SelectBox.tsx @@ -88,7 +88,7 @@ function SelectBox({ id, groupKey, ref, option, title, value, onChange, use }: P
    handleChoose(v)} aria-selected={v === select} >