From 8e9a978bcf2c697733beb375950cf42f56e166d9 Mon Sep 17 00:00:00 2001 From: happppi <102276917+hhbb0081@users.noreply.github.com> Date: Thu, 15 Aug 2024 17:27:04 +0900 Subject: [PATCH 1/2] =?UTF-8?q?Feat:=20=EB=A9=A4=EB=B2=84=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=20=EC=B4=88=EA=B8=B0=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?custom=20hook=20(useMemberProfileMutation)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/user/onboarding/page.tsx | 13 +- .../molecules/headerInfo/HeaderInfo.tsx | 3 +- .../user/onboarding/SetupUserOnboarding.tsx | 24 +-- .../components/NicknameOnboarding.tsx | 160 +++++++++++----- .../components/RealnameOnboarding.tsx | 176 +++++++++++------- .../user/onboarding/constants/const.ts | 126 ++++++------- src/hook/member/useMemberProfileMutation.ts | 22 ++- 7 files changed, 322 insertions(+), 202 deletions(-) diff --git a/src/app/user/onboarding/page.tsx b/src/app/user/onboarding/page.tsx index 1b86ad2..084c4ad 100644 --- a/src/app/user/onboarding/page.tsx +++ b/src/app/user/onboarding/page.tsx @@ -1,8 +1,13 @@ import SetupUserOnboarding from "@/features/user/onboarding/SetupUserOnboarding"; +import { Suspense } from "react"; const UserOnboarding = () => { - // 모임 가입 온보딩 페이지 - return ; -} + // 모임 가입 온보딩 페이지 + return ( + Loading...}> + + + ); +}; -export default UserOnboarding; \ No newline at end of file +export default UserOnboarding; diff --git a/src/components/molecules/headerInfo/HeaderInfo.tsx b/src/components/molecules/headerInfo/HeaderInfo.tsx index bf5dcc5..ac6a8ed 100644 --- a/src/components/molecules/headerInfo/HeaderInfo.tsx +++ b/src/components/molecules/headerInfo/HeaderInfo.tsx @@ -48,7 +48,8 @@ export function HeaderInfo({ const { data: loadData, isError, error } = useMemberAuthQuery(); if (isError) { console.log(error.response?.status); - if (error.response?.status) router.push('/user/onboarding'); + if (error.response?.status) + router.push("/user/onboarding?policy=REAL_NAME"); } if (loadData === undefined) return; const clubInfo = saveData.memberId === -1 ? loadData.data : saveData; diff --git a/src/features/user/onboarding/SetupUserOnboarding.tsx b/src/features/user/onboarding/SetupUserOnboarding.tsx index 86ec255..bf51d31 100644 --- a/src/features/user/onboarding/SetupUserOnboarding.tsx +++ b/src/features/user/onboarding/SetupUserOnboarding.tsx @@ -1,21 +1,17 @@ "use client"; -import { useState } from "react"; +import { useSearchParams } from "next/navigation"; import NicknameOnboarding from "./components/NicknameOnboarding"; import RealnameOnboarding from "./components/RealnameOnboarding"; -export default function SetupUserOnboarding( - ) { - // 유저 모임 가입 온보딩 페이지 - const [method, setMethod] = useState(2); // 1: nickname, 2: realname +export default function SetupUserOnboarding() { + // 유저 모임 가입 온보딩 페이지 + const searchParams = useSearchParams(); + const policy = searchParams.get("policy"); - return ( - <> - {method === 1 ? ( - - ) : ( - - )} - - ); + return ( + <> + {policy === "NICK_NAME" ? : } + + ); } diff --git a/src/features/user/onboarding/components/NicknameOnboarding.tsx b/src/features/user/onboarding/components/NicknameOnboarding.tsx index 3db89b1..b709523 100644 --- a/src/features/user/onboarding/components/NicknameOnboarding.tsx +++ b/src/features/user/onboarding/components/NicknameOnboarding.tsx @@ -1,65 +1,127 @@ +import AddPic from "@/assets/images/AddPic.png"; import { Button } from "@/components/atoms/button"; -import { FileUpload } from "@/components/atoms/fileUpload"; import { Text } from "@/components/atoms/text"; import { InputBox } from "@/components/molecules/inputBox"; import { Wrapper } from "@/components/organisms/Wrapper"; -import { COLORS } from "@/styles"; -import React from "react"; +import { MEMBERPROFILE_TITLE } from "@/features/member/profileEdit/constants/const"; +import { useMemberProfileMutation } from "@/hook/member/useMemberProfileMutation"; +import Image from "next/image"; +import React, { useState } from "react"; import { useForm } from "react-hook-form"; import { ONBOARDING_BTN, ONBOARDING_INPUT_ARR } from "../constants/const"; + import "./NicknameOnboarding.css"; interface FormData { - nickname: string; - introduce: string; - emailPublic: boolean; - mobilePublic: boolean; + memberName: string; + memberIntro: string; + profileImage: string | File; + isEmailPublic: boolean; + isPhonePublic: boolean; } const NicknameOnboarding = () => { - const methods = useForm({ - mode: 'onChange' - }); + const { control, handleSubmit, setValue } = useForm({ + mode: "onChange", + defaultValues: { + memberName: "", + memberIntro: "", + profileImage: "", + isEmailPublic: false, + isPhonePublic: false, + }, + }); + const [imageUrl, setImageUrl] = useState(); + const handleChangeImage = (e: React.ChangeEvent) => { + const files = e.target.files; + if (!files || files.length === 0) return; + const selectedFile = files[0]; + const newImageUrl = URL.createObjectURL(selectedFile); + setImageUrl(newImageUrl); + setValue("profileImage", selectedFile); + }; - const { handleSubmit, control } = methods; + const postFormData = (propData: FormData) => { + const resData = new FormData(); + resData.append("memberName", propData.memberName); + resData.append("memberIntro", propData.memberIntro); + resData.append("isEmailPublic", String(propData.isEmailPublic)); + resData.append("isPhonePublic", String(propData.isPhonePublic)); + resData.append("profileImage", propData.profileImage); - const submitOnboarding = (data: FormData) => { - console.log(data); - } - return ( -
- -
-
- 프로필 사진 - -
- {ONBOARDING_INPUT_ARR.nickname.map((box, index) => ( - - - - ))} -
-
- + return resData; + }; + + const { mutate } = useMemberProfileMutation(); + const submitOnboarding = (data: FormData) => { + console.log(data); + const PostData = postFormData(data); + console.log(PostData); + mutate(PostData); + }; + return ( + + +
+
+ + {MEMBERPROFILE_TITLE} + + <> + + + +
+ {ONBOARDING_INPUT_ARR.nickname.map((box, index) => ( + + + + ))} +
+
+ +
+
+ + ); +}; -export default NicknameOnboarding; \ No newline at end of file +export default NicknameOnboarding; diff --git a/src/features/user/onboarding/components/RealnameOnboarding.tsx b/src/features/user/onboarding/components/RealnameOnboarding.tsx index f57a315..223c653 100644 --- a/src/features/user/onboarding/components/RealnameOnboarding.tsx +++ b/src/features/user/onboarding/components/RealnameOnboarding.tsx @@ -1,83 +1,125 @@ +import AddPic from "@/assets/images/AddPic.png"; import { Button } from "@/components/atoms/button"; -import { FileUpload } from "@/components/atoms/fileUpload"; import { Text } from "@/components/atoms/text"; import { InputBox } from "@/components/molecules/inputBox"; import { Wrapper } from "@/components/organisms/Wrapper"; +import { MEMBERPROFILE_TITLE } from "@/features/member/profileEdit/constants/const"; import { useMemberProfileMutation } from "@/hook/member/useMemberProfileMutation"; -import { COLORS } from "@/styles"; +import Image from "next/image"; import React, { useState } from "react"; import { useForm } from "react-hook-form"; import { ONBOARDING_BTN, ONBOARDING_INPUT_ARR } from "../constants/const"; interface FormData { - memberName: string; - memberIntro: string; - profileImage: string | File; - isEmailPublic: boolean; - isPhonePublic: boolean; + memberName: string; + memberIntro: string; + profileImage: string | File; + isEmailPublic: boolean; + isPhonePublic: boolean; } const RealnameOnboarding = () => { - const { control, handleSubmit, setValue } = - useForm({ - mode: "onChange", - defaultValues: { - memberName: '', - memberIntro: '', - profileImage: '', - isEmailPublic: false, - isPhonePublic: false, - } - }); - const [imageUrl, setImageUrl] = useState(); - const handleChangeImage = (e: React.ChangeEvent) => { - const files = e.target.files; - if (!files || files.length === 0) return; - const selectedFile = files[0]; - const newImageUrl = URL.createObjectURL(selectedFile); - setImageUrl(newImageUrl); - setValue("profileImage", selectedFile); - }; + const { control, handleSubmit, setValue } = useForm({ + mode: "onChange", + defaultValues: { + memberName: "", + memberIntro: "", + profileImage: "", + isEmailPublic: false, + isPhonePublic: false, + }, + }); + const [imageUrl, setImageUrl] = useState(); + const handleChangeImage = (e: React.ChangeEvent) => { + const files = e.target.files; + if (!files || files.length === 0) return; + const selectedFile = files[0]; + const newImageUrl = URL.createObjectURL(selectedFile); + setImageUrl(newImageUrl); + setValue("profileImage", selectedFile); + }; - const { mutate } = useMemberProfileMutation() - const submitOnboarding = (data: FormData) => { - console.log(data); - // mutate(data); - } - return ( -
- -
-
- 프로필 사진 - -
- {ONBOARDING_INPUT_ARR.realname.map((box, index) => ( - - - - ))} -
-
- + const postFormData = (propData: FormData) => { + const resData = new FormData(); + resData.append("memberName", propData.memberName); + resData.append("memberIntro", propData.memberIntro); + resData.append("isEmailPublic", String(propData.isEmailPublic)); + resData.append("isPhonePublic", String(propData.isPhonePublic)); + resData.append("profileImage", propData.profileImage); + + return resData; + }; + + const { mutate } = useMemberProfileMutation(); + const submitOnboarding = (data: FormData) => { + console.log(data); + const PostData = postFormData(data); + console.log(PostData); + mutate(PostData); + }; + return ( + + +
+
+ + {MEMBERPROFILE_TITLE} + + <> + + + +
+ {ONBOARDING_INPUT_ARR.realname.map((box, index) => ( + + + + ))} +
+
+ +
+
+ + ); +}; -export default RealnameOnboarding; \ No newline at end of file +export default RealnameOnboarding; diff --git a/src/features/user/onboarding/constants/const.ts b/src/features/user/onboarding/constants/const.ts index fe03cf6..aae36e5 100644 --- a/src/features/user/onboarding/constants/const.ts +++ b/src/features/user/onboarding/constants/const.ts @@ -1,65 +1,65 @@ export const ONBOARDING_INPUT_ARR = { - nickname : [ - { - title: "닉네임", - maxCnt: 20, - type: "input", - essential: true, - name: "nickname" - }, - { - title: "한 줄 소개", - maxCnt: 30, - type: "input", - essential: false, - name: "introduce" - }, - { - title: "이메일 공개 여부", - type: "toggle", - subtitle: "이메일 공개 여부 마이페이지에서 변경할 수 있어요", - essential: true, - name: "emailPublic" - }, - { - title: "전화번호 공개 여부", - type: "toggle", - subtitle: "전화번호 공개 여부는 마이페이지에서 변경할 수 있어요", - essential: true, - name: "mobilePublic" - } - ], - realname : [ - { - title: "이름", - maxCnt: 10, - subtitle: "이 모임은 실명으로만 활동할 수 있어요 (이름 변경 불가)", - type: "input", - essential: true, - name: "name" - }, - { - title: "한 줄 소개", - maxCnt: 30, - type: "input", - essential: false, - name: "introduce" - }, - { - title: "이메일 공개 여부", - type: "toggle", - subtitle: "이메일 공개 여부 마이페이지에서 변경할 수 있어요", - essential: true, - name: "emailPublic" - }, - { - title: "전화번호 공개 여부", - type: "toggle", - subtitle: "전화번호 공개 여부는 마이페이지에서 변경할 수 있어요", - essential: true, - name: "mobilePublic" - } - ] -} + nickname: [ + { + title: "닉네임", + maxCnt: 20, + type: "input", + essential: true, + name: "memberName", + }, + { + title: "한 줄 소개", + maxCnt: 30, + type: "input", + essential: false, + name: "memberIntro", + }, + { + title: "이메일 공개 여부", + type: "toggle", + subtitle: "이메일 공개 여부 마이페이지에서 변경할 수 있어요", + essential: true, + name: "isEmailPublic", + }, + { + title: "전화번호 공개 여부", + type: "toggle", + subtitle: "전화번호 공개 여부는 마이페이지에서 변경할 수 있어요", + essential: true, + name: "isPhonePublic", + }, + ], + realname: [ + { + title: "이름", + maxCnt: 10, + subtitle: "이 모임은 실명으로만 활동할 수 있어요 (이름 변경 불가)", + type: "input", + essential: true, + name: "memberName", + }, + { + title: "한 줄 소개", + maxCnt: 30, + type: "input", + essential: false, + name: "memberIntro", + }, + { + title: "이메일 공개 여부", + type: "toggle", + subtitle: "이메일 공개 여부 마이페이지에서 변경할 수 있어요", + essential: true, + name: "isEmailPublic", + }, + { + title: "전화번호 공개 여부", + type: "toggle", + subtitle: "전화번호 공개 여부는 마이페이지에서 변경할 수 있어요", + essential: true, + name: "isPhonePublic", + }, + ], +}; -export const ONBOARDING_BTN = "프로필 생성하기" \ No newline at end of file +export const ONBOARDING_BTN = "프로필 생성하기"; diff --git a/src/hook/member/useMemberProfileMutation.ts b/src/hook/member/useMemberProfileMutation.ts index adf182c..f9de82b 100644 --- a/src/hook/member/useMemberProfileMutation.ts +++ b/src/hook/member/useMemberProfileMutation.ts @@ -2,6 +2,7 @@ import { http } from "@/apis/http"; import { FormatClubId } from "@/utils/extractPathElements"; import useToast from "@/utils/useToast"; import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { AxiosError } from "axios"; import { useRouter } from "next/navigation"; export function useMemberProfileMutation() { @@ -26,10 +27,23 @@ export function useMemberProfileMutation() { }, onError: (error) => { console.log("프로필 등록 실패", error); - showToast({ - message: "프로필 등록 실패", - type: "error", - }); + if ((error as AxiosError).isAxiosError) { + const axiosError = error as AxiosError; + if (axiosError.response) { + if (axiosError.response.data.errors) { + showToast({ + message: `${axiosError.response.data.errors[0].message}`, + type: "error", + }); + } else { + showToast({ + message: `${axiosError.response.data.message}`, + type: "error", + }); + if (axiosError.response.data.code === "2201") router.back(); + } + } + } }, }); } From 44b6f0f8366026dfc490dc99ce293c4ebbadef3a Mon Sep 17 00:00:00 2001 From: happppi <102276917+hhbb0081@users.noreply.github.com> Date: Thu, 15 Aug 2024 17:28:01 +0900 Subject: [PATCH 2/2] =?UTF-8?q?Feat:=20=EB=A9=A4=EB=B2=84=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../club/modify/components/ClubInfoModify.css | 2 +- .../modify/components/ClubInfoModifyForm.tsx | 2 +- src/hook/absence/useAbsenceAcceptMutation.ts | 37 ++++++++++--------- src/hook/club/useClubsInfoMutation.ts | 1 + 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/features/info/club/modify/components/ClubInfoModify.css b/src/features/info/club/modify/components/ClubInfoModify.css index 5be9268..75e02fd 100644 --- a/src/features/info/club/modify/components/ClubInfoModify.css +++ b/src/features/info/club/modify/components/ClubInfoModify.css @@ -1,5 +1,5 @@ .clubInfoModify { - padding-bottom: 5.5rem; + padding-bottom: 11rem; } .register__content { diff --git a/src/features/info/club/modify/components/ClubInfoModifyForm.tsx b/src/features/info/club/modify/components/ClubInfoModifyForm.tsx index 0862e49..31710e6 100644 --- a/src/features/info/club/modify/components/ClubInfoModifyForm.tsx +++ b/src/features/info/club/modify/components/ClubInfoModifyForm.tsx @@ -80,7 +80,7 @@ const ClubInfoModifyForm = () => { const { mutate } = useClubsInfoMutation() const submitModifyInfo = (data: ClubModifyFormData) => { const imageIsChanged = infoData?.data.clubProfileImage !== data.clubProfileImage; - console.log(data); + console.log(data, imageIsChanged); mutate({ data: data, imageIsChanged: imageIsChanged diff --git a/src/hook/absence/useAbsenceAcceptMutation.ts b/src/hook/absence/useAbsenceAcceptMutation.ts index a2821c3..041d9a4 100644 --- a/src/hook/absence/useAbsenceAcceptMutation.ts +++ b/src/hook/absence/useAbsenceAcceptMutation.ts @@ -1,8 +1,8 @@ -import { http } from "@/apis/http" -import { AbsenceAcceptParams } from "@/types/absence/types" -import useToast from "@/utils/useToast" -import { useMutation, useQueryClient } from "@tanstack/react-query" -import { AxiosError, AxiosResponse } from "axios" +import { http } from "@/apis/http"; +import { AbsenceAcceptParams } from "@/types/absence/types"; +import useToast from "@/utils/useToast"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { AxiosError, AxiosResponse } from "axios"; interface ErrorData { code: string; @@ -13,27 +13,28 @@ interface ErrorData { // 공결 신청 수락 (/{clubId}/official_absence/accept/{officialAbsenceId}) export const useAbsenceAcceptMutation = ({ clubId, - officialAbsenceId + officialAbsenceId, }: AbsenceAcceptParams) => { const { showToast } = useToast(); const queryClient = useQueryClient(); return useMutation, Error>({ - mutationFn: () => http.post(`/${clubId}/official-absence/accept/${officialAbsenceId}`), + mutationFn: () => + http.post(`/${clubId}/official-absence/accept/${officialAbsenceId}`), onSuccess: (data) => { console.log(data); if (data.status === 200 && data.data === "공결 신청 수락 완료") { showToast({ - message: '공결 신청이 수락되었습니다.', - type: 'success' + message: "공결 신청이 수락되었습니다.", + type: "success", }); queryClient.invalidateQueries({ - queryKey: ['request-absence'] - }) + queryKey: ["request-absence"], + }); } else { showToast({ message: data.data, - type: 'error' + type: "error", }); } }, @@ -43,13 +44,13 @@ export const useAbsenceAcceptMutation = ({ if (axiosError.response) { showToast({ message: `${axiosError.response.data.message}`, - type: 'error' + type: "error", }); queryClient.invalidateQueries({ - queryKey: ['request-absence'] - }) + queryKey: ["request-absence"], + }); } } - } - }) -} \ No newline at end of file + }, + }); +}; diff --git a/src/hook/club/useClubsInfoMutation.ts b/src/hook/club/useClubsInfoMutation.ts index 501a0e3..a7f80e0 100644 --- a/src/hook/club/useClubsInfoMutation.ts +++ b/src/hook/club/useClubsInfoMutation.ts @@ -43,6 +43,7 @@ async function modifyClubs({ }, }; try { + console.log(resData); const clubId = FormatClubId(); const res = await http.patch>(`/clubs/${clubId}/info`, resData, config); console.log(res);