Skip to content

Commit

Permalink
✨ feat: 프로필 수정 api 연결 #73
Browse files Browse the repository at this point in the history
  • Loading branch information
hyeona01 committed Oct 30, 2024
1 parent e80ba58 commit 42c3954
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 136 deletions.
29 changes: 5 additions & 24 deletions src/api/mypage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@ import {
EmployerProfileDetailResponse,
EmployerProfileRequest,
EmployerProfileResponse,
UserEditBodyRequest,
UserProfileResponse,
UserProfileDetailResponse,
UserProfileSummaryResponse,
} from '@/types/api/profile';

// 3.1 (유학생) 유저 프로필 조회하기
export const getUserProfile = async (): Promise<
RESTYPE<UserProfileResponse>
RESTYPE<UserProfileDetailResponse>
> => {
const response = await api.get('/users/details');
return response.data;
Expand Down Expand Up @@ -46,27 +45,9 @@ export const getOwnerSummaries = async (): Promise<
};

// 3.5 (유학생) 프로필 수정
export const patchUserProfile = async ({
image,
userProfile,
}: {
image?: File;
userProfile: UserEditBodyRequest;
}) => {
const formData = new FormData();

// 이미지가 있을 경우 FormData에 추가
if (image) {
formData.append('image', image);
}

// JSON 데이터를 문자열로 변환 후 Blob으로 FormData에 추가(FormData는 객체가 포함될 수 없음)
const jsonBlob = new Blob([JSON.stringify(userProfile)], {
type: 'application/json',
});
formData.append('body', jsonBlob);

const response = await api.patch('/users', formData);
export const patchUserProfile = async (userData: FormData) => {
// export const patchUserProfile = async (userData: UserEditProfileRequest) => {
const response = await api.patch('/users', userData);
return response.data;
};

Expand Down
14 changes: 7 additions & 7 deletions src/components/Profile/ProfileCard.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { UserProfileResponse } from '@/types/api/profile';
import { UserInformation } from '@/types/api/profile';
import { useNavigate } from 'react-router-dom';

type ProfileCardProps = {
data: UserProfileResponse;
data: UserInformation;
};

const ProfileCard = ({ data }: ProfileCardProps) => {
// TODO: 추후 로직 추가
const handleButtonClick = () => {};
const navigate = useNavigate();

return (
<div className="flex flex-col px-[1.125rem] pt-5 pb-4 rounded-[1.125rem] gap-4 bg-[rgba(255,255,255,0.5)]">
Expand All @@ -30,7 +30,7 @@ const ProfileCard = ({ data }: ProfileCardProps) => {
</div>

{/* 교육 정보 */}
{data.school_name === '' ? (
{data.school_name === ' - ' ? (
<span className="body-2 text-[#1E1926]">
Please register your
<br />
Expand All @@ -56,10 +56,10 @@ const ProfileCard = ({ data }: ProfileCardProps) => {
)}
</div>
</div>
{data.school_name === '' && (
{data.school_name === ' - ' && (
<button
className="grow w-full bg-[#FEF387] rounded-md py-2 text-center caption-1 text-[#1E1926] shadow-emphasizeShadow"
onClick={handleButtonClick}
onClick={() => navigate('/resume/education')}
>
Write your educational background
</button>
Expand Down
129 changes: 63 additions & 66 deletions src/pages/EditProfile/EditProfilePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,74 +5,63 @@ import Input from '@/components/Common/Input';
import RadioButton from '@/components/Information/RadioButton';
import EditProfilePicture from '@/components/Profile/EditProfilePicture';
import { buttonTypeKeys } from '@/constants/components';
import { GenderType, NationalityType, VisaType } from '@/constants/profile';
import { UserProfileDetailDataType } from '@/types/api/profile';
import { GenderType } from '@/constants/profile';
import {
InitialUserProfileDetail,
UserEditRequestBody,
} from '@/types/api/profile';
import { InputType } from '@/types/common/input';
import { transformToProfileRequest } from '@/utils/editProfileData';
import {
changeValidData,
transformToProfileRequest,
} from '@/utils/editProfileData';
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { country, phone, visa } from '@/constants/information';
import useNavigateBack from '@/hooks/useNavigateBack';
import { useGetUserProfile, usePatchUserProfile } from '@/hooks/api/useProfile';

const EditProfilePage = () => {
const navigate = useNavigate();
const [userData, setUserData] = useState<
UserProfileDetailDataType | undefined
>(undefined);
const { data: userProfile } = useGetUserProfile();
const { mutate } = usePatchUserProfile();

const [originalData, setOriginalData] = useState<UserEditRequestBody>();
const [userData, setUserData] = useState<UserEditRequestBody>(
InitialUserProfileDetail,
);
const [profileImage, setProfileImage] = useState<File | null>(null);
const [phoneNum, setPhoneNum] = useState({
start: '',
middle: '',
end: '',
});

const handleInputChange =
(field: keyof UserProfileDetailDataType) => (value: string) => {
setUserData((prevData) => {
if (!prevData) {
return { [field]: value } as UserProfileDetailDataType;
}
return {
...prevData,
[field]: value,
};
});
};

const handleBackButtonClick = useNavigateBack();

const handleSubmit = async (): Promise<void> => {
// TODO : API - 3.5 (유학생) 프로필 수정
const handleSubmit = () => {
// API - 3.5 (유학생) 프로필 수정
if (!userData) return;

navigate('/profile');

// get -> patch 데이터 변환
const transformedData = transformToProfileRequest(
userData,
// api 요청 형식과 일치시키는 함수(유효성 검증)
const transformedData = changeValidData(
userData as UserEditRequestBody,
phoneNum,
profileImage,
Boolean(profileImage), // 이미지 변경 여부 확인
);
try {
const formData = new FormData();

// 이미지가 있을 경우 FormData에 추가
if (transformedData.image) {
formData.append('image', transformedData.image);
}

// JSON 데이터를 Blob으로 변환 후 FormData에 추가
formData.append(
'body',
new Blob([JSON.stringify(transformedData.body)], {
type: 'application/json',
}),
);
navigate('/profile');
} catch (error) {
console.error('API 호출 중 에러 발생:', error);
const formData = new FormData();
// 이미지가 있을 경우 FormData에 추가
if (profileImage) {
formData.append('image', profileImage);
}
// JSON 데이터를 Blob으로 변환 후 FormData에 추가
formData.append(
'body',
new Blob([JSON.stringify(transformedData)], {
type: 'application/json',
}),
);
// mutate 호출
mutate(formData);
};

// 전화번호를 3개의 파트로 구분
Expand All @@ -83,24 +72,18 @@ const EditProfilePage = () => {
}
}, [userData]);

// 수정을 위한 초기 데이터 세팅
useEffect(() => {
// TODO : API - 3.1 (유학생) 유저 프로필 조회하기
setUserData({
profile_img_url:
'https://images.pexels.com/photos/1458926/pexels-photo-1458926.jpeg?cs=srgb&dl=pexels-poodles2doodles-1458926.jpg&fm=jpg',
first_name: 'Hyeona',
last_name: 'Seol',
birth: '2001-02-09',
gender: GenderType.FEMALE,
nationality: NationalityType.SOUTH_KOREA,
visa: VisaType.D_2_1,
phone_number: '010-1111-2222',
});
if (userProfile) {
const initailData = transformToProfileRequest(userProfile.data);
setOriginalData(initailData);
setUserData(initailData);
}
}, []);

return (
<>
{userData ? (
{userProfile ? (
<div className="w-full h-full">
<BaseHeader
hasBackButton={true}
Expand All @@ -110,7 +93,7 @@ const EditProfilePage = () => {
/>
<div className="flex flex-col px-6 gap-9 mb-32">
<EditProfilePicture
profileImgUrl={userData.profile_img_url}
profileImgUrl={userProfile.data.profile_img_url}
onImageUpdate={setProfileImage}
/>

Expand All @@ -123,7 +106,12 @@ const EditProfilePage = () => {
inputType={InputType.TEXT}
placeholder="First Name"
value={userData.first_name}
onChange={handleInputChange('first_name')}
onChange={(value) =>
setUserData({
...userData,
first_name: value,
})
}
canDelete={false}
/>
</div>
Expand All @@ -136,7 +124,12 @@ const EditProfilePage = () => {
inputType={InputType.TEXT}
placeholder="Last Name"
value={userData.last_name}
onChange={handleInputChange('last_name')}
onChange={(value) =>
setUserData({
...userData,
last_name: value,
})
}
canDelete={false}
/>
</div>
Expand Down Expand Up @@ -214,7 +207,7 @@ const EditProfilePage = () => {
placeholder="Select Visa Status"
options={visa}
setValue={(value: string) =>
setUserData({ ...userData, visa: value as VisaType })
setUserData({ ...userData, visa: value })
}
/>
</div>
Expand Down Expand Up @@ -257,9 +250,13 @@ const EditProfilePage = () => {
<Button
type={buttonTypeKeys.LARGE}
title="Save"
bgColor="bg-[#FEF387]"
fontColor="text-[#1E1926]"
onClick={handleSubmit}
bgColor={
originalData == userData ? 'bg-[#F4F4F9]' : 'bg-[#FEF387]'
}
fontColor={
originalData == userData ? 'text-[#BDBDBD]' : 'text-[#1E1926]'
}
onClick={originalData == userData ? undefined : handleSubmit}
isBorder={false}
/>
</div>
Expand Down
7 changes: 2 additions & 5 deletions src/pages/Profile/ProfilePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,14 @@ import ProfileCard from '@/components/Profile/ProfileCard';
import ProfileHeader from '@/components/Profile/ProfileHeader';
import ProfileMenuList from '@/components/Profile/ProfileMenuList';
import LogoutBottomSheet from '@/components/Profile/LogoutBottomSheet';
import { UserProfileSummaryData } from '@/constants/profile';
import { useLogout } from '@/hooks/api/useAuth';
// import { useGetUserSummaries } from '@/hooks/api/useProfile';
import { useGetUserSummaries } from '@/hooks/api/useProfile';

const ProfilePage = () => {
const [modalOpen, setModalOpen] = useState<boolean>(false);
const [bottomSheetOpen, setBottomSheetOpen] = useState<boolean>(false);

// TODO: API 완료, 퍼블리싱 작업 중 주석 처리
// const { data } = useGetUserSummaries();
const data = UserProfileSummaryData;
const { data } = useGetUserSummaries();

// 계정 삭제 모달 핸들러
const handleDeleteButton = (value: boolean) => {
Expand Down
41 changes: 27 additions & 14 deletions src/types/api/profile.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { GenderType, VisaType } from '@/constants/profile';
import { OwnerInfo } from '@/types/api/employ';
import { Address } from '@/types/api/users';

Expand All @@ -24,13 +23,14 @@ export type ApplicationCountType = {
successful_hire_counts: number;
};

// 프로필 페이지에서 사용 3.3 유저 요약정보 조회
export type UserProfileSummaryResponse = {
user_information: UserProfileResponse;
user_information: UserInformation;
language_level: LanguageLevelType;
meta_data: MetaDataType;
};

export type UserProfileResponse = {
export type UserInformation = {
profile_img_url: string;
first_name: string;
last_name: string;
Expand All @@ -41,12 +41,25 @@ export type UserProfileResponse = {
is_notification_allowed: boolean;
};

// ----------- 프로필 수정 -----------
// 프로필 수정시 사용 3.1 유학생 프로필 조회
export type UserProfileDetailResponse = {
profile_img_url: string;
first_name: string;
last_name: string;
birth: string;
gender: string;
nationality: string;
visa: string;
phone_number: string;
};

export type UserEditProfileRequest = {
image?: File; // multipart-form-data
body: UserEditBodyRequest;
body: UserEditRequestBody;
};

export type UserEditBodyRequest = {
export type UserEditRequestBody = {
first_name: string;
last_name: string;
birth: string; // yyyy-MM-dd
Expand All @@ -57,15 +70,15 @@ export type UserEditBodyRequest = {
is_profile_img_changed: boolean;
};

export type UserProfileDetailDataType = {
profile_img_url: string;
first_name: string;
last_name: string;
birth: string; // yyyy-MM-dd
gender: GenderType; // Enum(MALE, FEMALE, NONE)
nationality: string;
visa: VisaType; // Enum(D_2_1, D_2_2, D_2_3, D_2_4, D_2_6, D_2_7, D_2_8, D_4_1, D_4_7, F_2)
phone_number: string;
export const InitialUserProfileDetail: UserEditRequestBody = {
first_name: '',
last_name: '',
birth: '', // yyyy-MM-dd
gender: '', // Enum(MALE, FEMALE, NONE)
nationality: '',
visa: '', // Enum(D_2_1, D_2_2, D_2_3, D_2_4, D_2_6, D_2_7, D_2_8, D_4_1, D_4_7, F_2)
phone_number: '',
is_profile_img_changed: false,
};

// 고용주 프로필
Expand Down
Loading

0 comments on commit 42c3954

Please sign in to comment.