diff --git a/src/components/user/mypage/myProfile/MyPropfileWrapper.styled.ts b/src/components/user/mypage/myProfile/MyProfileWrapper.styled.ts similarity index 100% rename from src/components/user/mypage/myProfile/MyPropfileWrapper.styled.ts rename to src/components/user/mypage/myProfile/MyProfileWrapper.styled.ts diff --git a/src/components/user/mypage/myProfile/MyProfileWrapper.tsx b/src/components/user/mypage/myProfile/MyProfileWrapper.tsx index b994e7fb..9af44a56 100644 --- a/src/components/user/mypage/myProfile/MyProfileWrapper.tsx +++ b/src/components/user/mypage/myProfile/MyProfileWrapper.tsx @@ -1,4 +1,4 @@ -import * as S from './MyPropfileWrapper.styled'; +import * as S from './MyProfileWrapper.styled'; interface MyProfileWrapperProps { children: React.ReactNode; diff --git a/src/components/user/mypage/myProfile/editProfile/EditProfile.styled.ts b/src/components/user/mypage/myProfile/editProfile/EditProfile.styled.ts index 4761f6fd..10434a3e 100644 --- a/src/components/user/mypage/myProfile/editProfile/EditProfile.styled.ts +++ b/src/components/user/mypage/myProfile/editProfile/EditProfile.styled.ts @@ -43,6 +43,10 @@ export const InputBeginner = styled.input` accent-color: ${({ theme }) => theme.color.navy}; `; +export const GithubContainer = styled.div` + width: 85%; +`; + export const InputTextGithub = styled.div` width: 70%; `; @@ -53,6 +57,22 @@ export const GithubImg = styled.img` filter: invert(1); `; +export const GithubDeleteIcon = styled.div` + display: flex; + justify-content: center; + align-items: center; + gap: 0.5em; + + svg { + width: 1rem; + height: 1rem; + } +`; + +export const GithubSpan = styled.span` + width: auto; +`; + export const InputTextCareer = styled.div` width: 100%; `; diff --git a/src/components/user/mypage/myProfile/editProfile/EditProfile.tsx b/src/components/user/mypage/myProfile/editProfile/EditProfile.tsx index eb89563b..efbd2e5c 100644 --- a/src/components/user/mypage/myProfile/editProfile/EditProfile.tsx +++ b/src/components/user/mypage/myProfile/editProfile/EditProfile.tsx @@ -7,7 +7,7 @@ import TextareaAutosize from 'react-textarea-autosize'; import InputText from '../../../auth/InputText'; import { z } from 'zod'; import { SquaresPlusIcon, XMarkIcon } from '@heroicons/react/24/outline'; -import { useNavigate, useOutletContext } from 'react-router-dom'; +import { useLocation, useNavigate, useOutletContext } from 'react-router-dom'; import MyProfileWrapper from '../MyProfileWrapper'; import type { UserInfo } from '../../../../../models/userInfo'; import { useSearchFilteringTags } from '../../../../../hooks/user/useSearchFilteringTags'; @@ -15,10 +15,7 @@ import { useEditMyProfileInfo } from '../../../../../hooks/user/useMyInfo'; import useNickNameVerification from '../../../../../hooks/user/useNicknameVerification'; import { ROUTES } from '../../../../../constants/routes'; import Button from '../../../../common/Button/Button'; -import { - ERROR_MESSAGES, - OAUTH_PROVIDERS, -} from '../../../../../constants/user/authConstants'; +import { ERROR_MESSAGES } from '../../../../../constants/user/authConstants'; import githubIcon from '../../../../../assets/githubIcon.svg'; type ProfileFormData = z.infer; @@ -39,17 +36,14 @@ export default function EditProfile() { const { nicknameMessage, handleDuplicationNickname } = useNickNameVerification(); const navigate = useNavigate(); + const location = useLocation(); + const githubUrl = location.state?.githubUrl; const BASE_URL = import.meta.env.VITE_APP_API_BASE_URL; - const github = { - ...OAUTH_PROVIDERS.filter((oauth) => oauth.name.includes('github'))[0], - }; - - const handleClickGithubValidation = () => { - window.location.href = `${BASE_URL}/${github.url}`; - }; + const github = import.meta.env.VITE_APP_BASE_URL_GITHUB_LINK; const { control, + setValue, handleSubmit, reset, formState: { errors }, @@ -67,12 +61,44 @@ export default function EditProfile() { mode: 'onChange', }); + const handleClickGithubValidation = () => { + if (!github || !BASE_URL) { + console.error('GitHub OAuth URL이 설정되지 않았습니다.'); + return; + } + const oauthUrl = `${BASE_URL}/${github}`; + try { + new URL(oauthUrl); + } catch { + console.error('유효하지 않은 OAuth URL입니다.'); + return; + } + window.location.href = oauthUrl; + }; + + const handleClickDeleteGithubValue = () => { + reset({ + ...control._defaultValues, + github: '', + }); + setValue('github', '', { shouldValidate: true, shouldDirty: true }); + }; + useEffect(() => { if (scrollRef.current) { scrollRef.current.scrollTop = 0; } }, [scrollRef]); + useEffect(() => { + if (githubUrl) { + setValue('github', githubUrl, { + shouldValidate: true, + shouldDirty: true, + }); + } + }, [githubUrl, setValue]); + useEffect(() => { if (userInfoData) { const skillTagIds = userInfoData.skills @@ -93,7 +119,7 @@ export default function EditProfile() { bio: userInfoData.bio || '', beginner: userInfoData.beginner, positionTagIds, - github: userInfoData.github || '', + github: userInfoData.github || githubUrl || '', skillTagIds, career: userInfoData.career?.length ? userInfoData.career.map((item) => ({ @@ -105,7 +131,7 @@ export default function EditProfile() { : [{ name: '', periodStart: '', periodEnd: '', role: '' }], }); } - }, [userInfoData, skillTagsData, positionTagsData, reset]); + }, [userInfoData, skillTagsData, positionTagsData, reset, githubUrl]); const { fields, append, remove } = useFieldArray({ control, name: 'career' }); @@ -260,35 +286,55 @@ export default function EditProfile() { {/* 깃허브 */} - ( - - - - - {errors.github && ( - {errors.github.message} - )} - - - )} - /> + + ( + + + + + {!field.value ? ( + + ) : ( + + )} + {errors.github && ( + {errors.github.message} + )} + + )} + /> + {/* 경력 */} diff --git a/src/components/user/mypage/myProfile/editProfile/ProfileGithubSuccess.tsx b/src/components/user/mypage/myProfile/editProfile/ProfileGithubSuccess.tsx new file mode 100644 index 00000000..05436891 --- /dev/null +++ b/src/components/user/mypage/myProfile/editProfile/ProfileGithubSuccess.tsx @@ -0,0 +1,38 @@ +import { useEffect } from 'react'; +import { useNavigate, useSearchParams } from 'react-router-dom'; +import { ROUTES } from '../../../../../constants/routes'; +import { useModal } from '../../../../../hooks/useModal'; +import Modal from '../../../../common/modal/Modal'; +import { MODAL_MESSAGE } from '../../../../../constants/user/modalMessage'; + +export default function ProfileGithubSuccess() { + const navigate = useNavigate(); + const [searchParams] = useSearchParams(); + const { isOpen, message, handleModalOpen, handleModalClose } = useModal(); + + useEffect(() => { + (async () => { + const githubUrl = searchParams.get('githubUrl'); + console.log(githubUrl); + if (githubUrl) { + handleModalOpen(MODAL_MESSAGE.githubProfileSuccess); + setTimeout(() => { + navigate(`${ROUTES.mypage}/${ROUTES.mypageEdit}`, { + state: { githubUrl }, + }); + }, 1000); + } else { + handleModalOpen(MODAL_MESSAGE.githubProfileFail); + setTimeout(() => { + navigate(`${ROUTES.mypage}/${ROUTES.mypageEdit}`); + }, 1000); + } + })(); + }, [searchParams, handleModalOpen, navigate]); + + return ( + + {message} + + ); +} diff --git a/src/components/user/mypage/myProfile/profile/Profile.styled.ts b/src/components/user/mypage/myProfile/profile/Profile.styled.ts index f76afa42..f9c94ba7 100644 --- a/src/components/user/mypage/myProfile/profile/Profile.styled.ts +++ b/src/components/user/mypage/myProfile/profile/Profile.styled.ts @@ -1,20 +1,11 @@ +import { Link } from 'react-router-dom'; import styled from 'styled-components'; +import { SendButton } from '../../../customerService/inquiry/Inquiry.styled'; export const ProfileSection = styled.div` display: flex; flex-direction: column; gap: 1.25rem; - - a { - width: fit-content; - display: inline-block; - padding: 0.5rem 0.7rem; - border-radius: ${({ theme }) => theme.borderRadius.large}; - background-color: #3e5879; - color: ${({ theme }) => theme.color.white}; - font-size: 0.8rem; - margin-top: 1rem; - } `; export const BackgroundWrapper = styled.div` @@ -125,6 +116,12 @@ export const List = styled.div` } `; +export const GithubLink = styled(Link)` + &:hover { + color: ${({ theme }) => theme.color.lightnavy}; + } +`; + export const LabelBox = styled.div` display: flex; overflow: visible; @@ -174,3 +171,11 @@ export const Explain = styled.p` cursor: pointer; user-select: none; `; + +export const ChangePasswordLink = styled(SendButton)` + width: fit-content; + padding: 0.5rem 0.7rem; + background-color: #3e5879; + font-size: 0.8rem; + margin-top: 1rem; +`; diff --git a/src/components/user/mypage/myProfile/profile/Profile.tsx b/src/components/user/mypage/myProfile/profile/Profile.tsx index bc6ae0d5..4035fa7d 100644 --- a/src/components/user/mypage/myProfile/profile/Profile.tsx +++ b/src/components/user/mypage/myProfile/profile/Profile.tsx @@ -131,7 +131,11 @@ export default function Profile() { - {userInfoData.github || + {(userInfoData.github && ( + + {userInfoData.github} + + )) || (myPage ? PROFILE_DEFAULT_MESSAGE.myGithub : PROFILE_DEFAULT_MESSAGE.github)} @@ -190,7 +194,11 @@ export default function Profile() { - {myPage && 비밀번호 재설정} + {myPage && ( + + 비밀번호 재설정 + + )} ); } diff --git a/src/constants/routes.ts b/src/constants/routes.ts index 18c66d4d..84c08bf6 100644 --- a/src/constants/routes.ts +++ b/src/constants/routes.ts @@ -29,6 +29,7 @@ export const ROUTES = { inquiry: '/inquiry', evaluation: '/evaluation', loginSuccess: '/oauth-redirect', + githubSuccess: '/oauth/github-success', } as const; export const ADMIN_ROUTE = { @@ -50,8 +51,8 @@ export const ADMIN_ROUTE = { log: 'log', joinedProject: 'joined-project', createdProject: 'created-project', - appliedProject: 'apply-project', + appliedProject: 'applied-project', comments: 'comments', checkingApplicant: 'checked-applicants', applyingProject: 'applied-projects', -}; +} as const; diff --git a/src/constants/user/modalMessage.ts b/src/constants/user/modalMessage.ts index 0556fbe4..09d59fe1 100644 --- a/src/constants/user/modalMessage.ts +++ b/src/constants/user/modalMessage.ts @@ -30,4 +30,6 @@ export const MODAL_MESSAGE = { duplicationTag: '이미 존재하는 태그입니다.', emptyTag: '태그명을 입력하세요.', emptySkillImg: '스킬 이미지를 추가하세요.', + githubProfileFail: '깃허브 프로필 등록에 실패했습니다. 다시 시도해주세요.', + githubProfileSuccess: '깃허브 프로필이 성공적으로 등록되었습니다!', } as const; diff --git a/src/routes/AppRoutes.tsx b/src/routes/AppRoutes.tsx index b65e2c7a..166be35e 100644 --- a/src/routes/AppRoutes.tsx +++ b/src/routes/AppRoutes.tsx @@ -47,6 +47,12 @@ const Profile = lazy( const ProfileEdit = lazy( () => import('../components/user/mypage/myProfile/editProfile/EditProfile') ); +const ProfileGithubSuccess = lazy( + () => + import( + '../components/user/mypage/myProfile/editProfile/ProfileGithubSuccess' + ) +); const MyProjectVolunteer = lazy( () => import('../pages/user/manage/myProjectVolunteer/MyProjectVolunteer') ); @@ -110,6 +116,10 @@ export const AppRoutes = () => { path: ROUTES.loginSuccess, element: , }, + { + path: ROUTES.githubSuccess, + element: , + }, { path: ROUTES.signup, element: isLoggedIn ? (