Skip to content

Commit 3f1c4ae

Browse files
[fix] 프로필 등록, 편집 페이지 버그 수정
[fix] 프로필 등록, 편집 페이지 버그 수정
2 parents 7cf5fb2 + 9f6c24a commit 3f1c4ae

File tree

4 files changed

+207
-158
lines changed

4 files changed

+207
-158
lines changed

src/components/TextField.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ const Input = forwardRef(
8282
ref: Ref<HTMLInputElement>,
8383
) => {
8484
const wrapperClassNames = cn(
85-
"flex w-fit gap-1.5 border rounded-[0.375rem] border-gray-30 focus-within:border-blue-20 placeholder:text-gray-40 ",
85+
"flex w-fit gap-1.5 border rounded-[0.375rem] border-gray-30 focus-within:border-blue-20 placeholder:text-gray-40 bg-white",
8686
{
8787
"w-full": fullWidth,
8888
"bg-gray-20 text-gray-40": disabled,
@@ -136,7 +136,7 @@ const TextArea = forwardRef(
136136
ref: Ref<HTMLTextAreaElement>,
137137
) => {
138138
const wrapperClassNames = cn(
139-
"flex w-fit gap-1.5 border rounded-[0.375rem] border-gray-30 focus-within:border-blue-20 placeholder:text-gray-40 ",
139+
"flex w-fit gap-1.5 border rounded-[0.375rem] border-gray-30 focus-within:border-blue-20 placeholder:text-gray-40 bg-white",
140140
{
141141
"w-full": fullWidth,
142142
"bg-gray-20 text-gray-40": disabled,

src/hooks/useUserStore.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ interface UserState {
1616
user: User | null;
1717
token: string | null;
1818
isLoggedIn: boolean;
19+
updateUser: (partial: Partial<User>) => void;
1920
setUserAndToken: (user: User, token: string) => void;
2021
updateShopId: (shopId: string) => void;
2122
clearUser: () => void;
@@ -28,6 +29,14 @@ export const useUserStore = create<UserState>()(
2829
token: null,
2930
isLoggedIn: false,
3031

32+
updateUser: (partial) => {
33+
const current = get();
34+
if (!current.user) return;
35+
set({
36+
user: { ...current.user, ...partial },
37+
});
38+
},
39+
3140
setUserAndToken: (user, token) =>
3241
set({
3342
user,

src/pages/ProfileEditPage.tsx

Lines changed: 101 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const FIELD_LABELS: Record<keyof FormType, string> = {
3131

3232
export default function ProfileEditPage() {
3333
const navigate = useNavigate();
34-
const { user } = useUserStore();
34+
const { user, updateUser } = useUserStore();
3535
const [isSubmitting, setIsSubmitting] = useState(false);
3636
const openModal = useModalStore((state) => state.openModal);
3737

@@ -43,34 +43,52 @@ export default function ProfileEditPage() {
4343
});
4444

4545
useEffect(() => {
46-
async function fetchUser() {
46+
if (!user) {
47+
openModal({
48+
type: "alert",
49+
iconType: "warning",
50+
message: "로그인 후에 이용 가능한 기능입니다.",
51+
onClose: () => navigate(ROUTES.AUTH.SIGNIN),
52+
});
53+
return;
54+
}
55+
if (user.type === "employer") {
56+
openModal({
57+
type: "alert",
58+
iconType: "warning",
59+
message: "알바생 계정으로만 이용 가능한 기능입니다.",
60+
onClose: () => navigate(ROUTES.SHOP.ROOT),
61+
});
62+
return;
63+
}
64+
}, []);
65+
66+
useEffect(() => {
67+
const fetchUser = async () => {
4768
if (!user?.id) return;
4869
const res = await getUser(user.id);
70+
71+
if (!res.data.item?.name) {
72+
navigate(ROUTES.PROFILE.REGISTER);
73+
return;
74+
}
4975
const { name, phone, address, bio } = res.data.item;
5076
setForm({
5177
name: name ?? "",
5278
phone: phone ?? "",
5379
address,
5480
bio: bio ?? "",
5581
});
56-
}
82+
};
5783
fetchUser();
58-
}, [user?.id]);
84+
}, [user?.id, navigate]);
5985

6086
const handleChange = (key: keyof FormType, value: string | SeoulDistrict) => {
6187
setForm((prev) => ({ ...prev, [key]: value }));
6288
};
6389

6490
const handleSubmit = async () => {
65-
if (!user?.id) {
66-
openModal({
67-
type: "alert",
68-
iconType: "warning",
69-
message: "로그인 정보가 없습니다.",
70-
});
71-
return;
72-
}
73-
91+
if (!user?.id) return;
7492
if (isSubmitting) return;
7593

7694
const requiredFields: Array<keyof FormType> = ["name", "phone", "address"];
@@ -99,6 +117,7 @@ export default function ProfileEditPage() {
99117

100118
try {
101119
await putUser(user.id, payload);
120+
updateUser(payload);
102121
openModal({
103122
type: "message",
104123
iconType: "none",
@@ -120,72 +139,74 @@ export default function ProfileEditPage() {
120139
};
121140

122141
return (
123-
<form
124-
className="w-full max-w-[964px] mx-auto px-4 py-12"
125-
onSubmit={(e) => {
126-
e.preventDefault();
127-
handleSubmit();
128-
}}
129-
>
130-
<div className="flex justify-between items-center mb-8">
131-
<h2 className="sm:text-[1.75rem] text-[1.25rem] font-bold">
132-
내 프로필
133-
</h2>
134-
<button type="button" onClick={() => navigate("/profile")}>
135-
<Close className="sm:w-8 sm:h-8 w-6 h-6 cursor-pointer" />
136-
</button>
137-
</div>
138-
139-
<div className="grid md:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-5 mb-6">
140-
<TextField.Input
141-
label="이름*"
142-
placeholder="입력"
143-
fullWidth
144-
value={form.name}
145-
onChange={(e) => handleChange("name", e.target.value)}
146-
maxLength={20}
147-
/>
148-
<TextField.Input
149-
label="연락처*"
150-
placeholder="입력"
151-
fullWidth
152-
value={form.phone}
153-
onChange={(e) => {
154-
const formatted = autoHyphenFormatter(e.target.value);
155-
handleChange("phone", formatted);
156-
}}
157-
/>
158-
<Select
159-
label="선호 지역*"
160-
placeholder="선택"
161-
fullWidth
162-
options={SeoulDistricts.map((d) => ({ label: d, value: d }))}
163-
value={form.address}
164-
onValueChange={(value) => handleChange("address", value)}
165-
/>
166-
</div>
167-
<div className="mb-10">
168-
<TextField.TextArea
169-
label="소개 (최대 300자)"
170-
placeholder="입력"
171-
fullWidth
172-
rows={4}
173-
value={form.bio}
174-
maxLength={300}
175-
onChange={(e) => handleChange("bio", e.target.value)}
176-
/>
177-
</div>
178-
<div className="text-center">
179-
<Button
180-
variant="primary"
181-
textSize="md"
182-
className="sm:w-[350px] w-full px-34 py-3.5"
183-
disabled={isSubmitting}
184-
type="submit"
185-
>
186-
수정하기
187-
</Button>
188-
</div>
189-
</form>
142+
<div className="w-full bg-gray-5 min-h-screen">
143+
<form
144+
className="w-full max-w-[964px] mx-auto px-4 py-12"
145+
onSubmit={(e) => {
146+
e.preventDefault();
147+
handleSubmit();
148+
}}
149+
>
150+
<div className="flex justify-between items-center mb-8">
151+
<h2 className="sm:text-[1.75rem] text-[1.25rem] font-bold">
152+
내 프로필
153+
</h2>
154+
<button type="button" onClick={() => navigate("/profile")}>
155+
<Close className="sm:w-8 sm:h-8 w-6 h-6 cursor-pointer" />
156+
</button>
157+
</div>
158+
159+
<div className="grid lg:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-5 mb-6">
160+
<TextField.Input
161+
label="이름*"
162+
placeholder="입력"
163+
fullWidth
164+
value={form.name}
165+
onChange={(e) => handleChange("name", e.target.value)}
166+
maxLength={20}
167+
/>
168+
<TextField.Input
169+
label="연락처*"
170+
placeholder="입력"
171+
fullWidth
172+
value={form.phone}
173+
onChange={(e) => {
174+
const formatted = autoHyphenFormatter(e.target.value);
175+
handleChange("phone", formatted);
176+
}}
177+
/>
178+
<Select
179+
label="선호 지역*"
180+
placeholder="선택"
181+
fullWidth
182+
options={SeoulDistricts.map((d) => ({ label: d, value: d }))}
183+
value={form.address}
184+
onValueChange={(value) => handleChange("address", value)}
185+
/>
186+
</div>
187+
<div className="mb-10">
188+
<TextField.TextArea
189+
label="소개 (최대 300자)"
190+
placeholder="입력"
191+
fullWidth
192+
rows={4}
193+
value={form.bio}
194+
maxLength={300}
195+
onChange={(e) => handleChange("bio", e.target.value)}
196+
/>
197+
</div>
198+
<div className="text-center">
199+
<Button
200+
variant="primary"
201+
textSize="md"
202+
className="sm:w-[350px] w-full px-34 py-3.5"
203+
disabled={isSubmitting}
204+
type="submit"
205+
>
206+
수정하기
207+
</Button>
208+
</div>
209+
</form>
210+
</div>
190211
);
191212
}

0 commit comments

Comments
 (0)