From 84d10757952d0c8fd09f58c3d029dd1fd5de7ec1 Mon Sep 17 00:00:00 2001
From: Eugene Kim <67894159+eugene028@users.noreply.github.com>
Date: Mon, 12 Aug 2024 01:23:27 +0900
Subject: [PATCH] =?UTF-8?q?[Deploy]=20:=20wow-onboarding=202.0.0=20?=
=?UTF-8?q?=EB=B0=B0=ED=8F=AC=20(#98)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* fix: cookie test
* fix: 개발 환경 https 설정 제거
* chore: mkcert 패키지 제거
* chore: PR 템플릿 생성
* [Chore] 패키지 매니저를 pnpm으로 변경해요. (#52)
* chore: 패키지 매니저 pnpm으로 변경
* chore: yaml파일 삭제
* fix : eslint,prettier 제대로 되게 수정
* [Chore] client 서비스에 wow-design 시스템을 적용해요. (#56)
* feature: wowds로 마이그레이션
* fix: 디자인 시스템 마이그레이션
* feature: wow design system으로 마이그레이션
* fix: wowds 기본 CSS 설치
* feat : 디스코드 튜토리얼 UI 1차 반영
* feat : 가이드까지 UI 완성
* feat : width 에도 반영
* fix : spaceKet 로 타입 수정
* feat : spacing 토큰 변경
* feat : ㄹ리뷰 반영
* feat : 디스코드 api 연결
* feat : Image 컴포넌트 타입 수정
* fix: space 토큰 수정
* [Feature] github 로그인 페이지를 2차 MVP 페이지에 맞게 수정해요. (#62)
* feature: github 로그인 페이지 생성
* fix: 패키지 매니저 구성 변경
* fix: 패키지 구성 변경
* refactor : 리팩토링 및 변수명 변경
* fix: 하드코딩된 토큰 환경변수에 저장
* Create CODEOWNERS
* [Feature] 대시보드 2차 MVP DTO에 맞게 뷰를 수정해요. (#57)
* chore: 패키지 매니저 pnpm으로 변경
* chore: yaml파일 삭제
* feature: 새롭게 바뀐 DTO 반영
* chore: 컴포넌트 단순화 분리 작업
* feature: Mypage status 생성
* feature: wowds로 마이그레이션
* fix: 디자인 시스템 마이그레이션
* feature: wow design system으로 마이그레이션
* fix: 이것저것 반영
* feature: 대시보드 2차 MVP 틀 구현
* fix: 메인화면 네임 수정
* #51: #51: WIP on feature/#51
* feature: helpBox 생성
* fix: 서버 번경 사항 챙기기
* feat: 정회원 버튼 생성
* feat: react-hook-form 기본 세팅
* feat: signup 페이지 완성
* fix: 백엔드 DTO 변경에 따른 반영
* fix: 코드리뷰 반영
* fix: 코드리뷰 반영 - 랜더링 최적화
* fix: 패키지 변경사항 반영
* [Feature] 기본 회원 정보를 받을 수 있는 Signup 페이지를 2차 MVP에 맞게 수정해요. (#60)
* chore: 패키지 매니저 pnpm으로 변경
* chore: yaml파일 삭제
* feature: 새롭게 바뀐 DTO 반영
* chore: 컴포넌트 단순화 분리 작업
* feature: Mypage status 생성
* feature: wowds로 마이그레이션
* fix: 디자인 시스템 마이그레이션
* feature: wow design system으로 마이그레이션
* fix: 이것저것 반영
* feature: 대시보드 2차 MVP 틀 구현
* fix: 메인화면 네임 수정
* #51: #51: WIP on feature/#51
* feature: helpBox 생성
* fix: 서버 번경 사항 챙기기
* feat: 정회원 버튼 생성
* feat : wow ui 설치
* feat: react-hook-form 기본 세팅
* fix: 백엔드 api 명세 변경에 따른 프론트 수정 사항 반영
* fix: progressBar wow-ui로 변경
* fix: helpBox 안맞는 부분 수정
* fix: accesstoken 지우기
* feat: signup 페이지 완성
* fix: 코드리뷰 반영
* fix : pnpm install
* refactor : query 관련 훅으로 리팩토링, Space 컴포넌트 수정
* fix: getValues 로 수정
* refactor: react-hook-form 의 pattern 사용해서 유효성 검증
* feat : 라우팅 반영
* style : width 100% 수정
* [Feature] 정회원 지원하기 액션시트를 생성하고, API를 연결해요. (#63)
* chore: 패키지 매니저 pnpm으로 변경
* chore: yaml파일 삭제
* feature: 새롭게 바뀐 DTO 반영
* chore: 컴포넌트 단순화 분리 작업
* feature: Mypage status 생성
* feature: wowds로 마이그레이션
* fix: 디자인 시스템 마이그레이션
* feature: wow design system으로 마이그레이션
* fix: 이것저것 반영
* feature: 대시보드 2차 MVP 틀 구현
* fix: 메인화면 네임 수정
* #51: #51: WIP on feature/#51
* feature: helpBox 생성
* fix: 서버 번경 사항 챙기기
* feat: 정회원 버튼 생성
* feat: BottomSheet context 생성
* feat : wow ui 설치
* feat: react-hook-form 기본 세팅
* fix: 백엔드 api 명세 변경에 따른 프론트 수정 사항 반영
* fix: progressBar wow-ui로 변경
* fix: helpBox 안맞는 부분 수정
* fix: accesstoken 지우기
* chore: 패키지 업데이트
* feat: BottomSheet 기본 틀 잡기
* feat: 바텀시트 기본 틀 다잡아두기
* feature: API 연결
* fix: pc화면에서 어색해보이지 않도록 가운데 정렬
* fix: 준회원일 경우에만 가입 BottomSheet 보이게끔
* fix: merge 삑난거 수정하기
* fix: 코드리뷰 반영
* fix: 코드리뷰 반영
* fix: 코드리뷰 반영
* fix: bottomSheet overlay fixed로 변경하기
* fix: 코드리뷰 반영
* [Feature] Bevy 가입 인증 절차를 생성해요. (#70)
* feat: 기본 Bevy 뷰 생성
* fix: useMutation으로 API 분리
* fix: 사용하지 않는 파일 삭제
* [Feature] 홍익대학교 Gmail을 통해 재학생 인증 기능을 만들어요. (#67)
* feat: 인증하기 초기 화면 디자인 변경
* fix : 필요없는 파일 삭제
* fix: API 객체로 변경
* fix: 이메일 인증 화면 변경하기
* feat: 재학생 인증 실패/성공 화면 만들기
* fix: 백엔드 API 반영 전 상태로 되돌리기
* fix: 코드리뷰 작성
* fix: preventReload 적용
* fix: 버튼 삑나간거 고치기
* fix: media query 중단점 수정
* fix: wowds ui 업데이트
* fix: code를 서버에게 보내요.
* feat: 회비 납부 플로우 추가
* feat: 토스페이먼츠 결제하기 라우팅
* feat: 토스페이먼츠 클라이언트키 임시등록
* feat: 총 결제금액 표시
* feat: 결제 성공 시 마이페이지로 리다이렉트
* chore: 결제 위젯 연동에 필요한 패키지 설치
* fix: PENDING 상태일 때만 결제창 띄움
* fix: 총 결제 금액 임시 하드코딩
* feat: coupon API 추가
* design: 결제창 레이아웃 변경
* feat: 결제 성공 및 실패 화면, 라우팅
* chore: wowds-ui 설치
* feat: wowds로 마이그레이션
* design: wowds UI 적용
* fix: Box 테두리 색상 임시 변경
* feat: 결제정보 전달 API
* feat: 유저정보 API 임시설정
* feat: 쿠폰 타입 변경
* feat: 토스페이먼츠 최신 API 임시 구현 사항
* fix: API post -> get
* chore: payments 라이브러리 업데이트
* feat: 토스페이먼츠 위젯 라이브러리 업데이트에 의한 기능구현 변경
* feat: useProduct hook으로 결제 관리
* fix: 결제 실패 시 쿠폰 적용 페이지로 라우팅
* chore: react-secure-storage 설치
* feat: ENV 추가
* feat: 결제 정보 암호화, 로컬스토리지 저장
* fix: 할인금액이 있을 때만 노출
* feat: 결제 실패 시 로컬스토리지 초기화
* fix: 스토리지 리턴타입 단언
* fix: 토스페이먼츠 타입 any 허용
* refactor: 회비 납부 페이지 컴포넌트 분리
* feat: 임시 주문과 결제 승인 API 구분하기
* fix: 토스페이먼츠 테스트를 위한 로직 수정
* feat: 주문완료 API 추가
* design: 회비 납부 UI 수정
* feat: 쿠폰 정보 추가
* refactor: 라우팅 없이 결제 위젯 연결
* fix: 결제 실패 시 라우팅 변경
* fix: 스토리지 관련 로직 삭제
* fix: 스토리지 관련 로직 삭제
* refactor: useProduct 훅, 관련 로직 리렌더링 최소화 리팩토링
* fix: 스토리지 clear 로직 삭제
* fix: 테스트용 API 제거
* chore: 주석 제거
* chore: console.log 삭제
* chore: wowds-ui 버전업
* refactor: 쿠폰 드롭다운
* feat: 무료 주문 생성 API
* feat: 주문 생성 API mutation hook으로 변경, 총 가격에 따른 API 조건부 반환
* feat: 주문 완료 API mutation hook으로 변경
* fix : 빌드 에러 수정 , ci 작성
* fix : ci 수정
* fix :svg 속성, 필요없는 컴포넌트 삭제
* fix : 안쓰는 api 삭제
* [Fix]: 디스코드 연동 마이너 이슈 수정 (#75)
* fix: 디스코드 합류 체크 관련 API 호출 개선 및 문구 변경
* fix: 메서드 잘못된거 하나 슬쩍 고치기
* fix: API 문서 수정
* [Fix]: Signup 페이지 마이너 UI 이슈 수정 (#74)
* fix: signup 마이너 UI 이슈 수정
* fix: 안쓰는 스타일 객체 일단 삭제
* feat: 푸터 텍스트 로고 추가
* feat: 푸터 UI
* fix: 기존 홈 온보딩 이미지 삭제
* feat : qa반영
* fix : 불필요한 스타일 삭제, 텍필에 100% 추가
* [Refactor] : 학교 이메일 인증 페이지 QA 개선 반영 (#80)
* fix: email 인증 error코드 중복 제거
* refac: 스팸메일함 안내문구 추가
* chore: 채널톡 위젯 삭제
* [Refactor] : Signup 페이지 QA 개선 반영 (#79)
* fix: 하단 absolute 처리
* fix: bottom간격 해결
* fix: signup QA
* chore: wow-ui 버전 업데이트
* [Feature]: Sentry 세팅 (#81)
* chore: sentry 패키지 기본 설치
* feat: Sentry ErrorBoundary 추가
* fix: sentry 관련 기본적인 세팅 완료
* fix: json 문법 수정
* fix: Chatbot 삭제
* fix: 브라우저 설정 환경에 따른 sentry 세팅
* fix: 필요없는 dev 세팅 환경 지우기
* fix: 논리 테스트 (#82)
* [Chore]: Sentry 논리 되돌리기 (#83)
* fix: 논리 테스트
* fix: sentry 논리판단 되돌리기
* [Chore] : 빌드로그에서 vercel 환경변수 볼 수 있도록 하기 (#84)
* fix: 논리 테스트
* fix: sentry 논리판단 되돌리기
* chore: console 테스트
* fix: 로딩 스피너 추가 및 기존 패키지 제거 (#89)
* [Refactor]: 마이너 UI 이슈 수정 (#90)
* fix: textfield 가로길이 안맞는 부분 수정
* fix: scroll 반 쯤 내려가 있는 문제 해결
* [Refactor] : 결제 페이지에 준회원이 아닌 경우 접근하지 못하도록 해요. (#88)
* fix: payment 가드 생성
* fix: 현재 모집기간 닫혀있을때 결제화면 접근 못함
* refac: 토스페이먼츠 접근 화면 가드 꼼꼼하게 다듬기
* fix: data undefined 처리
* fix: payment 성공화면 access화면 생성
* [Refactor]: 학교 이메일 인증 정책을 변경해요 (#91)
* fix: email 인증 error코드 중복 제거
* refac: 스팸메일함 안내문구 추가
* chore: 채널톡 위젯 삭제
* fix: 학회원 모집 마감 처리 Box 생성
* fix: 이메일 인증 in_progress 단계 추가
* fix: 이미 사용하고 있는 타입으로 변경
* [Fix] 토스페이먼츠 QA 개선 반영 (#93)
* [Fix]: 서버 로그인 로직 변경에 따른 AccessToken, RefeshToken 쿠키 세팅 제거 및 landingStatus 제거 (#87)
* fix: 논리 테스트
* fix: sentry 논리판단 되돌리기
* chore: console 테스트
* fix: cookie base-url 상위 도메인으로 변경
* fix: landingStatus 로직 제거
* fix: 메인화면 지원하기 버튼 dashboard로 라우트
* fix:landingStatus 삭제 및 쿠키로직 수정
* fix: landingStatus 관련된 모든 로직 제거
* fix: 쿠키 판단 로직 재건
* fix: 필요없는 guard 모두 삭제
* fix: 리다이렉트 정리
* fix: 로그인 유지 시간 sessionStorage에서 확인
* fix: 쿠키 관련 도메인 로직 모두 삭제
* fix: Cookie 관련 모든 로직 삭제
* fix: 빌드에러 터지는거 해결
* fix: 서버에서 refresh갱신 실패할때 로그아웃 처리
* fix: 403 에러 왔을때 세션 만료
* fix: 모집 기간 마감 예외처리
* fix: 파일 확장명 변경
* [Fix] 토스페이먼츠 결제성공 페이지 가드 임시삭제 (#94)
* fix: PaymentsSuccess 가드 임시 삭제
* fix: 전체 금액이 0 미만일 때 0으로 처리
* fix: 사용하지 않는 import 삭제
* fix: 디스코드 관련 qa 반영
* feat : 인증을 완료한 경우에는 대시보드로 라우팅 하는 가드 설정
* [Fix]: 0807 QA 반영 (#95)
* fix: navigate 정상화
* fix: 모집 차수 깨져 보이는 현상 개선
* fix: 모집 기간 아닐 때 에러 화면 제거
* fix: signup화면 제출 문구 수정
* refac: 이메일 도메인 직접 입력할 수 있도록 변경
* feat: 로그아웃 로직 붙임
* fix: wowds-ui 버전 업데이트
* fix: username 닉네임 잘못된 부분 수정
* fix: 대기중 문구만 뜨는 것 고치기
* fix: console log 삭제
* fix: 합류 확인 여부 리팩토링
* fix: 로그인 코드 변경
* fix:joinServer 안내문구
* fix:빌드실패 고치기
* fix:서버 status 변경사항 반영
* fix: build 에러 해결
* fix: paymentStatus enum 변경
* [Fix] 토스페이먼츠 쿠폰 관련 QA 사항 반영 (#97)
* feat: 총 금액이 0원 이하일 때와 아닐 때의 로직 분리
* fix: 로직 수정 및 에러 토스트 메시지로 변환
* fix: 톤매너 정립
---------
Co-authored-by: Eugene Kim
---------
Co-authored-by: 강나연
Co-authored-by: 강나연 <103591752+kongnayeon@users.noreply.github.com>
Co-authored-by: SeieunYoo
Co-authored-by: SeieunYoo <101736358+SeieunYoo@users.noreply.github.com>
Co-authored-by: hamo-o
Co-authored-by: 이현영 <89445100+hamo-o@users.noreply.github.com>
---
package.json | 9 +-
pnpm-lock.yaml | 311 +++++++++++++++++-
src/App.tsx | 12 +-
src/apis/auth/authApi.ts | 9 +
src/apis/discord/discordApi.ts | 2 +-
src/apis/index.ts | 11 +-
src/apis/member/memberType.ts | 3 +-
src/components/ApiErrorBoundary.tsx | 3 +-
src/components/auth/guard/AuthAccessGuard.tsx | 24 +-
.../auth/guard/MypageAccessGuard.tsx | 14 -
.../guard/OnboardingClosedAccessGuard.tsx | 14 -
.../guard/OnboardingNotOpenedAccessGuard.tsx | 14 -
.../auth/guard/PaymentAccessGuard.tsx | 58 ++++
.../auth/guard/PaymentSuccessAccessGuard.tsx | 49 +++
.../auth/guard/SignupAccessGuard.tsx | 11 -
.../guard/StudentVerificationAccessGuard.tsx | 11 -
.../auth/guard/VerificationGuard.tsx | 63 ++++
src/components/auth/guard/index.ts | 6 -
.../JoinRegularMemberBottomSheet.tsx | 5 +-
src/components/chatbot/ChannelService.ts | 64 ----
src/components/chatbot/Chatbot.tsx | 17 -
src/components/common/LoadingSpinner.tsx | 31 ++
src/components/discordConnect/DiscordName.tsx | 8 +-
.../discordConnect/DiscordNickName.tsx | 8 +-
src/components/discordConnect/JoinServer.tsx | 29 +-
src/components/layout/Header.tsx | 19 +-
src/components/layout/Layout.tsx | 10 +-
src/components/myPage/ApproveBox.tsx | 27 +-
.../myPage/AssociateRequirementCheck.tsx | 87 +++--
src/components/myPage/BasicUserInfo.tsx | 14 +-
src/components/myPage/JoinRegularMember.tsx | 19 +-
src/components/myPage/JoinStatus.tsx | 6 +-
src/components/payments/PaymentsWidget.tsx | 2 +-
.../{auth => signup}/DepartmentSelect.tsx | 46 +--
src/components/signup/EmailInputField.tsx | 139 ++++++++
src/constants/environment.ts | 4 +-
src/constants/landingStatus.ts | 11 -
src/hooks/auth/useAuthToken.ts | 18 -
src/hooks/auth/useStudentVerification.ts | 2 +-
src/hooks/mutation/index.ts | 1 +
src/hooks/mutation/useCreateUserBasicInfo.ts | 2 -
src/hooks/mutation/useLogout.ts | 23 ++
src/hooks/mutation/usePostDiscordName.ts | 4 +-
src/hooks/mutation/usePostDiscordNickname.ts | 4 +-
src/hooks/mutation/usePostFreeOrder.ts | 22 ++
src/hooks/mutation/usePostOrder.ts | 6 +-
src/hooks/mutation/usePostPrevOrder.ts | 14 +-
src/hooks/mutation/useSendStudentEmail.ts | 3 -
src/hooks/query/useGetDiscordJoined.ts | 10 +-
src/hooks/zustand/useLandingStatus.ts | 31 --
src/hooks/zustand/useProduct.ts | 3 +-
src/main.tsx | 43 ++-
src/pages/Auth.tsx | 16 -
src/pages/Dashboard.tsx | 8 +-
src/pages/DiscordConnect.tsx | 2 +-
src/pages/OnboardingClosed.tsx | 95 ------
src/pages/OnboardingNotOpened.tsx | 77 -----
src/pages/PaymentsCheckout.tsx | 24 ++
src/pages/PaymentsSuccess.tsx | 11 +-
src/pages/SignUp.tsx | 153 +++------
src/pages/StudentVerification.tsx | 65 ++--
src/pages/index.ts | 2 -
.../redirect/AuthServerRedirectNavigate.tsx | 27 +-
.../StudentVerificationServerRedirect.tsx | 5 +-
src/routes/index.tsx | 111 ++++---
src/routes/routePath.ts | 11 +-
src/types/status.ts | 4 +-
src/types/user.ts | 8 +-
src/utils/auth.ts | 90 +----
src/utils/mypage/recruitmentNameFormat.ts | 14 +-
src/utils/sentry.ts | 46 +++
src/utils/storage/key.ts | 9 -
vite.config.ts | 19 +-
73 files changed, 1242 insertions(+), 911 deletions(-)
create mode 100644 src/apis/auth/authApi.ts
delete mode 100644 src/components/auth/guard/MypageAccessGuard.tsx
delete mode 100644 src/components/auth/guard/OnboardingClosedAccessGuard.tsx
delete mode 100644 src/components/auth/guard/OnboardingNotOpenedAccessGuard.tsx
create mode 100644 src/components/auth/guard/PaymentAccessGuard.tsx
create mode 100644 src/components/auth/guard/PaymentSuccessAccessGuard.tsx
delete mode 100644 src/components/auth/guard/SignupAccessGuard.tsx
delete mode 100644 src/components/auth/guard/StudentVerificationAccessGuard.tsx
create mode 100644 src/components/auth/guard/VerificationGuard.tsx
delete mode 100644 src/components/auth/guard/index.ts
delete mode 100644 src/components/chatbot/ChannelService.ts
delete mode 100644 src/components/chatbot/Chatbot.tsx
create mode 100644 src/components/common/LoadingSpinner.tsx
rename src/components/{auth => signup}/DepartmentSelect.tsx (54%)
create mode 100644 src/components/signup/EmailInputField.tsx
delete mode 100644 src/constants/landingStatus.ts
delete mode 100644 src/hooks/auth/useAuthToken.ts
create mode 100644 src/hooks/mutation/useLogout.ts
create mode 100644 src/hooks/mutation/usePostFreeOrder.ts
delete mode 100644 src/hooks/zustand/useLandingStatus.ts
delete mode 100644 src/pages/OnboardingClosed.tsx
delete mode 100644 src/pages/OnboardingNotOpened.tsx
create mode 100644 src/utils/sentry.ts
delete mode 100644 src/utils/storage/key.ts
diff --git a/package.json b/package.json
index 0fda0a7..c5f4747 100644
--- a/package.json
+++ b/package.json
@@ -26,14 +26,15 @@
"react-dom": "^18.2.0",
"react-hook-form": "^7.50.1",
"react-router-dom": "^6.22.1",
- "react-spinners": "^0.13.8",
"react-toastify": "^10.0.4",
- "zustand": "^4.5.0",
+ "wowds-icons": "^0.1.0",
"wowds-tokens": "^0.0.9",
- "wowds-ui": "^0.1.7",
- "wowds-icons": "^0.1.0"
+ "zustand": "^4.5.0",
+ "wowds-ui": "^0.1.9"
},
"devDependencies": {
+ "@sentry/react": "^8.22.0",
+ "@sentry/vite-plugin": "^2.21.1",
"@storybook/addon-essentials": "^7.6.14",
"@storybook/addon-interactions": "^7.6.14",
"@storybook/addon-links": "^7.6.14",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4687c3b..dc189e9 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -44,9 +44,6 @@ dependencies:
react-router-dom:
specifier: ^6.22.1
version: 6.22.1(react-dom@18.2.0)(react@18.2.0)
- react-spinners:
- specifier: ^0.13.8
- version: 0.13.8(react-dom@18.2.0)(react@18.2.0)
react-toastify:
specifier: ^10.0.4
version: 10.0.4(react-dom@18.2.0)(react@18.2.0)
@@ -57,13 +54,19 @@ dependencies:
specifier: ^0.0.9
version: 0.0.9
wowds-ui:
- specifier: ^0.1.7
- version: 0.1.7(next@14.2.4)(react@18.2.0)
+ specifier: ^0.1.9
+ version: 0.1.9(next@14.2.4)(react-dom@18.2.0)(react@18.2.0)
zustand:
specifier: ^4.5.0
version: 4.5.1(@types/react@18.2.58)(react@18.2.0)
devDependencies:
+ '@sentry/react':
+ specifier: ^8.22.0
+ version: 8.22.0(react@18.2.0)
+ '@sentry/vite-plugin':
+ specifier: ^2.21.1
+ version: 2.21.1
'@storybook/addon-essentials':
specifier: ^7.6.14
version: 7.6.17(@types/react-dom@18.2.19)(@types/react@18.2.58)(react-dom@18.2.0)(react@18.2.0)
@@ -3010,6 +3013,210 @@ packages:
dev: true
optional: true
+ /@sentry-internal/browser-utils@8.22.0:
+ resolution: {integrity: sha512-R0u8KPaSivueIwUOhmYxcisKaJq3gx+I0xOcWoluDB3OI1Ds/QOSP/vmTsMg/mjwG/nUJ8RRM8pj0s8vlqCrjg==}
+ engines: {node: '>=14.18'}
+ dependencies:
+ '@sentry/core': 8.22.0
+ '@sentry/types': 8.22.0
+ '@sentry/utils': 8.22.0
+ dev: true
+
+ /@sentry-internal/feedback@8.22.0:
+ resolution: {integrity: sha512-Sy2+v0xBmVnZ5LQ48603CvLy5vVQvAZ+hc9xQSAHexts07NkvApMU1qv26YNwxlAWfDha1wXiW6ryd4YDzaoVA==}
+ engines: {node: '>=14.18'}
+ dependencies:
+ '@sentry/core': 8.22.0
+ '@sentry/types': 8.22.0
+ '@sentry/utils': 8.22.0
+ dev: true
+
+ /@sentry-internal/replay-canvas@8.22.0:
+ resolution: {integrity: sha512-/gV8qN3JqWw0LXTMuCGB8RDI8Bx1VESNRBdh/7Cmc5+hxYBfcketuix3S8mHWcE/JO+Ed9g1Abzys6GphTB9LA==}
+ engines: {node: '>=14.18'}
+ dependencies:
+ '@sentry-internal/replay': 8.22.0
+ '@sentry/core': 8.22.0
+ '@sentry/types': 8.22.0
+ '@sentry/utils': 8.22.0
+ dev: true
+
+ /@sentry-internal/replay@8.22.0:
+ resolution: {integrity: sha512-sF8RyMPJP1fSIyyBDAbtybvKCu0dy8ZAfMwLP7ZqEnWrhZqktVuqM7/++EAFMlD5YaWJXm1IDuOXjgSQjUtSIQ==}
+ engines: {node: '>=14.18'}
+ dependencies:
+ '@sentry-internal/browser-utils': 8.22.0
+ '@sentry/core': 8.22.0
+ '@sentry/types': 8.22.0
+ '@sentry/utils': 8.22.0
+ dev: true
+
+ /@sentry/babel-plugin-component-annotate@2.21.1:
+ resolution: {integrity: sha512-u1L8gZ4He0WdyiIsohYkA/YOY1b6Oa5yIMRtfZZ9U5TiWYLgOfMWyb88X0GotZeghSbgxrse/yI4WeHnhAUQDQ==}
+ engines: {node: '>= 14'}
+ dev: true
+
+ /@sentry/browser@8.22.0:
+ resolution: {integrity: sha512-t3b+/9WWcP9SQTWwrHrB57B33ENgmUjyFlW2+JSlCXkSJBSmAoquPZ/GPjOuPaSr3HIA0mu9uEr4A41d5diASQ==}
+ engines: {node: '>=14.18'}
+ dependencies:
+ '@sentry-internal/browser-utils': 8.22.0
+ '@sentry-internal/feedback': 8.22.0
+ '@sentry-internal/replay': 8.22.0
+ '@sentry-internal/replay-canvas': 8.22.0
+ '@sentry/core': 8.22.0
+ '@sentry/types': 8.22.0
+ '@sentry/utils': 8.22.0
+ dev: true
+
+ /@sentry/bundler-plugin-core@2.21.1:
+ resolution: {integrity: sha512-F8FdL/bS8cy1SY1Gw0Mfo3ROTqlrq9Lvt5QGvhXi22dpVcDkWmoTWE2k+sMEnXOa8SdThMc/gyC8lMwHGd3kFQ==}
+ engines: {node: '>= 14'}
+ dependencies:
+ '@babel/core': 7.23.9
+ '@sentry/babel-plugin-component-annotate': 2.21.1
+ '@sentry/cli': 2.33.1
+ dotenv: 16.4.5
+ find-up: 5.0.0
+ glob: 9.3.5
+ magic-string: 0.30.8
+ unplugin: 1.0.1
+ transitivePeerDependencies:
+ - encoding
+ - supports-color
+ dev: true
+
+ /@sentry/cli-darwin@2.33.1:
+ resolution: {integrity: sha512-+4/VIx/E1L2hChj5nGf5MHyEPHUNHJ/HoG5RY+B+vyEutGily1c1+DM2bum7RbD0xs6wKLIyup5F02guzSzG8A==}
+ engines: {node: '>=10'}
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@sentry/cli-linux-arm64@2.33.1:
+ resolution: {integrity: sha512-DbGV56PRKOLsAZJX27Jt2uZ11QfQEMmWB4cIvxkKcFVE+LJP4MVA+MGGRUL6p+Bs1R9ZUuGbpKGtj0JiG6CoXw==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [linux, freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@sentry/cli-linux-arm@2.33.1:
+ resolution: {integrity: sha512-zbxEvQju+tgNvzTOt635le4kS/Fbm2XC2RtYbCTs034Vb8xjrAxLnK0z1bQnStUV8BkeBHtsNVrG+NSQDym2wg==}
+ engines: {node: '>=10'}
+ cpu: [arm]
+ os: [linux, freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@sentry/cli-linux-i686@2.33.1:
+ resolution: {integrity: sha512-g2LS4oPXkPWOfKWukKzYp4FnXVRRSwBxhuQ9eSw2peeb58ZIObr4YKGOA/8HJRGkooBJIKGaAR2mH2Pk1TKaiA==}
+ engines: {node: '>=10'}
+ cpu: [x86, ia32]
+ os: [linux, freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@sentry/cli-linux-x64@2.33.1:
+ resolution: {integrity: sha512-IV3dcYV/ZcvO+VGu9U6kuxSdbsV2kzxaBwWUQxtzxJ+cOa7J8Hn1t0koKGtU53JVZNBa06qJWIcqgl4/pCuKIg==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [linux, freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@sentry/cli-win32-i686@2.33.1:
+ resolution: {integrity: sha512-F7cJySvkpzIu7fnLKNHYwBzZYYwlhoDbAUnaFX0UZCN+5DNp/5LwTp37a5TWOsmCaHMZT4i9IO4SIsnNw16/zQ==}
+ engines: {node: '>=10'}
+ cpu: [x86, ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@sentry/cli-win32-x64@2.33.1:
+ resolution: {integrity: sha512-8VyRoJqtb2uQ8/bFRKNuACYZt7r+Xx0k2wXRGTyH05lCjAiVIXn7DiS2BxHFty7M1QEWUCMNsb/UC/x/Cu2wuA==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@sentry/cli@2.33.1:
+ resolution: {integrity: sha512-dUlZ4EFh98VFRPJ+f6OW3JEYQ7VvqGNMa0AMcmvk07ePNeK/GicAWmSQE4ZfJTTl80ul6HZw1kY01fGQOQlVRA==}
+ engines: {node: '>= 10'}
+ hasBin: true
+ requiresBuild: true
+ dependencies:
+ https-proxy-agent: 5.0.1
+ node-fetch: 2.7.0
+ progress: 2.0.3
+ proxy-from-env: 1.1.0
+ which: 2.0.2
+ optionalDependencies:
+ '@sentry/cli-darwin': 2.33.1
+ '@sentry/cli-linux-arm': 2.33.1
+ '@sentry/cli-linux-arm64': 2.33.1
+ '@sentry/cli-linux-i686': 2.33.1
+ '@sentry/cli-linux-x64': 2.33.1
+ '@sentry/cli-win32-i686': 2.33.1
+ '@sentry/cli-win32-x64': 2.33.1
+ transitivePeerDependencies:
+ - encoding
+ - supports-color
+ dev: true
+
+ /@sentry/core@8.22.0:
+ resolution: {integrity: sha512-fYPnxp7UkY2tckaOtivIySxnJvlbekuxs+Qi6rkUv9JpF+TYKpt7OPNUAbgVIhS0xazAEN6iKTfmnmpUbFRLmQ==}
+ engines: {node: '>=14.18'}
+ dependencies:
+ '@sentry/types': 8.22.0
+ '@sentry/utils': 8.22.0
+ dev: true
+
+ /@sentry/react@8.22.0(react@18.2.0):
+ resolution: {integrity: sha512-LcO8SPfjYsx3Zvg1mQwjreVvtriVxde+6njIJyXU9TArB0e8bFexvd4MGXdBExgW9aY449hNaStgKRWMNHeVHQ==}
+ engines: {node: '>=14.18'}
+ peerDependencies:
+ react: ^16.14.0 || 17.x || 18.x || 19.x
+ dependencies:
+ '@sentry/browser': 8.22.0
+ '@sentry/core': 8.22.0
+ '@sentry/types': 8.22.0
+ '@sentry/utils': 8.22.0
+ hoist-non-react-statics: 3.3.2
+ react: 18.2.0
+ dev: true
+
+ /@sentry/types@8.22.0:
+ resolution: {integrity: sha512-1MLK3xO+uF2oJaa+M98aLIrQsEHzV7xnVWPfE3MhejYLNQebj4rQnQKTut/xZNIF9W0Q+bRcakLarC3ce2a74g==}
+ engines: {node: '>=14.18'}
+ dev: true
+
+ /@sentry/utils@8.22.0:
+ resolution: {integrity: sha512-0ITG2+3EtyMtyc/nQG8aB9z9eIQ4L43nM/KuNgYSnM1vPl/zegbaLT0Ek/xkQB1OLIOLkEPQ6x9GWe+248/n3g==}
+ engines: {node: '>=14.18'}
+ dependencies:
+ '@sentry/types': 8.22.0
+ dev: true
+
+ /@sentry/vite-plugin@2.21.1:
+ resolution: {integrity: sha512-i2PqeLafGBcSROnmr9mS0dL2/JBJji/4rJZ2U2A+tqtAhDAAaCUNalbn6xLp/hawLExt/wRuBj1J7j46sGDOaA==}
+ engines: {node: '>= 14'}
+ dependencies:
+ '@sentry/bundler-plugin-core': 2.21.1
+ unplugin: 1.0.1
+ transitivePeerDependencies:
+ - encoding
+ - supports-color
+ dev: true
+
/@sinclair/typebox@0.27.8:
resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
dev: true
@@ -4655,6 +4862,15 @@ packages:
engines: {node: '>= 6.0.0'}
dev: true
+ /agent-base@6.0.2:
+ resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
+ engines: {node: '>= 6.0.0'}
+ dependencies:
+ debug: 4.3.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
/aggregate-error@3.1.0:
resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
engines: {node: '>=8'}
@@ -6764,6 +6980,16 @@ packages:
path-is-absolute: 1.0.1
dev: true
+ /glob@9.3.5:
+ resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ dependencies:
+ fs.realpath: 1.0.0
+ minimatch: 8.0.4
+ minipass: 4.2.8
+ path-scurry: 1.10.1
+ dev: true
+
/globals@11.12.0:
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
engines: {node: '>=4'}
@@ -6882,7 +7108,6 @@ packages:
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
dependencies:
react-is: 16.13.1
- dev: false
/hosted-git-info@2.8.9:
resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
@@ -6914,6 +7139,16 @@ packages:
- supports-color
dev: true
+ /https-proxy-agent@5.0.1:
+ resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
+ engines: {node: '>= 6'}
+ dependencies:
+ agent-base: 6.0.2
+ debug: 4.3.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
/human-signals@2.1.0:
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
engines: {node: '>=10.17.0'}
@@ -7574,6 +7809,21 @@ packages:
dependencies:
js-tokens: 4.0.0
+ /lottie-react@2.4.0(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-pDJGj+AQlnlyHvOHFK7vLdsDcvbuqvwPZdMlJ360wrzGFurXeKPr8SiRCjLf3LrNYKANQtSsh5dz9UYQHuqx4w==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+ dependencies:
+ lottie-web: 5.12.2
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /lottie-web@5.12.2:
+ resolution: {integrity: sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==}
+ dev: false
+
/loupe@2.3.7:
resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==}
dependencies:
@@ -7609,6 +7859,13 @@ packages:
'@jridgewell/sourcemap-codec': 1.4.15
dev: true
+ /magic-string@0.30.8:
+ resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.4.15
+ dev: true
+
/make-dir@2.1.0:
resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
engines: {node: '>=6'}
@@ -7740,6 +7997,13 @@ packages:
brace-expansion: 2.0.1
dev: true
+ /minimatch@8.0.4:
+ resolution: {integrity: sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ dependencies:
+ brace-expansion: 2.0.1
+ dev: true
+
/minimatch@9.0.3:
resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
engines: {node: '>=16 || 14 >=14.17'}
@@ -7765,6 +8029,11 @@ packages:
yallist: 4.0.0
dev: true
+ /minipass@4.2.8:
+ resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==}
+ engines: {node: '>=8'}
+ dev: true
+
/minipass@5.0.0:
resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==}
engines: {node: '>=8'}
@@ -8627,16 +8896,6 @@ packages:
react: 18.2.0
dev: false
- /react-spinners@0.13.8(react-dom@18.2.0)(react@18.2.0):
- resolution: {integrity: sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA==}
- peerDependencies:
- react: ^16.0.0 || ^17.0.0 || ^18.0.0
- react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0
- dependencies:
- react: 18.2.0
- react-dom: 18.2.0(react@18.2.0)
- dev: false
-
/react-style-singleton@2.2.1(@types/react@18.2.58)(react@18.2.0):
resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==}
engines: {node: '>=10'}
@@ -9720,6 +9979,15 @@ packages:
engines: {node: '>= 0.8'}
dev: true
+ /unplugin@1.0.1:
+ resolution: {integrity: sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA==}
+ dependencies:
+ acorn: 8.12.0
+ chokidar: 3.6.0
+ webpack-sources: 3.2.3
+ webpack-virtual-modules: 0.5.0
+ dev: true
+
/unplugin@1.7.1:
resolution: {integrity: sha512-JqzORDAPxxs8ErLV4x+LL7bk5pk3YlcWqpSNsIkAZj972KzFZLClc/ekppahKkOczGkwIG6ElFgdOgOlK4tXZw==}
dependencies:
@@ -9918,6 +10186,10 @@ packages:
engines: {node: '>=10.13.0'}
dev: true
+ /webpack-virtual-modules@0.5.0:
+ resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==}
+ dev: true
+
/webpack-virtual-modules@0.6.1:
resolution: {integrity: sha512-poXpCylU7ExuvZK8z+On3kX+S8o/2dQ/SVYueKA0D4WEMXROXgY8Ez50/bQEUmvoSMMrWcrJqCHuhAbsiwg7Dg==}
dev: true
@@ -10001,15 +10273,18 @@ packages:
resolution: {integrity: sha512-fMGyb92sZ1iSf0TGSabQVym/MWsYyfetgBBNbZ0K6eGfESKtZF8AM1aDYRODmwyPkPSnt0SmOtRWMDxnPsnCqg==}
dev: false
- /wowds-ui@0.1.7(next@14.2.4)(react@18.2.0):
- resolution: {integrity: sha512-ls2SnsTVfZpF2IOVu1N0FSo+XdGtlxtp+YOTwdd/l2lLX+Mh99/HKLsH6Q36p+yRF9zu0iiHv5dIlX790jvkOg==}
+ /wowds-ui@0.1.9(next@14.2.4)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-MDH0HqUCoRlHF1jtl+S6h+vusy5Lli+SVdu2SLhTaxlWJ6JQIqubesvNa16vaq/hRpn4WByX6x+aHrtM57cz3A==}
peerDependencies:
next: ^14.1.1
react: ^18.2.0
dependencies:
+ lottie-react: 2.4.0(react-dom@18.2.0)(react@18.2.0)
next: 14.2.4(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0)(sass@1.71.1)
react: 18.2.0
wowds-icons: 0.1.1
+ transitivePeerDependencies:
+ - react-dom
dev: false
/wrap-ansi@7.0.0:
diff --git a/src/App.tsx b/src/App.tsx
index be0eca6..b952095 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -12,9 +12,8 @@ import styled from '@emotion/styled';
import { css } from '@emotion/react';
import GlobalSize from '@/constants/globalSize';
import { useNavigate } from 'react-router-dom';
-import { getAuthRedirectPath } from '@/utils/auth';
import 'react-toastify/dist/ReactToastify.css';
-import useLandingStatus from '@/hooks/zustand/useLandingStatus';
+import RoutePath from './routes/routePath';
const IMG_SRC = [
'/onboarding/1.png',
@@ -29,7 +28,6 @@ const IMG_SRC = [
function App() {
const navigate = useNavigate();
- const { landingStatus } = useLandingStatus();
return (
@@ -162,12 +160,8 @@ function App() {
- navigate(getAuthRedirectPath(landingStatus))}>
- {landingStatus === 'ONBOARDING_CLOSED'
- ? '지금은 지원 기간이 아니에요'
- : '가입하기'}
+ navigate(RoutePath.Dashboard)}>
+ 가입하기
diff --git a/src/apis/auth/authApi.ts b/src/apis/auth/authApi.ts
new file mode 100644
index 0000000..150379e
--- /dev/null
+++ b/src/apis/auth/authApi.ts
@@ -0,0 +1,9 @@
+import apiClient from '..';
+
+const authApi = {
+ LOGOUT: async () => {
+ const response = await apiClient.get(`/auth/logout`);
+ return response.data;
+ }
+};
+export default authApi;
diff --git a/src/apis/discord/discordApi.ts b/src/apis/discord/discordApi.ts
index 5a795d6..40810f3 100644
--- a/src/apis/discord/discordApi.ts
+++ b/src/apis/discord/discordApi.ts
@@ -25,7 +25,7 @@ const discordApi = {
});
return response.data;
},
- GET_DISCORD_JOIN: async (name: string) => {
+ GET_DISCORD_JOIN: async (name: string): Promise<{ isJoined: boolean }> => {
const response = await apiClient.get('/onboarding/check-discord-join', {
params: {
username: name
diff --git a/src/apis/index.ts b/src/apis/index.ts
index a09ed77..ff10199 100644
--- a/src/apis/index.ts
+++ b/src/apis/index.ts
@@ -1,5 +1,4 @@
import { BASE_URL, DEV_AUTH_TOKEN } from '@/constants/environment';
-import useAuthToken from '@/hooks/auth/useAuthToken';
import axios from 'axios';
const apiClient = axios.create({
@@ -8,8 +7,12 @@ const apiClient = axios.create({
withCredentials: true
});
-apiClient.defaults.headers.common['Authorization'] = DEV_AUTH_TOKEN
- ? `${DEV_AUTH_TOKEN}`
- : `Bearer ${useAuthToken().accessToken}`;
+export function setAuthHeader() {
+ if (DEV_AUTH_TOKEN) {
+ apiClient.defaults.headers.common['Authorization'] = DEV_AUTH_TOKEN;
+ }
+}
+
+setAuthHeader();
export default apiClient;
diff --git a/src/apis/member/memberType.ts b/src/apis/member/memberType.ts
index 13f24eb..abd5ae0 100644
--- a/src/apis/member/memberType.ts
+++ b/src/apis/member/memberType.ts
@@ -1,6 +1,5 @@
-import { Status } from '@/types/status';
import { User } from '@/types/user';
-
+import { Status } from '@/types/status';
export interface MemberInfoResponse {
member: User;
currentRecruitmentRound: CurrentRecruitmentType;
diff --git a/src/components/ApiErrorBoundary.tsx b/src/components/ApiErrorBoundary.tsx
index 29bb051..d0efcd9 100644
--- a/src/components/ApiErrorBoundary.tsx
+++ b/src/components/ApiErrorBoundary.tsx
@@ -31,7 +31,8 @@ export default function ApiErrorBoundary({ children }: PropsWithChildren) {
case 401:
case 403:
toast.error(message);
- redirect(RoutePath.Index);
+ sessionStorage.setItem('isLogin', 'false');
+ redirect(RoutePath.Home);
break;
default:
toast.error(message);
diff --git a/src/components/auth/guard/AuthAccessGuard.tsx b/src/components/auth/guard/AuthAccessGuard.tsx
index a147080..9ea265b 100644
--- a/src/components/auth/guard/AuthAccessGuard.tsx
+++ b/src/components/auth/guard/AuthAccessGuard.tsx
@@ -1,13 +1,25 @@
-import useLandingStatus from '@/hooks/zustand/useLandingStatus';
-import { useEffect } from 'react';
-import { Outlet } from 'react-router-dom';
+import RoutePath from '@/routes/routePath';
+import { isAuthenticated } from '@/utils/auth';
+import { toast } from 'react-toastify';
+import { useNavigate, Outlet } from 'react-router-dom';
+import { useEffect, useState } from 'react';
export default function AuthAccessGuard() {
- const { clearLandingStatus } = useLandingStatus();
+ const navigate = useNavigate();
+ const [redirect, setRedirect] = useState(false);
useEffect(() => {
- clearLandingStatus();
+ if (!isAuthenticated()) {
+ toast.error('로그인이 필요한 서비스예요.');
+ setRedirect(true);
+ }
}, []);
- return ;
+ useEffect(() => {
+ if (redirect) {
+ navigate(RoutePath.Home);
+ }
+ }, [redirect, navigate]);
+
+ return isAuthenticated() ? : null;
}
diff --git a/src/components/auth/guard/MypageAccessGuard.tsx b/src/components/auth/guard/MypageAccessGuard.tsx
deleted file mode 100644
index c0ff901..0000000
--- a/src/components/auth/guard/MypageAccessGuard.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import LandingStatus from '@/constants/landingStatus';
-import useLandingStatus from '@/hooks/zustand/useLandingStatus';
-import { getAuthRedirectPath } from '@/utils/auth';
-import { Navigate, Outlet } from 'react-router-dom';
-
-export default function MypageAccessGuard() {
- const { landingStatus } = useLandingStatus();
-
- if (landingStatus !== LandingStatus.Dashboard) {
- return ;
- }
-
- return ;
-}
diff --git a/src/components/auth/guard/OnboardingClosedAccessGuard.tsx b/src/components/auth/guard/OnboardingClosedAccessGuard.tsx
deleted file mode 100644
index a4f8916..0000000
--- a/src/components/auth/guard/OnboardingClosedAccessGuard.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import LandingStatus from '@/constants/landingStatus';
-import useLandingStatus from '@/hooks/zustand/useLandingStatus';
-import { getAuthRedirectPath } from '@/utils/auth';
-import { Navigate, Outlet } from 'react-router-dom';
-
-export default function OnboardingClosedAccessGuard() {
- const { landingStatus } = useLandingStatus();
-
- if (landingStatus !== LandingStatus.OnboardingClosed) {
- return ;
- }
-
- return ;
-}
diff --git a/src/components/auth/guard/OnboardingNotOpenedAccessGuard.tsx b/src/components/auth/guard/OnboardingNotOpenedAccessGuard.tsx
deleted file mode 100644
index 09a6899..0000000
--- a/src/components/auth/guard/OnboardingNotOpenedAccessGuard.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import LandingStatus from '@/constants/landingStatus';
-import useLandingStatus from '@/hooks/zustand/useLandingStatus';
-import { getAuthRedirectPath } from '@/utils/auth';
-import { Navigate, Outlet } from 'react-router-dom';
-
-export default function OnboardingNotOpenedAccessGuard() {
- const { landingStatus } = useLandingStatus();
-
- if (landingStatus !== LandingStatus.OnboardingNotOpened) {
- return ;
- }
-
- return ;
-}
diff --git a/src/components/auth/guard/PaymentAccessGuard.tsx b/src/components/auth/guard/PaymentAccessGuard.tsx
new file mode 100644
index 0000000..0337722
--- /dev/null
+++ b/src/components/auth/guard/PaymentAccessGuard.tsx
@@ -0,0 +1,58 @@
+import { useQuery } from '@tanstack/react-query';
+import memberApi from '@/apis/member/memberApi';
+import { useState, useEffect } from 'react';
+import { Outlet, useNavigate } from 'react-router-dom';
+import RoutePath from '@/routes/routePath';
+import { toast } from 'react-toastify';
+import LoadingSpinner from '@/components/common/LoadingSpinner';
+
+const PaymentAccessGuard = () => {
+ const [redirect, setRedirect] = useState(false);
+ const navigate = useNavigate();
+ const { data, isLoading } = useQuery({
+ queryKey: ['member'],
+ queryFn: memberApi.GET_DASHBOARD
+ });
+
+ useEffect(() => {
+ if (!data) return;
+
+ if (data.member.role !== 'ASSOCIATE') {
+ toast.error('준회원 조건을 충족해주세요.');
+ setRedirect(true);
+ }
+
+ if (!data.currentMembership) {
+ toast.error('정회원 지원 이후 학회비를 결제할 수 있어요.');
+ setRedirect(true);
+ }
+
+ if (!data.currentRecruitmentRound) {
+ toast.error('지금은 정회원 모집 기간이 아니에요.');
+ setRedirect(true);
+ }
+ }, []);
+
+ useEffect(() => {
+ if (redirect) {
+ navigate(RoutePath.Dashboard);
+ }
+ }, [redirect, navigate]);
+
+ if (isLoading) {
+ return ;
+ }
+
+ if (!data) return;
+
+ if (
+ data.member.role !== 'ASSOCIATE' ||
+ !data.currentRecruitmentRound ||
+ !data.currentMembership
+ ) {
+ navigate(RoutePath.Dashboard);
+ return null;
+ } else return ;
+};
+
+export default PaymentAccessGuard;
diff --git a/src/components/auth/guard/PaymentSuccessAccessGuard.tsx b/src/components/auth/guard/PaymentSuccessAccessGuard.tsx
new file mode 100644
index 0000000..d651bdc
--- /dev/null
+++ b/src/components/auth/guard/PaymentSuccessAccessGuard.tsx
@@ -0,0 +1,49 @@
+import { useQuery } from '@tanstack/react-query';
+import memberApi from '@/apis/member/memberApi';
+import { useState, useEffect } from 'react';
+import { Outlet, useNavigate } from 'react-router-dom';
+import RoutePath from '@/routes/routePath';
+import { toast } from 'react-toastify';
+import LoadingSpinner from '@/components/common/LoadingSpinner';
+
+const PaymentSuccessAccessGuard = () => {
+ const [redirect, setRedirect] = useState(false);
+ const navigate = useNavigate();
+ const { data, isLoading } = useQuery({
+ queryKey: ['member'],
+ queryFn: memberApi.GET_DASHBOARD
+ });
+
+ useEffect(() => {
+ if (!data) return;
+
+ if (data.member.role !== 'REGULAR') {
+ toast.error('토스페이먼츠 결제를 완료해주세요.');
+ setRedirect(true);
+ }
+
+ if (!data.currentRecruitmentRound) {
+ toast.error('지금은 정회원 모집 기간이 아니에요.');
+ setRedirect(true);
+ }
+ }, []);
+
+ useEffect(() => {
+ if (redirect) {
+ navigate(RoutePath.Dashboard);
+ }
+ }, [redirect, navigate]);
+
+ if (isLoading) {
+ return ;
+ }
+
+ if (!data) return;
+
+ if (data.member.role !== 'REGULAR' || !data.currentRecruitmentRound) {
+ navigate(RoutePath.Dashboard);
+ return null;
+ } else return ;
+};
+
+export default PaymentSuccessAccessGuard;
diff --git a/src/components/auth/guard/SignupAccessGuard.tsx b/src/components/auth/guard/SignupAccessGuard.tsx
deleted file mode 100644
index 94c42ac..0000000
--- a/src/components/auth/guard/SignupAccessGuard.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import { Outlet } from 'react-router-dom';
-
-//deprecated: 추후 삭제 필요한 파일임
-export default function SignupAccessGuard() {
- //TODO: 추후 보안 정책에 따라 수정 필요
- // if (landingStatus !== LandingStatus.Signup) {
- // return ;
- // }
-
- return ;
-}
diff --git a/src/components/auth/guard/StudentVerificationAccessGuard.tsx b/src/components/auth/guard/StudentVerificationAccessGuard.tsx
deleted file mode 100644
index 7ec9007..0000000
--- a/src/components/auth/guard/StudentVerificationAccessGuard.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import { Outlet } from 'react-router-dom';
-
-export default function StudentVerificationAccessGuard() {
- // const { landingStatus } = useLandingStatus();
-
- // if (landingStatus !== LandingStatus.StudentAuthentication) {
- // return ;
- // }
-
- return ;
-}
diff --git a/src/components/auth/guard/VerificationGuard.tsx b/src/components/auth/guard/VerificationGuard.tsx
new file mode 100644
index 0000000..223dc83
--- /dev/null
+++ b/src/components/auth/guard/VerificationGuard.tsx
@@ -0,0 +1,63 @@
+import RoutePath from '@/routes/routePath';
+import { toast } from 'react-toastify';
+import { useNavigate } from 'react-router-dom';
+import { PropsWithChildren, useEffect } from 'react';
+import memberApi from '@/apis/member/memberApi';
+import { useQuery } from '@tanstack/react-query';
+
+type GuardType = 'StudentVerification' | 'Discord' | 'SignUp' | 'Bevy';
+
+interface VerificationGuardProps extends PropsWithChildren {
+ guardType: GuardType;
+}
+/** 기본 정보, 디스코드 정보, 이메일 정보가 인증되어 있는지에 대한 가드 */
+
+export default function VerificationGuard({
+ guardType,
+ children
+}: VerificationGuardProps) {
+ const navigate = useNavigate();
+ const { data } = useQuery({
+ queryKey: ['member'],
+ queryFn: memberApi.GET_DASHBOARD
+ });
+
+ useEffect(() => {
+ if (!data) return;
+
+ if (
+ guardType === 'SignUp' &&
+ data.member.associateRequirement.infoStatus === 'SATISFIED'
+ ) {
+ toast.error('기본 정보를 이미 입력했습니다.');
+ navigate(RoutePath.Dashboard);
+ return;
+ }
+ if (
+ guardType === 'Discord' &&
+ data.member.associateRequirement.discordStatus === 'SATISFIED'
+ ) {
+ toast.error('디스코드 연동을 이미 완료했습니다.');
+ navigate(RoutePath.Dashboard);
+ return;
+ }
+ if (
+ guardType === 'StudentVerification' &&
+ data.member.associateRequirement.univStatus === 'SATISFIED'
+ ) {
+ toast.error('재학생 인증을 이미 완료했습니다.');
+ navigate(RoutePath.Dashboard);
+ return;
+ }
+ if (
+ guardType === 'Bevy' &&
+ data.member.associateRequirement.bevyStatus === 'SATISFIED'
+ ) {
+ toast.error('bevy 가입을 이미 완료했습니다.');
+ navigate(RoutePath.Dashboard);
+ return;
+ }
+ }, [data, guardType, navigate]);
+
+ return children;
+}
diff --git a/src/components/auth/guard/index.ts b/src/components/auth/guard/index.ts
deleted file mode 100644
index 2d1665d..0000000
--- a/src/components/auth/guard/index.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export { default as AuthAccessGuard } from './AuthAccessGuard';
-export { default as MypageAccessGuard } from './MypageAccessGuard';
-export { default as SignupAccessGuard } from './SignupAccessGuard';
-export { default as StudentVerificationAccessGuard } from './StudentVerificationAccessGuard';
-export { default as OnboardingNotOpenedAccessGuard } from './OnboardingNotOpenedAccessGuard';
-export { default as OnboardingClosedAccessGuard } from './OnboardingClosedAccessGuard';
diff --git a/src/components/bottomsheet/JoinRegularMemberBottomSheet.tsx b/src/components/bottomsheet/JoinRegularMemberBottomSheet.tsx
index ad1ea79..b8b4ca6 100644
--- a/src/components/bottomsheet/JoinRegularMemberBottomSheet.tsx
+++ b/src/components/bottomsheet/JoinRegularMemberBottomSheet.tsx
@@ -19,7 +19,10 @@ const JoinRegularMemberBottomSheet = ({
currentRecruitment: CurrentRecruitmentType;
}) => {
const { joinRegularMember } = useJoinRegularMember();
- const bottomSheetTitle = convertRecruitmentName(currentRecruitment.name);
+ const bottomSheetTitle = convertRecruitmentName(
+ currentRecruitment.name,
+ currentRecruitment.roundTypeValue
+ );
const recruitmentPeriod = convertRecruitmentPeriod(currentRecruitment.period);
return (
diff --git a/src/components/chatbot/ChannelService.ts b/src/components/chatbot/ChannelService.ts
deleted file mode 100644
index 70e5326..0000000
--- a/src/components/chatbot/ChannelService.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-declare global {
- interface Window {
- ChannelIO: (arg0: string, arg1?: unknown, arg2?: unknown) => void;
- ChannelIOInitialized: boolean;
- }
-}
-
-class ChannelService {
- constructor() {
- this.loadScript();
- }
-
- loadScript() {
- const w = window;
- if (w.ChannelIOInitialized) {
- return;
- }
- const channelIO = function () {
- // eslint-disable-next-line prefer-rest-params
- channelIO.c(arguments);
- };
-
- channelIO.q = [] as any[];
- channelIO.c = function (args: any) {
- channelIO.q.push(args);
- };
- w.ChannelIO = channelIO;
- function initializeChannelIO() {
- if (w.ChannelIOInitialized) {
- return;
- }
- w.ChannelIOInitialized = true;
- const script = document.createElement("script");
- script.type = "text/javascript";
- script.async = true;
- script.src = "https://cdn.channel.io/plugin/ch-plugin-web.js";
- const firstScript = document.getElementsByTagName("script")[0];
- if (firstScript?.parentNode) {
- firstScript.parentNode.insertBefore(script, firstScript);
- }
- }
- if (document.readyState === "complete") {
- initializeChannelIO();
- } else {
- w.addEventListener("DOMContentLoaded", initializeChannelIO);
- w.addEventListener("load", initializeChannelIO);
- }
- }
- boot(settings: any, callback: any) {
- window.ChannelIO("boot", settings, callback);
- }
- onBadgeChanged(callback: (number: number) => void) {
- window.ChannelIO("onBadgeChanged", callback);
- }
- addTags(tags: string[]) {
- window.ChannelIO("addTags", tags);
- }
- shutdown() {
- window.ChannelIO("shutdown");
- }
-}
-
-export default ChannelService;
diff --git a/src/components/chatbot/Chatbot.tsx b/src/components/chatbot/Chatbot.tsx
deleted file mode 100644
index 422ef9e..0000000
--- a/src/components/chatbot/Chatbot.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import { useEffect } from 'react';
-
-import { CHANNELIO_PLUGIN_KEY } from '@constants/environment';
-
-import ChannelService from '@/components/chatbot/ChannelService';
-
-export default function Chatbot() {
- useEffect(() => {
- const channelTalk = new ChannelService();
-
- channelTalk.boot({ pluginKey: CHANNELIO_PLUGIN_KEY }, () => {});
-
- return () => channelTalk.shutdown();
- }, []);
-
- return ;
-}
diff --git a/src/components/common/LoadingSpinner.tsx b/src/components/common/LoadingSpinner.tsx
new file mode 100644
index 0000000..5c31af5
--- /dev/null
+++ b/src/components/common/LoadingSpinner.tsx
@@ -0,0 +1,31 @@
+import RainbowSpinner from 'wowds-ui/RainbowSpinner';
+import { media } from '@/styles';
+import GlobalSize from '@/constants/globalSize';
+import { Flex } from './Wrapper';
+import { color } from 'wowds-tokens';
+import styled from '@emotion/styled';
+
+const LoadingSpinner = () => {
+ return (
+
+
+
+ );
+};
+
+export default LoadingSpinner;
+
+const Wrapper = styled(Flex)`
+ min-height: 100vh;
+ position: fixed;
+ top: 0;
+ z-index: 999;
+ width: ${GlobalSize.width};
+ margin: 0px -16px;
+ padding: 0px 16px;
+ gap: 40px;
+ background-color: ${color.blackOpacity40};
+ ${media.mobile} {
+ width: 100vw;
+ }
+`;
diff --git a/src/components/discordConnect/DiscordName.tsx b/src/components/discordConnect/DiscordName.tsx
index 9c64aa8..de483ff 100644
--- a/src/components/discordConnect/DiscordName.tsx
+++ b/src/components/discordConnect/DiscordName.tsx
@@ -15,9 +15,7 @@ export const DiscordName = ({ onNext }: { onNext: () => void }) => {
const { getValues, control, trigger, setError } =
useFormContext();
- const { checkDuplicate, data, isSuccess } = usePostDiscordName(
- getValues('discordUsername')
- );
+ const { checkDuplicate, data, isSuccess } = usePostDiscordName();
useEffect(() => {
if (isSuccess) {
@@ -36,14 +34,14 @@ export const DiscordName = ({ onNext }: { onNext: () => void }) => {
const handleNextClick = useCallback(async () => {
const isValid = await trigger('discordUsername');
if (isValid) {
- checkDuplicate();
+ checkDuplicate(getValues('discordUsername'));
} else {
setError('discordUsername', {
type: 'manual',
message: '하단 규정에 맞춰 작성해주세요.'
});
}
- }, [checkDuplicate, setError, trigger]);
+ }, [checkDuplicate, getValues, setError, trigger]);
return (
<>
diff --git a/src/components/discordConnect/DiscordNickName.tsx b/src/components/discordConnect/DiscordNickName.tsx
index 1b47310..62592f9 100644
--- a/src/components/discordConnect/DiscordNickName.tsx
+++ b/src/components/discordConnect/DiscordNickName.tsx
@@ -12,9 +12,7 @@ import Divider from 'wowds-ui/Divider';
export const DiscordNickName = ({ onNext }: { onNext: () => void }) => {
const { getValues, control, setError, clearErrors, trigger } =
useFormContext();
- const { checkDuplicate, data, isSuccess } = usePostDiscordNickname(
- getValues('discordNickname')
- );
+ const { checkDuplicate, data, isSuccess } = usePostDiscordNickname();
useEffect(() => {
if (isSuccess) {
@@ -33,14 +31,14 @@ export const DiscordNickName = ({ onNext }: { onNext: () => void }) => {
const handleNextClick = useCallback(async () => {
const isValid = await trigger('discordNickname');
if (isValid) {
- checkDuplicate();
+ checkDuplicate(getValues('discordNickname'));
} else {
setError('discordNickname', {
type: 'manual',
message: '하단 규정에 맞춰 작성해주세요.'
});
}
- }, [checkDuplicate, setError, trigger]);
+ }, [checkDuplicate, getValues, setError, trigger]);
return (
<>
diff --git a/src/components/discordConnect/JoinServer.tsx b/src/components/discordConnect/JoinServer.tsx
index bf11183..0b1f1f8 100644
--- a/src/components/discordConnect/JoinServer.tsx
+++ b/src/components/discordConnect/JoinServer.tsx
@@ -7,10 +7,29 @@ import { useFormContext } from 'react-hook-form';
import useGetDiscordJoined from '@/hooks/query/useGetDiscordJoined';
import { DiscordFormValues } from '@/types/discord';
import RoutePath from '@/routes/routePath';
+import { useState, useEffect } from 'react';
+
+const FETCH_INTERVAL = 5000;
export const JoinServer = ({ onNext }: { onNext: () => void }) => {
const { getValues } = useFormContext();
- const { data } = useGetDiscordJoined(getValues('discordUsername'));
+ const [callQuery, setCallQuery] = useState(false);
+
+ // 초기에 5초 후에 isEnabled를 true로 설정
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ setCallQuery(true);
+ }, FETCH_INTERVAL);
+
+ return () => clearTimeout(timer);
+ }, []);
+
+ const { data } = useGetDiscordJoined(getValues('discordUsername'), callQuery);
+
+ useEffect(() => {
+ if (data?.isJoined) setCallQuery(false);
+ }, [data]);
+
return (
<>
@@ -27,7 +46,7 @@ export const JoinServer = ({ onNext }: { onNext: () => void }) => {
window.open(RoutePath.GDSCHongikDiscord, '_blank')}
/>
@@ -38,7 +57,11 @@ export const JoinServer = ({ onNext }: { onNext: () => void }) => {
}}
disabled={!data?.isJoined}
style={{ maxWidth: '100%' }}>
- 합류가 확인되면 넘어갈 수 있어요.
+ {callQuery
+ ? '합류 여부를 확인 중이에요.'
+ : data?.isJoined
+ ? '합류가 확인되었어요.'
+ : '합류가 확인되지 않았어요.'}
{
- navigation(getAuthRedirectPath(landingStatus));
+ if (isAuthenticated()) navigation(RoutePath.Dashboard);
+ else {
+ navigation(RoutePath.GithubSignin);
+ }
};
return (
@@ -29,11 +30,9 @@ export default function Header() {
-
- {landingStatus === 'TO_DASHBOARD' && (
+ {isAuthenticated() ? (
내 정보
- )}
- {pathname === '/' && landingStatus !== 'TO_DASHBOARD' && (
+ ) : (
로그인/가입하기
)}
diff --git a/src/components/layout/Layout.tsx b/src/components/layout/Layout.tsx
index aa2a109..97817f0 100644
--- a/src/components/layout/Layout.tsx
+++ b/src/components/layout/Layout.tsx
@@ -4,12 +4,18 @@ import { media } from '@/styles';
import { color } from 'wowds-tokens';
import Header from '@/components/layout/Header';
import Footer from '@/components/layout/Footer';
-
-import { Outlet } from 'react-router-dom';
+import { useLayoutEffect } from 'react';
+import { Outlet, useLocation } from 'react-router-dom';
import GlobalSize from '@/constants/globalSize';
import ApiErrorBoundary from '@/components/ApiErrorBoundary';
const Layout = () => {
+ const location = useLocation();
+
+ useLayoutEffect(() => {
+ window.scrollTo(0, 0);
+ }, [location]);
+
return (
diff --git a/src/components/myPage/ApproveBox.tsx b/src/components/myPage/ApproveBox.tsx
index 28cf01d..d6df24e 100644
--- a/src/components/myPage/ApproveBox.tsx
+++ b/src/components/myPage/ApproveBox.tsx
@@ -6,8 +6,8 @@ import {
convertRecruitmentName
} from '@/utils/mypage/recruitmentNameFormat';
import useBottomSheet from '@/hooks/common/useBottomSheet';
+import { UserRoleType } from '@/types/user';
-type MemberRole = 'GUEST' | 'ASSOCIATE' | 'REGULAR' | 'ADMIN';
type BoxVariantType = 'arrow' | 'checkbox' | 'text' | 'warn';
type BoxStatusType = 'default' | 'success' | 'error';
@@ -15,12 +15,23 @@ export const ApproveBox = ({
role,
currentRecruitment
}: {
- role: MemberRole;
+ role: UserRoleType;
currentRecruitment: CurrentRecruitmentType;
}) => {
const { handleBottomSheet } = useBottomSheet();
+
+ if (!currentRecruitment) {
+ return (
+
+ );
+ }
const boxContent: Record<
- MemberRole,
+ UserRoleType,
{
title: string;
description?: string;
@@ -29,13 +40,13 @@ export const ApproveBox = ({
}
> = {
GUEST: {
- title: `${convertRecruitmentName(currentRecruitment.name)}`,
+ title: `${convertRecruitmentName(currentRecruitment.name, currentRecruitment.roundTypeValue)}`,
description: '하단의 준회원 가입 조건을 완료해주세요.',
boxVariant: 'warn',
status: 'error'
},
ASSOCIATE: {
- title: `${convertRecruitmentName(currentRecruitment.name)}`,
+ title: `${convertRecruitmentName(currentRecruitment.name, currentRecruitment.roundTypeValue)}`,
description: `${convertRecruitmentPeriod(currentRecruitment.period)}`,
boxVariant: 'arrow',
status: 'error'
@@ -44,12 +55,6 @@ export const ApproveBox = ({
title: '모든 가입 절차를 완료했어요.',
boxVariant: 'text',
status: 'success'
- },
- //TODO: 어드민 가입 상태 논의하기
- ADMIN: {
- title: '모든 가입 절차를 완료했어요.',
- boxVariant: 'text',
- status: 'success'
}
};
return (
diff --git a/src/components/myPage/AssociateRequirementCheck.tsx b/src/components/myPage/AssociateRequirementCheck.tsx
index 2deefd4..e0206de 100644
--- a/src/components/myPage/AssociateRequirementCheck.tsx
+++ b/src/components/myPage/AssociateRequirementCheck.tsx
@@ -1,5 +1,6 @@
import { Flex, Text } from '@/components/common/Wrapper';
import Box from 'wowds-ui/Box';
+import { UnivEmailStatus } from '@/types/status';
import { Discord } from '@/assets/Discord';
import { AssociateRequirement } from '@/types/user';
import RoutePath from '@/routes/routePath';
@@ -14,6 +15,42 @@ const AssociateRequirementCheck = ({
associateRequirement;
const navigate = useNavigate();
+ const univStatusContent = (univStatus: UnivEmailStatus) => {
+ if (univStatus === 'UNSATISFIED')
+ return (
+
+
+ 재학생 이메일 인증이 필요해요.
+
+
+ 홍익대학교 재학생인지 알려주세요.
+
+ 학교 Gmail을 통해 인증할 수 있어요.
+
+
+ );
+ if (univStatus === 'IN_PROGRESS')
+ return (
+
+
+ 재학생 이메일 인증이 진행 중이에요.
+
+
+ 메일함을 확인해주세요.
+
+
+ );
+ return '홍익대학교 재학생 인증을 완료했어요.';
+ };
+
return (
@@ -21,30 +58,29 @@ const AssociateRequirementCheck = ({
{
- if (infoStatus === 'PENDING')
- navigate(RoutePath.AuthenticationProcess3_Signup);
+ if (infoStatus === 'UNSATISFIED') navigate(RoutePath.Signup);
}}
- status={infoStatus === 'PENDING' ? 'error' : 'success'}
- variant={infoStatus === 'PENDING' ? 'arrow' : 'text'}
+ status={infoStatus === 'UNSATISFIED' ? 'error' : 'success'}
+ variant={infoStatus === 'UNSATISFIED' ? 'arrow' : 'text'}
/>
}
- variant={discordStatus === 'PENDING' ? 'arrow' : 'text'}
- status={discordStatus === 'PENDING' ? 'error' : 'success'}
+ variant={discordStatus === 'UNSATISFIED' ? 'arrow' : 'text'}
+ status={discordStatus === 'UNSATISFIED' ? 'error' : 'success'}
onClick={() => {
- if (discordStatus === 'PENDING') {
+ if (discordStatus === 'UNSATISFIED') {
navigate(RoutePath.Discord);
} else {
window.open('https://discord.gg/dSV6vSEuGU');
@@ -53,34 +89,15 @@ const AssociateRequirementCheck = ({
/>
{
- navigate(RoutePath.AuthenticationProcess2_StudentVerification);
+ navigate(RoutePath.StudentVerification);
}}
- text={
- univStatus === 'PENDING' ? (
-
-
- 재학생 이메일 인증이 필요해요.
-
-
- 홍익대학교 재학생인지 알려주세요.
-
- 학교 Gmail을 통해 인증할 수 있어요.
-
-
- ) : (
- '홍익대학교 재학생 인증을 완료했어요.'
- )
- }
- status={univStatus === 'PENDING' ? 'error' : 'success'}
- variant={univStatus === 'PENDING' ? 'arrow' : 'text'}
+ text={univStatusContent(univStatus)}
+ status={univStatus === 'SATISFIED' ? 'success' : 'error'}
+ variant={univStatus === 'SATISFIED' ? 'text' : 'arrow'}
/>
{
- if (bevyStatus === 'PENDING') {
+ if (bevyStatus === 'UNSATISFIED') {
navigate(RoutePath.Bevy);
} else {
window.open(
diff --git a/src/components/myPage/BasicUserInfo.tsx b/src/components/myPage/BasicUserInfo.tsx
index 64fb95b..3858f7a 100644
--- a/src/components/myPage/BasicUserInfo.tsx
+++ b/src/components/myPage/BasicUserInfo.tsx
@@ -1,20 +1,12 @@
import { Flex, Text } from '@/components/common/Wrapper';
import { User } from '@/types/user';
-import useLandingStatus from '@/hooks/zustand/useLandingStatus';
-import { logout } from '@/utils/auth';
+import { useLogout } from '@/hooks/mutation';
import { typography, color } from 'wowds-tokens';
-import { useNavigate } from 'react-router-dom';
-
const BasicUserInfo = ({ member }: { member: User }) => {
- const navigate = useNavigate();
- const { clearLandingStatus } = useLandingStatus();
-
+ const { mutate } = useLogout();
const handleLogoutClick = () => {
- clearLandingStatus();
- logout();
-
- navigate('/');
+ mutate();
};
return (
diff --git a/src/components/myPage/JoinRegularMember.tsx b/src/components/myPage/JoinRegularMember.tsx
index a4068fd..6286d03 100644
--- a/src/components/myPage/JoinRegularMember.tsx
+++ b/src/components/myPage/JoinRegularMember.tsx
@@ -1,17 +1,14 @@
import { Text, Flex } from '@/components/common/Wrapper';
import RoutePath from '@/routes/routePath';
+import { Status } from '@/types/status';
import { useNavigate } from 'react-router-dom';
import Box from 'wowds-ui/Box';
-const JoinRegularMember = ({
- paymentStatus
-}: {
- paymentStatus: 'PENDING' | 'SATISFIED';
-}) => {
+const JoinRegularMember = ({ paymentStatus }: { paymentStatus: Status }) => {
const navigate = useNavigate();
const handleClickRoute = () => {
- if (paymentStatus !== 'PENDING') {
+ if (paymentStatus !== 'UNSATISFIED') {
return;
}
navigate(RoutePath.PaymentsCheckout);
@@ -28,15 +25,15 @@ const JoinRegularMember = ({
diff --git a/src/components/myPage/JoinStatus.tsx b/src/components/myPage/JoinStatus.tsx
index 58efd73..b8542e0 100644
--- a/src/components/myPage/JoinStatus.tsx
+++ b/src/components/myPage/JoinStatus.tsx
@@ -7,16 +7,14 @@ import { ApproveBox } from './ApproveBox';
import { Text, Flex, Space } from '../common/Wrapper';
import { CurrentRecruitmentType } from '@/apis/member/memberType';
import MemberStatusStepper from './MemberStatusStepper';
-import { User } from '@/types/user';
-
-type MemberRole = 'GUEST' | 'ASSOCIATE' | 'REGULAR' | 'ADMIN';
+import { User, UserRoleType } from '@/types/user';
const JoinStatus = ({
role,
currentRecruitmentRound,
member
}: {
- role: MemberRole;
+ role: UserRoleType;
currentRecruitmentRound: CurrentRecruitmentType;
member: User;
}) => {
diff --git a/src/components/payments/PaymentsWidget.tsx b/src/components/payments/PaymentsWidget.tsx
index 6f107d2..5c76830 100644
--- a/src/components/payments/PaymentsWidget.tsx
+++ b/src/components/payments/PaymentsWidget.tsx
@@ -34,7 +34,7 @@ export function PaymentsWidget() {
const { name, amount, discount, issuedCouponId, totalAmount } = useProduct();
- const { postPrevOrder } = usePostPrevOrder(amount);
+ const { postPrevOrder } = usePostPrevOrder(totalAmount);
const [ready, setReady] = useState(false);
diff --git a/src/components/auth/DepartmentSelect.tsx b/src/components/signup/DepartmentSelect.tsx
similarity index 54%
rename from src/components/auth/DepartmentSelect.tsx
rename to src/components/signup/DepartmentSelect.tsx
index 7c00368..a54256e 100644
--- a/src/components/auth/DepartmentSelect.tsx
+++ b/src/components/signup/DepartmentSelect.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+import styled from '@emotion/styled';
import { useGetDepartmentList } from '@/hooks/query';
import { Control, Controller } from 'react-hook-form';
import DropDown from 'wowds-ui/DropDown';
@@ -32,28 +33,35 @@ const DepartmentSelect = ({ control }: DepartmentSelectProps) => {
}
}}
render={({ field }) => (
- {
- field.onChange(selectedValue);
- }}>
-
- {departmentList.map((department, index) => {
- return (
-
- );
- })}
-
-
+
+ {
+ field.onChange(selectedValue);
+ }}>
+
+ {departmentList.map((department, index) => {
+ return (
+
+ );
+ })}
+
+
+
)}
/>
);
};
export default DepartmentSelect;
+
+const InputFormWrapper = styled.div`
+ height: 84.8px;
+ width: 100%;
+`;
diff --git a/src/components/signup/EmailInputField.tsx b/src/components/signup/EmailInputField.tsx
new file mode 100644
index 0000000..fa2f587
--- /dev/null
+++ b/src/components/signup/EmailInputField.tsx
@@ -0,0 +1,139 @@
+import { useState } from 'react';
+import styled from '@emotion/styled';
+import { Control, Controller } from 'react-hook-form';
+import DropDown from 'wowds-ui/DropDown';
+import DropDownOption from 'wowds-ui/DropDownOption';
+import { space } from 'wowds-tokens';
+import TextField from 'wowds-ui/TextField';
+
+type DepartmentSelectProps = {
+ control:
+ | Control<{
+ name: string;
+ studentId: string;
+ phone: string;
+ department: string;
+ email: string;
+ emailDomain: string;
+ terms: boolean;
+ personalPrivacy: boolean;
+ }>
+ | undefined;
+};
+
+const EmailInputField = ({ control }: DepartmentSelectProps) => {
+ const [customEmail, setCustomEmail] = useState(false);
+ return (
+
+ (
+
+
+
+ )}
+ />
+ (
+
+ {customEmail ? (
+
+
+
+ ) : (
+ {
+ if (selectedValue === 'custom') {
+ setCustomEmail(true);
+ } else {
+ field.onChange(selectedValue);
+ }
+ }}
+ style={{ marginTop: '22px', flex: 1, width: '100%' }}>
+
+
+
+
+
+
+ )}
+
+ )}
+ />
+
+ );
+};
+
+export default EmailInputField;
+
+const TextFieldWrapper = styled.div`
+ flex: 1;
+ height: 84.8px;
+`;
+
+const EmailFieldWrapper = styled.div`
+ position: relative;
+ width: 100%;
+ display: flex;
+ gap: ${space.sm};
+ align-items: center;
+ justify-content: space-between;
+`;
diff --git a/src/constants/environment.ts b/src/constants/environment.ts
index ab88763..6d5cc9e 100644
--- a/src/constants/environment.ts
+++ b/src/constants/environment.ts
@@ -4,5 +4,7 @@ export const {
VITE_DEV_AUTH_TOKEN: DEV_AUTH_TOKEN,
VITE_ACCESS_TOKEN: ACCESS_TOKEN,
VITE_CLIENT_KEY: CLIENT_KEY,
- REACT_APP_SECURE_LOCAL_STORAGE_HASH_KEY: SECURE_KEY
+ REACT_APP_SECURE_LOCAL_STORAGE_HASH_KEY: SECURE_KEY,
+ SENTRY_DSN_KEY: SENTRY_DSN_KEY,
+ SENTRY_AUTH_TOKEN: SENTRY_AUTH_TOKEN
} = import.meta.env;
diff --git a/src/constants/landingStatus.ts b/src/constants/landingStatus.ts
deleted file mode 100644
index 8430a3a..0000000
--- a/src/constants/landingStatus.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-//TODO: 추후, TO_DASHBOARD 제외하고 모두 제거
-const enum LandingStatus {
- //TO_DASHBOARD 이외 모든 페이지 서버에서 삭제된 상태임
- StudentAuthentication = 'TO_STUDENT_AUTHENTICATION',
- Signup = 'TO_REGISTRATION',
- Dashboard = 'TO_DASHBOARD',
- OnboardingNotOpened = 'ONBOARDING_NOT_OPENED',
- OnboardingClosed = 'ONBOARDING_CLOSED'
-}
-
-export default LandingStatus;
diff --git a/src/hooks/auth/useAuthToken.ts b/src/hooks/auth/useAuthToken.ts
deleted file mode 100644
index c86c7cf..0000000
--- a/src/hooks/auth/useAuthToken.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { deleteCookie, getCookie, setCookie } from '@/utils/auth';
-import { CookieKeys } from '@/utils/storage/key';
-
-export default function useAuthToken() {
- return {
- accessToken: getCookie(CookieKeys.AccessToken),
- refreshToken: getCookie(CookieKeys.RefreshToken),
- setToken: ({ type, value }: { type: CookieKeys; value: string | null }) => {
- if (value) {
- setCookie({ key: type, value });
- }
- },
- clearToken: () => {
- deleteCookie(CookieKeys.AccessToken);
- deleteCookie(CookieKeys.RefreshToken);
- }
- };
-}
diff --git a/src/hooks/auth/useStudentVerification.ts b/src/hooks/auth/useStudentVerification.ts
index ec800f5..7c452e5 100644
--- a/src/hooks/auth/useStudentVerification.ts
+++ b/src/hooks/auth/useStudentVerification.ts
@@ -24,7 +24,7 @@ export default function useStudentVerification() {
const onSubmit = async ({ univEmail }: FieldValues) => {
event?.preventDefault();
updateUnivEmail(univEmail);
- sendStudentEmail(univEmail);
+ sendStudentEmail(`${univEmail}@g.hongik.ac.kr`);
};
const onVerifyStudent = () => {
diff --git a/src/hooks/mutation/index.ts b/src/hooks/mutation/index.ts
index f15ca8d..f79133a 100644
--- a/src/hooks/mutation/index.ts
+++ b/src/hooks/mutation/index.ts
@@ -1,2 +1,3 @@
export { default as useSendStudentEmail } from './useSendStudentEmail';
export { default as useVerifyStudentEmail } from './useVerifyStudentEmail';
+export { default as useLogout } from './useLogout';
diff --git a/src/hooks/mutation/useCreateUserBasicInfo.ts b/src/hooks/mutation/useCreateUserBasicInfo.ts
index 6588c6c..499dc1e 100644
--- a/src/hooks/mutation/useCreateUserBasicInfo.ts
+++ b/src/hooks/mutation/useCreateUserBasicInfo.ts
@@ -5,12 +5,10 @@ import { useNavigate } from 'react-router-dom';
export default function useCreateUserBasicInfo() {
const navigation = useNavigate();
- // const { updateLandingStatue } = useLandingStatus();
const { mutate: createBasicInfo, ...rest } = useMutation({
mutationFn: createBasicInfoApi.BASIC_INFO,
onSuccess: () => {
- // updateLandingStatue(LandingStatus.Dashboard);
navigation(RoutePath.Dashboard, { replace: true });
}
});
diff --git a/src/hooks/mutation/useLogout.ts b/src/hooks/mutation/useLogout.ts
new file mode 100644
index 0000000..1e085ce
--- /dev/null
+++ b/src/hooks/mutation/useLogout.ts
@@ -0,0 +1,23 @@
+import { useMutation } from '@tanstack/react-query';
+import authApi from '@/apis/auth/authApi';
+import { useNavigate } from 'react-router-dom';
+import RoutePath from '@/routes/routePath';
+import { toast } from 'react-toastify';
+
+export default function useLogout() {
+ const navigate = useNavigate();
+
+ const mutation = useMutation({
+ mutationFn: authApi.LOGOUT,
+ onSuccess: () => {
+ sessionStorage.clear();
+ navigate(RoutePath.Home);
+ location.reload();
+ },
+ onError: () => {
+ toast.error('로그아웃에 실패했어요.');
+ }
+ });
+
+ return mutation;
+}
diff --git a/src/hooks/mutation/usePostDiscordName.ts b/src/hooks/mutation/usePostDiscordName.ts
index b8805fd..257a18d 100644
--- a/src/hooks/mutation/usePostDiscordName.ts
+++ b/src/hooks/mutation/usePostDiscordName.ts
@@ -1,9 +1,9 @@
import discordApi from '@/apis/discord/discordApi';
import { useMutation } from '@tanstack/react-query';
-export function usePostDiscordName(userName: string) {
+export function usePostDiscordName() {
const { mutate: checkDuplicate, ...rest } = useMutation({
- mutationFn: () => discordApi.GET_DISCORD_NAME(userName)
+ mutationFn: (userName: string) => discordApi.GET_DISCORD_NAME(userName)
});
return { checkDuplicate, ...rest };
}
diff --git a/src/hooks/mutation/usePostDiscordNickname.ts b/src/hooks/mutation/usePostDiscordNickname.ts
index c420758..911545b 100644
--- a/src/hooks/mutation/usePostDiscordNickname.ts
+++ b/src/hooks/mutation/usePostDiscordNickname.ts
@@ -1,9 +1,9 @@
import discordApi from '@/apis/discord/discordApi';
import { useMutation } from '@tanstack/react-query';
-export function usePostDiscordNickname(nickname: string) {
+export function usePostDiscordNickname() {
const { mutate: checkDuplicate, ...rest } = useMutation({
- mutationFn: () => discordApi.GET_DISCORD_NICKNAME(nickname)
+ mutationFn: (nickname: string) => discordApi.GET_DISCORD_NICKNAME(nickname)
});
return { checkDuplicate, ...rest };
}
diff --git a/src/hooks/mutation/usePostFreeOrder.ts b/src/hooks/mutation/usePostFreeOrder.ts
new file mode 100644
index 0000000..1765ac1
--- /dev/null
+++ b/src/hooks/mutation/usePostFreeOrder.ts
@@ -0,0 +1,22 @@
+import { useNavigate } from 'react-router-dom';
+import { useMutation } from '@tanstack/react-query';
+import ordersApi from '@/apis/orders/ordersApi';
+import RoutePath from '@/routes/routePath';
+import { toast } from 'react-toastify';
+
+const usePostFreeOrder = (amount: number) => {
+ const navigate = useNavigate();
+
+ const { mutate: postFreeOrder, ...rest } = useMutation({
+ onMutate: () => {
+ if (amount) toast('결제를 실패했어요. 문제가 지속되면 문의해주세요.');
+ },
+ mutationFn: ordersApi.POST_PREV_FREE_ORDER,
+ onError: () => navigate(RoutePath.PaymentsCheckout),
+ onSuccess: () => navigate(RoutePath.Dashboard)
+ });
+
+ return { postFreeOrder, ...rest };
+};
+
+export default usePostFreeOrder;
diff --git a/src/hooks/mutation/usePostOrder.ts b/src/hooks/mutation/usePostOrder.ts
index 789bbad..aace9e1 100644
--- a/src/hooks/mutation/usePostOrder.ts
+++ b/src/hooks/mutation/usePostOrder.ts
@@ -1,9 +1,13 @@
import { useMutation } from '@tanstack/react-query';
+import { useNavigate } from 'react-router-dom';
import ordersApi from '@/apis/orders/ordersApi';
+import RoutePath from '@/routes/routePath';
const usePostOrder = () => {
+ const navigate = useNavigate();
const { mutate: postOrder, ...rest } = useMutation({
- mutationFn: ordersApi.POST_ORDER
+ mutationFn: ordersApi.POST_ORDER,
+ onError: () => navigate(RoutePath.PaymentsFail)
});
return { postOrder, ...rest };
diff --git a/src/hooks/mutation/usePostPrevOrder.ts b/src/hooks/mutation/usePostPrevOrder.ts
index 881f150..a887a6d 100644
--- a/src/hooks/mutation/usePostPrevOrder.ts
+++ b/src/hooks/mutation/usePostPrevOrder.ts
@@ -1,11 +1,19 @@
import { useMutation } from '@tanstack/react-query';
+import { useNavigate } from 'react-router-dom';
+
import ordersApi from '@/apis/orders/ordersApi';
+import RoutePath from '@/routes/routePath';
+import { toast } from 'react-toastify';
const usePostPrevOrder = (amount: number) => {
+ const navigate = useNavigate();
+
const { mutate: postPrevOrder, ...rest } = useMutation({
- mutationFn: amount
- ? ordersApi.POST_PREV_ORDER
- : ordersApi.POST_PREV_FREE_ORDER
+ onMutate: () => {
+ if (!amount) toast('결제를 실패했어요. 문제가 지속되면 문의해주세요.');
+ },
+ mutationFn: ordersApi.POST_PREV_ORDER,
+ onError: () => navigate(RoutePath.PaymentsCheckout)
});
return { postPrevOrder, ...rest };
diff --git a/src/hooks/mutation/useSendStudentEmail.ts b/src/hooks/mutation/useSendStudentEmail.ts
index 63aabf7..a8077b1 100644
--- a/src/hooks/mutation/useSendStudentEmail.ts
+++ b/src/hooks/mutation/useSendStudentEmail.ts
@@ -11,9 +11,6 @@ export default function useSendStudentEmail() {
onSuccess: () => {
toast('메일 전송이 완료되었습니다.');
navigation(RoutePath.Dashboard);
- },
- onError: (error) => {
- toast(error.message);
}
});
diff --git a/src/hooks/query/useGetDiscordJoined.ts b/src/hooks/query/useGetDiscordJoined.ts
index 2e19d28..db4fdd8 100644
--- a/src/hooks/query/useGetDiscordJoined.ts
+++ b/src/hooks/query/useGetDiscordJoined.ts
@@ -2,11 +2,17 @@ import discordApi from '@/apis/discord/discordApi';
import QueryKeys from '@/constants/queryKey';
import { useQuery } from '@tanstack/react-query';
-export default function useGetDiscordJoined(username: string) {
+const FETCH_INTERVAL = 5000;
+export default function useGetDiscordJoined(
+ username: string,
+ isEnabled: boolean
+) {
const query = useQuery({
queryKey: [QueryKeys.DiscordJoined],
queryFn: () => discordApi.GET_DISCORD_JOIN(username),
- refetchOnWindowFocus: true
+ refetchOnWindowFocus: true,
+ refetchInterval: FETCH_INTERVAL,
+ enabled: isEnabled
});
return query;
diff --git a/src/hooks/zustand/useLandingStatus.ts b/src/hooks/zustand/useLandingStatus.ts
deleted file mode 100644
index 2f23752..0000000
--- a/src/hooks/zustand/useLandingStatus.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { create } from 'zustand';
-import { createJSONStorage, persist } from 'zustand/middleware';
-
-//TODO: 추후 삭제 필요
-export default function useLandingStatus() {
- return {
- landingStatus: useLandingStatusStore.getState().landingStatus,
- updateLandingStatue: (landingStatus: string | null) =>
- useLandingStatusStore.setState({ landingStatus }),
- clearLandingStatus: () =>
- useLandingStatusStore.setState({ landingStatus: null })
- };
-}
-
-type LandingStatusStore = {
- landingStatus: string | null;
- setLandingStatus: (status: string) => void;
-};
-
-const useLandingStatusStore = create(
- persist(
- (set) => ({
- landingStatus: null,
- setLandingStatus: (landingStatus) => set({ landingStatus })
- }),
- {
- name: 'landing-status',
- storage: createJSONStorage(() => sessionStorage)
- }
- )
-);
diff --git a/src/hooks/zustand/useProduct.ts b/src/hooks/zustand/useProduct.ts
index 268c63f..b97c1c8 100644
--- a/src/hooks/zustand/useProduct.ts
+++ b/src/hooks/zustand/useProduct.ts
@@ -19,7 +19,8 @@ export const useProductStore = create((set) => ({
setDiscount: (newDiscount, couponId) =>
set((state) => ({
discount: newDiscount,
- totalAmount: state.amount - newDiscount,
+ totalAmount:
+ state.amount - newDiscount < 0 ? 0 : state.amount - newDiscount,
issuedCouponId: couponId
}))
}));
diff --git a/src/main.tsx b/src/main.tsx
index 44b13d4..c561d5f 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -1,3 +1,5 @@
+import sentry from '@utils/sentry';
+import * as Sentry from '@sentry/react';
import React from 'react';
import ReactDOM from 'react-dom/client';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
@@ -8,7 +10,12 @@ import { GlobalStyle } from '@/styles';
import { Global } from '@emotion/react';
import { ToastContainer } from 'react-toastify';
import './styles/styles.scss';
-import Chatbot from '@/components/chatbot/Chatbot';
+
+try {
+ sentry.initSentry();
+} catch (error: unknown) {
+ console.log('Sentry init failed');
+}
const queryClient = new QueryClient({
defaultOptions: {
@@ -20,20 +27,22 @@ const queryClient = new QueryClient({
});
ReactDOM.createRoot(document.getElementById('root')!).render(
-
-
-
-
-
-
-
-
-
-
-
+ 에러가 발생되었어요. 관리자에게 문의해주세요.
}>
+
+
+
+
+
+
+
+
+
+
+
);
diff --git a/src/pages/Auth.tsx b/src/pages/Auth.tsx
index 5fa2324..63923f8 100644
--- a/src/pages/Auth.tsx
+++ b/src/pages/Auth.tsx
@@ -1,31 +1,15 @@
import { GitHubButton } from '@/components/auth/GitHubButton';
import { Text } from '@/components/common/Wrapper';
-import useLandingStatus from '@/hooks/zustand/useLandingStatus';
import RoutePath from '@/routes/routePath';
import { color, space } from 'wowds-tokens';
import { media } from '@/styles';
-import { setCookie } from '@/utils/auth';
import { css } from '@emotion/react';
import styled from '@emotion/styled';
import GlobalSize from '@/constants/globalSize';
-import { useEffect } from 'react';
import { Link } from 'react-router-dom';
/** 깃허브 로그인 및 가입하기 */
export const Auth = () => {
- const { clearLandingStatus } = useLandingStatus();
-
- useEffect(() => {
- clearLandingStatus();
- // 로그인을 위한 oauth-base-uri 쿠키 값 세팅
-
- setCookie({
- key: 'oauth-base-uri',
- value: window.location.origin,
- encoding: false
- });
- }, []);
-
const handleClick = () => {
// GitHub 로그인 페이지로 직접 리다이렉트
setTimeout(function () {
diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx
index f600f59..47a56e1 100644
--- a/src/pages/Dashboard.tsx
+++ b/src/pages/Dashboard.tsx
@@ -12,6 +12,7 @@ import memberApi from '@/apis/member/memberApi';
import GlobalSize from '@/constants/globalSize';
import JoinStatus from '@/components/myPage/JoinStatus';
import useBottomSheet from '@/hooks/common/useBottomSheet';
+import LoadingSpinner from '@/components/common/LoadingSpinner';
export const Dashboard = () => {
const { isOpen } = useBottomSheet();
@@ -20,9 +21,12 @@ export const Dashboard = () => {
queryFn: memberApi.GET_DASHBOARD
});
- //TODO: 추후 로딩 스피너 삽입할 것
if (!data) {
- return 로딩중 ...
;
+ return (
+
+
+
+ );
}
const { member, currentRecruitmentRound, currentMembership } = data;
diff --git a/src/pages/DiscordConnect.tsx b/src/pages/DiscordConnect.tsx
index 99221cb..f6027e4 100644
--- a/src/pages/DiscordConnect.tsx
+++ b/src/pages/DiscordConnect.tsx
@@ -15,7 +15,7 @@ import useCustomBack from '@/hooks/common/useCutomBack';
const steps = ['이름 설정', '별명 설정', '서버 합류', '서버 연동', '연동 완료'];
-export const DicordConnect = () => {
+export const DiscordConnect = () => {
const { Funnel, Step, setStep, currentStep } = useFunnel(steps[0]);
const methods = useForm({
diff --git a/src/pages/OnboardingClosed.tsx b/src/pages/OnboardingClosed.tsx
deleted file mode 100644
index 64d66bd..0000000
--- a/src/pages/OnboardingClosed.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-import { Text } from '@/components/common/Wrapper';
-import RoutePath from '@/routes/routePath';
-import { color, typography } from 'wowds-tokens';
-import styled from '@emotion/styled';
-import { Link } from 'react-router-dom';
-
-export default function OnboardingClosed() {
- return (
-
-
-
-
- 학회원 모집이 마감되었어요
-
-
- 지금은 가입 신청을 받고 있지 않아요.
-
-
- 이번 지원 기간동안 여러분이 보내주신 많은 관심에 진심으로
- 감사드려요.
-
-
- 2학기 모집 소식을 받고 싶으시다면{' '}
-
- @gdsc.hongik
-
- 을 팔로우 해주세요.
-
-
- 다음 학기에 더 멋진 모습으로 만나요!
-
-
- 이전 화면으로
-
-
- );
-}
-
-const Container = styled.div`
- width: 100%;
- height: calc(100vh - 54px);
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 16px;
-`;
-
-const AlignCenteredText = styled(Text)`
- text-align: center;
-`;
-
-const Box = styled.div`
- display: flex;
- flex-direction: column;
- background-color: ${color.white};
- align-items: center;
- gap: 24px;
- padding: 80px 24px;
- border: 1px solid ${color.mono400};
- border-radius: 8px;
-`;
-
-const TextContainer = styled.div`
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 20px;
-`;
-
-const InstagramLink = styled(Link)`
- color: ${color.textBlack};
- font-weight: 600;
- text-decoration: underline;
- &:active {
- color: ${color.sub};
- }
- &:hover {
- color: ${color.sub};
- }
- &:visited {
- color: ${color.textBlack};
- }
-`;
-
-const BackButton = styled.button`
- height: 44px;
- width: calc(100% - 42px);
- border-radius: 100px;
-
- color: ${color.white};
- background-color: ${color.primary};
- ${typography.h2};
-
- flex-shrink: 0;
-`;
diff --git a/src/pages/OnboardingNotOpened.tsx b/src/pages/OnboardingNotOpened.tsx
deleted file mode 100644
index 17fa84d..0000000
--- a/src/pages/OnboardingNotOpened.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import { Text } from '@/components/common/Wrapper';
-import RoutePath from '@/routes/routePath';
-import { color } from 'wowds-tokens';
-import styled from '@emotion/styled';
-import { Link } from 'react-router-dom';
-
-export default function OnboardingNotOpened() {
- return (
-
-
-
-
- 아직 2차 지원 기간이 시작되지 않았어요
-
-
- 현재는 준비 기간으로, 운영진들이 1차 지원자 분들의 가입 신청을
- 꼼꼼하게 검토 중이에요.
-
-
- 3월 4일에 모집이 다시 시작되면 인스타그램과 에브리타임을 통해 관련
- 소식을 전해드릴게요.
-
-
- 저희 소식을 더 빠르게 알고 싶으시다면{' '}
-
- @gdsc.hongik
-
- 을 팔로우 해주세요.
-
- 기다려 주셔서 감사합니다!
-
-
-
- );
-}
-
-const Container = styled.div`
- width: 100%;
- padding: 40px 40px;
-`;
-
-const AlignCenteredText = styled(Text)`
- text-align: center;
-`;
-
-const Box = styled.div`
- display: flex;
- flex-direction: column;
- background-color: ${color.white};
- align-items: center;
- gap: 24px;
- padding: 80px 24px;
- border: 1px solid ${color.mono400};
- border-radius: 8px;
-`;
-
-const TextContainer = styled.div`
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 20px;
-`;
-
-const InstagramLink = styled(Link)`
- color: ${color.textBlack};
- font-weight: 600;
- text-decoration: underline;
- &:active {
- color: ${color.sub};
- }
- &:hover {
- color: ${color.sub};
- }
- &:visited {
- color: ${color.textBlack};
- }
-`;
diff --git a/src/pages/PaymentsCheckout.tsx b/src/pages/PaymentsCheckout.tsx
index d8afa72..c8398a0 100644
--- a/src/pages/PaymentsCheckout.tsx
+++ b/src/pages/PaymentsCheckout.tsx
@@ -1,14 +1,38 @@
+import { nanoid } from 'nanoid';
+import { useQuery } from '@tanstack/react-query';
+
+import memberApi from '@/apis/member/memberApi';
import { useFunnel } from '@/hooks/common/useFunnel';
import { Payments } from '@/components/payments/Payments';
import { PaymentsWidget } from '@/components/payments/PaymentsWidget';
import useCustomBack from '@/hooks/common/useCutomBack';
+import { useProduct } from '@/hooks/zustand/useProduct';
+import usePostFreeOrder from '@/hooks/mutation/usePostFreeOrder';
const steps = ['회비 납부', '결제 위젯'];
export const PaymentsCheckout = () => {
const { Funnel, Step, setStep, currentStep } = useFunnel(steps[0]);
+ const { amount, discount, totalAmount, issuedCouponId } = useProduct();
+ const { postFreeOrder } = usePostFreeOrder(totalAmount);
+ const { data: dashboard } = useQuery({
+ queryKey: ['member'],
+ queryFn: memberApi.GET_DASHBOARD
+ });
const nextClickHandler = (step: string) => {
+ if (!totalAmount && dashboard) {
+ const id = nanoid();
+ postFreeOrder({
+ orderNanoId: id,
+ membershipId: dashboard.currentMembership.membershipId,
+ issuedCouponId: issuedCouponId,
+ totalAmount: amount,
+ discountAmount: discount,
+ finalPaymentAmount: totalAmount
+ });
+ return;
+ }
setStep(step);
};
diff --git a/src/pages/PaymentsSuccess.tsx b/src/pages/PaymentsSuccess.tsx
index 865089b..403482a 100644
--- a/src/pages/PaymentsSuccess.tsx
+++ b/src/pages/PaymentsSuccess.tsx
@@ -1,6 +1,6 @@
import { useEffect } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
-import { Flex, Text } from '@/components/common/Wrapper';
+import { Flex, Text, Space } from '@/components/common/Wrapper';
import { media } from '@/styles';
import styled from '@emotion/styled';
@@ -47,8 +47,8 @@ export function PaymentsSuccess() {
}, [searchParams]);
return (
-
-
+
+
회비 결제 완료
@@ -57,7 +57,10 @@ export function PaymentsSuccess() {
이제 GDSC 정회원으로 이번 학기에 활동하실 수 있어요!
-
+
+
+
+
);
}
diff --git a/src/pages/SignUp.tsx b/src/pages/SignUp.tsx
index 220db89..81db15e 100644
--- a/src/pages/SignUp.tsx
+++ b/src/pages/SignUp.tsx
@@ -1,4 +1,4 @@
-import DepartmentSelect from '@/components/auth/DepartmentSelect';
+import DepartmentSelect from '@/components/signup/DepartmentSelect';
import { useForm, Controller } from 'react-hook-form';
import type { color as colorType } from 'wowds-tokens';
import GlobalSize from '@/constants/globalSize';
@@ -10,15 +10,14 @@ import useCreateUserBasicInfo from '@/hooks/mutation/useCreateUserBasicInfo';
import Button from 'wowds-ui/Button';
import Checkbox from 'wowds-ui/Checkbox';
import TextField from 'wowds-ui/TextField';
-import DropDownOption from 'wowds-ui/DropDownOption';
-import DropDown from 'wowds-ui/DropDown';
import { LoadingForm } from '@/components/common/LoadingForm';
import RoutePath from '@/routes/routePath';
+import { Suspense } from 'react';
import { formatPhoneNumberInProgress } from '@/utils/phone';
import styled from '@emotion/styled';
-import { Suspense } from 'react';
import { Link } from 'react-router-dom';
+import EmailInputField from '@/components/signup/EmailInputField';
export type FormStateType = {
name: string;
@@ -75,7 +74,7 @@ export const SignUp = () => {
style={{
display: 'flex',
flexDirection: 'column',
- gap: '24px',
+ gap: '10px',
width: '100%'
}}>
{
}
}}
render={({ field, fieldState }) => (
-
+
+
+
)}
/>
{
}}
render={({ field, fieldState }) => {
return (
-
+
+
+
);
}}
/>
@@ -153,77 +156,24 @@ export const SignUp = () => {
}
}}
render={({ field, fieldState }) => (
-
+
+
+
)}
/>
}>
-
- (
-
-
-
- )}
- />
- (
- {
- field.onChange(selectedValue);
- }}
- defaultValue=""
- value={field.value}
- style={{ marginTop: '15px', flex: 1, width: '10rem' }}>
-
-
-
-
-
- )}
- />
-
+
{
align="center"
css={css`
margin-top: 16px;
+ @media (max-height: 750px) {
+ bottom: 0rem;
+ }
position: absolute;
bottom: 1.75rem;
width: 100%;
@@ -305,7 +258,7 @@ export const SignUp = () => {
role="button"
disabled={!isValid}
style={{ maxWidth: '100%' }}>
- 가입 신청하기
+ 입력 완료하기
@@ -316,6 +269,9 @@ export const SignUp = () => {
const Container = styled(Flex)`
position: relative;
flex-direction: column;
+ @media (max-height: 765px) {
+ min-height: 105vh;
+ }
min-height: calc(100vh - 54px);
justify-content: flex-start;
background-color: ${color.mono50};
@@ -346,16 +302,7 @@ const GuideLink = styled(Link)<{ color?: colorKey }>`
}
`;
-const TextFieldWrapper = styled.div`
- flex: 1;
- width: 50%;
-`;
-
-const EmailFieldWrapper = styled.div`
- position: relative;
+const InputFormWrapper = styled.div`
+ height: 84.8px;
width: 100%;
- display: flex;
- gap: ${space.sm};
- align-items: center;
- justify-content: space-between;
`;
diff --git a/src/pages/StudentVerification.tsx b/src/pages/StudentVerification.tsx
index 9668a05..a1a08cb 100644
--- a/src/pages/StudentVerification.tsx
+++ b/src/pages/StudentVerification.tsx
@@ -10,6 +10,7 @@ import { Controller } from 'react-hook-form';
import { useEffect, useState } from 'react';
import { media } from '@/styles';
import GlobalSize from '@/constants/globalSize';
+import LoadingSpinner from '@/components/common/LoadingSpinner';
/** 재학생 인증 페이지 */
export const StudentVerification = () => {
@@ -17,12 +18,12 @@ export const StudentVerification = () => {
//TODO: 추후 pending 상태 백엔드 API 수정하면 반영해둘것.
const [, setPending] = useState(false);
const [isClicked, setIsClicked] = useState(false);
- const { onSubmit, control, isValid, onVerifyStudent, loading } =
+ const { onSubmit, control, isValid, onVerifyStudent, isPending } =
useStudentVerification();
const IsStudentVerified = async () => {
const univStatus = await onVerifyStudent();
- if (univStatus === 'PENDING') {
+ if (univStatus === 'UNSATISFIED') {
setPending(true);
} else {
navigate(RoutePath.Dashboard);
@@ -39,12 +40,9 @@ export const StudentVerification = () => {
onSubmit();
};
- if (loading) {
- return 로딩중입니다...
;
- }
-
return (
+ {isPending && }
재학생 인증하기
@@ -68,34 +66,50 @@ export const StudentVerification = () => {
message: '* 이메일을 입력해주세요.'
},
pattern: {
- value: /^[a-zA-Z0-9._%+-]+@g\.hongik\.ac\.kr$/,
- message: '* 홍익대학교 이메일 형식을 지켜주세요.'
+ value: /^[a-zA-Z0-9._%+-]/,
+ message: '* 이메일 형식을 지켜주세요.'
}
}}
render={({ field, fieldState }) => (
-
+
+
+
+
+
+ @g.hongik.ac.kr
+
+
)}
/>
+
* 메일 전송이 최대 30분 가량 늦어질 수 있어요.
* 메일 전송이 되지 않을 경우 카카오톡 채널을 통해 코어 멤버에게
문의해 주세요.
+
* 인증메일이 스팸메일함에 전송될 수 있으니 확인해주세요.
학교 이메일이 무엇인가요?
@@ -130,7 +144,7 @@ const StudentGuideLink = styled(Link)`
color: ${color.sub};
}
&:visited {
- color: ${color.textBlack};
+ color: ${color.sub};
}
${typography.label2};
`;
@@ -158,3 +172,16 @@ const ButtonContainer = styled.div`
align-items: center;
gap: ${space.xs};
`;
+
+const EmailContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: ${space.xs};
+`;
+
+const TextFieldWrapper = styled.div`
+ flex: 1;
+ height: 84.8px;
+ width: 50%;
+`;
diff --git a/src/pages/index.ts b/src/pages/index.ts
index 75ad400..bc2a706 100644
--- a/src/pages/index.ts
+++ b/src/pages/index.ts
@@ -6,8 +6,6 @@ export * from './MyPageEdit';
export * from './SignUp';
export * from './StudentVerification';
export { default as UpdatedStudentVerification } from './UpdatedStudentVerification';
-export { default as OnboardingNotOpened } from './OnboardingNotOpened';
-export { default as OnboardingClosed } from './OnboardingClosed';
export * from './redirect/AuthServerRedirectNavigate';
export * from './redirect/StudentVerificationServerRedirect';
export * from './PaymentsCheckout';
diff --git a/src/pages/redirect/AuthServerRedirectNavigate.tsx b/src/pages/redirect/AuthServerRedirectNavigate.tsx
index e313487..de00c82 100644
--- a/src/pages/redirect/AuthServerRedirectNavigate.tsx
+++ b/src/pages/redirect/AuthServerRedirectNavigate.tsx
@@ -1,29 +1,14 @@
-import useAuthToken from '@/hooks/auth/useAuthToken';
-import useLandingStatus from '@/hooks/zustand/useLandingStatus';
-import { getAuthRedirectPath } from '@/utils/auth';
-import { CookieKeys } from '@/utils/storage/key';
+import RoutePath from '@/routes/routePath';
import { useEffect } from 'react';
-import { useSearchParams } from 'react-router-dom';
+import { useNavigate } from 'react-router-dom';
export const AuthServerRedirectNavigate = () => {
- const [searchParams] = useSearchParams();
- const { landingStatus: originLandingStatus, updateLandingStatue } =
- useLandingStatus();
- const { setToken } = useAuthToken();
- const landingStatus = searchParams.get('landing-status');
- const accessToken = searchParams.get('access');
- const refreshToken = searchParams.get('refresh');
+ const navigate = useNavigate();
useEffect(() => {
- if (originLandingStatus !== landingStatus) {
- updateLandingStatue(landingStatus);
- }
-
- setToken({ type: CookieKeys.AccessToken, value: accessToken });
- setToken({ type: CookieKeys.RefreshToken, value: refreshToken });
-
- window.location.href = getAuthRedirectPath(landingStatus);
- }, [originLandingStatus, accessToken, refreshToken, landingStatus]);
+ sessionStorage.setItem('isLogin', 'true');
+ navigate(RoutePath.Dashboard);
+ }, [navigate]);
return null;
};
diff --git a/src/pages/redirect/StudentVerificationServerRedirect.tsx b/src/pages/redirect/StudentVerificationServerRedirect.tsx
index d2c9056..b2c8598 100644
--- a/src/pages/redirect/StudentVerificationServerRedirect.tsx
+++ b/src/pages/redirect/StudentVerificationServerRedirect.tsx
@@ -7,9 +7,9 @@ import { media } from '@/styles';
import styled from '@emotion/styled';
import { css } from '@emotion/react';
import { useNavigate, useSearchParams } from 'react-router-dom';
-import { PulseLoader } from 'react-spinners';
import RoutePath from '@/routes/routePath';
import { useLayoutEffect } from 'react';
+import LoadingSpinner from '@/components/common/LoadingSpinner';
export const StudentVerificationServerRedirect = () => {
const [searchParams] = useSearchParams();
@@ -20,13 +20,12 @@ export const StudentVerificationServerRedirect = () => {
useLayoutEffect(() => {
if (token) verifyStudentMail(token);
}, [token, verifyStudentMail]);
- console.log(isSuccess);
//TODO: 추후 로딩 스피너 추가 필요
return (
{isPending ? (
-
+
) : (
{
return ;
};
// TODO: error page, meta tag
-const router = createBrowserRouter([
+const router = sentryCreateBrowserRouter([
{
path: RoutePath.Index,
element: ,
@@ -53,37 +48,42 @@ const router = createBrowserRouter([
element:
},
{
- path: RoutePath.AuthenticationProcess1_GithubSignin,
- element: ,
+ path: RoutePath.GithubSignin,
children: [{ index: true, element: }]
},
{
- path: RoutePath.AuthenticationProcess2_StudentVerification,
- element: ,
+ path: RoutePath.StudentVerification,
+ element: ,
children: [
{
index: true,
element: (
-
-
-
+
+
+
+
+
)
}
]
},
{
- path: RoutePath.AuthenticationProcess2_UpdatedStudentVerification,
- element: ,
- children: [{ index: true, element: }]
- },
- {
- path: RoutePath.AuthenticationProcess3_Signup,
- element: ,
- children: [{ index: true, element: }]
+ path: RoutePath.Signup,
+ element: ,
+ children: [
+ {
+ index: true,
+ element: (
+
+
+
+ )
+ }
+ ]
},
{
- path: RoutePath.Index,
- element: ,
+ path: RoutePath.Home,
+ element: ,
children: [
{
path: RoutePath.Dashboard,
@@ -91,11 +91,29 @@ const router = createBrowserRouter([
},
{
path: RoutePath.Discord,
- element:
+ children: [
+ {
+ index: true,
+ element: (
+
+
+
+ )
+ }
+ ]
},
{
path: RoutePath.DiscordConnect,
- element:
+ children: [
+ {
+ index: true,
+ element: (
+
+
+
+ )
+ }
+ ]
},
{
path: RoutePath.DiscordGuide,
@@ -103,27 +121,28 @@ const router = createBrowserRouter([
},
{
path: RoutePath.Bevy,
- element:
+ children: [
+ {
+ index: true,
+ element: (
+
+
+
+ )
+ }
+ ]
}
]
},
- {
- path: RoutePath.OnboardingNotOpened,
- element: ,
- children: [{ index: true, element: }]
- },
- {
- path: RoutePath.OnboardingClosed,
- element: ,
- children: [{ index: true, element: }]
- },
{
path: RoutePath.PaymentsCheckout,
- element:
+ element: ,
+ children: [{ index: true, element: }]
},
{
path: RoutePath.PaymentsFail,
- element:
+ element: ,
+ children: [{ index: true, element: }]
},
{
path: RoutePath.PaymentsSuccess,
diff --git a/src/routes/routePath.ts b/src/routes/routePath.ts
index c5eb9fc..9c706aa 100644
--- a/src/routes/routePath.ts
+++ b/src/routes/routePath.ts
@@ -10,14 +10,9 @@ const RoutePath = {
DiscordConnect: '/discord/connect',
DiscordGuide: '/discord/guide',
- OnboardingNotOpened: '/not-opened',
- OnboardingClosed: '/closed',
-
- AuthenticationProcess1_GithubSignin: '/auth',
- AuthenticationProcess2_StudentVerification: '/student-verification',
- AuthenticationProcess2_UpdatedStudentVerification:
- '/updated-student-verification',
- AuthenticationProcess3_Signup: '/signup',
+ GithubSignin: '/auth',
+ StudentVerification: '/student-verification',
+ Signup: '/signup',
AuthGithubLoginRedirect: `${BASE_URL}/oauth2/authorization/github`,
diff --git a/src/types/status.ts b/src/types/status.ts
index 23a532f..8c7fb8f 100644
--- a/src/types/status.ts
+++ b/src/types/status.ts
@@ -1 +1,3 @@
-export type Status = 'PENDING' | 'SATISFIED';
+export type Status = 'UNSATISFIED' | 'SATISFIED';
+export type PaymentStatus = 'PENDING' | 'SATISFIED';
+export type UnivEmailStatus = 'IN_PROGRESS' | 'UNSATISFIED' | 'SATISFIED';
diff --git a/src/types/user.ts b/src/types/user.ts
index e93e027..918d04f 100644
--- a/src/types/user.ts
+++ b/src/types/user.ts
@@ -1,21 +1,21 @@
-import { Status } from '@/types/status';
+import { Status, UnivEmailStatus } from '@/types/status';
export type User = {
memberId: string; // C000000 (학번)
role: UserRoleType;
basicInfo: UserBasicInfo;
associateRequirement: {
- univStatus: Status;
+ univStatus: UnivEmailStatus;
discordStatus: Status;
bevyStatus: Status;
infoStatus: Status;
};
};
-export type UserRoleType = 'GUEST' | 'ASSOCIATE' | 'REGULAR' | 'ADMIN';
+export type UserRoleType = 'GUEST' | 'ASSOCIATE' | 'REGULAR';
export type AssociateRequirement = {
- univStatus: Status;
+ univStatus: UnivEmailStatus;
discordStatus: Status;
bevyStatus: Status;
infoStatus: Status;
diff --git a/src/utils/auth.ts b/src/utils/auth.ts
index a12cb7c..2b15bb4 100644
--- a/src/utils/auth.ts
+++ b/src/utils/auth.ts
@@ -1,87 +1,5 @@
-import LandingStatus from '@/constants/landingStatus';
-import useAuthToken from '@/hooks/auth/useAuthToken';
-import RoutePath from '@/routes/routePath';
+export const isAuthenticated = () => {
+ const isLogin = sessionStorage.getItem('isLogin');
-/**
- * 깃허브 로그인 성공 시 header에서 추출한 landing status 통해 이동할 페이지 반환
- */
-export function getAuthRedirectPath(landingStatus: string | null | undefined) {
- switch (landingStatus) {
- case LandingStatus.StudentAuthentication:
- return RoutePath.AuthenticationProcess2_StudentVerification;
- case LandingStatus.Signup:
- return RoutePath.AuthenticationProcess3_Signup;
- case LandingStatus.Dashboard:
- return RoutePath.Dashboard;
- case LandingStatus.OnboardingNotOpened:
- return RoutePath.OnboardingNotOpened;
- case LandingStatus.OnboardingClosed:
- return RoutePath.OnboardingClosed;
- default:
- return RoutePath.AuthenticationProcess1_GithubSignin;
- }
-}
-
-/**
- * 쿠키 이름을 기반으로 쿠키 값을 가져옴
- * @param {string} name 가져올 쿠키의 이름
- * @returns {string} 쿠키 값 (존재하지 않을 경우 빈 스트링('') 반환)
- */
-export function getCookie(name: string): string {
- const cookieString: string = document.cookie;
- const cookies: string[] = cookieString.split(';');
-
- for (const cookie of cookies) {
- const [cookieName, value] = cookie.trim().split('=');
- if (cookieName === name) {
- return value;
- }
- }
-
- return '';
-}
-
-export function setCookie({
- key,
- value,
- days = 1,
- encoding = true
-}: {
- key: string;
- value: string;
- days?: number;
- encoding?: boolean;
-}) {
- const expirationDate = new Date();
- expirationDate.setDate(expirationDate.getDate() + days);
-
- const encodedKey = encodeURIComponent(key);
- const processedValue = encoding ? encodeURIComponent(value) : value;
-
- const isBaseUriCookie = key === 'oauth-base-uri';
- const domain = window.location.origin.includes('localhost')
- ? 'localhost'
- : '.gdschongik.com';
- const baseUriCookieValue = '; samesite=none; secure; domain=' + domain;
-
- const cookieValue =
- encodedKey +
- '=' +
- processedValue +
- '; expires=' +
- expirationDate.toUTCString() +
- '; path=/' +
- (isBaseUriCookie ? baseUriCookieValue : '');
-
- document.cookie = cookieValue;
-}
-
-export function deleteCookie(name: string) {
- document.cookie = name + '=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
-}
-
-export function logout() {
- useAuthToken().clearToken();
- sessionStorage.clear();
- location.reload();
-}
+ return isLogin === 'true';
+};
diff --git a/src/utils/mypage/recruitmentNameFormat.ts b/src/utils/mypage/recruitmentNameFormat.ts
index 33cbc38..337badf 100644
--- a/src/utils/mypage/recruitmentNameFormat.ts
+++ b/src/utils/mypage/recruitmentNameFormat.ts
@@ -9,11 +9,17 @@ export const convertRecruitmentPeriod = (period: {
return `지원 기간 : ${startDate} ~ ${endDate}`;
};
-export const convertRecruitmentName = (name: string) => {
- const [period, round] = name.split(' ');
+export const convertRecruitmentName = (
+ name: string,
+ roundValueType: string
+) => {
+ const [period] = name.split(' ');
const [year, semester] = period.split('-');
if (year === undefined || semester === undefined) {
- return `${round} 정회원 지원하기`;
+ return `정회원 지원하기`;
}
- return `${year}년 ${semester}학기 ${round} 정회원 지원하기`;
+ if (roundValueType === undefined) {
+ return `${year}년 ${semester}학기 정회원 지원하기`;
+ }
+ return `${year}년 ${semester}학기 ${roundValueType} 정회원 지원하기`;
};
diff --git a/src/utils/sentry.ts b/src/utils/sentry.ts
new file mode 100644
index 0000000..8eea869
--- /dev/null
+++ b/src/utils/sentry.ts
@@ -0,0 +1,46 @@
+import { useEffect } from 'react';
+import * as Sentry from '@sentry/react';
+import {
+ createRoutesFromChildren,
+ matchRoutes,
+ useLocation,
+ useNavigationType
+} from 'react-router-dom';
+import { SENTRY_DSN_KEY } from '@/constants/environment';
+
+const setSentry = () => {
+ function initSentry() {
+ if (process.env.NODE_ENV === 'development') return;
+
+ console.log(`VERCEL ENV : ${process.env.VERCEL_ENV}`);
+ Sentry.init({
+ environment: process.env.VERCEL_ENV,
+ dsn: SENTRY_DSN_KEY,
+ tracesSampleRate: 1.0,
+ integrations: [
+ Sentry.reactRouterV6BrowserTracingIntegration({
+ useEffect,
+ useLocation,
+ useNavigationType,
+ createRoutesFromChildren,
+ matchRoutes
+ }),
+ // eslint-disable-next-line import/namespace
+ Sentry.replayIntegration()
+ ],
+
+ tracePropagationTargets: [
+ /^https:\/\/onboarding.gdschongik.com\/?.*$/,
+ /^https:\/\/api\.gdschongik\.com\/?.*$/,
+ /^https:\/\/dev-onboarding.gdschongik.com\/?.*$/,
+ /^https:\/\/dev-api\.gdschongik\.com\/?.*$/
+ ],
+ replaysSessionSampleRate: 0.1,
+ replaysOnErrorSampleRate: 1.0
+ });
+ }
+ return { initSentry };
+};
+
+const sentry = setSentry();
+export default sentry;
diff --git a/src/utils/storage/key.ts b/src/utils/storage/key.ts
deleted file mode 100644
index 2fde82d..0000000
--- a/src/utils/storage/key.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export const enum StorageKeys {
- AccessToken = 'access_token',
- RefreshToken = 'refresh_token'
-}
-
-export const enum CookieKeys {
- AccessToken = 'accessToken',
- RefreshToken = 'refreshToken'
-}
diff --git a/vite.config.ts b/vite.config.ts
index f009a9d..1a9c1d8 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -2,7 +2,24 @@ import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import tsconfigPaths from 'vite-tsconfig-paths';
+import { sentryVitePlugin } from '@sentry/vite-plugin';
+
// https://vitejs.dev/config/
export default defineConfig({
- plugins: [react(), tsconfigPaths()]
+ plugins: [
+ react(),
+ tsconfigPaths(),
+ sentryVitePlugin({
+ org: process.env.SENTRY_ORG_NAME,
+ project: process.env.SENTRY_PROJECT_NAME,
+ authToken: process.env.SENTRY_AUTH_TOKEN,
+ sourcemaps: {
+ assets: './dist/**',
+ filesToDeleteAfterUpload: '**/*.map'
+ }
+ })
+ ],
+ build: {
+ sourcemap: true
+ }
});