diff --git a/src/app/(non-member)/layout.tsx b/src/app/(non-member)/find-password/layout.tsx similarity index 100% rename from src/app/(non-member)/layout.tsx rename to src/app/(non-member)/find-password/layout.tsx diff --git a/src/app/(non-member)/signin/layout.tsx b/src/app/(non-member)/signin/layout.tsx new file mode 100644 index 0000000..42dff67 --- /dev/null +++ b/src/app/(non-member)/signin/layout.tsx @@ -0,0 +1,12 @@ +import { ReactNode } from 'react'; + +import Header from '@/components/layout/Header'; + +export default function Layout({ children }: { children: ReactNode }) { + return ( + <> +
+ { children } + + ); +} diff --git a/src/app/(non-member)/signup/layout.tsx b/src/app/(non-member)/signup/layout.tsx new file mode 100644 index 0000000..42dff67 --- /dev/null +++ b/src/app/(non-member)/signup/layout.tsx @@ -0,0 +1,12 @@ +import { ReactNode } from 'react'; + +import Header from '@/components/layout/Header'; + +export default function Layout({ children }: { children: ReactNode }) { + return ( + <> +
+ { children } + + ); +} diff --git a/src/app/(non-member)/tos/privacy/page.tsx b/src/app/(non-member)/tos/privacy/page.tsx new file mode 100644 index 0000000..c8230a2 --- /dev/null +++ b/src/app/(non-member)/tos/privacy/page.tsx @@ -0,0 +1,482 @@ +'use client'; + +import { styled } from 'styled-components'; + +import Header from '@/components/common/Header'; + +export default function TosUsePage() { + return ( + <> +
+ + + POPO 2024년 2월 1일 + + + (주)4심(이하 회사)는 「개인정보 보호법」 제30조에 따라 이용자의 개인정보를 보호하고 + 이와 관련한 고충을 신속하고 원활하게 처리할 수 있도록 하기 위하여 다음과 같이 개인정보 처리방침을 수립 및 공개합니다. + + + 제1조 (개인정보의 처리목적) + + 회사는 다음의 목적을 위하여 개인정보를 처리하며, 처리하고 있는 개인정보는 다음의 목적 이외의 용도로는 이용되지 않습니다. + 이용 목적이 변경되는 경우에는 「개인정보 보호법」 제18조에 따라 별도의 동의를 받는 등 필요한 조치를 이행할 예정입니다. + + + 1. 회원 가입 및 로그인, 관리 + 회원 가입의사 확인과 회원제 서비스 제공에 따른 회원자격 유지 및 관리, 서비스 부정이용 방지, 각종 고지와 통지를 목적으로 개인정보를 처리합니다. + + + 2. 재화 또는 서비스 제공 + 본인 인증, 결제, 서비스 및 콘텐츠, 광고를 포함한 맞춤형 서비스 제공을 목적으로 개인정보를 처리합니다. + + + 3. 고충처리 + 이용자의 신원 확인, 문의사항 확인, 사실조사를 위한 연락, 통지, 처리결과 통보의 목적으로 개인정보를 처리합니다. + + + 4. 제휴 및 제안 + 제휴 및 제안 시 이용자 또는 사업자가 작성한 내용을 검토하고, 필요 시 연락을 위한 목적으로 개인정보를 처리합니다. + + + + + 제2조 (개인정보의 처리 및 보유기간) + + + ① 회사는 법령에 명시되어 있거나 이용자로부터 개인정보 수집 시 동의 받은 개인정보의 보유 및 이용기간 내에서 개인정보를 처리 및 보유합니다. + + + • 회원 가입 및 로그인, 관리 : 회원 탈퇴 시 + 단, 다음의 사유에 해당하는 경우에는 해당 사유 종료 시까지 + + + • 관계 법령 위반에 따른 수사, 조사 등이 진행 중인 경우에는 해당 수사, 조사 종료 시까지 + + + • 서비스 이용에 따른 채권, 채무관계 잔존 시에는 해당 채권, 채무관계 정산 시까지 + + + • 회원 탈퇴 후 복구 요청 기간 종료 시까지 (회원 탈퇴일로부터 5일) + + + • 재화 또는 서비스 제공 : 재화, 서비스 공급 완료 또는 서비스 이용 종료 시까지 + + + • 친구 초대 : ‘친구 초대’ 기능의 서비스 종료 또는 회원탈퇴 시까지 + + + • 고충처리 : 고충 처리 완료 시까지 + + + • 제휴 제안 : 제휴 및 제안 검토 완료 후 6개월 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
관련법령수집정보보유기간
통신비밀보호법서비스 이용 관련 정보(접속로그)3개월
전자상거래 등에서의 소비자 보호에 관한 법률소비자의 불만 또는 분쟁처리에 관한 기록3년
전자상거래 등에서의 소비자 보호에 관한 법률계약 또는 청약철회 등에 관한 기록5년
전자상거래 등에서의 소비자 보호에 관한 법률대금결제 및 재화 등의 공급에 관한 기록5년
+
+ + + + 제3조 (개인정보의 제3자 제공) + + + ① 회사는 이용자의 개인정보를 제1조(개인정보의 처리 목적)에서 명시한 범위 내에서만 처리하며, + 정보주체의 동의, 법률의 특별한 규정 등 「개인정보 보호법」 제17 조 및 제18조에 해당하는 경우에만 개인정보를 제3자에게 제공합니다. + + + ② 회사는 제3자에게 개인정보를 제공하지 않으며, 제공하게 될 경우 이용자에게 동의를 받겠습니다. + + + + + 제4조 (개인정보처리의 위탁) + + + ① 회사는 원활한 개인정보 업무처리를 위하여 다음과 같이 개인정보 처리업무를 위탁하고 있습니다. + + + - 위탁받는 자 (수탁자) : 네이버클라우드 주식회사, Google Firebase + + + - 위탁하는 업무의 내용 : 모바일 알림서비스, 앱 딥링크, 앱 푸시 발송 + + + - 위탁기간 : 3년 + + + ② 회사는 위탁계약 체결 시 「개인정보 보호법」 제26조에 따라 위탁업무 수행 목적 외 + 개인정보 처리 금지, 기술적 · 관리적 보호 조치, 재위탁 제한, 수탁자에 대한 관리·감독, 손해배상 등 + 책임에 관한 사항을 계약서 등 문서에 명시하고, 수탁자가 개인정보를 안전하게 처리하는지를 감독하고 있습니다. + + + ③ 위탁업무의 내용이나 수탁자가 변경될 경우에는 지체 없이 본 개인정보 처리방침을 통하여 공개하도록 하겠습니다. + + + + + 제5조 (이용자와 법정대리인의 권리·의무 및 행사방법) + + + ① 이용자는 회사에 대해 언제든지 개인정보 열람, 정정, 삭제, 처리 정지 요구 등의 권리를 행사할 수 있습니다. + + + ② 개인정보 열람 및 처리 정지 요구는 개인정보보호법 제35조 제4항, 제37조 제2항에 의하여 이용자의 권리가 제한될 수 있습니다. + + + ③ 제1항에 따른 권리 행사는 회사에 대해 개인정보 보호법 시행령 제41조 제1항에 따라 + 서면, 전자우편, 모사전송(FAX) 등을 통하여 하실 수 있으며 회사는 이에 대해 지체 없이 조치하겠습니다. + + + ④ 개인정보의 정정 및 삭제 요구는 다른 법령에서 그 개인정보가 수집 대상으로 명시되어 있는 경우에는 그 삭제를 요구할 수 없습니다. + + + ⑤ 회사는 이용자 권리에 따른 열람의 요구, 정정·삭제의 요구, + 처리 정지의 요구 시 열람 등 요구를 한 자가 본인이거나 정당한 대리인인지를 확인할 수 있습니다. + + + ⑥ 제5항에 따른 권리행사 주체가 대리인(이용자의 위임을 받은 자)인 경우 “개인정보 처리 방법에 관한 고시(제2020-7호)” + 별지 제11호 서식에 따른 위임장을 제출하셔야 합니다. + + + + + 제6조 (처리하는 개인정보 항목) + + + ① 회사는 다음의 개인정보 항목을 처리하고 있습니다. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
구분수집·이용목적필수/선택수집 및 이용항목
회원가입본인인증, 로그인필수이메일
회원가입 및 추천학교/친구 추천, 투표 성별 표시필수재학중인 학교 정보, 학년, 반, 이름, 성별
회원가입프로필 사진 등록선택프로필 사진
친구 초대친구 초대, 초대하는 친구의 서비스 가입 여부 확인선택암호화된 연락처
문의하기이용자 문의 및 고충 처리선택이메일 (공통)
문의하기이용자 문의 및 고충 처리: 결제, 환불 관련필수POPO 닉네임, 이름, 연락처(메일주소, 전화번호)
+ + ② 서비스 이용과정에서 아래 개인정보 항목이 자동으로 생성되어 수집될 수 있습니다. + IP주소, 쿠키, 서비스 이용기록 + + + ③ 서비스 이용과정에서 개인정보는 아니지만 아래의 정보가 생성되어 수집될 수 있습니다. + + + 광고식별자, 방문기록, 기기 정보(유형, 모델명, OS 버전, APP 버전, 기기 식별자, 언어 및 국가), 닉네임/성별/국가/프로필 사진, 서포트코드 + + + ④ 회사의 서비스를 이용하여 캐릭터 및 관련 콘텐츠를 생성할 경우, 이용자의 카메라 기능을 이용하지만 + 이용자의 사진을 복사하거나 회사의 서버로 전송하지 않습니다. + +
+ + + 제7조 (개인정보의 파기) + + + ① 회사는 이용자로부터 동의 받은 개인정보의 보유기간이 경과하거나 처리목적을 달성하여 + 더 이상 개인정보가 필요하지 않게 된 경우 지체없이 해당 개인정보를 파기합니다. + + + ② 제1항 해당됨에도 불구하고 다른 법령에 따라 개인정보를 계속 보존하여야 하는 경우에는, + 해당 개인정보를 별도의 데이터베이스(DB)로 옮기거나 보관장소를 달리하여 보존합니다. (법령에 따른 보관 기간은 제2조를 참조하시기 바랍니다) + + + ③ 개인정보 파기의 절차 및 방법은 다음과 같습니다. + + + 1. 파기절차 + + + 1) 개인정보 도용 등으로 인한 피해 발생 시 복구와 피해자 보호 등을 위하여 회원가입 시 수집한 개인정보를 14일 동안 임시로 보관할 수 있습니다. + + + 2) 회사는 파기 사유가 발생한 개인정보를 선정하고, 회사의 개인정보 보호책임자의 승인을 받아 개인정보를 파기합니다. + + + 2. 파기방법 + + + 1) 전자적 파일의 형태 : 복구 및 재생이 되지 않도록 기술적인 방법 이용 + + + 2) 종이 문서 : 분쇄기로 분쇄하거나 소각 + + + + + 제8조 (개인정보의 안전성 확보조치) + + + 1. 관리적 조치 + + + 내부관리계획 수립 및 시행, 정기적 임직원 교육, 정기적인 접속기록 점검, 수탁사 점검 등 + + + 2. 기술적 조치 + + + 개인정보처리시스템 등의 접근권한 관리, 접근통제시스템 설치, 내부 관리계획에 따른 암호화(전송구간 및 저장 시), 보안프로그램 설치 + + + 3. 물리적 조치 + + + 데이터센터, 자료보관실 등의 접근통제 + + + + + + 제9조 (개인정보 자동 수집 장치의 설치∙운영 및 거부에 관한 사항) + + + 회사는 이용자들에게 적합하고 보다 유용한 서비스와 광고 서비스(맞춤형 광고 포함)를 제공하기 위해서 + 이용자의 광고 식별자와 분석 소프트웨어를 사용하고 있습니다. + + + 1. 광고 식별자는 이용자가 소유한 스마트폰 및 태블릿 PC의 OS 설정에서 광고에 관한 기능을 + 활성화한 경우 자동으로 수집되며, 기기의 설정을 변경하거나 광고 플랫폼 사업자의 Opt-Out 기능을 활용함으로써 + 광고 식별자가 관심 사항에 기반하는 광고에 사용되지 못하도록 거부할 수 있습니다. + Opt-Out 기능을 설정하더라도 일방형 광고는 전송될 수 있습니다. + + + 1) 마케팅 분석툴 / 광고 플랫폼 사업자 + + + - 마케팅 분석툴 : Google Analytics + + + 2) 마케팅 정보 수신 차단 + + + - Android : [설정->Google->개인정보 보호->마케팅 정보 수신] 선택 해제 + + + 3) 개인 맞춤형 광고 차단 + + + - Android : [설정->Google->광고] 또는 [설정->Google->개인정보 보호->광고] + 에서 “광고 개인 최적화 선택 해제” 선택 + + + - iOS : [설정->개인정보 보호 및 보안->Apple 광고]에서 “개인 맞춤형 광고” 선택 해제 + + + 2. 분석 소프트웨어는 이용자가 웹 사이트를 방문하거나 모바일 서비스를 이용할 때 + 자동으로 생성되는 정보를 분석하기 위해 사용되며, 이용자는 이를 거부할 수 있습니다. + + + - Android : [설정->인터넷 설정->개인정보 보호 및 보안]에서 “스마트 추적 방지” 또는 “사이트에서 추적하지 못하도록 요청” 선택 + + + - iOS : [설정->개인정보 보호 및 보안->추적]에서 “앱이 추적을 요청하도록 허용” 선택 해제 + + + + + + 제10조 (개인정보 보호책임자) + + + ① 회사는 개인정보 처리에 관한 업무를 총괄해서 책임지고, + 개인정보 처리와 관련한 정보주체의 불만처리 및 피해구제 등을 위하여 아래와 같이 개인정보 보호책임자를 지정하고 있습니다. + + + ▶ 개인정보 보호책임자 + + + 성명 : 서평원 + + + 직책 : 대표 + + + 직급 : CEO + + + 연락처 : popo-service@kakao.com + + + ※ 개인정보 보호 담당부서로 연결됩니다. + + + ② 정보주체는 회사의 서비스(또는 사업)을 이용하시면서 발생한 모든 개인정보 보호 관련 문의, + 불만처리, 피해구제 등에 관한 사항을 개인정보 보호책임자 및 담당부서로 문의하실 수 있습니다. + 회사는 정보주체의 문의에 대해 지체 없이 답변 및 처리해 드릴 것입니다. + + + + + + 제11조 (권익침해 구제방법) + + + 이용자는 개인정보 침해에 대한 피해구제나 상담 등이 필요하신 경우에 아래의 기관에 문의하실 수 있습니다. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
기관명홈페이지전화
개인정보 침해신고센터https://privacy.kisa.or.kr/(국번없이) 118
개인정보 분쟁조정위원회https://www.kopico.go.kr/(국번없이) 1833-6972
대검찰청 사이버수사과https://cybercid.spo.go.kr/(국번없이) 1301
경찰청 사이버범죄 신고시스템https://ecrm.police.go.kr/(국번없이) 182
+
+ + + 제12조 (본 개인정보 처리방침의 적용 범위) + + + ① 본 개인정보 처리방침은 회사가 제공하는 모든 서비스(웹사이트 및 APP 포함)에 + 적용되지만, 서비스의 특성이 상이한 경우, 서비스 별로 특화된 개인정보 처리방침이 적용될 수 있습니다. + + + ② 회사 서비스에 링크되어 있는 다른 회사의 웹사이트를 방문하거나, 방문하신 웹사이트에서 개인정보를 수집하는 경우 본 개인정보 처리방침이 적용되지 않습니다. + + + + + 제13조 (개인정보 처리방침의 변경 및 고지) + + + ① 본 개인정보 처리방침의 내용 추가, 삭제 및 수정이 있을 경우 개정 최소 7일 전에 ‘공지사항’을 통해 사전 공지를 하겠습니다. + 다만, 수집하는 개인정보의 항목, 이용목적의 변경 등과 같이 이용자 권리의 중대한 변경이 발생할 경우 이용자 동의를 다시 받을 수도 있습니다. + + + ② 이 개인정보 처리방침은 2024. 2. 1부터 적용됩니다. + + +
+ + ); +} + +const Containter = styled.div` + width: 100%; + height: 100%; + padding: 1rem 1rem; + display: flex; + flex-direction: column; + gap: 20px; + overflow: auto; +`; + +const Title = styled.p` + font-size: 1.2rem; + line-height: 1.2; + font-weight: bold; + color: ${({ theme }) => theme.color.text.title01}; +`; + +const Typograpy = styled.p` + font-size: 0.9rem; + line-height: 1.5; + color: ${({ theme }) => theme.color.text.title01}; +`; + +const TosContainer = styled.div` + width: 100%; + display: flex; + flex-direction: column; + gap: 10px; +`; + +const Table = styled.table` + th, td { + border: 1px solid #888888; + padding: 4px; + } +`; diff --git a/src/app/(non-member)/tos/use/page.tsx b/src/app/(non-member)/tos/use/page.tsx new file mode 100644 index 0000000..38c1623 --- /dev/null +++ b/src/app/(non-member)/tos/use/page.tsx @@ -0,0 +1,429 @@ +'use client'; + +import { styled } from 'styled-components'; + +import Header from '@/components/common/Header'; + +export default function TosUsePage() { + return ( + <> +
+ + + POPO 2023년 12월 20일 + + + 본 이용약관(이하 "이용약관")은 + 회사(이하 “회사”)의 POPO 앱 및 관련하여 제공하는 프로그램, + 소프트웨어 등(이하 "서비스" 또는 "POPO") 및 본 이용약관의 적용을 받으며 POPO 앱에서 업로드 및 다운로드, + 공유되는 모든 정보 및 텍스트, 그래픽, 사진, 기타 자료(이하 통칭 "콘텐츠")에 대한 접근 및 이용에 관한 사항을 규정합니다. + 본 이용약관에 동의하지 않는 경우 POPO를 이용할 수 없으므로, 사용 전 신중하게 확인한 후 동의하여 주시기 바랍니다. + + + 1. 회사와의 계약 + + 1) 준거법: 사용자는 회사와 계약을 체결하였으며, 법 조항의 상충 여부와 관계없이 대한민국 법의 적용을 받습니다. + + + 2) 회사에 제공한 모든 정보는 개인정보의 수집 및 이용에 관한 회사의 개인정보 취급방침의 적용을 받습니다. + 사용자는 서비스를 이용하는 것으로 관련 법률상 개인정보 보호 정책에 따라 사용자의 개인정보의 수집 및 이용에 동의합니다. + 본 서비스의 일환으로 회사는 사용자에게 서비스 알림 및 정보성 메시지를 전송할 수 있으며, 이는 서비스의 일부이므로 수신 거부할 수 없습니다. + + + 3) 회사는 ‘가입신청자’의 회원가입신청에 POPO 서비스 시스템에의 기계적 접근 또는 계정도용, + 거짓된 정보의 제공 및 ‘가입신청자’의 ‘서비스’ 어뷰징 내역 확인 등의 사유가 있어 + 회사가 ‘가입신청자’의 신청을 승낙하는 것이 적절하지 않은 경우 그 승낙을 유보 또는 거부하거나, + 사후에 이용계약을 해지할 수 있고, 필요한 경우 일정기간 동안 서비스 이용을 제한할 수 있습니다. + + + + + 2. 약관의 게시와 개정 + + + 1) 회사는 이 약관의 내용을 사용자가 쉽게 알 수 있도록 POPO 서비스 초기화면 내 또는 별도의 연결화면에 게시하거나 팝업화면 등으로 제공합니다. + + + 2) 회사는 정보통신망이용촉진및정보보호등에관한법률(이하 ‘정보통신망법’), + 전자상거래등에서의소비자보호에관한법률, + 약관의규제에관한법률 등 관련 법을 위반하지 않는 범위에서 이 약관을 개정할 수 있습니다. + + + 3) 회사가 약관을 개정할 경우에는 적용일자 및 개정사유를 명시하여 + 현행 약관과 함께 제1항의 방식에 따라 그 개정약관의 적용일자 7일 전부터 적용일자 전일까지 공지합니다. + 다만, 그 변경 내용이 법적으로 사용자에게 불리한 것일 경우, + 그 적용일자 30일 이전부터 동일한 내용을 ‘서비스’를 통해 공지할 뿐만 아니라, + 해당 내용을 사용자의 이메일 등으로 개별적으로 통지합니다. + + + 4) 회사가 전항에 따라 개정약관을 공지 또는 통지하면서 사용자에게 7일 또는 30일 기간 내에 + 거부의 의사표시를 하지 않으면 약관 개정에 동의한 것으로 간주한다는 뜻을 명확하게 공지 또는 통지하였음에도 + 사용자가 명시적으로 거부의 의사표시를 하지 아니한 경우 사용자가 개정약관에 동의한 것으로 봅니다. + + + 5) 사용자가 개정약관의 적용에 동의하지 않는 경우 POPO 개정약관의 내용을 적용할 수 없으며, + 이 경우 사용자는 이용계약을 해지할 수 있습니다. 다만, 기존 약관을 적용할 수 없는 + 특별한 사정이 있는 경우에는 회사는 이용계약을 해지할 수 있습니다. + + + + + + 3. POPO 콘텐츠 및 사용자 콘텐츠 + + + + 1) "POPO IP(Intellectual Property) 콘텐츠"란, + POPO 서비스를 구성하고 운영하기 위해 회사가 제작한 모든 저작물(아이템, 영상, 이미지, 설문, 텍스트, 그래픽, 문구 등)을 의미합니다 + (시각적으로 확인 가능한 자료들을 대상으로 하며, 컴퓨터 등 정보처리장치 내에서 직접 및 간접적으로 사용되는 프로그램, 소프트웨어 등은 제외). + "POPO IP 콘텐츠"의 선택과 배치 등을 비롯하여 서비스에 포함된 모든 자료는 저작권, 상표권, 트레이드 드레스, + 특허권 및 기타 지적 재산권은 회사에게 있으며, + 관련 법률에 의해 보호받습니다. + + + 2) 사용자는 "POPO IP 콘텐츠"를 이용하여 + 사진, 동영상, 텍스트, 그래픽, 아이템 및 기타 자료(이하 "사용자 콘텐츠")를 제작하고 게시하며, + 전송 및 저장하는 등 적극적인 상호작용을 할 수 있습니다. + 회사는 사용자 간의 적극적인 상호작용을 장려하기 위하여 POPO에서 하는 활동에 기초하여 사용자가 관심을 가질만한 "콘텐츠", + 기능을 제안하거나 추천할 수 있으며, 사용자에게 POPO를 경험하는 방법을 제안하기도 합니다. 물론, + 사용자는 개인정보 설정에 따라 본인의 "사용자 콘텐츠"를 볼 수 있는 대상을 제한할 수 있습니다. + + + 3) 사용자가 제작한 "사용자 콘텐츠"는 타인이 조회할 수 있으며, + 사용자는 개인정보 설정 기능을 통해 콘텐츠에 대한 접근을 관리할 수 있습니다. + 회사의 직원은 POPO에 업로드 된 "사용자 콘텐츠"를 확인할 수 있습니다. + 회사는 사용자의 개인 콘텐츠를 안전하게 보호하기 위해 합당한 조치를 취하고 있으나, 100% 안전은 보장할 수 없으며, + 제3자가 무단으로 보안을 뚫고 개인 콘텐츠에 접근하는 상황이 발생할 수도 있음을 양해하여 주시기 바랍니다. + + + 4) "사용자 콘텐츠"에 대한 모든 저작권 및 기타 지적재산권은 본인에게 있습니다. + 다만, "사용자 콘텐츠"는 "POPO IP 콘텐츠"를 기초로 창작 + 또는 제작된 것으로 본 서비스 이용으로 인해 발생하는 모든 데이터 사용료는 사용자의 부담입니다. + + + 5) "사용자 콘텐츠"를 POPO에 게시함으로써 사용자는 + 현재 또는 추후 개발되는 모든 미디어 및 배포 매체에 해당 사용자 콘텐츠를 사용( + 기계 학습 및 회사 단독 또는 계열사와 합작 R&D 목적으로 얼굴 이미지, 사진, 동영상을 이용하는 것도 포함) + 권한을 회사에 부여한 것으로 간주되며, 마찬가지로 다른 사용자가 "사용자 콘텐츠"를 + POPO 플랫폼 내부 및 외부에서 회사가 제공하는 가이드라인에 따라 사용하는 것에 동의한 것으로 봅니다. + 이때, 사용자는 개인정보 설정에 따라 본인의 사용자 콘텐츠를 볼 수 있는 대상을 제한할 수 있습니다. + + + 6) 사용자는 "사용자 콘텐츠" 및 그로 인해 발생하는 일체의 손해배상에 대해 + 전적으로 책임을 부담하며, 회사는 이에 대해 어떠한 책임도 지지 않습니다. 비록 의무는 아니나, + 회사는 독자적 결정에 따라 언제든지 사용자 콘텐츠를 검토, 감독 및 삭제할 수 있습니다. + + + + + 4. 피드백 + + + 사용자가 이메일 또는 기타 형식으로 회사 또는 서비스에 대하여 제공한 + 피드백, 제안, 아이디어 및 기타 정보(이하 "피드백")는 기밀 자료에 해당하지 않으며, + 회사의 고유한 자산으로 간주됩니다. 즉, 회사는 제공 사용자에게 어떠한 통보나 보상을 + 제공하지 않고도 상업적 또는 여타의 목적으로 해당 피드백을 제한 없이 이용하고 배포할 수 있으며, + 사용자는 이에 대해 저작권 및 저작인격권을 포함하여 어떠한 권리도 행사할 수 없습니다. + 회사는 사용자 의견에 대한 소유권 및 기타 권리나 금전적 보상을 하지 않습니다. + + + + + 5. 금지 행위 + + + 사용자는 본 이용약관에서 명시한 제한 사항과 더불어 다음의 행위를 삼가는 데 동의합니다. + 본 이용약관에서 명시적으로 허용하는 경우를 제외하고, + 회사의 사전 서면 동의 없이 POPO IP 콘텐츠 및 서비스를 이용하는 행위는 엄격히 금지되며, + 이러한 행위가 발생할 경우, 본 이용약관에서 부여한 이용권한이 종료됩니다. + + + ● 불법 또는 본래 이용범위를 벗어난 목적으로 또는 본 이용약관 및 특정 서비스에 관한 제3자 이용약관의 금지 조항을 위반하여 서비스를 이용하는 행위 + + + ● 다른 사용자의 서비스 이용을 방해, 중단 및 제한하고, 이에 부정적인 영향을 주거나, + 서비스 기능에 손상, 장애, 과부하, 파손을 초래하는 방식으로 서비스를 이용하는 행위 + + + ● 서비스 보안을 훼손하는 행위 + + + ● 회사에서 제공하지 않은 로봇, 스파이더, 크롤러, 스크래퍼 및 기타 자동화된 수단이나 인터페이스를 사용하여 서비스에 접근하거나 데이터를 추출하는 행위 + + + ● 서비스 일부를 역설계하거나 서비스의 영역, 콘텐츠, 코드에 대한 접근을 방지하고 제한하기 위해 설계된 장치를 우회하거나 회피하고 + , 소스 코드를 찾아내려는 행위 + + + ● 다른 사용자의 계정을 무단으로 사용하거나 이를 시도하는 행위 + + + ● 서비스에서 명시적으로 허용하는 경우를 제외하고, POPO IP 콘텐츠 및 서비스, 그에 포함된 일체의 정보를 다운로드하는 행위(페이지 캐싱 제외) + + + ● 무단으로 또는 제3자와 POPO API에 접근하는 행위 + + + ● 회사와의 관계를 드러내거나 회사의 명시적인 서면 동의 없이 제품 및 서비스를 홍보하는 행위 + + + ● 욕설, 괴롭힘, 협박, 위협 및 스토킹 등에 가담하는 행위 + + + ● 타인이나 기관 또는 그 관계를 사칭하는 행위 + + + ● 동의 없이 사진을 촬영 및 사용하는 등 타인의 초상권, 사생활, 정보보호 권리를 침해하는 행위 + + + ● 타인의 특허권, 상표권, 영업 비밀, 저작권, 기타 지적 재산권, 소유권을 침해하는 행위 + + + ● 금전을 대가로 POPO의 사전 서면 동의 없이 POPO 계정, 친구 링크에 대한 접근 권한을 매매, 임대, 대여, 기타 방식으로 판매하는 행위 + + + ● 회사의 사전 서면 동의 없이 사용자 콘텐츠 또는 서비스와 상호작용할 수 있는 제3자 앱을 개발하는 행위 + + + ● 불법 또는 무단으로 서비스를 이용하거나 본 이용약관을 위반하는 행위를 권장 또는 촉진하는 행위 + + + ● iTunes 앱 스토어 서비스 이용약관 및 안드로이드 마켓 서비스 이용약관 등 + POPO에 대한 리뷰를 게시할 때는 본 서비스에 적용되는 제3자 이용약관을 준수해야 합니다. + 앱 스토어 리뷰 작성 시 POPO 사용자명을 노출하는 것은 엄격히 금지되며, 이를 위반할 경우 POPO 계정이 삭제될 수도 있습니다. + + + + + 6. 서비스 이용 라이선스 + + + 회사는 사용자에게 서비스의 일부로 제공되는 소프트웨어에 대한 개인적이고, + 전 세계적이며, 양도 불가능하며, 사용료 없이 이용 가능한 비독점적 라이선스 사용 권한을 부여합니다. + 해당 라이선스는 본 이용약관에서 허용하는 범위 내에서 회사 서비스의 혜택을 누리기 위한 목적으로만 제공됩니다. + + + 1. 계정 정보: 서비스를 이용하려면 POPO 계정을 생성해야 합니다. + 로그인 자격증명에 대한 보안 및 계정을 통해 이루어진 모든 행위에 대한 책임은 본인에게 있습니다. + 사용자는 POPO 서비스와 관련한 프로그램, 소프트웨어의 전체 또는 일부를 복제, 재생산, 재게시, 변형, + 다운로드, 전송, 수정, 전시, 역설계, 판매 및 판촉, 임대, 대여, 양도, 분배, 라이선스, 서브라이선스, + 부당 이용 등의 행위를 할 수 없습니다. + + + + + 7. 회사의 권리 + + + 본 서비스에 대한 모든 소유권 및 권리, 지분(사용자가 제공한 콘텐츠는 제외)은 회사 및 회사 라이선스의 독점적 재산입니다. + 서비스는 저작권, 상표권 및 기타 법률의 보호를 받으며, 본 이용약관의 어떠한 조항도 회사의 상호 및 상표권, 로고, 도메인명, + 기타 고유한 브랜드 특징을 이용할 수 있는 권한을 부여하지 않습니다. + 회사 및 서비스에 관한 피드백, 의견 및 제안은 사용자의 자발적 의지로 제공되는 것이며, 회사에서 적합하다고 판단할 경우, + 제공 회사자에게 통지하지 않고도 해당 의견, 피드백 및 제안을 자유롭게 사용할 수 있습니다. + + + + + 8. 광고의 게재 + + + 회사는 회사 서비스의 운영과 관련하여 서비스 화면에 직접 또는 제휴 관계에 있는 제3자를 통해 광고를 게재할 수 있습니다. + + + + + + 9. 유료서비스의 내용 등의 표시 + + + 회사는 다음 사항을 해당 유료서비스의 이용초기화면이나 FAQ 등에 사용자가 알기 쉽게 표시합니다. + + + 1) 유료서비스의 명칭 또는 제호 + + + 2) 유료서비스 주체의 성명(법인인 경우는 법인의 명칭), 주소, 전화번호 + + + 3) 유료서비스의 내용, 이용방법, 이용료, 기타 이용조건 + + + 4) 회사의 유료서비스의 이용가능기기 및 이용에 필요한 최소한의 기술사항은 권장사양정보에 따릅니다. + + + 5) 회사는 유료서비스를 제공함에 있어 유료서비스의 교환·반품·보증과 그 대금 환불의 조건 및 절차에 관한 사항을 제공합니다. + + + 6) 회사의 정책 및 제1항의 결제방법 제공자가 정한 기준에 따라 사용자의 월별 누적 결제액 및 유료서비스 구매한도가 제한될 수 있습니다. + 해당 기준을 초과한 경우 유료서비스의 추가 이용은 불가능할 수 있습니다. + + + + + + 10. 사용기간 등 + + + 유료서비스의 사용기간 또는 유효기간은 계약 당시 표시한 바에 따릅니다. 해당 기간이 경과한 유료서비스는 이용권한이 소멸될 수 있습니다. + + + + + + 11. 재화등의 하자에 의한 피해보상 + + + 유료서비스의 하자 등에 의한 사용자 피해보상은 콘텐츠이용자보호지침에서 정한 바에 따릅니다. + + + + + 12. 저작권 정책 + + + 1) 본인의 콘텐츠가 정보통신망법 및 저작권법 등 관련법에 위반되는 내용을 포함하는 경우, + 관련법이 정한 절차에 따라 해당 "게시물"의 게시중단 및 삭제 등을 요청할 수 있으며, + 회사는 관련법에 따라 조치를 취하여야 합니다. + + + 2) 회사는 전항에 따른 권리자의 요청이 없는 경우라도 권리침해가 인정될 만한 사유가 있거나 + 기타 회사 정책 및 관련법에 위반되는 경우에는 관련법에 따라 해당 콘텐츠에 대해 임시조치 등을 취할 수 있으며, + 이에 대해 어떠한 책임도 지지 않습니다. 회사는 필요한 경우, 여러 차례 반복해서 저작권을 침해하는 사용자가 있다면, + 해당 계정을 종료시킬 수 있습니다. + + + 3) 본 조에 따른 세부절차는 "정보통신망법" 및 "저작권법"이 규정한 범위 내에서 + 회사가 정한 게시중단요청서비스에 따릅니다. + + + + + + 13. 면책 조항 + + + 1) 서비스 이용 과정에서 불쾌하고, 선정적이며, 모욕적인 자료에 노출될 수 있으며, + 서비스에 접근하고 이를 이용함으로써 이러한 위험 요소를 받아들이는 것에 동의합니다. + 회사의 웹사이트 또는 서비스에 노출되는 콘텐츠는 회사의 의견을 반영한 것이 아닐 수도 있으며, + 서비스의 사용자가 게시한 어떠한 콘텐츠도 지원하거나 지지하지 않습니다. + + + 2) 회사는 사용자의 콘텐츠를 안전하게 보호하기 위해 합당한 조치를 시행하고 있으나, + 해당 콘텐츠의 노출로 인해 발생할 수 있는 모든 위험을 100% 완벽하게 예방할 수는 없습니다. + + + 3) 면책 조항: 관련 법률에서 허용하는 최대 범위 내에서 회사의 서비스 및 + 웹사이트, 앱, 콘텐츠, 기타 모든 자료는 어떠한 명시적, 묵시적, 법적 보증 없이 + "있는 그대로" 사용자에게 제공됩니다. 회사는 (1) 서비스 및 자료가 사용자의 요구사항에 부합하거나 지속적으로 중단 없이, + 적시에, 안전하게, 오류 없이 이용 가능하며, (2) 웹사이트, 서비스, 자료의 이용을 통해 획득한 결과가 효과적이며, + 정확하고, 신뢰할 수 있으며, (3) 웹사이트, 서비스, 자료에서 발견되는 모든 오류 및 결함을 즉시 해결할 수 있음을 보증하지 않습니다. + + + + + + 14. 책임 제한 + + + 법률에서 금지하는 경우를 제외하고, 회사 및 회사의 공급업체, + 각각의 임원, 이사, 직원, 대리인(이하 "회사 측")은 (1) 서비스 이용 및 이용 불능, + (2) 서비스 제공 및 서비스를 통해 이용 가능한 자료, (3) 서비스 사용자의 행위로 말미암아 발생하는 + 간접적, 특별적, 징벌적, 부수적, 모범적, 결과적 손해에 대하여 어떠한 책임도 지지 않습니다. + + + + + + 15. 회사와의 분쟁 해결 + + + 1) 서면으로 달리 정하지 않는 한, 회사와 분쟁이 발생하는 경우, 제소 당시의 사용자의 주소에 의하고, + 주소가 없는 경우 거소를 관할하는 지방법원의 전속관할로 합니다. + 단, 제소 당시 사용자의 주소 또는 거소가 명확하지 아니한 경우의 관할법원은 민사소송법에 따라 정합니다. + + + 2) 해외에 주소나 거소가 있는 사용자의 경우 회사와 사용자간 발생한 분쟁에 관한 소송은 전항에도 불구하고 대한민국 서울중앙지방법원을 관할법원으로 합니다. + + + 3) 면책 조항: 회사와 사용자는 국제 물품 매매 계약에 관한 유엔 협약상 책임과 권리를 부인하며, 본 서비스의 사용에 있어 이를 적용하지 않기로 합의합니다. + + + + + 16. 종료 + + + 1) 사용자는 언제든지 서비스 이용을 중단할 수 있습니다. + + + 2) 회사는 서비스의 기능을 언제든지 추가, 수정 및 삭제할 수 있습니다. + 또한, 서비스의 제공을 일시 또는 영구적으로 중단하거나 새로운 제한 사항을 추가할 수도 있습니다. + + + 3) 사용자 계정의 사용이 종료되더라도, 지불 의무는 그대로 유효합니다. + + + 4) 서비스가 종료 또는 중단되는 경우, 회사는 사용자에게 이를 알리기 위해 합당한 노력을 기울이고, 사용자의 콘텐츠를 복구할 수 있도록 협조합니다. + + + + + 17. 일반 조항 + + + 1) 분리 조항: 법원의 판결을 통해 본 이용약관의 일부 조항이 집행이 불가능하거나 실효되더라도 나머지 조항은 유효하게 적용됩니다. + + + 2) 권리불포기: 회사가 본 이용약관을 집행하지 않거나 집행을 유예하였더라도 이는 본 약관의 집행 권리를 포기하는 것으로 간주되지 않습니다. + + + 3) 양도: 회사의 서면 동의 없이 사용자는 본 이용약관에서 정한 권리 및 의무를 타인에게 양도할 수 없습니다. + 단, 인수 합병 및 서비스 매각이 발생하는 경우, 회사는 사용자의 동의 없이 사용자에 가지는 회사의 권리 및 의무를 양도할 수 있습니다. + + + 4) 완전합의: 본 이용약관은 서비스에 관한 회사와 사용자 간의 완전하고 독점적인 합의를 나타내며, + 서비스와 관련하여 이전에 체결된 모든 계약을 대체합니다. 회사는 때때로 본 이용약관을 수정할 수 있으며, + 독자적 결정에 의거 수정 사항이 중대하다고 판단하는 경우, 웹페이지 배너 또는 통지 유형에 따라 적절한 수단을 사용하여 사용자에게 고지합니다. + 사용자가 수정 사항이 적용된 후에도 서비스를 계속 이용하는 경우, 변경 후의 이용약관에 동의를 한 것으로 간주됩니다. + + + + + + ); +} + +const Containter = styled.div` + width: 100%; + height: 100%; + padding: 1rem 1rem; + display: flex; + flex-direction: column; + gap: 20px; + overflow: auto; +`; + +const Title = styled.p` + font-size: 1.2rem; + line-height: 1.2; + font-weight: bold; + color: ${({ theme }) => theme.color.text.title01}; +`; + +const Typograpy = styled.p` + font-size: 0.9rem; + line-height: 1.5; + color: ${({ theme }) => theme.color.text.title01}; +`; + +const TosContainer = styled.div` + width: 100%; + display: flex; + flex-direction: column; + gap: 10px; +`; + +// 1조 +// 1항 + +// ul diff --git a/src/app/(setting)/setting/tos/privacy/page.tsx b/src/app/(setting)/setting/tos/privacy/page.tsx deleted file mode 100644 index d943039..0000000 --- a/src/app/(setting)/setting/tos/privacy/page.tsx +++ /dev/null @@ -1,475 +0,0 @@ -'use client'; - -import { styled } from 'styled-components'; - -export default function TosUsePage() { - return ( - - - POPO 2024년 2월 1일 - - - (주)4심(이하 회사)는 「개인정보 보호법」 제30조에 따라 이용자의 개인정보를 보호하고 - 이와 관련한 고충을 신속하고 원활하게 처리할 수 있도록 하기 위하여 다음과 같이 개인정보 처리방침을 수립 및 공개합니다. - - - 제1조 (개인정보의 처리목적) - - 회사는 다음의 목적을 위하여 개인정보를 처리하며, 처리하고 있는 개인정보는 다음의 목적 이외의 용도로는 이용되지 않습니다. - 이용 목적이 변경되는 경우에는 「개인정보 보호법」 제18조에 따라 별도의 동의를 받는 등 필요한 조치를 이행할 예정입니다. - - - 1. 회원 가입 및 로그인, 관리 - 회원 가입의사 확인과 회원제 서비스 제공에 따른 회원자격 유지 및 관리, 서비스 부정이용 방지, 각종 고지와 통지를 목적으로 개인정보를 처리합니다. - - - 2. 재화 또는 서비스 제공 - 본인 인증, 결제, 서비스 및 콘텐츠, 광고를 포함한 맞춤형 서비스 제공을 목적으로 개인정보를 처리합니다. - - - 3. 고충처리 - 이용자의 신원 확인, 문의사항 확인, 사실조사를 위한 연락, 통지, 처리결과 통보의 목적으로 개인정보를 처리합니다. - - - 4. 제휴 및 제안 - 제휴 및 제안 시 이용자 또는 사업자가 작성한 내용을 검토하고, 필요 시 연락을 위한 목적으로 개인정보를 처리합니다. - - - - - 제2조 (개인정보의 처리 및 보유기간) - - - ① 회사는 법령에 명시되어 있거나 이용자로부터 개인정보 수집 시 동의 받은 개인정보의 보유 및 이용기간 내에서 개인정보를 처리 및 보유합니다. - - - • 회원 가입 및 로그인, 관리 : 회원 탈퇴 시 - 단, 다음의 사유에 해당하는 경우에는 해당 사유 종료 시까지 - - - • 관계 법령 위반에 따른 수사, 조사 등이 진행 중인 경우에는 해당 수사, 조사 종료 시까지 - - - • 서비스 이용에 따른 채권, 채무관계 잔존 시에는 해당 채권, 채무관계 정산 시까지 - - - • 회원 탈퇴 후 복구 요청 기간 종료 시까지 (회원 탈퇴일로부터 5일) - - - • 재화 또는 서비스 제공 : 재화, 서비스 공급 완료 또는 서비스 이용 종료 시까지 - - - • 친구 초대 : ‘친구 초대’ 기능의 서비스 종료 또는 회원탈퇴 시까지 - - - • 고충처리 : 고충 처리 완료 시까지 - - - • 제휴 제안 : 제휴 및 제안 검토 완료 후 6개월 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
관련법령수집정보보유기간
통신비밀보호법서비스 이용 관련 정보(접속로그)3개월
전자상거래 등에서의 소비자 보호에 관한 법률소비자의 불만 또는 분쟁처리에 관한 기록3년
전자상거래 등에서의 소비자 보호에 관한 법률계약 또는 청약철회 등에 관한 기록5년
전자상거래 등에서의 소비자 보호에 관한 법률대금결제 및 재화 등의 공급에 관한 기록5년
-
- - - - 제3조 (개인정보의 제3자 제공) - - - ① 회사는 이용자의 개인정보를 제1조(개인정보의 처리 목적)에서 명시한 범위 내에서만 처리하며, - 정보주체의 동의, 법률의 특별한 규정 등 「개인정보 보호법」 제17 조 및 제18조에 해당하는 경우에만 개인정보를 제3자에게 제공합니다. - - - ② 회사는 제3자에게 개인정보를 제공하지 않으며, 제공하게 될 경우 이용자에게 동의를 받겠습니다. - - - - - 제4조 (개인정보처리의 위탁) - - - ① 회사는 원활한 개인정보 업무처리를 위하여 다음과 같이 개인정보 처리업무를 위탁하고 있습니다. - - - - 위탁받는 자 (수탁자) : 네이버클라우드 주식회사, Google Firebase - - - - 위탁하는 업무의 내용 : 모바일 알림서비스, 앱 딥링크, 앱 푸시 발송 - - - - 위탁기간 : 3년 - - - ② 회사는 위탁계약 체결 시 「개인정보 보호법」 제26조에 따라 위탁업무 수행 목적 외 - 개인정보 처리 금지, 기술적 · 관리적 보호 조치, 재위탁 제한, 수탁자에 대한 관리·감독, 손해배상 등 - 책임에 관한 사항을 계약서 등 문서에 명시하고, 수탁자가 개인정보를 안전하게 처리하는지를 감독하고 있습니다. - - - ③ 위탁업무의 내용이나 수탁자가 변경될 경우에는 지체 없이 본 개인정보 처리방침을 통하여 공개하도록 하겠습니다. - - - - - 제5조 (이용자와 법정대리인의 권리·의무 및 행사방법) - - - ① 이용자는 회사에 대해 언제든지 개인정보 열람, 정정, 삭제, 처리 정지 요구 등의 권리를 행사할 수 있습니다. - - - ② 개인정보 열람 및 처리 정지 요구는 개인정보보호법 제35조 제4항, 제37조 제2항에 의하여 이용자의 권리가 제한될 수 있습니다. - - - ③ 제1항에 따른 권리 행사는 회사에 대해 개인정보 보호법 시행령 제41조 제1항에 따라 - 서면, 전자우편, 모사전송(FAX) 등을 통하여 하실 수 있으며 회사는 이에 대해 지체 없이 조치하겠습니다. - - - ④ 개인정보의 정정 및 삭제 요구는 다른 법령에서 그 개인정보가 수집 대상으로 명시되어 있는 경우에는 그 삭제를 요구할 수 없습니다. - - - ⑤ 회사는 이용자 권리에 따른 열람의 요구, 정정·삭제의 요구, 처리 정지의 요구 시 열람 등 요구를 한 자가 본인이거나 정당한 대리인인지를 확인할 수 있습니다. - - - ⑥ 제5항에 따른 권리행사 주체가 대리인(이용자의 위임을 받은 자)인 경우 “개인정보 처리 방법에 관한 고시(제2020-7호)” - 별지 제11호 서식에 따른 위임장을 제출하셔야 합니다. - - - - - 제6조 (처리하는 개인정보 항목) - - - ① 회사는 다음의 개인정보 항목을 처리하고 있습니다. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
구분수집·이용목적필수/선택수집 및 이용항목
회원가입본인인증, 로그인필수이메일
회원가입 및 추천학교/친구 추천, 투표 성별 표시필수재학중인 학교 정보, 학년, 반, 이름, 성별
회원가입프로필 사진 등록선택프로필 사진
친구 초대친구 초대, 초대하는 친구의 서비스 가입 여부 확인선택암호화된 연락처
문의하기이용자 문의 및 고충 처리선택이메일 (공통)
문의하기이용자 문의 및 고충 처리: 결제, 환불 관련필수POPO 닉네임, 이름, 연락처(메일주소, 전화번호)
- - ② 서비스 이용과정에서 아래 개인정보 항목이 자동으로 생성되어 수집될 수 있습니다. - IP주소, 쿠키, 서비스 이용기록 - - - ③ 서비스 이용과정에서 개인정보는 아니지만 아래의 정보가 생성되어 수집될 수 있습니다. - - - 광고식별자, 방문기록, 기기 정보(유형, 모델명, OS 버전, APP 버전, 기기 식별자, 언어 및 국가), 닉네임/성별/국가/프로필 사진, 서포트코드 - - - ④ 회사의 서비스를 이용하여 캐릭터 및 관련 콘텐츠를 생성할 경우, 이용자의 카메라 기능을 이용하지만 이용자의 사진을 복사하거나 회사의 서버로 전송하지 않습니다. - -
- - - 제7조 (개인정보의 파기) - - - ① 회사는 이용자로부터 동의 받은 개인정보의 보유기간이 경과하거나 처리목적을 달성하여 - 더 이상 개인정보가 필요하지 않게 된 경우 지체없이 해당 개인정보를 파기합니다. - - - ② 제1항 해당됨에도 불구하고 다른 법령에 따라 개인정보를 계속 보존하여야 하는 경우에는, - 해당 개인정보를 별도의 데이터베이스(DB)로 옮기거나 보관장소를 달리하여 보존합니다. (법령에 따른 보관 기간은 제2조를 참조하시기 바랍니다) - - - ③ 개인정보 파기의 절차 및 방법은 다음과 같습니다. - - - 1. 파기절차 - - - 1) 개인정보 도용 등으로 인한 피해 발생 시 복구와 피해자 보호 등을 위하여 회원가입 시 수집한 개인정보를 14일 동안 임시로 보관할 수 있습니다. - - - 2) 회사는 파기 사유가 발생한 개인정보를 선정하고, 회사의 개인정보 보호책임자의 승인을 받아 개인정보를 파기합니다. - - - 2. 파기방법 - - - 1) 전자적 파일의 형태 : 복구 및 재생이 되지 않도록 기술적인 방법 이용 - - - 2) 종이 문서 : 분쇄기로 분쇄하거나 소각 - - - - - 제8조 (개인정보의 안전성 확보조치) - - - 1. 관리적 조치 - - - 내부관리계획 수립 및 시행, 정기적 임직원 교육, 정기적인 접속기록 점검, 수탁사 점검 등 - - - 2. 기술적 조치 - - - 개인정보처리시스템 등의 접근권한 관리, 접근통제시스템 설치, 내부 관리계획에 따른 암호화(전송구간 및 저장 시), 보안프로그램 설치 - - - 3. 물리적 조치 - - - 데이터센터, 자료보관실 등의 접근통제 - - - - - - 제9조 (개인정보 자동 수집 장치의 설치∙운영 및 거부에 관한 사항) - - - 회사는 이용자들에게 적합하고 보다 유용한 서비스와 광고 서비스(맞춤형 광고 포함)를 제공하기 위해서 이용자의 광고 식별자와 분석 소프트웨어를 사용하고 있습니다. - - - 1. 광고 식별자는 이용자가 소유한 스마트폰 및 태블릿 PC의 OS 설정에서 광고에 관한 기능을 - 활성화한 경우 자동으로 수집되며, 기기의 설정을 변경하거나 광고 플랫폼 사업자의 Opt-Out 기능을 활용함으로써 - 광고 식별자가 관심 사항에 기반하는 광고에 사용되지 못하도록 거부할 수 있습니다. - Opt-Out 기능을 설정하더라도 일방형 광고는 전송될 수 있습니다. - - - 1) 마케팅 분석툴 / 광고 플랫폼 사업자 - - - - 마케팅 분석툴 : Google Analytics - - - 2) 마케팅 정보 수신 차단 - - - - Android : [설정->Google->개인정보 보호->마케팅 정보 수신] 선택 해제 - - - 3) 개인 맞춤형 광고 차단 - - - - Android : [설정->Google->광고] 또는 [설정->Google->개인정보 보호->광고] - 에서 “광고 개인 최적화 선택 해제” 선택 - - - - iOS : [설정->개인정보 보호 및 보안->Apple 광고]에서 “개인 맞춤형 광고” 선택 해제 - - - 2. 분석 소프트웨어는 이용자가 웹 사이트를 방문하거나 모바일 서비스를 이용할 때 - 자동으로 생성되는 정보를 분석하기 위해 사용되며, 이용자는 이를 거부할 수 있습니다. - - - - Android : [설정->인터넷 설정->개인정보 보호 및 보안]에서 “스마트 추적 방지” 또는 “사이트에서 추적하지 못하도록 요청” 선택 - - - - iOS : [설정->개인정보 보호 및 보안->추적]에서 “앱이 추적을 요청하도록 허용” 선택 해제 - - - - - - 제10조 (개인정보 보호책임자) - - - ① 회사는 개인정보 처리에 관한 업무를 총괄해서 책임지고, - 개인정보 처리와 관련한 정보주체의 불만처리 및 피해구제 등을 위하여 아래와 같이 개인정보 보호책임자를 지정하고 있습니다. - - - ▶ 개인정보 보호책임자 - - - 성명 : 서평원 - - - 직책 : 대표 - - - 직급 : CEO - - - 연락처 : popo-service@kakao.com - - - ※ 개인정보 보호 담당부서로 연결됩니다. - - - ② 정보주체는 회사의 서비스(또는 사업)을 이용하시면서 발생한 모든 개인정보 보호 관련 문의, - 불만처리, 피해구제 등에 관한 사항을 개인정보 보호책임자 및 담당부서로 문의하실 수 있습니다. - 회사는 정보주체의 문의에 대해 지체 없이 답변 및 처리해 드릴 것입니다. - - - - - - 제11조 (권익침해 구제방법) - - - 이용자는 개인정보 침해에 대한 피해구제나 상담 등이 필요하신 경우에 아래의 기관에 문의하실 수 있습니다. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
기관명홈페이지전화
개인정보 침해신고센터https://privacy.kisa.or.kr/(국번없이) 118
개인정보 분쟁조정위원회https://www.kopico.go.kr/(국번없이) 1833-6972
대검찰청 사이버수사과https://cybercid.spo.go.kr/(국번없이) 1301
경찰청 사이버범죄 신고시스템https://ecrm.police.go.kr/(국번없이) 182
-
- - - 제12조 (본 개인정보 처리방침의 적용 범위) - - - ① 본 개인정보 처리방침은 회사가 제공하는 모든 서비스(웹사이트 및 APP 포함)에 - 적용되지만, 서비스의 특성이 상이한 경우, 서비스 별로 특화된 개인정보 처리방침이 적용될 수 있습니다. - - - ② 회사 서비스에 링크되어 있는 다른 회사의 웹사이트를 방문하거나, 방문하신 웹사이트에서 개인정보를 수집하는 경우 본 개인정보 처리방침이 적용되지 않습니다. - - - - - 제13조 (개인정보 처리방침의 변경 및 고지) - - - ① 본 개인정보 처리방침의 내용 추가, 삭제 및 수정이 있을 경우 개정 최소 7일 전에 ‘공지사항’을 통해 사전 공지를 하겠습니다. - 다만, 수집하는 개인정보의 항목, 이용목적의 변경 등과 같이 이용자 권리의 중대한 변경이 발생할 경우 이용자 동의를 다시 받을 수도 있습니다. - - - ② 이 개인정보 처리방침은 2024. 2. 1부터 적용됩니다. - - -
- ); -} - -const Containter = styled.div` - width: 100%; - height: 100%; - padding: 1rem 1rem; - display: flex; - flex-direction: column; - gap: 20px; - overflow: auto; -`; - -const Title = styled.p` - font-size: 1.2rem; - line-height: 1.2; - font-weight: bold; - color: ${({ theme }) => theme.color.text.title01}; -`; - -const Typograpy = styled.p` - font-size: 0.9rem; - line-height: 1.5; - color: ${({ theme }) => theme.color.text.title01}; -`; - -const TosContainer = styled.div` - width: 100%; - display: flex; - flex-direction: column; - gap: 10px; -`; - -const Table = styled.table` - th, td { - border: 1px solid #888888; - padding: 4px; - - } -`; diff --git a/src/app/(setting)/setting/tos/use/page.tsx b/src/app/(setting)/setting/tos/use/page.tsx deleted file mode 100644 index ead5390..0000000 --- a/src/app/(setting)/setting/tos/use/page.tsx +++ /dev/null @@ -1,422 +0,0 @@ -'use client'; - -import { styled } from 'styled-components'; - -export default function TosUsePage() { - return ( - - - POPO 2023년 12월 20일 - - - 본 이용약관(이하 "이용약관")은 - 회사(이하 “회사”)의 POPO 앱 및 관련하여 제공하는 프로그램, - 소프트웨어 등(이하 "서비스" 또는 "POPO") 및 본 이용약관의 적용을 받으며 POPO 앱에서 업로드 및 다운로드, - 공유되는 모든 정보 및 텍스트, 그래픽, 사진, 기타 자료(이하 통칭 "콘텐츠")에 대한 접근 및 이용에 관한 사항을 규정합니다. - 본 이용약관에 동의하지 않는 경우 POPO를 이용할 수 없으므로, 사용 전 신중하게 확인한 후 동의하여 주시기 바랍니다. - - - 1. 회사와의 계약 - - 1) 준거법: 사용자는 회사와 계약을 체결하였으며, 법 조항의 상충 여부와 관계없이 대한민국 법의 적용을 받습니다. - - - 2) 회사에 제공한 모든 정보는 개인정보의 수집 및 이용에 관한 회사의 개인정보 취급방침의 적용을 받습니다. - 사용자는 서비스를 이용하는 것으로 관련 법률상 개인정보 보호 정책에 따라 사용자의 개인정보의 수집 및 이용에 동의합니다. - 본 서비스의 일환으로 회사는 사용자에게 서비스 알림 및 정보성 메시지를 전송할 수 있으며, 이는 서비스의 일부이므로 수신 거부할 수 없습니다. - - - 3) 회사는 ‘가입신청자’의 회원가입신청에 POPO 서비스 시스템에의 기계적 접근 또는 계정도용, - 거짓된 정보의 제공 및 ‘가입신청자’의 ‘서비스’ 어뷰징 내역 확인 등의 사유가 있어 - 회사가 ‘가입신청자’의 신청을 승낙하는 것이 적절하지 않은 경우 그 승낙을 유보 또는 거부하거나, - 사후에 이용계약을 해지할 수 있고, 필요한 경우 일정기간 동안 서비스 이용을 제한할 수 있습니다. - - - - - 2. 약관의 게시와 개정 - - - 1) 회사는 이 약관의 내용을 사용자가 쉽게 알 수 있도록 POPO 서비스 초기화면 내 또는 별도의 연결화면에 게시하거나 팝업화면 등으로 제공합니다. - - - 2) 회사는 정보통신망이용촉진및정보보호등에관한법률(이하 ‘정보통신망법’), - 전자상거래등에서의소비자보호에관한법률, - 약관의규제에관한법률 등 관련 법을 위반하지 않는 범위에서 이 약관을 개정할 수 있습니다. - - - 3) 회사가 약관을 개정할 경우에는 적용일자 및 개정사유를 명시하여 - 현행 약관과 함께 제1항의 방식에 따라 그 개정약관의 적용일자 7일 전부터 적용일자 전일까지 공지합니다. - 다만, 그 변경 내용이 법적으로 사용자에게 불리한 것일 경우, - 그 적용일자 30일 이전부터 동일한 내용을 ‘서비스’를 통해 공지할 뿐만 아니라, - 해당 내용을 사용자의 이메일 등으로 개별적으로 통지합니다. - - - 4) 회사가 전항에 따라 개정약관을 공지 또는 통지하면서 사용자에게 7일 또는 30일 기간 내에 - 거부의 의사표시를 하지 않으면 약관 개정에 동의한 것으로 간주한다는 뜻을 명확하게 공지 또는 통지하였음에도 - 사용자가 명시적으로 거부의 의사표시를 하지 아니한 경우 사용자가 개정약관에 동의한 것으로 봅니다. - - - 5) 사용자가 개정약관의 적용에 동의하지 않는 경우 POPO 개정약관의 내용을 적용할 수 없으며, - 이 경우 사용자는 이용계약을 해지할 수 있습니다. 다만, 기존 약관을 적용할 수 없는 - 특별한 사정이 있는 경우에는 회사는 이용계약을 해지할 수 있습니다. - - - - - - 3. POPO 콘텐츠 및 사용자 콘텐츠 - - - - 1) "POPO IP(Intellectual Property) 콘텐츠"란, - POPO 서비스를 구성하고 운영하기 위해 회사가 제작한 모든 저작물(아이템, 영상, 이미지, 설문, 텍스트, 그래픽, 문구 등)을 의미합니다 - (시각적으로 확인 가능한 자료들을 대상으로 하며, 컴퓨터 등 정보처리장치 내에서 직접 및 간접적으로 사용되는 프로그램, 소프트웨어 등은 제외). - "POPO IP 콘텐츠"의 선택과 배치 등을 비롯하여 서비스에 포함된 모든 자료는 저작권, 상표권, 트레이드 드레스, - 특허권 및 기타 지적 재산권은 회사에게 있으며, - 관련 법률에 의해 보호받습니다. - - - 2) 사용자는 "POPO IP 콘텐츠"를 이용하여 - 사진, 동영상, 텍스트, 그래픽, 아이템 및 기타 자료(이하 "사용자 콘텐츠")를 제작하고 게시하며, - 전송 및 저장하는 등 적극적인 상호작용을 할 수 있습니다. - 회사는 사용자 간의 적극적인 상호작용을 장려하기 위하여 POPO에서 하는 활동에 기초하여 사용자가 관심을 가질만한 "콘텐츠", - 기능을 제안하거나 추천할 수 있으며, 사용자에게 POPO를 경험하는 방법을 제안하기도 합니다. 물론, - 사용자는 개인정보 설정에 따라 본인의 "사용자 콘텐츠"를 볼 수 있는 대상을 제한할 수 있습니다. - - - 3) 사용자가 제작한 "사용자 콘텐츠"는 타인이 조회할 수 있으며, - 사용자는 개인정보 설정 기능을 통해 콘텐츠에 대한 접근을 관리할 수 있습니다. - 회사의 직원은 POPO에 업로드 된 "사용자 콘텐츠"를 확인할 수 있습니다. - 회사는 사용자의 개인 콘텐츠를 안전하게 보호하기 위해 합당한 조치를 취하고 있으나, 100% 안전은 보장할 수 없으며, - 제3자가 무단으로 보안을 뚫고 개인 콘텐츠에 접근하는 상황이 발생할 수도 있음을 양해하여 주시기 바랍니다. - - - 4) "사용자 콘텐츠"에 대한 모든 저작권 및 기타 지적재산권은 본인에게 있습니다. - 다만, "사용자 콘텐츠"는 "POPO IP 콘텐츠"를 기초로 창작 - 또는 제작된 것으로 본 서비스 이용으로 인해 발생하는 모든 데이터 사용료는 사용자의 부담입니다. - - - 5) "사용자 콘텐츠"를 POPO에 게시함으로써 사용자는 - 현재 또는 추후 개발되는 모든 미디어 및 배포 매체에 해당 사용자 콘텐츠를 사용( - 기계 학습 및 회사 단독 또는 계열사와 합작 R&D 목적으로 얼굴 이미지, 사진, 동영상을 이용하는 것도 포함) - 권한을 회사에 부여한 것으로 간주되며, 마찬가지로 다른 사용자가 "사용자 콘텐츠"를 - POPO 플랫폼 내부 및 외부에서 회사가 제공하는 가이드라인에 따라 사용하는 것에 동의한 것으로 봅니다. - 이때, 사용자는 개인정보 설정에 따라 본인의 사용자 콘텐츠를 볼 수 있는 대상을 제한할 수 있습니다. - - - 6) 사용자는 "사용자 콘텐츠" 및 그로 인해 발생하는 일체의 손해배상에 대해 - 전적으로 책임을 부담하며, 회사는 이에 대해 어떠한 책임도 지지 않습니다. 비록 의무는 아니나, - 회사는 독자적 결정에 따라 언제든지 사용자 콘텐츠를 검토, 감독 및 삭제할 수 있습니다. - - - - - 4. 피드백 - - - 사용자가 이메일 또는 기타 형식으로 회사 또는 서비스에 대하여 제공한 - 피드백, 제안, 아이디어 및 기타 정보(이하 "피드백")는 기밀 자료에 해당하지 않으며, - 회사의 고유한 자산으로 간주됩니다. 즉, 회사는 제공 사용자에게 어떠한 통보나 보상을 - 제공하지 않고도 상업적 또는 여타의 목적으로 해당 피드백을 제한 없이 이용하고 배포할 수 있으며, - 사용자는 이에 대해 저작권 및 저작인격권을 포함하여 어떠한 권리도 행사할 수 없습니다. - 회사는 사용자 의견에 대한 소유권 및 기타 권리나 금전적 보상을 하지 않습니다. - - - - - 5. 금지 행위 - - - 사용자는 본 이용약관에서 명시한 제한 사항과 더불어 다음의 행위를 삼가는 데 동의합니다. - 본 이용약관에서 명시적으로 허용하는 경우를 제외하고, - 회사의 사전 서면 동의 없이 POPO IP 콘텐츠 및 서비스를 이용하는 행위는 엄격히 금지되며, - 이러한 행위가 발생할 경우, 본 이용약관에서 부여한 이용권한이 종료됩니다. - - - ● 불법 또는 본래 이용범위를 벗어난 목적으로 또는 본 이용약관 및 특정 서비스에 관한 제3자 이용약관의 금지 조항을 위반하여 서비스를 이용하는 행위 - - - ● 다른 사용자의 서비스 이용을 방해, 중단 및 제한하고, 이에 부정적인 영향을 주거나, - 서비스 기능에 손상, 장애, 과부하, 파손을 초래하는 방식으로 서비스를 이용하는 행위 - - - ● 서비스 보안을 훼손하는 행위 - - - ● 회사에서 제공하지 않은 로봇, 스파이더, 크롤러, 스크래퍼 및 기타 자동화된 수단이나 인터페이스를 사용하여 서비스에 접근하거나 데이터를 추출하는 행위 - - - ● 서비스 일부를 역설계하거나 서비스의 영역, 콘텐츠, 코드에 대한 접근을 방지하고 제한하기 위해 설계된 장치를 우회하거나 회피하고, 소스 코드를 찾아내려는 행위 - - - ● 다른 사용자의 계정을 무단으로 사용하거나 이를 시도하는 행위 - - - ● 서비스에서 명시적으로 허용하는 경우를 제외하고, POPO IP 콘텐츠 및 서비스, 그에 포함된 일체의 정보를 다운로드하는 행위(페이지 캐싱 제외) - - - ● 무단으로 또는 제3자와 POPO API에 접근하는 행위 - - - ● 회사와의 관계를 드러내거나 회사의 명시적인 서면 동의 없이 제품 및 서비스를 홍보하는 행위 - - - ● 욕설, 괴롭힘, 협박, 위협 및 스토킹 등에 가담하는 행위 - - - ● 타인이나 기관 또는 그 관계를 사칭하는 행위 - - - ● 동의 없이 사진을 촬영 및 사용하는 등 타인의 초상권, 사생활, 정보보호 권리를 침해하는 행위 - - - ● 타인의 특허권, 상표권, 영업 비밀, 저작권, 기타 지적 재산권, 소유권을 침해하는 행위 - - - ● 금전을 대가로 POPO의 사전 서면 동의 없이 POPO 계정, 친구 링크에 대한 접근 권한을 매매, 임대, 대여, 기타 방식으로 판매하는 행위 - - - ● 회사의 사전 서면 동의 없이 사용자 콘텐츠 또는 서비스와 상호작용할 수 있는 제3자 앱을 개발하는 행위 - - - ● 불법 또는 무단으로 서비스를 이용하거나 본 이용약관을 위반하는 행위를 권장 또는 촉진하는 행위 - - - ● iTunes 앱 스토어 서비스 이용약관 및 안드로이드 마켓 서비스 이용약관 등 - POPO에 대한 리뷰를 게시할 때는 본 서비스에 적용되는 제3자 이용약관을 준수해야 합니다. - 앱 스토어 리뷰 작성 시 POPO 사용자명을 노출하는 것은 엄격히 금지되며, 이를 위반할 경우 POPO 계정이 삭제될 수도 있습니다. - - - - - 6. 서비스 이용 라이선스 - - - 회사는 사용자에게 서비스의 일부로 제공되는 소프트웨어에 대한 개인적이고, - 전 세계적이며, 양도 불가능하며, 사용료 없이 이용 가능한 비독점적 라이선스 사용 권한을 부여합니다. - 해당 라이선스는 본 이용약관에서 허용하는 범위 내에서 회사 서비스의 혜택을 누리기 위한 목적으로만 제공됩니다. - - - 1. 계정 정보: 서비스를 이용하려면 POPO 계정을 생성해야 합니다. - 로그인 자격증명에 대한 보안 및 계정을 통해 이루어진 모든 행위에 대한 책임은 본인에게 있습니다. - 사용자는 POPO 서비스와 관련한 프로그램, 소프트웨어의 전체 또는 일부를 복제, 재생산, 재게시, 변형, - 다운로드, 전송, 수정, 전시, 역설계, 판매 및 판촉, 임대, 대여, 양도, 분배, 라이선스, 서브라이선스, - 부당 이용 등의 행위를 할 수 없습니다. - - - - - 7. 회사의 권리 - - - 본 서비스에 대한 모든 소유권 및 권리, 지분(사용자가 제공한 콘텐츠는 제외)은 회사 및 회사 라이선스의 독점적 재산입니다. - 서비스는 저작권, 상표권 및 기타 법률의 보호를 받으며, 본 이용약관의 어떠한 조항도 회사의 상호 및 상표권, 로고, 도메인명, - 기타 고유한 브랜드 특징을 이용할 수 있는 권한을 부여하지 않습니다. - 회사 및 서비스에 관한 피드백, 의견 및 제안은 사용자의 자발적 의지로 제공되는 것이며, 회사에서 적합하다고 판단할 경우, - 제공 회사자에게 통지하지 않고도 해당 의견, 피드백 및 제안을 자유롭게 사용할 수 있습니다. - - - - - 8. 광고의 게재 - - - 회사는 회사 서비스의 운영과 관련하여 서비스 화면에 직접 또는 제휴 관계에 있는 제3자를 통해 광고를 게재할 수 있습니다. - - - - - - 9. 유료서비스의 내용 등의 표시 - - - 회사는 다음 사항을 해당 유료서비스의 이용초기화면이나 FAQ 등에 사용자가 알기 쉽게 표시합니다. - - - 1) 유료서비스의 명칭 또는 제호 - - - 2) 유료서비스 주체의 성명(법인인 경우는 법인의 명칭), 주소, 전화번호 - - - 3) 유료서비스의 내용, 이용방법, 이용료, 기타 이용조건 - - - 4) 회사의 유료서비스의 이용가능기기 및 이용에 필요한 최소한의 기술사항은 권장사양정보에 따릅니다. - - - 5) 회사는 유료서비스를 제공함에 있어 유료서비스의 교환·반품·보증과 그 대금 환불의 조건 및 절차에 관한 사항을 제공합니다. - - - 6) 회사의 정책 및 제1항의 결제방법 제공자가 정한 기준에 따라 사용자의 월별 누적 결제액 및 유료서비스 구매한도가 제한될 수 있습니다. - 해당 기준을 초과한 경우 유료서비스의 추가 이용은 불가능할 수 있습니다. - - - - - - 10. 사용기간 등 - - - 유료서비스의 사용기간 또는 유효기간은 계약 당시 표시한 바에 따릅니다. 해당 기간이 경과한 유료서비스는 이용권한이 소멸될 수 있습니다. - - - - - - 11. 재화등의 하자에 의한 피해보상 - - - 유료서비스의 하자 등에 의한 사용자 피해보상은 콘텐츠이용자보호지침에서 정한 바에 따릅니다. - - - - - 12. 저작권 정책 - - - 1) 본인의 콘텐츠가 정보통신망법 및 저작권법 등 관련법에 위반되는 내용을 포함하는 경우, - 관련법이 정한 절차에 따라 해당 "게시물"의 게시중단 및 삭제 등을 요청할 수 있으며, - 회사는 관련법에 따라 조치를 취하여야 합니다. - - - 2) 회사는 전항에 따른 권리자의 요청이 없는 경우라도 권리침해가 인정될 만한 사유가 있거나 - 기타 회사 정책 및 관련법에 위반되는 경우에는 관련법에 따라 해당 콘텐츠에 대해 임시조치 등을 취할 수 있으며, - 이에 대해 어떠한 책임도 지지 않습니다. 회사는 필요한 경우, 여러 차례 반복해서 저작권을 침해하는 사용자가 있다면, - 해당 계정을 종료시킬 수 있습니다. - - - 3) 본 조에 따른 세부절차는 "정보통신망법" 및 "저작권법"이 규정한 범위 내에서 회사가 정한 게시중단요청서비스에 따릅니다. - - - - - - 13. 면책 조항 - - - 1) 서비스 이용 과정에서 불쾌하고, 선정적이며, 모욕적인 자료에 노출될 수 있으며, - 서비스에 접근하고 이를 이용함으로써 이러한 위험 요소를 받아들이는 것에 동의합니다. - 회사의 웹사이트 또는 서비스에 노출되는 콘텐츠는 회사의 의견을 반영한 것이 아닐 수도 있으며, - 서비스의 사용자가 게시한 어떠한 콘텐츠도 지원하거나 지지하지 않습니다. - - - 2) 회사는 사용자의 콘텐츠를 안전하게 보호하기 위해 합당한 조치를 시행하고 있으나, - 해당 콘텐츠의 노출로 인해 발생할 수 있는 모든 위험을 100% 완벽하게 예방할 수는 없습니다. - - - 3) 면책 조항: 관련 법률에서 허용하는 최대 범위 내에서 회사의 서비스 및 - 웹사이트, 앱, 콘텐츠, 기타 모든 자료는 어떠한 명시적, 묵시적, 법적 보증 없이 - "있는 그대로" 사용자에게 제공됩니다. 회사는 (1) 서비스 및 자료가 사용자의 요구사항에 부합하거나 지속적으로 중단 없이, - 적시에, 안전하게, 오류 없이 이용 가능하며, (2) 웹사이트, 서비스, 자료의 이용을 통해 획득한 결과가 효과적이며, - 정확하고, 신뢰할 수 있으며, (3) 웹사이트, 서비스, 자료에서 발견되는 모든 오류 및 결함을 즉시 해결할 수 있음을 보증하지 않습니다. - - - - - - 14. 책임 제한 - - - 법률에서 금지하는 경우를 제외하고, 회사 및 회사의 공급업체, - 각각의 임원, 이사, 직원, 대리인(이하 "회사 측")은 (1) 서비스 이용 및 이용 불능, - (2) 서비스 제공 및 서비스를 통해 이용 가능한 자료, (3) 서비스 사용자의 행위로 말미암아 발생하는 - 간접적, 특별적, 징벌적, 부수적, 모범적, 결과적 손해에 대하여 어떠한 책임도 지지 않습니다. - - - - - - 15. 회사와의 분쟁 해결 - - - 1) 서면으로 달리 정하지 않는 한, 회사와 분쟁이 발생하는 경우, 제소 당시의 사용자의 주소에 의하고, - 주소가 없는 경우 거소를 관할하는 지방법원의 전속관할로 합니다. - 단, 제소 당시 사용자의 주소 또는 거소가 명확하지 아니한 경우의 관할법원은 민사소송법에 따라 정합니다. - - - 2) 해외에 주소나 거소가 있는 사용자의 경우 회사와 사용자간 발생한 분쟁에 관한 소송은 전항에도 불구하고 대한민국 서울중앙지방법원을 관할법원으로 합니다. - - - 3) 면책 조항: 회사와 사용자는 국제 물품 매매 계약에 관한 유엔 협약상 책임과 권리를 부인하며, 본 서비스의 사용에 있어 이를 적용하지 않기로 합의합니다. - - - - - 16. 종료 - - - 1) 사용자는 언제든지 서비스 이용을 중단할 수 있습니다. - - - 2) 회사는 서비스의 기능을 언제든지 추가, 수정 및 삭제할 수 있습니다. - 또한, 서비스의 제공을 일시 또는 영구적으로 중단하거나 새로운 제한 사항을 추가할 수도 있습니다. - - - 3) 사용자 계정의 사용이 종료되더라도, 지불 의무는 그대로 유효합니다. - - - 4) 서비스가 종료 또는 중단되는 경우, 회사는 사용자에게 이를 알리기 위해 합당한 노력을 기울이고, 사용자의 콘텐츠를 복구할 수 있도록 협조합니다. - - - - - 17. 일반 조항 - - - 1) 분리 조항: 법원의 판결을 통해 본 이용약관의 일부 조항이 집행이 불가능하거나 실효되더라도 나머지 조항은 유효하게 적용됩니다. - - - 2) 권리불포기: 회사가 본 이용약관을 집행하지 않거나 집행을 유예하였더라도 이는 본 약관의 집행 권리를 포기하는 것으로 간주되지 않습니다. - - - 3) 양도: 회사의 서면 동의 없이 사용자는 본 이용약관에서 정한 권리 및 의무를 타인에게 양도할 수 없습니다. - 단, 인수 합병 및 서비스 매각이 발생하는 경우, 회사는 사용자의 동의 없이 사용자에 가지는 회사의 권리 및 의무를 양도할 수 있습니다. - - - 4) 완전합의: 본 이용약관은 서비스에 관한 회사와 사용자 간의 완전하고 독점적인 합의를 나타내며, - 서비스와 관련하여 이전에 체결된 모든 계약을 대체합니다. 회사는 때때로 본 이용약관을 수정할 수 있으며, - 독자적 결정에 의거 수정 사항이 중대하다고 판단하는 경우, 웹페이지 배너 또는 통지 유형에 따라 적절한 수단을 사용하여 사용자에게 고지합니다. - 사용자가 수정 사항이 적용된 후에도 서비스를 계속 이용하는 경우, 변경 후의 이용약관에 동의를 한 것으로 간주됩니다. - - - - - ); -} - -const Containter = styled.div` - width: 100%; - height: 100%; - padding: 1rem 1rem; - display: flex; - flex-direction: column; - gap: 20px; - overflow: auto; -`; - -const Title = styled.p` - font-size: 1.2rem; - line-height: 1.2; - font-weight: bold; - color: ${({ theme }) => theme.color.text.title01}; -`; - -const Typograpy = styled.p` - font-size: 0.9rem; - line-height: 1.5; - color: ${({ theme }) => theme.color.text.title01}; -`; - -const TosContainer = styled.div` - width: 100%; - display: flex; - flex-direction: column; - gap: 10px; -`; - -// 1조 -// 1항 - -// ul diff --git a/src/components/common/Checkbox.test.tsx b/src/components/common/Checkbox.test.tsx new file mode 100644 index 0000000..3a298a7 --- /dev/null +++ b/src/components/common/Checkbox.test.tsx @@ -0,0 +1,36 @@ +import { screen } from '@testing-library/react'; + +import { renderWithProviders } from '@/utils/testHelper'; + +import Checkbox from './Checkbox'; + +jest.mock('usehooks-ts', () => ({ + useDarkMode: () => ({ isDarkMode: false }), +})); + +describe('Checkbox', () => { + const onChange = jest.fn(); + + const renderCheckbox = () => renderWithProviders( + , + ); + + it('체크박스 텍스트를 나타낸다.', () => { + given('checked', () => false); + renderCheckbox(); + + expect(screen.getByText(/체크박스/)).toBeInTheDocument(); + }); + + it('체크박스를 클릭하면 onChange 함수가 실행된다.', () => { + given('checked', () => false); + renderCheckbox(); + + screen.getByText(/체크박스/).click(); + expect(onChange).toHaveBeenCalled(); + }); +}); diff --git a/src/components/common/Checkbox.tsx b/src/components/common/Checkbox.tsx new file mode 100644 index 0000000..2497cc5 --- /dev/null +++ b/src/components/common/Checkbox.tsx @@ -0,0 +1,77 @@ +import styled from 'styled-components'; +import { useDarkMode } from 'usehooks-ts'; + +import CheckIconLight from '@/lib/assets/check-icon.svg'; +import CheckIconDark from '@/lib/assets/check-icon-dark.svg'; +import UncheckIcon from '@/lib/assets/check-icon-inactive.svg'; + +export type CheckboxProps = React.PropsWithChildren<{ + checked: boolean, + text:string, + onChange:(value:boolean)=>void +}>; + +export default function CheckBox({ + checked, text, onChange, children, +}: CheckboxProps) { + const { isDarkMode } = useDarkMode(); + const { CheckedIcon, checkedBorderColor, checkedTextColor } = isDarkMode ? { + CheckedIcon: CheckIconDark, + checkedBorderColor: '#FFFFFF', + checkedTextColor: '#FFFFFF', + } : { + CheckedIcon: CheckIconLight, + checkedBorderColor: '#000000', + checkedTextColor: '#000000', + }; + + const CheckIcon = checked ? CheckedIcon : UncheckIcon; + const borderColor = checked ? checkedBorderColor : '#A0A0A0'; + const textColor = checked ? checkedTextColor : '#A0A0A0'; + + return ( + + { + onChange(!checked); + }} + > + {checked ? : } + {text} + + {children && ( + + )} + {children} + + ); +} + +const Divider = styled.div<{ $borderColor:string }>` + width: 100%; + height: 1px; + background-color: ${({ $borderColor }) => $borderColor} +`; + +const Container = styled.div<{ $borderColor:string }>` + display: flex; + flex-direction: column; + ${({ $borderColor }) => `border: 1px solid ${$borderColor};`} +`; + +const CheckboxContainer = styled.div` + display: flex; + align-items: center; + padding: 10px; + gap:8px; +`; + +const LabelText = styled.label<{ $textColor:string }>` + font-size: 14px; + line-height: 16px; + color: ${({ $textColor }) => ($textColor)}; +`; diff --git a/src/components/common/Header.test.tsx b/src/components/common/Header.test.tsx new file mode 100644 index 0000000..56dc877 --- /dev/null +++ b/src/components/common/Header.test.tsx @@ -0,0 +1,47 @@ +import { usePathname, useRouter } from 'next/navigation'; + +import { fireEvent, screen } from '@testing-library/react'; + +import { renderWithProviders } from '@/utils/testHelper'; + +import Header from './Header'; + +jest.mock('next/navigation', () => ({ + usePathname: jest.fn(), + useRouter: jest.fn(), +})); + +describe('Header', () => { + const mockBack = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + + (usePathname as jest.Mock).mockImplementation(() => given.pathname); + (useRouter as jest.Mock).mockImplementation(() => ({ + back: mockBack, + })); + }); + + const rendeHeader = () => renderWithProviders(
); + + context('제목이 설정 일 때', () => { + it('설정 타이틀이 보인다.', () => { + rendeHeader(); + + expect(screen.getByText('설정')).toBeInTheDocument(); + }); + }); + + context('뒤로 가기 버튼을 누르면', () => { + given('pathname', () => '/setting/tos'); + + it('페이지가 뒤로간다.', () => { + rendeHeader(); + + fireEvent.click(screen.getByTestId('back-button')); + + expect(mockBack).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/components/common/Header.tsx b/src/components/common/Header.tsx new file mode 100644 index 0000000..f962300 --- /dev/null +++ b/src/components/common/Header.tsx @@ -0,0 +1,50 @@ +'use client'; + +import { useRouter } from 'next/navigation'; + +import styled from 'styled-components'; + +import BackIcon from '@/lib/assets/back-icon.svg'; + +type Props = { + title: string; +}; + +export default function Header({ title }:Props) { + const router = useRouter(); + + const onBack = () => router.back(); + + return ( + + + {title} + + ); +} + +const Container = styled.div` + position: relative; + display: flex; + width: 100%; + min-height: 72px; + height: 72px; + justify-content: center; + align-items: center; +`; + +const BackButton = styled(BackIcon)` + position: absolute; + left: 16px; + top: 21px; + path{ + fill: ${({ theme }) => theme.color.text.title02}; + } +`; + +const Title = styled.div` + font-weight: 500; + font-size: 18px; + line-height: 26px; + color: ${({ theme }) => theme.color.text.title01}; +`; diff --git a/src/components/layout/SettingHeader.tsx b/src/components/layout/SettingHeader.tsx index bf3381e..adb6c4e 100644 --- a/src/components/layout/SettingHeader.tsx +++ b/src/components/layout/SettingHeader.tsx @@ -1,10 +1,8 @@ 'use client'; -import { usePathname, useRouter } from 'next/navigation'; +import { usePathname } from 'next/navigation'; -import styled from 'styled-components'; - -import BackIcon from '@/lib/assets/back-icon.svg'; +import Header from '../common/Header'; const settingTitle:{ [key: string]: string } = { '/setting': '설정', @@ -21,42 +19,10 @@ const settingTitle:{ [key: string]: string } = { export default function SettingHeader() { const pathname = usePathname(); - const router = useRouter(); const title = settingTitle[pathname || '/setting']; - const onBack = () => router.back(); - return ( - - - {title} - +
); } - -const Container = styled.div` - position: relative; - display: flex; - width: 100%; - min-height: 72px; - height: 72px; - justify-content: center; - align-items: center; -`; - -const BackButton = styled(BackIcon)` - position: absolute; - left: 16px; - top: 21px; - path{ - fill: ${({ theme }) => theme.color.text.title02}; - } -`; - -const Title = styled.div` - font-weight: 500; - font-size: 18px; - line-height: 26px; - color: ${({ theme }) => theme.color.text.title01}; -`; diff --git a/src/components/relation/index.tsx b/src/components/relation/index.tsx index 7b7f293..a8e2661 100644 --- a/src/components/relation/index.tsx +++ b/src/components/relation/index.tsx @@ -3,12 +3,14 @@ import { useState } from 'react'; import { useSearchParams } from 'next/navigation'; import { styled } from 'styled-components'; +import { useDarkMode } from 'usehooks-ts'; import UserCard from '@/components/search/UserCard'; import useGetInfiniteFollow, { GET_INFINITE_FOLLOW_KEY } from '@/hooks/api/useGetInfiniteRelations'; import useToggleRelation from '@/hooks/api/useToggleRelation'; export default function Relation() { + const { isDarkMode } = useDarkMode(); const searchParams = useSearchParams(); const search = searchParams?.get('defaultType'); const [type, setType] = useState<'follower' | 'followee'>((search ?? 'follower') as ('follower' | 'followee')); @@ -58,7 +60,7 @@ const TabContainer = styled.div` const TabItem = styled.div<{ active?: boolean }>` font-size: 36px; font-weight: 200; - color: ${({ active }) => (active ? '#000' : '#BDBDBD')}; + color: ${({ theme, active }) => (active ? theme.color.text.title01 : theme.color.text.subTitle02)}; cursor: pointer; `; diff --git a/src/components/signup/SignUpButton.test.tsx b/src/components/signup/SignUpButton.test.tsx index 1e6d1a2..c621335 100644 --- a/src/components/signup/SignUpButton.test.tsx +++ b/src/components/signup/SignUpButton.test.tsx @@ -16,7 +16,7 @@ describe('StepButton', () => { }); context('회원가입 첫 번째 페이지일 경우', () => { - given('step', () => 0); + given('step', () => 1); it('"이메일로 인증번호 전송"버튼을 화면에 보여준다.', () => { renderStepButton(); @@ -25,7 +25,7 @@ describe('StepButton', () => { }); context('회원가입 두 번째 페이지일 경우', () => { - given('step', () => 1); + given('step', () => 2); it('"확인"버튼을 화면에 보여준다.', () => { renderStepButton(); @@ -34,7 +34,7 @@ describe('StepButton', () => { }); context('회원가입 마지막 페이지일 경우', () => { - given('step', () => 7); + given('step', () => 8); it('"가입 완료"버튼을 화면에 보여준다.', () => { renderStepButton(); @@ -43,7 +43,7 @@ describe('StepButton', () => { }); context('그 외의 페이지의 경우', () => { - given('step', () => 5); + given('step', () => 6); it('"다음"버튼을 화면에 보여준다.', () => { renderStepButton(); diff --git a/src/components/signup/SignUpButton.tsx b/src/components/signup/SignUpButton.tsx index 679f337..9e0b1c1 100644 --- a/src/components/signup/SignUpButton.tsx +++ b/src/components/signup/SignUpButton.tsx @@ -8,13 +8,13 @@ type SignUpButtonProps = { }; const getButtonText = (step: number) => { - if (step === 0) { + if (step === 1) { return '이메일로 인증번호 전송'; } - if (step === 1) { + if (step === 2) { return '확인'; } - if (step === 7) { + if (step === 8) { return '가입 완료'; } return '다음'; diff --git a/src/components/signup/SignUpForm.test.tsx b/src/components/signup/SignUpForm.test.tsx index 0ed6d55..3691921 100644 --- a/src/components/signup/SignUpForm.test.tsx +++ b/src/components/signup/SignUpForm.test.tsx @@ -10,11 +10,12 @@ describe('SignUpForm', () => { , ); context('회원가입 첫 번째 화면일 때', () => { - given('step', () => 0); + given('step', () => 1); it('이메일 입력 필드를 화면에 보여준다.', () => { renderSignUpForm(); @@ -24,7 +25,7 @@ describe('SignUpForm', () => { }); context('회원가입 네 번째 화면일 때', () => { - given('step', () => 3); + given('step', () => 4); it('이름 입력 필드를 화면에 보여준다.', () => { renderSignUpForm(); diff --git a/src/components/signup/SignUpForm.tsx b/src/components/signup/SignUpForm.tsx index cbd2f45..4f6fd19 100644 --- a/src/components/signup/SignUpForm.tsx +++ b/src/components/signup/SignUpForm.tsx @@ -12,11 +12,16 @@ import GenderSelector from './StepField/GenderSelector'; import NameField from './StepField/NameField'; import PasswordField from './StepField/PasswordField'; import SchoolField from './StepField/SchoolField'; +import TosField from './StepField/TosField'; import YearField from './StepField/YearField'; type SignUpFormProps = { step: number; formData:{ + tosAgree: { + value: boolean; + onChangeTosAgree: (agree:boolean) => void; + } email: InputItem; certificationNumber: InputItem; password: InputItem; @@ -38,25 +43,27 @@ type SignUpFormProps = { export default function SignUpForm({ step, formData, onResend }:SignUpFormProps) { const { - email, certificationNumber, password, passwordConfirm, name, year, grade, gender, school, + tosAgree, email, certificationNumber, password, + passwordConfirm, name, year, grade, gender, school, } = formData; const renderData = [ - , + , + , <> - + 인증번호 재전송 , - , - , - , + , + , + , , - , - , + , + , ]; return ( diff --git a/src/components/signup/SignUpTitle.test.tsx b/src/components/signup/SignUpTitle.test.tsx index cdbfd18..ecd43a5 100644 --- a/src/components/signup/SignUpTitle.test.tsx +++ b/src/components/signup/SignUpTitle.test.tsx @@ -12,57 +12,66 @@ describe('SignUpTitle', () => { it('이메일 입력 타이틀을 화면에 보여준다.', () => { renderStepTitle(); - expect(screen.getByText(/가입할 이메일을/)).toBeInTheDocument(); + expect(screen.getByText(/약관을 확인/)).toBeInTheDocument(); }); }); context('회원가입 두 번째 페이지일 경우', () => { given('step', () => 1); - it('인증번호 입력 타이틀을 화면에 보여준다.', () => { + it('이메일 입력 타이틀을 화면에 보여준다.', () => { renderStepTitle(); - expect(screen.getByText(/이메일로 받은 인증번호를/)).toBeInTheDocument(); + expect(screen.getByText(/가입할 이메일을/)).toBeInTheDocument(); }); }); context('회원가입 세 번째 페이지일 경우', () => { given('step', () => 2); - it('비밀번호 입력 타이틀을 화면에 보여준다.', () => { + it('인증번호 입력 타이틀을 화면에 보여준다.', () => { renderStepTitle(); - expect(screen.getByText(/로그인에 사용할 비밀번호를/)).toBeInTheDocument(); + expect(screen.getByText(/이메일로 받은 인증번호를/)).toBeInTheDocument(); }); }); context('회원가입 네 번째 페이지일 경우', () => { given('step', () => 3); - it('이름 입력 타이틀을 화면에 보여준다.', () => { + it('비밀번호 입력 타이틀을 화면에 보여준다.', () => { renderStepTitle(); - expect(screen.getByText(/이름을/)).toBeInTheDocument(); + expect(screen.getByText(/로그인에 사용할 비밀번호를/)).toBeInTheDocument(); }); }); context('회원가입 다섯 번째 페이지일 경우', () => { given('step', () => 4); - it('년도 입력 타이틀을 화면에 보여준다.', () => { + it('이름 입력 타이틀을 화면에 보여준다.', () => { renderStepTitle(); - expect(screen.getByText(/태어난 년도를/)).toBeInTheDocument(); + expect(screen.getByText(/이름을/)).toBeInTheDocument(); }); }); context('회원가입 여섯 번째 페이지일 경우', () => { given('step', () => 5); - it('성별 선택 타이틀을 화면에 보여준다.', () => { + it('년도 입력 타이틀을 화면에 보여준다.', () => { renderStepTitle(); - expect(screen.getByText(/성별을/)).toBeInTheDocument(); + expect(screen.getByText(/태어난 년도를/)).toBeInTheDocument(); }); }); context('회원가입 일곱 번째 페이지일 경우', () => { given('step', () => 6); + it('성별 선택 타이틀을 화면에 보여준다.', () => { + renderStepTitle(); + + expect(screen.getByText(/성별을/)).toBeInTheDocument(); + }); + }); + + context('회원가입 여덟 번째 페이지일 경우', () => { + given('step', () => 7); it('학교 선택 타이틀을 화면에 보여준다.', () => { renderStepTitle(); @@ -71,7 +80,7 @@ describe('SignUpTitle', () => { }); context('회원가입 마지막 페이지일 경우', () => { - given('step', () => 7); + given('step', () => 8); it('입력한 정보 확인 타이틀을 화면에 보여준다.', () => { renderStepTitle(); diff --git a/src/components/signup/SignUpTitle.tsx b/src/components/signup/SignUpTitle.tsx index 2073501..759547a 100644 --- a/src/components/signup/SignUpTitle.tsx +++ b/src/components/signup/SignUpTitle.tsx @@ -5,6 +5,7 @@ type SignUpTitleProps = { }; const stepTitles = [ + '약관을 확인해주세요', '가입할 이메일을\n입력해주세요', '이메일로 받은 인증번호를\n입력해주세요', '로그인에 사용할 비밀번호를\n입력해주세요', diff --git a/src/components/signup/StepField/TosField.tsx b/src/components/signup/StepField/TosField.tsx new file mode 100644 index 0000000..141f84c --- /dev/null +++ b/src/components/signup/StepField/TosField.tsx @@ -0,0 +1,42 @@ +import Link from 'next/link'; + +import { styled } from 'styled-components'; + +import CheckBox from '@/components/common/Checkbox'; + +type Props = { + value: boolean; + onChange: (value:boolean)=>void; +}; + +export default function TosField({ value, onChange }:Props) { + return ( +
+ + + + 서비스 이용약관 + + + 개인정보 처리방침 + + + +
+ ); +} + +const Container = styled.div` + width: max-content; + padding: 10px; + gap: 12px; + display: flex; + flex-direction: column; +`; + +const UnderlineText = styled.label` + font-size: 14px; + line-height: 16px; + color: ${({ theme }) => theme.color.text.subTitle01}; + text-decoration: underline; +`; diff --git a/src/components/signup/index.test.tsx b/src/components/signup/index.test.tsx index c6aab7d..324f8f9 100644 --- a/src/components/signup/index.test.tsx +++ b/src/components/signup/index.test.tsx @@ -23,7 +23,7 @@ describe('SignUp', () => { const renderSignUp = () => renderWithProviders(); it('onSubmit 호출', () => { - given('step', () => 0); + given('step', () => 1); renderSignUp(); const button = screen.getByRole('button', { name: '이메일로 인증번호 전송' }); diff --git a/src/components/tos/index.test.tsx b/src/components/tos/index.test.tsx index 81947c5..26379dc 100644 --- a/src/components/tos/index.test.tsx +++ b/src/components/tos/index.test.tsx @@ -33,7 +33,7 @@ describe('Tos', () => { fireEvent.click(settingItem); - expect(routerPush).toHaveBeenCalledWith('/setting/tos/use'); + expect(routerPush).toHaveBeenCalledWith('/tos/use'); }); }); @@ -47,7 +47,7 @@ describe('Tos', () => { fireEvent.click(settingItem); - expect(routerPush).toHaveBeenCalledWith('/setting/tos/privacy'); + expect(routerPush).toHaveBeenCalledWith('/tos/privacy'); }); }); }); diff --git a/src/components/tos/index.tsx b/src/components/tos/index.tsx index 520685b..b4657bb 100644 --- a/src/components/tos/index.tsx +++ b/src/components/tos/index.tsx @@ -11,13 +11,13 @@ export default function Tos() { router.push('/setting/tos/use')} + onClick={() => router.push('/tos/use')} showArrow /> router.push('/setting/tos/privacy')} + onClick={() => router.push('/tos/privacy')} showArrow /> diff --git a/src/fixtures/signupField.ts b/src/fixtures/signupField.ts index 12b8c0b..7b152c0 100644 --- a/src/fixtures/signupField.ts +++ b/src/fixtures/signupField.ts @@ -1,6 +1,7 @@ import testRegister from '@/fixtures/testRegister'; const signupField = { + tosAgree: { value: true, onChangeTosAgree: jest.fn() }, year: { register: { ...testRegister, name: 'year' }, value: 1997, onClickReset: jest.fn() }, grade: { register: { ...testRegister, name: 'grade' }, value: 1, onClickReset: jest.fn() }, password: { register: { ...testRegister, name: 'password' }, value: '1234', onClickReset: jest.fn() }, diff --git a/src/hooks/useSignUpForm.test.tsx b/src/hooks/useSignUpForm.test.tsx index d9a1ebf..dffc879 100644 --- a/src/hooks/useSignUpForm.test.tsx +++ b/src/hooks/useSignUpForm.test.tsx @@ -87,7 +87,7 @@ describe('useSignUpForm', () => { ); describe('STEP 별 Submit TEST', () => { - describe('step0', () => { + describe('step1', () => { context('이메일이 유효하지 않은 경우', () => { given('signUpSendEmail', () => Promise.reject()); it('실패 팝업을 띄운다.', async () => { @@ -97,6 +97,10 @@ describe('useSignUpForm', () => { await result.current.onSubmit(); }); + await act(async () => { + await result.current.onSubmit(); + }); + expect(result.current.popInfo.show).toEqual(true); act(() => { @@ -118,12 +122,16 @@ describe('useSignUpForm', () => { await result.current.onSubmit(); }); - expect(result.current.step).toEqual(1); + await act(async () => { + await result.current.onSubmit(); + }); + + expect(result.current.step).toEqual(2); }); }); }); - describe('step1', () => { + describe('step2', () => { given('signUpSendEmail', () => ({ code: 0, message: 'ok', @@ -141,6 +149,10 @@ describe('useSignUpForm', () => { await result.current.onSubmit(); }); + await act(async () => { + await result.current.onSubmit(); + }); + expect(result.current.popInfo.show).toEqual(true); act(() => { @@ -167,12 +179,16 @@ describe('useSignUpForm', () => { await result.current.onSubmit(); }); - expect(result.current.step).toEqual(2); + await act(async () => { + await result.current.onSubmit(); + }); + + expect(result.current.step).toEqual(3); }); }); }); - describe('step < 7', () => { + describe('step <', () => { beforeEach(() => { given('signUpSendEmail', () => ({ code: 0, @@ -194,13 +210,17 @@ describe('useSignUpForm', () => { await result.current.onSubmit(); }); + await act(async () => { + await result.current.onSubmit(); + }); + Array.from({ length: 5 }).forEach(() => { act(() => { result.current.onSubmit(); }); }); - expect(result.current.step).toEqual(7); + expect(result.current.step).toEqual(8); }); }); @@ -226,6 +246,11 @@ describe('useSignUpForm', () => { await act(async () => { await result.current.onSubmit(); + }); + + await act(async () => { + await result.current.onSubmit(); + result.current.formData.tosAgree.onChangeTosAgree(true); result.current.formData.gender.onChangeGender('FEMALE'); result.current.formData.school.onChangeSchool({ id: 106, @@ -257,6 +282,11 @@ describe('useSignUpForm', () => { it('실패 팝업을 띄운다.', async () => { const { result } = renderSignUpFormHook(); + await act(async () => { + result.current.formData.tosAgree.onChangeTosAgree(true); + await result.current.onSubmit(); + }); + await act(async () => { await result.current.onSubmit(); }); diff --git a/src/hooks/useSignUpForm.ts b/src/hooks/useSignUpForm.ts index 35c316b..bdcfd1e 100644 --- a/src/hooks/useSignUpForm.ts +++ b/src/hooks/useSignUpForm.ts @@ -32,6 +32,7 @@ const useSignUpForm = () => { const [step, setStep] = useState(0); + const [tosAgree, setTosAgree] = useState(false); const [gender, setGender] = useState(null); const [school, setSchool] = useState(null); const [popInfo, setPopInfo] = useState(getDefaultPopInfo()); @@ -48,12 +49,12 @@ const useSignUpForm = () => { const signUp = useSignUpMutation(); const onSubmit = handleSubmit(() => { - if (step === 0) { + if (step === 1) { signUpSendEmailMutation.mutate({ email: watch('email'), }, { onSuccess: () => { - setStep(1); + setStep(2); }, onError: () => { setPopInfo({ @@ -67,13 +68,13 @@ const useSignUpForm = () => { return; } - if (step === 1) { + if (step === 2) { signUpAuthEmailMutation.mutate({ email: watch('email'), userCode: watch('certificationNumber'), }, { onSuccess: () => { - setStep(2); + setStep(3); }, onError: () => { setPopInfo({ @@ -87,7 +88,7 @@ const useSignUpForm = () => { return; } - if (step < 7) { + if (step < 8) { setStep((prev) => prev + 1); return; } @@ -131,29 +132,32 @@ const useSignUpForm = () => { const getActive = useCallback((currentStep: number) => { if (currentStep === 0) { - return getActiveCheck('email'); + return tosAgree !== false; } if (currentStep === 1) { - return getActiveCheck('certificationNumber'); + return getActiveCheck('email'); } if (currentStep === 2) { - return getActiveCheck('password') && getActiveCheck('passwordConfirm'); + return getActiveCheck('certificationNumber'); } if (currentStep === 3) { - return getActiveCheck('name'); + return getActiveCheck('password') && getActiveCheck('passwordConfirm'); } if (currentStep === 4) { - return getActiveCheck('year'); + return getActiveCheck('name'); } if (currentStep === 5) { - return gender !== null; + return getActiveCheck('year'); } if (currentStep === 6) { + return gender !== null; + } + if (currentStep === 7) { return school !== null && getActiveCheck('grade'); } return true; - }, [gender, getActiveCheck, school]); + }, [tosAgree, gender, getActiveCheck, school]); const onResend = () => { signUpSendEmailMutation.mutate({ @@ -173,6 +177,10 @@ const useSignUpForm = () => { return { step, formData: { + tosAgree: { + value: tosAgree, + onChangeTosAgree: (agree: boolean) => setTosAgree(agree), + }, email: { register: getDefaultRegister({ name: 'email' }), value: watch('email'), diff --git a/src/lib/assets/check-icon-dark.svg b/src/lib/assets/check-icon-dark.svg new file mode 100644 index 0000000..6550e29 --- /dev/null +++ b/src/lib/assets/check-icon-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/lib/assets/check-icon-inactive.svg b/src/lib/assets/check-icon-inactive.svg new file mode 100644 index 0000000..1daf9d8 --- /dev/null +++ b/src/lib/assets/check-icon-inactive.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/lib/assets/check-icon.svg b/src/lib/assets/check-icon.svg new file mode 100644 index 0000000..ae7d43f --- /dev/null +++ b/src/lib/assets/check-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/middleware.ts b/src/middleware.ts index 155281f..3dc5c48 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -9,7 +9,7 @@ export async function middleware(req:NextRequest) { const { pathname } = req.nextUrl; - if (/^(\/signin|\/signup|\/find-password)$/.test(pathname)) { + if (/^(\/signin|\/signup|\/find-password|\/tos\/use|\/tos\/privacy)$/.test(pathname)) { if (token) { return NextResponse.redirect(new URL('/', req.url)); } @@ -27,6 +27,8 @@ export const config = { '/signup', '/find-password', '/find-following', + '/tos/privacy', + '/tos/use', '/profile-image', '/', '/alarm', @@ -38,7 +40,5 @@ export const config = { '/setting/tos', '/setting/change-password', '/setting/remove-account', - '/setting/tos/use', - '/setting/tos/privacy', ], };