From ecc239a2fec7a65df94e3e814b2274983554da3b Mon Sep 17 00:00:00 2001
From: sangminlee98
Date: Tue, 5 Sep 2023 18:31:38 +0900
Subject: [PATCH 01/11] =?UTF-8?q?feat:=20=ED=9A=8C=EC=9B=90=EA=B0=80?=
=?UTF-8?q?=EC=9E=85=20UI=20=EC=95=BD=EA=B4=80=EC=B6=94=EA=B0=80=20?=
=?UTF-8?q?=EB=B0=8F=20=EC=A0=84=EC=B2=B4=EB=8F=99=EC=9D=98=20=EA=B8=B0?=
=?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80,=20=EA=B3=B5=EC=9D=B8=EC=A4=91?=
=?UTF-8?q?=EA=B0=9C=EC=82=AC=20=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20?=
=?UTF-8?q?=EB=A7=81=ED=81=AC=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/Routes.tsx | 2 +
src/components/Terms/MarketingTerm.tsx | 33 +++
src/components/Terms/PrivacyTerm.tsx | 36 +++
src/components/Terms/ServiceTerm.tsx | 313 +++++++++++++++++++++++
src/components/Terms/index.tsx | 324 ++----------------------
src/components/Terms/styles.module.scss | 2 +-
src/pages/AgentSignUp/index.tsx | 3 +
src/pages/SignUp/index.tsx | 116 ++++++++-
src/pages/SignUp/styles.module.scss | 94 +++++++
src/types/signUp.ts | 1 +
10 files changed, 605 insertions(+), 319 deletions(-)
create mode 100644 src/components/Terms/MarketingTerm.tsx
create mode 100644 src/components/Terms/PrivacyTerm.tsx
create mode 100644 src/components/Terms/ServiceTerm.tsx
create mode 100644 src/pages/AgentSignUp/index.tsx
create mode 100644 src/types/signUp.ts
diff --git a/src/Routes.tsx b/src/Routes.tsx
index 1db43e5..c7e09ef 100644
--- a/src/Routes.tsx
+++ b/src/Routes.tsx
@@ -5,6 +5,7 @@ import GlobalLayout from '@/pages/_layout';
const MainPage = lazy(() => import('@/pages/Main'));
const LoginPage = lazy(() => import('@/pages/Login'));
const SignUpPage = lazy(() => import('@/pages/SignUp'));
+const AgentSignUpPage = lazy(() => import('@/pages/AgentSignUp'));
const MyPage = lazy(() => import('@/pages/Mypage'));
const IntroducePage = lazy(() => import('@/pages/Introduce'));
const IntroWritePage = lazy(() => import('@/pages/Introduce/Write'));
@@ -28,6 +29,7 @@ export const routes: RouteObject[] = [
{ index: true, element: },
{ path: 'login', element: },
{ path: 'signup', element: },
+ { path: 'agentSignup', element: },
{ path: 'mypage', element: },
{ path: 'introduce', element: },
{ path: 'intro_write', element: },
diff --git a/src/components/Terms/MarketingTerm.tsx b/src/components/Terms/MarketingTerm.tsx
new file mode 100644
index 0000000..16546e5
--- /dev/null
+++ b/src/components/Terms/MarketingTerm.tsx
@@ -0,0 +1,33 @@
+import styles from './styles.module.scss';
+
+export type MarketingTermProps = {
+ onToggleClick: () => void;
+};
+
+export default function MarketingTerm({ onToggleClick }: MarketingTermProps) {
+ return (
+
+
마켓팅 활용 및 광고성 정보 수신 동의(선택)
+
+
+ 전자적 전송매체(SMS/MMS/이메일 등)를 통해, 주말내집이 제공하는
+ 이벤트/혜택 등 다양한 정보(뉴스레터 포함)를 수신하실 수 있고, 기타
+ 유용한 광고나 정보를 수신하실 수 있습니다.
+
+
+ 본 마케팅 활용 및 광고성 정보수신 등의 항목은 선택사항이므로 동의를
+ 거부하는 경우에도 주말내집 서비스의 이용에는 영향이 없습니다. 다만
+ 거부시 동의를 통해 제공 가능한 각종 혜택, 이벤트 안내를 받아 보실 수
+ 없습니다.
+
+
+ 본 수신 동의를 철회하고자 할 경우에는 고객센터(주말내집 이메일)를 통해
+ 언제든 수신동의를 철회를 요청하실 수 있습니다.
+
+
+
+ 확인
+
+
+ );
+}
diff --git a/src/components/Terms/PrivacyTerm.tsx b/src/components/Terms/PrivacyTerm.tsx
new file mode 100644
index 0000000..a9ef530
--- /dev/null
+++ b/src/components/Terms/PrivacyTerm.tsx
@@ -0,0 +1,36 @@
+import styles from './styles.module.scss';
+
+export type PrivacyTermProps = {
+ onToggleClick: () => void;
+};
+
+export default function PrivacyTerm({ onToggleClick }: PrivacyTermProps) {
+ return (
+
+
개인정보 수집 및 이용 동의(선택)
+
+
+ 1. 개인정보의 수집·이용 목적
+ 마케팅에의 활용.
+
+
+ 2. 개인정보 보유 및 이용기간
+ 회원 탈퇴 시까지
+
+
+ 3. 처리하는 개인정보 항목
+ 이름, 이메일 주소, 전화번호, 주거래 매물, 연령대
+
+
+ 이는 주말내집이 제공하는 서비스를 보다 원활하게 이용하도록 하기 위해서
+ 그 수집 및 이용이 필요한 개인정보이므로 해당 항목에 동의를 거부하시는
+ 경우에도 위 개인정보를 수집 및 이용하는 서비스를 제외하고 나머지
+ 서비스에 대해서는 이용이 가능합니다.
+
+
+
+ 확인
+
+
+ );
+}
diff --git a/src/components/Terms/ServiceTerm.tsx b/src/components/Terms/ServiceTerm.tsx
new file mode 100644
index 0000000..02b8be4
--- /dev/null
+++ b/src/components/Terms/ServiceTerm.tsx
@@ -0,0 +1,313 @@
+import styles from './styles.module.scss';
+
+export type ServiceTermProps = {
+ onToggleClick: () => void;
+};
+
+export default function ServiceTerm({ onToggleClick }: ServiceTermProps) {
+ return (
+
+
이용약관(필수)
+
+
+ 총칙
+
+
+ 제 1조(목적)
+
+ 주말내집 서비스 이용약관은 주말내집 (이하 “회사”)가 서비스를
+ 제공함에 있어, 회사와 회원 간의 권리, 의무 및 책임 사항 등을
+ 규정함을 목적으로 합니다.
+
+
+
+ 제 2조(정의)
+
+ 이 약관에서 사용하는 용어의 정의는 다음과 같습니다.
+
+ '회사'란, 서비스를 제공하는 주체를 말합니다.
+
+ '서비스'란, 회사가 제공하는 모든 서비스 및 기능을
+ 말합니다.
+
+
+ '회원'이란, 약관에 따라 서비스에 회원등록을 하고
+ 서비스를 이용하는 자를 말합니다.
+
+
+ '계정'이란, 이용계약을 통해 생성된 회원의 고유
+ 아이디와 이에 수반하는 정보를 말합니다.
+
+
+ '콘텐츠'란, 서비스에서 제공하는 모든 종류의 ‘대화
+ 주제’ 등을 말합니다.
+
+
+ '관련법'이란, 정보통신망 이용촉진 및 정보보호 등에
+ 관한 법률, 개인정보보호법, 통신비밀보호법을 비롯한 국내 법령을
+ 말합니다.
+
+
+
+ 1항에서 정의되지 않는 약관 내 용어의 의미는 일반적인 이용관행에
+ 의합니다.
+
+
+
+
+
+ 제 3조(약관 등의 명시와 설명 및 개정)
+
+
+ 회사는 이 약관을 회원가입 화면 및 페이지 하단에 게시합니다.
+
+ 회사는 관련법을 위배하지 않는 범위 내에서 이 약관을 개정할 수
+ 있습니다.
+
+
+ 개정 내용이 회원에게 불리할 경우, 적용일자 및 개정사유를 명시하여
+ 현행약관과 함께 알림 수단을 통해 고지하며 변경될 내용을 변경 30일
+ 전에 미리 알려드리겠습니다.
+
+
+ 회원이 개정약관의 적용에 동의하지 않는 경우, 이용계약을
+ 해지함으로써 거부 의사를 표시할 수 있습니다. 단, 30일 내에 거부
+ 의사 표시를 하지 않을 경우 약관에 동의한 것으로 간주합니다.
+
+ 회원은 본 약관의 일부분만을 동의 또는 거부할 수 없습니다.
+
+
+
+ 제 4조(서비스의 제공)
+
+ 회사는 다음 서비스를 제공합니다.
+
+ 오도이촌 소개 서비스
+ 커뮤니티 서비스
+ 마이페이지 서비스
+ 이벤트, 프로모션, 광고 정보 제공 서비스
+ 기타 회사가 정하는 서비스
+
+
+ 회사는 운영상, 기술상의 필요에 따라 제공하고 있는 서비스를 변경할
+ 수 있습니다.
+
+
+ 회사는 회원의 개인정보 및 서비스 이용 기록에 따라 서비스 이용에
+ 차이를 둘 수 있습니다.
+
+
+ 회사는 천재지변, 인터넷 장애, 경영 악화 등으로 인해 서비스를
+ 더이상 제공하기 어려울 경우, 서비스를 통보 없이 중단할 수
+ 있습니다.
+
+
+ 회사는 1항부터 전항까지와 다음 내용으로 인해 발생한 피해에 대해
+ 어떠한 책임도 지지 않습니다.
+
+
+
+ 모든 서비스, 콘텐츠, 이용 기록의 진본성, 무결성, 신뢰성,
+ 이용가능성
+
+
+ 서비스 내에서 성사된 모임에서 발생한 금전적, 신체적, 정신적 피해
+
+
+ 온라인, 오프라인에서의 서비스 이용 중 사용자에게 발생한 피해
+
+
+ 광고의 버튼, 하이퍼링크 등 외부로 연결된 서비스와 같이 회사가
+ 제공하지 않은 서비스에서 발생한 피해
+
+
+ 회원의 귀책 사유 또는 회사의 귀책 사유가 아닌 사유로 발생한
+ 회원의 피해
+
+
+
+
+
+ 제 5조(서비스 이용계약의 성립)
+
+
+ 회사와 회원의 서비스 이용계약은 서비스 내부의 회원가입 화면 가입
+ 양식에 따라 회원정보를 기입한 후 필수 약관에 동의한다는 의사표시를
+ 하면서 체결됩니다.
+
+
+ 회원은 회사에서 제공하는 절차에 따라 회원가입을 진행해야 하며,
+ 반드시 실제 이메일과 생년월일을 사용해야 합니다. 실제 정보를
+ 입력하지 않은 이용자는 법적인 보호를 받을 수 없으며, 서비스 이용에
+ 제한을 받을 수 있습니다
+
+
+
+
+ 제 6조(개인정보의 관리 및 보호)
+
+
+ 회원이 회사와 체결한 서비스 이용계약은 처음 이용계약을 체결한
+ 본인에 한해 적용됩니다.
+
+
+ 회원의 이메일과 비밀번호, 닉네임 등 모든 개인정보의 관리책임은
+ 본인에게 있으므로, 타인에게 양도 및 대여할 수 없으며, 유출되지
+ 않도록 관리해야합니다. 만약 본인의 이메일 및 비밀번호를 타인이
+ 사용하고 있음을 인지했을 경우 즉시 비밀번호를 변경해야 합니다.
+
+
+ 회사는 2항부터 전항까지를 이행하지 않아 발생한 피해에 대해 어떠한
+ 책임을 지지 않습니다.
+
+
+
+
+ 제 7조(서비스 이용계약의 종료)
+
+
+ 회원은 언제든지 본인의 계정으로 로그인한 뒤 서비스 내부의
+ '회원 탈퇴' 버튼을 누르는 방법으로 탈퇴를 요청할 수
+ 있으며, 문의 창구를 통한 탈퇴 요청 등은 처리되지 않습니다. 회사는
+ 해당 요청을 확인한 후 탈퇴를 처리합니다.
+
+
+ 회사는 천재지변, 서비스 종료 등 불가피한 사유로 더이상 서비스를
+ 제공할 수 없을 경우, 회원의 동의 없이 회원자격을 박탈할 수
+ 있습니다.
+
+
+ 회사는 1항부터 전항까지로 인해 발생한 피해에 대해 어떠한 책임을
+ 지지 않습니다.
+
+
+
+
+ 제 8조(회원에 대한 통보)
+
+
+ 회사가 회원에 대한 통보를 하는 경우, 회원이 회원가입 시 입력한
+ 이메일을 이용합니다.
+
+
+ 회사는 다수의 회원에 대한 통보를 할 경우 서비스 내부 알림 메시지를
+ 띄우는 등의 방법을 통해 개별 통보에 갈음할 수 있습니다.
+
+
+ 회원이 30일 이내에 의사표시를 하지 않을 경우, 통보 내용에 대해
+ 동의한 것으로 간주합니다.
+
+
+
+
+ 제 9조(저작권의 귀속)
+
+
+ 회사는 유용하고 편리한 서비스를 제공하기 위해, 2022년부터 서비스
+ 및 서비스 내부의 기능 체계와 다양한 기능을 직접 설계 및 운영하고
+ 있는 데이터베이스 제작자에 해당합니다. 회사는 저작권법에 따라
+ 데이터베이스 제작자는 복제권 및 전송권을 포함한 데이터베이스
+ 전부에 대한 권리를 가지고 있으며, 이는 법률에 따라 보호를 받는
+ 대상입니다. 그러므로 회원은 데이터 베이스 제작자인 회사의 승인
+ 없이 데이터베이스의 전부 또는 일부를 복제・배포・방송 또는 전송할
+ 수 없습니다.
+
+
+ 회사가 작성한 콘텐츠에 대한 권리는 회사에 귀속됩니다. 회원은
+ 별도의 허락 없이 회사의 콘텐츠에 대해 본래의 서비스 이용을 제외한
+ 목적으로 사용, 수정, 배포할 수 없습니다
+
+
+
+
+ 제 10조(광고의 게재)
+
+
+ 회사는 서비스의 운용과 관련하여 서비스 화면, 홈페이지, 이메일 등에
+ 광고를 게재할 수 있습니다.
+
+
+ 회사는 서비스에 게재되어 있는 광고주의 판촉활동에 회원이
+ 참여하거나 교신 또는 거래의 결과로 인해 발생하는 모든 손실 및
+ 손해에 대해 책임을 지지 않습니다.
+
+
+
+
+ 제 11조(금지행위)
+
+ 회원에 의한 다음 행위는 금지되어 있습니다.
+
+ 개인정보 또는 계정 기만, 침해, 공유 행위
+ 개인정보를 허위, 누락, 오기, 도용하여 작성하는 행위
+ 타인의 개인정보 및 계정을 수집, 저장, 공개, 이용하는 행위
+ 자신과 타인의 개인정보를 제 3자에게 공개, 양도하는 행위
+ 시스템 부정행위
+ 허가하지 않은 방식의 서비스 이용 행위
+ 회사의 모든 재산에 대한 침해 행위
+ 업무 방해 행위
+
+ 서비스 관리자 또는 이에 준하는 자격을 사칭하거나 허가없이
+ 취득하여 직권을 행사하는 행위
+
+ 회사 및 타인의 명예를 손상시키거나 업무를 방해하는 행위
+
+ 서비스 내부 정보 일체를 허가 없이 이용, 변조, 삭제 및 외부로
+ 유출하는 행위
+
+
+ 이 약관, 개인정보 처리방침에서 이행 및 비이행을 명시한 내용에
+ 반하는 행위
+
+ 기타 현행법에 어긋나거나 부적절하다고 판단되는 행위
+
+
+ 회원이 1항에 해당하는 행위를 할 경우, 회사는 다음과 같은 조치를
+ 영구적으로 취할 수 있습니다.
+
+
+ 회원의 서비스 이용 권한, 자격, 혜택 제한 및 회수
+ 회원과 체결된 이용계약을 회원의 동의나 통보 없이 파기
+ 회원가입 거부
+ 그 외 회사가 필요하다고 판단되는 조치
+
+
+ 회사는 1항부터 전항까지로 인해 발생한 피해에 대해 어떠한 책임을
+ 지지 않으며, 회원은 귀책사유로 인해 발생한 모든 손해를 배상할
+ 책임이 있습니다.
+
+
+
+
+ 제 12조(재판권 및 준거법)
+
+
+ 회사와 회원 간에 발생한 분쟁에 관한 소송은 대한민국
+ 서울중앙지방법원을 관할 법원으로 합니다. 다만, 제소 당시 회원의
+ 주소 또는 거소가 분명하지 않거나 외국 거주자의 경우에는
+ 민사소송법상의 관할법원에 제기합니다.
+
+ 회사와 회원 간에 제기된 소송에는 한국법을 적용합니다.
+
+
+
+ 제 13조(기타)
+
+ 이 약관은 2023년 1월 27일에 제정되었습니다.
+
+ 이 약관에서 정하지 아니한 사항과 이 약관의 해석에 관하여는 관련법
+ 또는 관례에 따릅니다.
+
+
+ 이 약관에도 불구하고 다른 약관이나 서비스 이용 중 안내 문구 등으로
+ 달리 정함이 있는 경우에는 해당 내용을 우선으로 합니다.
+
+
+
+
+
+ 확인
+
+
+ );
+}
diff --git a/src/components/Terms/index.tsx b/src/components/Terms/index.tsx
index 8dce9bb..2455402 100644
--- a/src/components/Terms/index.tsx
+++ b/src/components/Terms/index.tsx
@@ -1,11 +1,16 @@
import React from 'react';
+import { TermType } from '@/types/signUp';
+import MarketingTerm from './MarketingTerm';
+import PrivacyTerm from './PrivacyTerm';
+import ServiceTerm from './ServiceTerm';
import styles from './styles.module.scss';
type TermsProps = {
+ selectedTerm: TermType;
setToggle: React.Dispatch>;
};
-export default function Terms({ setToggle }: TermsProps) {
+export default function Terms({ selectedTerm, setToggle }: TermsProps) {
const onToggleClick = () => {
const bodyEl = document.querySelector('body');
bodyEl?.classList.remove('over_hidden');
@@ -13,314 +18,15 @@ export default function Terms({ setToggle }: TermsProps) {
};
return (
-
-
이용약관(필수)
-
-
- 총칙
-
-
- 제 1조(목적)
-
- 주말내집 서비스 이용약관은 주말내집 (이하 “회사”)가 서비스를
- 제공함에 있어, 회사와 회원 간의 권리, 의무 및 책임 사항 등을
- 규정함을 목적으로 합니다.
-
-
-
- 제 2조(정의)
-
- 이 약관에서 사용하는 용어의 정의는 다음과 같습니다.
-
- '회사'란, 서비스를 제공하는 주체를 말합니다.
-
- '서비스'란, 회사가 제공하는 모든 서비스 및 기능을
- 말합니다.
-
-
- '회원'이란, 약관에 따라 서비스에 회원등록을 하고
- 서비스를 이용하는 자를 말합니다.
-
-
- '계정'이란, 이용계약을 통해 생성된 회원의 고유
- 아이디와 이에 수반하는 정보를 말합니다.
-
-
- '콘텐츠'란, 서비스에서 제공하는 모든 종류의 ‘대화
- 주제’ 등을 말합니다.
-
-
- '관련법'이란, 정보통신망 이용촉진 및 정보보호 등에
- 관한 법률, 개인정보보호법, 통신비밀보호법을 비롯한 국내 법령을
- 말합니다.
-
-
-
- 1항에서 정의되지 않는 약관 내 용어의 의미는 일반적인 이용관행에
- 의합니다.
-
-
-
-
-
- 제 3조(약관 등의 명시와 설명 및 개정)
-
-
-
- 회사는 이 약관을 회원가입 화면 및 페이지 하단에 게시합니다.
-
-
- 회사는 관련법을 위배하지 않는 범위 내에서 이 약관을 개정할 수
- 있습니다.
-
-
- 개정 내용이 회원에게 불리할 경우, 적용일자 및 개정사유를
- 명시하여 현행약관과 함께 알림 수단을 통해 고지하며 변경될 내용을
- 변경 30일 전에 미리 알려드리겠습니다.
-
-
- 회원이 개정약관의 적용에 동의하지 않는 경우, 이용계약을
- 해지함으로써 거부 의사를 표시할 수 있습니다. 단, 30일 내에 거부
- 의사 표시를 하지 않을 경우 약관에 동의한 것으로 간주합니다.
-
- 회원은 본 약관의 일부분만을 동의 또는 거부할 수 없습니다.
-
-
-
- 제 4조(서비스의 제공)
-
- 회사는 다음 서비스를 제공합니다.
-
- 오도이촌 소개 서비스
- 커뮤니티 서비스
- 마이페이지 서비스
- 이벤트, 프로모션, 광고 정보 제공 서비스
- 기타 회사가 정하는 서비스
-
-
- 회사는 운영상, 기술상의 필요에 따라 제공하고 있는 서비스를
- 변경할 수 있습니다.
-
-
- 회사는 회원의 개인정보 및 서비스 이용 기록에 따라 서비스 이용에
- 차이를 둘 수 있습니다.
-
-
- 회사는 천재지변, 인터넷 장애, 경영 악화 등으로 인해 서비스를
- 더이상 제공하기 어려울 경우, 서비스를 통보 없이 중단할 수
- 있습니다.
-
-
- 회사는 1항부터 전항까지와 다음 내용으로 인해 발생한 피해에 대해
- 어떠한 책임도 지지 않습니다.
-
-
-
- 모든 서비스, 콘텐츠, 이용 기록의 진본성, 무결성, 신뢰성,
- 이용가능성
-
-
- 서비스 내에서 성사된 모임에서 발생한 금전적, 신체적, 정신적
- 피해
-
-
- 온라인, 오프라인에서의 서비스 이용 중 사용자에게 발생한 피해
-
-
- 광고의 버튼, 하이퍼링크 등 외부로 연결된 서비스와 같이 회사가
- 제공하지 않은 서비스에서 발생한 피해
-
-
- 회원의 귀책 사유 또는 회사의 귀책 사유가 아닌 사유로 발생한
- 회원의 피해
-
-
-
-
-
- 제 5조(서비스 이용계약의 성립)
-
-
- 회사와 회원의 서비스 이용계약은 서비스 내부의 회원가입 화면 가입
- 양식에 따라 회원정보를 기입한 후 필수 약관에 동의한다는
- 의사표시를 하면서 체결됩니다.
-
-
- 회원은 회사에서 제공하는 절차에 따라 회원가입을 진행해야 하며,
- 반드시 실제 이메일과 생년월일을 사용해야 합니다. 실제 정보를
- 입력하지 않은 이용자는 법적인 보호를 받을 수 없으며, 서비스
- 이용에 제한을 받을 수 있습니다
-
-
-
-
- 제 6조(개인정보의 관리 및 보호)
-
-
- 회원이 회사와 체결한 서비스 이용계약은 처음 이용계약을 체결한
- 본인에 한해 적용됩니다.
-
-
- 회원의 이메일과 비밀번호, 닉네임 등 모든 개인정보의 관리책임은
- 본인에게 있으므로, 타인에게 양도 및 대여할 수 없으며, 유출되지
- 않도록 관리해야합니다. 만약 본인의 이메일 및 비밀번호를 타인이
- 사용하고 있음을 인지했을 경우 즉시 비밀번호를 변경해야 합니다.
-
-
- 회사는 2항부터 전항까지를 이행하지 않아 발생한 피해에 대해
- 어떠한 책임을 지지 않습니다.
-
-
-
-
- 제 7조(서비스 이용계약의 종료)
-
-
- 회원은 언제든지 본인의 계정으로 로그인한 뒤 서비스 내부의
- '회원 탈퇴' 버튼을 누르는 방법으로 탈퇴를 요청할 수
- 있으며, 문의 창구를 통한 탈퇴 요청 등은 처리되지 않습니다.
- 회사는 해당 요청을 확인한 후 탈퇴를 처리합니다.
-
-
- 회사는 천재지변, 서비스 종료 등 불가피한 사유로 더이상 서비스를
- 제공할 수 없을 경우, 회원의 동의 없이 회원자격을 박탈할 수
- 있습니다.
-
-
- 회사는 1항부터 전항까지로 인해 발생한 피해에 대해 어떠한 책임을
- 지지 않습니다.
-
-
-
-
- 제 8조(회원에 대한 통보)
-
-
- 회사가 회원에 대한 통보를 하는 경우, 회원이 회원가입 시 입력한
- 이메일을 이용합니다.
-
-
- 회사는 다수의 회원에 대한 통보를 할 경우 서비스 내부 알림
- 메시지를 띄우는 등의 방법을 통해 개별 통보에 갈음할 수 있습니다.
-
-
- 회원이 30일 이내에 의사표시를 하지 않을 경우, 통보 내용에 대해
- 동의한 것으로 간주합니다.
-
-
-
-
- 제 9조(저작권의 귀속)
-
-
- 회사는 유용하고 편리한 서비스를 제공하기 위해, 2022년부터 서비스
- 및 서비스 내부의 기능 체계와 다양한 기능을 직접 설계 및 운영하고
- 있는 데이터베이스 제작자에 해당합니다. 회사는 저작권법에 따라
- 데이터베이스 제작자는 복제권 및 전송권을 포함한 데이터베이스
- 전부에 대한 권리를 가지고 있으며, 이는 법률에 따라 보호를 받는
- 대상입니다. 그러므로 회원은 데이터 베이스 제작자인 회사의 승인
- 없이 데이터베이스의 전부 또는 일부를 복제・배포・방송 또는
- 전송할 수 없습니다.
-
-
- 회사가 작성한 콘텐츠에 대한 권리는 회사에 귀속됩니다. 회원은
- 별도의 허락 없이 회사의 콘텐츠에 대해 본래의 서비스 이용을
- 제외한 목적으로 사용, 수정, 배포할 수 없습니다
-
-
-
-
- 제 10조(광고의 게재)
-
-
- 회사는 서비스의 운용과 관련하여 서비스 화면, 홈페이지, 이메일
- 등에 광고를 게재할 수 있습니다.
-
-
- 회사는 서비스에 게재되어 있는 광고주의 판촉활동에 회원이
- 참여하거나 교신 또는 거래의 결과로 인해 발생하는 모든 손실 및
- 손해에 대해 책임을 지지 않습니다.
-
-
-
-
- 제 11조(금지행위)
-
- 회원에 의한 다음 행위는 금지되어 있습니다.
-
- 개인정보 또는 계정 기만, 침해, 공유 행위
- 개인정보를 허위, 누락, 오기, 도용하여 작성하는 행위
-
- 타인의 개인정보 및 계정을 수집, 저장, 공개, 이용하는 행위
-
- 자신과 타인의 개인정보를 제 3자에게 공개, 양도하는 행위
- 시스템 부정행위
- 허가하지 않은 방식의 서비스 이용 행위
- 회사의 모든 재산에 대한 침해 행위
- 업무 방해 행위
-
- 서비스 관리자 또는 이에 준하는 자격을 사칭하거나 허가없이
- 취득하여 직권을 행사하는 행위
-
- 회사 및 타인의 명예를 손상시키거나 업무를 방해하는 행위
-
- 서비스 내부 정보 일체를 허가 없이 이용, 변조, 삭제 및 외부로
- 유출하는 행위
-
-
- 이 약관, 개인정보 처리방침에서 이행 및 비이행을 명시한 내용에
- 반하는 행위
-
- 기타 현행법에 어긋나거나 부적절하다고 판단되는 행위
-
-
- 회원이 1항에 해당하는 행위를 할 경우, 회사는 다음과 같은 조치를
- 영구적으로 취할 수 있습니다.
-
-
- 회원의 서비스 이용 권한, 자격, 혜택 제한 및 회수
- 회원과 체결된 이용계약을 회원의 동의나 통보 없이 파기
- 회원가입 거부
- 그 외 회사가 필요하다고 판단되는 조치
-
-
- 회사는 1항부터 전항까지로 인해 발생한 피해에 대해 어떠한 책임을
- 지지 않으며, 회원은 귀책사유로 인해 발생한 모든 손해를 배상할
- 책임이 있습니다.
-
-
-
-
- 제 12조(재판권 및 준거법)
-
-
- 회사와 회원 간에 발생한 분쟁에 관한 소송은 대한민국
- 서울중앙지방법원을 관할 법원으로 합니다. 다만, 제소 당시 회원의
- 주소 또는 거소가 분명하지 않거나 외국 거주자의 경우에는
- 민사소송법상의 관할법원에 제기합니다.
-
- 회사와 회원 간에 제기된 소송에는 한국법을 적용합니다.
-
-
-
- 제 13조(기타)
-
- 이 약관은 2023년 1월 27일에 제정되었습니다.
-
- 이 약관에서 정하지 아니한 사항과 이 약관의 해석에 관하여는
- 관련법 또는 관례에 따릅니다.
-
-
- 이 약관에도 불구하고 다른 약관이나 서비스 이용 중 안내 문구
- 등으로 달리 정함이 있는 경우에는 해당 내용을 우선으로 합니다.
-
-
-
-
-
- 확인
-
-
+ {selectedTerm === 'SERVICE' && (
+
+ )}
+ {selectedTerm === 'PRIVACY' && (
+
+ )}
+ {selectedTerm === 'MARKETING' && (
+
+ )}
);
}
diff --git a/src/components/Terms/styles.module.scss b/src/components/Terms/styles.module.scss
index b4c065b..35de5d4 100644
--- a/src/components/Terms/styles.module.scss
+++ b/src/components/Terms/styles.module.scss
@@ -14,7 +14,7 @@
display: flex;
flex-direction: column;
width: 38.25rem;
- height: 51.5rem;
+ max-height: 51.5rem;
background-color: white;
border-radius: 25px;
& > h1 {
diff --git a/src/pages/AgentSignUp/index.tsx b/src/pages/AgentSignUp/index.tsx
new file mode 100644
index 0000000..0462ac2
--- /dev/null
+++ b/src/pages/AgentSignUp/index.tsx
@@ -0,0 +1,3 @@
+export default function AgentSignUpPage() {
+ return 공인중개사 회원가입 페이지
;
+}
diff --git a/src/pages/SignUp/index.tsx b/src/pages/SignUp/index.tsx
index 0bafba6..dfc9351 100644
--- a/src/pages/SignUp/index.tsx
+++ b/src/pages/SignUp/index.tsx
@@ -10,6 +10,7 @@ import { restFetcher } from '@/queryClient';
import Terms from '@/components/Terms';
import userStore from '@/store/userStore';
import useCheckAPI from '@/hooks/useCheckAPI';
+import { TermType } from '@/types/signUp';
import { opacityVariants } from '@/constants/variants';
import styles from './styles.module.scss';
@@ -22,7 +23,7 @@ type IForm = {
phone_check: string;
age: string;
join_paths: string[];
- terms: boolean;
+ service_term: boolean;
};
type ISubmitForm = {
email: string;
@@ -38,6 +39,7 @@ export default function SignUpPage() {
register,
watch,
handleSubmit,
+ setValue,
formState: { errors },
} = useForm({
mode: 'onSubmit',
@@ -93,6 +95,11 @@ export default function SignUpPage() {
const [phoneSMSCheck, setPhoneSMSCheck] = useState(false); // 전화번호 인증 완료 상태
const [phoneSMSMessage, setPhoneSMSMessage] = useState(); // 전화번호 인증 완료 상태
const [phoneErrMessage, setPhoneErrMessage] = useState(); // 전화번호 에러 메세지
+ const [isServiceTerm, setIsServiceTerm] = useState(false);
+ const [isPrivacyTerm, setIsPrivacyTerm] = useState(false);
+ const [isMarketingTerm, setIsMarketingTerm] = useState(false);
+ const [selectedTerm, setSelectedTerm] = useState('');
+
const [
idCheck,
idCheckMessage,
@@ -121,10 +128,11 @@ export default function SignUpPage() {
'이미 존재하는 닉네임 입니다.',
'닉네임 형식에 맞지 않습니다.',
);
- const onToggleClick = () => {
+ const onToggleClick = (term: TermType) => {
const bodyEl = document.querySelector('body');
bodyEl?.classList.add('over_hidden');
setToggle(true);
+ setSelectedTerm(term);
};
const onEyeClick = (e: React.MouseEvent) => {
if (e.currentTarget.id === 'passwordEye') setEyeState((prev) => !prev);
@@ -199,6 +207,12 @@ export default function SignUpPage() {
},
);
};
+
+ const handleAllSelect = (isSelected: boolean) => {
+ setIsServiceTerm(isSelected);
+ setIsPrivacyTerm(isSelected);
+ setIsMarketingTerm(isSelected);
+ };
useEffect(() => {
onChangeInput(setIdCheck, setIdCheckMessage, '아이디');
}, [watch('email')]);
@@ -221,6 +235,18 @@ export default function SignUpPage() {
className={styles.container}
>
+
+
+ 공인중개사 회원이신가요?
+
+ navigate('/agentSignup')}
+ >
+ 공인중개사 회원가입
>
+
+
- {toggle ? : null}
+ {toggle ? (
+
+ ) : null}
);
}
diff --git a/src/pages/SignUp/styles.module.scss b/src/pages/SignUp/styles.module.scss
index 51fafa4..a6ceb11 100644
--- a/src/pages/SignUp/styles.module.scss
+++ b/src/pages/SignUp/styles.module.scss
@@ -13,6 +13,30 @@
margin-top: 5.25rem;
margin-bottom: 2rem;
}
+.agentSingUp {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: 2rem;
+ margin-bottom: 3rem;
+ font-family: 'Pretendard';
+ & > h3 {
+ font-size: 1.45rem;
+ color: #4d5256;
+ & > strong {
+ font-weight: bold;
+ }
+ }
+ & > button {
+ @extend .termsButton;
+ display: flex;
+ gap: 0.25rem;
+ & > p {
+ text-decoration: underline;
+ text-underline-position: under;
+ }
+ }
+}
.formContent {
display: flex;
flex-direction: column;
@@ -34,6 +58,33 @@
margin-bottom: 0.5rem;
margin-left: 0.5rem;
}
+ & > span {
+ flex: 0 0 auto;
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ &:hover {
+ opacity: 0.8;
+ }
+ & > input {
+ appearance: none;
+ background-color: var(--gray-color);
+ width: 1.5rem;
+ height: 1.5rem;
+ border-radius: 5px;
+ margin: 0;
+ margin-right: 0.5rem;
+ cursor: pointer;
+ &:checked {
+ background-color: var(--main-color);
+ }
+ }
+ & > label {
+ font-family: 'Pretendard';
+ color: #4d5256;
+ cursor: pointer;
+ }
+ }
& > input {
width: 100%;
}
@@ -101,6 +152,47 @@
outline: none;
}
}
+.inputContainerTitle {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 1rem;
+ & > label {
+ font-family: 'Pretendard';
+ font-weight: 700;
+ font-size: 1.25rem;
+ color: #4d5256;
+ margin-bottom: 0.5rem;
+ margin-left: 0.5rem;
+ }
+ & > span {
+ flex: 0 0 auto;
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ &:hover {
+ opacity: 0.8;
+ }
+ & > input {
+ appearance: none;
+ background-color: var(--gray-color);
+ width: 1.5rem;
+ height: 1.5rem;
+ border-radius: 5px;
+ margin: 0;
+ margin-right: 0.5rem;
+ cursor: pointer;
+ &:checked {
+ background-color: var(--main-color);
+ }
+ }
+ & > label {
+ font-family: 'Pretendard';
+ color: #4d5256;
+ cursor: pointer;
+ }
+ }
+}
.buttonStyle {
width: 8rem;
border: 2px solid #a9afb3;
@@ -190,12 +282,14 @@
.signUpButton {
width: 100%;
height: 4rem;
+ margin-top: 3rem;
margin-bottom: 8rem;
border: none;
border-radius: 8px;
background-color: var(--darkgray-color);
font-size: 1.5rem;
color: white;
+ cursor: pointer;
&:hover {
opacity: 0.8;
}
diff --git a/src/types/signUp.ts b/src/types/signUp.ts
new file mode 100644
index 0000000..b6ef942
--- /dev/null
+++ b/src/types/signUp.ts
@@ -0,0 +1 @@
+export type TermType = '' | 'SERVICE' | 'PRIVACY' | 'MARKETING';
From e070b888feb7cdf09e888abce939d8414bf0e9a5 Mon Sep 17 00:00:00 2001
From: sangminlee98
Date: Tue, 19 Sep 2023 00:02:05 +0900
Subject: [PATCH 02/11] =?UTF-8?q?design:=20=EA=B3=B5=EC=9D=B8=EC=A4=91?=
=?UTF-8?q?=EA=B0=9C=EC=82=AC=20=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20?=
=?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20UI?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/Routes.tsx | 2 +-
src/components/Trade/AddressModal/index.tsx | 14 +-
src/pages/AgentSignUp/index.tsx | 3 -
src/pages/SignUp/AgentSignUp/index.tsx | 396 ++++++++++++++++++
.../SignUp/AgentSignUp/styles.module.scss | 49 +++
src/pages/SignUp/styles.module.scss | 1 +
src/pages/Trade/Write/index.tsx | 13 +-
src/styles/reset.scss | 1 +
8 files changed, 465 insertions(+), 14 deletions(-)
delete mode 100644 src/pages/AgentSignUp/index.tsx
create mode 100644 src/pages/SignUp/AgentSignUp/index.tsx
create mode 100644 src/pages/SignUp/AgentSignUp/styles.module.scss
diff --git a/src/Routes.tsx b/src/Routes.tsx
index c7e09ef..24e85fd 100644
--- a/src/Routes.tsx
+++ b/src/Routes.tsx
@@ -5,7 +5,7 @@ import GlobalLayout from '@/pages/_layout';
const MainPage = lazy(() => import('@/pages/Main'));
const LoginPage = lazy(() => import('@/pages/Login'));
const SignUpPage = lazy(() => import('@/pages/SignUp'));
-const AgentSignUpPage = lazy(() => import('@/pages/AgentSignUp'));
+const AgentSignUpPage = lazy(() => import('@/pages/SignUp/AgentSignUp'));
const MyPage = lazy(() => import('@/pages/Mypage'));
const IntroducePage = lazy(() => import('@/pages/Introduce'));
const IntroWritePage = lazy(() => import('@/pages/Introduce/Write'));
diff --git a/src/components/Trade/AddressModal/index.tsx b/src/components/Trade/AddressModal/index.tsx
index 1f736e3..9440d15 100644
--- a/src/components/Trade/AddressModal/index.tsx
+++ b/src/components/Trade/AddressModal/index.tsx
@@ -1,14 +1,14 @@
import React from 'react';
-import DaumPostcodeEmbed from 'react-daum-postcode';
+import DaumPostcodeEmbed, { Address } from 'react-daum-postcode';
import styles from './styles.module.scss';
type AddressModalProps = {
- setForm: React.Dispatch>;
+ callback: (fullAddress: string, zipCode?: string) => void;
setIsPostcodeOpen: React.Dispatch>;
};
-function AddressModal({ setForm, setIsPostcodeOpen }: AddressModalProps) {
- const handleComplete = (data: any) => {
+function AddressModal({ callback, setIsPostcodeOpen }: AddressModalProps) {
+ const handleComplete = (data: Address) => {
let fullAddress = data.address;
let extraAddress = '';
@@ -22,11 +22,7 @@ function AddressModal({ setForm, setIsPostcodeOpen }: AddressModalProps) {
}
fullAddress += extraAddress !== '' ? ` (${extraAddress})` : '';
}
- setForm((prev: any) => ({
- ...prev,
- city: fullAddress,
- zipCode: data.zonecode,
- }));
+ callback(fullAddress, data.zonecode);
setIsPostcodeOpen((pre) => !pre);
};
return (
diff --git a/src/pages/AgentSignUp/index.tsx b/src/pages/AgentSignUp/index.tsx
deleted file mode 100644
index 0462ac2..0000000
--- a/src/pages/AgentSignUp/index.tsx
+++ /dev/null
@@ -1,3 +0,0 @@
-export default function AgentSignUpPage() {
- return 공인중개사 회원가입 페이지
;
-}
diff --git a/src/pages/SignUp/AgentSignUp/index.tsx b/src/pages/SignUp/AgentSignUp/index.tsx
new file mode 100644
index 0000000..89a5bfe
--- /dev/null
+++ b/src/pages/SignUp/AgentSignUp/index.tsx
@@ -0,0 +1,396 @@
+import { useState } from 'react';
+import { Navigate } from 'react-router-dom';
+import { motion } from 'framer-motion';
+import logoImage from '@/assets/common/logo.svg';
+import AddressModal from '@/components/Trade/AddressModal';
+import userStore from '@/store/userStore';
+import { opacityVariants } from '@/constants/variants';
+import styles from './styles.module.scss';
+import signUpStyles from '../styles.module.scss';
+
+export default function AgentSignUpPage() {
+ const { token } = userStore();
+ const [isPostcodeOpen, setIsPostcodeOpen] = useState(false);
+
+ const [companyAddress, setCompanyAddress] = useState('');
+
+ const postCodeCallback = (fullAddress: string) => {
+ setCompanyAddress(fullAddress);
+ };
+
+ if (token) {
+ return ;
+ }
+ return (
+
+ {isPostcodeOpen && (
+
+ )}
+
+
+
+ 공인중개사 회원가입 안내사항
+
+
+
+
주말내집의 공인중개사 회원가입은
+
+ 국가공간정보포털의 부동산중개업 정보에 등록된
+
+
+ 대표 공인중개사 만 가능합니다.
+
+
+
+
+ 공인중개사 회원은 담당자가 확인 후 가입 승인 해
+ 드리기에 승인 기간이 소요되는 점 참고 부탁드립니다.
+
+
+ 중개사무소 정보를 정확히 입력해주세요.
+
+
+
+
+
+
+ );
+}
diff --git a/src/pages/SignUp/AgentSignUp/styles.module.scss b/src/pages/SignUp/AgentSignUp/styles.module.scss
new file mode 100644
index 0000000..81b3de7
--- /dev/null
+++ b/src/pages/SignUp/AgentSignUp/styles.module.scss
@@ -0,0 +1,49 @@
+.subtitle {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin-top: 1.75rem;
+ & > h3 {
+ font-size: 1.5rem;
+ font-weight: 600;
+ color: var(--basic-text-color);
+ & > strong {
+ color: var(--main-color);
+ }
+ }
+}
+
+.descriptionWrapper {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 1.5rem;
+ width: 33rem;
+ margin-top: 2.5rem;
+ margin-bottom: 5rem;
+ padding: 1rem 1.5rem;
+ background-color: #eceff0;
+ border-radius: 0.625rem;
+ font-size: 1.25rem;
+ line-height: 1.5rem;
+ color: var(--basic-text-color);
+ & > div {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ }
+ & > ul {
+ margin-left: 1.5rem;
+ box-sizing: content-box;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: flex-start;
+ list-style-type: disc;
+ }
+ & strong {
+ font-weight: 600;
+ }
+}
diff --git a/src/pages/SignUp/styles.module.scss b/src/pages/SignUp/styles.module.scss
index a6ceb11..e7b4bac 100644
--- a/src/pages/SignUp/styles.module.scss
+++ b/src/pages/SignUp/styles.module.scss
@@ -7,6 +7,7 @@
justify-content: center;
align-items: center;
background-color: var(--background-color);
+ font-family: 'Pretendard';
}
.logo {
width: 20rem;
diff --git a/src/pages/Trade/Write/index.tsx b/src/pages/Trade/Write/index.tsx
index c231283..a971731 100644
--- a/src/pages/Trade/Write/index.tsx
+++ b/src/pages/Trade/Write/index.tsx
@@ -46,6 +46,14 @@ export default function TradeWritePage() {
// const appendSpecialCategory = (category: string) => {};
const [isPostcodeOpen, setIsPostcodeOpen] = useState(false);
+ const postCodeCallback = (fullAddress: string, zipCode?: string) => {
+ setForm((prev: TradeBoardForm) => ({
+ ...prev,
+ city: fullAddress,
+ zipCode: zipCode ?? '',
+ }));
+ };
+
const onChangeForm = (e: React.ChangeEvent) => {
const { name, value } = e.target;
@@ -79,7 +87,10 @@ export default function TradeWritePage() {
animate="mount"
>
{isPostcodeOpen && (
-
+
)}
매물 등록
diff --git a/src/styles/reset.scss b/src/styles/reset.scss
index f7cdd07..3f0efcd 100644
--- a/src/styles/reset.scss
+++ b/src/styles/reset.scss
@@ -11,6 +11,7 @@
--gray-background: #eaeeef;
--background-color: #f8fafb;
--sub-color: #5772ff;
+ --basic-text-color: #4d5256;
}
html,
From 68dd29d03cdc024d759c03ab77d8541edc071e6b Mon Sep 17 00:00:00 2001
From: sangminlee98
Date: Tue, 19 Sep 2023 06:36:01 +0900
Subject: [PATCH 03/11] =?UTF-8?q?feat:=20=EA=B3=B5=EC=9D=B8=EC=A4=91?=
=?UTF-8?q?=EA=B0=9C=EC=82=AC=20=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20API?=
=?UTF-8?q?=20=EC=97=B0=EB=8F=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/pages/SignUp/AgentSignUp/index.tsx | 737 +++++++++++++++++++++++--
src/pages/SignUp/index.tsx | 2 +-
2 files changed, 688 insertions(+), 51 deletions(-)
diff --git a/src/pages/SignUp/AgentSignUp/index.tsx b/src/pages/SignUp/AgentSignUp/index.tsx
index 89a5bfe..77434b0 100644
--- a/src/pages/SignUp/AgentSignUp/index.tsx
+++ b/src/pages/SignUp/AgentSignUp/index.tsx
@@ -1,23 +1,260 @@
-import { useState } from 'react';
-import { Navigate } from 'react-router-dom';
+import { useEffect, useState } from 'react';
+import { useForm } from 'react-hook-form';
+import { Navigate, useNavigate } from 'react-router-dom';
+import { useMutation } from '@tanstack/react-query';
import { motion } from 'framer-motion';
+import eyeImage from '@/assets/common/eye.svg';
+import eyeClosedImage from '@/assets/common/eyeClosed.svg';
import logoImage from '@/assets/common/logo.svg';
import AddressModal from '@/components/Trade/AddressModal';
+import { restFetcher } from '@/queryClient';
+import Terms from '@/components/Terms';
import userStore from '@/store/userStore';
+import useCheckAPI from '@/hooks/useCheckAPI';
+import { TermType } from '@/types/signUp';
import { opacityVariants } from '@/constants/variants';
import styles from './styles.module.scss';
import signUpStyles from '../styles.module.scss';
+type IForm = {
+ email: string;
+ password: string;
+ password_check: string;
+ nick_name: string;
+ phone_num: string;
+ phone_check: string;
+ age: string;
+ join_paths: string[];
+ agent_code: string;
+ business_code: string;
+ company_name: string;
+ agent_name: string;
+ company_phone_num: string;
+ assistant_name: string | null;
+ company_address: string;
+ company_address_detail: string;
+ company_email: string;
+ estate: string;
+ service_term: boolean;
+};
+type ISubmitForm = {
+ email: string;
+ password: string;
+ nick_name: string;
+ phone_num: string;
+ age: string;
+ join_paths: string[];
+ agent_code: string;
+ business_code: string;
+ company_name: string;
+ agent_name: string;
+ company_phone_num: string;
+ assistant_name: string | null;
+ company_address: string;
+ company_address_detail: string;
+ company_email: string;
+ estate: string;
+};
+
export default function AgentSignUpPage() {
const { token } = userStore();
- const [isPostcodeOpen, setIsPostcodeOpen] = useState(false);
+ const navigate = useNavigate();
+
+ const [toggle, setToggle] = useState(false); // 약관 토글
+ const [isPostcodeOpen, setIsPostcodeOpen] = useState(false); // 주소 모달 토글
+ const [eyeState, setEyeState] = useState(false);
+ const [eyeCheckState, setEyeCheckState] = useState(false);
+ const [isCheckNum, setIsCheckNum] = useState(false); // 전화번호 인증 중 상태
+ const [phoneSMSCheck, setPhoneSMSCheck] = useState(false); // 전화번호 인증 완료 상태
+ const [phoneSMSMessage, setPhoneSMSMessage] = useState(); // 전화번호 인증 완료 상태
+ const [phoneErrMessage, setPhoneErrMessage] = useState(); // 전화번호 에러 메세지
+ const [isServiceTerm, setIsServiceTerm] = useState(false);
+ const [isPrivacyTerm, setIsPrivacyTerm] = useState(false);
+ const [isMarketingTerm, setIsMarketingTerm] = useState(false);
+ const [selectedTerm, setSelectedTerm] = useState('');
- const [companyAddress, setCompanyAddress] = useState('');
+ const {
+ register,
+ watch,
+ handleSubmit,
+ setValue,
+ formState: { errors },
+ } = useForm();
+
+ const { mutate: idCheckAPI } = useMutation((email: string) =>
+ restFetcher({
+ method: 'POST',
+ path: '/users/check/email',
+ body: { email },
+ }),
+ );
+ const { mutate: nicknameCheckAPI } = useMutation((nick_name: string) =>
+ restFetcher({
+ method: 'POST',
+ path: '/users/check/nick-name',
+ body: { nick_name },
+ }),
+ );
+ const { mutate: phoneSMSAPI } = useMutation((phone_num: string) =>
+ restFetcher({
+ method: 'POST',
+ path: '/users/send/sms',
+ body: { phone_num },
+ }),
+ );
+ const { mutate: phoneCheckAPI } = useMutation((phone_check: string) =>
+ restFetcher({
+ method: 'POST',
+ path: '/users/check/sms',
+ body: { phone_num: watch('phone_num'), code: phone_check },
+ }),
+ );
+ const { mutate: singUpAPI } = useMutation((form: ISubmitForm) =>
+ restFetcher({
+ method: 'POST',
+ path: '/users/sign-up',
+ body: form,
+ }),
+ );
+
+ const [
+ idCheck,
+ idCheckMessage,
+ idCheckHandler,
+ setIdCheck,
+ setIdCheckMessage,
+ ] = useCheckAPI(
+ idCheckAPI,
+ /^(?=.*[A-Za-z])[A-Za-z_0-9]{4,20}$/g,
+ watch('email'),
+ '사용가능한 ID입니다.',
+ '이미 존재하는 아이디 입니다.',
+ '4~20자리/영문, 숫자, 특수문자’_’만 사용해주세요.',
+ );
+ const [
+ nicknameCheck,
+ nicknameCheckMessage,
+ nicknameCheckHandler,
+ setNicknameCheck,
+ setNicknameCheckMessage,
+ ] = useCheckAPI(
+ nicknameCheckAPI,
+ /^(?=.*[a-zA-Z0-9가-힣])[A-Za-z0-9가-힣]{1,20}$/g,
+ watch('nick_name'),
+ '사용가능한 닉네임입니다.',
+ '이미 존재하는 닉네임 입니다.',
+ '닉네임 형식에 맞지 않습니다.',
+ );
+ const onToggleClick = (term: TermType) => {
+ const bodyEl = document.querySelector('body');
+ bodyEl?.classList.add('over_hidden');
+ setToggle(true);
+ setSelectedTerm(term);
+ };
+ const onEyeClick = (e: React.MouseEvent) => {
+ if (e.currentTarget.id === 'passwordEye') setEyeState((prev) => !prev);
+ else setEyeCheckState((prev) => !prev);
+ };
+ const onSendSMS = () => {
+ if (/^01(?:0|1|[6-9])[0-9]{7,8}$/g.test(watch('phone_num')) === false)
+ return;
+ phoneSMSAPI(watch('phone_num'), {
+ onSuccess: (res) => {
+ if (!res) throw Error;
+ setPhoneErrMessage(undefined);
+ setIsCheckNum(true);
+ },
+ onError: () => {
+ setPhoneErrMessage('이미 가입된 전화번호입니다.');
+ },
+ });
+ };
+ const onCheckSMS = () => {
+ if (/^(?=.*[0-9])[0-9]{4}$/g.test(watch('phone_check')) === false) {
+ setPhoneSMSCheck(false);
+ setPhoneSMSMessage('잘못된 인증번호입니다.');
+ }
+ phoneCheckAPI(watch('phone_check'), {
+ onSuccess: (res) => {
+ if (res.data === true) {
+ setPhoneSMSCheck(true);
+ setPhoneSMSMessage('인증에 성공하셨습니다.');
+ } else if (res.data === false) {
+ setPhoneSMSCheck(false);
+ setPhoneSMSMessage('인증번호가 일치하지 않습니다.');
+ }
+ },
+ });
+ };
+ const onChangeInput = (
+ setCheckState: React.Dispatch>,
+ setMessage: React.Dispatch>,
+ feild: string,
+ ) => {
+ setCheckState(false);
+ setMessage(`${feild} 중복검사를 해주세요`);
+ };
const postCodeCallback = (fullAddress: string) => {
- setCompanyAddress(fullAddress);
+ setValue('company_address', fullAddress);
+ };
+
+ const onSubmit = (data: IForm) => {
+ if (!idCheck) {
+ alert('아이디 중복검사를 해주세요.');
+ return;
+ }
+ if (!nicknameCheck) {
+ alert('닉네임 중복검사를 해주세요.');
+ return;
+ }
+ if (!phoneSMSCheck) {
+ alert('전화번호 인증을 해주세요.');
+ return;
+ }
+ const form: ISubmitForm = {
+ email: data.email,
+ password: data.password,
+ nick_name: data.nick_name,
+ phone_num: data.phone_num,
+ age: data.age,
+ join_paths: data.join_paths,
+ agent_code: data.agent_code,
+ business_code: data.business_code,
+ company_name: data.company_name,
+ agent_name: data.agent_name,
+ company_phone_num: data.company_phone_num,
+ assistant_name: data.assistant_name === '' ? null : data.assistant_name,
+ company_address: data.company_address,
+ company_address_detail: data.company_address_detail,
+ company_email: data.company_email,
+ estate: data.estate,
+ };
+ singUpAPI(form, {
+ onSuccess: () => {
+ alert('회원가입에 성공하였습니다.');
+ navigate('/login');
+ },
+ });
+ };
+
+ const handleAllSelect = (isSelected: boolean) => {
+ setIsServiceTerm(isSelected);
+ setIsPrivacyTerm(isSelected);
+ setIsMarketingTerm(isSelected);
};
+ useEffect(() => {
+ onChangeInput(setIdCheck, setIdCheckMessage, '아이디');
+ }, [watch('email')]);
+ useEffect(() => {
+ onChangeInput(setNicknameCheck, setNicknameCheckMessage, '닉네임');
+ }, [watch('nick_name')]);
+ useEffect(() => {
+ setPhoneSMSCheck(false);
+ setPhoneSMSMessage('전화번호 인증을 해주세요.');
+ }, [watch('phone_num')]);
+
if (token) {
return ;
}
@@ -70,20 +307,34 @@ export default function AgentSignUpPage() {
id="agent_code"
type="text"
placeholder="‘-’ 포함하여 작성 숫자 14자리"
+ {...register('agent_code', {
+ required: '필수 입력입니다.',
+ // TODO: 형식에 맞는 정규표현식 작성 후 패턴 등록하기
+ })}
/>
+
+ {errors.agent_code && errors.agent_code.message}
+
{/* 사업자 등록번호 */}
-
공인중개사 등록번호
+
사업자 등록번호
+
+ {errors.business_code && errors.business_code.message}
+
{/* 공인중개사 사무소 상호명 & 대표자 이름 */}
@@ -96,8 +347,14 @@ export default function AgentSignUpPage() {
id="company_name"
type="text"
placeholder="상호명"
+ {...register('company_name', {
+ required: '필수 입력입니다.',
+ })}
/>
+
+ {errors.company_name && errors.company_name.message}
+
{/* 대표자 이름 */}
@@ -108,8 +365,14 @@ export default function AgentSignUpPage() {
id="agent_name"
type="text"
placeholder="부동산 대표자명으로 작성"
+ {...register('agent_name', {
+ required: '필수 입력입니다.',
+ })}
/>
+
+ {errors.agent_name && errors.agent_name.message}
+
{/* 공인중개사 사무소 대표 전화번호 */}
@@ -123,11 +386,24 @@ export default function AgentSignUpPage() {
id="company_phone_num"
type="text"
placeholder="지역번호까지 입력 예) 02, 031"
+ {...register('company_phone_num', {
+ required: '비밀번호는 필수 입력입니다.',
+ pattern: {
+ value: /^\d{9,11}$/g,
+ message: `'-' 제외한 유효한 번호를 입력해주세요.`,
+ },
+ })}
/>
+
+ {errors.company_phone_num && errors.company_phone_num.message}
+
{/* 중개 보조원명 */}
-
+
@@ -147,8 +424,10 @@ export default function AgentSignUpPage() {
className={signUpStyles.inputStyle}
id="company_address"
type="text"
- value={companyAddress}
readOnly
+ {...register('company_address', {
+ required: '필수 입력입니다.',
+ })}
/>
+
+ {errors.company_address && errors.company_address.message}
+
{/* 상세 주소 */}
+
+ {errors.company_address_detail &&
+ errors.company_address_detail.message}
+
{/* 이메일 */}
-
이메일
+
이메일
-
- 중복확인
-
+
+ {errors.company_email && errors.company_email.message}
+
-
+
{/* 아이디 */}
아이디
@@ -194,11 +494,34 @@ export default function AgentSignUpPage() {
id="id"
type="text"
placeholder="4~20자리/영문, 숫자, 특수문자’_’사용가능"
+ {...register('email', {
+ required: '아이디는 필수 입력입니다.',
+ pattern: {
+ value: /^(?=.*[A-Za-z])[A-Za-z_0-9]{4,20}$/g,
+ message: '4~20자리/영문, 숫자, 특수문자’_’만 사용해주세요.',
+ },
+ })}
/>
-
+
중복확인
+
+ {errors.email && errors.email.message}
+ {!errors.email && idCheckMessage && idCheckMessage}
+
{/* 비밀번호 */}
@@ -207,22 +530,65 @@ export default function AgentSignUpPage() {
+ {watch('password') !== '' && (
+
+ )}
+
+ {errors.password && errors.password.message}
+
{/* 비밀번호 확인 */}
-
비밀번호 확인
+
비밀번호 확인
+
+ {errors.password_check && errors.password_check.message}
+
{/* 닉네임 */}
@@ -232,12 +598,39 @@ export default function AgentSignUpPage() {
className={signUpStyles.inputStyle}
id="nick_name"
type="text"
- placeholder="20자 이하의 조합 "
+ placeholder="20자 이하의 조합"
+ {...register('nick_name', {
+ required: '닉네임은 필수 입력입니다.',
+ pattern: {
+ value: /^(?=.*[a-zA-Z0-9가-힣])[A-Za-z0-9가-힣]{1,20}$/g,
+ message: '20자 이하의 조합만 사용해주세요.',
+ },
+ })}
/>
-
+
중복확인
+
+ {errors.nick_name && errors.nick_name.message}
+ {!errors.nick_name && nicknameCheckMessage && nicknameCheckMessage}
+
{/* 휴대폰 */}
@@ -248,97 +641,286 @@ export default function AgentSignUpPage() {
id="phone_num"
type="text"
placeholder="‘-’빼고 숫자만 입력"
+ {...register('phone_num', {
+ required: '전화번호를 입력해주세요.',
+ pattern: {
+ value: /^01(?:0|1|[6-9])[0-9]{7,8}$/g,
+ message: '‘-’빼고 숫자만 입력해주세요.',
+ },
+ })}
/>
-
- 중복확인
+
+ 인증요청
+
+ {errors.phone_num && errors.phone_num.message}
+ {!errors.phone_num && phoneErrMessage && phoneErrMessage}
+
+ {/* 인증번호 */}
+ {isCheckNum && (
+
+
인증번호
+
+
+
+ 확인
+
+
+
+ {errors.phone_check && errors.phone_check.message}
+ {!errors.phone_check && phoneSMSMessage && phoneSMSMessage}
+
+
+ )}
{/* 주거래 매물 */}
{/* 연령대 */}
{/* 가입경로 */}
{/* 약관 */}
@@ -346,51 +928,106 @@ export default function AgentSignUpPage() {
약관
-
+ {
+ handleAllSelect(
+ !(isServiceTerm && isPrivacyTerm && isMarketingTerm),
+ );
+ setValue('service_term', !isServiceTerm, {
+ shouldValidate: true,
+ });
+ }}
+ checked={isServiceTerm && isPrivacyTerm && isMarketingTerm}
+ />
전체동의
-
+ {
+ setIsServiceTerm((prev) => !prev);
+ },
+ })}
+ checked={isServiceTerm}
+ />
서비스 이용약관에 동의(필수)
-
+ onToggleClick('SERVICE')}
+ >
약관보기 >
+
+ {errors.service_term && errors.service_term.message}
+
+
-
+ setIsPrivacyTerm((prev) => !prev)}
+ />
개인정보 수집 및 이용 동의(선택)
-
+ onToggleClick('PRIVACY')}
+ >
약관보기 >
-
+ setIsMarketingTerm((prev) => !prev)}
+ />
마켓팅 활용 및 광고성 정보 수신 동의(선택)
-
+ onToggleClick('MARKETING')}
+ >
약관보기 >
-
+
회원가입
+ {toggle ? (
+
+ ) : null}
);
}
diff --git a/src/pages/SignUp/index.tsx b/src/pages/SignUp/index.tsx
index dfc9351..ec4eb62 100644
--- a/src/pages/SignUp/index.tsx
+++ b/src/pages/SignUp/index.tsx
@@ -349,7 +349,7 @@ export default function SignUpPage() {
className={styles.inputStyle}
id="nick_name"
type="text"
- placeholder="20자 이하의 조합 "
+ placeholder="20자 이하의 조합"
{...register('nick_name', {
required: '닉네임은 필수 입력입니다.',
pattern: {
From 7e0cffc1ae2df88f6db5cdaea4114942fdeaf025 Mon Sep 17 00:00:00 2001
From: sangminlee98
Date: Tue, 19 Sep 2023 15:58:40 +0900
Subject: [PATCH 04/11] =?UTF-8?q?chore:=20=EA=B5=AC=EA=B8=80=20=ED=83=9C?=
=?UTF-8?q?=EA=B7=B8=EB=A7=A4=EB=8B=88=EC=A0=80=20=EC=A0=81=EC=9A=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
package.json | 2 ++
src/App.tsx | 2 ++
src/hooks/useReactGTM.ts | 12 ++++++++++++
yarn.lock | 10 ++++++++++
4 files changed, 26 insertions(+)
create mode 100644 src/hooks/useReactGTM.ts
diff --git a/package.json b/package.json
index bdd3fb1..a4550ae 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
"@tanstack/react-query-devtools": "^4.24.6",
"@types/dompurify": "^3.0.1",
"@types/lodash": "^4.14.192",
+ "@types/react-gtm-module": "^2.0.1",
"@vitejs/plugin-react": "^3.1.0",
"aws-sdk": "^2.1363.0",
"axios": "^1.3.6",
@@ -34,6 +35,7 @@
"react-daum-postcode": "^3.1.3",
"react-dom": "^18.2.0",
"react-ga4": "^2.1.0",
+ "react-gtm-module": "^2.0.11",
"react-hook-form": "^7.43.5",
"react-icons": "^4.8.0",
"react-kakao-maps-sdk": "^1.1.9",
diff --git a/src/App.tsx b/src/App.tsx
index 6729348..8ab45e1 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -3,10 +3,12 @@ import { QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { routes } from '@/Routes';
import useReactGA from './hooks/useReactGA';
+import useReactGTM from './hooks/useReactGTM';
import { getClient } from './queryClient';
export default function App() {
useReactGA();
+ useReactGTM();
const queryClient = getClient();
const elem = useRoutes(routes);
diff --git a/src/hooks/useReactGTM.ts b/src/hooks/useReactGTM.ts
new file mode 100644
index 0000000..2531621
--- /dev/null
+++ b/src/hooks/useReactGTM.ts
@@ -0,0 +1,12 @@
+import { useEffect } from 'react';
+import TagManager from 'react-gtm-module';
+
+const GTM_ID = import.meta.env.VITE_GTM_ID;
+
+const GoogleTagManager = () => {
+ useEffect(() => {
+ TagManager.initialize({ gtmId: GTM_ID });
+ }, [GTM_ID]);
+};
+
+export default GoogleTagManager;
diff --git a/yarn.lock b/yarn.lock
index 2a5d634..d4310dc 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -589,6 +589,11 @@
dependencies:
"@types/react" "*"
+"@types/react-gtm-module@^2.0.1":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@types/react-gtm-module/-/react-gtm-module-2.0.1.tgz#b2c6cd14ec251d6ae7fa576edf1d43825908a378"
+ integrity sha512-T/DN9gAbCYk5wJ1nxf4pSwmXz4d1iVjM++OoG+mwMfz9STMAotGjSb65gJHOS5bPvl6vLSsJnuC+y/43OQrltg==
+
"@types/react@*", "@types/react@^18.0.27":
version "18.0.38"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.38.tgz#02a23bef8848b360a0d1dceef4432c15c21c600c"
@@ -3055,6 +3060,11 @@ react-ga4@^2.1.0:
resolved "https://registry.yarnpkg.com/react-ga4/-/react-ga4-2.1.0.tgz#56601f59d95c08466ebd6edfbf8dede55c4678f9"
integrity sha512-ZKS7PGNFqqMd3PJ6+C2Jtz/o1iU9ggiy8Y8nUeksgVuvNISbmrQtJiZNvC/TjDsqD0QlU5Wkgs7i+w9+OjHhhQ==
+react-gtm-module@^2.0.11:
+ version "2.0.11"
+ resolved "https://registry.yarnpkg.com/react-gtm-module/-/react-gtm-module-2.0.11.tgz#14484dac8257acd93614e347c32da9c5ac524206"
+ integrity sha512-8gyj4TTxeP7eEyc2QKawEuQoAZdjKvMY4pgWfycGmqGByhs17fR+zEBs0JUDq4US/l+vbTl+6zvUIx27iDo/Vw==
+
react-hook-form@^7.43.5:
version "7.43.9"
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.43.9.tgz#84b56ac2f38f8e946c6032ccb760e13a1037c66d"
From 5448c0468f79af196677222760f19c7023a55d8d Mon Sep 17 00:00:00 2001
From: sangminlee98
Date: Wed, 20 Sep 2023 23:16:10 +0900
Subject: [PATCH 05/11] =?UTF-8?q?fix:=20=EC=A3=BC=EA=B1=B0=EB=9E=98=20?=
=?UTF-8?q?=EB=A7=A4=EB=AC=BC=EA=B3=BC=20=EC=97=B0=EB=A0=B9=EB=8C=80=20?=
=?UTF-8?q?=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC=20=EC=97=90?=
=?UTF-8?q?=EB=9F=AC=20=EC=83=81=ED=83=9C=20=EB=A9=94=EC=84=B8=EC=A7=80=20?=
=?UTF-8?q?=EA=B3=B5=EC=9C=A0=ED=95=98=EB=8A=94=20=EB=B2=84=EA=B7=B8=20?=
=?UTF-8?q?=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/pages/SignUp/AgentSignUp/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pages/SignUp/AgentSignUp/index.tsx b/src/pages/SignUp/AgentSignUp/index.tsx
index 77434b0..50ab78f 100644
--- a/src/pages/SignUp/AgentSignUp/index.tsx
+++ b/src/pages/SignUp/AgentSignUp/index.tsx
@@ -747,7 +747,7 @@ export default function AgentSignUpPage() {
- {errors.age && errors.age.message}
+ {errors.estate && errors.estate.message}
{/* 연령대 */}
From 1ad7be1a199f3b1f463d282d7d3896649cfe0875 Mon Sep 17 00:00:00 2001
From: sangminlee98
Date: Wed, 20 Sep 2023 23:16:10 +0900
Subject: [PATCH 06/11] =?UTF-8?q?fix:=20=EC=A3=BC=EA=B1=B0=EB=9E=98=20?=
=?UTF-8?q?=EB=A7=A4=EB=AC=BC=EA=B3=BC=20=EC=97=B0=EB=A0=B9=EB=8C=80=20?=
=?UTF-8?q?=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC=20=EC=97=90?=
=?UTF-8?q?=EB=9F=AC=20=EC=83=81=ED=83=9C=20=EB=A9=94=EC=84=B8=EC=A7=80=20?=
=?UTF-8?q?=EA=B3=B5=EC=9C=A0=ED=95=98=EB=8A=94=20=EB=B2=84=EA=B7=B8=20?=
=?UTF-8?q?=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/pages/SignUp/AgentSignUp/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pages/SignUp/AgentSignUp/index.tsx b/src/pages/SignUp/AgentSignUp/index.tsx
index 77434b0..50ab78f 100644
--- a/src/pages/SignUp/AgentSignUp/index.tsx
+++ b/src/pages/SignUp/AgentSignUp/index.tsx
@@ -747,7 +747,7 @@ export default function AgentSignUpPage() {
- {errors.age && errors.age.message}
+ {errors.estate && errors.estate.message}
{/* 연령대 */}
From 0d465b4925aa7606f555e494b929c84e533b35e5 Mon Sep 17 00:00:00 2001
From: sangminlee98
Date: Tue, 26 Sep 2023 01:42:35 +0900
Subject: [PATCH 07/11] =?UTF-8?q?feat:=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20?=
=?UTF-8?q?=EC=9D=B8=EC=A6=9D=20API=20=EC=97=B0=EB=8F=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/apis/login.ts | 2 +-
src/pages/Login/index.tsx | 2 +-
src/pages/SignUp/AgentSignUp/index.tsx | 257 +++++++++++++++++++++++--
src/pages/SignUp/index.tsx | 250 ++++++++++++++++++++----
src/types/signUp.ts | 2 +-
src/types/user.d.ts | 2 +
6 files changed, 459 insertions(+), 56 deletions(-)
diff --git a/src/apis/login.ts b/src/apis/login.ts
index 67caba5..a0dfce4 100644
--- a/src/apis/login.ts
+++ b/src/apis/login.ts
@@ -5,7 +5,7 @@ import {
} from '@/types/apiResponseType';
export type LoginForm = {
- email: string;
+ userName: string;
password: string;
};
diff --git a/src/pages/Login/index.tsx b/src/pages/Login/index.tsx
index a51c844..c286c8f 100644
--- a/src/pages/Login/index.tsx
+++ b/src/pages/Login/index.tsx
@@ -19,7 +19,7 @@ export default function LoginPage() {
};
const handleLogin = async () => {
const form: LoginForm = {
- email: id,
+ userName: id,
password,
};
const response = await LoginAPI(form);
diff --git a/src/pages/SignUp/AgentSignUp/index.tsx b/src/pages/SignUp/AgentSignUp/index.tsx
index 50ab78f..7ef383e 100644
--- a/src/pages/SignUp/AgentSignUp/index.tsx
+++ b/src/pages/SignUp/AgentSignUp/index.tsx
@@ -16,8 +16,14 @@ import { opacityVariants } from '@/constants/variants';
import styles from './styles.module.scss';
import signUpStyles from '../styles.module.scss';
+type AgentSignUpTerm =
+ | 'SERVICE_USED_AGREE'
+ | 'PERSONAL_INFO_NOTI'
+ | 'PERSONAL_INFO_USED_AGREE'
+ | 'MARKETING_ADVERTISEMENT_AGREE';
+
type IForm = {
- email: string;
+ userName: string;
password: string;
password_check: string;
nick_name: string;
@@ -34,11 +40,13 @@ type IForm = {
company_address: string;
company_address_detail: string;
company_email: string;
+ email_code: string;
estate: string;
service_term: boolean;
+ agent_term: boolean;
};
type ISubmitForm = {
- email: string;
+ userName: string;
password: string;
nick_name: string;
phone_num: string;
@@ -54,6 +62,7 @@ type ISubmitForm = {
company_address_detail: string;
company_email: string;
estate: string;
+ terms: AgentSignUpTerm[];
};
export default function AgentSignUpPage() {
@@ -68,7 +77,12 @@ export default function AgentSignUpPage() {
const [phoneSMSCheck, setPhoneSMSCheck] = useState(false); // 전화번호 인증 완료 상태
const [phoneSMSMessage, setPhoneSMSMessage] = useState(); // 전화번호 인증 완료 상태
const [phoneErrMessage, setPhoneErrMessage] = useState(); // 전화번호 에러 메세지
+ const [isCheckEmail, setIsCheckEmail] = useState(false); // 이메일 인증 중 상태
+ const [emailCheck, setEmailCheck] = useState(false); // 이메일 인증 완료 상태
+ const [emailMessage, setEmailMessage] = useState(); // 이메일 인증 상태 메세지
+ const [emailErrMessage, setEmailErrMessage] = useState(); // 이메일 에러 메세지
const [isServiceTerm, setIsServiceTerm] = useState(false);
+ const [isAgentPrivacyTerm, setIsAgentPrivacyTerm] = useState(false);
const [isPrivacyTerm, setIsPrivacyTerm] = useState(false);
const [isMarketingTerm, setIsMarketingTerm] = useState(false);
const [selectedTerm, setSelectedTerm] = useState('');
@@ -79,13 +93,38 @@ export default function AgentSignUpPage() {
handleSubmit,
setValue,
formState: { errors },
- } = useForm();
+ } = useForm({
+ mode: 'onSubmit',
+ defaultValues: {
+ userName: '',
+ password: '',
+ password_check: '',
+ nick_name: '',
+ phone_num: '',
+ phone_check: '',
+ age: '',
+ join_paths: [],
+ agent_code: '',
+ business_code: '',
+ company_name: '',
+ agent_name: '',
+ company_phone_num: '',
+ assistant_name: '',
+ company_address: '',
+ company_address_detail: '',
+ company_email: '',
+ email_code: '',
+ estate: '',
+ service_term: false,
+ agent_term: false,
+ },
+ });
- const { mutate: idCheckAPI } = useMutation((email: string) =>
+ const { mutate: idCheckAPI } = useMutation((userName: string) =>
restFetcher({
method: 'POST',
- path: '/users/check/email',
- body: { email },
+ path: '/users/check/user-name',
+ body: { userName },
}),
);
const { mutate: nicknameCheckAPI } = useMutation((nick_name: string) =>
@@ -109,6 +148,21 @@ export default function AgentSignUpPage() {
body: { phone_num: watch('phone_num'), code: phone_check },
}),
);
+ const { mutate: emailSendAPI } = useMutation((email: string) =>
+ restFetcher({
+ method: 'POST',
+ path: '/users/send/email',
+ body: { email },
+ }),
+ );
+ const { mutate: emailCheckAPI } = useMutation(
+ (body: { email: string; code: string }) =>
+ restFetcher({
+ method: 'POST',
+ path: '/users/check/email',
+ body,
+ }),
+ );
const { mutate: singUpAPI } = useMutation((form: ISubmitForm) =>
restFetcher({
method: 'POST',
@@ -126,7 +180,7 @@ export default function AgentSignUpPage() {
] = useCheckAPI(
idCheckAPI,
/^(?=.*[A-Za-z])[A-Za-z_0-9]{4,20}$/g,
- watch('email'),
+ watch('userName'),
'사용가능한 ID입니다.',
'이미 존재하는 아이디 입니다.',
'4~20자리/영문, 숫자, 특수문자’_’만 사용해주세요.',
@@ -186,6 +240,48 @@ export default function AgentSignUpPage() {
},
});
};
+ const onSendEmail = () => {
+ if (
+ /^([\w\.\_\-])*[a-zA-Z0-9]+([\w\.\_\-])*([a-zA-Z0-9])+([\w\.\_\-])+@([a-zA-Z0-9]+\.)+[a-zA-Z0-9]{2,8}$/g.test(
+ watch('company_email'),
+ ) === false
+ )
+ return;
+ emailSendAPI(watch('company_email'), {
+ onSuccess: (res) => {
+ if (!res) throw Error;
+ setEmailErrMessage(undefined);
+ setIsCheckEmail(true);
+ },
+ onError: () => {
+ setEmailErrMessage('이미 가입된 이메일입니다.');
+ },
+ });
+ };
+ const onCheckEmail = () => {
+ if (
+ /^([\w\.\_\-])*[a-zA-Z0-9]+([\w\.\_\-])*([a-zA-Z0-9])+([\w\.\_\-])+@([a-zA-Z0-9]+\.)+[a-zA-Z0-9]{2,8}$/g.test(
+ watch('email_code'),
+ ) === false
+ ) {
+ setEmailCheck(false);
+ setEmailMessage('잘못된 인증코드입니다.');
+ }
+ emailCheckAPI(
+ { email: watch('company_email'), code: watch('email_code') },
+ {
+ onSuccess: (res) => {
+ if (res.data === true) {
+ setEmailCheck(true);
+ setEmailMessage('인증에 성공하셨습니다.');
+ } else if (res.data === false) {
+ setEmailCheck(false);
+ setEmailMessage('인증코드가 일치하지 않습니다.');
+ }
+ },
+ },
+ );
+ };
const onChangeInput = (
setCheckState: React.Dispatch>,
setMessage: React.Dispatch>,
@@ -199,6 +295,15 @@ export default function AgentSignUpPage() {
setValue('company_address', fullAddress);
};
+ const getTerms = () => {
+ const termsArr: AgentSignUpTerm[] = [];
+ if (isServiceTerm) termsArr.push('SERVICE_USED_AGREE');
+ if (isAgentPrivacyTerm) termsArr.push('PERSONAL_INFO_NOTI');
+ if (isPrivacyTerm) termsArr.push('PERSONAL_INFO_USED_AGREE');
+ if (isMarketingTerm) termsArr.push('MARKETING_ADVERTISEMENT_AGREE');
+ return termsArr;
+ };
+
const onSubmit = (data: IForm) => {
if (!idCheck) {
alert('아이디 중복검사를 해주세요.');
@@ -212,8 +317,12 @@ export default function AgentSignUpPage() {
alert('전화번호 인증을 해주세요.');
return;
}
+ if (!emailCheck) {
+ alert('이메일 인증을 해주세요.');
+ return;
+ }
const form: ISubmitForm = {
- email: data.email,
+ userName: data.userName,
password: data.password,
nick_name: data.nick_name,
phone_num: data.phone_num,
@@ -229,6 +338,7 @@ export default function AgentSignUpPage() {
company_address_detail: data.company_address_detail,
company_email: data.company_email,
estate: data.estate,
+ terms: getTerms(),
};
singUpAPI(form, {
onSuccess: () => {
@@ -240,13 +350,14 @@ export default function AgentSignUpPage() {
const handleAllSelect = (isSelected: boolean) => {
setIsServiceTerm(isSelected);
+ setIsAgentPrivacyTerm(isSelected);
setIsPrivacyTerm(isSelected);
setIsMarketingTerm(isSelected);
};
useEffect(() => {
onChangeInput(setIdCheck, setIdCheckMessage, '아이디');
- }, [watch('email')]);
+ }, [watch('userName')]);
useEffect(() => {
onChangeInput(setNicknameCheck, setNicknameCheckMessage, '닉네임');
}, [watch('nick_name')]);
@@ -254,6 +365,10 @@ export default function AgentSignUpPage() {
setPhoneSMSCheck(false);
setPhoneSMSMessage('전화번호 인증을 해주세요.');
}, [watch('phone_num')]);
+ useEffect(() => {
+ setEmailCheck(false);
+ setEmailMessage('이메일 인증을 해주세요.');
+ }, [watch('company_email')]);
if (token) {
return ;
@@ -306,10 +421,13 @@ export default function AgentSignUpPage() {
className={signUpStyles.inputStyle}
id="agent_code"
type="text"
- placeholder="‘-’ 포함하여 작성 숫자 14자리"
+ placeholder="‘-’빼고 10자리 숫자 입력"
{...register('agent_code', {
required: '필수 입력입니다.',
- // TODO: 형식에 맞는 정규표현식 작성 후 패턴 등록하기
+ pattern: {
+ value: /^\d{10}$/g,
+ message: '‘-’빼고 10자리 숫자를 입력해주세요',
+ },
})}
/>
@@ -325,10 +443,13 @@ export default function AgentSignUpPage() {
className={signUpStyles.inputStyle}
id="business_code"
type="text"
- placeholder="‘-’ 포함하여 작성 숫자 10자리"
+ placeholder="‘-’빼고 14자리 숫자 입력"
{...register('business_code', {
required: '필수 입력입니다.',
- // TODO: 형식에 맞는 정규표현식 작성 후 패턴 등록하기
+ pattern: {
+ value: /^\d{14}$/g,
+ message: '‘-’빼고 14자리 숫자를 입력해주세요',
+ },
})}
/>
@@ -476,11 +597,67 @@ export default function AgentSignUpPage() {
},
})}
/>
+
+ 인증요청
+
{errors.company_email && errors.company_email.message}
+ {!errors.company_email && emailErrMessage && emailErrMessage}
+ {isCheckEmail && (
+
+
인증코드
+
+
+
+ 확인
+
+
+
+ {errors.email_code && errors.email_code.message}
+ {!errors.email_code && emailMessage && emailMessage}
+
+
+ )}
+
- {errors.email && errors.email.message}
- {!errors.email && idCheckMessage && idCheckMessage}
+ {errors.userName && errors.userName.message}
+ {!errors.userName && idCheckMessage && idCheckMessage}
{/* 비밀번호 */}
@@ -933,13 +1110,26 @@ export default function AgentSignUpPage() {
type="checkbox"
onChange={() => {
handleAllSelect(
- !(isServiceTerm && isPrivacyTerm && isMarketingTerm),
+ !(
+ isServiceTerm &&
+ isAgentPrivacyTerm &&
+ isPrivacyTerm &&
+ isMarketingTerm
+ ),
);
setValue('service_term', !isServiceTerm, {
shouldValidate: true,
});
+ setValue('agent_term', !isAgentPrivacyTerm, {
+ shouldValidate: true,
+ });
}}
- checked={isServiceTerm && isPrivacyTerm && isMarketingTerm}
+ checked={
+ isServiceTerm &&
+ isAgentPrivacyTerm &&
+ isPrivacyTerm &&
+ isMarketingTerm
+ }
/>
전체동의
@@ -971,6 +1161,35 @@ export default function AgentSignUpPage() {
{errors.service_term && errors.service_term.message}
+
+
+ {
+ setIsAgentPrivacyTerm((prev) => !prev);
+ },
+ })}
+ checked={isAgentPrivacyTerm}
+ />
+
+ 공인중개사 식별 개인정보 수집 이용 동의(필수)
+
+
+ onToggleClick('AGENT')}
+ >
+ 약관보기 >
+
+
+
+ {errors.agent_term && errors.agent_term.message}
+
+
(); // 전화번호 인증 상태 메세지
+ const [phoneErrMessage, setPhoneErrMessage] = useState
(); // 전화번호 에러 메세지
+ const [isCheckEmail, setIsCheckEmail] = useState(false); // 이메일 인증 중 상태
+ const [emailCheck, setEmailCheck] = useState(false); // 이메일 인증 완료 상태
+ const [emailMessage, setEmailMessage] = useState(); // 이메일 인증 상태 메세지
+ const [emailErrMessage, setEmailErrMessage] = useState(); // 이메일 에러 메세지
+ const [isServiceTerm, setIsServiceTerm] = useState(false);
+ const [isPrivacyTerm, setIsPrivacyTerm] = useState(false);
+ const [isMarketingTerm, setIsMarketingTerm] = useState(false);
+ const [selectedTerm, setSelectedTerm] = useState('');
+
const {
register,
watch,
@@ -44,18 +72,24 @@ export default function SignUpPage() {
} = useForm({
mode: 'onSubmit',
defaultValues: {
+ userName: '',
email: '',
+ email_code: '',
password: '',
- passwordCheck: '',
+ password_check: '',
nick_name: '',
phone_num: '',
+ phone_check: '',
+ age: '',
+ join_paths: [],
+ service_term: false,
},
});
- const { mutate: idCheckAPI } = useMutation((email: string) =>
+ const { mutate: idCheckAPI } = useMutation((userName: string) =>
restFetcher({
method: 'POST',
- path: '/users/check/email',
- body: { email },
+ path: '/users/check/user-name',
+ body: { userName },
}),
);
const { mutate: nicknameCheckAPI } = useMutation((nick_name: string) =>
@@ -79,6 +113,21 @@ export default function SignUpPage() {
body: { phone_num: watch('phone_num'), code: phone_check },
}),
);
+ const { mutate: emailSendAPI } = useMutation((email: string) =>
+ restFetcher({
+ method: 'POST',
+ path: '/users/send/email',
+ body: { email },
+ }),
+ );
+ const { mutate: emailCheckAPI } = useMutation(
+ (body: { email: string; code: string }) =>
+ restFetcher({
+ method: 'POST',
+ path: '/users/check/email',
+ body,
+ }),
+ );
const { mutate: singUpAPI } = useMutation((form: ISubmitForm) =>
restFetcher({
method: 'POST',
@@ -86,19 +135,6 @@ export default function SignUpPage() {
body: form,
}),
);
- const navigate = useNavigate();
- const { token } = userStore();
- const [toggle, setToggle] = useState(false); // 약관 토글
- const [eyeState, setEyeState] = useState(false);
- const [eyeCheckState, setEyeCheckState] = useState(false);
- const [isCheckNum, setIsCheckNum] = useState(false); // 전화번호 인증 중 상태
- const [phoneSMSCheck, setPhoneSMSCheck] = useState(false); // 전화번호 인증 완료 상태
- const [phoneSMSMessage, setPhoneSMSMessage] = useState(); // 전화번호 인증 완료 상태
- const [phoneErrMessage, setPhoneErrMessage] = useState(); // 전화번호 에러 메세지
- const [isServiceTerm, setIsServiceTerm] = useState(false);
- const [isPrivacyTerm, setIsPrivacyTerm] = useState(false);
- const [isMarketingTerm, setIsMarketingTerm] = useState(false);
- const [selectedTerm, setSelectedTerm] = useState('');
const [
idCheck,
@@ -109,7 +145,7 @@ export default function SignUpPage() {
] = useCheckAPI(
idCheckAPI,
/^(?=.*[A-Za-z])[A-Za-z_0-9]{4,20}$/g,
- watch('email'),
+ watch('userName'),
'사용가능한 ID입니다.',
'이미 존재하는 아이디 입니다.',
'4~20자리/영문, 숫자, 특수문자’_’만 사용해주세요.',
@@ -169,6 +205,48 @@ export default function SignUpPage() {
},
});
};
+ const onSendEmail = () => {
+ if (
+ /^([\w\.\_\-])*[a-zA-Z0-9]+([\w\.\_\-])*([a-zA-Z0-9])+([\w\.\_\-])+@([a-zA-Z0-9]+\.)+[a-zA-Z0-9]{2,8}$/g.test(
+ watch('email'),
+ ) === false
+ )
+ return;
+ emailSendAPI(watch('email'), {
+ onSuccess: (res) => {
+ if (!res) throw Error;
+ setEmailErrMessage(undefined);
+ setIsCheckEmail(true);
+ },
+ onError: () => {
+ setEmailErrMessage('이미 가입된 이메일입니다.');
+ },
+ });
+ };
+ const onCheckEmail = () => {
+ if (
+ /^([\w\.\_\-])*[a-zA-Z0-9]+([\w\.\_\-])*([a-zA-Z0-9])+([\w\.\_\-])+@([a-zA-Z0-9]+\.)+[a-zA-Z0-9]{2,8}$/g.test(
+ watch('email_code'),
+ ) === false
+ ) {
+ setEmailCheck(false);
+ setEmailMessage('잘못된 인증코드입니다.');
+ }
+ emailCheckAPI(
+ { email: watch('email'), code: watch('email_code') },
+ {
+ onSuccess: (res) => {
+ if (res.data === true) {
+ setEmailCheck(true);
+ setEmailMessage('인증에 성공하셨습니다.');
+ } else if (res.data === false) {
+ setEmailCheck(false);
+ setEmailMessage('인증코드가 일치하지 않습니다.');
+ }
+ },
+ },
+ );
+ };
const onChangeInput = (
setCheckState: React.Dispatch>,
setMessage: React.Dispatch>,
@@ -177,6 +255,13 @@ export default function SignUpPage() {
setCheckState(false);
setMessage(`${feild} 중복검사를 해주세요`);
};
+ const getTerms = () => {
+ const termsArr: SignUpTerm[] = [];
+ if (isServiceTerm) termsArr.push('SERVICE_USED_AGREE');
+ if (isPrivacyTerm) termsArr.push('PERSONAL_INFO_USED_AGREE');
+ if (isMarketingTerm) termsArr.push('MARKETING_ADVERTISEMENT_AGREE');
+ return termsArr;
+ };
const onSubmit = (data: IForm) => {
if (!idCheck) {
alert('아이디 중복검사를 해주세요.');
@@ -190,14 +275,20 @@ export default function SignUpPage() {
alert('전화번호 인증을 해주세요.');
return;
}
+ if (!emailCheck) {
+ alert('이메일 인증을 해주세요.');
+ return;
+ }
singUpAPI(
{
+ userName: data.userName,
email: data.email,
password: data.password,
nick_name: data.nick_name,
phone_num: data.phone_num,
age: data.age,
join_paths: data.join_paths,
+ terms: getTerms(),
},
{
onSuccess: () => {
@@ -207,15 +298,15 @@ export default function SignUpPage() {
},
);
};
-
const handleAllSelect = (isSelected: boolean) => {
setIsServiceTerm(isSelected);
setIsPrivacyTerm(isSelected);
setIsMarketingTerm(isSelected);
};
+
useEffect(() => {
onChangeInput(setIdCheck, setIdCheckMessage, '아이디');
- }, [watch('email')]);
+ }, [watch('userName')]);
useEffect(() => {
onChangeInput(setNicknameCheck, setNicknameCheckMessage, '닉네임');
}, [watch('nick_name')]);
@@ -223,6 +314,10 @@ export default function SignUpPage() {
setPhoneSMSCheck(false);
setPhoneSMSMessage('전화번호 인증을 해주세요.');
}, [watch('phone_num')]);
+ useEffect(() => {
+ setEmailCheck(false);
+ setEmailMessage('이메일 인증을 해주세요.');
+ }, [watch('email')]);
if (token) {
return ;
@@ -248,15 +343,16 @@ export default function SignUpPage() {