├── src ├── stores │ └── .gitkeep ├── components │ ├── register │ │ ├── Attraction │ │ │ ├── index.tsx │ │ │ ├── AttractionLand.tsx │ │ │ └── AttractionJeju.tsx │ │ ├── Button.tsx │ │ ├── PlaceSearchBox.tsx │ │ ├── SelectHomeImage │ │ │ ├── UploadImage.tsx │ │ │ ├── index.tsx │ │ │ └── SelectImage.tsx │ │ ├── PeopleInformation.tsx │ │ ├── CohabitInformation.tsx │ │ ├── LinkShare.tsx │ │ ├── HouseType.tsx │ │ ├── HomePrecautions.tsx │ │ ├── PlaceInputContainer.tsx │ │ ├── Counter.tsx │ │ ├── HomeInformation.tsx │ │ └── BottomSheet.tsx │ ├── common │ │ ├── ImageDiv.tsx │ │ ├── SEO.tsx │ │ ├── CloseHeader.tsx │ │ ├── DropZone.tsx │ │ ├── CheckboxButton.tsx │ │ └── Modal.tsx │ └── notification │ │ └── Notification.tsx ├── services │ └── libs │ │ └── api.ts ├── pages │ ├── search │ │ └── index.tsx │ ├── _app.tsx │ ├── _document.tsx │ ├── notification │ │ └── index.tsx │ ├── index.tsx │ ├── detail │ │ ├── [location].tsx │ │ └── info │ │ │ └── [id].tsx │ └── register │ │ └── index.tsx ├── hooks │ ├── useModal.tsx │ └── useToast.tsx └── styles │ └── globalStyle.ts ├── public ├── favicon.ico └── assets │ ├── images │ ├── img_main.png │ ├── index.ts │ ├── img_ocean_small.svg │ ├── img_ocean.svg │ ├── img_upload.svg │ ├── img_road_small.svg │ ├── img_road.svg │ ├── img_farm_small.svg │ ├── img_farm.svg │ ├── img_swimming.svg │ ├── img_swimming_small.svg │ ├── img_exercise_small.svg │ ├── img_exercise.svg │ ├── img_culture_small.svg │ ├── img_activity_small.svg │ └── img_hot_place_small.svg │ └── icons │ ├── ic_line.svg │ ├── ic_check_empty.svg │ ├── ic_back.svg │ ├── ic_minus_active.svg │ ├── ic_minus_blue.svg │ ├── ic_minus_gray.svg │ ├── ic_plus_active.svg │ ├── ic_plus_blue.svg │ ├── ic_plus_gray.svg │ ├── ic_close.svg │ ├── ic_check_active.svg │ ├── ic_close_bg.svg │ ├── ic_detail_back.svg │ ├── ic_like.svg │ ├── ic_location.svg │ ├── ic_mark.svg │ ├── ic_location_colored.svg │ ├── ic_calendar.svg │ ├── index.ts │ ├── ic_brand.svg │ ├── ic_notice.svg │ ├── ic_alert.svg │ ├── ic_home.svg │ └── ic_kakao.svg ├── .babelrc ├── .github ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE │ └── feature_request.md ├── .prettierrc ├── next.config.js ├── .gitignore ├── tsconfig.json ├── .eslintrc.json ├── package.json └── README.md /src/stores/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NiZipNaeZip/frontend/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/assets/images/img_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NiZipNaeZip/frontend/HEAD/public/assets/images/img_main.png -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["next/babel"], 3 | "plugins": [["styled-components", { "ssr": true, "displayName": true, "preprocess": false }]] 4 | } 5 | -------------------------------------------------------------------------------- /src/components/register/Attraction/index.tsx: -------------------------------------------------------------------------------- 1 | function Attraction() { 2 | return
Attraction
; 3 | } 4 | 5 | export default Attraction; 6 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## 🚩 관련 이슈 2 | - close #issue_number 3 | 4 | ## 📌 PR Point 5 | - 무슨 이유로 어떻게 코드를 변경했는지 6 | - 어떤 부분에 리뷰어가 집중해야 하는지 7 | 8 | ## 📸 스크린샷 9 | -------------------------------------------------------------------------------- /src/components/register/Attraction/AttractionLand.tsx: -------------------------------------------------------------------------------- 1 | function AttractionLand() { 2 | return
AttractionLand
; 3 | } 4 | 5 | export default AttractionLand; 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSameLine": true, 3 | "printWidth": 120, 4 | "semi": true, 5 | "singleQuote": true, 6 | "trailingComma": "all", 7 | "tabWidth": 2 8 | } 9 | -------------------------------------------------------------------------------- /public/assets/icons/ic_line.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/assets/icons/ic_check_empty.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/services/libs/api.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | export const client = axios.create({ 4 | baseURL: 'https://jipyo.link:8081', 5 | headers: { 6 | 'Content-Type': 'application/json', 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /public/assets/icons/ic_back.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | images: { 4 | domains: ['jipyo.link'], 5 | }, 6 | reactStrictMode: true, 7 | swcMinify: true, 8 | }; 9 | 10 | module.exports = nextConfig; 11 | -------------------------------------------------------------------------------- /public/assets/icons/ic_minus_active.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/assets/icons/ic_minus_blue.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/assets/icons/ic_minus_gray.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## ✨ Description 11 | 구현할 기능 작성 12 | 13 | ## ✅ To Do List 14 | - [ ] 작업 1 15 | - [ ] 작업 2 16 | - [ ] 작업 3 17 | -------------------------------------------------------------------------------- /public/assets/icons/ic_plus_active.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/assets/icons/ic_plus_blue.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/assets/icons/ic_plus_gray.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/assets/icons/ic_close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/assets/icons/ic_check_active.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/pages/search/index.tsx: -------------------------------------------------------------------------------- 1 | import SEO from '@src/components/common/SEO'; 2 | import PlaceSearchBox from '@src/components/register/PlaceSearchBox'; 3 | 4 | function Search() { 5 | return ( 6 | <> 7 | 8 | 9 | 10 | ); 11 | } 12 | 13 | export default Search; 14 | -------------------------------------------------------------------------------- /src/components/common/ImageDiv.tsx: -------------------------------------------------------------------------------- 1 | import Image, { ImageProps } from 'next/image'; 2 | 3 | function ImageDiv(props: ImageProps) { 4 | const { alt = '', className, ...rest } = props; 5 | 6 | return ( 7 |
8 | {alt} 9 |
10 | ); 11 | } 12 | 13 | export default ImageDiv; 14 | -------------------------------------------------------------------------------- /public/assets/icons/ic_close_bg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import type { AppProps } from 'next/app'; 2 | import GlobalStyle from '@src/styles/globalStyle'; 3 | import { RecoilRoot } from 'recoil'; 4 | 5 | function MyApp({ Component, pageProps }: AppProps) { 6 | return ( 7 | 8 | 9 | 10 | 11 | ); 12 | } 13 | 14 | export default MyApp; 15 | -------------------------------------------------------------------------------- /public/assets/icons/ic_detail_back.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /src/components/common/SEO.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head'; 2 | 3 | interface SEOProps { 4 | title: string; 5 | } 6 | 7 | function SEO(props: SEOProps) { 8 | const { title } = props; 9 | 10 | return ( 11 | 12 | {title} 13 | 14 | 15 | 16 | 17 | 18 | 19 | ); 20 | } 21 | 22 | export default SEO; 23 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "baseUrl": ".", 18 | "paths": { 19 | "@src/*": ["src/*"] 20 | } 21 | }, 22 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 23 | "exclude": ["node_modules"] 24 | } 25 | -------------------------------------------------------------------------------- /src/components/common/CloseHeader.tsx: -------------------------------------------------------------------------------- 1 | import { useRouter } from 'next/router'; 2 | import { icClose } from 'public/assets/icons'; 3 | import styled from 'styled-components'; 4 | import ImageDiv from './ImageDiv'; 5 | 6 | function CloseHeader() { 7 | const router = useRouter(); 8 | 9 | return ( 10 | 11 | 14 | 15 | ); 16 | } 17 | 18 | export default CloseHeader; 19 | 20 | const StCloseHeader = styled.div` 21 | padding: 16px 20px 17px 20px; 22 | height: 60px; 23 | 24 | .close { 25 | width: 27px; 26 | height: 27px; 27 | cursor: pointer; 28 | } 29 | `; 30 | -------------------------------------------------------------------------------- /public/assets/images/index.ts: -------------------------------------------------------------------------------- 1 | export { default as imgUpload } from './img_upload.svg'; 2 | export { default as imgAdd } from './img_add.svg'; 3 | export { default as imgOcean } from './img_ocean.svg'; 4 | export { default as imgExercise } from './img_exercise.svg'; 5 | export { default as imgFarm } from './img_farm.svg'; 6 | export { default as imgRoad } from './img_road.svg'; 7 | export { default as imgSwimming } from './img_swimming.svg'; 8 | export { default as imgOceanSmall } from './img_ocean_small.svg'; 9 | export { default as imgExerciseSmall } from './img_exercise_small.svg'; 10 | export { default as imgFarmSmall } from './img_farm_small.svg'; 11 | export { default as imgRoadSmall } from './img_road_small.svg'; 12 | export { default as imgSwimmingSmall } from './img_swimming_small.svg'; 13 | export { default as imgActivitySmall } from './img_activity_small.svg'; 14 | -------------------------------------------------------------------------------- /src/components/register/Button.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | interface IProps { 4 | name: string; 5 | handleClick: () => void; 6 | nextValid: boolean; 7 | } 8 | export default function Button(props: IProps) { 9 | const { name, handleClick, nextValid } = props; 10 | return ( 11 | 12 | {name} 13 | 14 | ); 15 | } 16 | 17 | const StButton = styled.button<{ disabled: boolean }>` 18 | width: 100%; 19 | max-width: 380px; 20 | height: 61px; 21 | padding: 17px 0; 22 | border-radius: 10px; 23 | margin-top: 8px; 24 | text-align: center; 25 | font-weight: 500; 26 | font-size: 17px; 27 | line-height: 27px; 28 | color: white; 29 | background-color: ${({ disabled }) => (disabled ? '#E9E9FF' : '#6765FF')}; 30 | cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')}; 31 | `; 32 | -------------------------------------------------------------------------------- /public/assets/icons/ic_like.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "node": true 6 | }, 7 | "parser": "@typescript-eslint/parser", 8 | "parserOptions": { 9 | "ecmaFeatures": { 10 | "jsx": true 11 | }, 12 | "ecmaVersion": "latest", 13 | "sourceType": "module" 14 | }, 15 | "plugins": ["@typescript-eslint"], 16 | "extends": [ 17 | "eslint:recommended", 18 | "plugin:prettier/recommended", 19 | "plugin:@typescript-eslint/recommended", 20 | "plugin:@next/next/recommended", 21 | "next/core-web-vitals", 22 | "prettier" 23 | ], 24 | "rules": { 25 | "prettier/prettier": ["error", { "endOfLine": "auto" }, { "usePrettierrc": true }], 26 | "react/react-in-jsx-scope": "off", 27 | "react/prop-types": "off", 28 | "react/display-name": "off", 29 | "no-unused-vars": "off", 30 | "@typescript-eslint/no-var-requires": 0, 31 | "@typescript-eslint/no-unused-vars": ["error"], 32 | "@typescript-eslint/explicit-module-boundary-types": "off" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@types/react-daum-postcode": "^1.6.1", 13 | "@types/react-slick": "^0.23.10", 14 | "axios": "^1.1.2", 15 | "next": "12.3.1", 16 | "react": "18.2.0", 17 | "react-daum-postcode": "^3.1.1", 18 | "react-dom": "18.2.0", 19 | "react-dropzone": "^14.2.3", 20 | "react-slick": "^0.29.0", 21 | "recoil": "^0.7.6", 22 | "slick-carousel": "^1.8.1", 23 | "styled-components": "^5.3.6", 24 | "styled-reset": "^4.4.2" 25 | }, 26 | "devDependencies": { 27 | "@types/node": "18.8.4", 28 | "@types/react": "18.0.21", 29 | "@types/react-dom": "18.0.6", 30 | "@types/styled-components": "^5.1.26", 31 | "babel-plugin-styled-components": "^2.0.7", 32 | "eslint": "8.25.0", 33 | "eslint-config-next": "12.3.1", 34 | "typescript": "4.8.4" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/components/register/PlaceSearchBox.tsx: -------------------------------------------------------------------------------- 1 | import { useRouter } from 'next/router'; 2 | import DaumPostcodeEmbed from 'react-daum-postcode'; 3 | import styled from 'styled-components'; 4 | import CloseHeader from '../common/CloseHeader'; 5 | 6 | function PlaceSearchBox() { 7 | const router = useRouter(); 8 | const handleComplete = (data: { zonecode: string; address: string }) => { 9 | router.push({ 10 | pathname: 'register', 11 | query: { zoneCode: data.zonecode, address: data.address }, 12 | }); 13 | }; 14 | 15 | return ( 16 | <> 17 | 18 | 19 | 20 | 21 | 22 | ); 23 | } 24 | 25 | export default PlaceSearchBox; 26 | 27 | const StPlaceSearchBox = styled.div` 28 | display: flex; 29 | flex-direction: column; 30 | align-items: center; 31 | & > div { 32 | width: 100vw !important; 33 | max-width: 42rem; 34 | height: 49.4rem !important; 35 | min-height: calc(100vh - 60px); 36 | } 37 | `; 38 | -------------------------------------------------------------------------------- /public/assets/icons/ic_location.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/assets/icons/ic_mark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/assets/icons/ic_location_colored.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/components/register/SelectHomeImage/UploadImage.tsx: -------------------------------------------------------------------------------- 1 | import { Dispatch, SetStateAction } from 'react'; 2 | import styled from 'styled-components'; 3 | import DropZone from '../../common/DropZone'; 4 | 5 | interface IProps { 6 | setFiles: Dispatch>; 7 | setImages: Dispatch>; 8 | } 9 | export default function UploadImage(props: IProps) { 10 | const { setFiles, setImages } = props; 11 | return ( 12 |
13 | 14 | 15 | 16 | 17 |

