Skip to content

Commit fe809c9

Browse files
authored
refactor/마이페이지 알림설정과 닉네임 변경 수정 (#112)
* [feat] 탭별개인화 * [feat]알림 설정기능 * [feat]알콜도수기능 * [feat]마이페이지 개인화 * [chore]미개발 부분 주석처리 * [chore]미개발 컴포넌트 주석처리 * [refactor]알림 컨펌기능 * [refactor] 알콜도수 도수 색 변화 * [fix] 칵테일 드롭다운 수정사항 반영 * [style] 알콜도수와 %표시띄움
1 parent 7ccdd93 commit fe809c9

File tree

11 files changed

+145
-58
lines changed

11 files changed

+145
-58
lines changed

src/domains/mypage/components/EditNickName.tsx

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ import TextButton from '@/shared/components/button/TextButton';
44
import Input from '@/shared/components/Input-box/Input';
55
import ModalLayout from '@/shared/components/modal-pop/ModalLayout';
66
import { useToast } from '@/shared/hook/useToast';
7-
import { Dispatch, SetStateAction } from 'react';
7+
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
88

99
interface Props {
1010
open: boolean;
1111
onClose: () => void;
12+
nickname: string;
1213
setNickName: (v: string) => void;
1314
setIsOpen: Dispatch<SetStateAction<boolean>>;
1415
editNickName: string;
@@ -18,14 +19,22 @@ interface Props {
1819
function EditNickName({
1920
open,
2021
onClose,
22+
nickname,
2123
setNickName,
2224
setIsOpen,
2325
editNickName,
2426
setEditNickName,
2527
}: Props) {
26-
const { toastError } = useToast();
28+
const [defaultNickname, setDefaultNickname] = useState(nickname);
29+
const { toastSuccess, toastError } = useToast();
30+
31+
useEffect(() => {
32+
setEditNickName(nickname);
33+
setDefaultNickname(nickname);
34+
}, [nickname, setEditNickName]);
35+
2736
const handlesave = async () => {
28-
if (editNickName.length <= 1) {
37+
if (editNickName.length <= 1 || editNickName.length >= 8) {
2938
toastError('닉네임은 2글자 이상 입력해야합니다');
3039
return;
3140
}
@@ -43,16 +52,21 @@ function EditNickName({
4352
}),
4453
});
4554
await setIsOpen(false);
55+
toastSuccess('닉네임이 저장되었습니다.');
4656
};
4757

4858
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
4959
setEditNickName(e.target.value);
5060
};
5161

62+
const handleDefaultNickname = () => {
63+
setEditNickName(defaultNickname);
64+
};
65+
5266
return (
5367
<ModalLayout
54-
title="닉네임 수정"
55-
description="닉네임을 수정해주세요."
68+
title="닉네임 변경"
69+
description="닉네임을 변경해주세요."
5670
open={open}
5771
onClose={onClose}
5872
buttons={
@@ -67,11 +81,12 @@ function EditNickName({
6781
</label>
6882
<Input
6983
onChange={(e) => handleChange(e)}
70-
placeholder="8글자 이내로 입력해주세요"
84+
placeholder="닉네임을 2글자 이상 8글자 이내로 입력해주세요"
7185
id="editNickName"
86+
value={editNickName}
7287
className="w-full"
7388
/>
74-
<TextButton onClick={onClose}>기존 이름으로 돌아가기</TextButton>
89+
<TextButton onClick={handleDefaultNickname}>전 닉네임으로 돌아가기</TextButton>
7590
</div>
7691
</ModalLayout>
7792
);
Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
'use client';
22
import { getApi } from '@/app/api/config/appConfig';
3-
import { useToast } from '@/shared/hook/useToast';
43
import clsx from 'clsx';
54
import { useEffect, useState } from 'react';
5+
import AlarmConfirm from './pages/my-alarm/AlarmConfirm';
66

77
function ToggleBtn() {
8-
const [isClick, setIsClick] = useState<boolean | null>(null);
9-
const { toastSuccess } = useToast();
8+
const [isAlarm, setIsAlarm] = useState<boolean | null>(null);
9+
const [isClick, setIsClick] = useState<boolean>(false);
1010

1111
useEffect(() => {
1212
const fetchToggle = async () => {
@@ -16,7 +16,8 @@ function ToggleBtn() {
1616
credentials: 'include',
1717
});
1818
const json = await res.json();
19-
setIsClick(json.data.enabled);
19+
console.log(json);
20+
setIsAlarm(json.data.enabled);
2021
} catch {
2122
console.error();
2223
}
@@ -25,36 +26,36 @@ function ToggleBtn() {
2526
}, []);
2627

2728
const handleClick = async () => {
28-
if (isClick === null) return;
29-
const next = !isClick;
30-
setIsClick(next);
31-
32-
await fetch(`${getApi}/me/notification-setting`, {
33-
method: 'PATCH',
34-
credentials: 'include',
35-
headers: { 'Content-Type': 'application/json' },
36-
body: JSON.stringify({
37-
enabled: next,
38-
}),
39-
});
40-
next ? toastSuccess('알림이 설정되었습니다.') : toastSuccess('알림이 해제되었습니다');
29+
setIsClick(true);
4130
};
4231

4332
return (
44-
<button
45-
className={clsx(
46-
'rounded-full flex py-0.5 pl-[2px] w-17 h-7 duration-300',
47-
isClick ? 'bg-tertiary' : 'bg-white'
33+
<div>
34+
{isClick && (
35+
<AlarmConfirm
36+
open={isClick}
37+
onClose={() => setIsClick(false)}
38+
state={isAlarm}
39+
cancle={() => setIsClick(isClick)}
40+
setIsAlarm={setIsAlarm}
41+
setIsClick={setIsClick}
42+
/>
4843
)}
49-
onClick={handleClick}
50-
>
51-
<div
44+
<button
5245
className={clsx(
53-
'rounded-full w-6 h-6 duration-300',
54-
isClick ? 'bg-secondary translate-x-10' : 'bg-gray-dark'
46+
'rounded-full flex py-0.5 pl-[2px] w-17 h-7 duration-300',
47+
isAlarm ? 'bg-tertiary' : 'bg-white'
5548
)}
56-
></div>
57-
</button>
49+
onClick={handleClick}
50+
>
51+
<div
52+
className={clsx(
53+
'rounded-full w-6 h-6 duration-300',
54+
isAlarm ? 'bg-secondary translate-x-10' : 'bg-gray-dark'
55+
)}
56+
></div>
57+
</button>
58+
</div>
5859
);
5960
}
6061
export default ToggleBtn;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { useConfirm } from '@/domains/mypage/hook/useConfirm';
2+
import ConfirmModal from '@/shared/components/modal-pop/ConfirmModal';
3+
import { Dispatch, SetStateAction } from 'react';
4+
5+
interface Props {
6+
open: boolean;
7+
onClose: () => void;
8+
state: boolean | null;
9+
cancle: () => void;
10+
setIsAlarm: Dispatch<SetStateAction<boolean | null>>;
11+
setIsClick: Dispatch<SetStateAction<boolean>>;
12+
}
13+
14+
function AlarmConfirm({ open, onClose, state, cancle, setIsAlarm, setIsClick }: Props) {
15+
const { patchAlarm } = useConfirm(state, setIsAlarm, setIsClick);
16+
17+
return (
18+
<ConfirmModal
19+
open={open}
20+
onClose={onClose}
21+
description={state ? '알림을 해제하시겠습니까?' : '알림을 설정하시겠습니까?'}
22+
onConfirm={patchAlarm}
23+
onCancel={cancle}
24+
></ConfirmModal>
25+
);
26+
}
27+
export default AlarmConfirm;

src/domains/mypage/components/pages/my-bar/MyBar.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use client';
22
import { getApi } from '@/app/api/config/appConfig';
33
import CocktailCard from '@/domains/shared/components/cocktail-card/CocktailCard';
4+
import Link from 'next/link';
45
import { useEffect, useState } from 'react';
56

67
interface MyCocktail {
@@ -37,14 +38,15 @@ function MyBar() {
3738
"
3839
>
3940
{myCocktail.map(({ cocktailId, cocktailName, imageUrl }) => (
40-
<CocktailCard
41-
key={cocktailId}
42-
src={imageUrl}
43-
textSize1="text-xl"
44-
name={cocktailName}
45-
nameKo="올드 패션드"
46-
keep={false}
47-
></CocktailCard>
41+
<Link href={`/recipe/${cocktailId}`} key={cocktailId}>
42+
<CocktailCard
43+
src={imageUrl}
44+
textSize1="text-xl"
45+
name={cocktailName}
46+
nameKo="올드 패션드"
47+
keep={false}
48+
></CocktailCard>
49+
</Link>
4850
))}
4951
</div>
5052
) : (
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { getApi } from '@/app/api/config/appConfig';
2+
import { useToast } from '@/shared/hook/useToast';
3+
import { Dispatch, SetStateAction } from 'react';
4+
5+
export function useConfirm(
6+
state: boolean | null,
7+
setIsAlarm: Dispatch<SetStateAction<boolean | null>>,
8+
setIsClick: Dispatch<SetStateAction<boolean>>
9+
) {
10+
const { toastSuccess } = useToast();
11+
const next = !state;
12+
const patchAlarm = async () => {
13+
await fetch(`${getApi}/me/notification-setting`, {
14+
method: 'PATCH',
15+
credentials: 'include',
16+
headers: { 'Content-Type': 'application/json' },
17+
body: JSON.stringify({
18+
enabled: next,
19+
}),
20+
});
21+
setIsAlarm(next);
22+
setIsClick(false);
23+
24+
(await next) ? toastSuccess('알림이 설정되었습니다.') : toastSuccess('알림이 해제되었습니다');
25+
};
26+
return { patchAlarm };
27+
}

src/domains/mypage/main/MyAbv.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,18 @@ function MyAbv({ abv }: { abv: number }) {
99
const viewPoint = isMd ? 'web' : 'mobileLongText';
1010
const fixedAbv = abv.toFixed(1);
1111

12+
const t = Math.min(1, Math.max(0, abv / 100));
13+
14+
// HEX → RGB
15+
const from = [255, 202, 141]; // FFCA8D
16+
const to = [250, 36, 36]; // FA2424
17+
18+
// RGB
19+
const r = Math.round(from[0] + (to[0] - from[0]) * t);
20+
const g = Math.round(from[1] + (to[1] - from[1]) * t);
21+
const b = Math.round(from[2] + (to[2] - from[2]) * t);
22+
const color = `rgb(${r}, ${g}, ${b})`;
23+
1224
return (
1325
<dl className="flex justify-between items-center text-gray-dark gap-2">
1426
<dt className="flex gap-1 items-center">
@@ -22,8 +34,11 @@ function MyAbv({ abv }: { abv: number }) {
2234
<Help />
2335
</ToolTip>
2436
</dt>
25-
<dd className="text-base">
26-
<span className="text-2xl md:text-4xl font-bold">{fixedAbv}</span>%
37+
<dd className="text-base flex gap-[2px] items-end">
38+
<span className="text-2xl md:text-4xl font-bold" style={{ color }}>
39+
{fixedAbv}
40+
</span>
41+
%
2742
</dd>
2843
</dl>
2944
);

src/domains/mypage/main/MySetting.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import EditNickName from '@/domains/mypage/components/EditNickName';
33
import ToggleBtn from '@/domains/mypage/components/ToggleBtn';
44
import WithdrawModal from '@/domains/mypage/components/WithdrawModal';
5-
import Button from '@/shared/components/button/Button';
65
import TextButton from '@/shared/components/button/TextButton';
76
import { useEffect, useState } from 'react';
87
import useFetchProfile from '../api/fetchProfile';
@@ -26,6 +25,7 @@ function MySetting() {
2625
<section className="flex flex-col h-80 md:h-100 lg:h-125 justify-between">
2726
{isOpen && (
2827
<EditNickName
28+
nickname={nickname ?? ''}
2929
setIsOpen={setIsOpen}
3030
editNickName={editNickName}
3131
setEditNickName={setEditNickName}
@@ -42,16 +42,12 @@ function MySetting() {
4242
</div>
4343
<div className="flex justify-between py-5">
4444
<h2>알람설정</h2>
45+
4546
<ToggleBtn />
4647
</div>
4748
</div>
48-
<div className="flex justify-between items-center">
49+
<div className="flex justify-end items-center">
4950
<TextButton onClick={() => setIsQuit(!isQuit)}>회원탈퇴</TextButton>
50-
51-
<div className="flex gap-2 ">
52-
<Button color="purple">취소</Button>
53-
<Button>변경상태 저장</Button>
54-
</div>
5551
</div>
5652
</section>
5753
);

src/domains/recipe/details/DetailItem.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,16 @@ function DetailItem({ name, nameKo, story, src, abv, glassType }: Props) {
3535
<div className="flex flex-col gap-1 items-center md:items-end md:w-1/2">
3636
<span>{alcoholTitle && <Label title={alcoholTitle} />}</span>
3737
<h2 className="flex flex-col gap-2">
38-
<span className="w-fit font-serif font-bold text-right text-3xl lg:text-4xl text-secondary ">
38+
<span className="w-fit font-serif font-bold text-center md:text-right text-3xl lg:text-4xl text-secondary ">
3939
{name}
4040
</span>
41-
<span className="font-serif font-bold text-right text-xl lg:whitespace-nowrap lg:text-4xl text-secondary">
41+
<span className="font-serif font-bold text-center md:text-right text-xl lg:whitespace-nowrap lg:text-4xl text-secondary">
4242
{nameKo}
4343
</span>
4444
</h2>
4545
</div>
4646

47-
<p className=" text-base self-center w-3/4 md:text-sm md:self-end text-secondary md:w-70 lg:text-base lg:w-100">
47+
<p className=" text-base self-center md:w-1/2 md:text-sm md:self-end text-secondary lg:text-base lg:w-100">
4848
{story}
4949
</p>
5050

src/domains/shared/components/abv-graph/AbvGraph.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ function AbvGraph({ max, abv, type = 'cocktail' }: Props) {
2828

2929
const bandClass = clsx(
3030
'h-full rounded-full transition-[width] duration-500',
31-
'bg-gradient-to-r from-amber-300 to-red-500', // 기본 그라데이션
31+
'bg-gradient-to-r from-[#FFCA8D] to-[#FA2424]', // 기본 그라데이션
3232
pct >= 80 && 'shadow-[0_0_12px_rgba(250,36,36,0.45)]'
3333
);
3434

src/domains/shared/components/keep/Keep.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import KeepIcon from '@/shared/assets/icons/keep_36.svg';
44
import KeepIconActive from '@/shared/assets/icons/keep_active_36.svg';
55
import { useState } from 'react';
66
import { deleteKeep, postKeep } from '../../api/keep/keep';
7+
import { useToast } from '@/shared/hook/useToast';
78

89
interface Props {
910
className?: string;
@@ -13,6 +14,7 @@ interface Props {
1314
// 만약 타입 안맞는다면 그냥 두셔도 됩니다.
1415

1516
function Keep({ className, cocktailId }: Props) {
17+
const { toastSuccess } = useToast();
1618
const [isClick, setIsClick] = useState(false);
1719

1820
const handleClick = async (e: React.MouseEvent<HTMLButtonElement>) => {
@@ -25,8 +27,10 @@ function Keep({ className, cocktailId }: Props) {
2527
if (!cocktailId) return;
2628
if (!isClick) {
2729
await postKeep(cocktailId);
30+
toastSuccess('저장에 성공하셨습니다.');
2831
} else {
2932
await deleteKeep(cocktailId);
33+
toastSuccess('저장을 취소하셨습니다.');
3034
}
3135
} catch (err) {
3236
console.error(err);

0 commit comments

Comments
 (0)