diff --git a/.eslintrc.json b/.eslintrc.json index a56b0f04..96795714 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -23,6 +23,7 @@ "prettier" // eslint-config-prettier prettier와 중복된 eslint 규칙 제거 ], "rules": { + "import/order": "off", "react/react-in-jsx-scope": "off", // react 17부턴 import 안해도돼서 기능 끔 // 경고표시, 파일 확장자를 .ts나 .tsx 모두 허용함 "react/jsx-filename-extension": ["warn", { "extensions": [".ts", ".tsx"] }], diff --git a/README.md b/README.md index 4491d02c..93e36bbe 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,165 @@ -# Officener Sixsense Client ver. +# 🏢 오피스너 (officener) -## 커밋 컨벤션 목록 :) +> 입주 경험은 높이고, 관리 소요는 낮추고 +> 스마트 오피스 빌딩 통합 플랫폼 오피스너! -- feat: 새로운 기능을 추가한 경우 -- fix: 에러를 수정한 경우 -- design: CSS 등 UI 디자인을 변경한 경우 -- BREAKING: CHANGE 중대한 API를 변경한 경우 -- HOTFIX: 급하게 치명적인 에러를 고친 경우 -- style: 코드 포맷 변경을 하거나 세미 콜론 누락하여 추가하면서 코드 수정이 없는 경우 -- refactor: 코드를 리팩토링한 경우 -- comment: 주석을 추가하거나 변경한 경우 -- docs: 문서를 수정한 경우 -- test: 테스트 코드를 추가, 변경, 리팩토링한 경우 -- chore: 기타 변경사항 (빌드 스크립트 수정, 패키지 매니징 설정 등) -- rename: 파일 or 폴더명 수정하거나 옮기는 경우 -- remove: 파일을 삭제하는 작업만 수행한 경우 + -### 팀 식스센스 코드 컨벤션 +### 🖥 [클라이언트 DEMO](https://officener.vercel.app/) -### 에어비엔비 코드 컨벤션 링크 +### [⚙️ 어드민 DEMO](https://officener-admin.vercel.app/) -[에어비엔비](https://github.com/tipjs/javascript-style-guide) + + +## 🗓️ 프로젝트 소개 + +> **주 제** : 빌딩 내 입주자 활성화를 위한 서비스 기획/개발 > **목 표** : 유저 그로스 기획/개발을 통해 핵심 지표인 '유저 가입자 수'와 'WAU' 높이기 > **개발 기간** : 2023. 08. 16 ~ 2023. 10. 06 (2개월) + + + +## 👤 프로젝트 팀원 + +| 김준희 | 김진우 | 이시우 | 유희태 (팀장) | 조은상 | +| :-----------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------: | +| | | | | | +| 초대장 생성 | 초대장 뷰관리자 | 초대장 수정초대장 뷰 | 홈 리디자인오늘 점심 | 오늘점심 | + + + +## 🛠️️ 사용기술 및 개발환경 + +**Front-End** + + + + + + + + + + + +**Back-End** + + + + + + + + + + + + +**Deployment** + + + + + + + +**Cowork Tools** + + + + + + + + + + + +## 🖥️ 기능 소개 + +### 1. 방문자 초대장 + +- 방문자 초대하기 +- 초대장 목록 확인 +- 초대장 수정/삭제 +- 실내 지도 확인 +- 방문할 빌딩 근처 시설 안내 +- 방문증 알림톡 +- 방문자 관리 웹 + + + +### 2. 주차 정산 + +- 방문 주차 등록 +- 주차 결제 (준비 중) +- 주차 할인 적용 (준비 중) +- 주차 사전 정산 (준비 중) + + + +### 3. 오늘 점심 + +- 메뉴 랭킹 +- 메뉴 랭킹별 리뷰 +- 점심 메뉴 추천 룰렛 +- 룰렛 결과 메뉴 리뷰 확인 +- 리뷰 작성 +- 나만의 점심 달력 만들기 + + + +### 4. 기타 + +- 홈 화면 리디자인 +- 마이 페이지 리디자인 +- 포인트 지도 +- 포인트 활용 (준비 중) + + + +| 홈 리디자인 | 마이페이지 리디자인 | +| :---------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------: | +| | | +| 방문자 초대장 생성 | 방문자 초대장 뷰 | +| | | +| 초대장 리스트 | 빌딩 정보 | +| | | +| 초대 장소 확인 | 주차 등록 | +| | | +| 오늘 점심 룰렛 | 오늘 점심 메인 | +| | | +| 오늘 점심 리뷰 작성 | 오늘 점심 리뷰 작성 | +| | | +| 오늘 점심 달력 | 오늘 점심 랭킹별 리뷰 | +| | | + + + +## 💻 프로젝트 테스트 + +### clone project + +```bash +$ git@github.com:livable-final/client.git +$ git@github.com:livable-final/admin.git +``` + +### go to project + +```bash +$ cd client +$ cd admin +``` + +### install npm + +```bash +$ npm install +``` + +### start project + +```bash +$ npm run dev +``` + + diff --git a/next.config.js b/next.config.js index 35c9f13d..c8a55053 100644 --- a/next.config.js +++ b/next.config.js @@ -5,8 +5,12 @@ const nextConfig = { emotion: true, }, images: { - domains: ['https://livable-final.s3.ap-northeast-2.amazonaws.com'], - + deviceSizes: [361, 480], + imageSizes: [242, 358], + domains: [ + 'https://livable-final.s3.ap-northeast-2.amazonaws.com', + 'img1.kakaocdn.net', + ], remotePatterns: [ { protocol: 'https', diff --git a/package-lock.json b/package-lock.json index 1c90df08..2c92b714 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "react-calendar": "^4.6.0", "react-datepicker": "^4.18.0", "react-dom": "18.2.0", + "react-hot-toast": "^2.4.1", "react-spinners": "^0.13.8", "swiper": "^10.2.0", "typescript": "5.2.2", @@ -4907,6 +4908,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/goober": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.13.tgz", + "integrity": "sha512-jFj3BQeleOoy7t93E9rZ2de+ScC4lQICLwiAQmKMg9F6roKGaLSHoCDYKkWlSafg138jejvq/mTdvmnwDQgqoQ==", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -6293,6 +6302,21 @@ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" }, + "node_modules/react-hot-toast": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.1.tgz", + "integrity": "sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==", + "dependencies": { + "goober": "^2.1.10" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", diff --git a/package.json b/package.json index 7dc8280a..efa4efdd 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "react-calendar": "^4.6.0", "react-datepicker": "^4.18.0", "react-dom": "18.2.0", + "react-hot-toast": "^2.4.1", "react-spinners": "^0.13.8", "swiper": "^10.2.0", "typescript": "5.2.2", diff --git a/public/defaultImage.jpg b/public/defaultImage.jpg deleted file mode 100644 index 75f474b2..00000000 Binary files a/public/defaultImage.jpg and /dev/null differ diff --git a/public/favicon.ico b/public/favicon.ico index 718d6fea..be739309 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/invitation/TestBuildingMap.png b/public/invitation/TestBuildingMap.png new file mode 100644 index 00000000..539f003a Binary files /dev/null and b/public/invitation/TestBuildingMap.png differ diff --git a/public/invitation/invitationPreview.png b/public/invitation/invitationPreview.png new file mode 100644 index 00000000..612d78f4 Binary files /dev/null and b/public/invitation/invitationPreview.png differ diff --git a/public/menu.png b/public/menu.png deleted file mode 100644 index 0d63727b..00000000 Binary files a/public/menu.png and /dev/null differ diff --git a/public/point/Wrappedgift1.png b/public/point/Wrappedgift1.png new file mode 100644 index 00000000..cb990654 Binary files /dev/null and b/public/point/Wrappedgift1.png differ diff --git a/public/ruppy.png b/public/ruppy.png deleted file mode 100644 index 185af651..00000000 Binary files a/public/ruppy.png and /dev/null differ diff --git a/src/assets/defaultImage.jpg b/src/assets/defaultImage.jpg deleted file mode 100644 index 75f474b2..00000000 Binary files a/src/assets/defaultImage.jpg and /dev/null differ diff --git a/src/assets/fonts/YeongdeokBlueroad.ttf b/src/assets/fonts/YeongdeokBlueroad.ttf deleted file mode 100644 index bf0b699d..00000000 Binary files a/src/assets/fonts/YeongdeokBlueroad.ttf and /dev/null differ diff --git a/src/assets/icons/BottomArrow.svg b/src/assets/icons/BottomArrow.svg deleted file mode 100644 index faba8cb6..00000000 --- a/src/assets/icons/BottomArrow.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/src/assets/icons/Clock.svg b/src/assets/icons/Clock.svg deleted file mode 100644 index 1061e57d..00000000 --- a/src/assets/icons/Clock.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/assets/icons/Rank1.svg b/src/assets/icons/Rank1.svg deleted file mode 100644 index 25c68770..00000000 --- a/src/assets/icons/Rank1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/assets/icons/Rank2.svg b/src/assets/icons/Rank2.svg deleted file mode 100644 index e9a204ba..00000000 --- a/src/assets/icons/Rank2.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/assets/icons/Rank3.svg b/src/assets/icons/Rank3.svg deleted file mode 100644 index 4eecf3ec..00000000 --- a/src/assets/icons/Rank3.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/assets/icons/Sunny.svg b/src/assets/icons/Sunny.svg deleted file mode 100644 index 494b2f89..00000000 --- a/src/assets/icons/Sunny.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src/assets/icons/Back.svg b/src/assets/icons/common/Back.svg similarity index 100% rename from src/assets/icons/Back.svg rename to src/assets/icons/common/Back.svg diff --git a/src/assets/icons/Check.svg b/src/assets/icons/common/Check.svg similarity index 100% rename from src/assets/icons/Check.svg rename to src/assets/icons/common/Check.svg diff --git a/src/assets/icons/check=on.svg b/src/assets/icons/common/Check=on.svg similarity index 100% rename from src/assets/icons/check=on.svg rename to src/assets/icons/common/Check=on.svg diff --git a/src/assets/icons/Close.svg b/src/assets/icons/common/Close.svg similarity index 100% rename from src/assets/icons/Close.svg rename to src/assets/icons/common/Close.svg diff --git a/src/assets/icons/Error.svg b/src/assets/icons/common/Error.svg similarity index 100% rename from src/assets/icons/Error.svg rename to src/assets/icons/common/Error.svg diff --git a/src/assets/icons/common/Exit=medium.svg b/src/assets/icons/common/Exit=medium.svg new file mode 100644 index 00000000..4e1fca0c --- /dev/null +++ b/src/assets/icons/common/Exit=medium.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/assets/icons/Exit=small.svg b/src/assets/icons/common/Exit=small.svg similarity index 100% rename from src/assets/icons/Exit=small.svg rename to src/assets/icons/common/Exit=small.svg diff --git a/src/assets/icons/LeftSmall.svg b/src/assets/icons/common/LeftSmall.svg similarity index 100% rename from src/assets/icons/LeftSmall.svg rename to src/assets/icons/common/LeftSmall.svg diff --git a/src/assets/icons/Plus=big.svg b/src/assets/icons/common/Plus=big.svg similarity index 100% rename from src/assets/icons/Plus=big.svg rename to src/assets/icons/common/Plus=big.svg diff --git a/src/assets/icons/Plus=small.svg b/src/assets/icons/common/Plus=small.svg similarity index 100% rename from src/assets/icons/Plus=small.svg rename to src/assets/icons/common/Plus=small.svg diff --git a/src/assets/icons/profile.svg b/src/assets/icons/common/Profile.svg similarity index 100% rename from src/assets/icons/profile.svg rename to src/assets/icons/common/Profile.svg diff --git a/src/assets/icons/ProfileWithBg.svg b/src/assets/icons/common/ProfileWithBg.svg similarity index 100% rename from src/assets/icons/ProfileWithBg.svg rename to src/assets/icons/common/ProfileWithBg.svg diff --git a/src/assets/icons/Right.svg b/src/assets/icons/common/Right.svg similarity index 100% rename from src/assets/icons/Right.svg rename to src/assets/icons/common/Right.svg diff --git a/src/assets/icons/Right=small.svg b/src/assets/icons/common/Right=small.svg similarity index 100% rename from src/assets/icons/Right=small.svg rename to src/assets/icons/common/Right=small.svg diff --git a/src/assets/icons/Rights.svg b/src/assets/icons/common/Rights.svg similarity index 100% rename from src/assets/icons/Rights.svg rename to src/assets/icons/common/Rights.svg diff --git a/src/assets/icons/UnCheck.svg b/src/assets/icons/common/UnCheck.svg similarity index 100% rename from src/assets/icons/UnCheck.svg rename to src/assets/icons/common/UnCheck.svg diff --git a/src/assets/icons/Up.svg b/src/assets/icons/common/Up.svg similarity index 100% rename from src/assets/icons/Up.svg rename to src/assets/icons/common/Up.svg diff --git a/src/assets/icons/XS_1.5.svg b/src/assets/icons/common/XS_1.5.svg similarity index 100% rename from src/assets/icons/XS_1.5.svg rename to src/assets/icons/common/XS_1.5.svg diff --git a/src/assets/icons/XS_black.svg b/src/assets/icons/common/XS_black.svg similarity index 100% rename from src/assets/icons/XS_black.svg rename to src/assets/icons/common/XS_black.svg diff --git a/src/assets/icons/Barcode.svg b/src/assets/icons/home/Barcode.svg similarity index 100% rename from src/assets/icons/Barcode.svg rename to src/assets/icons/home/Barcode.svg diff --git a/src/assets/icons/Bell.svg b/src/assets/icons/home/Bell.svg similarity index 100% rename from src/assets/icons/Bell.svg rename to src/assets/icons/home/Bell.svg diff --git a/src/assets/icons/home/Destination.svg b/src/assets/icons/home/Destination.svg new file mode 100644 index 00000000..b9acecd9 --- /dev/null +++ b/src/assets/icons/home/Destination.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/assets/icons/Down.svg b/src/assets/icons/home/Down.svg similarity index 100% rename from src/assets/icons/Down.svg rename to src/assets/icons/home/Down.svg diff --git a/src/assets/icons/Home.svg b/src/assets/icons/home/Home.svg similarity index 100% rename from src/assets/icons/Home.svg rename to src/assets/icons/home/Home.svg diff --git a/src/assets/icons/HomeActive.svg b/src/assets/icons/home/HomeActive.svg similarity index 100% rename from src/assets/icons/HomeActive.svg rename to src/assets/icons/home/HomeActive.svg diff --git a/src/assets/icons/Line.svg b/src/assets/icons/home/Line.svg similarity index 100% rename from src/assets/icons/Line.svg rename to src/assets/icons/home/Line.svg diff --git a/src/assets/icons/Lunch.svg b/src/assets/icons/home/Lunch.svg similarity index 100% rename from src/assets/icons/Lunch.svg rename to src/assets/icons/home/Lunch.svg diff --git a/src/assets/icons/LunchActive.svg b/src/assets/icons/home/LunchActive.svg similarity index 100% rename from src/assets/icons/LunchActive.svg rename to src/assets/icons/home/LunchActive.svg diff --git a/src/assets/icons/LunchCalendar.svg b/src/assets/icons/home/LunchCalendar.svg similarity index 100% rename from src/assets/icons/LunchCalendar.svg rename to src/assets/icons/home/LunchCalendar.svg diff --git a/src/assets/icons/My.svg b/src/assets/icons/home/My.svg similarity index 100% rename from src/assets/icons/My.svg rename to src/assets/icons/home/My.svg diff --git a/src/assets/icons/MyActive.svg b/src/assets/icons/home/MyActive.svg similarity index 100% rename from src/assets/icons/MyActive.svg rename to src/assets/icons/home/MyActive.svg diff --git a/src/assets/icons/Roulette.svg b/src/assets/icons/home/Roulette.svg similarity index 100% rename from src/assets/icons/Roulette.svg rename to src/assets/icons/home/Roulette.svg diff --git a/src/assets/icons/Servey.svg b/src/assets/icons/home/Servey.svg similarity index 100% rename from src/assets/icons/Servey.svg rename to src/assets/icons/home/Servey.svg diff --git a/src/assets/icons/ServiceCafeteria.svg b/src/assets/icons/home/ServiceCafeteria.svg similarity index 100% rename from src/assets/icons/ServiceCafeteria.svg rename to src/assets/icons/home/ServiceCafeteria.svg diff --git a/src/assets/icons/ServiceCalendar.svg b/src/assets/icons/home/ServiceCalendar.svg similarity index 100% rename from src/assets/icons/ServiceCalendar.svg rename to src/assets/icons/home/ServiceCalendar.svg diff --git a/src/assets/icons/ServiceInvitation.svg b/src/assets/icons/home/ServiceInvitation.svg similarity index 100% rename from src/assets/icons/ServiceInvitation.svg rename to src/assets/icons/home/ServiceInvitation.svg diff --git a/src/assets/icons/ServiceParking.svg b/src/assets/icons/home/ServiceParking.svg similarity index 100% rename from src/assets/icons/ServiceParking.svg rename to src/assets/icons/home/ServiceParking.svg diff --git a/src/assets/icons/ServiceReception.svg b/src/assets/icons/home/ServiceReception.svg similarity index 100% rename from src/assets/icons/ServiceReception.svg rename to src/assets/icons/home/ServiceReception.svg diff --git a/src/assets/icons/ServiceTemp.svg b/src/assets/icons/home/ServiceTemp.svg similarity index 100% rename from src/assets/icons/ServiceTemp.svg rename to src/assets/icons/home/ServiceTemp.svg diff --git a/src/assets/icons/Setting.svg b/src/assets/icons/home/Setting.svg similarity index 100% rename from src/assets/icons/Setting.svg rename to src/assets/icons/home/Setting.svg diff --git a/src/assets/icons/TearOffCalendar.svg b/src/assets/icons/home/TearOffCalendar.svg similarity index 100% rename from src/assets/icons/TearOffCalendar.svg rename to src/assets/icons/home/TearOffCalendar.svg diff --git a/src/assets/icons/Top.svg b/src/assets/icons/home/Top.svg similarity index 100% rename from src/assets/icons/Top.svg rename to src/assets/icons/home/Top.svg diff --git a/src/assets/icons/Write.svg b/src/assets/icons/home/Write.svg similarity index 100% rename from src/assets/icons/Write.svg rename to src/assets/icons/home/Write.svg diff --git a/src/assets/icons/index.ts b/src/assets/icons/index.ts index 32e9558a..b509d2dd 100644 --- a/src/assets/icons/index.ts +++ b/src/assets/icons/index.ts @@ -1,60 +1,6 @@ -import As from '@/assets/icons/As.svg'; -import Back from '@/assets/icons/Back.svg'; -import Calendar from '@/assets/icons/Calendar.svg'; -import CalendarFill from '@/assets/icons/Calender-Fill.svg'; -import Check from '@/assets/icons/Check.svg'; -import CheckOn from '@/assets/icons/check=on.svg'; -import Clock from '@/assets/icons/Clock.svg'; -import Down from '@/assets/icons/Down.svg'; -import Etc from '@/assets/icons/Etc.svg'; -import FixedtermWork from '@/assets/icons/FixedtermWork.svg'; -import Interview from '@/assets/icons/Interview.svg'; -import Location from '@/assets/icons/Location.svg'; -import LocationFill from '@/assets/icons/Location-fill.svg'; -import Meeting from '@/assets/icons/meeting.svg'; -import Right from '@/assets/icons/Right.svg'; -import Seminar from '@/assets/icons/seminar.svg'; -import Up from '@/assets/icons/Up.svg'; -import Info from '@/assets/icons/Info.svg'; -import PlusBig from '@/assets/icons/Plus=big.svg'; -import PlusSmall from '@/assets/icons/Plus=small.svg'; -import ExitSmall from '@/assets/icons/Exit=small.svg'; -import RightSmall from '@/assets/icons/Right=small.svg'; -import Direction from '@/assets/icons/Direction.svg'; -import UnCheck from '@/assets/icons/UnCheck.svg'; -import SearchIcon from '@/assets/icons/Search.svg'; -import XIcon from '@/assets/icons/XS_1.5.svg'; -import Gift from '@/assets/icons/Gift.svg'; -import Plate from '@/assets/icons/Plate.svg'; -import Bento from '@/assets/icons/Bento.svg'; -import Smile from '@/assets/icons/Smile.svg'; -import Confused from '@/assets/icons/Confused.svg'; -import Chef from '@/assets/icons/Chef.svg'; -import Rice from '@/assets/icons/Rice.svg'; -import ThumbsUp from '@/assets/icons/ThumbsUp.svg'; -import Camera from '@/assets/icons/Camera.svg'; -import XSBlack from '@/assets/icons/XS_black.svg'; -import Profile from '@/assets/icons/profile.svg'; -import Copy from '@/assets/icons/Copy_light.svg'; -import CopyBlue from '@/assets/icons/Copy.svg'; -import Subway from '@/assets/icons/Subway.svg'; -import Bus from '@/assets/icons/Bus.svg'; -import Home from '@/assets/icons/Home.svg'; -import Send from '@/assets/icons/Send.svg'; -import LeftSmall from '@/assets/icons/LeftSmall.svg'; -import DateDish from '@/assets/icons/DateDish.svg'; -import DateDishNoPhoto from '@/assets/icons/DateDishNoPhoto.svg'; -import Setting from '@/assets/icons/Setting.svg'; -import Coin from '@/assets/icons/Coin.svg'; -import TearOffCalendar from '@/assets/icons/TearOffCalendar.svg'; -import Barcode from '@/assets/icons/Barcode.svg'; -import Bell from '@/assets/icons/Bell.svg'; -import Line from '@/assets/icons/Line.svg'; -import Roulette from '@/assets/icons/Roulette.svg'; -import Rights from '@/assets/icons/Rights.svg'; -import Sunny from '@/assets/icons/Sunny.svg'; -import Location20 from '@/assets/icons/Location20.svg'; -import Delicious from '@/assets/icons/Delicious.svg'; +/* eslint-disable sort-imports */ + +// ** Weather ** import ClearDay from '@/assets/icons/weather/ClearDay.svg'; import ClearNight from '@/assets/icons/weather/ClearNight.svg'; import FewClouds from '@/assets/icons/weather/FewClouds.svg'; @@ -65,127 +11,161 @@ import Rain from '@/assets/icons/weather/Rain.svg'; import ThunderStorm from '@/assets/icons/weather/ThunderStorm.svg'; import Snow from '@/assets/icons/weather/Snow.svg'; import Mist from '@/assets/icons/weather/Mist.svg'; -import LunchCalendar from '@/assets/icons/LunchCalendar.svg'; -import Lunch from '@/assets/icons/Lunch.svg'; -import Rank1 from '@/assets/icons/Rank1.svg'; -import Rank2 from '@/assets/icons/Rank2.svg'; -import Rank3 from '@/assets/icons/Rank3.svg'; -import Reviewer from '@/assets/icons/Reviewer.svg'; -import Close from '@/assets/icons/Close.svg'; -import Top from '@/assets/icons/Top.svg'; -import CameraFlash from '@/assets/icons/CameraFlash.svg'; -import Servey from '@/assets/icons/Servey.svg'; -import ServiceCafeteria from '@/assets/icons/ServiceCafeteria.svg'; -import ServiceCalendar from '@/assets/icons/ServiceCalendar.svg'; -import ServiceInvitation from '@/assets/icons/ServiceInvitation.svg'; -import ServiceParking from '@/assets/icons/ServiceParking.svg'; -import ServiceReception from '@/assets/icons/ServiceReception.svg'; -import ServiceTemp from '@/assets/icons/ServiceTemp.svg'; -import ProfileWithBg from '@/assets/icons/ProfileWithBg.svg'; -import Error from '@/assets/icons/Error.svg'; -import My from '@/assets/icons/My.svg'; -import Write from '@/assets/icons/Write.svg'; -import Popup from '@/assets/icons/Popup.svg'; -import PopupActive from '@/assets/icons/PopupActive.svg'; -import Present from '@/assets/icons/present.svg'; -import Point10 from '@/assets/icons/point10.svg'; -import Point500 from '@/assets/icons/point500.svg'; -import Point10Pink from '@/assets/icons/point10pink.svg'; -import Point1000 from '@/assets/icons/point1000.svg'; -import Point1500 from '@/assets/icons/point1500.svg'; -import Present500 from '@/assets/icons/present500.svg'; -import Present1000 from '@/assets/icons/present1000.svg'; -import Present1500 from '@/assets/icons/present.1500.svg'; -import InfoBuilding from '@/assets/icons/InfoBuliding.svg'; -import InfoPlace from '@/assets/icons/InfoPlace.svg'; -import InfoHost from '@/assets/icons/InfoHost.svg'; -import InfoParking from '@/assets/icons/InfoParking.svg'; -import FoodNoPhoto from '@/assets/icons/foodNoPhoto.svg'; -import FoodCafe from '@/assets/icons/foodCafe.svg'; -import FoodLunchBox from '@/assets/icons/foodLunchBox.svg'; -import HomeActive from '@/assets/icons/HomeActive.svg'; -import LunchActive from '@/assets/icons/LunchActive.svg'; -import MyActive from '@/assets/icons/MyActive.svg'; -import PlateSmall from '@/assets/icons/plateSmall.svg'; -import ErrorIcon from '@/assets/icons/Erroricon.svg'; + +// ** Common +import Back from '@/assets/icons/common/Back.svg'; +import Check from '@/assets/icons/common/Check.svg'; +import CheckOn from '@/assets/icons/common/Check=on.svg'; +import Close from '@/assets/icons/common/Close.svg'; +import Error from '@/assets/icons/common/Error.svg'; +import PlusBig from '@/assets/icons/common/Plus=big.svg'; +import PlusSmall from '@/assets/icons/common/Plus=small.svg'; +import ExitSmall from '@/assets/icons/common/Exit=small.svg'; +import ExitMedium from '@/assets/icons/common/Exit=medium.svg'; +import LeftSmall from '@/assets/icons/common/LeftSmall.svg'; +import Profile from '@/assets/icons/common/Profile.svg'; +import ProfileWithBg from '@/assets/icons/common/ProfileWithBg.svg'; +import Right from '@/assets/icons/common/Right.svg'; +import Rights from '@/assets/icons/common/Rights.svg'; +import RightSmall from '@/assets/icons/common/Right=small.svg'; +import UnCheck from '@/assets/icons/common/UnCheck.svg'; +import Up from '@/assets/icons/common/Up.svg'; +import XIcon from '@/assets/icons/common/XS_1.5.svg'; +import XSBlack from '@/assets/icons/common/XS_black.svg'; + +// ** Home +import Barcode from '@/assets/icons/home/Barcode.svg'; +import Bell from '@/assets/icons/home/Bell.svg'; +import Destination from '@/assets/icons/home/Destination.svg'; +import Down from '@/assets/icons/home/Down.svg'; +import Home from '@/assets/icons/home/Home.svg'; +import HomeActive from '@/assets/icons/home/HomeActive.svg'; +import Line from '@/assets/icons/home/Line.svg'; +import Lunch from '@/assets/icons/home/Lunch.svg'; +import LunchActive from '@/assets/icons/home/LunchActive.svg'; +import LunchCalendar from '@/assets/icons/home/LunchCalendar.svg'; +import My from '@/assets/icons/home/My.svg'; +import MyActive from '@/assets/icons/home/MyActive.svg'; +import Roulette from '@/assets/icons/home/Roulette.svg'; +import Servey from '@/assets/icons/home/Servey.svg'; +import ServiceCafeteria from '@/assets/icons/home/ServiceCafeteria.svg'; +import ServiceCalendar from '@/assets/icons/home/ServiceCalendar.svg'; +import ServiceInvitation from '@/assets/icons/home/ServiceInvitation.svg'; +import ServiceParking from '@/assets/icons/home/ServiceParking.svg'; +import ServiceReception from '@/assets/icons/home/ServiceReception.svg'; +import ServiceTemp from '@/assets/icons/home/ServiceTemp.svg'; +import Setting from '@/assets/icons/home/Setting.svg'; +import TearOffCalendar from '@/assets/icons/home/TearOffCalendar.svg'; +import Top from '@/assets/icons/home/Top.svg'; +import Write from '@/assets/icons/home/Write.svg'; + +// ** Invitation +import As from '@/assets/icons/invitation/As.svg'; +import BoxGrey from '@/assets/icons/invitation/BoxGrey.svg'; +import BoxWhite from '@/assets/icons/invitation/BoxWhite.svg'; +import Bus from '@/assets/icons/invitation/Bus.svg'; +import Calendar from '@/assets/icons/invitation/Calendar.svg'; +import CalendarFill from '@/assets/icons/invitation/Calender-Fill.svg'; +import Call from '@/assets/icons/invitation/Call.svg'; +import CopyBlue from '@/assets/icons/invitation/Copy.svg'; +import Copy from '@/assets/icons/invitation/Copy_light.svg'; +import Direction from '@/assets/icons/invitation/Direction.svg'; +import ErrorIcon from '@/assets/icons/invitation/ErrorIcon.svg'; +import Etc from '@/assets/icons/invitation/Etc.svg'; +import FixedtermWork from '@/assets/icons/invitation/FixedtermWork.svg'; +import Info from '@/assets/icons/invitation/Info.svg'; +import InfoBuilding from '@/assets/icons/invitation/InfoBuliding.svg'; +import InfoHost from '@/assets/icons/invitation/InfoHost.svg'; +import InfoParking from '@/assets/icons/invitation/InfoParking.svg'; +import InfoPlace from '@/assets/icons/invitation/InfoPlace.svg'; +import Interview from '@/assets/icons/invitation/Interview.svg'; +import LocationFill from '@/assets/icons/invitation/Location-fill.svg'; +import Location from '@/assets/icons/invitation/Location.svg'; +import Location20 from '@/assets/icons/invitation/Location20.svg'; +import LocationLine from '@/assets/icons/invitation/LocationLine.svg'; +import Meeting from '@/assets/icons/invitation/Meeting.svg'; +import RightZoom from '@/assets/icons/invitation/RightZoom.svg'; +import Seminar from '@/assets/icons/invitation/Seminar.svg'; +import Subway from '@/assets/icons/invitation/Subway.svg'; + +// ** Lunch +import Bento from '@/assets/icons/lunch/Bento.svg'; +import Camera from '@/assets/icons/lunch/Camera.svg'; +import CameraFlash from '@/assets/icons/lunch/CameraFlash.svg'; +import Chef from '@/assets/icons/lunch/Chef.svg'; +import Clock from '@/assets/icons/lunch/Clock.svg'; +import Coin from '@/assets/icons/lunch/Coin.svg'; +import Confused from '@/assets/icons/lunch/Confused.svg'; +import DateDish from '@/assets/icons/lunch/DateDish.svg'; +import DateDishNoPhoto from '@/assets/icons/lunch/DateDishNoPhoto.svg'; +import Delicious from '@/assets/icons/lunch/Delicious.svg'; +import FoodCafe from '@/assets/icons/lunch/FoodCafe.svg'; +import FoodLunchBox from '@/assets/icons/lunch/FoodLunchBox.svg'; +import FoodNoPhoto from '@/assets/icons/lunch/FoodNoPhoto.svg'; +import Gift from '@/assets/icons/lunch/Gift.svg'; +import Plate from '@/assets/icons/lunch/Plate.svg'; +import PlateSmall from '@/assets/icons/lunch/PlateSmall.svg'; +import Point10 from '@/assets/icons/lunch/Point10.svg'; +import Point500 from '@/assets/icons/lunch/Point500.svg'; +import Point10Pink from '@/assets/icons/lunch/Point10pink.svg'; +import Point1000 from '@/assets/icons/lunch/Point1000.svg'; +import Point1500 from '@/assets/icons/lunch/Point1500.svg'; +import Present500 from '@/assets/icons/lunch/Present500.svg'; +import Present1000 from '@/assets/icons/lunch/Present1000.svg'; +import Present1500 from '@/assets/icons/lunch/Present.1500.svg'; +import Popup from '@/assets/icons/lunch/Popup.svg'; +import PopupActive from '@/assets/icons/lunch/PopupActive.svg'; +import Present from '@/assets/icons/lunch/Present.svg'; +import Reviewer from '@/assets/icons/lunch/Reviewer.svg'; +import Rice from '@/assets/icons/lunch/Rice.svg'; +import SearchIcon from '@/assets/icons/lunch/Search.svg'; +import Send from '@/assets/icons/lunch/Send.svg'; +import Smile from '@/assets/icons/lunch/Smile.svg'; +import ThumbsUp from '@/assets/icons/lunch/ThumbsUp.svg'; export { - As, + ClearDay, + ClearNight, + FewClouds, + Clouds, + BrokenClouds, + ShowerRain, + Rain, + ThunderStorm, + Snow, + Mist, Back, - Calendar, - CalendarFill, + Check, CheckOn, - Clock, - Down, - Etc, - FixedtermWork, - Interview, - Location, - LocationFill, - Meeting, - Right, - Seminar, - Send, - Up, - Info, + Close, + Error, PlusBig, PlusSmall, ExitSmall, + ExitMedium, + LeftSmall, + Profile, + ProfileWithBg, + Right, + Rights, RightSmall, - Direction, - Check, UnCheck, - SearchIcon, + Up, XIcon, - Gift, - Plate, - Chef, - Bento, - Smile, - Confused, - Rice, - ThumbsUp, - Camera, XSBlack, - Profile, - Copy, - CopyBlue, - Subway, - Bus, - Home, - LeftSmall, - DateDish, - DateDishNoPhoto, - Setting, - Coin, - TearOffCalendar, Barcode, Bell, + Destination, + Down, + Home, + HomeActive, Line, - Roulette, - Rights, - Sunny, - Location20, - Delicious, - ClearDay, - ClearNight, - FewClouds, - Clouds, - BrokenClouds, - ShowerRain, - Rain, - ThunderStorm, - Snow, - Mist, - LunchCalendar, Lunch, - Rank1, - Rank2, - Rank3, - Reviewer, - Close, - Top, - CameraFlash, + LunchActive, + LunchCalendar, + My, + MyActive, + Roulette, Servey, ServiceCafeteria, ServiceCalendar, @@ -193,13 +173,53 @@ export { ServiceParking, ServiceReception, ServiceTemp, - ProfileWithBg, - Error, - My, + Setting, + TearOffCalendar, + Top, Write, - Popup, - PopupActive, - Present, + As, + BoxGrey, + BoxWhite, + Bus, + Calendar, + CalendarFill, + Call, + CopyBlue, + Copy, + Direction, + ErrorIcon, + Etc, + FixedtermWork, + Info, + InfoBuilding, + InfoHost, + InfoParking, + InfoPlace, + Interview, + LocationFill, + Location, + Location20, + LocationLine, + Meeting, + RightZoom, + Seminar, + Subway, + Bento, + Camera, + CameraFlash, + Chef, + Clock, + Coin, + Confused, + DateDish, + DateDishNoPhoto, + Delicious, + FoodCafe, + FoodLunchBox, + FoodNoPhoto, + Gift, + Plate, + PlateSmall, Point10, Point500, Point10Pink, @@ -208,16 +228,13 @@ export { Present500, Present1000, Present1500, - InfoBuilding, - InfoPlace, - InfoHost, - InfoParking, - FoodNoPhoto, - FoodCafe, - FoodLunchBox, - HomeActive, - LunchActive, - MyActive, - PlateSmall, - ErrorIcon, + Popup, + PopupActive, + Present, + Reviewer, + Rice, + SearchIcon, + Send, + Smile, + ThumbsUp, }; diff --git a/src/assets/icons/As.svg b/src/assets/icons/invitation/As.svg similarity index 100% rename from src/assets/icons/As.svg rename to src/assets/icons/invitation/As.svg diff --git a/src/assets/icons/invitation/BoxGrey.svg b/src/assets/icons/invitation/BoxGrey.svg new file mode 100644 index 00000000..9f5e5955 --- /dev/null +++ b/src/assets/icons/invitation/BoxGrey.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/invitation/BoxWhite.svg b/src/assets/icons/invitation/BoxWhite.svg new file mode 100644 index 00000000..d74f21f9 --- /dev/null +++ b/src/assets/icons/invitation/BoxWhite.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/Bus.svg b/src/assets/icons/invitation/Bus.svg similarity index 100% rename from src/assets/icons/Bus.svg rename to src/assets/icons/invitation/Bus.svg diff --git a/src/assets/icons/Calendar.svg b/src/assets/icons/invitation/Calendar.svg similarity index 100% rename from src/assets/icons/Calendar.svg rename to src/assets/icons/invitation/Calendar.svg diff --git a/src/assets/icons/Calender-Fill.svg b/src/assets/icons/invitation/Calender-Fill.svg similarity index 100% rename from src/assets/icons/Calender-Fill.svg rename to src/assets/icons/invitation/Calender-Fill.svg diff --git a/src/assets/icons/invitation/Call.svg b/src/assets/icons/invitation/Call.svg new file mode 100644 index 00000000..4a002bc7 --- /dev/null +++ b/src/assets/icons/invitation/Call.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/Copy.svg b/src/assets/icons/invitation/Copy.svg similarity index 100% rename from src/assets/icons/Copy.svg rename to src/assets/icons/invitation/Copy.svg diff --git a/src/assets/icons/Copy_light.svg b/src/assets/icons/invitation/Copy_light.svg similarity index 100% rename from src/assets/icons/Copy_light.svg rename to src/assets/icons/invitation/Copy_light.svg diff --git a/src/assets/icons/Direction.svg b/src/assets/icons/invitation/Direction.svg similarity index 100% rename from src/assets/icons/Direction.svg rename to src/assets/icons/invitation/Direction.svg diff --git a/src/assets/icons/ErrorIcon.svg b/src/assets/icons/invitation/ErrorIcon.svg similarity index 100% rename from src/assets/icons/ErrorIcon.svg rename to src/assets/icons/invitation/ErrorIcon.svg diff --git a/src/assets/icons/Etc.svg b/src/assets/icons/invitation/Etc.svg similarity index 100% rename from src/assets/icons/Etc.svg rename to src/assets/icons/invitation/Etc.svg diff --git a/src/assets/icons/FixedtermWork.svg b/src/assets/icons/invitation/FixedtermWork.svg similarity index 100% rename from src/assets/icons/FixedtermWork.svg rename to src/assets/icons/invitation/FixedtermWork.svg diff --git a/src/assets/icons/Info.svg b/src/assets/icons/invitation/Info.svg similarity index 100% rename from src/assets/icons/Info.svg rename to src/assets/icons/invitation/Info.svg diff --git a/src/assets/icons/InfoBuliding.svg b/src/assets/icons/invitation/InfoBuliding.svg similarity index 100% rename from src/assets/icons/InfoBuliding.svg rename to src/assets/icons/invitation/InfoBuliding.svg diff --git a/src/assets/icons/InfoHost.svg b/src/assets/icons/invitation/InfoHost.svg similarity index 100% rename from src/assets/icons/InfoHost.svg rename to src/assets/icons/invitation/InfoHost.svg diff --git a/src/assets/icons/InfoParking.svg b/src/assets/icons/invitation/InfoParking.svg similarity index 100% rename from src/assets/icons/InfoParking.svg rename to src/assets/icons/invitation/InfoParking.svg diff --git a/src/assets/icons/InfoPlace.svg b/src/assets/icons/invitation/InfoPlace.svg similarity index 100% rename from src/assets/icons/InfoPlace.svg rename to src/assets/icons/invitation/InfoPlace.svg diff --git a/src/assets/icons/Interview.svg b/src/assets/icons/invitation/Interview.svg similarity index 100% rename from src/assets/icons/Interview.svg rename to src/assets/icons/invitation/Interview.svg diff --git a/src/assets/icons/Location-fill.svg b/src/assets/icons/invitation/Location-fill.svg similarity index 100% rename from src/assets/icons/Location-fill.svg rename to src/assets/icons/invitation/Location-fill.svg diff --git a/src/assets/icons/Location.svg b/src/assets/icons/invitation/Location.svg similarity index 100% rename from src/assets/icons/Location.svg rename to src/assets/icons/invitation/Location.svg diff --git a/src/assets/icons/Location20.svg b/src/assets/icons/invitation/Location20.svg similarity index 100% rename from src/assets/icons/Location20.svg rename to src/assets/icons/invitation/Location20.svg diff --git a/src/assets/icons/invitation/LocationLine.svg b/src/assets/icons/invitation/LocationLine.svg new file mode 100644 index 00000000..9a733748 --- /dev/null +++ b/src/assets/icons/invitation/LocationLine.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/icons/meeting.svg b/src/assets/icons/invitation/Meeting.svg similarity index 100% rename from src/assets/icons/meeting.svg rename to src/assets/icons/invitation/Meeting.svg diff --git a/src/assets/icons/invitation/RightZoom.svg b/src/assets/icons/invitation/RightZoom.svg new file mode 100644 index 00000000..681e769e --- /dev/null +++ b/src/assets/icons/invitation/RightZoom.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/seminar.svg b/src/assets/icons/invitation/Seminar.svg similarity index 100% rename from src/assets/icons/seminar.svg rename to src/assets/icons/invitation/Seminar.svg diff --git a/src/assets/icons/Subway.svg b/src/assets/icons/invitation/Subway.svg similarity index 100% rename from src/assets/icons/Subway.svg rename to src/assets/icons/invitation/Subway.svg diff --git a/src/assets/icons/Bento.svg b/src/assets/icons/lunch/Bento.svg similarity index 100% rename from src/assets/icons/Bento.svg rename to src/assets/icons/lunch/Bento.svg diff --git a/src/assets/icons/Camera.svg b/src/assets/icons/lunch/Camera.svg similarity index 100% rename from src/assets/icons/Camera.svg rename to src/assets/icons/lunch/Camera.svg diff --git a/src/assets/icons/CameraFlash.svg b/src/assets/icons/lunch/CameraFlash.svg similarity index 100% rename from src/assets/icons/CameraFlash.svg rename to src/assets/icons/lunch/CameraFlash.svg diff --git a/src/assets/icons/Chef.svg b/src/assets/icons/lunch/Chef.svg similarity index 100% rename from src/assets/icons/Chef.svg rename to src/assets/icons/lunch/Chef.svg diff --git a/src/assets/icons/lunch/Clock.svg b/src/assets/icons/lunch/Clock.svg new file mode 100644 index 00000000..1f3bcdb0 --- /dev/null +++ b/src/assets/icons/lunch/Clock.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/Coin.svg b/src/assets/icons/lunch/Coin.svg similarity index 100% rename from src/assets/icons/Coin.svg rename to src/assets/icons/lunch/Coin.svg diff --git a/src/assets/icons/Confused.svg b/src/assets/icons/lunch/Confused.svg similarity index 100% rename from src/assets/icons/Confused.svg rename to src/assets/icons/lunch/Confused.svg diff --git a/src/assets/icons/DateDish.svg b/src/assets/icons/lunch/DateDish.svg similarity index 100% rename from src/assets/icons/DateDish.svg rename to src/assets/icons/lunch/DateDish.svg diff --git a/src/assets/icons/DateDishNoPhoto.svg b/src/assets/icons/lunch/DateDishNoPhoto.svg similarity index 100% rename from src/assets/icons/DateDishNoPhoto.svg rename to src/assets/icons/lunch/DateDishNoPhoto.svg diff --git a/src/assets/icons/Delicious.svg b/src/assets/icons/lunch/Delicious.svg similarity index 100% rename from src/assets/icons/Delicious.svg rename to src/assets/icons/lunch/Delicious.svg diff --git a/src/assets/icons/foodCafe.svg b/src/assets/icons/lunch/FoodCafe.svg similarity index 100% rename from src/assets/icons/foodCafe.svg rename to src/assets/icons/lunch/FoodCafe.svg diff --git a/src/assets/icons/foodLunchBox.svg b/src/assets/icons/lunch/FoodLunchBox.svg similarity index 100% rename from src/assets/icons/foodLunchBox.svg rename to src/assets/icons/lunch/FoodLunchBox.svg diff --git a/src/assets/icons/foodNoPhoto.svg b/src/assets/icons/lunch/FoodNoPhoto.svg similarity index 100% rename from src/assets/icons/foodNoPhoto.svg rename to src/assets/icons/lunch/FoodNoPhoto.svg diff --git a/src/assets/icons/Gift.svg b/src/assets/icons/lunch/Gift.svg similarity index 100% rename from src/assets/icons/Gift.svg rename to src/assets/icons/lunch/Gift.svg diff --git a/src/assets/icons/Plate.svg b/src/assets/icons/lunch/Plate.svg similarity index 100% rename from src/assets/icons/Plate.svg rename to src/assets/icons/lunch/Plate.svg diff --git a/src/assets/icons/plateSmall.svg b/src/assets/icons/lunch/PlateSmall.svg similarity index 100% rename from src/assets/icons/plateSmall.svg rename to src/assets/icons/lunch/PlateSmall.svg diff --git a/src/assets/icons/point10.svg b/src/assets/icons/lunch/Point10.svg similarity index 100% rename from src/assets/icons/point10.svg rename to src/assets/icons/lunch/Point10.svg diff --git a/src/assets/icons/point1000.svg b/src/assets/icons/lunch/Point1000.svg similarity index 100% rename from src/assets/icons/point1000.svg rename to src/assets/icons/lunch/Point1000.svg diff --git a/src/assets/icons/point10pink.svg b/src/assets/icons/lunch/Point10pink.svg similarity index 100% rename from src/assets/icons/point10pink.svg rename to src/assets/icons/lunch/Point10pink.svg diff --git a/src/assets/icons/point1500.svg b/src/assets/icons/lunch/Point1500.svg similarity index 100% rename from src/assets/icons/point1500.svg rename to src/assets/icons/lunch/Point1500.svg diff --git a/src/assets/icons/point500.svg b/src/assets/icons/lunch/Point500.svg similarity index 100% rename from src/assets/icons/point500.svg rename to src/assets/icons/lunch/Point500.svg diff --git a/src/assets/icons/Popup.svg b/src/assets/icons/lunch/Popup.svg similarity index 100% rename from src/assets/icons/Popup.svg rename to src/assets/icons/lunch/Popup.svg diff --git a/src/assets/icons/PopupActive.svg b/src/assets/icons/lunch/PopupActive.svg similarity index 100% rename from src/assets/icons/PopupActive.svg rename to src/assets/icons/lunch/PopupActive.svg diff --git a/src/assets/icons/present.1500.svg b/src/assets/icons/lunch/Present.1500.svg similarity index 100% rename from src/assets/icons/present.1500.svg rename to src/assets/icons/lunch/Present.1500.svg diff --git a/src/assets/icons/present.svg b/src/assets/icons/lunch/Present.svg similarity index 100% rename from src/assets/icons/present.svg rename to src/assets/icons/lunch/Present.svg diff --git a/src/assets/icons/present1000.svg b/src/assets/icons/lunch/Present1000.svg similarity index 100% rename from src/assets/icons/present1000.svg rename to src/assets/icons/lunch/Present1000.svg diff --git a/src/assets/icons/present500.svg b/src/assets/icons/lunch/Present500.svg similarity index 100% rename from src/assets/icons/present500.svg rename to src/assets/icons/lunch/Present500.svg diff --git a/src/assets/icons/Reviewer.svg b/src/assets/icons/lunch/Reviewer.svg similarity index 87% rename from src/assets/icons/Reviewer.svg rename to src/assets/icons/lunch/Reviewer.svg index 0ef6acb8..57b54ec1 100644 --- a/src/assets/icons/Reviewer.svg +++ b/src/assets/icons/lunch/Reviewer.svg @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/src/assets/icons/Rice.svg b/src/assets/icons/lunch/Rice.svg similarity index 100% rename from src/assets/icons/Rice.svg rename to src/assets/icons/lunch/Rice.svg diff --git a/src/assets/icons/Search.svg b/src/assets/icons/lunch/Search.svg similarity index 100% rename from src/assets/icons/Search.svg rename to src/assets/icons/lunch/Search.svg diff --git a/src/assets/icons/Send.svg b/src/assets/icons/lunch/Send.svg similarity index 100% rename from src/assets/icons/Send.svg rename to src/assets/icons/lunch/Send.svg diff --git a/src/assets/icons/Smile.svg b/src/assets/icons/lunch/Smile.svg similarity index 100% rename from src/assets/icons/Smile.svg rename to src/assets/icons/lunch/Smile.svg diff --git a/src/assets/icons/ThumbsUp.svg b/src/assets/icons/lunch/ThumbsUp.svg similarity index 100% rename from src/assets/icons/ThumbsUp.svg rename to src/assets/icons/lunch/ThumbsUp.svg diff --git a/src/assets/images/index.ts b/src/assets/images/index.ts index 3f1cda38..47ab3729 100644 --- a/src/assets/images/index.ts +++ b/src/assets/images/index.ts @@ -10,6 +10,9 @@ import unLock from '$/roulette/unLock.webp'; import unLockPressed from '$/roulette/unLockPressed.webp'; import coin from '$/point/coin.webp'; import point10 from '$/point/point10.webp'; +import Wrappedgift1 from '$/point/Wrappedgift1.png'; +import invitationPreview from '$/invitation/invitationPreview.png'; +import TestBuildingMap from '$/invitation/TestBuildingMap.png'; export { again, @@ -24,4 +27,7 @@ export { unLockPressed, coin, point10, + Wrappedgift1, + invitationPreview, + TestBuildingMap, }; diff --git a/src/assets/menu.png b/src/assets/menu.png deleted file mode 100644 index 0d63727b..00000000 Binary files a/src/assets/menu.png and /dev/null differ diff --git a/src/assets/ruppy.png b/src/assets/ruppy.png deleted file mode 100644 index 185af651..00000000 Binary files a/src/assets/ruppy.png and /dev/null differ diff --git a/src/assets/testImg/TestBuildingImg.svg b/src/assets/testImg/TestBuildingImg.svg deleted file mode 100644 index ffdfd340..00000000 --- a/src/assets/testImg/TestBuildingImg.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/assets/testImg/TestMap.svg b/src/assets/testImg/TestMap.svg deleted file mode 100644 index 7e4dca48..00000000 --- a/src/assets/testImg/TestMap.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/assets/testImg/index.ts b/src/assets/testImg/index.ts deleted file mode 100644 index 3db5e457..00000000 --- a/src/assets/testImg/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import TestMap from '@/assets/testImg/TestMap.svg'; -import TestBuildingImg from '@/assets/testImg/TestBuildingImg.svg'; - -export { TestMap, TestBuildingImg }; diff --git a/src/components/auth/AuthForm.tsx b/src/components/auth/AuthForm.tsx deleted file mode 100644 index fd8b6bd9..00000000 --- a/src/components/auth/AuthForm.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import mq from '@/utils/mediaquery'; -import Category from '@/components/common/Category'; -import { css } from '@emotion/react'; -import { COMMON_USER_NAME } from '@/constants/common'; -import useSaveStore from '@/stores/useSaveStore'; -import { useRouter } from 'next/router'; - -function AuthForm() { - const router = useRouter(); - const MEMBER_TOKEN = process.env.MEMBER_TOKEN as string; - const { setUserToken } = useSaveStore(); - - const onClickCategoryHandler = () => { - setUserToken(MEMBER_TOKEN); - router.push('/'); - }; - - return ( - - - - {COMMON_USER_NAME.map((item) => ( - - - - ))} - - - - ); -} - -const purposeContainerStyles = css` - position: relative; - display: flex; - flex-direction: column; - align-items: center; - gap: 32px; - max-width: 230px; - - ${mq.lg} { - max-width: 640px; - } - ${mq.tab} { - max-width: 1024px; - } -`; - -const categoryContainerStyles = css` - position: relative; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - gap: 16px; -`; - -const categoryWrapperStyles = css` - display: flex; - justify-content: center; - align-items: center; - flex-wrap: wrap; - gap: 10px; - min-width: 280px; - max-width: 360px; - padding: 0 4px 0; - - ${mq.md} { - max-width: 360px; - } - ${mq.lg} { - max-width: 360px; - } - ${mq.tab} { - max-width: 480px; - } -`; - -export default AuthForm; diff --git a/src/components/common/Add.tsx b/src/components/common/Add.tsx index 75ff9524..9f5bec0d 100644 --- a/src/components/common/Add.tsx +++ b/src/components/common/Add.tsx @@ -1,11 +1,11 @@ import theme from '@/styles/theme'; import Icons from '@/components/common/Icons'; -import PlusBig from '@/assets/icons/Plus=big.svg'; +import { PlusBig } from '@/assets/icons'; import { css } from '@emotion/react'; import { AddBtnProps } from '@/types/common/add'; import { COMMON_ICON_NAMES } from '@/constants/common'; -function Add({ isBlue = false, onClick }: AddBtnProps) { +function Add({ isDisabled, isBlue = false, onClick }: AddBtnProps) { const { invitation } = COMMON_ICON_NAMES; return ( @@ -13,6 +13,7 @@ function Add({ isBlue = false, onClick }: AddBtnProps) { type="button" css={isBlue ? addBtnBlueStyles : addBtnGreyStyles} onClick={onClick} + disabled={isDisabled} > {isBlue ? ( @@ -65,8 +66,8 @@ const iconStyles = css` display: flex; justify-content: center; align-items: center; - width: 18px; - height: 18px; + width: 16px; + height: 16px; margin-bottom: 2px; `; diff --git a/src/components/common/AddressBook.tsx b/src/components/common/AddressBook.tsx index da6b1ee1..123d43d8 100644 --- a/src/components/common/AddressBook.tsx +++ b/src/components/common/AddressBook.tsx @@ -1,5 +1,5 @@ import Alert from '@/components/common/Alert'; -import useAlertStore from '@/stores/useAlertStore'; +import useAlertStore from '@/stores/common/useAlertStore'; import theme from '@/styles/theme'; import { css } from '@emotion/react'; import { RightSmall } from '@/assets/icons'; diff --git a/src/components/common/Alert.tsx b/src/components/common/Alert.tsx index a6532748..af7ff718 100644 --- a/src/components/common/Alert.tsx +++ b/src/components/common/Alert.tsx @@ -1,6 +1,6 @@ import { css } from '@emotion/react'; import theme from '@/styles/theme'; -import useAlertStore from '@/stores/useAlertStore'; +import useAlertStore from '@/stores/common/useAlertStore'; import Icons from '@/components/common/Icons'; function Alert() { @@ -9,7 +9,7 @@ function Alert() { return ( - + {alertState.title ? ( alertState.title @@ -18,9 +18,11 @@ function Alert() { )} {alertState.content} - - - + closeAlert(alertState.onClick)} + > @@ -45,47 +47,50 @@ const backgroundStyles = css` const alertContainerStyles = css` position: relative; display: flex; - justify-content: flex-start; - align-items: center; + flex-direction: column; + justify-content: center; width: 90%; max-width: 500px; height: 96px; - padding-left: 20px; border-radius: 16px; background-color: ${theme.palette.state.danger}; z-index: 11; + padding: 0 16px; + gap: 8px; `; -const titleContentWrapperStyles = css` +const contentsWrapperStyles = css` display: flex; - gap: 14px; + gap: 10px; + width: 100%; + height: 100%; `; const alertTitleStyles = css` + width: 20px; + display: flex; + align-items: center; color: ${theme.palette.input.enabled}; - font: ${theme.font.etc.rankingNumber}; - font-size: 36px; + font: ${theme.font.alert.pretendard}; `; const alertContentStyles = css` display: flex; align-items: center; + width: 100%; color: ${theme.palette.greyscale.grey10}; - font: ${theme.font.title.title1_godo}; + font: ${theme.font.alert.pretendard}; white-space: pre-wrap; `; -const btnWrapperStyles = css` - position: absolute; - right: 0; -`; - const defaultBtnStyles = css` + top: 12px; + right: 12px; + display: flex; + align-items: flex-start; color: ${theme.palette.white}; - font: ${theme.font.body.body2_400}; cursor: pointer; - font-size: 24px; - padding: 0 16px 48px 0; + padding-top: 16px; `; export default Alert; diff --git a/src/components/common/BottomSheet.tsx b/src/components/common/BottomSheet.tsx index 941b4d73..1328b455 100644 --- a/src/components/common/BottomSheet.tsx +++ b/src/components/common/BottomSheet.tsx @@ -1,6 +1,6 @@ import { css } from '@emotion/react'; import theme from '@/styles/theme'; -import useBottomSheetStore from '@/stores/useBottomSheetStore'; +import useBottomSheetStore from '@/stores/common/useBottomSheetStore'; function BottomSheet() { const { bottomSheetState, closeBottomSheet } = useBottomSheetStore(); @@ -52,7 +52,7 @@ const containerStyles = (isOpen: boolean) => css` border-radius: 20px 20px 0 0; width: 100%; max-width: 1024px; - max-height: 95vh; + max-height: 90vh; height: auto; background-color: ${theme.palette.white}; animation: ${isOpen diff --git a/src/components/common/Button.tsx b/src/components/common/Button.tsx index cd78d6ce..99958804 100644 --- a/src/components/common/Button.tsx +++ b/src/components/common/Button.tsx @@ -1,6 +1,7 @@ import { COMMON_BUTTON_COLORS } from '@/constants/common'; import { ButtonColorProps, ButtonProps } from '@/types/common/button'; import { css } from '@emotion/react'; +import theme from '@/styles/theme'; function Button({ content, variant, isDisabled, onClick }: ButtonProps) { const variantData = COMMON_BUTTON_COLORS[variant]; @@ -19,18 +20,18 @@ function Button({ content, variant, isDisabled, onClick }: ButtonProps) { const buttonStyles = (variantData: ButtonColorProps) => css` display: flex; - cursor: pointer; - font-family: inherit; justify-content: center; align-items: center; width: 100%; min-width: 100px; - border-radius: 16px; padding: 16px 0; - font-size: 18px; + border: 1px solid ${variantData.color}; + border-radius: 16px; background: ${variantData.background}; color: ${variantData.color}; - border: 1px solid ${variantData.color}; + font: ${theme.font.subTitle.subTitle1_500}; + cursor: pointer; + transition: ease 1300ms; &:disabled { pointer-events: none; @@ -38,8 +39,12 @@ const buttonStyles = (variantData: ButtonColorProps) => css` } &:active { - transition: transform 150ms cubic-bezier(0.4, 0, 0.2, 1); - transform: scale(0.95); + background: linear-gradient( + 0deg, + rgba(0, 0, 0, 0.2) 0%, + rgba(0, 0, 0, 0.2) 100% + ), + ${theme.palette.primary}; } `; diff --git a/src/components/common/Category.tsx b/src/components/common/Category.tsx index 2b5a8975..0d1d6296 100644 --- a/src/components/common/Category.tsx +++ b/src/components/common/Category.tsx @@ -1,8 +1,9 @@ +import Icons from '@/components/common/Icons'; +import theme from '@/styles/theme'; +import mq from '@/utils/mediaquery'; import { COMMON_CATEGORY_COLORS } from '@/constants/common'; import { CategoryProps, CategoryColorProps } from '@/types/common/category'; import { css } from '@emotion/react'; -import Icons from '@/components/common/Icons'; -import mq from '@/utils/mediaquery'; function Category({ icon, title, variant }: CategoryProps) { const variantData = COMMON_CATEGORY_COLORS[variant]; @@ -16,32 +17,21 @@ function Category({ icon, title, variant }: CategoryProps) { ); } - const CategoryContainer = (variantData: CategoryColorProps) => css` display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 10px; - width: 110px; + min-width: 110px; + max-width: 140px; height: 110px; border: ${variantData.border}; border-radius: 16px; background-color: ${variantData.backgroundColor}; cursor: pointer; - &:hover { - border: ${COMMON_CATEGORY_COLORS.hoveredBlue.border}; - - > div { - color: ${COMMON_CATEGORY_COLORS.hoveredBlue.color}; - } - > div > svg { - color: ${COMMON_CATEGORY_COLORS.hoveredBlue.color}; - } - } - - ${mq.tab} { + ${mq.lg} { width: 140px; } `; @@ -56,10 +46,7 @@ const IconContainer = css` const CategoryTitle = (variantData: CategoryColorProps) => css` color: ${variantData.color}; - font-size: 16px; - font-style: normal; - font-weight: 600; - line-height: 24px; + font: ${theme.font.body.body1_500}; `; export default Category; diff --git a/src/components/common/CheckBox.tsx b/src/components/common/CheckBox.tsx index 2e35efdc..30319c03 100644 --- a/src/components/common/CheckBox.tsx +++ b/src/components/common/CheckBox.tsx @@ -1,6 +1,6 @@ +import Icons from '@/components/common/Icons'; import theme from '@/styles/theme'; -import useSaveStore from '@/stores/useSaveStore'; -import { Check, UnCheck } from '@/assets/icons'; +import useSaveStore from '@/stores/common/useSaveStore'; import { CheckBoxProps } from '@/types/common/checkBox'; import { css } from '@emotion/react'; import { useEffect, useState } from 'react'; @@ -27,11 +27,13 @@ function CheckBox({ text }: CheckBoxProps) { - {isSelect ? ( - - ) : ( - - )} + + {isSelect ? ( + + ) : ( + + )} + {text} @@ -54,6 +56,7 @@ const checkBoxContainerStyles = (isSelect: boolean) => css` align-items: center; p { + font: ${theme.font.body.body1_400}; color: ${isSelect ? theme.palette.primary : theme.palette.greyscale.grey40}; @@ -61,12 +64,8 @@ const checkBoxContainerStyles = (isSelect: boolean) => css` } `; -const btnImgStyles = css` - display: flex; - justify-content: center; - align-items: center; +const iconWrapper = css` width: 20px; height: 20px; margin-right: 4px; - flex-grow: 0; `; diff --git a/src/components/common/ErrorMessage.tsx b/src/components/common/ErrorMessage.tsx index c091d831..e0e8b7ff 100644 --- a/src/components/common/ErrorMessage.tsx +++ b/src/components/common/ErrorMessage.tsx @@ -16,28 +16,38 @@ function ErrorMessage({ errorType }: ErrorMessageProps) { return ( - + + + {errorMessage(errorType)} ); } -const errorContainerStyles = () => css` +const errorContainerStyles = css` display: flex; justify-content: left; align-items: center; + gap: 4px; width: 100%; margin-top: 12px; - color: ${theme.palette.state.warning}; `; -const errorTextStyles = () => css` +const iconWrapperStyles = css` + display: flex; + justify-content: center; + align-items: center; + width: 20px; + height: 20px; +`; + +const errorTextStyles = css` display: flex; justify-content: left; text-align: center; align-items: center; - margin-left: 4px; color: ${theme.palette.state.warning}; + font: ${theme.font.body.body3_400}; `; export default ErrorMessage; diff --git a/src/components/common/Header.tsx b/src/components/common/Header.tsx index 350c4bff..5109dcab 100644 --- a/src/components/common/Header.tsx +++ b/src/components/common/Header.tsx @@ -5,7 +5,7 @@ import { Back } from '@/assets/icons'; import mq from '@/utils/mediaquery'; import theme from '@/styles/theme'; import Icons from '@/components/common/Icons'; -import usePagesStore from '@/stores/usePagesStore'; +import usePagesStore from '@/stores/common/usePagesStore'; function Header({ title, @@ -89,8 +89,10 @@ const headerStyles = ( `; const titleStyles = css` - font: ${theme.font.subTitle.subTitle1_600}; justify-self: center; + span { + font: ${theme.font.subTitle.subTitle1_600}; + } `; const iconStyles = (type: string) => css` diff --git a/src/components/common/Icons.tsx b/src/components/common/Icons.tsx index bb2b7ee6..e70a4c59 100644 --- a/src/components/common/Icons.tsx +++ b/src/components/common/Icons.tsx @@ -10,7 +10,6 @@ import { Etc, Info, Direction, - CopyBlue, Home, Back, Coin, @@ -41,6 +40,7 @@ import { My, Error, ExitSmall, + ExitMedium, InfoBuilding, InfoPlace, InfoHost, @@ -49,6 +49,8 @@ import { LunchActive, MyActive, Popup, + Copy, + Reviewer, } from '@/assets/icons'; function Icons({ icon, color, size }: IconsProps) { @@ -72,7 +74,7 @@ function Icons({ icon, color, size }: IconsProps) { case invitation.direction: return ; case invitation.copy: - return ; + return ; case invitation.list: return ; case invitation.plusSmall: @@ -149,6 +151,10 @@ function Icons({ icon, color, size }: IconsProps) { return ; case common.exitSmall: return ; + case common.exitMedium: + return ; + case common.reviewer: + return ; default: break; } diff --git a/src/components/common/Input.tsx b/src/components/common/Input.tsx index 36848bd6..b81a8234 100644 --- a/src/components/common/Input.tsx +++ b/src/components/common/Input.tsx @@ -1,9 +1,9 @@ -import React from 'react'; import { css } from '@emotion/react'; import { InputColorProps, InputProps } from '@/types/common/input'; import { COMMON_INPUT_COLORS } from '@/constants/common'; import { Location } from '@/assets/icons'; import ErrorMessage from '@/components/common/ErrorMessage'; +import theme from '@/styles/theme'; function Input({ inputIcon, @@ -18,6 +18,7 @@ function Input({ value, onChange, name, + type, }: InputProps) { const variantData = COMMON_INPUT_COLORS[variant]; @@ -36,11 +37,11 @@ function Input({ onChange={onChange} cols={30} rows={row} - css={inputTextareaStyles(variantData)} + css={inputTextareaStyles(variantData, type)} disabled={isDisabled} maxLength={maxLength} /> - + {value.length}/{maxLength + 1} @@ -129,16 +130,26 @@ const inputStyles = () => css` border-radius: 12px; height: 58px; min-width: 100px; - font-size: 1rem; + font: ${theme.font.subTitle.subTitle2_400}; `; -const inputTextareaStyles = (variantData: InputColorProps) => css` - margin: 17px 16px; +const inputTextareaStyles = ( + variantData: InputColorProps, + type: string | undefined, +) => css` + height: ${type === 'review' ? '96px' : 'none'}; + margin: ${type === 'review' ? '12px 16px' : '16px'}; border: none; background-color: ${variantData.backgroundColor}; font: ${variantData.font}; font-size: 1rem; resize: none; + letter-spacing: 0; + line-height: 24px; +`; + +const maxLengthStyles = css` + color: ${theme.palette.greyscale.grey30}; `; export default Input; diff --git a/src/components/common/Loading.tsx b/src/components/common/Loading.tsx new file mode 100644 index 00000000..bedaaab7 --- /dev/null +++ b/src/components/common/Loading.tsx @@ -0,0 +1,8 @@ +import theme from '@/styles/theme'; +import { BeatLoader } from 'react-spinners'; + +function Loading() { + return ; +} + +export default Loading; diff --git a/src/components/common/Modal.tsx b/src/components/common/Modal.tsx index 5d031cbe..198d89a9 100644 --- a/src/components/common/Modal.tsx +++ b/src/components/common/Modal.tsx @@ -1,7 +1,7 @@ import { css } from '@emotion/react'; import { ModalProps } from '@/types/common/modal'; import theme from '@/styles/theme'; -import useModalStore from '@/stores/useModalStore'; +import useModalStore from '@/stores/common/useModalStore'; import { COMMON_MODAL_BUTTONS } from '@/constants/common'; function Modal({ isAlert, content, onClick }: ModalProps) { diff --git a/src/components/common/RadioBtnBox.tsx b/src/components/common/RadioBtnBox.tsx index 79a3ac8a..f70548d0 100644 --- a/src/components/common/RadioBtnBox.tsx +++ b/src/components/common/RadioBtnBox.tsx @@ -1,8 +1,8 @@ import theme from '@/styles/theme'; -import { RadioBtnBoxProps } from '@/types/common/radioBtn'; import { css } from '@emotion/react'; import { useState } from 'react'; import { CheckOn, UnCheck } from '@/assets/icons'; +import { RadioBtnBoxProps } from '@/types/common/radioBtn'; function RadioBtnBox({ list, name, placeholder }: RadioBtnBoxProps) { const [selectData, setSelectData] = useState(list[0]); @@ -28,7 +28,6 @@ function RadioBtnBox({ list, name, placeholder }: RadioBtnBoxProps) { return ( {list.map((item) => { - // console.log(selectData === item); return ( diff --git a/src/components/common/TimeSelector.tsx b/src/components/common/TimeSelector.tsx index 53586dbf..31c475ee 100644 --- a/src/components/common/TimeSelector.tsx +++ b/src/components/common/TimeSelector.tsx @@ -4,23 +4,25 @@ import { TimeSelectorColorProps, } from '@/types/invitation/create'; import { css } from '@emotion/react'; -import { useState } from 'react'; -import useTimeSelectorStore from '@/stores/useTimeSelectorStore'; +import React, { useState } from 'react'; +import useInvitaionTimeSelectorStore from '@/stores/invitaion/useInvitationTimeSelectorStore'; import theme from '@/styles/theme'; function TimeSelector({ content, status }: TimeSelectorProps) { + // content "00:00" 문자열 + // 토글을 통해 가변할 수 있는 variant state 관리 const [varientState, setVarientState] = useState(status); const [time] = useState(content); const variantData = COMMON_TIME_SELECTOR[varientState]; - const { setSelectTime, clearSelectTime } = useTimeSelectorStore(); + const { setSelectTime } = useInvitaionTimeSelectorStore(); const { abled, enabled, disabled } = COMMON_TIME_SELECTOR; const onClickHandler = () => { - clearSelectTime(); // 선택시 버튼 상태 변경 + // abled 선택 가능 / enabled 선택 / disabled 선택 불가 if (varientState === abled.status) { setVarientState(enabled.status); } else if (varientState === enabled.status) { @@ -71,4 +73,4 @@ const timeSelectorStyles = (variantData: TimeSelectorColorProps) => css` } `; -export default TimeSelector; +export default React.memo(TimeSelector); diff --git a/src/components/common/Title.tsx b/src/components/common/Title.tsx index f5a4d292..4d8b2f1a 100644 --- a/src/components/common/Title.tsx +++ b/src/components/common/Title.tsx @@ -4,8 +4,9 @@ import { css } from '@emotion/react'; import Icons from '@/components/common/Icons'; import { Barcode, Bell, LunchCalendar, Setting } from '@/assets/icons'; import Link from 'next/link'; +import Loading from '@/components/common/Loading'; -function Title({ title, isMain, part }: TitleProps) { +function Title({ title, isMain, part, loading }: TitleProps) { const renderIcons = (type: string) => { switch (type) { case 'main': @@ -31,7 +32,7 @@ function Title({ title, isMain, part }: TitleProps) { return ( - {title} + {loading ? : title} {isMain && } {renderIcons(part)} diff --git a/src/components/common/ToWrite.tsx b/src/components/common/ToWrite.tsx index b378967c..7f47a540 100644 --- a/src/components/common/ToWrite.tsx +++ b/src/components/common/ToWrite.tsx @@ -31,9 +31,9 @@ const wrapperStyles = (hasBnb?: boolean) => css` `; const topButtonStyles = css` - border: 16px; - width: 44px; - height: 44px; + padding: 15px; + width: 54px; + height: 54px; border-radius: 100px; background-color: ${theme.palette.white}; box-shadow: diff --git a/src/components/common/Toggle.tsx b/src/components/common/Toggle.tsx index a64639fa..ba2192a7 100644 --- a/src/components/common/Toggle.tsx +++ b/src/components/common/Toggle.tsx @@ -1,5 +1,5 @@ import theme from '@/styles/theme'; -import useToggleStore from '@/stores/useToggleStore'; +import useToggleStore from '@/stores/common/useToggleStore'; import { COMMON_TOGGLE_TITLE } from '@/constants/common'; import { css } from '@emotion/react'; diff --git a/src/components/home/bulletin/HomeBulletinNotice.tsx b/src/components/home/bulletin/HomeBulletinNotice.tsx index 3e19f0bf..d629fc54 100644 --- a/src/components/home/bulletin/HomeBulletinNotice.tsx +++ b/src/components/home/bulletin/HomeBulletinNotice.tsx @@ -21,14 +21,23 @@ const containerStyles = css` `; const titleStyles = css` - font: ${theme.font.body.body3_400}; + font: ${theme.font.body.body3_300}; color: ${theme.palette.greyscale.grey50}; line-height: 21px; + min-width: 24px; + + @media (min-width: 320px) { + font: ${theme.font.body.body3_400}; + } `; const contentStyles = css` - font: ${theme.font.body.body3_400}; + font: ${theme.font.body.body3_300}; color: ${theme.palette.greyscale.grey70}; line-height: 21px; + + @media (min-width: 320px) { + font: ${theme.font.body.body3_400}; + } `; export default HomeBulletinNotice; diff --git a/src/components/home/bulletin/HomeBulletinWeather.tsx b/src/components/home/bulletin/HomeBulletinWeather.tsx index ec046e94..3ba55b20 100644 --- a/src/components/home/bulletin/HomeBulletinWeather.tsx +++ b/src/components/home/bulletin/HomeBulletinWeather.tsx @@ -5,7 +5,7 @@ import Icons from '@/components/common/Icons'; import getWeatherIcon from '@/utils/getWeatherIcon'; import { useQuery } from '@tanstack/react-query'; import getCelsius from '@/utils/getCelsius'; -import { BeatLoader } from 'react-spinners'; +import Loading from '@/components/common/Loading'; function HomeBulletinWeather() { const { data, isError, error, isLoading } = useQuery( @@ -19,7 +19,7 @@ function HomeBulletinWeather() { // TOFIXED: 에러용 단순 모달 필요 if (isError) return {error?.toString()}; - if (isLoading) return ; + if (isLoading) return ; const weatherId = data?.weather[0].icon; const weatherTemp = data?.main.temp; diff --git a/src/components/home/reception/index.tsx b/src/components/home/reception/index.tsx index 1cd6f325..0402bf6c 100644 --- a/src/components/home/reception/index.tsx +++ b/src/components/home/reception/index.tsx @@ -6,7 +6,7 @@ import { css } from '@emotion/react'; import { Rights } from '@/assets/icons'; import useFetch from '@/hooks/useFetch'; import { getMyData } from '@/pages/api/home/homeRequests'; -import useUserStore from '@/stores/useUserStore'; +import useUserStore from '@/stores/common/useUserStore'; import { useEffect } from 'react'; function HomeReception() { diff --git a/src/components/home/service/HomeServiceCard.tsx b/src/components/home/service/HomeServiceCard.tsx index ed1c5d32..7f81ab64 100644 --- a/src/components/home/service/HomeServiceCard.tsx +++ b/src/components/home/service/HomeServiceCard.tsx @@ -18,20 +18,45 @@ const containerStyles = css` display: flex; height: 87px; padding: 12px auto; - width: 72px; flex-direction: column; justify-content: center; align-items: center; gap: 8px; border-radius: 12px; + max-width: 72px; + width: 100%; + + > svg { + height: 32px; + } &:active { border-radius: 12px; background: ${theme.palette.greyscale.grey5}; } + @media (min-width: 320px) { + max-width: 72px; + } + ${mq.md} { - width: 91px; + max-width: 84px; + } + + @media (min-width: 440px) { + max-width: 96px; + } + + ${mq.lg} { + max-width: 120px; + } + + ${mq.tab} { + max-width: 176px; + } + + @media (min-width: 768px) { + max-width: 232px; } `; @@ -39,6 +64,9 @@ const titleStyles = css` font: ${theme.font.body.body2_400}; color: ${theme.palette.greyscale.grey60}; line-height: 22px; + + ${mq.md} { + } `; export default HomeServiceCard; diff --git a/src/components/home/service/index.tsx b/src/components/home/service/index.tsx index 99e48f69..88862692 100644 --- a/src/components/home/service/index.tsx +++ b/src/components/home/service/index.tsx @@ -29,7 +29,6 @@ function HomeService() { const containerStyles = css` display: flex; flex-direction: column; - align-items: flex-start; gap: 16px; align-self: stretch; flex-wrap: wrap; @@ -37,9 +36,11 @@ const containerStyles = css` `; const titleStyles = css` + display: flex; font: ${theme.font.body.body1_600}; color: ${theme.palette.title}; line-height: 24px; + justify-content: flex-start; `; const menusStyles = css` @@ -47,8 +48,22 @@ const menusStyles = css` padding: 0px 16px; justify-content: center; align-items: center; - gap: 10px; flex-wrap: wrap; + gap: 12px; + + @media (min-width: 320px) { + gap: 4px; + } + + ${mq.md} { + justify-content: center; + width: 100%; + } + + ${mq.lg} { + justify-content: center; + width: 100%; + } ${mq.tab} { justify-content: center; diff --git a/src/components/invitation/InvitaitonEditForm.tsx b/src/components/invitation/InvitaitonEditForm.tsx new file mode 100644 index 00000000..5d30284e --- /dev/null +++ b/src/components/invitation/InvitaitonEditForm.tsx @@ -0,0 +1,39 @@ +import usePagesStore from '@/stores/common/usePagesStore'; +import InvitationDoneContainer from '@/components/invitation/create/InvitationDoneContainer'; +import InvitationEdit from '@/components/invitation/edit/InvitationEdit'; +import { InvitationEditProps } from '@/types/invitation/edit'; +import { css } from '@emotion/react'; +import mq from '@/utils/mediaquery'; + +function InvitaitonEditForm({ id }: InvitationEditProps) { + const { nextComponent } = usePagesStore(); + if (nextComponent === 'InvitationDoneContainer') { + return ( + + ; + + ); + } + + return ; +} + +const containerStyles = css` + position: relative; + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; + margin: 0 auto; + ${mq.md} { + max-width: 360px; + } + ${mq.lg} { + max-width: 480px; + } + ${mq.tab} { + max-width: 640px; + } +`; +export default InvitaitonEditForm; diff --git a/src/components/invitation/InvitationCreateForm.tsx b/src/components/invitation/InvitationCreateForm.tsx index 8eeb11e8..22005ce2 100644 --- a/src/components/invitation/InvitationCreateForm.tsx +++ b/src/components/invitation/InvitationCreateForm.tsx @@ -1,19 +1,22 @@ -import usePagesStore from '@/stores/usePagesStore'; import InvitationPurposeContainer from '@/components/invitation/create/InvitationPurposeContainer'; import InvitationVisitorsContainer from '@/components/invitation/create/InvitationVisitorsContainer'; import InvitationInfoContainer from '@/components/invitation/create/InvitationInfoContainer'; import InvitationDoneContainer from '@/components/invitation/create/InvitationDoneContainer'; +import COMPONENT_NAME from '@/constants/common/pages'; +import usePagesStore from '@/stores/common/usePagesStore'; +import { ComponentName } from '@/types/common/pages'; function InvitationCreateForm() { const { nextComponent } = usePagesStore(); + const { invitation }: ComponentName = COMPONENT_NAME; - if (nextComponent === 'InvitationVisitorsContainer') { + if (nextComponent === invitation.create.visitors) { return ; } - if (nextComponent === 'InvitationInfoContainer') { + if (nextComponent === invitation.create.info) { return ; } - if (nextComponent === 'InvitationDoneContainer') { + if (nextComponent === invitation.create.done) { return ; } diff --git a/src/components/invitation/InvitationViewForm.tsx b/src/components/invitation/InvitationViewForm.tsx index ee76c415..4e2624f0 100644 --- a/src/components/invitation/InvitationViewForm.tsx +++ b/src/components/invitation/InvitationViewForm.tsx @@ -1,6 +1,6 @@ import Header from '@/components/common/Header'; import useFetch from '@/hooks/useFetch'; -import usePagesStore from '@/stores/usePagesStore'; +import usePagesStore from '@/stores/common/usePagesStore'; import InvitationQrInfo from '@/components/invitation/view/InvitationQrInfo'; import InvitationBuildingInfo from '@/components/invitation/view/InvitationBuildingInfo'; import InvitationHostInfo from '@/components/invitation/view/InvitationHostInfo'; @@ -8,9 +8,10 @@ import InvitationOfficeInfo from '@/components/invitation/view/InvitationOfficeI import InvitationViewFooter from '@/components/invitation/view/InvitationViewFooter'; import InvitationInfoContainer from '@/components/invitation/view/InvitationInfoContainer'; import InvitationCarouselContainer from '@/components/invitation/view/InvitationCarouselContainer'; +import InvitationParking from '@/components/invitation/view/InvitationParking'; import { css } from '@emotion/react'; import { INVITATION_VEIW_INFO_TEXTS } from '@/constants/invitation/viewTexts'; -import useSaveStore from '@/stores/useSaveStore'; +import useSaveStore from '@/stores/common/useSaveStore'; import { useEffect } from 'react'; import { getVisitationInfo } from '@/pages/api/invitation/viewRequests'; @@ -28,17 +29,20 @@ function InvitationViewForm() { }, [VISITOR_TOKEN, setVisitorToken]); if (nextComponent === `${INVITATION_VEIW_INFO_TEXTS.category.building}`) { - return ; + return ; } if (nextComponent === `${INVITATION_VEIW_INFO_TEXTS.category.host}`) { return ; } if (nextComponent === `${INVITATION_VEIW_INFO_TEXTS.category.place}`) { - return ; + return ; } if (nextComponent === `${INVITATION_VEIW_INFO_TEXTS.category.code}`) { return ; } + if (nextComponent === `${INVITATION_VEIW_INFO_TEXTS.category.parking}`) { + return ; + } const onClickHandler = () => { setNextComponent(`${INVITATION_VEIW_INFO_TEXTS.category.main}`); @@ -48,6 +52,7 @@ function InvitationViewForm() { diff --git a/src/components/invitation/create/InvitationDateTime.tsx b/src/components/invitation/create/InvitationDateTime.tsx index 61533c88..aee8b9fd 100644 --- a/src/components/invitation/create/InvitationDateTime.tsx +++ b/src/components/invitation/create/InvitationDateTime.tsx @@ -6,12 +6,14 @@ import Button from '@/components/common/Button'; import Alert from '@/components/common/Alert'; import InvitationSelectTime from '@/components/invitation/create/InvitationSelectTime'; import CREATE_TEXTS from '@/constants/invitation/createTexts'; -import useBottomSheetStore from '@/stores/useBottomSheetStore'; -import useAlertStore from '@/stores/useAlertStore'; -import useToggleStore from '@/stores/useToggleStore'; -import useInvitationCreateStore from '@/stores/useInvitationCreateStore'; +import useBottomSheetStore from '@/stores/common/useBottomSheetStore'; +import useAlertStore from '@/stores/common/useAlertStore'; +import useToggleStore from '@/stores/common/useToggleStore'; +import useInvitaionTimeSelectorStore from '@/stores/invitaion/useInvitationTimeSelectorStore'; +import useInvitationCreateStore from '@/stores/invitaion/useInvitationCreateStore'; import getFormatDate from '@/utils/getFormatDate'; import getCommonTimes from '@/utils/getCommonTimeList'; +import parseDate from '@/utils/parseDate'; import theme from '@/styles/theme'; import mq from '@/utils/mediaquery'; import { addMonths } from 'date-fns'; @@ -20,19 +22,16 @@ import { useState, useEffect } from 'react'; import { InvitationCreateTexts } from '@/types/invitation/create'; import { getInvitationTimeList } from '@/pages/api/invitation/createRequests'; import { GetInvitationTimeListData } from '@/types/invitation/api'; -import useTimeSelectorStore from '@/stores/useTimeSelectorStore'; -import parseDate from '@/utils/parseDate'; function InvitationDateTime() { - const { title, button }: InvitationCreateTexts = CREATE_TEXTS; + const { title, button, error }: InvitationCreateTexts = CREATE_TEXTS; const { closeBottomSheet } = useBottomSheetStore(); const { alertState, openAlert } = useAlertStore(); const { isOn, onToggle, offToggle } = useToggleStore(); - const { selectTime } = useTimeSelectorStore(); + const { selectTime, clearSelectTime } = useInvitaionTimeSelectorStore(); const { createContents, setCreateContents } = useInvitationCreateStore(); // Thu Oct 26 2023 00:00:00 GMT+0900 (한국 표준시) - // 임시로 12일로 설정해둔 상태 -> 추후 new Date()로 변경 const [startDate, setStartDate] = useState(new Date()); const [endDate, setEndDate] = useState(new Date()); const [isUpdated, setIsUpdated] = useState(false); @@ -55,31 +54,35 @@ function InvitationDateTime() { }); setFetchData(response?.data); } - } catch (error) { - openAlert('ERROR!', '예약 가능 시간 API에 문제가 생겼습니다.'); + } catch (err: unknown) { + openAlert('🚨', error.timeAPI); } }; - fetchGetTimeList(); - }, [ - createContents.commonPlaceId, - startDate, - endDate, - openAlert, - isUpdated, - offToggle, - onToggle, - ]); + }, [createContents.commonPlaceId, startDate, endDate, isUpdated]); + // API호출 응답값인 fetchData가 바뀔 때마다 공통된 시간 출력 + // commonTimes ['15:00', '15:30', '17:00', '17:30'] useEffect(() => { if (fetchData) { - // 기존 fetchData 중에서 공통된 시간만 출력 - // ['15:00:00', '15:30:00', '17:00:00', '17:30:00'] - const common = getCommonTimes(fetchData); + const common = getCommonTimes(startDate, endDate, fetchData); setCommonTimes([...common]); } + // 날짜를 다시 지정했으므로 기존 선택했던 시간 배열 초기화 + clearSelectTime(); }, [fetchData]); + // commonTimes.Length(가능한 시간)에 따라 종일 활성화 여부 + // 가능한 시간이 18개(09~18시)가 아닌 경우에는 토글 off하여 시간 선택 유도 + useEffect(() => { + if (commonTimes.length !== 18) { + // 타임 셀렉터 렌더링 이슈로 임시 setTimeout 함수 지정 + setTimeout(() => offToggle(), 200); + } else { + onToggle(); + } + }, [commonTimes]); + // startDate나 endDate가 변경될 때 isUpdated === true useEffect(() => { if (startDate && endDate) { @@ -106,11 +109,13 @@ function InvitationDateTime() { // 토글 버튼 비활성화 = 시간 선택했을 때 setCreateContents( 'startDate', - `${getFormatDate(startDate)}T${selectTime}:00`, + `${getFormatDate(startDate)}T${selectTime[0]}:00`, ); setCreateContents( 'endDate', - `${getFormatDate(endDate)}T${parseDate(selectTime as string)}:00`, + `${getFormatDate(endDate)}T${parseDate( + selectTime[selectTime.length - 1] as string, + )}:00`, ); } @@ -125,7 +130,7 @@ function InvitationDateTime() { { router.push(`/user/invitation-list`); diff --git a/src/components/invitation/create/InvitationDoneMessage.tsx b/src/components/invitation/create/InvitationDoneMessage.tsx index 739c8bce..4d663edc 100644 --- a/src/components/invitation/create/InvitationDoneMessage.tsx +++ b/src/components/invitation/create/InvitationDoneMessage.tsx @@ -1,26 +1,43 @@ -import useInvitationCreateStore from '@/stores/useInvitationCreateStore'; +import useInvitationCreateStore from '@/stores/invitaion/useInvitationCreateStore'; +import useInvitationEditStore from '@/stores/invitaion/useInvitationEditStore'; +import usePagesStore from '@/stores/common/usePagesStore'; import theme from '@/styles/theme'; import { css } from '@emotion/react'; import { Send } from '@/assets/icons'; function InvitationDoneMessage() { + const { backComponents } = usePagesStore(); const { createContents } = useInvitationCreateStore(); - const { visitors } = createContents; + const { editContents } = useInvitationEditStore(); + const resendVisitors = editContents.visitors; + const createVisitors = createContents.visitors; return ( - - {visitors.length === 1 - ? `${visitors[0].name}님께\n초대장을 보냈어요` - : `${visitors[0].name}님 외 ${ - visitors.length - 1 - }명에게\n초대장을 보냈어요`} - + {/* 초대장 생성 플로우 - 이전 컴포넌트가 InvitationInfoContainer일 때 사용 */} + {backComponents[backComponents.length - 1] === + 'InvitationInfoContainer' ? ( + + {createVisitors?.length === 1 + ? `${createVisitors[0]?.name}님께\n초대장을 보냈어요` + : `${createVisitors[0]?.name}님 외 ${ + createVisitors.length - 1 + }명에게\n초대장을 보냈어요`} + + ) : ( + // 초대장 수정 플로우 - 재전송 방문자가 1명 이상 있을 때 사용 + + {resendVisitors && resendVisitors?.length === 1 + ? `${resendVisitors[0]?.name}님께\n초대장을 다시 보냈어요` + : `${resendVisitors && resendVisitors[0]?.name}님 외 ${ + resendVisitors && resendVisitors.length - 1 + }명에게\n초대장을 다시 보냈어요`} + + )} ); } - const containerStyles = css` display: flex; flex-direction: column; diff --git a/src/components/invitation/create/InvitationInfo.tsx b/src/components/invitation/create/InvitationInfo.tsx index 94382842..c86772d8 100644 --- a/src/components/invitation/create/InvitationInfo.tsx +++ b/src/components/invitation/create/InvitationInfo.tsx @@ -4,21 +4,23 @@ import Alert from '@/components/common/Alert'; import BottomSheet from '@/components/common/BottomSheet'; import InvitationPlace from '@/components/invitation/create/InvitationPlace'; import InvitationDateTime from '@/components/invitation/create/InvitationDateTime'; -import useInvitationCreateStore from '@/stores/useInvitationCreateStore'; -import useBottomSheetStore from '@/stores/useBottomSheetStore'; -import useAlertStore from '@/stores/useAlertStore'; +import useInvitationCreateStore from '@/stores/invitaion/useInvitationCreateStore'; +import useBottomSheetStore from '@/stores/common/useBottomSheetStore'; +import useAlertStore from '@/stores/common/useAlertStore'; import useFetch from '@/hooks/useFetch'; import CREATE_TEXTS from '@/constants/invitation/createTexts'; import theme from '@/styles/theme'; -import mq from '@/utils/mediaquery'; +import { css } from '@emotion/react'; import { useState, useEffect } from 'react'; -import { Location, Calendar, Clock } from '@/assets/icons'; +import { LocationLine, Calendar, Clock } from '@/assets/icons'; import { COMMON_ERROR_MESSAGE } from '@/constants/common'; import { getInvitationPlaceList } from '@/pages/api/invitation/createRequests'; import { GetInvitationPlaceData } from '@/types/invitation/api'; -import { InvitationInfoProps } from '@/types/invitation/create'; import { ErrorMessageProps } from '@/types/common/errorMessage'; -import { css } from '@emotion/react'; +import { + InvitationCreateTexts, + InvitationInfoProps, +} from '@/types/invitation/create'; function InvitationInfo({ tip, @@ -29,11 +31,13 @@ function InvitationInfo({ const { createContents } = useInvitationCreateStore(); const { bottomSheetState, openBottomSheet } = useBottomSheetStore(); const { alertState, openAlert } = useAlertStore(); - const { title, placeholder, checkbox } = CREATE_TEXTS; + + const { title, placeholder, checkbox }: InvitationCreateTexts = CREATE_TEXTS; const { noPlace }: ErrorMessageProps = COMMON_ERROR_MESSAGE; const [placeList, setPlaceList] = useState(); + // 날짜/시간 input value const [date, setDate] = useState(''); const [time, setTime] = useState(''); @@ -42,19 +46,31 @@ function InvitationInfo({ fetchFn: getInvitationPlaceList, }); + // 초대 가능한 장소 응답 데이터 저장 useEffect(() => { - // 초대 가능한 장소 응답 데이터 저장 if (response?.data) { setPlaceList(response.data); } }, [response]); + // 초대장 스토어 데이터가 변할 때 startDate, endDate 설정 useEffect(() => { - if (createContents.startDate) { + if (createContents.startDate.includes('undefined')) { + // 시간을 선택하지 않거나 유효한 예약 시간이 아닐 경우 + openAlert('', '예약 가능한 시간을 다시 확인해 주세요!'); + setDate(''); + setTime(''); + } else if (createContents.startDate) { setDate( - `${createContents.startDate.split('T')[0]} ~ ${ + // startDate와 endDate가 같을 경우: yyyy-mm-dd + // 다를 경우: yyyy-mm-dd ~ yyyy-mm-dd 표기 + createContents.startDate.split('T')[0] === createContents.endDate.split('T')[0] - }`, + ? `${createContents.startDate.split('T')[0]} + ` + : `${createContents.startDate.split('T')[0]} ~ ${ + createContents.endDate.split('T')[0] + }`, ); setTime( `${createContents.startDate @@ -63,9 +79,6 @@ function InvitationInfo({ .split('T')[1] ?.slice(0, 5)}`, ); - } else { - setDate(''); - setTime(''); } }, [createContents]); @@ -93,7 +106,7 @@ function InvitationInfo({ {/* 장소 선택 */} - + ([]); const [tip, setTip] = useState(visit.visitMsgText); @@ -49,23 +51,28 @@ function InvitationInfoContainer() { // 모달에서 전송을 눌렀을 때 최종 초대장 데이터 useEffect(() => { if (isConfirmed) { + // 모달에서 전송하기 버튼 눌렀을 때 스토어에 tip 저장 setCreateContents('description', tip); const postData = async () => { try { + // 스토어에 저장된 초대장 데이터로 초대장 API 호출 const response = await postInvitation(createContents); - // 성공했을 때에만 다음 컴포넌트 연결 + // 초대장 생성 성공했을 때에만 다음 컴포넌트 연결 + // 다음 렌더링 컴포넌트: 초대 완료 if (response.status === 201) { - setNextComponent('InvitationDoneContainer'); + setNextComponent(invitation.create.done); } } catch (err: unknown) { const error = err as ErrorProps; - openAlert('🚨', error.response?.error); + openAlert('🚨', error.message); } }; postData(); } + // '다음에도 이 메세지를 사용'을 선택했을 때 작성 tip 스토어 저장 + // 해제했을 때 스토어에 저장된 값 삭제 if (visit.visitMsg) { setVisitMsgText(tip); } else { @@ -81,47 +88,46 @@ function InvitationInfoContainer() { setCreateContents('visitors', deletedVisitors); }; - // 방문 팁 작성 + // 방문 팁 작성 핸들러 const onChangeTipHandler = ( - e: ChangeEvent | ChangeEvent, + e: + | React.ChangeEvent + | React.ChangeEvent, ) => { setTip(e.target.value); }; - // input 포커스될 때 버튼 숨김 + // input 포커스될 때 '초대장 보내기' 버튼 숨김 const onFocusInputHandler = () => { setIsFocused(true); }; - // input 블러될 때 버튼 활성 + // input 블러될 때 '초대장 보내기' 버튼 활성 const onBlurInputHandler = () => { setTimeout(() => setIsFocused(false), 300); }; - // 하단 버튼 핸들러 (초대장 보내기) + // 하단 버튼 '초대장 보내기' 핸들러 const onClickBtnHandler = () => { openModal(modal.send.title, modal.send.content); }; // 최종 전송 확인 핸들러 (모달) const onClickModalHandler = () => { - if (initialCreateState !== createContents) { - setIsConfirmed(!isConfirmed); - closeModal(); - } else { - openAlert('📢', '초대장 정보를 다시 확인해 주세요!'); - closeModal(); - } + setIsConfirmed(!isConfirmed); + closeModal(); }; return ( + {/* 초대 장소, 날짜, 시간 선택 */} + {/* 방문자 리스트 */} {modalState.isOpen && ( + // btn : 전송하기 )} {alertState.isOpen && } @@ -150,17 +163,7 @@ const containerStyles = css` gap: 40px; width: 100%; min-width: 280px; - max-width: 360px; - - ${mq.md} { - max-width: 480px; - } - ${mq.lg} { - max-width: 640px; - } - ${mq.tab} { - max-width: 1024px; - } + max-width: 1024px; `; const buttonWrapperStyles = (isFocused: boolean) => css` @@ -169,21 +172,8 @@ const buttonWrapperStyles = (isFocused: boolean) => css` display: ${isFocused ? 'none' : 'block'}; width: 100%; min-width: 280px; - max-width: 360px; + max-width: 1024px; padding: 0 16px 20px; - - ${mq.md} { - min-width: 361px; - max-width: 480px; - } - ${mq.lg} { - min-width: 481px; - max-width: 640px; - } - ${mq.tab} { - min-width: 641px; - max-width: 1024px; - } `; export default InvitationInfoContainer; diff --git a/src/components/invitation/create/InvitationPlace.tsx b/src/components/invitation/create/InvitationPlace.tsx index baea6be4..fdb64e15 100644 --- a/src/components/invitation/create/InvitationPlace.tsx +++ b/src/components/invitation/create/InvitationPlace.tsx @@ -1,14 +1,14 @@ import Button from '@/components/common/Button'; import RadioBtn from '@/components/common/RadioBtn'; import CREATE_TEXTS from '@/constants/invitation/createTexts'; -import useBottomSheetStore from '@/stores/useBottomSheetStore'; -import useInvitationCreateStore from '@/stores/useInvitationCreateStore'; +import useBottomSheetStore from '@/stores/common/useBottomSheetStore'; +import useInvitationCreateStore from '@/stores/invitaion/useInvitationCreateStore'; import getIsCommonData from '@/utils/getIsCommonData'; import getPlaceId from '@/utils/getPlaceId'; import theme from '@/styles/theme'; import mq from '@/utils/mediaquery'; import { css } from '@emotion/react'; -import { useState, useEffect, ChangeEvent } from 'react'; +import { useState, useEffect } from 'react'; import { InvitationCreateTexts, InvitationPlaceProps, @@ -18,6 +18,7 @@ import { function InvitationPlace({ placeList }: InvitationPlaceProps) { const { closeBottomSheet } = useBottomSheetStore(); const { setCreateContents } = useInvitationCreateStore(); + const { title, button, placeholder, radioBtn }: InvitationCreateTexts = CREATE_TEXTS; @@ -46,17 +47,18 @@ function InvitationPlace({ placeList }: InvitationPlaceProps) { }, [allPlaceList, selectPlaceName]); // 라디오버튼 선택 - const onChangeRadioHandler = (e: ChangeEvent) => { + const onChangeRadioHandler = (e: React.ChangeEvent) => { setSelectPlaceName(e.target.value); }; // 직접입력 - const onChangeInputHandler = (e: ChangeEvent) => { + const onChangeInputHandler = (e: React.ChangeEvent) => { setSelectPlaceName(e.target.value); }; - // 하단 버튼 핸들러 + // 하단 '완료' 버튼 핸들러 const onClickBtnHandler = () => { + // 초대장 생성 스토어에 초대 장소명, ID 저장 setCreateContents('officeName', selectPlaceName); setCreateContents('commonPlaceId', selectPlaceId); closeBottomSheet(); diff --git a/src/components/invitation/create/InvitationPreview.tsx b/src/components/invitation/create/InvitationPreview.tsx new file mode 100644 index 00000000..72ff2758 --- /dev/null +++ b/src/components/invitation/create/InvitationPreview.tsx @@ -0,0 +1,63 @@ +import Image from 'next/image'; +import Icons from '@/components/common/Icons'; +import theme from '@/styles/theme'; +import { css } from '@emotion/react'; +import { COMMON_ICON_NAMES } from '@/constants/common'; +import { InvitationPreviewProps } from '@/types/invitation/create'; +import { invitationPreview } from '@/assets/images'; + +function InvitationPreview({ onClick }: InvitationPreviewProps) { + const { common } = COMMON_ICON_NAMES; + + return ( + + + + + + + + + ); +} + +const backgroundStyles = css` + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + justify-content: center; + align-items: center; + background-color: rgba(0, 0, 0, 0.75); + z-index: 10; +`; + +const previewContainerStyles = css` + position: relative; + display: flex; + justify-content: center; + align-items: center; +`; + +const iconStyles = css` + position: fixed; + top: 20px; + right: 20px; + width: 20px; + height: 20px; +`; + +export default InvitationPreview; diff --git a/src/components/invitation/create/InvitationPurposeContainer.tsx b/src/components/invitation/create/InvitationPurposeContainer.tsx index 3fdecaba..0a978ee0 100644 --- a/src/components/invitation/create/InvitationPurposeContainer.tsx +++ b/src/components/invitation/create/InvitationPurposeContainer.tsx @@ -1,18 +1,18 @@ import theme from '@/styles/theme'; -import mq from '@/utils/mediaquery'; import Input from '@/components/common/Input'; import Icons from '@/components/common/Icons'; import Category from '@/components/common/Category'; import Button from '@/components/common/Button'; import CREATE_TEXTS from '@/constants/invitation/createTexts'; -import useViewStore from '@/stores/usePagesStore'; -import useInvitationHeaderTitleStore from '@/stores/useInvitationHeaderTitleStore'; -import useInvitationCreateStore from '@/stores/useInvitationCreateStore'; -import { ChangeEvent, useEffect, useState } from 'react'; +import COMPONENT_NAME from '@/constants/common/pages'; +import useViewStore from '@/stores/common/usePagesStore'; +import useInvitationHeaderTitleStore from '@/stores/invitaion/useInvitationHeaderTitleStore'; +import useInvitationCreateStore from '@/stores/invitaion/useInvitationCreateStore'; +import { useEffect, useState } from 'react'; import { css } from '@emotion/react'; import { COMMON_CATEGORIES } from '@/constants/common'; +import { ComponentName } from '@/types/common/pages'; import { - CategoryInvitation, CommonCategory, InvitationCreateTexts, } from '@/types/invitation/create'; @@ -21,7 +21,8 @@ function InvitationPurposeContainer() { const { setNextComponent } = useViewStore(); const { setHeaderTitle } = useInvitationHeaderTitleStore(); const { setCreateContents, clearCreateContents } = useInvitationCreateStore(); - const { invitation }: CategoryInvitation = COMMON_CATEGORIES; + + const { invitation }: ComponentName = COMPONENT_NAME; const { header, title, @@ -29,41 +30,49 @@ function InvitationPurposeContainer() { placeholder, button, }: InvitationCreateTexts = CREATE_TEXTS; - const categories: CommonCategory[] = Object.values(invitation); + + const categories: CommonCategory[] = Object.values(COMMON_CATEGORIES); + const [selectedCategory, setSelectedCategory] = useState('meeting'); const [etcPurpose, setEtcPurpose] = useState(''); const [isFocused, setIsFocused] = useState(false); - // 최초 렌더링 시 기존값 초기화 + // 최초 렌더링 시 타이틀 & 초대장 데이터 초기화 useEffect(() => { + setHeaderTitle(header.default); clearCreateContents(); - }, [clearCreateContents]); + }, [clearCreateContents, header.default, setHeaderTitle]); - // 방문 목적 카테고리 선택 + // 초대 목적 카테고리 선택 const onClickCategoryHandler = (item: CommonCategory) => { setSelectedCategory(item.icon); }; - // 기타 선택 시 방문 목적 작성 + // 초대 목적 - 기타 선택 시 방문 목적 작성 const onChange = ( - e: ChangeEvent | ChangeEvent, + e: + | React.ChangeEvent + | React.ChangeEvent, ) => { setEtcPurpose(e.target.value); }; - // input 포커스될 때 버튼 숨김 + // input 포커스될 때 '다음' 버튼 숨김 const onFocusInputHandler = () => { setIsFocused(true); }; - // input 블러될 때 버튼 활성 + // input 블러될 때 '다음' 버튼 활성 const onBlurInputHandler = () => { setTimeout(() => setIsFocused(false), 300); }; - // 하단 버튼 클릭 핸들러 + // 하단 '다음' 버튼 클릭 핸들러 const onClickBtnHandler = () => { - setNextComponent('InvitationVisitorsContainer'); + // 다음 렌더링 컴포넌트: 방문자 정보 + // 타이틀 스토어에 초대 목적 저장 + // 초대장 생성 스토어에 초대 목적 저장 (기타일 경우 사용자 입력값 저장) + setNextComponent(invitation.create.visitors); setHeaderTitle(header[selectedCategory]); setCreateContents( 'purpose', @@ -97,10 +106,10 @@ function InvitationPurposeContainer() { - {description[selectedCategory]} + {description[selectedCategory]} @@ -119,6 +128,7 @@ function InvitationPurposeContainer() { content={button.next} variant="blue" onClick={onClickBtnHandler} + // 초대 목적 - 기타를 선택할 경우, 사용자 입력값이 없으면 버튼 비활성화 isDisabled={selectedCategory === 'etc' && !etcPurpose.length} /> @@ -133,25 +143,17 @@ const purposeContainerStyles = css` flex-direction: column; align-items: center; gap: 32px; - min-width: 280px; - max-width: 360px; - - ${mq.md} { - max-width: 480px; - } - ${mq.lg} { - max-width: 640px; - } - ${mq.tab} { - max-width: 1024px; - } + width: 100%; + min-width: 240px; + max-width: 1024px; `; const purposeQuestionStyles = css` display: flex; + justify-content: flex-start; width: 100%; min-width: 280px; - max-width: 360px; + max-width: 450px; height: 28px; padding-left: 4px; @@ -161,16 +163,6 @@ const purposeQuestionStyles = css` line-height: 28px; text-align: left; } - - ${mq.md} { - max-width: 360px; - } - ${mq.lg} { - max-width: 360px; - } - ${mq.tab} { - max-width: 420px; - } `; const categoryContainerStyles = css` @@ -180,6 +172,7 @@ const categoryContainerStyles = css` justify-content: center; align-items: center; gap: 16px; + width: 100%; `; const categoryWrapperStyles = css` @@ -188,19 +181,10 @@ const categoryWrapperStyles = css` align-items: center; flex-wrap: wrap; gap: 10px; + width: 100%; min-width: 280px; - max-width: 360px; + max-width: 450px; padding: 0 4px 0; - - ${mq.md} { - max-width: 360px; - } - ${mq.lg} { - max-width: 360px; - } - ${mq.tab} { - max-width: 480px; - } `; const descriptionWrapperStyles = css` @@ -208,8 +192,8 @@ const descriptionWrapperStyles = css` justify-content: flex-start; gap: 4px; width: 100%; - min-width: 260px; - max-width: 280px; + min-width: 240px; + max-width: 440px; height: 44px; padding: 0 4px 0; @@ -220,35 +204,26 @@ const descriptionWrapperStyles = css` line-height: 22px; text-align: left; } +`; - ${mq.md} { - max-width: 360px; - } - ${mq.lg} { - max-width: 360px; - } - ${mq.tab} { - max-width: 440px; - } +const descriptionStyles = css` + display: flex; + justify-content: flex-start; + word-break: break-all; + width: 100%; + min-width: 200px; + max-width: 450px; `; const iconWrapperStyles = css` padding-top: 4px; `; -const inputWrapperStyles = css` - max-width: 280px; - - ${mq.md} { - min-width: 360px; - } - ${mq.lg} { - min-width: 360px; - } - ${mq.tab} { - min-width: 440px; - max-width: 1024px; - } +const inputWrapperStyles = (isFocused: boolean) => css` + width: 100%; + min-width: 240px; + max-width: 440px; + margin-bottom: ${isFocused ? '30px' : '0'}; `; const buttonWrapperStyles = (isFocused: boolean) => css` @@ -257,21 +232,8 @@ const buttonWrapperStyles = (isFocused: boolean) => css` display: ${isFocused ? 'none' : 'block'}; width: 100%; min-width: 280px; - max-width: 360px; + max-width: 1024px; padding: 0 16px 20px; - - ${mq.md} { - min-width: 361px; - max-width: 480px; - } - ${mq.lg} { - min-width: 481px; - max-width: 640px; - } - ${mq.tab} { - min-width: 641px; - max-width: 1024px; - } `; export default InvitationPurposeContainer; diff --git a/src/components/invitation/create/InvitationSelectTime.tsx b/src/components/invitation/create/InvitationSelectTime.tsx index a7c790e9..9188a48e 100644 --- a/src/components/invitation/create/InvitationSelectTime.tsx +++ b/src/components/invitation/create/InvitationSelectTime.tsx @@ -1,48 +1,103 @@ import TimeSelector from '@/components/common/TimeSelector'; import createTimeSlots from '@/utils/createTimeSlots'; -import useToggleStore from '@/stores/useToggleStore'; +import useToggleStore from '@/stores/common/useToggleStore'; +import useInvitaionTimeSelectorStore from '@/stores/invitaion/useInvitationTimeSelectorStore'; +import useInvitationCreateStore from '@/stores/invitaion/useInvitationCreateStore'; import theme from '@/styles/theme'; import { css } from '@emotion/react'; import { useState, useEffect } from 'react'; import { InvitationSelectTimeProps, TimeSlot } from '@/types/invitation/create'; +import { BoxGrey, BoxWhite } from '@/assets/icons'; function InvitationSelectTime({ commonTimes }: InvitationSelectTimeProps) { - // commonTimes ['15:00', '15:30', '17:00', '17:30'] + // commonTimes + // ['15:00', '15:30', '17:00', '17:30'] + // [{...오전}, {...오후}] const [timeSlot, setTimeSlot] = useState([[], []]); + const [isUpdated, setIsUpdated] = useState(false); const { isOn } = useToggleStore(); + const { selectTime } = useInvitaionTimeSelectorStore(); + const { createContents } = useInvitationCreateStore(); + const { commonPlaceId } = createContents; useEffect(() => { - const res = createTimeSlots(JSON.parse(JSON.stringify(commonTimes))); + const res = createTimeSlots( + JSON.parse(JSON.stringify(commonTimes)), + commonPlaceId, + ); setTimeSlot(res); - }, [commonTimes]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + // 시작 시간/종료 시간 선택 시 timeSlot 재정의 + useEffect(() => { + setIsUpdated(false); + const res = createTimeSlots( + JSON.parse(JSON.stringify(commonTimes)), + commonPlaceId, + ); + setTimeSlot(res); + setIsUpdated(true); + }, [commonPlaceId, commonTimes]); + + // 시작 시간 ~ 종료 시간 사이 선택 처리 (enabled) + useEffect(() => { + if (isUpdated && selectTime.length >= 2) { + const amSlot = timeSlot[0].map((slot) => { + if (slot.time >= selectTime[0] && slot.time <= selectTime[1]) { + slot.status = 'enabled'; + } + return slot; + }); + const pmSlot = timeSlot[1].map((slot) => { + if (slot.time >= selectTime[0] && slot.time <= selectTime[1]) { + slot.status = 'enabled'; + } + return slot; + }); + setTimeSlot([[...amSlot], [...pmSlot]]); + } + }, [isUpdated, selectTime, timeSlot]); return ( !isOn && ( - - 오전 - - {timeSlot[0].map((value) => ( - - ))} + + + 오전 + + {timeSlot[0].map((value) => ( + + ))} + + + + 오후 + + {timeSlot[1].map((value) => ( + + ))} + - - 오후 - - {timeSlot[1].map((value) => ( - - ))} + + + + 선택 가능 + + + + 선택 불가 @@ -51,6 +106,12 @@ function InvitationSelectTime({ commonTimes }: InvitationSelectTimeProps) { } const containerStyles = css` + display: flex; + flex-direction: column; + gap: 16px; +`; + +const selectorContainerStyles = css` display: flex; flex-direction: column; align-items: flex-start; @@ -58,7 +119,7 @@ const containerStyles = css` align-self: stretch; `; -const wrapperStyles = css` +const selectorWrapperStyles = css` display: flex; flex-direction: column; align-items: flex-start; @@ -79,4 +140,26 @@ const selectorStyles = css` flex-wrap: wrap; `; +const availableTextStyles = css` + display: flex; + justify-content: flex-end; + gap: 12px; +`; + +const boxWrapperStyles = css` + display: flex; + align-items: center; + gap: 4px; +`; + +const able = css` + font: ${theme.font.body.body3_500}; + color: ${theme.palette.greyscale.grey50}; +`; + +const disable = css` + font: ${theme.font.body.body3_500}; + color: ${theme.palette.greyscale.grey40}; +`; + export default InvitationSelectTime; diff --git a/src/components/invitation/create/InvitationVisitorsContainer.tsx b/src/components/invitation/create/InvitationVisitorsContainer.tsx index f44630e9..10a13276 100644 --- a/src/components/invitation/create/InvitationVisitorsContainer.tsx +++ b/src/components/invitation/create/InvitationVisitorsContainer.tsx @@ -4,18 +4,19 @@ import Alert from '@/components/common/Alert'; import Add from '@/components/common/Add'; import AddressBook from '@/components/common/AddressBook'; import InvitationVisitorsList from '@/components/invitation/create/InvitationVisitorsList'; +import useAlertStore from '@/stores/common/useAlertStore'; +import useViewStore from '@/stores/common/usePagesStore'; import CREATE_TEXTS from '@/constants/invitation/createTexts'; -import useAlertStore from '@/stores/useAlertStore'; -import useViewStore from '@/stores/usePagesStore'; -import useInvitationCreateStore from '@/stores/useInvitationCreateStore'; +import COMPONENT_NAME from '@/constants/common/pages'; +import useInvitationCreateStore from '@/stores/invitaion/useInvitationCreateStore'; import theme from '@/styles/theme'; -import mq from '@/utils/mediaquery'; import { css } from '@emotion/react'; -import { ChangeEvent, useState } from 'react'; +import { useState } from 'react'; import { COMMON_ERROR_MESSAGE } from '@/constants/common'; import { InvitationCreateTexts } from '@/types/invitation/create'; import { VisitorInfo } from '@/types/invitation/api'; import { ErrorMessageProps } from '@/types/common/errorMessage'; +import { ComponentName } from '@/types/common/pages'; import { checkValidationName, checkValidationContact, @@ -23,23 +24,26 @@ import { function InvitationVisitorsContainer() { const { setNextComponent } = useViewStore(); - const { createContents, setCreateContents } = useInvitationCreateStore(); const { alertState, openAlert } = useAlertStore(); + const { createContents, setCreateContents } = useInvitationCreateStore(); + + const { invitation }: ComponentName = COMPONENT_NAME; const { title, button, placeholder }: InvitationCreateTexts = CREATE_TEXTS; const { noName, noContact, noNameContact }: ErrorMessageProps = COMMON_ERROR_MESSAGE; - const [isFocused, setIsFocused] = useState(false); const [visitorInfo, setVisitorInfo] = useState({ name: '', contact: '', }); - // 흐름 확인을 위한 예비 데이터 (최종 배포시 삭제) const [visitorsList, setVisitorsList] = useState([]); + const [isFocused, setIsFocused] = useState(false); - // 이름/연락처 입력 + // 이름/전화번호 입력 const onChangeInfoHandler = ( - e: ChangeEvent | ChangeEvent, + e: + | React.ChangeEvent + | React.ChangeEvent, ) => { const { name: infoType, value } = e.target; @@ -90,9 +94,11 @@ function InvitationVisitorsContainer() { setTimeout(() => setIsFocused(false), 300); }; - // 하단 버튼 클릭 핸들러 + // 하단 '다음' 버튼 클릭 핸들러 const onClickBtnHandler = () => { - setNextComponent('InvitationInfoContainer'); + // 다음 렌더링 컴포넌트: 초대 정보 + // 초대장 생성 스토어에 방문자 정보 저장 + setNextComponent(invitation.create.info); setCreateContents('visitors', visitorsList); }; @@ -105,25 +111,27 @@ function InvitationVisitorsContainer() { @@ -131,6 +139,7 @@ function InvitationVisitorsContainer() { + {/* 초대 목적이 면접이고, 등록한 방문자가 1명이면 '추가' 버튼 비활성화 */} {createContents.purpose === 'interview' && visitorsList.length === 1 ? null : ( @@ -148,7 +157,7 @@ function InvitationVisitorsContainer() { content={button.next} variant="blue" onClick={onClickBtnHandler} - isDisabled={visitorsList.length === 0} + isDisabled={visitorsList.length === 0} // 방문자 정보 입력값이 없을 경우 버튼 비활성화 /> {alertState.isOpen && } @@ -162,19 +171,10 @@ const containerStyles = css` flex-direction: column; align-items: center; gap: 30px; + width: 100%; min-width: 280px; - max-width: 360px; + max-width: 640px; overflow: scroll; - - ${mq.md} { - min-width: 361px; - } - ${mq.lg} { - min-width: 481px; - } - ${mq.tab} { - min-width: 641px; - } `; const titleStyles = css` @@ -193,16 +193,6 @@ const titleStyles = css` line-height: 28px; text-align: left; } - - ${mq.md} { - max-width: 360px; - } - ${mq.lg} { - max-width: 480px; - } - ${mq.tab} { - max-width: 640px; - } `; const inputContainerStyles = css` @@ -244,26 +234,13 @@ const buttonWrapperStyles = (isFocused: boolean) => css` display: ${isFocused ? 'none' : 'block'}; width: 100%; min-width: 280px; - max-width: 360px; + max-width: 1024px; padding: 0 16px 20px; background-image: linear-gradient( to top, ${theme.palette.white} 70%, transparent 30% ); - - ${mq.md} { - min-width: 361px; - max-width: 480px; - } - ${mq.lg} { - min-width: 481px; - max-width: 640px; - } - ${mq.tab} { - min-width: 641px; - max-width: 1024px; - } `; export default InvitationVisitorsContainer; diff --git a/src/components/invitation/create/InvitationVisitorsList.tsx b/src/components/invitation/create/InvitationVisitorsList.tsx index 1f107757..b90230c8 100644 --- a/src/components/invitation/create/InvitationVisitorsList.tsx +++ b/src/components/invitation/create/InvitationVisitorsList.tsx @@ -1,12 +1,11 @@ import Add from '@/components/common/Add'; import NameTag from '@/components/common/NameTag'; import BottomSheet from '@/components/common/BottomSheet'; -import useViewStore from '@/stores/usePagesStore'; -import useBottomSheetStore from '@/stores/useBottomSheetStore'; -import useInvitationCreateStore from '@/stores/useInvitationCreateStore'; +import useViewStore from '@/stores/common/usePagesStore'; +import useBottomSheetStore from '@/stores/common/useBottomSheetStore'; +import useInvitationCreateStore from '@/stores/invitaion/useInvitationCreateStore'; import CREATE_TEXTS from '@/constants/invitation/createTexts'; import InvitationAddVisitorList from '@/components/invitation/edit/InvitationAddVisitorList'; -import mq from '@/utils/mediaquery'; import theme from '@/styles/theme'; import { css } from '@emotion/react'; import { @@ -72,18 +71,9 @@ const containerStyles = css` flex-direction: column; gap: 16px; width: 100%; - max-width: 280px; + min-width: 280px; + max-width: 640px; margin-bottom: 100px; - - ${mq.md} { - max-width: 360px; - } - ${mq.lg} { - max-width: 480px; - } - ${mq.tab} { - max-width: 640px; - } `; const titleWrapperStyles = css` diff --git a/src/components/invitation/edit/InvitationAddVisitorList.tsx b/src/components/invitation/edit/InvitationAddVisitorList.tsx index 6b061f69..9e5c60c9 100644 --- a/src/components/invitation/edit/InvitationAddVisitorList.tsx +++ b/src/components/invitation/edit/InvitationAddVisitorList.tsx @@ -6,10 +6,13 @@ import Add from '@/components/common/Add'; import Button from '@/components/common/Button'; import NameTag from '@/components/common/NameTag'; import AddressBook from '@/components/common/AddressBook'; -import useBottomSheetStore from '@/stores/useBottomSheetStore'; -import useInvitationCreateStore from '@/stores/useInvitationCreateStore'; -import useInvitationEditStore from '@/stores/useInvitationEditStore'; +import useBottomSheetStore from '@/stores/common/useBottomSheetStore'; +import useAlertStore from '@/stores/common/useAlertStore'; +import useInvitationCreateStore from '@/stores/invitaion/useInvitationCreateStore'; +import useInvitationEditStore from '@/stores/invitaion/useInvitationEditStore'; +import usePagesStore from '@/stores/common/usePagesStore'; import { InvitationAddVisitorListProps } from '@/types/invitation/edit'; +import Alert from '@/components/common/Alert'; function InvitationAddVisitorList({ visitorsList, @@ -17,21 +20,32 @@ function InvitationAddVisitorList({ const [addVisitorName, setAddVisitorName] = useState(''); const [addVisitorContact, setAddVisitorContact] = useState(''); const { closeBottomSheet } = useBottomSheetStore(); + const { alertState, openAlert } = useAlertStore(); const { createContents, setCreateContents } = useInvitationCreateStore(); const { editContents, setEditContents } = useInvitationEditStore(); + const { nextComponent } = usePagesStore(); // 방문자 삭제 버튼 핸들러 const onClickDeleteVisitorHandler = (name: string) => { - const deletedVisitors = createContents.visitors?.filter( - (visitor) => visitor.name !== name, - ); - setCreateContents('visitors', deletedVisitors); + if (createContents.visitors) { + const deletedVisitors = createContents.visitors?.filter( + (visitor) => visitor.name !== name, + ); + setCreateContents('visitors', deletedVisitors); + } + if (editContents.visitors) { + const deletedVisitors = editContents.visitors?.filter( + (visitor) => visitor.name !== name, + ); + setEditContents('visitors', deletedVisitors); + } }; // 추가 사용자 이름 input handler const onChangeInputNameHandler = (e: React.ChangeEvent) => { setAddVisitorName(e.target.value); }; + // 추가 사용자 연락처 input handler const onChangeInputContactHandler = ( e: React.ChangeEvent, @@ -46,16 +60,19 @@ function InvitationAddVisitorList({ name, contact, }; - // 수정 페이지 - if (editContents.visitors) { - setEditContents('visitors', [...editContents.visitors, newVisitorInfo]); - } - // 생성 페이지 - if (visitorsList) { - setCreateContents('visitors', [ - ...createContents.visitors, - newVisitorInfo, - ]); + + if (nextComponent === 'InvitationInfoContainer') { + // 생성 페이지 + if (visitorsList) { + setCreateContents('visitors', [ + ...createContents.visitors, + newVisitorInfo, + ]); + } + } else if (nextComponent !== 'InvitationInfoContainer') { + if (editContents.visitors) { + setEditContents('visitors', [...editContents.visitors, newVisitorInfo]); + } } // input창 clear setAddVisitorName(''); @@ -64,7 +81,11 @@ function InvitationAddVisitorList({ // + 버튼 클릭시 newVisotorList에 input값 추가 const onClickAddHandler = () => { - newVisitorList(addVisitorName, addVisitorContact); + if (addVisitorName !== '' && addVisitorContact !== '') { + newVisitorList(addVisitorName, addVisitorContact); + } else { + openAlert('📢', '이름과 연락처를 모두 입력해 주세요.'); + } }; // 완료 버튼 @@ -95,7 +116,11 @@ function InvitationAddVisitorList({ - + {addVisitorName !== '' && addVisitorContact !== '' ? ( + + ) : ( + + )} {/* 기존 visitorList */} @@ -107,6 +132,15 @@ function InvitationAddVisitorList({ onClick={onClickDeleteVisitorHandler} /> ))} + {nextComponent !== 'InvitationInfoContainer' && + editContents.visitors && + editContents.visitors?.map((item) => ( + + ))} @@ -115,9 +149,11 @@ function InvitationAddVisitorList({ variant="blue" onClick={onclickDoneBtnHandler} /> + {alertState.isOpen && } ); } + const invitationEditVisitorAddStyles = css` display: flex; flex-direction: column; @@ -141,7 +177,8 @@ const visitorAddInputContainerStyles = css` const visitorAddInputStyles = css` display: flex; border: none; - border-bottom: 2px solid ${theme.palette.greyscale.grey10}; + border-radius: 0; + border-bottom: 1px solid ${theme.palette.greyscale.grey10}; `; const visitorcontactaddBtnStyles = css` display: flex; @@ -162,7 +199,7 @@ const newVisitorListStyles = css` display: flex; flex-direction: row; flex-wrap: wrap; - gap: 0 8px; + gap: 9px; margin-bottom: 16px; `; export default InvitationAddVisitorList; diff --git a/src/components/invitation/edit/InvitationEdit.tsx b/src/components/invitation/edit/InvitationEdit.tsx index c9ce8061..d7eca795 100644 --- a/src/components/invitation/edit/InvitationEdit.tsx +++ b/src/components/invitation/edit/InvitationEdit.tsx @@ -5,8 +5,12 @@ import { getInvitationEditList, getInvitationListItem, } from '@/pages/api/invitation/editRequests'; -import { Clock, Calendar, Location } from '@/assets/icons'; import { InvitationEditProps } from '@/types/invitation/edit'; +import { + GetInvitationListItemData, + InvitationListItemVisitor, +} from '@/types/invitation/api'; +import { Clock, Calendar, Location } from '@/assets/icons'; import theme from '@/styles/theme'; import useFetch from '@/hooks/useFetch'; import Add from '@/components/common/Add'; @@ -16,35 +20,49 @@ import Header from '@/components/common/Header'; import NameTag from '@/components/common/NameTag'; import CheckBox from '@/components/common/CheckBox'; import BottomSheet from '@/components/common/BottomSheet'; -import changeVisitPurpose from '@/utils/changeVisitPurpose'; -import useBottomSheetStore from '@/stores/useBottomSheetStore'; import InvitationEditvisitorAdd from '@/components/invitation/edit/InvitationAddVisitorList'; -import useInvitationEditStore from '@/stores/useInvitationEditStore'; -import { GetInvitationListItemData } from '@/types/invitation/api'; +import changeVisitPurpose from '@/utils/changeVisitPurpose'; +import useViewStore from '@/stores/common/usePagesStore'; +import useModalStore from '@/stores/common/useModalStore'; +import useBottomSheetStore from '@/stores/common/useBottomSheetStore'; +import useInvitationEditStore from '@/stores/invitaion/useInvitationEditStore'; +import Modal from '@/components/common/Modal'; function InvitationEdit({ id }: InvitationEditProps) { + const { setNextComponent } = useViewStore(); + const { modalState, openModal, closeModal } = useModalStore(); const { editContents, setEditContents } = useInvitationEditStore(); const { openBottomSheet } = useBottomSheetStore(); - const [descriptionInputValue, setDescriptionInputValue] = useState(''); + const [newDate, setNewDAte] = useState(''); + const [invitedList, setInvitedList] = useState( + [], + ); const { response } = useFetch({ fetchFn: () => getInvitationListItem(id), }); const data = response && response?.data; + useEffect(() => { + const initInvitedListHandler = () => { + setInvitedList(data && data?.visitors); + }; + initInvitedListHandler(); + }, [data?.visitors]); + const setInitStateHandler = ( startDate: string, endDate: string, initData?: GetInvitationListItemData, ) => { setEditContents('commonPlaceId', initData?.commonPlaceId); - setEditContents('description', initData?.description); + setEditContents( + 'description', + editContents.description || initData?.description, + ); setEditContents('startDate', startDate); setEditContents('endDate', endDate); }; - useEffect(() => { - setInitStateHandler(startDate, endDate, data); - }, []); // 수정용 일시 데이터로 변환 const editStartDateFometer = (date?: string, time?: string) => { @@ -65,21 +83,40 @@ function InvitationEdit({ id }: InvitationEditProps) { }; const timeValue = timeValueFormeter(data?.startTime, data?.endTime); - // 이미 초대된 방문자 목록 - const invitedList = data?.visitors; - // 방문 목적 영한 변환 const purpose = changeVisitPurpose(data?.purpose); - const onClickHandler = () => { + // 발송 완료 방문자 목록 + const resendList = invitedList?.map((item) => { + const { visitorId, ...newItem } = item; + return newItem; + }); + + const resendInvitatuion = () => { + if (editContents && editContents?.visitors?.length === 0) { + setEditContents('visitors', [...editContents.visitors, ...resendList]); + } + }; + + // 초대장 다시 보내기 버튼 클릭시 + const onClickModalHandler = () => { getInvitationEditList(editContents, id as string); + resendInvitatuion(); + closeModal(); + setNextComponent('InvitationDoneContainer'); + }; + const onClickHandler = () => { + openModal( + `${INVITATION_EDIT_TEXTS.modal.title}`, + `${INVITATION_EDIT_TEXTS.modal.content}`, + ); + setInitStateHandler(startDate, endDate, data); }; const onChangeEditTextHandler = ( e: | React.ChangeEvent | React.ChangeEvent, ) => { - setDescriptionInputValue(e.target.value); setEditContents('description', e.target.value); }; @@ -88,6 +125,22 @@ function InvitationEdit({ id }: InvitationEditProps) { , ); }; + // 태그 삭제 버튼 클릭시 + const onClickDeleteHandler = async (name: string) => { + if (editContents) { + const deletedVisitors = editContents.visitors?.filter( + (visitor) => visitor.name !== name, + ); + setEditContents('visitors', deletedVisitors); + } + if (invitedList) { + const deleteinvitedVisitList = invitedList?.filter( + (visitor) => visitor.name !== name, + ); + setInvitedList(deleteinvitedVisitList); + } + }; + return ( - + - + {purpose === '면접' ? ( + { + setNewDAte(e.target.value); + }} + /> + ) : ( + + )} - + + {purpose === '면접' ? ( + + ) : ( + + )} @@ -145,7 +204,7 @@ function InvitationEdit({ id }: InvitationEditProps) { ))} @@ -155,7 +214,7 @@ function InvitationEdit({ id }: InvitationEditProps) { ))} @@ -170,6 +229,9 @@ function InvitationEdit({ id }: InvitationEditProps) { onClick={onClickHandler} /> + {modalState.isOpen && ( + + )} ); } @@ -196,7 +258,7 @@ const officeInfoContainerStyles = css` display: flex; align-items: center; padding: 0 16px; - border: 2px solid ${theme.palette.greyscale.grey10}; + border: 1px solid ${theme.palette.greyscale.grey10}; border-radius: 12px; color: ${theme.palette.greyscale.grey30}; input { @@ -206,7 +268,7 @@ const officeInfoContainerStyles = css` const dateTimeContainerStyles = css` display: flex; flex-direction: column; - border: 2px solid ${theme.palette.greyscale.grey10}; + border: 1px solid ${theme.palette.greyscale.grey10}; border-radius: 12px; padding: 0 16px; input { diff --git a/src/components/invitation/view/InvitaitionCarousel.tsx b/src/components/invitation/view/InvitaitionCarousel.tsx index 51072938..aa63c185 100644 --- a/src/components/invitation/view/InvitaitionCarousel.tsx +++ b/src/components/invitation/view/InvitaitionCarousel.tsx @@ -21,20 +21,31 @@ function InvitaitionCarousel({ type }: InvitationCarouselProps) { {type === 'restaurant' ? `${restaurant.subtitle}` : `${cafe.subtitle}`} - {type === 'restaurant' ? `${restaurant.body}` : `${cafe.body}`} + {type === 'restaurant' ? ( + + 테라타워 근처 {restaurant.contents} 추천! + + ) : ( + + 근처 {cafe.title}를 알려드릴게요 + + )} {datas && datas.map((item) => ( - + + {item.restaurantName} {item.inBuilding ? ( @@ -61,6 +72,9 @@ const carouselTitleStyles = css` margin-bottom: 20px; color: ${theme.palette.title}; font: ${theme.font.subTitle.subTitle2_600}; + span { + color: ${theme.palette.primary}; + } `; const carouselStyles = css` @@ -87,11 +101,20 @@ const carouselItemStyles = css` border-radius: 8px; `; const itemImageStyles = css` + width: 135px; + height: 80px; + object-fit: cover; + position: relative; + background-color: aliceblue; border-radius: 8px; +`; +const itemImageContainerStyles = css` width: 135px; height: 80px; position: relative; background-color: aliceblue; + overflow: hidden; + border-radius: 8px; `; const carouselItemInfoStyles = css` display: flex; @@ -100,8 +123,11 @@ const carouselItemInfoStyles = css` align-self: stretch; position: absolute; bottom: 0; - width: 100%; - height: auto; + width: 135px; + height: 52px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; padding: 6px; border-radius: 8px; background: rgba(255, 255, 255, 0.85); @@ -111,7 +137,11 @@ const carouselItemInfoStyles = css` const itemInfoNameStyles = css` font: ${theme.font.body.body1_500}; color: ${theme.palette.greyscale.grey80}; + width: 123px; line-height: 24px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; `; const itemInFloorStyles = css` font: ${theme.font.body.body4}; diff --git a/src/components/invitation/view/InvitationBuildingInfo.tsx b/src/components/invitation/view/InvitationBuildingInfo.tsx index aeffe7fb..dd9653e5 100644 --- a/src/components/invitation/view/InvitationBuildingInfo.tsx +++ b/src/components/invitation/view/InvitationBuildingInfo.tsx @@ -2,12 +2,19 @@ import theme from '@/styles/theme'; import { css } from '@emotion/react'; import { useState } from 'react'; import mq from '@/utils/mediaquery'; +import { Back } from '@/assets/icons'; +import usePagesStore from '@/stores/common/usePagesStore'; +import { InvitationBuildingInfoProps } from '@/types/invitation/view'; import InvitationBuildingInfoItem from './InvitationBuildingInfoItem'; import InvitationBuildingMap from './InvitationBuildingMap'; import InvitationBuildingTitle from './InvitationBuildingTitle'; import InvitationBuildingPublicTransportItem from './InvitationBuildingPublicTransportItem'; -function InvitationBuildingInfo() { +function InvitationBuildingInfo({ data }: InvitationBuildingInfoProps) { + const { goBack } = usePagesStore(); + + const { buildingRepresentativeImageUrl } = data; + // 스크롤 추적을 위한 state, onScrollHandler const [isScrollBottom, setIsScrollBottom] = useState(false); const onScrollHandler = (e: React.UIEvent) => { @@ -22,6 +29,10 @@ function InvitationBuildingInfo() { } }; + const onBackClickHandler = () => { + goBack(); + }; + const publicTransport = [ { platform: 'subway', @@ -34,15 +45,17 @@ function InvitationBuildingInfo() { ]; return ( - + + + onScrollHandler(e)} > @@ -53,11 +66,11 @@ function InvitationBuildingInfo() { /> @@ -91,10 +104,15 @@ const ContainerStyles = css` } `; -const BuildingImgStyles = css` - background-color: #b4b4b4; +const BuildingImgStyles = (props: { + buildingRepresentativeImageUrl: string; +}) => css` + background-image: url(${props.buildingRepresentativeImageUrl}); + background-size: cover; + background-position: 0 20%; height: 500px; margin: 0 -16px; + padding: 16px 16px; `; const BuildingInfoStyles = (props: { isScrollBottom: boolean }) => css` diff --git a/src/components/invitation/view/InvitationBuildingPublicTransportItem.tsx b/src/components/invitation/view/InvitationBuildingPublicTransportItem.tsx index 4a5d9ed0..0e9f89f3 100644 --- a/src/components/invitation/view/InvitationBuildingPublicTransportItem.tsx +++ b/src/components/invitation/view/InvitationBuildingPublicTransportItem.tsx @@ -6,7 +6,7 @@ function InvitationBuildingPublicTransportItem({ platform, location, }: InvitationBuildingPublicTransportItemProps) { - let icon = null; + let icon; if (platform === 'subway') { icon = ; } else if (platform === 'bus') { diff --git a/src/components/invitation/view/InvitationBuildingTitle.tsx b/src/components/invitation/view/InvitationBuildingTitle.tsx index e58a4396..6dce5e10 100644 --- a/src/components/invitation/view/InvitationBuildingTitle.tsx +++ b/src/components/invitation/view/InvitationBuildingTitle.tsx @@ -1,5 +1,6 @@ import Icons from '@/components/common/Icons'; import theme from '@/styles/theme'; +import toast, { Toaster } from 'react-hot-toast'; import { InvitationBuildingTitleProps } from '@/types/invitation/view'; import { css } from '@emotion/react'; @@ -7,15 +8,32 @@ function InvitationBuildingTitle({ title, address, }: InvitationBuildingTitleProps) { + const handleCopyClipBoard = async () => { + try { + await navigator.clipboard.writeText(address); + + toast('주소가 복사되었습니다.', { + style: { + borderRadius: '50px', + backgroundColor: '#4d4d4d', + + color: '#fff', + }, + }); + } catch (error) { + toast('주소복사를 실패했습니다.'); + } + }; + return ( {title} - {address} - - 주소복사 - - + {address} + + + + ); @@ -27,26 +45,14 @@ const TitleStyles = css` `; const AddressStyles = css` - display: flex; - gap: 16px; - align-items: start; - p { + span { color: ${theme.palette.greyscale.grey50}; line-height: 24px; } `; const CopyStyles = css` - display: flex; - align-items: center; - padding: 4px 0; - p { - white-space: nowrap; - margin-right: 4px; - font: ${theme.font.body.body3_400}; - color: ${theme.palette.bluescale.blue50}; - line-height: 21px; - } + transform: translate(0, 20%); `; export default InvitationBuildingTitle; diff --git a/src/components/invitation/view/InvitationFindRoadBtn.tsx b/src/components/invitation/view/InvitationFindRoadBtn.tsx index 3da0c69f..6b63c496 100644 --- a/src/components/invitation/view/InvitationFindRoadBtn.tsx +++ b/src/components/invitation/view/InvitationFindRoadBtn.tsx @@ -1,3 +1,4 @@ +import { TestBuildingMap } from '@/assets/images/'; import Icons from '@/components/common/Icons'; import theme from '@/styles/theme'; import { css } from '@emotion/react'; @@ -5,7 +6,6 @@ import { css } from '@emotion/react'; function InvitationFindRoadBtn() { return ( - 지도! 길찾기 @@ -19,9 +19,14 @@ const mapStyles = css` justify-content: center; align-items: center; position: relative; - height: 268px; margin: 25px 0; - background-color: ${theme.palette.greyscale.grey30}; + background: url(${TestBuildingMap.src}); + + width: 100%; + height: 500px; + background-repeat: no-repeat; + background-size: cover; + background-position: center; `; const buttonStyles = css` diff --git a/src/components/invitation/view/InvitationHostInfo.tsx b/src/components/invitation/view/InvitationHostInfo.tsx index 7ca4f9fc..5a43c8ed 100644 --- a/src/components/invitation/view/InvitationHostInfo.tsx +++ b/src/components/invitation/view/InvitationHostInfo.tsx @@ -2,7 +2,7 @@ import { css } from '@emotion/react'; import theme from '@/styles/theme'; import Header from '@/components/common/Header'; import InvitationHostInfoItem from '@/components/invitation/view/InvitationHostInfoItem'; -import { Profile } from '@/assets/icons'; +import Icon from '@/components/common/Icons'; import { InvitationInfoContainerProps } from '@/types/invitation/view'; import { INVITATION_VEIW_INFO_TEXTS } from '@/constants/invitation/viewTexts'; @@ -11,7 +11,7 @@ function InvitationHostInfo({ data }: InvitationInfoContainerProps) { - + - - {INVITATION_VEIW_INFO_TEXTS.host.card} + + + {INVITATION_VEIW_INFO_TEXTS.host.card} + @@ -39,6 +41,7 @@ const InvitationHostInfoStyles = css` display: flex; flex-direction: column; position: relative; + justify-content: space-between; `; const InvitationHostInfoBackGroundStyles = css` position: absolute; @@ -48,33 +51,31 @@ const InvitationHostInfoBackGroundStyles = css` max-width: 1024px; height: 258px; background-clip: border-box; - background-image: linear-gradient( - -200deg, - rgba(97, 132, 255, 0.3) 1.42%, - rgba(97, 132, 255, 0.16) 27.47%, - rgba(97, 132, 255, 0.09) 57.59%, - rgba(97, 132, 255, 0) 94.71% - ); + background-color: ${theme.palette.bluescale.blue10}; `; const InvitationHostInfoProfileStyles = css` display: flex; justify-content: center; align-items: center; color: ${theme.palette.greyscale.grey30}; - background-color: ${theme.palette.white}; - width: 108px; - height: 108px; + background-color: ${theme.palette.bluescale.blue20}; + width: 100px; + height: 100px; margin: 44px auto; border-radius: 50%; - box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1); + box-shadow: 0px 4px 10px 0px rgba(0, 0, 0, 0.1); `; const InvitationInfoItemContinerStyles = css` + font: ${theme.font.subTitle.subTitle1_500}; margin-top: 30px; `; +const InvitationHostInfoCardContainerSyles = css` + overflow-x: scroll; +`; const InvitationHostInfoCardSyles = css` - min-width: 350px; - min-height: 158px; - margin: 62px 4px 38px; + width: 358px; + height: 200px; + margin: 62px auto 38px; display: flex; justify-content: center; border-radius: 16px; diff --git a/src/components/invitation/view/InvitationHostInfoItem.tsx b/src/components/invitation/view/InvitationHostInfoItem.tsx index 1e9fcb7f..571966ef 100644 --- a/src/components/invitation/view/InvitationHostInfoItem.tsx +++ b/src/components/invitation/view/InvitationHostInfoItem.tsx @@ -1,20 +1,47 @@ -import theme from '@/styles/theme'; import { css } from '@emotion/react'; import { InvitationHostInfoItemProps } from '@/types/invitation/view'; +import toast, { Toaster } from 'react-hot-toast'; import { Copy } from '@/assets/icons'; +import { COMMON_ERROR_MESSAGE } from '@/constants/common/index'; +import theme from '@/styles/theme'; +import Alert from '@/components/common/Alert'; +import useAlertStore from '@/stores/common/useAlertStore'; function InvitationHostInfoItem({ label, content, isContact, }: InvitationHostInfoItemProps) { + const { alertState, openAlert } = useAlertStore(); + + const ClickCopyhandler = async () => { + try { + await navigator.clipboard.writeText(content); + toast(COMMON_ERROR_MESSAGE.copy, { + style: { + borderRadius: '50px', + backgroundColor: '#4d4d4d', + color: '#fff', + }, + }); + } catch (error) { + openAlert('🚨', COMMON_ERROR_MESSAGE.copyFailed); + } + }; + return ( - {label} - + {label} + {content} - {isContact && } + {isContact && ( + + + + )} + {alertState.isOpen && } + ); } @@ -22,24 +49,23 @@ const HostInfoItemStyles = css` display: flex; flex-direction: row; justify-content: space-between; - margin-left: 21px; - .label { - min-width: 47px; - padding: 20px 0; - margin-right: 25px; - font: ${theme.font.subTitle.subTitle1_500}; - color: ${theme.palette.greyscale.grey40}; - } - .content { - display: flex; - justify-content: space-between; - align-items: center; - width: 100%; - padding: 20px 12px; - border-bottom: 1px solid ${theme.palette.greyscale.grey10}; - font: ${theme.font.subTitle.subTitle1_400}; - color: ${theme.palette.greyscale.grey60}; - } +`; +const labelStyles = css` + min-width: 47px; + padding: 20px 0; + margin-right: 25px; + font: ${theme.font.subTitle.subTitle1_500}; + color: ${theme.palette.greyscale.grey40}; +`; +const contactStyles = css` + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + padding: 20px 12px; + border-bottom: 1px solid ${theme.palette.greyscale.grey10}; + font: ${theme.font.subTitle.subTitle1_400}; + color: ${theme.palette.greyscale.grey60}; `; export default InvitationHostInfoItem; diff --git a/src/components/invitation/view/InvitationInfo.tsx b/src/components/invitation/view/InvitationInfo.tsx index deda662b..3a52d100 100644 --- a/src/components/invitation/view/InvitationInfo.tsx +++ b/src/components/invitation/view/InvitationInfo.tsx @@ -1,23 +1,24 @@ import theme from '@/styles/theme'; import { css } from '@emotion/react'; -import { LocationFill, CalendarFill } from '@/assets/icons'; +import { LocationFill, CalendarFill, RightZoom } from '@/assets/icons'; import { InvitationInfoProps, InvitationInfoThemeProps, } from '@/types/invitation/view'; -import usePagesStore from '@/stores/usePagesStore'; +import usePagesStore from '@/stores/common/usePagesStore'; import useFetch from '@/hooks/useFetch'; import Image from 'next/image'; import { getVisitationQr } from '@/pages/api/invitation/viewRequests'; -import { INVITATION_VIEW_TICKET_THEME } from '@/constants/invitation/viewTexts'; -import useThemeStore from '@/stores/useThemeStore'; +import { + INVITATION_VIEW_TICKET_THEME, + INVITATION_VEIW_INFO_TEXTS, +} from '@/constants/invitation/viewTexts'; +import useInvitationThemeStore from '@/stores/invitaion/useInvitationThemeStore'; function InvitationInfo({ value, data }: InvitationInfoProps) { - const { themeState, setThemeState } = useThemeStore(); + const { ticket } = INVITATION_VEIW_INFO_TEXTS; + const { themeState, setThemeState } = useInvitationThemeStore(); const { setNextComponent } = usePagesStore(); - const onClickHandler = (event: React.MouseEvent) => { - setNextComponent((event.target as HTMLButtonElement).id); - }; const { response } = useFetch({ fetchFn: getVisitationQr, }); @@ -36,10 +37,13 @@ function InvitationInfo({ value, data }: InvitationInfoProps) { const startDate = changeDatefometer(data.invitationStartDate); const endDate = changeDatefometer(data.invitationEndDate).substring(5, 10); - // 테마 커스텀 > 어떤 화면에서 커스텀 할지 추후 수정이라 두페이지 모두에 남겨두었습니다 + const onClickHandler = () => { + setNextComponent(value); + }; const onClickSetThemeHandler = () => { // 클릭 시마다 클릭 횟수 증가 setThemeState('clickCount', themeState.clickCount + 1); + if (themeState.clickCount === 4) { setThemeState('clickCount', 0); } @@ -63,85 +67,97 @@ function InvitationInfo({ value, data }: InvitationInfoProps) { const variantData = INVITATION_VIEW_TICKET_THEME[themeState.theme]; return ( - + - - - - - - {data.invitationOfficeName} - - - - + + + + + + + + {data.invitationOfficeName} - - - {startDate} ~ {endDate} + + + - - {startTime} ~ {endTime} + + + {startDate} ~ {endDate} + + {startTime} ~ {endTime} + + - + - 임시출입증 - + {ticket.headers} + - 크게보기 + + {ticket.zoom} + - + ); } const infoContainerStyles = (variantData: InvitationInfoThemeProps) => css` display: flex; flex-direction: row; - text-align: left; - justify-content: space-between; - align-items: flex-start; position: relative; - padding: 30px 0 30px 40px; + padding: 0 0 0 40px; margin: 0 auto 26px; width: 358px; + height: 178px; color: ${theme.palette.white}; background-image: ${variantData.backgroundImage}; - box-shadow: ${variantData.shadow}; border-radius: 12px; ::before { content: ''; position: absolute; - left: 0px; - width: 100%; - height: 78%; - border-radius: 40%; + left: 20px; + width: 90%; + height: 85%; + border-radius: 2%; background: ${variantData.boxShadow}; - filter: blur(20px); /* 그라데이션 설정 */ - z-index: -1; /* 가상 요소를 실제 요소 뒤로 이동 */ + filter: blur(10px); + z-index: -1; } `; +const themeBtnStyles = css` + display: flex; + flex-direction: row; + text-align: left; + justify-content: space-between; + align-items: flex-start; + padding: 34px 0; + color: ${theme.palette.white}; +`; + const infoContainerDesignStyles = ( variantData: InvitationInfoThemeProps, ) => css` position: absolute; top: 36%; - left: -2px; - width: 26px; + left: -20px; + width: 48px; height: 48px; border-radius: 0 100px 100px 0; background-image: ${variantData.side}; @@ -159,6 +175,8 @@ const iconContainerStyles = css` `; const textInfoStyles = css` margin-left: 2px; + font: ${theme.font.body.body1_400}; + line-height: 24px; `; const infoLineStyles = css` display: flex; @@ -180,13 +198,23 @@ const infoQRContainerStyles = css` color: ${theme.palette.white}; cursor: pointer; } - //삭제예정입니다 - .test { - margin: 15px auto; - width: 40px; - height: 40px; - background-color: aliceblue; + div { + font: ${theme.font.body.body1_500}; } `; +const qrStyles = css` + position: relative; + margin: 10px auto; + width: 46px; + height: 46px; +`; +const zoomBtnStyles = css` + display: flex; + flex-direction: row; + white-space: nowrap; + justify-content: center; + align-items: center; + font: ${theme.font.body.body3_500}; +`; export default InvitationInfo; diff --git a/src/components/invitation/view/InvitationInfoCategory.tsx b/src/components/invitation/view/InvitationInfoCategory.tsx index 131671df..c657bf1b 100644 --- a/src/components/invitation/view/InvitationInfoCategory.tsx +++ b/src/components/invitation/view/InvitationInfoCategory.tsx @@ -2,19 +2,19 @@ import { css } from '@emotion/react'; import theme from '@/styles/theme'; import mq from '@/utils/mediaquery'; import { InvitationInfoCategoryProps } from '@/types/invitation/view'; -import usePagesStore from '@/stores/usePagesStore'; +import usePagesStore from '@/stores/common/usePagesStore'; import Icons from '@/components/common/Icons'; -import useThemeStore from '@/stores/useThemeStore'; +import useInvitationThemeStore from '@/stores/invitaion/useInvitationThemeStore'; import { INVITATION_VIEW_TICKET_THEME } from '@/constants/invitation/viewTexts'; function InvitationInfoCategory({ value, icon }: InvitationInfoCategoryProps) { const { setNextComponent } = usePagesStore(); - const { themeState } = useThemeStore(); + const { themeState } = useInvitationThemeStore(); const variantData = INVITATION_VIEW_TICKET_THEME[themeState.theme]; - const onClickHandler = (event: React.MouseEvent) => { - setNextComponent((event.target as HTMLButtonElement).id); + const onClickHandler = () => { + setNextComponent(value); }; return ( @@ -39,12 +39,9 @@ const InvitationInfoCategoryStyles = css` width: 75px; height: 100%; color: ${theme.palette.greyscale.grey50}; - font: ${theme.font.body.body3_500}; - button { - height: 100%; - } span { color: ${theme.palette.greyscale.grey50}; + font: ${theme.font.body.body3_500}; } ${mq.md} { @@ -57,8 +54,6 @@ const InvitationInfoCategoryStyles = css` } `; -const CategoryContainerStyles = css` - margin: 0 auto; -`; +const CategoryContainerStyles = css``; export default InvitationInfoCategory; diff --git a/src/components/invitation/view/InvitationOfficeInfo.tsx b/src/components/invitation/view/InvitationOfficeInfo.tsx index deaf56df..689ad8dd 100644 --- a/src/components/invitation/view/InvitationOfficeInfo.tsx +++ b/src/components/invitation/view/InvitationOfficeInfo.tsx @@ -1,27 +1,34 @@ import Header from '@/components/common/Header'; -import { INVITATION_VIEW_TEXTS } from '@/constants/invitation/viewTexts'; +import { INVITATION_VEIW_INFO_TEXTS } from '@/constants/invitation/viewTexts'; import { css } from '@emotion/react'; import mq from '@/utils/mediaquery'; +import { InvitationOfficeInfoProps } from '@/types/invitation/view'; import InvitationVisitTip from './InvitationOfficeVisitTip'; import InvitationOfficeMap from './InvitationOfficeMap'; import InvitationOfficeLocation from './InvitationOfficeLocation'; -function InvitationOfficeInfo() { +function InvitationOfficeInfo({ data }: InvitationOfficeInfoProps) { return ( - + - + + - + - + + ); } const OfficeInfoStyles = css` margin: 0 auto; + ${mq.md} { max-width: 360px; } @@ -37,4 +44,11 @@ const OfficeInfoStyles = css` } `; +const containerStyles = css` + display: flex; + flex-direction: column; + gap: 50px; + margin-top: 20px; +`; + export default InvitationOfficeInfo; diff --git a/src/components/invitation/view/InvitationOfficeLocation.tsx b/src/components/invitation/view/InvitationOfficeLocation.tsx index 73a204b8..68d4e77f 100644 --- a/src/components/invitation/view/InvitationOfficeLocation.tsx +++ b/src/components/invitation/view/InvitationOfficeLocation.tsx @@ -1,16 +1,16 @@ import theme from '@/styles/theme'; +import { InvitationOfficeLocationProps } from '@/types/invitation/view'; import { css } from '@emotion/react'; -function InvitationOfficeLocation() { - const testText = { - officeName: '식스센스', - officeLocation: '10층 1004호', - }; +function InvitationOfficeLocation({ + invitationOfficeName, + hostCompanyName, +}: InvitationOfficeLocationProps) { return ( - {testText.officeName}사무실은 + {hostCompanyName}사무실은 - {testText.officeLocation}에 있어요 + {invitationOfficeName}에 있어요 ); diff --git a/src/components/invitation/view/InvitationOfficeMap.tsx b/src/components/invitation/view/InvitationOfficeMap.tsx index 7fc590e9..6f585ea7 100644 --- a/src/components/invitation/view/InvitationOfficeMap.tsx +++ b/src/components/invitation/view/InvitationOfficeMap.tsx @@ -1,18 +1,42 @@ -import { TestMap } from '@/assets/testImg'; +import { InvitationOfficeMapProps } from '@/types/invitation/view'; +import mq from '@/utils/mediaquery'; import { css } from '@emotion/react'; +import Image from 'next/image'; -function InvitationOfficeMap() { +function InvitationOfficeMap({ placeType }: InvitationOfficeMapProps) { + let imgUrl = ''; + if (placeType === 'COMPANY') { + imgUrl = + 'https://livable-final.s3.ap-northeast-2.amazonaws.com/Livable_Company_Map.png'; + } + if (placeType === 'COMMON_PLACE') { + imgUrl = + 'https://livable-final.s3.ap-northeast-2.amazonaws.com/Livable_Common_Place_Map.png'; + } return ( - + ); } const MapStyles = css` + width: 100%; + + position: relative; max-width: 500px; margin: 0 auto; padding: 0 55px; + + ${mq.md} { + height: 250px; + } + ${mq.lg} { + height: 350px; + } + ${mq.tab} { + height: 400px; + } `; export default InvitationOfficeMap; diff --git a/src/components/invitation/view/InvitationOfficeVisitTip.tsx b/src/components/invitation/view/InvitationOfficeVisitTip.tsx index 65e07605..1eb349c7 100644 --- a/src/components/invitation/view/InvitationOfficeVisitTip.tsx +++ b/src/components/invitation/view/InvitationOfficeVisitTip.tsx @@ -1,10 +1,10 @@ import theme from '@/styles/theme'; +import { InvitationVisitTipProps } from '@/types/invitation/view'; import { css } from '@emotion/react'; -function InvitationVisitTip() { - // 추후 API값으로 변경예정 - const VisitTipText = - '1층 우측 계단 앞 엘리베이터를 이용하면 빠르게 올라올 수 있어요!'; +function InvitationVisitTip({ invitationTip }: InvitationVisitTipProps) { + const VisitTipText = invitationTip; + return ( 방문 TIP diff --git a/src/components/invitation/view/InvitationParking.tsx b/src/components/invitation/view/InvitationParking.tsx new file mode 100644 index 00000000..cb861f4e --- /dev/null +++ b/src/components/invitation/view/InvitationParking.tsx @@ -0,0 +1,145 @@ +// import Alert from '@/components/common/Alert'; +import Header from '@/components/common/Header'; +import { + INVITATION_CAROUSEL_TEXTS, + INVITATION_VEIW_INFO_TEXTS, +} from '@/constants/invitation/viewTexts'; +import { postParking } from '@/pages/api/invitation/viewRequests'; +// import useAlertStore from '@/stores/useAlertStore'; +import useInvitationParkingStore from '@/stores/invitaion/useInvitationParkingStore'; +// import { ErrorProps } from 'next/error'; +import { useState } from 'react'; +import { css } from '@emotion/react'; +import theme from '@/styles/theme'; +import Button from '@/components/common/Button'; +import mq from '@/utils/mediaquery'; + +function InvitationParking() { + const { carNumber, setCarNumber } = useInvitationParkingStore(); + const [isDone, setisDone] = useState(false); + + // const { alertState, openAlert } = useAlertStore(); + const onClickParkingAddHandler = async () => { + try { + const response = await postParking(carNumber); + + if (response.status === 201) { + setisDone(true); + } + } catch (err) { + // const error = err as ErrorProps; + // openAlert('📢', error.message || ''); + } + setisDone(true); + }; + + const onChangeHandler = (event: React.ChangeEvent) => { + setCarNumber(event.target.value); + }; + + const onClickParkingCancelHandler = () => { + setisDone(false); + setCarNumber(''); + }; + const onClickParkingChangeHandler = () => {}; + return ( + + + {!isDone ? ( + <> + {INVITATION_CAROUSEL_TEXTS.parking.upParking} + + + {/* { content, variant, isDisabled, onClick } */} + + + {/* {alertState.isOpen && } */} + > + ) : ( + <> + {INVITATION_CAROUSEL_TEXTS.parking.doneParking} + + + + + 등록취소 + + + + > + )} + + ); +} + +const containerStyles = css` + p { + margin: 20px 0; + width: 200px; + height: 60px; + font: ${theme.font.title.title2_500}; + } + input { + margin-bottom: 80px; + } +`; +const btnDivStyles = css` + display: flex; + flex-direction: column; + gap: 5px; + + ${mq.md} { + flex-direction: row; + } +`; + +const buttonStyles = css` + display: flex; + justify-content: center; + align-items: center; + width: 100%; + min-width: 100px; + padding: 16px 0; + border-radius: 16px; + background: #e7eeff; + color: ${theme.palette.primary}; + font: ${theme.font.subTitle.subTitle1_500}; + + cursor: pointer; + + &:active { + transition: transform 150ms cubic-bezier(0.4, 0, 0.2, 1); + transform: scale(0.95); + } +`; + +const doneInputStyles = css` + border: 0; + border-bottom: 2px solid ${theme.palette.greyscale.grey20}; + border-radius: 0; + + font: ${theme.font.title.title2_600}; +`; +export default InvitationParking; diff --git a/src/components/invitation/view/InvitationQrInfo.tsx b/src/components/invitation/view/InvitationQrInfo.tsx index 0df5cc20..0167497f 100644 --- a/src/components/invitation/view/InvitationQrInfo.tsx +++ b/src/components/invitation/view/InvitationQrInfo.tsx @@ -6,14 +6,15 @@ import { } from '@/constants/invitation/viewTexts'; import InvitationQrInfoText from '@/components/invitation/view/InvitationQrInfoText'; import InvitationQrInfoCode from '@/components/invitation/view/InvitationQrInfoCode'; -import useThemeStore from '@/stores/useThemeStore'; +import useInvitationThemeStore from '@/stores/invitaion/useInvitationThemeStore'; import { InvitationInfoContainerProps, InvitationInfoThemeProps, } from '@/types/invitation/view'; +import mq from '@/utils/mediaquery'; function InvitationQrInfo({ data }: InvitationInfoContainerProps) { - const { themeState, setThemeState } = useThemeStore(); + const { themeState, setThemeState } = useInvitationThemeStore(); const { category } = INVITATION_VEIW_INFO_TEXTS; const onClickSetThemeHandler = () => { // 클릭 시마다 클릭 횟수 증가 @@ -58,6 +59,17 @@ function InvitationQrInfo({ data }: InvitationInfoContainerProps) { } const queryStyles = css` overflow-x: scroll; + ${mq.md} { + display: flex; + justify-content: space-between; + margin: 0 auto; + } + ${mq.lg} { + display: flex; + justify-content: space-between; + width: 70%; + margin: 0 auto; + } `; const invitationQrContainer = (variantData: InvitationInfoThemeProps) => css` position: relative; @@ -67,7 +79,18 @@ const invitationQrContainer = (variantData: InvitationInfoThemeProps) => css` padding: 30px; border-radius: 12px; box-shadow: ${variantData.shadow}; - background-image: ${variantData.backgroundImage}; + background-image: ${variantData.backgroundImageBig}; + ::before { + content: ''; + position: absolute; + left: 20px; + width: 87%; + height: 95%; + border-radius: 5%; + background-image: ${variantData.boxShadow}; + filter: blur(20px); + z-index: -1; + } `; const invitationQrticket = css` display: flex; @@ -77,18 +100,18 @@ const invitationQrticket = css` const leftPuchingStyles = (variantData: InvitationInfoThemeProps) => css` position: absolute; background-color: #fff; - width: 22px; + width: 44px; height: 44px; - left: -1px; + left: -20px; border-radius: 0 22px 22px 0; background-image: ${variantData.side}; `; const rightPuchingStyles = (variantData: InvitationInfoThemeProps) => css` position: absolute; background-color: #fff; - width: 22px; + width: 42px; height: 44px; - right: -1px; + right: -20px; border-radius: 22px 0 0 22px; background-image: ${variantData.sideRight}; `; diff --git a/src/components/invitation/view/InvitationQrInfoCode.tsx b/src/components/invitation/view/InvitationQrInfoCode.tsx index c808d713..571da610 100644 --- a/src/components/invitation/view/InvitationQrInfoCode.tsx +++ b/src/components/invitation/view/InvitationQrInfoCode.tsx @@ -4,27 +4,27 @@ import React from 'react'; import useFetch from '@/hooks/useFetch'; import Image from 'next/image'; import { getVisitationQr } from '@/pages/api/invitation/viewRequests'; +import { INVITATION_VEIW_INFO_TEXTS } from '@/constants/invitation/viewTexts'; function InvitationQrInfoCode() { + const { qr } = INVITATION_VEIW_INFO_TEXTS; const { response } = useFetch({ fetchFn: getVisitationQr, }); - const qr = response?.data; + const qrData = response?.data; return ( - 임시출입증 + {qr.title} - - 초대 시간 전후로 1시간 사용할수 있습니다 - + {qr.body} ); } @@ -45,6 +45,7 @@ const qrStyles = css` width: 163px; height: 163px; `; + const alertStyles = css` width: 182px; text-align: center; diff --git a/src/components/invitation/view/InvitationQrInfoText.tsx b/src/components/invitation/view/InvitationQrInfoText.tsx index d6a6b54f..d3d01878 100644 --- a/src/components/invitation/view/InvitationQrInfoText.tsx +++ b/src/components/invitation/view/InvitationQrInfoText.tsx @@ -5,17 +5,17 @@ import { LocationFill, CalendarFill } from '@/assets/icons'; function InvitationQrInfoText({ data }: InvitationQrInfoTextProps) { // 시간 포멧 변환 - const startTime = data?.invitationStartTime.substring(0, 5); - const endTime = data?.invitationEndTime.substring(0, 5); + // const startTime = data?.invitationStartTime.substring(0, 5); + // const endTime = data?.invitationEndTime.substring(0, 5); // 날짜 포멧 변환 - const changeDatefometer = (date: string) => { - const [year, month, day] = data && date.split('-'); - const changedDate = `${year}.${month}.${day}`; - return changedDate; - }; - const startDate = changeDatefometer(data.invitationStartDate); - const endDate = changeDatefometer(data.invitationEndDate).substring(5, 10); + // const changeDatefometer = (date: string) => { + // const [year, month, day] = data && date.split('-'); + // const changedDate = `${year}.${month}.${day}`; + // return changedDate; + // }; + // const startDate = changeDatefometer(data.invitationStartDate); + // const endDate = changeDatefometer(data.invitationEndDate).substring(5, 10); return ( @@ -27,10 +27,12 @@ function InvitationQrInfoText({ data }: InvitationQrInfoTextProps) { - {startDate} ~ {endDate} + {/* {startDate} ~ {endDate} */} + 2023.10.10 - {startTime} ~ {endTime} + {/* {startTime} ~ {endTime} */} + 10:00 ~ 12:00 diff --git a/src/components/invitation/view/InvitationViewFooter.tsx b/src/components/invitation/view/InvitationViewFooter.tsx index 8be9d05c..f47428e5 100644 --- a/src/components/invitation/view/InvitationViewFooter.tsx +++ b/src/components/invitation/view/InvitationViewFooter.tsx @@ -1,16 +1,22 @@ -import theme from '@/styles/theme'; +import { Call } from '@/assets/icons'; import { css } from '@emotion/react'; +import { INVITATION_VEIW_INFO_TEXTS } from '@/constants/invitation/viewTexts'; +import theme from '@/styles/theme'; function InvitationViewFooter() { + const { footer } = INVITATION_VEIW_INFO_TEXTS; + const onClickCallBtnHandler = () => { + window.location.href = `tel:${18339092}`; + }; return ( - (주)리버블 + {footer.title} - 고객센터 : 1833-9092 - 사이트 : https://www.officener.com + {footer.call} + {footer.site} - - 관리실 문의하기 + + {footer.btn} ); @@ -38,7 +44,10 @@ const infoStyles = css` flex-direction: column; align-items: flex-start; margin-bottom: 16px; - font: ${theme.font.body.body3_400}; + span { + font: ${theme.font.body.body3_400}; + line-height: 21px; + } `; const buttonStyles = css` display: flex; @@ -47,8 +56,10 @@ const buttonStyles = css` justify-content: center; align-items: center; border-radius: 8px; + gap: 0 4px; font: ${theme.font.body.body3_500}; color: ${theme.palette.white}; background-color: ${theme.palette.greyscale.grey30}; + line-height: 21px; `; export default InvitationViewFooter; diff --git a/src/components/lunch/LunchRest.tsx b/src/components/lunch/LunchRest.tsx index adf6c994..c59c569d 100644 --- a/src/components/lunch/LunchRest.tsx +++ b/src/components/lunch/LunchRest.tsx @@ -1,4 +1,3 @@ -import menu from '$/menu.png'; import Image from 'next/image'; import theme from '@/styles/theme'; import { css } from '@emotion/react'; @@ -12,7 +11,7 @@ function LunchRest({ ...item }: GetRestListData) { {button5[0]} - {item.tastePercentage}% + {item.tastePercentage || 100}% @@ -67,6 +66,8 @@ const badgeStyles = css` font: ${theme.font.body.body4}; color: ${theme.palette.greyscale.grey70}; line-height: 16px; + white-space: nowrap; + min-width: 82px; `; const nameStyles = css` @@ -74,6 +75,14 @@ const nameStyles = css` color: ${theme.palette.title}; line-height: 24px; text-align: left; + overflow: hidden; + white-space: nowrap; + width: 128px; + text-overflow: ellipsis; + + @media (min-width: 400px) { + overflow: visible; + } `; const addressStyles = css` @@ -81,6 +90,14 @@ const addressStyles = css` color: ${theme.palette.greyscale.grey50}; line-height: 24px; text-align: left; + width: 128px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + + @media (min-width: 400px) { + overflow: visible; + } `; export default LunchRest; diff --git a/src/components/lunch/LunchRoulette.tsx b/src/components/lunch/LunchRoulette.tsx index a6e70461..65e2ca5f 100644 --- a/src/components/lunch/LunchRoulette.tsx +++ b/src/components/lunch/LunchRoulette.tsx @@ -2,7 +2,7 @@ import theme from '@/styles/theme'; import mq from '@/utils/mediaquery'; import { css } from '@emotion/react'; import useFetch from '@/hooks/useFetch'; -import useRouletteStore from '@/stores/useRouletteStore'; +import useLunchRouletteStore from '@/stores/lunch/useLunchRouletteStore'; import { getMenus } from '@/pages/api/lunch/lunchRequests'; import { LUNCH_ROULETTE_CONSTANTS } from '@/constants/lunch'; import LunchRouletteBg from '@/components/lunch/roulette/LunchRouletteBg'; @@ -18,9 +18,8 @@ import { function LunchRoulette() { const { time } = LUNCH_ROULETTE_CONSTANTS; // 시간 상수 const { categoryState, menuState, isLocked, isOperated, isPressed, isAgain } = - useRouletteStore(); - const { setState } = useRouletteStore; - + useLunchRouletteStore(); + const { setState } = useLunchRouletteStore; const { response } = useFetch({ fetchFn: getMenus, }); @@ -29,6 +28,8 @@ function LunchRoulette() { const onClickBtnHandler = () => { setState({ isOperated: !isOperated }); // 가동 중! setState({ isPressed: !isPressed }); // 버튼 눌림! + setState({ isDecided: false }); // 결정하지 못함 + setState({ isCompleted: false }); // *** 카테고리 고정 시! *** if (isLocked && isAgain) { @@ -62,7 +63,6 @@ function LunchRoulette() { // 메뉴 셔플 속도 (100ms) }, time.interval); - setTimeout(() => { clearInterval(menuInterval); }, time.duration.menu); // 카테고리 선택 완료 후 메뉴 선택까지의 시간 인터벌 (500ms) @@ -77,6 +77,7 @@ function LunchRoulette() { setState({ isOperated: true }); // 가동 완료! setState({ isPressed: false }); // 버튼 원상 복귀! setState({ isSelected: false }); // 선택 완료 초기화! + setState({ isCompleted: true }); }, time.duration.category + time.duration.menu); // 모든 선택이 완료되는 시간 인터벌 (500ms + 3500ms = 4000ms) } }; @@ -109,11 +110,11 @@ const layoutStyles = css` const bgStyles = css` position: relative; width: 242px; - height: 218px; + height: 242px; ${mq.md} { width: 358px; - height: 338px; + height: 358px; } `; @@ -125,13 +126,16 @@ const wrapperStyles = css` align-items: center; z-index: 2; height: 218px; - gap: 10px; + gap: 16px; + top: 68px; + left: calc((100% - 150px) / 2); ${mq.md} { - height: 318px; - gap: 48px; + height: 358px; + gap: 52px; left: calc((100% - 230px) / 2); + top: 46px; } `; diff --git a/src/components/lunch/LunchSubTitle.tsx b/src/components/lunch/LunchSubTitle.tsx index 9d36f032..14f6ef06 100644 --- a/src/components/lunch/LunchSubTitle.tsx +++ b/src/components/lunch/LunchSubTitle.tsx @@ -49,6 +49,7 @@ const titleStyles = ( lineHeight?: string, margin?: string, ) => css` + background-color: ${theme.palette.white}; font: ${fontStyle}; font-size: ${fontSize}; line-height: ${lineHeight}; diff --git a/src/components/lunch/calendar/LunchCalendarBottomSheet.tsx b/src/components/lunch/calendar/LunchCalendarBottomSheet.tsx index cbec5f5c..ea2fa74a 100644 --- a/src/components/lunch/calendar/LunchCalendarBottomSheet.tsx +++ b/src/components/lunch/calendar/LunchCalendarBottomSheet.tsx @@ -6,8 +6,8 @@ import { COMMON_ICON_NAMES } from '@/constants/common'; import { CALENDAR_CONTENT } from '@/constants/lunch'; import theme from '@/styles/theme'; import Icons from '@/components/common/Icons'; -import useBottomSheetStore from '@/stores/useBottomSheetStore'; -import useSaveStore from '@/stores/useSaveStore'; +import useBottomSheetStore from '@/stores/common/useBottomSheetStore'; +import useSaveStore from '@/stores/common/useSaveStore'; interface BottomSheetProps { onClickSubmit: () => void; @@ -87,6 +87,9 @@ const textStyles = css` display: flex; flex-direction: column; align-self: start; + strong { + font: ${theme.font.subTitle.subTitle1_600}; + } `; const textBtnStyles = (isChecked: boolean) => css` @@ -96,7 +99,10 @@ const textBtnStyles = (isChecked: boolean) => css` margin-top: 7px; text-align: start; cursor: pointer; - font: ${theme.font.body.body2_400}; + span { + font: ${theme.font.body.body2_400}; + } + color: ${!isChecked ? `${theme.palette.greyscale.grey40}` : `${theme.palette.bluescale.blue50}`}; @@ -115,6 +121,9 @@ const btnStyles = css` border-radius: 8px; background-color: ${theme.palette.greyscale.grey5}; } + span { + font: ${theme.font.subTitle.subTitle2_600}; + } `; const btncolorStyles = css` diff --git a/src/components/lunch/calendar/LunchCalendarCafeteria.tsx b/src/components/lunch/calendar/LunchCalendarCafeteria.tsx index 8b550347..a0a05218 100644 --- a/src/components/lunch/calendar/LunchCalendarCafeteria.tsx +++ b/src/components/lunch/calendar/LunchCalendarCafeteria.tsx @@ -12,23 +12,25 @@ import LunchSubTitle from '@/components/lunch/LunchSubTitle'; import LunchCalendarPhoto from '@/components/lunch/calendar/LunchCalendarPhoto'; import LunchCalendarRatingBtn from '@/components/lunch/calendar/LunchCalendarRatingBtn'; import LunchCalendarBottomSheet from '@/components/lunch/calendar/LunchCalendarBottomSheet'; -import usePagesStore from '@/stores/usePagesStore'; -import useBottomSheetStore from '@/stores/useBottomSheetStore'; -import useSaveStore from '@/stores/useSaveStore'; -import useWriteStore from '@/stores/useWriteStore'; -import useUserStore from '@/stores/useUserStore'; +import usePagesStore from '@/stores/common/usePagesStore'; +import useBottomSheetStore from '@/stores/common/useBottomSheetStore'; +import useSaveStore from '@/stores/common/useSaveStore'; +import useLunchWriteStore from '@/stores/lunch/useLunchWriteStore'; +import useUserStore from '@/stores/common/useUserStore'; import COMPONENT_NAME from '@/constants/common/pages'; -import useAlertStore from '@/stores/useAlertStore'; +import useAlertStore from '@/stores/common/useAlertStore'; import { ErrorProps } from '@/types/common/response'; import Alert from '@/components/common/Alert'; function LunchCalendarCafeteria() { const [searchText, setSearchText] = useState(''); + const [isBad, setIsBad] = useState(1); + const [isGood, setIsGood] = useState(1); const { setNextComponent, reset } = usePagesStore(); const { bottomSheetState, openBottomSheet, closeBottomSheet } = useBottomSheetStore(); const { isSave } = useSaveStore(); - const { ratingState, imageFiles } = useWriteStore(); + const { ratingState, imageFiles } = useLunchWriteStore(); const { buildingName } = useUserStore(); const { category, subTitle, button } = CALENDAR_CONTENT; const { calendar } = COMPONENT_NAME.lunch; @@ -62,7 +64,7 @@ function LunchCalendarCafeteria() { } } catch (err) { const error = err as ErrorProps; - openAlert('📢', error.message || '리뷰 등록 오류'); + openAlert('📢', error.message || ''); } finally { if (!isSave.PhotoMsg) { closeBottomSheet(); @@ -93,13 +95,25 @@ function LunchCalendarCafeteria() { {buildingName} - {button.button5.map((value) => ( - - ))} + + {subTitle.review} 0 + ? onClickBtnHandler + : onClickMsgBtnHandler + } /> {bottomSheetState.isOpen && !isSave.PhotoMsg && } diff --git a/src/components/lunch/calendar/LunchCalendarDate.tsx b/src/components/lunch/calendar/LunchCalendarDate.tsx index 3661f93d..0d7b37ef 100644 --- a/src/components/lunch/calendar/LunchCalendarDate.tsx +++ b/src/components/lunch/calendar/LunchCalendarDate.tsx @@ -1,10 +1,10 @@ import dayjs from 'dayjs'; import { DateDish } from '@/assets/icons'; -import useCalendarStore from '@/stores/useCalendarStore'; +import useLunchCalendarStore from '@/stores/lunch/useLunchCalendarStore'; import LunchCalendarDateContent from '@/components/lunch/calendar/LunchCalendarDateContent'; function CalendarTileContent({ date, view }: { date: Date; view: string }) { - const { reviewDetails } = useCalendarStore(); + const { reviewDetails } = useLunchCalendarStore(); if ( view === 'month' && diff --git a/src/components/lunch/calendar/LunchCalendarDateContent.tsx b/src/components/lunch/calendar/LunchCalendarDateContent.tsx index 2304513d..92ce1f7a 100644 --- a/src/components/lunch/calendar/LunchCalendarDateContent.tsx +++ b/src/components/lunch/calendar/LunchCalendarDateContent.tsx @@ -2,12 +2,12 @@ import Image from 'next/image'; import { css } from '@emotion/react'; import { DateDishNoPhoto } from '@/assets/icons'; import { DateDishPhotoProps } from '@/types/lunch/calendar'; -import useCalendarStore from '@/stores/useCalendarStore'; -import useWriteStore from '@/stores/useWriteStore'; +import useLunchCalendarStore from '@/stores/lunch/useLunchCalendarStore'; +import useLunchWriteStore from '@/stores/lunch/useLunchWriteStore'; function LunchCalendarDateContent({ dayReviewData }: DateDishPhotoProps) { - const setIsChecked = useWriteStore((state) => state.setIsChecked); - const { reviewDetails, setReviewDetails } = useCalendarStore(); + const setIsChecked = useLunchWriteStore((state) => state.setIsChecked); + const { reviewDetails, setReviewDetails } = useLunchCalendarStore(); const allReviews = [...reviewDetails]; const dayReview = [...dayReviewData]; @@ -26,22 +26,42 @@ function LunchCalendarDateContent({ dayReviewData }: DateDishPhotoProps) { } return ( - + + + + ); } -const ImageStyles = css` - object-fit: cover; +const imageBoxStyles = css` + position: relative; + width: 44px; + height: 44px; border-radius: 100px; border: 2.4px solid #e2e2e2; box-sizing: border-box; + overflow: hidden; + flex-shrink: 0; +`; + +const overlayStyles = css` + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(255, 255, 255, 0.5); /* 흰색 불투명도 50% 설정 */ + pointer-events: none; /* 이벤트를 이미지 아래로 전달 */ +`; + +const imageStyles = css` + object-fit: cover; `; export default LunchCalendarDateContent; diff --git a/src/components/lunch/calendar/LunchCalendarDetailsSlide.tsx b/src/components/lunch/calendar/LunchCalendarDetailsSlide.tsx index 9e869516..5298d41b 100644 --- a/src/components/lunch/calendar/LunchCalendarDetailsSlide.tsx +++ b/src/components/lunch/calendar/LunchCalendarDetailsSlide.tsx @@ -1,8 +1,8 @@ import Image from 'next/image'; import theme from '@/styles/theme'; import dayjs from 'dayjs'; -import useWriteStore from '@/stores/useWriteStore'; -import useCalendarStore from '@/stores/useCalendarStore'; +import useLunchWriteStore from '@/stores/lunch/useLunchWriteStore'; +import useLunchCalendarStore from '@/stores/lunch/useLunchCalendarStore'; import { css } from '@emotion/react'; import { Location20, @@ -19,8 +19,8 @@ import 'swiper/css/navigation'; import 'swiper/css/pagination'; function LunchCalendarDetailsSlide() { - const setIsChecked = useWriteStore((state) => state.setIsChecked); - const reviewDetails = useCalendarStore((state) => state.reviewDetails); + const setIsChecked = useLunchWriteStore((state) => state.setIsChecked); + const reviewDetails = useLunchCalendarStore((state) => state.reviewDetails); const { lunch } = COMMON_ICON_NAMES; const onClickHandler = ( @@ -32,7 +32,11 @@ function LunchCalendarDetailsSlide() { const target = event.target as HTMLInputElement; // click 이벤트 발생할 때, e.target과 e.currentTarget이 달라서 비교 조건 사용 불가 - if (target.className === 'swiper-slide swiper-slide-active') setIsChecked(); + if ( + target.className === 'swiper-slide swiper-slide-active' || + target.className === 'swiper-slide swiper-slide-active swiper-slide-next' + ) + setIsChecked(); }; return ( @@ -55,7 +59,7 @@ function LunchCalendarDetailsSlide() { - {value.reviewTitle} + {value.reviewTitle} {value.reviewType === 'restaurant' && ( @@ -80,8 +84,7 @@ function LunchCalendarDetailsSlide() { css` @@ -143,7 +147,7 @@ const slideStyles = (type: boolean) => css` left: 0; right: 0; margin: auto; - width: 250px; + width: 290px; max-height: ${type ? '350px' : '281px'}; padding: 20px 0; box-sizing: content-box; @@ -152,14 +156,19 @@ const slideStyles = (type: boolean) => css` background-color: ${theme.palette.white}; .swiper.swiper-initialized.swiper-horizontal { + position: relative; .swiper-pagination { + position: absolute; + bottom: 24px; + left: 80%; background: rgba(0, 0, 0, 0.25); - margin-left: 200px; - margin-bottom: 20px; width: 40px; border-radius: 10px; font: ${theme.font.body.body3_500}; color: ${theme.palette.white}; + @media (min-width: 480px) { + left: 88%; + } } } @@ -168,6 +177,14 @@ const slideStyles = (type: boolean) => css` width: 20px; height: 20px; } + + @media (max-width: 280px) { + width: 280px; + } + + @media (min-width: 480px) { + width: 480px; + } `; const titleStyles = css` @@ -175,7 +192,7 @@ const titleStyles = css` justify-content: space-between; padding: 0 20px; - strong { + p { margin-left: 4px; display: block; max-width: 160px; @@ -200,11 +217,15 @@ const locationStyles = css` const ImageBoxStyles = css` position: relative; width: 100%; - height: 100%; + height: 193px; dispaly: flex; justify-content: center; align-items: center; - padding: 16px 0; + margin: 16px 0; + + @media (min-width: 480px) { + height: 220px; + } `; const ImageStyles = css` diff --git a/src/components/lunch/calendar/LunchCalendarEatOut.tsx b/src/components/lunch/calendar/LunchCalendarEatOut.tsx index 11889453..6f764633 100644 --- a/src/components/lunch/calendar/LunchCalendarEatOut.tsx +++ b/src/components/lunch/calendar/LunchCalendarEatOut.tsx @@ -13,12 +13,12 @@ import LunchCalendarReviewCategory from '@/components/lunch/calendar/LunchCalend import LunchCalendarPhoto from '@/components/lunch/calendar/LunchCalendarPhoto'; import LunchCalendarRatingBtn from '@/components/lunch/calendar/LunchCalendarRatingBtn'; import LunchCalendarBottomSheet from '@/components/lunch/calendar/LunchCalendarBottomSheet'; -import usePagesStore from '@/stores/usePagesStore'; -import useBottomSheetStore from '@/stores/useBottomSheetStore'; -import useSaveStore from '@/stores/useSaveStore'; -import useWriteStore from '@/stores/useWriteStore'; +import usePagesStore from '@/stores/common/usePagesStore'; +import useBottomSheetStore from '@/stores/common/useBottomSheetStore'; +import useSaveStore from '@/stores/common/useSaveStore'; +import useLunchWriteStore from '@/stores/lunch/useLunchWriteStore'; import COMPONENT_NAME from '@/constants/common/pages'; -import useAlertStore from '@/stores/useAlertStore'; +import useAlertStore from '@/stores/common/useAlertStore'; import { ErrorProps } from '@/types/common/response'; import Alert from '@/components/common/Alert'; @@ -33,11 +33,13 @@ function LunchCalenderEatOut() { resetSelectedMenu, ratingState, imageFiles, - } = useWriteStore(); + } = useLunchWriteStore(); const { isSave } = useSaveStore(); const { subTitle, category, subCategory, button } = CALENDAR_CONTENT; const { calendar } = COMPONENT_NAME.lunch; const { alertState, openAlert } = useAlertStore(); + const [isBad, setIsBad] = useState(1); + const [isGood, setIsGood] = useState(1); const router = useRouter(); @@ -122,12 +124,20 @@ function LunchCalenderEatOut() { - {button.button5.map((value) => ( - - - - - ))} + + {subCategory.map((item) => { @@ -147,6 +157,7 @@ function LunchCalenderEatOut() { {subTitle.review} 0 + ? onClickBtnHandler + : onClickMsgBtnHandler + } /> {bottomSheetState.isOpen && !isSave.PhotoMsg && } diff --git a/src/components/lunch/calendar/LunchCalendarForm.tsx b/src/components/lunch/calendar/LunchCalendarForm.tsx index 741b5460..244b6057 100644 --- a/src/components/lunch/calendar/LunchCalendarForm.tsx +++ b/src/components/lunch/calendar/LunchCalendarForm.tsx @@ -4,8 +4,8 @@ import Calendar from 'react-calendar'; import dayjs from 'dayjs'; import { css } from '@emotion/react'; import { RightSmall, LeftSmall } from '@/assets/icons'; -import useCalendarStore from '@/stores/useCalendarStore'; -import useAlertStore from '@/stores/useAlertStore'; +import useLunchCalendarStore from '@/stores/lunch/useLunchCalendarStore'; +import useAlertStore from '@/stores/common/useAlertStore'; import LunchCalendarDate from '@/components/lunch/calendar/LunchCalendarDate'; import { getReviewDetailsData } from '@/pages/api/lunch/calendarRequests'; import { ErrorProps } from '@/types/common/response'; @@ -13,7 +13,7 @@ import { ErrorProps } from '@/types/common/response'; function LunchCalendarForm() { const [year, setYear] = useState(new Date().getFullYear()); const [month, setMonth] = useState(new Date().getMonth() + 1); - const { setReviewDetails } = useCalendarStore(); + const { setReviewDetails } = useLunchCalendarStore(); const { openAlert } = useAlertStore(); useEffect(() => { @@ -70,26 +70,29 @@ function LunchCalendarForm() { } const CalendarStyles = css` - margin: 12px 0 20px; + padding: 12px 0 20px; - .react-calendar { - width: 350px; + &.react-calendar { max-width: 100%; - background: white; + background-color: ${theme.palette.white}; + } .react-calendar--doubleView { width: 700px; + } .react-calendar--doubleView .react-calendar__viewContainer { display: flex; margin: -0.5em; + } .react-calendar--doubleView .react-calendar__viewContainer > * { width: 50%; margin: 0.5em; + } .react-calendar, @@ -99,6 +102,7 @@ const CalendarStyles = css` -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; + background-color: ${theme.palette.white}; } .react-calendar button { @@ -116,6 +120,10 @@ const CalendarStyles = css` height: 44px; margin-bottom: 1em; } + .react-calendar__navigation__label__labelText { +font: ${theme.font.subTitle.subTitle2_500}; +color: ${theme.palette.greyscale.grey60}; + } .react-calendar__navigation button { min-width: 44px; @@ -179,17 +187,19 @@ const CalendarStyles = css` line-height: 21px; font: ${theme.font.body.body3_400}; // 사진이 있을 때 글자색 white로 설정하기 - color: ${theme.palette.greyscale.grey50}; + abbr { + z-index: 1; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); cursor: pointer; - + pointer-events: none; /* 이벤트를 이미지 아래로 전달 */ + color: ${theme.palette.greyscale.grey50}; @media (max-width: 320px) { //사진이 없을 때만 설정하기 - margin-left: 4px; + margin-left: 3px; } } } diff --git a/src/components/lunch/calendar/LunchCalendarListItem.tsx b/src/components/lunch/calendar/LunchCalendarListItem.tsx index c327fef1..03a74a24 100644 --- a/src/components/lunch/calendar/LunchCalendarListItem.tsx +++ b/src/components/lunch/calendar/LunchCalendarListItem.tsx @@ -7,10 +7,12 @@ import { Clock, XIcon } from '@/assets/icons'; import { CALENDAR_CASE } from '@/constants/lunch'; import { COMMON_ICON_NAMES } from '@/constants/common'; import { LunchCalendarListItemProps } from '@/types/lunch/calendar'; -import useWriteStore from '@/stores/useWriteStore'; -import useSaveStore from '@/stores/useSaveStore'; +import useLunchWriteStore from '@/stores/lunch/useLunchWriteStore'; +import useSaveStore from '@/stores/common/useSaveStore'; +import useUserStore from '@/stores/common/useUserStore'; function LunchCalendarListItem({ + id, type, item, content, @@ -20,10 +22,11 @@ function LunchCalendarListItem({ onClick, }: LunchCalendarListItemProps) { const [isChecked, setIsChecked] = useState(false); - const selectedMenu = useWriteStore((state) => state.selectedMenu); - const setSelectedMenu = useWriteStore((state) => state.setSelectedMenu); - const setRemoveMenu = useWriteStore((state) => state.setRemoveMenu); - const deleteKeyword = useSaveStore((state) => state.deleteKeyword); + const selectedMenu = useLunchWriteStore((state) => state.selectedMenu); + const setSelectedMenu = useLunchWriteStore((state) => state.setSelectedMenu); + const setRemoveMenu = useLunchWriteStore((state) => state.setRemoveMenu); + const deleteKeywordList = useSaveStore((state) => state.deleteKeywordList); + const buildingName = useUserStore((state) => state.buildingName); const { listItem } = CALENDAR_CASE; const { home } = COMMON_ICON_NAMES; @@ -45,22 +48,23 @@ function LunchCalendarListItem({ setRemoveMenu(item); } }; - const onClickDeleteHandler = (keyword: string | undefined) => { - if (keyword) { - deleteKeyword(keyword); - } + + const onClickDeleteHandler = (e: React.MouseEvent) => { + e.preventDefault(); + if (!id) return; + deleteKeywordList(id); }; switch (type) { case listItem.type1: return ( - - + + - {content} - - - + {content} + + + ); case listItem.type2: return ( @@ -70,7 +74,9 @@ function LunchCalendarListItem({ {content} {category} - 테리타워에서 {time}분 + + {buildingName}에서 {time}분 + - - {item?.menuName} + + {item?.menuName} css` padding: ${type === 'searched' ? `16px 4px` : `20px 4px`}; `; -const contentStyles = (type: string) => css` +const contentStyles = () => css` display: flex; align-items: center; - gap: 6px; - font: ${type === 'searched' - ? `${theme.font.body.body1_400}` - : `${theme.font.subTitle.subTitle2_400}`}; - color: ${type === 'searched' - ? `${theme.palette.greyscale.grey60}` - : `${theme.palette.greyscale.grey70}`}; + gap: 8px; + cursor: pointer; +`; + +const searchedStyles = css` + font: ${theme.font.body.body1_400}; + color: ${theme.palette.greyscale.grey60}; +`; + +const menuStyles = css` + font: ${theme.font.subTitle.subTitle2_400}; + color: ${theme.palette.greyscale.grey70}; `; const searchingContentStyles = css` @@ -155,7 +166,6 @@ const ImageStyles = css` width: 56px; height: 56px; border-radius: 8px; - border: 1px solid ${theme.palette.greyscale.grey60} overflow: hidden; `; diff --git a/src/components/lunch/calendar/LunchCalendarLunchBox.tsx b/src/components/lunch/calendar/LunchCalendarLunchBox.tsx index 1db8c7e1..41d1bb43 100644 --- a/src/components/lunch/calendar/LunchCalendarLunchBox.tsx +++ b/src/components/lunch/calendar/LunchCalendarLunchBox.tsx @@ -10,12 +10,12 @@ import BottomSheet from '@/components/common/BottomSheet'; import LunchSubTitle from '@/components/lunch/LunchSubTitle'; import LunchCalendarPhoto from '@/components/lunch/calendar/LunchCalendarPhoto'; import LunchCalendarBottomSheet from '@/components/lunch/calendar/LunchCalendarBottomSheet'; -import usePagesStore from '@/stores/usePagesStore'; -import useBottomSheetStore from '@/stores/useBottomSheetStore'; -import useSaveStore from '@/stores/useSaveStore'; -import useWriteStore from '@/stores/useWriteStore'; +import usePagesStore from '@/stores/common/usePagesStore'; +import useBottomSheetStore from '@/stores/common/useBottomSheetStore'; +import useSaveStore from '@/stores/common/useSaveStore'; +import useLunchWriteStore from '@/stores/lunch/useLunchWriteStore'; import COMPONENT_NAME from '@/constants/common/pages'; -import useAlertStore from '@/stores/useAlertStore'; +import useAlertStore from '@/stores/common/useAlertStore'; import { ErrorProps } from '@/types/common/response'; import Alert from '@/components/common/Alert'; @@ -25,7 +25,7 @@ function LunchCalendarLunchBox() { const { bottomSheetState, openBottomSheet, closeBottomSheet } = useBottomSheetStore(); const { isSave } = useSaveStore(); - const { imageFiles } = useWriteStore(); + const { imageFiles } = useLunchWriteStore(); const { category, subTitle, button } = CALENDAR_CONTENT; const { calendar } = COMPONENT_NAME.lunch; const { alertState, openAlert } = useAlertStore(); @@ -87,6 +87,7 @@ function LunchCalendarLunchBox() { 0 + ? onClickBtnHandler + : onClickMsgBtnHandler + } /> {bottomSheetState.isOpen && !isSave.PhotoMsg && } diff --git a/src/components/lunch/calendar/LunchCalendarMain.tsx b/src/components/lunch/calendar/LunchCalendarMain.tsx index f8c0a0df..33f8eabc 100644 --- a/src/components/lunch/calendar/LunchCalendarMain.tsx +++ b/src/components/lunch/calendar/LunchCalendarMain.tsx @@ -2,23 +2,25 @@ import { useState, useEffect } from 'react'; import { useRouter } from 'next/router'; import { css } from '@emotion/react'; import { CALENDAR_CONTENT } from '@/constants/lunch'; -import { Rice } from '@/assets/icons'; import { getReviewDetailsData } from '@/pages/api/lunch/calendarRequests'; +import theme from '@/styles/theme'; import Header from '@/components/common/Header'; import Alert from '@/components/common/Alert'; import LunchCalendarWriteBtn from '@/components/lunch/calendar/LunchCalendarWriteBtn'; import LunchSubTitle from '@/components/lunch/LunchSubTitle'; import LunchCalendarForm from '@/components/lunch/calendar/LunchCalendarForm'; import LunchCalendarDetailsSlide from '@/components/lunch/calendar/LunchCalendarDetailsSlide'; -import useWriteStore from '@/stores/useWriteStore'; -import useAlertStore from '@/stores/useAlertStore'; +import useLunchWriteStore from '@/stores/lunch/useLunchWriteStore'; +import useAlertStore from '@/stores/common/useAlertStore'; import { ErrorProps } from '@/types/common/response'; import checkTodayReview from '@/utils/checkTodayReview'; +import useUserStore from '@/stores/common/useUserStore'; function LunchCalendarMain() { const [isCompleted, setIsCompleted] = useState(false); - const isChecked = useWriteStore((state) => state.isChecked); + const isChecked = useLunchWriteStore((state) => state.isChecked); const { alertState, openAlert } = useAlertStore(); + const memberName = useUserStore((state) => state.memberName); const { title, subTitle } = CALENDAR_CONTENT; @@ -53,15 +55,20 @@ function LunchCalendarMain() { }; return ( - + {alertState.isOpen && } {isChecked && } - - - - + + + + + + - ([]); - const { restaurant, selectedMenu } = useWriteStore(); + const { restaurant, selectedMenu } = useLunchWriteStore(); const { setNextComponent, goBack } = usePagesStore(); const { modalState, openModal } = useModalStore(); const { subTitle, button } = CALENDAR_CONTENT; diff --git a/src/components/lunch/calendar/LunchCalendarPhoto.tsx b/src/components/lunch/calendar/LunchCalendarPhoto.tsx index 280302ff..91898eb3 100644 --- a/src/components/lunch/calendar/LunchCalendarPhoto.tsx +++ b/src/components/lunch/calendar/LunchCalendarPhoto.tsx @@ -3,12 +3,12 @@ import theme from '@/styles/theme'; import { useRef, useState } from 'react'; import { css } from '@emotion/react'; import { Camera, XSBlack } from '@/assets/icons'; -import useWriteStore from '@/stores/useWriteStore'; +import useLunchWriteStore from '@/stores/lunch/useLunchWriteStore'; function LunchCalendarPhoto() { const [previews, setPreviews] = useState([]); - const imageFiles = useWriteStore((state) => state.imageFiles); - const setImagefiles = useWriteStore((state) => state.setImageFiles); + const imageFiles = useLunchWriteStore((state) => state.imageFiles); + const setImagefiles = useLunchWriteStore((state) => state.setImageFiles); const fileInput = useRef(null); // ref 클릭 @@ -61,7 +61,7 @@ function LunchCalendarPhoto() { - 0/5 + {previews.length}/5 state.point); @@ -77,10 +78,10 @@ function LunchCalendarPointCard() { type="title" margin="24px" /> - + {numbersArray.map((value, idx) => ( - + {count > 0 && idx + 1 <= 13 && idx + 1 <= count && @@ -113,7 +114,12 @@ function LunchCalendarPointCard() { ) : ( {value === 6 || value === 14 || value === 21 ? ( - + ) : ( {value} )} @@ -125,54 +131,25 @@ function LunchCalendarPointCard() { {card.text1} - {card.text2} - {card.text3} + + {card.text2} + {card.text3} + ); } -const pageStyles = css``; const pointBoxStyles = css` display: grid; - grid-template-columns: repeat(5, 1fr); + grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(11, 1fr); - - // display: flex; - // justify-content: space-between; - // flex-wrap: wrap; margin: 32px 0 40px; +`; - // li:nth-child(4) { - // grid-column: 2; - // } - // li:nth-child(6) { - // grid-column: 2; - // } - // li:nth-child(9) { - // grid-column: 2; - // } - // li:nth-child(11) { - // grid-column: 2; - // } - // li:nth-child(14) { - // grid-column: 2; - // } - // li:nth-child(16) { - // grid-column: 2; - // } - // li:nth-child(19) { - // grid-column: 2; - // } - // li:nth-child(21) { - // grid-column: 2; - // } - // li:nth-child(24) { - // grid-column: 2; - // } - // li:nth-child(26) { - // grid-column: 2; - // } +const liStyles = css` + display: flex; + justify-content: center; `; const circleStyles = css` @@ -187,16 +164,27 @@ const circleStyles = css` `; const textStyles = css` + font: ${theme.font.title.title2_500}; color: ${theme.palette.greyscale.grey40}; `; const cardStyles = css` + margin: 0 -16px 20px; padding: 24px 16px; background-color: ${theme.palette.greyscale.grey10}; + color: ${theme.palette.greyscale.grey50}; strong: { display: block; margin-bottom: 8px; + font: ${theme.font.body.body2_500}; + } + + > div { + margin-top: 8px; + } + p { + font: ${theme.font.body.body3_400}; } `; export default LunchCalendarPointCard; diff --git a/src/components/lunch/calendar/LunchCalendarPointInform.tsx b/src/components/lunch/calendar/LunchCalendarPointInform.tsx index 2160397e..e6781a58 100644 --- a/src/components/lunch/calendar/LunchCalendarPointInform.tsx +++ b/src/components/lunch/calendar/LunchCalendarPointInform.tsx @@ -3,11 +3,11 @@ import Image from 'next/image'; import theme from '@/styles/theme'; import Header from '@/components/common/Header'; import Button from '@/components/common/Button'; -import { css } from '@emotion/react'; +import { css, keyframes } from '@emotion/react'; import { CALENDAR_CONTENT } from '@/constants/lunch'; import { RightSmall } from '@/assets/icons'; -import { coin } from '@/assets/images'; -import usePagesStore from '@/stores/usePagesStore'; +import { coin, point10 } from '@/assets/images'; +import usePagesStore from '@/stores/common/usePagesStore'; function LunchCalendarPointInform() { const router = useRouter(); @@ -31,7 +31,16 @@ function LunchCalendarPointInform() { - + + + + {title.photoReview} {subTitle.photoReview} @@ -52,6 +61,27 @@ function LunchCalendarPointInform() { ); } +const fadeIn = keyframes` +0%{ + opacity: 0; + transform: translateY(16px); +} +50% { + opacity: 1; +} +80% { + opacity: 1; +} +100% { + opacity: .6; + +} +`; +const fadeInStyles = css` + opacity: 0; + animation: ${fadeIn} 0.6s 1s ease-in-out; +`; + const pageStyles = css` height: 100vh; display: flex; @@ -67,6 +97,13 @@ const contentStyles = css` gap: 32px; `; +const imageStyles = css` + display: flex; + flex-direction: column; + align-items: center; + gap: 12px; +`; + const textStyles = css` text-align: center; h1 { diff --git a/src/components/lunch/calendar/LunchCalendarRatingBtn.tsx b/src/components/lunch/calendar/LunchCalendarRatingBtn.tsx index cb9642e0..98ae6e2e 100644 --- a/src/components/lunch/calendar/LunchCalendarRatingBtn.tsx +++ b/src/components/lunch/calendar/LunchCalendarRatingBtn.tsx @@ -5,36 +5,53 @@ import { css } from '@emotion/react'; import { CALENDAR_CONTENT } from '@/constants/lunch'; import { COMMON_ICON_NAMES } from '@/constants/common'; import { LunchCalendarRatingBtnProps } from '@/types/lunch/calendar'; -import useWriteStore from '@/stores/useWriteStore'; +import useLunchWriteStore from '@/stores/lunch/useLunchWriteStore'; -function LunchCalendarRatingBtn({ title }: LunchCalendarRatingBtnProps) { +function LunchCalendarRatingBtn({ + title, + isGood, + isBad, + setIsGood, + setIsBad, +}: LunchCalendarRatingBtnProps) { const [isGoodChecked, setIsGoodChecked] = useState(false); const [isBadChecked, setIsBadChecked] = useState(false); - const setRatingState = useWriteStore((state) => state.setRatingState); + const setRatingState = useLunchWriteStore((state) => state.setRatingState); const { button } = CALENDAR_CONTENT; const { lunch } = COMMON_ICON_NAMES; const onClickGoodHandler = () => { - setIsGoodChecked(!isGoodChecked); - setRatingState({ taste: 'GOOD' }); + if (!isGoodChecked) { + setIsGoodChecked(true); + setIsBad(0); + setIsGood(2); + setRatingState({ taste: 'GOOD' }); + } else if (isGoodChecked) { + setIsGoodChecked(false); + setIsBad(1); + setIsGood(1); + setRatingState({ taste: '' }); + } }; const onClickBadHandler = () => { if (!isBadChecked) { setIsBadChecked(true); + setIsBad(2); + setIsGood(0); setRatingState({ taste: 'BAD' }); } else if (isBadChecked) { setIsBadChecked(false); - setRatingState({ taste: 'GOOD' }); + setIsBad(1); + setIsGood(1); + setRatingState({ taste: '' }); } }; return ( {title === `${button.button5[0]}` ? ( - + ) : ( - + )} @@ -55,7 +72,7 @@ function LunchCalendarRatingBtn({ title }: LunchCalendarRatingBtnProps) { ); } -const buttonStyles = (isChecked: boolean) => css` +const buttonStyles = (isChecked: number) => css` display: flex; flex-direction: column; align-items: center; @@ -64,28 +81,30 @@ const buttonStyles = (isChecked: boolean) => css` width: 100%; padding: 16px 0; border-radius: 16px; - font: ${theme.font.body.body1_500}; border: 2px solid - ${!isChecked - ? `{theme.palette.greyscale.grey10}` - : `${theme.palette.orange}`}; - background-color: ${!isChecked - ? `${theme.palette.greyscale.grey5}` - : `${theme.palette.white}`}; + ${isChecked === 2 + ? `${theme.palette.orange}` + : `{theme.palette.greyscale.grey10}`}; + background-color: ${isChecked === 2 + ? `${theme.palette.white}` + : `${theme.palette.greyscale.grey5}`}; + + p { + font: ${theme.font.body.body1_500}; + color: ${isChecked === 2 + ? `${theme.palette.orange}` + : `${theme.palette.greyscale.grey50}`}; + } svg { - filter: ${isChecked && 'none'}; - transform: ${isChecked && 'scale(1.2)'}; - transition: ${isChecked && 'transform 0.1s ease'}; + filter: ${isChecked === 0 ? `saturate(5%)` : 'none'}; + transform: ${isChecked === 2 && 'scale(1.1)'}; + transition: ${isChecked === 2 && 'transform 0.1s ease'}; } `; -const iconStyles = (isChecked: boolean) => css` +const iconStyles = () => css` margin-bottom: 4px; - - // svg { - // filter: ${isChecked ? `saturate(5%)` : `none`}; - // } `; export default LunchCalendarRatingBtn; diff --git a/src/components/lunch/calendar/LunchCalendarReview.tsx b/src/components/lunch/calendar/LunchCalendarReview.tsx index ba70b5ab..e72fcdf0 100644 --- a/src/components/lunch/calendar/LunchCalendarReview.tsx +++ b/src/components/lunch/calendar/LunchCalendarReview.tsx @@ -3,7 +3,7 @@ import { CALENDAR_CONTENT } from '@/constants/lunch'; import { useRouter } from 'next/router'; import Header from '@/components/common/Header'; import LunchSubTitle from '@/components/lunch/LunchSubTitle'; -import usePagesStore from '@/stores/usePagesStore'; +import usePagesStore from '@/stores/common/usePagesStore'; import LunchCalendarSelectBtn from '@/components/lunch/calendar/LunchCalendarSelectBtn'; import LunchCalendarSearch from '@/components/lunch/calendar/LunchCalendarSearch'; import LunchCalendarEatOut from '@/components/lunch/calendar/LunchCalendarEatOut'; @@ -11,7 +11,7 @@ import LunchCalendarLunchBox from '@/components/lunch/calendar/LunchCalendarLunc import LunchCalendarCafeteria from '@/components/lunch/calendar/LunchCalendarCafeteria'; import LunchCalendarPointInform from '@/components/lunch/calendar/LunchCalendarPointInform'; import COMPONENT_NAME from '@/constants/common/pages'; -import LunchCalendarMenu from './LunchCalendarMenu'; +import LunchCalendarMenu from '@/components/lunch/calendar/LunchCalendarMenu'; function LunchCalendarReview() { const { nextComponent } = usePagesStore(); @@ -57,12 +57,12 @@ function LunchCalendarReview() { const buttonListStyles = css` display: flex; - gap: 16px; flex-wrap: wrap; + gap: 22px 16px; margin-top: 32px; padding: 0 20px; - @media (max-width: 480px) { + @media (max-width: 479px) { display: flex; justify-content: space-between; } diff --git a/src/components/lunch/calendar/LunchCalendarReviewCategory.tsx b/src/components/lunch/calendar/LunchCalendarReviewCategory.tsx index 10d6d832..52e882f6 100644 --- a/src/components/lunch/calendar/LunchCalendarReviewCategory.tsx +++ b/src/components/lunch/calendar/LunchCalendarReviewCategory.tsx @@ -5,14 +5,14 @@ import { COMMON_ICON_NAMES } from '@/constants/common'; import { useState } from 'react'; import { LunchCalendarReviewCategoryProps } from '@/types/lunch/calendar'; import Icons from '@/components/common/Icons'; -import useWriteStore from '@/stores/useWriteStore'; +import useLunchWriteStore from '@/stores/lunch/useLunchWriteStore'; function LunchCalendarReviewCategory({ type, title, }: LunchCalendarReviewCategoryProps) { const [isChecked, setIsChecked] = useState(false); - const setRatingState = useWriteStore((state) => state.setRatingState); + const setRatingState = useLunchWriteStore((state) => state.setRatingState); const { button, subCategory } = CALENDAR_CONTENT; const { lunch } = COMMON_ICON_NAMES; @@ -74,14 +74,20 @@ const buttonStyles = (isChecked: boolean) => css` cursor: pointer; border-radius: 100px; background-color: ${theme.palette.white}; - font: ${theme.font.body.body3_500}; + span { + font: ${theme.font.body.body3_500}; + color: ${!isChecked + ? `${theme.palette.greyscale.grey30};` + : `${theme.palette.orange}`}; + } + border: 1px solid ${!isChecked ? `${theme.palette.greyscale.grey20}` : `${theme.palette.orange}`}; color: ${!isChecked - ? `${theme.palette.greyscale.grey40};` + ? `${theme.palette.greyscale.grey30};` : `${theme.palette.orange}`}; `; diff --git a/src/components/lunch/calendar/LunchCalendarSearch.tsx b/src/components/lunch/calendar/LunchCalendarSearch.tsx index bf32c934..c62d383a 100644 --- a/src/components/lunch/calendar/LunchCalendarSearch.tsx +++ b/src/components/lunch/calendar/LunchCalendarSearch.tsx @@ -9,18 +9,24 @@ import theme from '@/styles/theme'; import Header from '@/components/common/Header'; import Input from '@/components/common/Input'; import LunchCalendarListItem from '@/components/lunch/calendar/LunchCalendarListItem'; -import usePagesStore from '@/stores/usePagesStore'; -import useWriteStore from '@/stores/useWriteStore'; -import useSaveStore from '@/stores/useSaveStore'; +import usePagesStore from '@/stores/common/usePagesStore'; +import useLunchWriteStore from '@/stores/lunch/useLunchWriteStore'; +import useSaveStore from '@/stores/common/useSaveStore'; import keyDate from '@/utils/key'; +import Alert from '@/components/common/Alert'; +import useAlertStore from '@/stores/common/useAlertStore'; +import { ErrorProps } from '@/types/common/response'; function LunchCalendarSearch() { const [searchData, setSearchData] = useState([]); const [showSearch, setShowSearch] = useState(false); const [keyword, setKeyword] = useState(''); const { setNextComponent, goBack } = usePagesStore(); - const setRestaurant = useWriteStore((state) => state.setRestaurant); - const keywordData = useSaveStore((state) => state.keyword); + const { alertState, openAlert } = useAlertStore(); + const setRestaurant = useLunchWriteStore((state) => state.setRestaurant); + const keywordList = useSaveStore((state) => state.keywordList); + const setKeywordList = useSaveStore((state) => state.setKeywordList); + const key = keyDate(); const { calendar } = COMPONENT_NAME.lunch; @@ -38,8 +44,10 @@ function LunchCalendarSearch() { const res = await getRestaurants(keyword); setSearchData(res.data); setShowSearch(true); + setKeywordList({ id: key, text: keyword }); } catch (err) { - // 검색 오류 예외 처리 + const error = err as ErrorProps; + openAlert('📢', error.message || '검색 오류'); } }; const onClickBtnHandler = ( @@ -61,8 +69,24 @@ function LunchCalendarSearch() { setKeyword(e.target.value); }; + const onClickKeywordHandler = async ( + e: React.MouseEvent, + text: string, + ) => { + e.preventDefault(); + try { + const res = await getRestaurants(text); + setSearchData(res.data); + setShowSearch(true); + } catch (err) { + const error = err as ErrorProps; + openAlert('📢', error.message || '검색 오류'); + } + }; + return ( + {alertState.isOpen && } @@ -75,11 +99,13 @@ function LunchCalendarSearch() { {subTitle.recentSearches} - {keywordData.map((value) => ( + {keywordList.map((value) => ( onClickKeywordHandler(e, value.text)} /> ))} @@ -99,7 +125,7 @@ function LunchCalendarSearch() { content={item.restaurantName} category={item.restaurantCategory} time={item.estimatedTime} - imageUrl="/ruppy.png" + imageUrl={item.thumbnailImageUrl} onClick={(e) => onClickBtnHandler(e, item.restaurantId, item.restaurantName) } diff --git a/src/components/lunch/calendar/LunchCalendarSelectBtn.tsx b/src/components/lunch/calendar/LunchCalendarSelectBtn.tsx index 62ab5b75..a2743a9f 100644 --- a/src/components/lunch/calendar/LunchCalendarSelectBtn.tsx +++ b/src/components/lunch/calendar/LunchCalendarSelectBtn.tsx @@ -3,7 +3,7 @@ import { css } from '@emotion/react'; import { CALENDAR_CONTENT } from '@/constants/lunch'; import { Chef, Bento, PlateSmall } from '@/assets/icons'; import { LunchCalendarSelectBtnProps } from '@/types/lunch/calendar'; -import usePagesStore from '@/stores/usePagesStore'; +import usePagesStore from '@/stores/common/usePagesStore'; function LunchCalendarSelectBtn({ text }: LunchCalendarSelectBtnProps) { const { setNextComponent } = usePagesStore(); diff --git a/src/components/lunch/calendar/LunchCalendarWriteBtn.tsx b/src/components/lunch/calendar/LunchCalendarWriteBtn.tsx index ce5d183a..5e89759f 100644 --- a/src/components/lunch/calendar/LunchCalendarWriteBtn.tsx +++ b/src/components/lunch/calendar/LunchCalendarWriteBtn.tsx @@ -26,7 +26,7 @@ function LunchCalendarWriteBtn({ } return ( - + {icon} {text} @@ -40,20 +40,28 @@ const buttonStyles = css` justify-content: space-between; align-items: center; width: 100%; - padding: 28px 0; + margin-top: 12px; + padding: 28px 16px; white-space: pre-line; background-color: ${theme.palette.white}; - font: ${theme.font.body.body1_600}; cursor: pointer; + box-shadow: + 0 4px 4px rgba(0, 0, 0, 0.03), + 0 -4px 4px rgba(0, 0, 0, 0.03); `; -const contentStyles = css` +const contentStyles = (isCompleted: boolean) => css` display: flex; align-items: center; - gap: 12px; + gap: ${!isCompleted ? '12px' : '14px'}; + svg { + flex-shrink: 0; + } `; const textStyles = css` text-align: left; + font: ${theme.font.body.body1_600}; + color: ${theme.palette.greyscale.grey50}; `; export default LunchCalendarWriteBtn; diff --git a/src/components/lunch/detail/LunchDetailContents.tsx b/src/components/lunch/detail/LunchDetailContents.tsx index 4c8095e1..88d56675 100644 --- a/src/components/lunch/detail/LunchDetailContents.tsx +++ b/src/components/lunch/detail/LunchDetailContents.tsx @@ -1,6 +1,6 @@ import { css } from '@emotion/react'; import LunchReview from '@/components/lunch/review/LunchReview'; -import useReviewStore from '@/stores/useReviewStore'; +import useLunchReviewStore from '@/stores/lunch/useLunchReviewStore'; import LunchSubTitle from '@/components/lunch/LunchSubTitle'; import { LUNCH_MAIN_CONSTANTS } from '@/constants/lunch'; import theme from '@/styles/theme'; @@ -9,9 +9,9 @@ import { getRestReviewList } from '@/pages/api/lunch/lunchRequests'; // 리뷰 상세 내부 컨텐츠 컴포넌트 function LunchDetailContents() { - const { reviewList } = useReviewStore(); + const { reviewList } = useLunchReviewStore(); const { title } = LUNCH_MAIN_CONSTANTS.main.detail; // '의 더 많은 리뷰' - const { restaurantId } = useReviewStore().reviewList; + const { restaurantId } = useLunchReviewStore().reviewList; const { response } = useFetch({ fetchFn: () => getRestReviewList(restaurantId), }); diff --git a/src/components/lunch/detail/index.tsx b/src/components/lunch/detail/index.tsx index 4ad7ebe5..23657edf 100644 --- a/src/components/lunch/detail/index.tsx +++ b/src/components/lunch/detail/index.tsx @@ -2,8 +2,8 @@ import theme from '@/styles/theme'; import { css } from '@emotion/react'; import Header from '@/components/common/Header'; import ToWrite from '@/components/common/ToWrite'; -import usePagesStore from '@/stores/usePagesStore'; -import useReviewStore from '@/stores/useReviewStore'; +import usePagesStore from '@/stores/common/usePagesStore'; +import useLunchReviewStore from '@/stores/lunch/useLunchReviewStore'; import { LUNCH_MAIN_CONSTANTS } from '@/constants/lunch'; import LunchReview from '@/components/lunch/review/LunchReview'; import LunchDetailContents from '@/components/lunch/detail/LunchDetailContents'; @@ -11,7 +11,7 @@ import LunchDetailContents from '@/components/lunch/detail/LunchDetailContents'; // 리뷰 상세 컴포넌트 function LunchDetail() { const { title } = LUNCH_MAIN_CONSTANTS.review; // '리뷰' - const { reviewList } = useReviewStore(); // ReviewStore에 저장된 리뷰 리스트 + const { reviewList } = useLunchReviewStore(); // ReviewStore에 저장된 리뷰 리스트 const { setNextComponent } = usePagesStore(); // const onClickHandler = () => { setNextComponent(''); diff --git a/src/components/lunch/ranking/LunchRankingReviews.tsx b/src/components/lunch/ranking/LunchRankingReviews.tsx index 9111a1af..5a1f0d7c 100644 --- a/src/components/lunch/ranking/LunchRankingReviews.tsx +++ b/src/components/lunch/ranking/LunchRankingReviews.tsx @@ -4,29 +4,23 @@ import mq from '@/utils/mediaquery'; import { css } from '@emotion/react'; import useFetch from '@/hooks/useFetch'; import Icons from '@/components/common/Icons'; -import usePagesStore from '@/stores/usePagesStore'; -import useReviewStore from '@/stores/useReviewStore'; +import usePagesStore from '@/stores/common/usePagesStore'; +import useLunchReviewStore from '@/stores/lunch/useLunchReviewStore'; import COMPONENT_NAME from '@/constants/common/pages'; import { ReviewList } from '@/types/lunch/reviewList'; import LunchReview from '@/components/lunch/review/LunchReview'; import { getMenuReviews } from '@/pages/api/lunch/lunchRequests'; -// import { getMenuReviews } from '@/pages/api/lunch/lunchRequests'; // '오늘 점심' 랭킹별 리뷰 컴포넌트 function LunchRankingReviews({ menuId }: { menuId: number }) { const [isMore, setIsMore] = useState(false); // 더보기 버튼 클릭 여부 const { setNextComponent } = usePagesStore(); - const { setReviewList } = useReviewStore(); + const { setReviewList } = useLunchReviewStore(); const { detail } = COMPONENT_NAME.lunch.detail; // 오늘 점심 리뷰 상세 const { response } = useFetch({ fetchFn: () => getMenuReviews(menuId), }); - // useQuery로 API 호출 - // const { data } = useQuery(['menuReviews', page], () => - // getMenuReviews({ menuId: 1, page }), - // ); - // 클릭 시 리뷰 상세로 이동하는 핸들러 const onClickDetailHandler = (item: ReviewList) => { setNextComponent(detail); // LunchDetail.tsx로 이동 diff --git a/src/components/lunch/ranking/index.tsx b/src/components/lunch/ranking/index.tsx index 459197fe..7ed7078e 100644 --- a/src/components/lunch/ranking/index.tsx +++ b/src/components/lunch/ranking/index.tsx @@ -1,33 +1,34 @@ import LunchCard from '@/components/lunch/LunchCard'; import LunchRankingPodium from '@/components/lunch/ranking/LunchRankingPodium'; import { css } from '@emotion/react'; -import usePagesStore from '@/stores/usePagesStore'; +import usePagesStore from '@/stores/common/usePagesStore'; import theme from '@/styles/theme'; import { LUNCH_MAIN_CONSTANTS } from '@/constants/lunch'; import { Right } from '@/assets/icons'; import useFetch from '@/hooks/useFetch'; import { getRanking } from '@/pages/api/lunch/lunchRequests'; -import useUserStore from '@/stores/useUserStore'; +import useUserStore from '@/stores/common/useUserStore'; import COMPONENT_NAME from '@/constants/common/pages'; +import Loading from '@/components/common/Loading'; // '오늘 점심' 홈의 랭킹 파트 function LunchRanking() { const { title, heights, colors, margin } = LUNCH_MAIN_CONSTANTS.main.ranking; + const { reviewByRanking } = COMPONENT_NAME.lunch.detail; const { setNextComponent } = usePagesStore(); const { buildingId } = useUserStore(); - const { response } = useFetch({ + const { response, loading } = useFetch({ fetchFn: () => getRanking(buildingId), }); const top3Menus = response?.data.slice(0, 3); - let sortedMenus; const onClickHandler = () => { - setNextComponent(COMPONENT_NAME.lunch.detail.reviewByRanking); // 리뷰별 랭킹페이지로 이동 + setNextComponent(reviewByRanking); // 리뷰별 랭킹페이지로 이동 window.scrollTo({ top: 0 }); // 페이지 top: 0으로 이동 }; // 2위 - 1위 - 3위 순으로 정렬. - + let sortedMenus; if (response) { sortedMenus = [ { @@ -59,18 +60,22 @@ function LunchRanking() { - {sortedMenus?.map((item) => ( - - ))} + {loading ? ( + + ) : ( + sortedMenus?.map((item) => ( + + )) + )} diff --git a/src/components/lunch/review/LunchReview.tsx b/src/components/lunch/review/LunchReview.tsx index 3eccbd99..3a9c0aa5 100644 --- a/src/components/lunch/review/LunchReview.tsx +++ b/src/components/lunch/review/LunchReview.tsx @@ -1,11 +1,11 @@ import theme from '@/styles/theme'; import mq from '@/utils/mediaquery'; import { css } from '@emotion/react'; -import { Reviewer } from '@/assets/icons'; import getTimeDiff from '@/utils/getTimeDiff'; import { LunchReviewProps } from '@/types/lunch/reviewList'; import LunchReviewPhotos from '@/components/lunch/review/LunchReviewPhotos'; import LunchReviewRatings from '@/components/lunch/review/LunchReviewRatings'; +import Icons from '@/components/common/Icons'; // '오늘 점심' 리뷰 글에 대한 레이아웃 function LunchReview({ ...props }: LunchReviewProps) { @@ -14,7 +14,7 @@ function LunchReview({ ...props }: LunchReviewProps) { - + {props.memberName} diff --git a/src/components/lunch/review/LunchReviewPhotos.tsx b/src/components/lunch/review/LunchReviewPhotos.tsx index a24c8244..6971fdba 100644 --- a/src/components/lunch/review/LunchReviewPhotos.tsx +++ b/src/components/lunch/review/LunchReviewPhotos.tsx @@ -18,6 +18,7 @@ function LunchReviewPhotos({ photos, isRow }: ReviewPhotosProps) { alt={`이미지${idx}`} width={isRow ? ranking.photoWidth : review.photoWidth} height={isRow ? ranking.photoHeight : review.photoHeight} + priority /> ))} diff --git a/src/components/lunch/review/LunchReviewRestList.tsx b/src/components/lunch/review/LunchReviewRestList.tsx new file mode 100644 index 00000000..2ec7f4fb --- /dev/null +++ b/src/components/lunch/review/LunchReviewRestList.tsx @@ -0,0 +1,40 @@ +import useLunchRouletteStore from '@/stores/lunch/useLunchRouletteStore'; +import useFetch from '@/hooks/useFetch'; +import { getRestList } from '@/pages/api/lunch/lunchRequests'; +import LunchRest from '@/components/lunch/LunchRest'; +import { css } from '@emotion/react'; +import { LunchRestListProps } from '@/types/lunch/reviewList'; + +function LunchReviewRestList({ onClick }: LunchRestListProps) { + const { menuIdState } = useLunchRouletteStore(); + const { setState } = useLunchRouletteStore; + const onClickHandler = () => { + setState({ isDecided: false }); + }; + const { response } = useFetch({ + fetchFn: () => getRestList(menuIdState), + onClick: onClickHandler, + }); + + return ( + + {response?.data.map((item) => ( + onClick(item)} + > + + + ))} + + ); +} + +const wrapperStyles = css` + display: flex; + flex-direction: column; + gap: 16px; +`; + +export default LunchReviewRestList; diff --git a/src/components/lunch/review/LunchReviews.tsx b/src/components/lunch/review/LunchReviews.tsx index 543cecbc..c875cbc0 100644 --- a/src/components/lunch/review/LunchReviews.tsx +++ b/src/components/lunch/review/LunchReviews.tsx @@ -1,20 +1,20 @@ import theme from '@/styles/theme'; import { css } from '@emotion/react'; import useFetch from '@/hooks/useFetch'; -import usePagesStore from '@/stores/usePagesStore'; +import usePagesStore from '@/stores/common/usePagesStore'; import LunchCard from '@/components/lunch/LunchCard'; -import useReviewStore from '@/stores/useReviewStore'; +import useLunchReviewStore from '@/stores/lunch/useLunchReviewStore'; import COMPONENT_NAME from '@/constants/common/pages'; import { ReviewList } from '@/types/lunch/reviewList'; import { LUNCH_MAIN_CONSTANTS } from '@/constants/lunch'; -import useUserStore from '@/stores/useUserStore'; +import useUserStore from '@/stores/common/useUserStore'; import LunchSubTitle from '@/components/lunch/LunchSubTitle'; import { getReviewList } from '@/pages/api/lunch/lunchRequests'; import LunchReview from '@/components/lunch/review/LunchReview'; // function LunchReviews() { - const { setReviewList } = useReviewStore(); + const { setReviewList } = useLunchReviewStore(); const { setNextComponent } = usePagesStore(); const { buildingId, buildingName } = useUserStore(); const { prefix, suffix } = LUNCH_MAIN_CONSTANTS.main.reviews; diff --git a/src/components/lunch/review/LunchReviewsByRanking.tsx b/src/components/lunch/review/LunchReviewsByRanking.tsx index 9d383c8f..08dda781 100644 --- a/src/components/lunch/review/LunchReviewsByRanking.tsx +++ b/src/components/lunch/review/LunchReviewsByRanking.tsx @@ -1,9 +1,9 @@ import useFetch from '@/hooks/useFetch'; import ToTop from '@/components/common/ToTop'; import Header from '@/components/common/Header'; -import usePagesStore from '@/stores/usePagesStore'; +import usePagesStore from '@/stores/common/usePagesStore'; import { LUNCH_MAIN_CONSTANTS } from '@/constants/lunch'; -import useUserStore from '@/stores/useUserStore'; +import useUserStore from '@/stores/common/useUserStore'; import { getRanking } from '@/pages/api/lunch/lunchRequests'; import LunchRankings from '@/components/lunch/ranking/LunchRankings'; diff --git a/src/components/lunch/roulette/LunchRouletteBg.tsx b/src/components/lunch/roulette/LunchRouletteBg.tsx index fd9dcb05..66faa9aa 100644 --- a/src/components/lunch/roulette/LunchRouletteBg.tsx +++ b/src/components/lunch/roulette/LunchRouletteBg.tsx @@ -7,9 +7,21 @@ function LunchRouletteBg({ isOperated }: { isOperated: boolean }) { const { alt } = LUNCH_ROULETTE_CONSTANTS; return isOperated ? ( - + ) : ( - + ); } diff --git a/src/components/lunch/roulette/LunchRouletteLockBtn.tsx b/src/components/lunch/roulette/LunchRouletteLockBtn.tsx index c51ddb18..6d9540e8 100644 --- a/src/components/lunch/roulette/LunchRouletteLockBtn.tsx +++ b/src/components/lunch/roulette/LunchRouletteLockBtn.tsx @@ -2,26 +2,43 @@ import Image from 'next/image'; import mq from '@/utils/mediaquery'; import { css } from '@emotion/react'; import { lockPressed, unLock } from '@/assets/images'; -import useRouletteStore from '@/stores/useRouletteStore'; +import useLunchRouletteStore from '@/stores/lunch/useLunchRouletteStore'; import { LUNCH_ROULETTE_CONSTANTS } from '@/constants/lunch'; import { RouletteButtonProps } from '@/types/lunch/roulette'; // 룰렛 잠금 버튼 렌딩 컴포넌트 function LunchRouletteLockBtn({ onClick }: RouletteButtonProps) { const { alt } = LUNCH_ROULETTE_CONSTANTS; - const { isLocked, isAgain, isOperated } = useRouletteStore(); + const { isLocked, isAgain, isOperated } = useLunchRouletteStore(); const renderBtn = () => { // 최초 룰렛 가동이 아닌 재가동일 경우 if (isAgain) { return isLocked ? ( // 카테고리가 고정인 경우 - + ) : ( - + ); } // 카테고리가 고정이면서 재가동일 경우 - return ; + return ( + + ); }; return ( diff --git a/src/components/lunch/roulette/LunchRoulettePopup.tsx b/src/components/lunch/roulette/LunchRoulettePopup.tsx index e90546e4..e35171a0 100644 --- a/src/components/lunch/roulette/LunchRoulettePopup.tsx +++ b/src/components/lunch/roulette/LunchRoulettePopup.tsx @@ -1,10 +1,10 @@ import { useCallback, useState } from 'react'; import { css } from '@emotion/react'; -import useRouletteStore from '@/stores/useRouletteStore'; +import useLunchRouletteStore from '@/stores/lunch/useLunchRouletteStore'; import { postMenu } from '@/pages/api/lunch/lunchRequests'; import createHyphenDate from '@/utils/createHyphenDate'; import { ErrorProps } from '@/types/common/response'; -import useAlertStore from '@/stores/useAlertStore'; +import useAlertStore from '@/stores/common/useAlertStore'; import Alert from '@/components/common/Alert'; import theme from '@/styles/theme'; import { LUNCH_ROULETTE_CONSTANTS } from '@/constants/lunch'; @@ -13,9 +13,9 @@ import { Popup, PopupActive } from '@/assets/icons'; // 룰렛 팝업 렌딩 컴포넌트 function LunchRoulettePopup() { const { popup } = LUNCH_ROULETTE_CONSTANTS; - const { isOperated, isAgain } = useRouletteStore(); - const { setState } = useRouletteStore; - const { menuIdState } = useRouletteStore(); + const { isOperated, isAgain, isDecided } = useLunchRouletteStore(); + const { setState } = useLunchRouletteStore; + const { menuIdState } = useLunchRouletteStore(); const { alertState, openAlert } = useAlertStore(); const [isActive, setIsActive] = useState(false); @@ -29,39 +29,49 @@ function LunchRoulettePopup() { } catch (err: unknown) { const error = err as ErrorProps; openAlert('📣', error.message); + } finally { + setState({ isDecided: true }); // 메뉴 결정 완료 } }, [menuIdState, openAlert, setState]); // 마우스 클릭 버튼을 누를 때 이벤트 핸들러 const onPressHandler = () => { - setIsActive((prev) => !prev); + setIsActive(true); }; // 마우스 클릭 버튼을 뗄 때 이벤트 핸들러 const onReleaseHandler = () => { - setIsActive((prev) => !prev); + setIsActive(false); }; return ( - - - {alertState.isOpen && } - {isOperated && isAgain && ( - <> - - {popup} - - {isActive ? : } - > - )} - - + + {alertState.isOpen ? ( + + ) : ( + + + {isOperated && isAgain && ( + <> + + {popup} + + + {isActive ? : } + + > + )} + + + )} + ); } diff --git a/src/components/lunch/roulette/LunchRoulettePushBtn.tsx b/src/components/lunch/roulette/LunchRoulettePushBtn.tsx index 8150ee18..871331ad 100644 --- a/src/components/lunch/roulette/LunchRoulettePushBtn.tsx +++ b/src/components/lunch/roulette/LunchRoulettePushBtn.tsx @@ -1,7 +1,7 @@ import Image from 'next/image'; import mq from '@/utils/mediaquery'; import { css } from '@emotion/react'; -import useRouletteStore from '@/stores/useRouletteStore'; +import useLunchRouletteStore from '@/stores/lunch/useLunchRouletteStore'; import { LUNCH_ROULETTE_CONSTANTS } from '@/constants/lunch'; import { RouletteButtonProps } from '@/types/lunch/roulette'; import { push, pushPressed, again, againPressed } from '@/assets/images'; @@ -9,7 +9,7 @@ import { push, pushPressed, again, againPressed } from '@/assets/images'; // 룰렛 PUSH & AGAIN 버튼 렌딩 컴포넌트 function LunchRoulettePushBtn({ onClick }: RouletteButtonProps) { const { alt } = LUNCH_ROULETTE_CONSTANTS; - const { isPressed, isAgain } = useRouletteStore(); + const { isPressed, isAgain } = useLunchRouletteStore(); const renderBtn = () => { if (isAgain) { @@ -19,7 +19,7 @@ function LunchRoulettePushBtn({ onClick }: RouletteButtonProps) { src={againPressed} alt={alt.push} fill - sizes="100vw" + sizes="(min-width: 360px) 100vw" /> ) : ( ); } @@ -37,10 +37,16 @@ function LunchRoulettePushBtn({ onClick }: RouletteButtonProps) { src={pushPressed} alt={alt.push} fill - sizes="100vw" + sizes="(min-width: 360px) 100vw" /> ) : ( - + ); }; return ( diff --git a/src/components/lunch/review/LunchReviewsByRest.tsx b/src/components/lunch/roulette/LunchRouletteReviews.tsx similarity index 52% rename from src/components/lunch/review/LunchReviewsByRest.tsx rename to src/components/lunch/roulette/LunchRouletteReviews.tsx index ccf04959..84bb452d 100644 --- a/src/components/lunch/review/LunchReviewsByRest.tsx +++ b/src/components/lunch/roulette/LunchRouletteReviews.tsx @@ -1,35 +1,26 @@ import { css } from '@emotion/react'; import { LUNCH_ROULETTE_CONSTANTS } from '@/constants/lunch'; -import LunchSubTitle from '@/components/lunch/LunchSubTitle'; import LunchRest from '@/components/lunch/LunchRest'; import theme from '@/styles/theme'; -import useRouletteStore from '@/stores/useRouletteStore'; -import { getRestList } from '@/pages/api/lunch/lunchRequests'; -import useFetch from '@/hooks/useFetch'; -import usePagesStore from '@/stores/usePagesStore'; +import useLunchRouletteStore from '@/stores/lunch/useLunchRouletteStore'; +import usePagesStore from '@/stores/common/usePagesStore'; import { useRouter } from 'next/router'; -import useReviewStore from '@/stores/useReviewStore'; +import useLunchReviewStore from '@/stores/lunch/useLunchReviewStore'; import { GetRestListData } from '@/types/lunch/api'; import COMPONENT_NAME from '@/constants/common/pages'; -import useUserStore from '@/stores/useUserStore'; +import useUserStore from '@/stores/common/useUserStore'; +import DUMMY_DATA from '@/constants/lunch/dummy'; +import LunchSubTitle from '@/components/lunch/LunchSubTitle'; +import LunchReviewRestList from '@/components/lunch/review/LunchReviewRestList'; -function LunchReviewsByRest({ menuId }: { menuId?: number }) { +function LunchRouletteReviews() { const router = useRouter(); const { title } = LUNCH_ROULETTE_CONSTANTS; const { detail } = COMPONENT_NAME.lunch.detail; const { memberName } = useUserStore(); const { setNextComponent } = usePagesStore(); - const { setReviewList, reviewList } = useReviewStore(); - const { menuState, isAgain, isOperated, menuIdState } = useRouletteStore(); - const { response } = useFetch({ - fetchFn: () => getRestList(menuId || menuIdState), - }); - - const renderTitle = () => { - return isAgain && isOperated - ? `"${menuState}" ${title.review} ` - : `${memberName}${title.recent}`; - }; + const { setReviewList, reviewList } = useLunchReviewStore(); + const { isAgain, menuState, isDecided, isOperated } = useLunchRouletteStore(); const onClickHandler = (item: GetRestListData) => { router.push('/lunch'); @@ -43,12 +34,28 @@ function LunchReviewsByRest({ menuId }: { menuId?: number }) { window.scrollTo({ top: 0 }); // 페이지 top: 0으로 이동 }; - return ( - - - - - {response?.data.map((item) => ( + // 타이틀 렌더 함수 + const renderTitle = () => { + // '이걸로 결정' 버튼을 눌렀을 경우 + if (isDecided) return `"${menuState}" ${title.review}`; + + // 최초 동작 완료 전일 경우 + if (isOperated && !isAgain) return `${memberName}${title.recent}`; + + // 그 이외에는 아무 내용도 보이지 않는다. + return ''; + }; + + // 식당 리스트 렌더 함수 + const renderRestList = () => { + // '이걸로 결정' 버튼을 눌렀을 경우 + if (isDecided) { + return ; + } + + // 최초 동작 완료 전일 경우 + if (isOperated && !isAgain) { + return DUMMY_DATA.map((item) => ( - ))} + )); + } + + // 그 이외에는 아무 내용도 보이지 않는다. + return ''; + }; + + return ( + + + + + {renderRestList()} ); } @@ -76,4 +95,4 @@ const stickyStyles = css` background-color: ${theme.palette.white}; `; -export default LunchReviewsByRest; +export default LunchRouletteReviews; diff --git a/src/components/user/UserInfo.tsx b/src/components/user/UserInfo.tsx index 4d958aeb..43f23c8f 100644 --- a/src/components/user/UserInfo.tsx +++ b/src/components/user/UserInfo.tsx @@ -5,7 +5,7 @@ import { ProfileWithBg } from '@/assets/icons'; import useFetch from '@/hooks/useFetch'; import { getMyData } from '@/pages/api/home/homeRequests'; import { useEffect } from 'react'; -import useUserStore from '@/stores/useUserStore'; +import useUserStore from '@/stores/common/useUserStore'; function UserInfo() { const { setState } = useUserStore; diff --git a/src/components/user/UserInvitationList.tsx b/src/components/user/UserInvitationList.tsx index 52a6ff1c..37c2caf6 100644 --- a/src/components/user/UserInvitationList.tsx +++ b/src/components/user/UserInvitationList.tsx @@ -3,16 +3,21 @@ import Header from '@/components/common/Header'; import useFetch from '@/hooks/useFetch'; import createHyphenDate from '@/utils/createHyphenDate'; import UserInvitatioListItem from '@/components/user/UserInvitationListItem'; -import useBottomSheetStore from '@/stores/useBottomSheetStore'; import UserInvitationListEdit from '@/components/user/UserInvitationListEdit'; import { css } from '@emotion/react'; import { useRouter } from 'next/router'; +import { useEffect } from 'react'; import { USER_INVITATIONLIST_TEXT } from '@/constants/user/userInvitationTexts'; import { getInvitationList } from '@/pages/api/invitation/editRequests'; +import useBottomSheetStore from '@/stores/common/useBottomSheetStore'; +// import useInvitationListStore from '@/stores/useInvitationListStore'; +import useInvitationEditStore from '@/stores/invitaion/useInvitationEditStore'; import BottomSheet from '../common/BottomSheet'; function UserInvitationList() { const { openBottomSheet } = useBottomSheetStore(); + const { setEditContents } = useInvitationEditStore(); + // const { setInvitationListeState } = useInvitationListStore(); const router = useRouter(); const onClickHandler = () => { router.push('/user'); @@ -26,9 +31,22 @@ function UserInvitationList() { fetchFn: getInvitationList, }); - // 빋어온 데이터 객체를 다중 배열로 변환 + useEffect(() => { + setEditContents('commonPlaceId', ''); + setEditContents('description', ''); + setEditContents('startDate', ''); + setEditContents('endDate', ''); + setEditContents('visitors', []); + }, []); + const invitationList = response && Object.values(response?.data); + // 빋어온 데이터 객체를 다중 배열로 변환 + // const invitationListHandler = () => { + // const invitationList = response && Object.values(response?.data); + // setInvitationListeState(invitationList); + // }; + // 오늘 날짜 가져오는 로직 const currentDate = new Date(); // 데이터상 날짜 비교를 위한 포켓 변환 @@ -66,6 +84,7 @@ function UserInvitationList() { ); } + const userInvitationListStyles = css` display: flex; flex-direction: column; diff --git a/src/components/user/UserInvitationListEdit.tsx b/src/components/user/UserInvitationListEdit.tsx index e801875e..0bea0f0c 100644 --- a/src/components/user/UserInvitationListEdit.tsx +++ b/src/components/user/UserInvitationListEdit.tsx @@ -8,17 +8,19 @@ import { UserInvitationListEditProps } from '@/types/invitation/edit'; import { getInvitationDeleteList } from '@/pages/api/invitation/editRequests'; import theme from '@/styles/theme'; import Modal from '@/components/common/Modal'; -import useModalStore from '@/stores/useModalStore'; -import useBottomSheetStore from '@/stores/useBottomSheetStore'; +import useModalStore from '@/stores/common/useModalStore'; +import useBottomSheetStore from '@/stores/common/useBottomSheetStore'; function UserInvitationListEdit({ id }: UserInvitationListEditProps) { const router = useRouter(); const { title, confirm } = USER_INVITATIONLIST_BUTTON_TEXT; - const { modalState, openModal } = useModalStore(); + const { modalState, openModal, closeModal } = useModalStore(); const { closeBottomSheet } = useBottomSheetStore(); const onclickModalHandler = () => { getInvitationDeleteList(id as string); + closeModal(); + closeBottomSheet(); }; const onclickdeleteHandler = () => { diff --git a/src/components/user/UserInvitationListItem.tsx b/src/components/user/UserInvitationListItem.tsx index fc0ce1da..7dfb53e5 100644 --- a/src/components/user/UserInvitationListItem.tsx +++ b/src/components/user/UserInvitationListItem.tsx @@ -2,6 +2,7 @@ import theme from '@/styles/theme'; import changeVisitPurpose from '@/utils/changeVisitPurpose'; import { css } from '@emotion/react'; import { UserInvitationListItemProps } from '@/types/user/invitationList'; +import mq from '@/utils/mediaquery'; function UserInvitationListItem({ data }: UserInvitationListItemProps) { const visitorCount = data.visitorCount - 1; @@ -22,7 +23,8 @@ function UserInvitationListItem({ data }: UserInvitationListItemProps) { {data.officeName} - {startTime}~{endTime} + {startTime}~ + {endTime} ); @@ -47,9 +49,10 @@ const firstLineStyles = css` display: flex; flex-direction: row; align-items: center; + margin-bottom: 2px; `; const visitorInfoStyles = css` - font: ${theme.font.subTitle.subTitle1_400}; + font: ${theme.font.subTitle.subTitle2_400}; color: ${theme.palette.title}; margin-right: 8px; `; @@ -59,10 +62,20 @@ const purposeStyles = css` `; const placeStyles = css` font: ${theme.font.body.body2_400}; - color: ${theme.palette.greyscale.grey40}; + color: ${theme.palette.greyscale.grey50}; + text-align: left; `; const timeStyles = css` + display: flex; + flex-direction: column; + justify-content: right; font: ${theme.font.body.body1_400}; color: ${theme.palette.primary}; + ${mq.md} { + display: flex; + flex-direction: row; + } + ${mq.tab} { + } `; export default UserInvitationListItem; diff --git a/src/constants/common/index.ts b/src/constants/common/index.ts index e3767a87..700175a8 100644 --- a/src/constants/common/index.ts +++ b/src/constants/common/index.ts @@ -69,7 +69,7 @@ export const COMMON_INPUT_COLORS: InputColorsProps = { }, }; -// 에러메세지 내용은 추후 변경 +// 에러메세지 export const COMMON_ERROR_MESSAGE = { default: '오류가 발생했습니다', name: '이름 형식이 올바르지 않아요', @@ -82,6 +82,8 @@ export const COMMON_ERROR_MESSAGE = { noServer: '네트워크 연결상태를 확인해주세요', back: '이전으로 돌아가기', prepare: '기능 준비 중입니다.', + copyFailed: '클립보드 복사 실패', + copy: '클립보드 복사 완료', }; // Header @@ -154,36 +156,36 @@ export const COMMON_ICON_NAMES = { close: 'close', error: 'error', exitSmall: 'exitSmall', + reviewer: 'reviewer', + exitMedium: 'exitMedium', }, }; -// 카테고리 이름 +// 초대장 생성 - 초대 목적 카테고리 export const COMMON_CATEGORIES = { - invitation: { - meeting: { - icon: 'meeting', - title: '회의', - }, - interview: { - icon: 'interview', - title: '면접', - }, - fixedTermWork: { - icon: 'fixedTermWork', - title: '기간 근무', - }, - seminar: { - icon: 'seminar', - title: '세미나', - }, - as: { - icon: 'as', - title: 'AS/점검', - }, - etc: { - icon: 'etc', - title: '기타', - }, + meeting: { + icon: 'meeting', + title: '회의', + }, + interview: { + icon: 'interview', + title: '면접', + }, + fixedTermWork: { + icon: 'fixedTermWork', + title: '기간 근무', + }, + seminar: { + icon: 'seminar', + title: '세미나', + }, + as: { + icon: 'as', + title: 'AS/점검', + }, + etc: { + icon: 'etc', + title: '기타', }, }; diff --git a/src/constants/common/pages.ts b/src/constants/common/pages.ts index 2c463648..474847e9 100644 --- a/src/constants/common/pages.ts +++ b/src/constants/common/pages.ts @@ -1,10 +1,10 @@ const COMPONENT_NAME = { invitation: { create: { - visiors: 'InvitationVisitorsContainer', + purpose: 'InvitationPurposeContainer', + visitors: 'InvitationVisitorsContainer', info: 'InvitationInfoContainer', done: 'InvitationDoneContainer', - purpose: 'InvitationPurposeContainer', }, view: {}, }, diff --git a/src/constants/home/homeTexts.ts b/src/constants/home/homeTexts.ts index ba3ac06d..f94fa7f8 100644 --- a/src/constants/home/homeTexts.ts +++ b/src/constants/home/homeTexts.ts @@ -19,8 +19,8 @@ export const HOME_TEXTS = { href: '/lunch/roulette', }, bulletin: [ - { title: '공지', content: '엘리베이터 정기 점검 안내(8/23)' }, - { title: '이벤트', content: '테라빌딩 커피 무료 나눔 이벤트(9/17)' }, + { title: '공지', content: '엘리베이터 정기 점검 안내(10/10)' }, + { title: '이벤트', content: '테라타워 커피 무료 나눔 이벤트(10/6)' }, ], cafeteria: { title: '구내식당', diff --git a/src/constants/invitation/createTexts.ts b/src/constants/invitation/createTexts.ts index 3705288d..159b4136 100644 --- a/src/constants/invitation/createTexts.ts +++ b/src/constants/invitation/createTexts.ts @@ -7,6 +7,7 @@ const CREATE_TEXTS = { seminar: '세미나 초대', as: 'AS/점검 초대', etc: '방문자 초대', + preview: '예시', }, title: { purpose: '방문증을 만드는 이유는 무엇인가요?', @@ -54,6 +55,9 @@ const CREATE_TEXTS = { }, btn: '전송하기', }, + error: { + timeAPI: '예약 가능 시간 API에 문제가 생겼습니다.', + }, checkbox: '이 메세지를 다음에도 사용', radioBtn: '기타 (직접입력)', timeSelector: { diff --git a/src/constants/invitation/editTexts.ts b/src/constants/invitation/editTexts.ts index 840a1642..f059ac40 100644 --- a/src/constants/invitation/editTexts.ts +++ b/src/constants/invitation/editTexts.ts @@ -7,6 +7,10 @@ export const INVITATION_EDIT_TEXTS = { contact: '전화번호 입력', btn: '완료', }, + modal: { + title: `초대장 재전송`, + content: `초대장을 이대로 수정하고 전송할까요?`, + }, }; export const test = { test: 'test', diff --git a/src/constants/invitation/viewTexts.ts b/src/constants/invitation/viewTexts.ts index 59f8d375..2cbef6d3 100644 --- a/src/constants/invitation/viewTexts.ts +++ b/src/constants/invitation/viewTexts.ts @@ -1,14 +1,13 @@ import { InvitationInfoThemesProps } from '@/types/invitation/view'; import theme from '@/styles/theme'; -// 상수도 초대장 메인 브랜치 작업 완료되면 수정할 예정입니다 export const INVITATION_VEIW_INFO_TEXTS = { category: { main: '식스센스 초대장', building: '빌딩 소개', place: '초대 장소', host: '초대자 정보', - parking: '주차 정보', + parking: '주차 등록', code: '식스센스 출입증', }, icon: { @@ -17,12 +16,26 @@ export const INVITATION_VEIW_INFO_TEXTS = { host: 'InfoHost', parking: 'InfoParking', }, + qr: { + title: '임시출입증', + body: '초대 시간 전후로 \n 1시간 동안 사용할수 있습니다', + }, host: { name: '이름', companyName: '회사', contact: '연락처', card: '현재 등록한 명함이 없습니다', }, + ticket: { + headers: '임시출입증', + zoom: '크게보기', + }, + footer: { + title: '주)리버블', + call: '고객센터 : 1833-9092', + site: '사이트 : https://www.officener.com', + btn: '관리실 문의하기', + }, }; // tikect theme 지정 @@ -36,57 +49,45 @@ export const INVITATION_VIEW_TICKET_THEME: InvitationInfoThemesProps = { #5c8fff 56.65%, #2563eb 82.62% );`, + backgroundImageBig: `linear-gradient(141deg, #2563EB 11.61%, #457FFE 22.34%, #2563EB 40.09%, #5C8FFF 71.66%, #2563EB 80.29%);`, shadow: `0px 25px 20px -15px #9bafff89;`, boxShadow: `linear-gradient(28deg, rgba(37, 99, 235, 0.30) 33.02%, rgba(37, 99, 235, 0.22) 70.11%, rgba(37, 99, 235, 0.26) 90.84%);`, - side: `linear-gradient( - to left, - rgba(213, 223, 255, 0.895), - #ffffff - );`, - sideRight: `linear-gradient( - to right, - rgba(213, 223, 255, 0.895), - #ffffff - );`, - icon: `${theme.palette.primary};`, + side: `linear-gradient(to left, #c7d5ff, #ffffff, #ffffff);`, + sideRight: `linear-gradient(to right, #9eb0ff72, #eef6ff11, #ffffff);`, + icon: `${theme.palette.primary}`, }, pink: { backgroundImage: `linear-gradient(105deg, #FFB2B2 1.1%, #EDB1BC 46.72%, #AED3FF 100.31%);`, - shadow: `0px 25px 20px -15px rgba(212, 191, 215, 0.5);`, + backgroundImageBig: `linear-gradient(154deg, #FFB2B2 0.46%, #EDB1D5 63.2%, #AED3FF 104.55%);`, + shadow: `0px 25px 20px -15px rgba(212, 191, 215, 0.1);`, boxShadow: `linear-gradient( 284deg, rgba(78, 154, 253, 0.473) 3.48%, rgba(212, 191, 215, 0.5) 30.95%, rgba(254, 178, 178, 0.69) 59.89% - );`, - side: `linear-gradient(to left, #ffebeb93, #ffffff);`, - sideRight: `linear-gradient(to right, #ffebeb93, #ffffff);`, + )`, + side: `linear-gradient(to left, #f5e0f2, #ffffff, #ffffff);`, + sideRight: `linear-gradient(to right, #ffc4eba1, #eef6ff11, #ffffff);`, icon: `rgba(255, 178, 178, 1)`, }, green: { backgroundImage: `linear-gradient(105deg, #6386D5 1.1%, #3CD1A4 52.33%, #F9DC77 88.25%, #FEFFCA 100.31%);`, + backgroundImageBig: `linear-gradient(154deg, #6386D5 0.46%, #3CD1A4 54.21%, #F9DC77 91.9%, #FEFFCA 104.55%);`, shadow: `0px 25px 20px -15px rgba(99, 134, 213, 0.2);`, boxShadow: `linear-gradient( - to right, + 105deg, rgba(99, 134, 213, 0.5) 1.1%, rgba(60, 209, 164, 0.5) 52.33%, rgba(249, 220, 119, 0.5) 88.25%, rgba(254, 255, 202, 0.5) 100.31% );`, - side: ` linear-gradient( - to left, - rgba(212, 225, 254, 0.783), - #ffffff - );`, - sideRight: ` linear-gradient( - to right, - rgba(212, 225, 254, 0.783), - #ffffff - );`, - icon: `rgba(99, 134, 213, 1)`, + side: `linear-gradient(to left, #c0d7e7, #eef6ff, #ffffff);`, + sideRight: `linear-gradient(to right, #3cccd16b, #eef6ff11, #ffffff);`, + icon: `rgba(67, 209, 190, 1)`, }, orange: { backgroundImage: `linear-gradient(140deg, #FFAC6F 0.63%, #FF9141 53.71%, #FF6B6B 90.91%, #FF9AB3 103.4%);`, + backgroundImageBig: `linear-gradient(140deg, #FFAC6F 0.63%, #FF9141 53.71%, #FF6B6B 90.91%, #FF9AB3 103.4%);`, shadow: `0px 25px 20px -15px rgba(240, 145, 145, 0.5);`, boxShadow: `linear-gradient( 105deg, @@ -95,20 +96,13 @@ export const INVITATION_VIEW_TICKET_THEME: InvitationInfoThemesProps = { rgba(255, 233, 157, 0.5) 88.25%, rgba(211, 255, 203, 0.5) 100.31% );`, - side: `linear-gradient( - to left, - rgba(252, 221, 221, 0.885), - #ffffff - );`, - sideRight: `linear-gradient( - to right, - rgba(252, 221, 221, 0.885), - #ffffff - );`, + side: `linear-gradient(to left, #f4d2cb, #ffffff, #ffffff);`, + sideRight: `linear-gradient(to right, #ff976b60, #eef6ff11, #ffffff)`, icon: `rgba(255, 172, 111, 1)`, }, skyblue: { backgroundImage: `linear-gradient(105deg, #91CEF0 1.1%, #90B1F9 52.33%, #B19EFF 90.17%, #FF9EE4 100.31%);`, + backgroundImageBig: `linear-gradient(154deg, #91CEF0 0.46%, #90B1F9 54.21%, #B19EFF 93.91%, #FF9EE4 104.55%);`, shadow: ` box-shadow: 0px 25px 20px -15px #e8e2ff70;`, boxShadow: `linear-gradient( 105deg, @@ -117,8 +111,8 @@ export const INVITATION_VIEW_TICKET_THEME: InvitationInfoThemesProps = { #b19eff 90.17%, #ff9ee4 100.31% );`, - side: `linear-gradient(to left, #e6f6ffd2, #ffffff);`, - sideRight: `linear-gradient(to right, #e6f6ffd2, #ffffff);`, + side: `linear-gradient(to left, #d5dff6, #ffffff, #ffffff);`, + sideRight: `linear-gradient(to right, #9eb0ff72, #eef6ff11, #ffffff);`, icon: `rgba(145, 206, 240, 1)`, }, }; @@ -127,18 +121,14 @@ export const INVITATION_CAROUSEL_TEXTS = { restaurant: { title: '식당', subtitle: '점심메뉴 고민,', - body: '테라타워 근처 맛집 추천!', + contents: '맛집', }, cafe: { title: '카페', subtitle: '조금 빨리 도착하셨나요?', - body: '근처 카페를 추천드릴게요', }, -}; - -// 오피스 정보 상수(수정 예정) -export const INVITATION_VIEW_TEXTS = { - header: { - office: '오피스 정보', + parking: { + upParking: '방문 시 주차를 원하시면 차량 정보를 등록해주세요', + doneParking: '차량번호를 등록했어요', }, }; diff --git a/src/constants/lunch/dummy.ts b/src/constants/lunch/dummy.ts index e387daef..fef2d08f 100644 --- a/src/constants/lunch/dummy.ts +++ b/src/constants/lunch/dummy.ts @@ -1,296 +1,65 @@ // 임시용 -export const DUMMY_DATA = [ +const DUMMY_DATA = [ { - restaurantName: '새마을식당', - restaurantId: '1', - memberName: '백종원', - profileImageUrl: '/defaultImage.jpg', - reviewId: 1, - reviewTaste: 'GOOD', - reviewAmount: 'GOOD', - reviewService: 'GOOD', - reviewSpeed: 'GOOD', - reviewCreatedAt: '2023-09-23T09:20:00', - reviewImageUrl: [ - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - ], - reviewDescription: `매일 가는 단골 식당이에요 부대찌개 말고도 다른 메뉴들도 맛있어요! 사장님도 친절하십니다 ㅎㅎ`, + address: '경기 남양주시 다산지금로 202 2층', + estimatedTime: 0, + floor: 2, + inBuilding: true, + representativeImageUrl: + 'https://img1.kakaocdn.net/cthumb/local/C320x320/?fname=http%3A%2F%2Ft1.daumcdn.net%2Fplace%2FDFD007D1D3354AC8A7CA9AD3D4841ED6', + restaurantId: 1, + restaurantName: '레드신 다산직영점', + review: '좋아요', + tastePercentage: 95, }, { - restaurantName: '노브랜드 버거', - restaurantId: '2', - memberName: '정용진', - profileImageUrl: '/defaultImage.jpg', - reviewId: 2, - reviewTaste: 'BAD', - reviewAmount: 'BAD', - reviewService: 'GOOD', - reviewSpeed: 'BAD', - reviewCreatedAt: '2023-09-22T08:12:00', - reviewImageUrl: [ - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - ], - reviewDescription: - '평소랑 오늘은 다른맛이긴 했어요. 버거 패티가 바뀌었나..그 전이 더 맛있었는데 다음에도 오늘과 같으면 안갈 것 같아요.', + address: '경기 남양주시 다산지금로 202 1층', + estimatedTime: 0, + floor: 1, + inBuilding: true, + representativeImageUrl: + 'https://img1.kakaocdn.net/cthumb/local/R0x420/?fname=https%3A%2F%2Fpostfiles.pstatic.net%2FMjAyMzAxMjBfMjU3%2FMDAxNjc0MjI0MDM4MTYz.CJ0i7OmUlkFNuJxLRZnJCkdo0WDFTB2bfT1LwY1gdB4g.2fQZFSPj66VXSmsLLVoLeOa5PStrnIz0Bos5hZAuVO0g.JPEG.free1206%2FKMG03525.jpg%3Ftype%3Dw966', + restaurantId: 8, + restaurantName: '초록분식', + review: '옛날 떡볶이', + tastePercentage: 92, }, { - restaurantName: '집게리아', - restaurantId: '3', - memberName: '집게사장', - profileImageUrl: '/defaultImage.jpg', - reviewId: 3, - reviewTaste: 'BAD', - reviewAmount: 'BAD', - reviewService: 'GOOD', - reviewSpeed: 'BAD', - reviewCreatedAt: '2023-09-13T10:21:00', - reviewImageUrl: [ - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - ], - reviewDescription: - '카운터에 있는 직원이 너무 불친절했어요. 특히 사장님은 직원을 이봐 징징이라고 부르시는 모습에 버거맛이 뚝 떨어졌어요.', + address: '경기 남양주시 다산지금로 202 1층', + estimatedTime: 0, + floor: 1, + inBuilding: true, + representativeImageUrl: + 'https://img1.kakaocdn.net/cthumb/local/R0x420/?fname=https%3A%2F%2Fpostfiles.pstatic.net%2FMjAyMzA0MDNfMTUg%2FMDAxNjgwNDg0MDQ3NTE0.RusRbSD6jf0aMd2XbTD0e_A11Y1bdnaqUWGDk2781eQg.lC6kTsr2CPL20XCC_NNbWWZQRxokdKFjM7l6KcqarmIg.JPEG.tjdls1221%2F20230330_204644.jpg%3Ftype%3Dw966', + restaurantId: 17, + restaurantName: '수유리우동집 다산테라타워점', + review: '잘 말아주는 김밥', + tastePercentage: 94, }, { - restaurantName: '플랑크톤 상점', - restaurantId: '4', - memberName: '플랑크톤', - profileImageUrl: '/defaultImage.jpg', - reviewId: 4, - reviewTaste: 'GOOD', - reviewAmount: 'GOOD', - reviewService: 'BAD', - reviewSpeed: 'GOOD', - reviewCreatedAt: '2023-09-12T09:10:00', - reviewImageUrl: [ - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - ], - reviewDescription: - '여기 집게리아 게살버거보다 맛있네요. 광고같아 보이지만 광고 맞습니다.', - }, -]; - -export const DUMMMY_MENU_TOP_TEN = [ - { - date: '2023-09-11', - count: 194, - rank: 1, - menuId: 36, - menuName: '부대찌개', - menuImage: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - }, - { - date: '2023-09-11', - count: 152, - rank: 2, - menuId: 12, - menuName: '제육볶음', - menuImage: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - }, - { - date: '2023-09-11', - count: 121, - rank: 3, - menuId: 74, - menuName: '돈까스', - menuImage: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - }, - { - date: '2023-09-11', - count: 95, - rank: 4, - menuId: 14, - menuName: '메밀국수', - menuImage: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - }, - { - date: '2023-09-11', - count: 95, - rank: 5, - menuId: 14, - menuName: '치킨', - menuImage: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - }, - { - date: '2023-09-11', - count: 95, - rank: 6, - menuId: 14, - menuName: '피자', - menuImage: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - }, - { - date: '2023-09-11', - count: 95, - rank: 7, - menuId: 14, - menuName: '햄버거', - menuImage: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - }, - { - date: '2023-09-11', - count: 95, - rank: 8, - menuId: 14, - menuName: '양갈비', - menuImage: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - }, - { - date: '2023-09-11', - count: 95, - rank: 9, - menuId: 14, - menuName: '소갈비', - menuImage: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', + address: '경기 남양주시 다산지금로 202 1층', + estimatedTime: 0, + floor: 1, + inBuilding: true, + representativeImageUrl: + 'https://img1.kakaocdn.net/cthumb/local/R0x420/?fname=http%3A%2F%2Ft1.daumcdn.net%2Flocal%2FkakaomapPhoto%2Freview%2F952855d7f214b7ce83cbdce0a3cae856dd703b32%3Foriginal', + restaurantId: 22, + restaurantName: '길동우동 다산 현대테라타워점', + review: '맛있는 우동 한그릇', + tastePercentage: 92, }, { - date: '2023-09-11', - count: 95, - rank: 10, - menuId: 14, - menuName: '돼지갈비', - menuImage: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', + address: '경기 남양주시 다산지금로 202 지하1층', + estimatedTime: 0, + floor: 2, + inBuilding: true, + representativeImageUrl: + 'https://img1.kakaocdn.net/cthumb/local/R0x420/?fname=http%3A%2F%2Ft1.daumcdn.net%2Fplace%2FEA2C7E49B71F454DB12840B15A2A17FE', + restaurantId: 31, + restaurantName: '맛자랑떡볶이 다산직영점', + review: '좋아요', + tastePercentage: 96, }, ]; -export const DUMMY_RESPONSE = { - data: [ - { - restaurantId: 1, - name: '현수네 기사식당', - tastePercentage: 34, - representativeImageUrl: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - address: '테라타워 11층', - floor: 11, - isBuilding: true, - estimatedTime: 0, - review: '맛나용!', - }, - { - restaurantId: 2, - name: '현수네 백반집', - tastePercentage: 55, - representativeImageUrl: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - address: '테라타워 10층', - floor: 10, - isBuilding: true, - estimatedTime: 0, - review: '맛나용!', - }, - { - restaurantId: 3, - name: '현수네 한식왕', - tastePercentage: 77, - representativeImageUrl: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - address: '마미상가 3층', - floor: 0, - isBuilding: false, - estimatedTime: 3, - review: '맛나용!', - }, - { - restaurantId: 4, - name: '현수네 기사식당', - tastePercentage: 34, - representativeImageUrl: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - address: '테라타워 11층', - floor: 11, - isBuilding: true, - estimatedTime: 0, - review: '맛나용!', - }, - { - restaurantId: 5, - name: '현수네 백반집', - tastePercentage: 55, - representativeImageUrl: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - address: '테라타워 10층', - floor: 10, - isBuilding: true, - estimatedTime: 0, - review: '맛나용!', - }, - { - restaurantId: 6, - name: '현수네 한식왕', - tastePercentage: 77, - representativeImageUrl: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - address: '마미상가 지하 1층', - floor: 0, - isBuilding: false, - estimatedTime: 3, - review: '맛나용!', - }, - { - restaurantId: 7, - name: '현수네 기사식당', - tastePercentage: 34, - representativeImageUrl: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - address: '테라타워 11층', - floor: 11, - isBuilding: true, - estimatedTime: 0, - review: '맛나용!', - }, - { - restaurantId: 8, - name: '현수네 백반집', - tastePercentage: 55, - representativeImageUrl: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - address: '테라타워 10층', - floor: 10, - isBuilding: true, - estimatedTime: 0, - review: '맛나용!', - }, - { - restaurantId: 9, - name: '현수네 한식왕', - tastePercentage: 77, - representativeImageUrl: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - address: '마미상가 3층', - floor: 0, - isBuilding: false, - estimatedTime: 3, - review: '맛나용!', - }, - { - restaurantId: 10, - name: '현수네 한식왕', - tastePercentage: 77, - representativeImageUrl: - 'https://livable-final.s3.ap-northeast-2.amazonaws.com/%EB%A7%88%EB%9D%BC%ED%83%95.jpg', - address: '마미상가 3층', - floor: 0, - isBuilding: false, - estimatedTime: 3, - review: '맛나용!', - }, - ], -}; +export default DUMMY_DATA; diff --git a/src/constants/lunch/index.ts b/src/constants/lunch/index.ts index 21f965c4..a067f782 100644 --- a/src/constants/lunch/index.ts +++ b/src/constants/lunch/index.ts @@ -164,10 +164,6 @@ export const LUNCH_ROULETTE_CONSTANTS = { lock: '잠금', }, popup: `이 메뉴로 결정! \n 맛집 보러가기`, - menu: { - min: 0, - max: 68, - }, }; export const POINT_CONSTANTS = { diff --git a/src/hooks/useFetch.ts b/src/hooks/useFetch.ts index cc6f1a1d..73d05353 100644 --- a/src/hooks/useFetch.ts +++ b/src/hooks/useFetch.ts @@ -1,23 +1,24 @@ -import useAlertStore from '@/stores/useAlertStore'; +import useAlertStore from '@/stores/common/useAlertStore'; import { ErrorProps, FetchProps } from '@/types/common/response'; import { useEffect, useState, useCallback } from 'react'; // API fetch custom Hook -const useFetch = ({ fetchFn }: FetchProps) => { +const useFetch = ({ fetchFn, onClick }: FetchProps) => { const [response, setResponse] = useState(null as T); const [loading, setLoading] = useState(false); + const [isError, setIsError] = useState(false); const { alertState, openAlert } = useAlertStore(); const fetchData = useCallback(async () => { try { - // TODO: 로딩 처리 정의 해야함 setLoading(true); + setIsError(false); const data = await fetchFn(); setResponse(data); - // TODO: 에러 처리 정의 해야함 } catch (err: unknown) { const error = err as ErrorProps; - openAlert('📢', error.message); + setIsError(true); + openAlert('📢', error.message, onClick); } finally { setLoading(false); } @@ -27,7 +28,7 @@ const useFetch = ({ fetchFn }: FetchProps) => { fetchData(); }, []); - return { response, loading, alertState }; + return { response, loading, alertState, isError }; }; export default useFetch; diff --git a/src/pages/_document.tsx b/src/pages/_document.tsx index 33d0fd22..fe9f362b 100644 --- a/src/pages/_document.tsx +++ b/src/pages/_document.tsx @@ -4,7 +4,11 @@ function Document() { return ( - Livable + + + + + Officener diff --git a/src/pages/api/invitation/viewRequests.ts b/src/pages/api/invitation/viewRequests.ts index ee611950..c7428b6d 100644 --- a/src/pages/api/invitation/viewRequests.ts +++ b/src/pages/api/invitation/viewRequests.ts @@ -4,6 +4,7 @@ import { GetInvitationCarouselData, GetVisitationInfoData, GetVisitationQrData, + PostInvitationParkingData, } from '@/types/invitation/api'; // 초대장 근처 식당 정보 @@ -29,3 +30,8 @@ export const getVisitationQr = async (): Promise< const response = await apiInstance.get('visitation/qr'); return response.data; }; + +export const postParking = async (carNumber: PostInvitationParkingData) => { + const response = await apiInstance.post(`visitation/parking`, carNumber); + return response; +}; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 21dab3df..08698691 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -7,24 +7,23 @@ import { getHome } from '@/pages/api/home/homeRequests'; import theme from '@/styles/theme'; import { css } from '@emotion/react'; import { useEffect } from 'react'; -import usePagesStore from '@/stores/usePagesStore'; -import useSaveStore from '@/stores/useSaveStore'; -import { useRouter } from 'next/router'; -import useUserStore from '@/stores/useUserStore'; +import usePagesStore from '@/stores/common/usePagesStore'; +import useSaveStore from '@/stores/common/useSaveStore'; +import useUserStore from '@/stores/common/useUserStore'; import Alert from '@/components/common/Alert'; function Home() { - const router = useRouter(); + const MEMBER_TOKEN = process.env.MEMBER_TOKEN as string; + const { setUserToken, clearToken } = useSaveStore(); const { reset } = usePagesStore(); const { setState } = useUserStore; - const { response, alertState } = useFetch({ + const { response, alertState, loading } = useFetch({ fetchFn: getHome, }); useEffect(() => { - if (!useSaveStore.getState().user) { - router.push('/login'); - } + clearToken(); + setUserToken(MEMBER_TOKEN); reset(); if (response?.data.buildingId) { setState({ ...response?.data }); @@ -34,7 +33,12 @@ function Home() { return ( <> {alertState.isOpen && } - + @@ -44,7 +48,7 @@ function Home() { } const containerStyles = css` - margin: 0 -16px 90px; + margin: 0 -16px calc(env(safe-area-inset-bottom) + 54px); background: ${theme.palette.background.home}; `; diff --git a/src/pages/invitation/create.tsx b/src/pages/invitation/create.tsx index f3e983a4..bfce7486 100644 --- a/src/pages/invitation/create.tsx +++ b/src/pages/invitation/create.tsx @@ -1,31 +1,39 @@ import Header from '@/components/common/Header'; import InvitationCreateForm from '@/components/invitation/InvitationCreateForm'; -import useInvitationHeaderTitleStore from '@/stores/useInvitationHeaderTitleStore'; -import useViewStore from '@/stores/usePagesStore'; -import useModalStore from '@/stores/useModalStore'; +import InvitationPreview from '@/components/invitation/create/InvitationPreview'; +import useInvitationHeaderTitleStore from '@/stores/invitaion/useInvitationHeaderTitleStore'; +import useViewStore from '@/stores/common/usePagesStore'; +import CREATE_TEXTS from '@/constants/invitation/createTexts'; import mq from '@/utils/mediaquery'; +import { useState } from 'react'; import { css } from '@emotion/react'; -import Modal from '@/components/common/Modal'; +import { InvitationCreateTexts } from '@/types/invitation/create'; function Create() { const { nextComponent } = useViewStore(); const { headerTitle } = useInvitationHeaderTitleStore(); - const { modalState, openModal } = useModalStore(); + const { header }: InvitationCreateTexts = CREATE_TEXTS; + + // 예시 컴포넌트 오픈 상태 + const [isOpen, setIsOpen] = useState(false); + + // 예시 버튼 클릭 핸들러 + const onClick = () => { + setIsOpen(!isOpen); + }; return ( - + - openModal('test', '방문증 미리보기가 구현될 예정이에요!') - } + text={header.preview} + onClick={onClick} /> - {modalState.isOpen && } + {isOpen && } ); } @@ -50,9 +58,12 @@ const createContainerStyles = css` } `; -const headerContainerStyles = css` +const headerContainerStyles = (nextComponent: string) => css` position: sticky; top: 0; + display: ${nextComponent === 'InvitationDoneContainer' + ? 'none' // 초대장 전송 완료 컴포넌트에서 헤더 미사용 + : 'block'}; width: 100%; z-index: 1; `; diff --git a/src/pages/invitation/edit.tsx b/src/pages/invitation/edit.tsx index 85903f98..dcf04402 100644 --- a/src/pages/invitation/edit.tsx +++ b/src/pages/invitation/edit.tsx @@ -1,10 +1,10 @@ import { useRouter } from 'next/router'; -import InvitationEdit from '@/components/invitation/edit/InvitationEdit'; +import InvitaitonEditForm from '@/components/invitation/InvitaitonEditForm'; function Edit() { const router = useRouter(); const { id } = router.query; - return ; + return ; } export default Edit; diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx deleted file mode 100644 index 0561532f..00000000 --- a/src/pages/login/index.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import AuthForm from '@/components/auth/AuthForm'; -import Title from '@/components/common/Title'; -import { HOME_TEXTS } from '@/constants/home/homeTexts'; -import useSaveStore from '@/stores/useSaveStore'; -import mq from '@/utils/mediaquery'; -import { css } from '@emotion/react'; -import { useRouter } from 'next/router'; -import { useEffect, useState } from 'react'; - -function Login() { - const [userToken, setUserToken] = useState(null); - const router = useRouter(); - - useEffect(() => { - const token = useSaveStore.getState().user; - setUserToken(token); - }, []); - - if (userToken) router.push('/'); - - return ( - - - - - ); -} - -const containerStyles = css` - position: relative; - display: flex; - flex-direction: column; - align-items: center; - height: 100vh; - gap: 96px; - min-width: 280px; - max-width: 360px; - - ${mq.md} { - max-width: 480px; - } - ${mq.lg} { - max-width: 640px; - } - ${mq.tab} { - max-width: 1024px; - } -`; -export default Login; diff --git a/src/pages/lunch/index.tsx b/src/pages/lunch/index.tsx index fca2f971..eb21df3d 100644 --- a/src/pages/lunch/index.tsx +++ b/src/pages/lunch/index.tsx @@ -6,7 +6,7 @@ import LunchMainContents from '@/components/lunch/LunchMainContents'; import LunchReviewsByRanking from '@/components/lunch/review/LunchReviewsByRanking'; import COMPONENT_NAME from '@/constants/common/pages'; import { HOME_TEXTS } from '@/constants/home/homeTexts'; -import usePagesStore from '@/stores/usePagesStore'; +import usePagesStore from '@/stores/common/usePagesStore'; import theme from '@/styles/theme'; import { css } from '@emotion/react'; @@ -37,7 +37,7 @@ function LunchHome() { } const containerStyles = css` - margin: 0 -16px 90px; + margin: 0 -16px env(safe-area-inset-bottom); background: ${theme.palette.background.home}; `; diff --git a/src/pages/lunch/roulette.tsx b/src/pages/lunch/roulette.tsx index bc96006a..9462a2cd 100644 --- a/src/pages/lunch/roulette.tsx +++ b/src/pages/lunch/roulette.tsx @@ -1,16 +1,12 @@ import Header from '@/components/common/Header'; import LunchRoulette from '@/components/lunch/LunchRoulette'; -import LunchReviewsByRest from '@/components/lunch/review/LunchReviewsByRest'; +import LunchRouletteReviews from '@/components/lunch/roulette/LunchRouletteReviews'; import LunchRoulettePopup from '@/components/lunch/roulette/LunchRoulettePopup'; import { LUNCH_ROULETTE_CONSTANTS } from '@/constants/lunch'; -import useRouletteStore from '@/stores/useRouletteStore'; -import getRandomNumber from '@/utils/getRandomNumber'; import { css } from '@emotion/react'; function Roulette() { - const { isOperated, isAgain, isSelected } = useRouletteStore(); - const { title, menu } = LUNCH_ROULETTE_CONSTANTS; - const randomMenuId = getRandomNumber(menu.max); + const { title } = LUNCH_ROULETTE_CONSTANTS; return ( <> @@ -18,8 +14,7 @@ function Roulette() { - {(isOperated && isAgain && isSelected && ) || - (!isAgain && )} + > ); diff --git a/src/pages/temp.tsx b/src/pages/temp.tsx index 02717a35..d19df6e1 100644 --- a/src/pages/temp.tsx +++ b/src/pages/temp.tsx @@ -6,7 +6,7 @@ import RadioBtn from '@/components/common/RadioBtnBox'; import InvitationFindRoadBtn from '@/components/invitation/view/InvitationFindRoadBtn'; import CheckBox from '@/components/common/CheckBox'; import BottomSheet from '@/components/common/BottomSheet'; -import useBottomSheetStore from '@/stores/useBottomSheetStore'; +import useBottomSheetStore from '@/stores/common/useBottomSheetStore'; import Bnb from '@/components/common/Bnb'; function Temp() { diff --git a/src/stores/useAlertStore.ts b/src/stores/common/useAlertStore.ts similarity index 59% rename from src/stores/useAlertStore.ts rename to src/stores/common/useAlertStore.ts index e5264c23..dac1a75d 100644 --- a/src/stores/useAlertStore.ts +++ b/src/stores/common/useAlertStore.ts @@ -6,15 +6,16 @@ const initialAlertState = { isOpen: false, title: null, content: null, + onClick: () => {}, }; const useAlertStore = create()((set) => ({ alertState: initialAlertState, - openAlert: (title, content) => { - set({ alertState: { isOpen: true, title, content } }); + openAlert: (title, content, onClick) => { + set({ alertState: { isOpen: true, title, content, onClick } }); }, - closeAlert: () => { - set({ alertState: initialAlertState }); + closeAlert: (onClick) => { + set({ alertState: { ...initialAlertState, onClick } }); }, })); diff --git a/src/stores/useBottomSheetStore.ts b/src/stores/common/useBottomSheetStore.ts similarity index 100% rename from src/stores/useBottomSheetStore.ts rename to src/stores/common/useBottomSheetStore.ts diff --git a/src/stores/useModalStore.ts b/src/stores/common/useModalStore.ts similarity index 100% rename from src/stores/useModalStore.ts rename to src/stores/common/useModalStore.ts diff --git a/src/stores/usePagesStore.ts b/src/stores/common/usePagesStore.ts similarity index 100% rename from src/stores/usePagesStore.ts rename to src/stores/common/usePagesStore.ts diff --git a/src/stores/useSaveStore.ts b/src/stores/common/useSaveStore.ts similarity index 79% rename from src/stores/useSaveStore.ts rename to src/stores/common/useSaveStore.ts index dc7fc55d..f0266b8b 100644 --- a/src/stores/useSaveStore.ts +++ b/src/stores/common/useSaveStore.ts @@ -13,24 +13,29 @@ type Visit = { visitMsg: boolean; visitMsgText: string; }; +interface Keyword { + id: number; + text: string; +} type SaveStore = { isSave: Save; user: string; visitor: string; - keyword: string[]; + keywordList: Keyword[]; visit: Visit; point: PointData; setIsSavePhotoMsg: () => void; setPoint: (data: PointData) => void; - setKeyword: (data: string) => void; - deleteKeyword: (data: string) => void; + setKeywordList: (data: Keyword) => void; + deleteKeywordList: (id: number) => void; clearIsSave: () => void; setUserToken: (value: string) => void; setVisitorToken: (value: string) => void; setIsSaveVisitMsg: (state: boolean) => void; setVisitMsgText: (text: string) => void; clearVisitMsg: () => void; + clearToken: () => void; }; // 오늘점심 초기값 @@ -61,7 +66,7 @@ const useSaveStore = create()( isSave: initialSaveState, user: initialTokenState.user, visitor: initialTokenState.visitor, - keyword: [], + keywordList: [], visit: initialVisitMsg, point: initialPoint, setIsSavePhotoMsg: () => @@ -69,13 +74,13 @@ const useSaveStore = create()( isSave: { ...pre.isSave, PhotoMsg: true }, })), setPoint: (data) => set((pre) => ({ point: { ...pre.point, ...data } })), - setKeyword: (data) => + setKeywordList: (data) => set((pre) => ({ - keyword: [...pre.keyword, data], + keywordList: [...pre.keywordList, data], })), - deleteKeyword: (data) => - set((pre) => ({ - keyword: [...pre.keyword.filter((value) => value !== data)], + deleteKeywordList: (id) => + set((state) => ({ + keywordList: state.keywordList.filter((value) => value.id !== id), })), clearIsSave: () => { set({ isSave: initialSaveState }); @@ -100,6 +105,11 @@ const useSaveStore = create()( clearVisitMsg: () => { set({ visit: initialVisitMsg }); }, + clearToken: () => + set({ + user: initialTokenState.user, + visitor: initialTokenState.visitor, + }), }), { name: 'user-storage', diff --git a/src/stores/useToggleStore.ts b/src/stores/common/useToggleStore.ts similarity index 100% rename from src/stores/useToggleStore.ts rename to src/stores/common/useToggleStore.ts diff --git a/src/stores/useUserStore.ts b/src/stores/common/useUserStore.ts similarity index 100% rename from src/stores/useUserStore.ts rename to src/stores/common/useUserStore.ts diff --git a/src/stores/useInvitationCreateStore.ts b/src/stores/invitaion/useInvitationCreateStore.ts similarity index 91% rename from src/stores/useInvitationCreateStore.ts rename to src/stores/invitaion/useInvitationCreateStore.ts index c15be31c..007c1d2a 100644 --- a/src/stores/useInvitationCreateStore.ts +++ b/src/stores/invitaion/useInvitationCreateStore.ts @@ -7,7 +7,7 @@ import { export const initialCreateState: PostInvitationContents = { purpose: '', commonPlaceId: null, - officeName: '5층 공용 라운지 (5층 509호)', + officeName: '식스센스 10층 사무실 (10층 1004호)', description: '', startDate: '', endDate: '', diff --git a/src/stores/useInvitationEditStore.ts b/src/stores/invitaion/useInvitationEditStore.ts similarity index 100% rename from src/stores/useInvitationEditStore.ts rename to src/stores/invitaion/useInvitationEditStore.ts diff --git a/src/stores/useInvitationHeaderTitleStore.ts b/src/stores/invitaion/useInvitationHeaderTitleStore.ts similarity index 100% rename from src/stores/useInvitationHeaderTitleStore.ts rename to src/stores/invitaion/useInvitationHeaderTitleStore.ts diff --git a/src/stores/invitaion/useInvitationListStore.ts b/src/stores/invitaion/useInvitationListStore.ts new file mode 100644 index 00000000..4c8cdca6 --- /dev/null +++ b/src/stores/invitaion/useInvitationListStore.ts @@ -0,0 +1,26 @@ +import { create } from 'zustand'; +import { + UserInvitationList, + InvitationListStore, +} from '@/types/user/invitationList'; + +// 테마 초기값 +const initialInvitationListState: UserInvitationList = { + invitationId: 0, + visitorName: '', + visitorCount: 0, + purpose: '', + officeName: '', + startDate: '', + startTime: '', + endTime: '', +}; + +const useInvitationListStore = create()((set) => ({ + invitationList: initialInvitationListState, + setInvitationListeState: (item: UserInvitationList) => { + set({ invitationList: item }); + }, +})); + +export default useInvitationListStore; diff --git a/src/stores/invitaion/useInvitationParkingStore.ts b/src/stores/invitaion/useInvitationParkingStore.ts new file mode 100644 index 00000000..689d4ceb --- /dev/null +++ b/src/stores/invitaion/useInvitationParkingStore.ts @@ -0,0 +1,22 @@ +import { + InvitationParkingStore, + PostInvitationParkingData, +} from '@/types/invitation/api'; +import { create } from 'zustand'; + +export const parkingState: PostInvitationParkingData = { + carNumber: '', +}; + +const useInvitationParkingStore = create((set) => ({ + carNumber: parkingState, + setCarNumber: (number) => { + set(() => ({ + carNumber: { + carNumber: number, + }, + })); + }, +})); + +export default useInvitationParkingStore; diff --git a/src/stores/useThemeStore.ts b/src/stores/invitaion/useInvitationThemeStore.ts similarity index 77% rename from src/stores/useThemeStore.ts rename to src/stores/invitaion/useInvitationThemeStore.ts index 74861d13..3f363390 100644 --- a/src/stores/useThemeStore.ts +++ b/src/stores/invitaion/useInvitationThemeStore.ts @@ -7,7 +7,7 @@ const initialThemeState = { theme: 'default', }; -const useThemeStore = create()((set) => ({ +const useInvitationThemeStore = create()((set) => ({ themeState: initialThemeState, setThemeState: (key, content) => { set((state) => ({ @@ -18,4 +18,4 @@ const useThemeStore = create()((set) => ({ })); }, })); -export default useThemeStore; +export default useInvitationThemeStore; diff --git a/src/stores/invitaion/useInvitationTimeSelectorStore.ts b/src/stores/invitaion/useInvitationTimeSelectorStore.ts new file mode 100644 index 00000000..ce51ed62 --- /dev/null +++ b/src/stores/invitaion/useInvitationTimeSelectorStore.ts @@ -0,0 +1,22 @@ +import { create } from 'zustand'; + +type SelectTimeType = string | JSX.Element; +interface TimeSelectorStoreTypes { + selectTime: SelectTimeType[]; + setSelectTime: (time: SelectTimeType) => void; + clearSelectTime: () => void; +} + +const useInvitaionTimeSelectorStore = create()( + (set) => ({ + selectTime: [], + setSelectTime: (time: SelectTimeType) => { + set((prev) => ({ selectTime: [...prev.selectTime, time].sort() })); // TimeSelector를 순서대로 누르지 않았을 경우 대비하여 데이터 정렬 + }, + clearSelectTime: () => { + set({ selectTime: [] }); + }, + }), +); + +export default useInvitaionTimeSelectorStore; diff --git a/src/stores/useCalendarStore.ts b/src/stores/lunch/useLunchCalendarStore.ts similarity index 90% rename from src/stores/useCalendarStore.ts rename to src/stores/lunch/useLunchCalendarStore.ts index 595149e0..5e8acfcf 100644 --- a/src/stores/useCalendarStore.ts +++ b/src/stores/lunch/useLunchCalendarStore.ts @@ -29,7 +29,7 @@ const initialCalendarState = { year: new Date().getFullYear(), month: new Date().getMonth() + 1, }; -const useCalendarStore = create()((set) => ({ +const useLunchCalendarStore = create()((set) => ({ dateData: initialCalendarState, reviewDetails: [], setReviewDetails: (data) => set({ reviewDetails: data }), @@ -44,4 +44,4 @@ const useCalendarStore = create()((set) => ({ clearDate: () => set({ dateData: initialCalendarState }), })); -export default useCalendarStore; +export default useLunchCalendarStore; diff --git a/src/stores/useReviewStore.ts b/src/stores/lunch/useLunchReviewStore.ts similarity index 85% rename from src/stores/useReviewStore.ts rename to src/stores/lunch/useLunchReviewStore.ts index 4839d387..ac28585b 100644 --- a/src/stores/useReviewStore.ts +++ b/src/stores/lunch/useLunchReviewStore.ts @@ -17,11 +17,11 @@ const initialState: ReviewList = { reviewDescription: '', }; -const useReviewStore = create((set) => ({ +const useLunchReviewStore = create((set) => ({ reviewList: initialState, setReviewList: (item: ReviewList) => { set({ reviewList: item }); }, })); -export default useReviewStore; +export default useLunchReviewStore; diff --git a/src/stores/useRouletteStore.ts b/src/stores/lunch/useLunchRouletteStore.ts similarity index 62% rename from src/stores/useRouletteStore.ts rename to src/stores/lunch/useLunchRouletteStore.ts index b64dc41a..95683b20 100644 --- a/src/stores/useRouletteStore.ts +++ b/src/stores/lunch/useLunchRouletteStore.ts @@ -1,15 +1,17 @@ // 룰렛 가동 시 선택되는 요소들을 관리하는 store import { create } from 'zustand'; -const useRouletteStore = create(() => ({ +const useLunchRouletteStore = create(() => ({ categoryState: '카테고리', // 랜덤 카테고리명 menuState: '메뉴', // 랜덤 메뉴명 - menuIdState: 1, // 메뉴 ID + menuIdState: 5, // 메뉴 ID isLocked: false, // 카테고리 잠금 state isOperated: true, // 가동 완료 여부 state isPressed: false, // 버튼 클릭 state isAgain: false, // 재선택 여부 state - isSelected: false, // 메뉴 결정 여부 state + isSelected: false, // 메뉴 추출 여부 state + isDecided: false, // 메뉴로 결정 여부 state + isCompleted: false, })); -export default useRouletteStore; +export default useLunchRouletteStore; diff --git a/src/stores/useWriteStore.ts b/src/stores/lunch/useLunchWriteStore.ts similarity index 95% rename from src/stores/useWriteStore.ts rename to src/stores/lunch/useLunchWriteStore.ts index 34e1fd9b..3e0e93be 100644 --- a/src/stores/useWriteStore.ts +++ b/src/stores/lunch/useLunchWriteStore.ts @@ -53,7 +53,7 @@ const initialRatingState = { service: 'BAD', }; -const useWriteStore = create()((set) => ({ +const useLunchWriteStore = create()((set) => ({ restaurant: initialState, selectedMenu: initialArray, ratingState: initialRatingState, @@ -82,4 +82,4 @@ const useWriteStore = create()((set) => ({ }, })); -export default useWriteStore; +export default useLunchWriteStore; diff --git a/src/stores/useTimeSelectorStore.ts b/src/stores/useTimeSelectorStore.ts deleted file mode 100644 index 6e384bb0..00000000 --- a/src/stores/useTimeSelectorStore.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { create } from 'zustand'; - -interface TimeSelectorStoreTypes { - selectTime: string | JSX.Element; - setSelectTime: (time: string | JSX.Element) => void; - clearSelectTime: () => void; -} - -const useTimeSelectorStore = create()((set) => ({ - selectTime: '', - setSelectTime: (time: string | JSX.Element) => { - set({ selectTime: time }); - }, - clearSelectTime: () => { - set({ selectTime: '' }); - }, -})); - -export default useTimeSelectorStore; diff --git a/src/styles/font.ts b/src/styles/font.ts index 64b5a363..2a5b11e4 100644 --- a/src/styles/font.ts +++ b/src/styles/font.ts @@ -20,14 +20,9 @@ const yeongdeok = localFont({ variable: '--yeongdeok', }); -const yeongdeokBlueroad = localFont({ - src: '../assets/fonts/YeongdeokBlueroad.ttf', - variable: '--yeongdeokBlueroad', -}); - const dnfBitBit = localFont({ src: '../assets/fonts/DNFBitBit.ttf', variable: '--dnfBitBit', }); -export { pretendard, godo, gwPower, yeongdeok, yeongdeokBlueroad, dnfBitBit }; +export { pretendard, godo, gwPower, yeongdeok, dnfBitBit }; diff --git a/src/styles/theme.ts b/src/styles/theme.ts index 4702799e..4b136bdf 100644 --- a/src/styles/theme.ts +++ b/src/styles/theme.ts @@ -20,7 +20,7 @@ const theme = { greyscale: { grey5: '#F9FAFB', grey10: '#F0F1F3', - grey20: '#D7DCE3', + grey20: '#E9EBED', grey30: '#C3C6CC', grey40: '#96A2AC', grey45: '#D3D3D3', @@ -73,17 +73,22 @@ const theme = { body2_400: '400 normal 15px var(--pretendard)', body3_500: '500 normal 14px var(--pretendard)', body3_400: '400 normal 14px var(--pretendard)', + body3_300: '300 normal 11px var(--pretendard)', body4: '400 normal 12px var(--pretendard)', }, input: { default: '400 normal 10px var(--pretendard)', }, + alert: { + pretendard: '400 normal 15px var(--pretendard)', + godo: '400 normal 16px var(--godoM)', + }, etc: { findRoad: '500 normal 12px var(--pretendard)', userPoint: '500 normal 13px var(--pretendard)', rankingNumber: '400 normal 20px var(--dnfBitBit)', reviewDesc: '400 normal 15px var(--yeongdeok)', - review: '400 normal 16px var(--yeongdeokBlueroad)', + review: '400 normal 16px var(--yeongdeok)', rouletteTitle: '400 normal 24px var(--dnfBitBit)', rouletteContent: '400 normal 20px var(--dnfBitBit)', roulettePopup: '400 normal 24px var(--dnfBitBit)', diff --git a/src/types/common/add.ts b/src/types/common/add.ts index 2097d37a..89309527 100644 --- a/src/types/common/add.ts +++ b/src/types/common/add.ts @@ -1,4 +1,5 @@ export interface AddBtnProps { onClick: (e: React.MouseEvent) => void; isBlue?: boolean; + isDisabled?: boolean; } diff --git a/src/types/common/alert.ts b/src/types/common/alert.ts index 37edc185..91b7774a 100644 --- a/src/types/common/alert.ts +++ b/src/types/common/alert.ts @@ -1,19 +1,17 @@ // useAlertStore.ts export interface AlertStoreTypes { alertState: AlertStateTypes; - openAlert: (title: string, content: string | JSX.Element) => void; - closeAlert: () => void; + openAlert: ( + title: string, + content: string | JSX.Element, + onClick?: () => void, + ) => void; + closeAlert: (onClick?: () => void) => void; } export interface AlertStateTypes { isOpen: boolean; title: string | null; content: string | JSX.Element | null; -} - -// Alert.tsx -export interface AlertProps { - isAlert?: boolean; - content?: string; onClick?: () => void; } diff --git a/src/types/common/input.ts b/src/types/common/input.ts index af426e93..7d83fe5d 100644 --- a/src/types/common/input.ts +++ b/src/types/common/input.ts @@ -15,6 +15,7 @@ export interface InputProps { | React.ChangeEvent, ) => void; name?: string; + type?: string; } export interface InputColorProps { diff --git a/src/types/common/pages.ts b/src/types/common/pages.ts index ddb680db..d8ae0a00 100644 --- a/src/types/common/pages.ts +++ b/src/types/common/pages.ts @@ -5,3 +5,25 @@ export interface PagesStore { goBack: () => void; reset: () => void; } + +export interface ComponentName { + invitation: { + create: { + [key: string]: string; + }; + view: { + [key: string]: string; + }; + }; + lunch: { + calendar: { + [key: string]: string; + }; + detail: { + [key: string]: string; + }; + }; + common: { + [key: string]: string; + }; +} diff --git a/src/types/common/response.ts b/src/types/common/response.ts index fd117e26..bf9772ed 100644 --- a/src/types/common/response.ts +++ b/src/types/common/response.ts @@ -13,6 +13,7 @@ export interface FetchFunction { export interface FetchProps { fetchFn: FetchFunction; + onClick?: () => void; } export interface ErrorProps extends Error { diff --git a/src/types/common/title.ts b/src/types/common/title.ts index 7a4fae28..6191b7bc 100644 --- a/src/types/common/title.ts +++ b/src/types/common/title.ts @@ -2,4 +2,5 @@ export interface TitleProps { title?: string; isMain?: boolean; part: string; + loading?: boolean; } diff --git a/src/types/invitation/api.ts b/src/types/invitation/api.ts index c1d10b97..2250e3d9 100644 --- a/src/types/invitation/api.ts +++ b/src/types/invitation/api.ts @@ -74,6 +74,7 @@ export interface GetVisitationInfoData { hostCompanyName: string; hostContact: string; hostBusinessCardImageUrl: string; + placeType: string; } // 주변 식당 응답 데이터 export interface GetInvitationCarouselData { @@ -147,3 +148,13 @@ export interface PatchInvitationContents { endDate?: Date | string; visitors?: VisitorInfo[]; } + +// 주차 등록 스토어 +export interface InvitationParkingStore { + carNumber: PostInvitationParkingData; + setCarNumber: (carNumber: string) => void; +} + +export interface PostInvitationParkingData { + carNumber: string; +} diff --git a/src/types/invitation/create.ts b/src/types/invitation/create.ts index a277df0a..066fb3bd 100644 --- a/src/types/invitation/create.ts +++ b/src/types/invitation/create.ts @@ -19,11 +19,16 @@ export interface InvitationCreateTexts { [key: string]: string; }; modal: { - [key: string]: - | { - [key: string]: string; - } - | string; + send: { + [key: string]: string; + }; + resend: { + [key: string]: string; + }; + btn: string; + }; + error: { + [key: string]: string; }; checkbox: string; radioBtn: string; @@ -35,10 +40,8 @@ export interface InvitationCreateTexts { // ****************** 초대 목적 ****************** // // ****************** Purpose ****************** // // Invitation Purpose -export interface CategoryInvitation { - [key: string]: { - [key: string]: CommonCategory; - }; +export interface InvitationCategory { + [key: string]: CommonCategory; } // 카테고리 @@ -47,6 +50,13 @@ export interface CommonCategory { title: string; } +// ****************** 초대 목적 ****************** // +// ****************** Purpose ****************** // +// Invitation Preview +export interface InvitationPreviewProps { + onClick: () => void; +} + // ****************** 방문자 ********************* // // ****************** Visitor ****************** // // Invitation Visitors @@ -104,6 +114,10 @@ export interface TimeSlot { export interface TimeSelectorProps { content: string | JSX.Element; status: string; + // timeSlot: TimeSlot[][]; + // selectedStartTime: string; + // selectedEndTime: string; + // onTimeSelectorClick: (time: string, status: string) => void; } export interface TimeSelectorColorProps { diff --git a/src/types/invitation/view.ts b/src/types/invitation/view.ts index 9a68ea1a..aeb429cb 100644 --- a/src/types/invitation/view.ts +++ b/src/types/invitation/view.ts @@ -23,12 +23,22 @@ export interface InvitationInfoThemesProps { } export interface InvitationInfoThemeProps { backgroundImage: string; + backgroundImageBig: string; shadow: string; boxShadow: string; side: string; sideRight: string; icon: string; } + +export interface InvitationBuildingInfoProps { + data: GetVisitationInfoData; +} + +export interface InvitationOfficeInfoProps { + data: GetVisitationInfoData; +} + export interface InvitationInfoContainerProps { data: GetVisitationInfoData; } @@ -60,3 +70,16 @@ export interface InvitationBuildingPublicTransportItemProps { export interface InvitationQrInfoTextProps { data: GetVisitationInfoData; } + +export interface InvitationVisitTipProps { + invitationTip: string; +} + +export interface InvitationOfficeMapProps { + placeType: string; +} + +export interface InvitationOfficeLocationProps { + invitationOfficeName: string; + hostCompanyName: string; +} diff --git a/src/types/lunch/api.ts b/src/types/lunch/api.ts index 6910b76f..bdbe86dd 100644 --- a/src/types/lunch/api.ts +++ b/src/types/lunch/api.ts @@ -30,7 +30,7 @@ export interface GetRestListData { representativeImageUrl: string; address: string; floor: number; - isBuilding: boolean; + inBuilding: boolean; estimatedTime: number; review: string; } diff --git a/src/types/lunch/calendar.ts b/src/types/lunch/calendar.ts index 271ade32..e9b7b292 100644 --- a/src/types/lunch/calendar.ts +++ b/src/types/lunch/calendar.ts @@ -37,6 +37,7 @@ export interface MenuDataProps { // 컴포넌트 타입 export interface LunchCalendarListItemProps { + id?: number; type: string; content?: string; item?: MenuData; @@ -48,6 +49,10 @@ export interface LunchCalendarListItemProps { export interface LunchCalendarRatingBtnProps { title: string; + isGood: number; + isBad: number; + setIsGood: React.Dispatch>; + setIsBad: React.Dispatch>; } export interface LunchCalendarReviewCategoryProps { diff --git a/src/types/lunch/reviewList.ts b/src/types/lunch/reviewList.ts index 74ab7495..9fe09a79 100644 --- a/src/types/lunch/reviewList.ts +++ b/src/types/lunch/reviewList.ts @@ -1,3 +1,5 @@ +import { GetRestListData } from '@/types/lunch/api'; + export interface ReviewList { restaurantName: string; restaurantId: number; @@ -23,3 +25,7 @@ export interface LunchReviewProps extends ReviewList { isRow?: boolean; noPad?: boolean; } + +export interface LunchRestListProps { + onClick: (item: GetRestListData) => void; +} diff --git a/src/types/user/invitationList.ts b/src/types/user/invitationList.ts index 8bdf137e..98419bc6 100644 --- a/src/types/user/invitationList.ts +++ b/src/types/user/invitationList.ts @@ -10,3 +10,18 @@ export interface UserInvitationListItemProps { endTime: string; }; } +export interface UserInvitationList { + invitationId: number; + visitorName: string; + visitorCount: number; + purpose: string; + officeName: string; + startDate: string; + startTime: string; + endTime: string; +} + +export interface InvitationListStore { + invitationList: UserInvitationList; + setInvitationListeState: (item: UserInvitationList) => void; +} diff --git a/src/utils/createTimeSlots.ts b/src/utils/createTimeSlots.ts index 5401608c..e1078810 100644 --- a/src/utils/createTimeSlots.ts +++ b/src/utils/createTimeSlots.ts @@ -1,8 +1,10 @@ import CREATE_TEXTS from '@/constants/invitation/createTexts'; -// import createTimeSlot from './createTimeSlot'; // 09:00 ~ 18:00의 건물 운영 시간 타임 슬롯을 담는 유틸 함수 (우선 모두 disabled) -const createTimeSlots = (commonTimes: string[]) => { +const createTimeSlots = ( + commonTimes: string[], + commonPlaceId: number | null, +) => { // commonTimes // ['12:30:00', '15:00:00', '17:30:00'] @@ -21,17 +23,28 @@ const createTimeSlots = (commonTimes: string[]) => { closeTime.setHours(timeSelector.endHour, 0, 0, 0); while (openTime <= closeTime) { + // 오전일 경우 if (openTime.getHours() < 12) { - // Mon Oct 02 2023 15:18:25 GMT+0900 (한국 표준시) - const time = String(openTime).split(' ')[4].slice(0, 5); - // console.log(time); - const status = commonTimes.includes(time) ? 'abled' : 'disabled'; - amTimeSlots.push({ time, status }); - } else { - const time = String(openTime).split(' ')[4].slice(0, 5); - // console.log(time); - const status = commonTimes.includes(time) ? 'abled' : 'disabled'; - pmTimeSlots.push({ time, status }); + // 재직 중인 사무실을 선택하고, 공통 시간이 없을 경우에는 모든 타임 셀렉터 활성화 + if (commonPlaceId === null && commonTimes.length === 0) { + const time = String(openTime).split(' ')[4].slice(0, 5); + amTimeSlots.push({ time, status: 'abled' }); + } else { + const time = String(openTime).split(' ')[4].slice(0, 5); + const status = commonTimes.includes(time) ? 'abled' : 'disabled'; + amTimeSlots.push({ time, status }); + } + // 오후일 경우 + } else if (openTime.getHours() >= 12) { + if (commonPlaceId === null && commonTimes.length === 0) { + // Mon Oct 02 2023 15:18:25 GMT+0900 (한국 표준시) + const time = String(openTime).split(' ')[4].slice(0, 5); + pmTimeSlots.push({ time, status: 'abled' }); + } else { + const time = String(openTime).split(' ')[4].slice(0, 5); + const status = commonTimes.includes(time) ? 'abled' : 'disabled'; + pmTimeSlots.push({ time, status }); + } } // 30분씩 증가 diff --git a/src/utils/getCommonTimeList.ts b/src/utils/getCommonTimeList.ts index 2e7db617..60666ff8 100644 --- a/src/utils/getCommonTimeList.ts +++ b/src/utils/getCommonTimeList.ts @@ -1,8 +1,25 @@ import { GetInvitationTimeListData } from '@/types/invitation/api'; -// [{…}, {…}] +// 공통으로 예약 가능한 시간을 리턴하는 함수 +// timeList: [{…}, {…}] // { date: '2023-10-20', availableTimes: ['12:30:00', '15:00:00', '17:30:00'] } -const getCommonTimes = (timeList: GetInvitationTimeListData[]) => { +const getCommonTimes = ( + startDate: Date, + endDate: Date, + timeList: GetInvitationTimeListData[], +) => { + // 두 날짜 사이의 밀리초 수 계산 + const countTimes = Math.abs(endDate.getTime() - startDate.getTime()); + // 밀리초를 일로 변환 (두 날짜를 포함하는 총 일수) + const countDays = Math.ceil(countTimes / (1000 * 60 * 60 * 24)) + 1; + + // 예약 가능한 API 응답값의 길이가 startDate ~ endDate 기간과 동일하지 않을 경우 + // 모든 날짜에 동일한 시간이 있다고 보기 어려우므로 빈 배열 리턴 + if (countDays !== timeList.length) { + return []; + } + + // startDate ~ endDate 기간만큼 데이터가 응답됐을 경우 const timeCounts: Record = {}; timeList.forEach((item: GetInvitationTimeListData) => { diff --git a/src/utils/parseDate.ts b/src/utils/parseDate.ts index ed2ffdda..2f4dcb5e 100644 --- a/src/utils/parseDate.ts +++ b/src/utils/parseDate.ts @@ -1,5 +1,12 @@ -// 선택한 값에 30분을 더한 시간 출력 +// 선택한 값에 30분을 더한 시간 출력 함수 const parseDate = (startTime: string) => { + // startTime: "00:00" + + // 시간 데이터가 안 들어올 경우 + if (!startTime) { + return ''; + } + const [hour, minute] = startTime.split(':'); const hourInt = parseInt(hour, 10);
+ + + + + + + +
+ + + + + + + + +
+ + + +
+ + + + + +
{text}
{title}
{address}
주소복사
{testText.officeName}사무실은
{hostCompanyName}사무실은
- {testText.officeLocation}에 있어요 + {invitationOfficeName}에 있어요
방문 TIP
{INVITATION_CAROUSEL_TEXTS.parking.upParking}
{INVITATION_CAROUSEL_TEXTS.parking.doneParking}
{buildingName}
{subTitle.review}
{value.reviewTitle}
{content}
테리타워에서 {time}분
+ {buildingName}에서 {time}분 +
{item?.menuName}
0/5
{previews.length}/5
{card.text2}
{card.text3}
{subTitle.photoReview}