당신의 집을 가장 잘 표현한 사진을

18 |

첫번째로 골라주세요!

19 |
20 |
21 | ); 22 | } 23 | 24 | const StDropZoneDiv = styled.div` 25 | width: 375px; 26 | height: 222px; 27 | margin: 0 auto; 28 | margin-top: 100px; 29 | background: url('/assets/images/img_add.svg'); 30 | cursor: pointer; 31 | `; 32 | 33 | const StInformationDiv = styled.div` 34 | margin-top: 33px; 35 | font-size: 14px; 36 | font-weight: 400; 37 | line-height: 22px; 38 | text-align: center; 39 | `; 40 | -------------------------------------------------------------------------------- /public/assets/icons/ic_calendar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/components/register/PeopleInformation.tsx: -------------------------------------------------------------------------------- 1 | import { Dispatch, SetStateAction } from 'react'; 2 | import styled from 'styled-components'; 3 | import HouseType from './HouseType'; 4 | import Counter from './Counter'; 5 | import CohabitInformation from './CohabitInformation'; 6 | 7 | interface PeopleInformationProps { 8 | setNextValid: Dispatch>; 9 | } 10 | 11 | function PeopleInformation(props: PeopleInformationProps) { 12 | const { setNextValid } = props; 13 | 14 | return ( 15 |
16 | 어떤 집인가요? 17 | 18 | 19 | 몇 명이 지낼 수 있나요? 20 | 21 | 22 | 23 | 다른 사람과 24 |
25 | 함께 지내는 집인가요? 26 |
27 | 28 |
29 | ); 30 | } 31 | 32 | export default PeopleInformation; 33 | 34 | const StLine = styled.div` 35 | max-width: 420px; 36 | width: 100%; 37 | background: #f9f9f9; 38 | height: 10px; 39 | `; 40 | 41 | const StTitle = styled.h2` 42 | padding: 0 20px; 43 | padding-top: 38px; 44 | 45 | &:last-child { 46 | margin-bottom: 30px; 47 | } 48 | `; 49 | -------------------------------------------------------------------------------- /public/assets/icons/index.ts: -------------------------------------------------------------------------------- 1 | export { default as icBack } from './ic_back.svg'; 2 | export { default as icClose } from './ic_close.svg'; 3 | export { default as icMinusGray } from './ic_minus_gray.svg'; 4 | export { default as icMinusActive } from './ic_minus_active.svg'; 5 | export { default as icPlusGray } from './ic_plus_gray.svg'; 6 | export { default as icPlusActive } from './ic_plus_active.svg'; 7 | export { default as icCheckEmpty } from './ic_check_empty.svg'; 8 | export { default as icCheckActive } from './ic_check_active.svg'; 9 | export { default as icCloseBg } from './ic_close_bg.svg'; 10 | export { default as icAlert } from './ic_alert.svg'; 11 | export { default as icLocation } from './ic_location.svg'; 12 | export { default as icLocationColored } from './ic_location_colored.svg'; 13 | export { default as icLine } from './ic_line.svg'; 14 | export { default as icCalendar } from './ic_calendar.svg'; 15 | export { default as icLike } from './ic_like.svg'; 16 | export { default as icMark } from './ic_mark.svg'; 17 | export { default as icKakao } from './ic_kakao.svg'; 18 | export { default as icBrand } from './ic_brand.svg'; 19 | export { default as icHome } from './ic_home.svg'; 20 | export { default as icNotice } from './ic_notice.svg'; 21 | export { default as icDetailBack } from './ic_detail_back.svg'; 22 | -------------------------------------------------------------------------------- /src/pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import Document, { DocumentContext, Html, Head, Main, NextScript } from 'next/document'; 2 | import { ServerStyleSheet } from 'styled-components'; 3 | 4 | export default class MyDocument extends Document { 5 | static async getInitialProps(ctx: DocumentContext) { 6 | const sheet = new ServerStyleSheet(); 7 | const originalRenderPage = ctx.renderPage; 8 | try { 9 | ctx.renderPage = () => 10 | originalRenderPage({ 11 | enhanceApp: (App) => (props) => sheet.collectStyles(), 12 | }); 13 | const initialProps = await Document.getInitialProps(ctx); 14 | return { 15 | ...initialProps, 16 | styles: ( 17 | <> 18 | {' '} 19 | {initialProps.styles} {sheet.getStyleElement()}{' '} 20 | 21 | ), 22 | }; 23 | } finally { 24 | sheet.seal(); 25 | } 26 | } 27 | 28 | render() { 29 | return ( 30 | 31 | 32 | 36 | 37 | 38 |
39 | 40 | 41 | 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /public/assets/icons/ic_brand.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/components/common/DropZone.tsx: -------------------------------------------------------------------------------- 1 | import { Dispatch, SetStateAction } from 'react'; 2 | import { ReactElement, useCallback } from 'react'; 3 | import { useDropzone } from 'react-dropzone'; 4 | 5 | interface IProps { 6 | setFiles: Dispatch>; 7 | setImages: Dispatch>; 8 | children: React.ReactNode; 9 | } 10 | const DropZone: React.FC = ({ setFiles, setImages, children }) => { 11 | const onDrop = useCallback((acceptedFiles: Blob[]) => { 12 | acceptedFiles.forEach((file: Blob) => { 13 | const reader = new FileReader(); 14 | setFiles((prev) => [...prev, file]); 15 | const bloburl = URL.createObjectURL(file); 16 | setImages((prev) => [...prev, bloburl]); 17 | reader.onabort = () => console.log('file reading was aborted'); 18 | reader.onerror = () => console.log('file reading has failed'); 19 | reader.onload = () => { 20 | // Do whatever you want with the file contents 21 | const binaryStr = reader.result; 22 | }; 23 | reader.readAsArrayBuffer(file); 24 | }); 25 | }, []); 26 | const { getRootProps, getInputProps } = useDropzone({ onDrop }); 27 | return ( 28 |
29 | 30 | {children} 31 |
32 | ); 33 | }; 34 | 35 | export default DropZone; 36 | -------------------------------------------------------------------------------- /src/components/register/SelectHomeImage/index.tsx: -------------------------------------------------------------------------------- 1 | import { Dispatch, SetStateAction } from 'react'; 2 | import styled from 'styled-components'; 3 | import SelectImage from './SelectImage'; 4 | import UploadImage from './UploadImage'; 5 | 6 | interface IProps { 7 | setFiles: Dispatch>; 8 | setImages: Dispatch>; 9 | setRepresentImg: Dispatch>; 10 | setNextValid: Dispatch>; 11 | images: string[]; 12 | representImg: string | null; 13 | } 14 | 15 | export default function SelectHomeImage(props: IProps) { 16 | const { setFiles, setImages, images, representImg, setRepresentImg, setNextValid } = props; 17 | return ( 18 | 19 | 20 |
내 집은
21 |
이렇게 생겼어요!
22 |
23 | {images.length === 0 ? ( 24 | 25 | ) : ( 26 | 32 | )} 33 |
34 | ); 35 | } 36 | 37 | const StMainDiv = styled.div` 38 | width: 100%; 39 | `; 40 | 41 | const StHeaderDiv = styled.div` 42 | margin-top: 40px; 43 | padding: 0 20px; 44 | `; 45 | -------------------------------------------------------------------------------- /src/hooks/useModal.tsx: -------------------------------------------------------------------------------- 1 | import Modal from '@src/components/common/Modal'; 2 | import { useState } from 'react'; 3 | 4 | interface IProps { 5 | isConfirm: boolean; 6 | title: string; 7 | content: string; 8 | rightComment: string; 9 | leftComment: string; 10 | handleRightButton?: () => void; 11 | handleLeftButton: () => void; 12 | } 13 | 14 | export default function useModal(props: IProps) { 15 | const { isConfirm, title, rightComment, content, leftComment, handleRightButton, handleLeftButton } = props; 16 | const [isOpen, setIsOpen] = useState(false); 17 | const openModal = () => setIsOpen(true); 18 | const closeModal = () => setIsOpen(false); 19 | const handleRightButtonClick = () => { 20 | if (isConfirm) { 21 | setIsOpen(false); 22 | return; 23 | } 24 | if (handleRightButton) handleRightButton(); 25 | setIsOpen(false); 26 | }; 27 | const modal = () => ( 28 | { 37 | handleLeftButton(); 38 | setIsOpen(false); 39 | }} 40 | handleRightButton={handleRightButtonClick} 41 | /> 42 | ); 43 | return { 44 | openModal, 45 | Modal: modal, 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /public/assets/icons/ic_notice.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/components/register/CohabitInformation.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import styled from 'styled-components'; 3 | import CheckboxButton from '../common/CheckboxButton'; 4 | 5 | function CohabitInformation() { 6 | const [checkedButton, setCheckedButton] = useState('집 전체'); 7 | 8 | return ( 9 | 10 | setCheckedButton('집 전체')} 12 | isChecked={checkedButton === '집 전체'} 13 | option="집 전체" 14 | description="모든 공간을 단독으로 사용하고 있어요." 15 | /> 16 | setCheckedButton('1인실')} 18 | isChecked={checkedButton === '1인실'} 19 | option="1인실" 20 | description="침실은 단독으로 사용하지만, 욕실 및 주방 등 다른 사람과 공유하는 공간이 있어요." 21 | /> 22 | setCheckedButton('다인실')} 24 | isChecked={checkedButton === '다인실'} 25 | option="다인실" 26 | description="침실을 포함한 모든 공간을 다른 사람과 공유하고 있어요." 27 | /> 28 | 29 | ); 30 | } 31 | 32 | export default CohabitInformation; 33 | 34 | const StCohabitInformation = styled.div` 35 | margin: 30px 20px 40px 20px; 36 | 37 | & > button { 38 | display: flex; 39 | align-items: center; 40 | gap: 15px; 41 | width: 100%; 42 | min-width: fit-content; 43 | padding: 10px 0; 44 | 45 | &:not(:last-child) { 46 | margin-bottom: 15px; 47 | } 48 | } 49 | `; 50 | -------------------------------------------------------------------------------- /src/styles/globalStyle.ts: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from 'styled-components'; 2 | import reset from 'styled-reset'; 3 | 4 | const GlobalStyle = createGlobalStyle` 5 | ${reset}; 6 | 7 | html, 8 | body { 9 | width: 100%; 10 | height: 100%; 11 | } 12 | 13 | h2 { 14 | font-size: 21px; 15 | font-weight: 700; 16 | line-height: 28px; 17 | letter-spacing: -0.004em; 18 | text-align: left; 19 | } 20 | 21 | h5 { 22 | font-size: 21px; 23 | font-weight: 700; 24 | line-height: 34px; 25 | text-align: left; 26 | } 27 | 28 | #__next { 29 | display: flex; 30 | flex-direction: column; 31 | max-width: 42rem; 32 | min-height: 100vh; 33 | margin: 0 auto; 34 | } 35 | 36 | html { 37 | font-size: 62.5%; 38 | } 39 | 40 | * { 41 | box-sizing: border-box; 42 | } 43 | 44 | body, button, input, textarea { 45 | font-family: 'Noto Sans KR', sans-serif; 46 | } 47 | 48 | textarea { 49 | border: none; 50 | outline: none; 51 | resize: none; 52 | } 53 | 54 | button { 55 | cursor: pointer; 56 | border: none; 57 | outline: none; 58 | background-color: transparent; 59 | -webkit-tap-highlight-color : transparent; 60 | padding: 0; 61 | } 62 | 63 | input { 64 | outline: none; 65 | border: none; 66 | } 67 | 68 | a, a:visited { 69 | text-decoration: none; 70 | color: black; 71 | } 72 | `; 73 | 74 | export default GlobalStyle; 75 | -------------------------------------------------------------------------------- /src/components/register/LinkShare.tsx: -------------------------------------------------------------------------------- 1 | import { Dispatch, SetStateAction, useEffect, useState } from 'react'; 2 | import styled from 'styled-components'; 3 | import ImageDiv from '../common/ImageDiv'; 4 | import { icKakao } from 'public/assets/icons'; 5 | 6 | interface LinkShareProps { 7 | setNextValid: Dispatch>; 8 | } 9 | 10 | function LinkShare(props: LinkShareProps) { 11 | const { setNextValid } = props; 12 | const [link, setLink] = useState(''); 13 | const handleChange = (e: React.ChangeEvent) => { 14 | setLink(e.target.value); 15 | }; 16 | 17 | useEffect(() => { 18 | setNextValid(link ? true : false); 19 | }, [link]); 20 | 21 | return ( 22 | 23 | 24 |

25 | 26 | 소통할 채팅방의 링크를 27 |

28 |

공유해 주세요

29 |
30 | 31 |
32 | ); 33 | } 34 | 35 | export default LinkShare; 36 | 37 | const StLinkShare = styled.div` 38 | padding: 0 20px; 39 | 40 | input { 41 | width: 100%; 42 | height: 46px; 43 | margin-top: 30px; 44 | font-size: 12px; 45 | line-height: 160.3%; 46 | border-bottom: 1px solid #e1e1e1; 47 | } 48 | `; 49 | 50 | const StHeader = styled.div` 51 | font-weight: 700; 52 | font-size: 21px; 53 | line-height: 160.3%; 54 | margin-top: 40px; 55 | 56 | & > p { 57 | display: flex; 58 | } 59 | `; 60 | -------------------------------------------------------------------------------- /public/assets/images/img_ocean_small.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/components/register/SelectHomeImage/SelectImage.tsx: -------------------------------------------------------------------------------- 1 | import ImageDiv from '@src/components/common/ImageDiv'; 2 | import { Dispatch, SetStateAction } from 'react'; 3 | import styled from 'styled-components'; 4 | 5 | interface IProps { 6 | images: string[]; 7 | representImg: string | null; 8 | setRepresentImg: Dispatch>; 9 | setNextValid: Dispatch>; 10 | } 11 | 12 | export default function SelectImage(props: IProps) { 13 | const { images, representImg, setRepresentImg, setNextValid } = props; 14 | setNextValid(true); 15 | return ( 16 | 17 | 18 | 19 | {images.map((image) => ( 20 | setRepresentImg(image)} 26 | /> 27 | ))} 28 | 29 | 30 | ); 31 | } 32 | 33 | const StSelectImage = styled.div` 34 | margin-top: 40px; 35 | padding: 0 20px; 36 | 37 | .representative { 38 | position: relative; 39 | width: 100%; 40 | max-width: 420px; 41 | height: 312px; 42 | margin-bottom: 16px; 43 | } 44 | 45 | img { 46 | border-radius: 8px; 47 | object-fit: cover; 48 | } 49 | `; 50 | 51 | const StImageContainer = styled.div` 52 | display: flex; 53 | flex-wrap: wrap; 54 | gap: 14px; 55 | 56 | .selected-image { 57 | position: relative; 58 | width: calc(calc(100% - 28px) / 3); 59 | height: 108px; 60 | cursor: pointer; 61 | } 62 | `; 63 | -------------------------------------------------------------------------------- /public/assets/icons/ic_alert.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/assets/images/img_ocean.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /public/assets/images/img_upload.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /public/assets/icons/ic_home.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/components/register/HouseType.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | function HouseType() { 4 | return ( 5 | 6 |
7 |
건물 유형
8 | 14 |
15 |
16 |
방 개수
17 | 23 |
24 |
25 |
전체 평수
26 | 32 |
33 |
34 | ); 35 | } 36 | 37 | export default HouseType; 38 | 39 | const StHouseType = styled.div` 40 | display: flex; 41 | margin: 30px 20px 40px 20px; 42 | 43 | & > div { 44 | width: calc(100% / 3); 45 | height: 62px; 46 | padding: 9px 10px 10px 12px; 47 | background: #f3f7fb; 48 | 49 | div { 50 | font-size: 12px; 51 | line-height: 160.3%; 52 | color: #9190cf; 53 | } 54 | } 55 | 56 | & > div:first-child { 57 | border-top-left-radius: 10px; 58 | border-bottom-left-radius: 10px; 59 | } 60 | 61 | & > div:last-child { 62 | border-top-right-radius: 10px; 63 | border-bottom-right-radius: 10px; 64 | } 65 | 66 | & > div:not(:last-child) { 67 | border-right: 1px solid #9190cf; 68 | } 69 | 70 | select { 71 | width: 100%; 72 | margin-top: 5px; 73 | background-color: transparent; 74 | font-size: 14px; 75 | line-height: 22px; 76 | border: 0; 77 | outline: 0; 78 | } 79 | `; 80 | -------------------------------------------------------------------------------- /src/components/register/HomePrecautions.tsx: -------------------------------------------------------------------------------- 1 | import { icAlert } from 'public/assets/icons'; 2 | import { Dispatch, SetStateAction, useEffect, useState } from 'react'; 3 | import styled from 'styled-components'; 4 | import ImageDiv from '../common/ImageDiv'; 5 | 6 | interface IProps { 7 | setNextValid: Dispatch>; 8 | } 9 | export default function HomePrecautions(props: IProps) { 10 | const { setNextValid } = props; 11 | const [precautions, setPrecautions] = useState(''); 12 | setNextValid(true); 13 | return ( 14 | 15 | 16 | 17 |
이런 활동은 주의해 주세요!
18 |
19 | 20 |