+
{
+ handleTab("일정 채우기");
+ setCurrentProgress(4);
+ }}
+ >
);
diff --git a/src/create-schedule/components/FinishWriting.tsx b/src/create-schedule/components/FinishWriting.tsx
index e928e653..5525a0db 100644
--- a/src/create-schedule/components/FinishWriting.tsx
+++ b/src/create-schedule/components/FinishWriting.tsx
@@ -1,28 +1,51 @@
-import { useState } from "react";
+import { FINISH_WRITING_TAG } from "@create-schedule/constants";
+import { useEffect, useState } from "react";
import MenuContent from "./MenuContent";
import MenuContentContainer from "./MenuContentContainer";
import SideBarMenuBox from "./SideBarMenuBox";
-const FinishWriting = () => {
- const boxTitle = "작성 마무리";
+interface FinishWritingProps {
+ currentProgress: number;
+ currentTab: string;
+ handleTab: (value: string) => void;
+}
+
+const FinishWriting = ({
+ currentProgress,
+ currentTab,
+ handleTab,
+}: FinishWritingProps) => {
const [isOpen, setIsOpen] = useState(false);
const handleToggle = () => {
setIsOpen((prev) => !prev);
};
+ useEffect(() => {
+ if (currentProgress === 5) {
+ setIsOpen(true);
+ }
+ }, [currentProgress]);
+
return (
<>
{isOpen && (
-
-
+ {FINISH_WRITING_TAG.map((title) => (
+
+ ))}
)}
>
diff --git a/src/create-schedule/components/LocationModal.tsx b/src/create-schedule/components/LocationModal.tsx
new file mode 100644
index 00000000..351de989
--- /dev/null
+++ b/src/create-schedule/components/LocationModal.tsx
@@ -0,0 +1,79 @@
+import { useState } from "react";
+import { LOCATION } from "@shared/constants";
+import { LocationType } from "@shared/types";
+
+interface LocationModalProps {
+ callType: "first" | "second";
+ handleLocation: (value: string) => void;
+ firstLocation?: string;
+}
+
+const LocationModal = ({
+ callType,
+ handleLocation,
+ firstLocation,
+}: LocationModalProps) => {
+ const [clickedCity, setClickedCity] = useState("");
+
+ const onClick = (index: number) => {
+ if (callType === "first") {
+ setClickedCity(Object.keys(LOCATION)[index]);
+ } else if (firstLocation) {
+ setClickedCity(LOCATION[firstLocation as keyof LocationType][index]);
+ }
+ };
+
+ return (
+ <>
+
+ {callType === "first"
+ ? Object.keys(LOCATION).map((location, index) => (
+
+
onClick(index)}
+ >
+ {location}
+
+
+ ))
+ : firstLocation &&
+ LOCATION[firstLocation as keyof LocationType].map(
+ (location, index) => (
+
+
onClick(index)}
+ >
+ {location}
+
+
+ ),
+ )}
+
+
+
+
+ >
+ );
+};
+
+export default LocationModal;
diff --git a/src/create-schedule/components/MenuContent.tsx b/src/create-schedule/components/MenuContent.tsx
index a3d6b9ee..19ac186b 100644
--- a/src/create-schedule/components/MenuContent.tsx
+++ b/src/create-schedule/components/MenuContent.tsx
@@ -1,24 +1,32 @@
import { useSetRecoilState } from "recoil";
-import { currentPageName } from "@shared/recoil";
-import { CurrentPageType } from "@shared/types";
+import { currentScheduleProgress } from "@shared/recoil";
interface MenuContentProps {
title: string;
- boxTitle: CurrentPageType;
- isClicked?: boolean;
+ targetProgress: number;
+ currentTab: string;
+ handleTab: (value: string) => void;
}
-const MenuContent = ({ title, boxTitle, isClicked }: MenuContentProps) => {
- const setCurrentPage = useSetRecoilState(currentPageName);
+const MenuContent = ({
+ title,
+ targetProgress,
+ currentTab,
+ handleTab,
+}: MenuContentProps) => {
+ const setCurrentProgress = useSetRecoilState(currentScheduleProgress);
return (
setCurrentPage(boxTitle)}
+ onClick={() => {
+ handleTab(title);
+ setCurrentProgress(targetProgress);
+ }}
>
- {title}
+
{title}
);
};
diff --git a/src/create-schedule/components/PageContent.tsx b/src/create-schedule/components/PageContent.tsx
index 7e6226b6..4dea7c8c 100644
--- a/src/create-schedule/components/PageContent.tsx
+++ b/src/create-schedule/components/PageContent.tsx
@@ -1,26 +1,33 @@
import { SUBTITLE, TITLE } from "@create-schedule/constants";
-import { useRecoilValue } from "recoil";
-import { currentProgress } from "@shared/recoil";
+import { TemplateSchedule, TemporarySchedule } from "@shared/types";
import PlanDefaultInfo from "./PlanDefaultInfo";
import Remains from "./Remains";
import ScheduleTagTemplate from "./ScheduleTagTemplate";
import Title from "./Title";
-const PageContent = () => {
- const current = useRecoilValue(currentProgress);
+interface PageContentProps {
+ currentProgress: number;
+ temporary: TemporarySchedule[];
+ templates: TemplateSchedule[];
+}
+const PageContent = ({
+ currentProgress,
+ temporary,
+ templates,
+}: PageContentProps) => {
return (
<>
- {current === 1 && (
+ {currentProgress === 1 && (
<>
-
+
>
)}
- {current === 2 && (
+ {currentProgress === 2 && (
)}
- {current === 3 && (
+ {currentProgress === 3 && (
-
+
)}
>
diff --git a/src/create-schedule/components/PlanContent.tsx b/src/create-schedule/components/PlanContent.tsx
index ddd806ed..071babcd 100644
--- a/src/create-schedule/components/PlanContent.tsx
+++ b/src/create-schedule/components/PlanContent.tsx
@@ -1,11 +1,34 @@
+import { useEffect } from "react";
+import { useRecoilState } from "recoil";
+import { currentScheduleProgress } from "@shared/recoil";
+import { TemplateSchedule, TemporarySchedule } from "@shared/types";
import CurrentPage from "./CurrentPage";
import PageContent from "./PageContent";
-const PlanContent = () => {
+interface PlanContentProps {
+ temporary: TemporarySchedule[];
+ templates: TemplateSchedule[];
+}
+
+const PlanContent = ({ temporary, templates }: PlanContentProps) => {
+ const [currentProgress, setCurrentProgress] = useRecoilState(
+ currentScheduleProgress,
+ );
+
+ useEffect(() => {
+ if (temporary.length === 0 && currentProgress !== 2) {
+ setCurrentProgress(2);
+ }
+ }, [temporary]);
+
return (
);
};
diff --git a/src/create-schedule/components/PlanSideBar.tsx b/src/create-schedule/components/PlanSideBar.tsx
index 235d45bd..2cce2176 100644
--- a/src/create-schedule/components/PlanSideBar.tsx
+++ b/src/create-schedule/components/PlanSideBar.tsx
@@ -1,3 +1,11 @@
+import {
+ BASIC_INFO_TAG,
+ FINISH_WRITING_TAG,
+ TAG_N_TEMPLATE_TAG,
+} from "@create-schedule/constants";
+import { useEffect, useState } from "react";
+import { useRecoilValue } from "recoil";
+import { currentScheduleProgress } from "@shared/recoil";
import BasicInfo from "./BasicInfo";
import FillPlan from "./FillPlan";
import FinishWriting from "./FinishWriting";
@@ -5,13 +13,48 @@ import SideBarIntro from "./SideBarIntro";
import TagNTemplate from "./TagNTemplate";
const PlanSideBar = () => {
+ const currentProgress = useRecoilValue(currentScheduleProgress);
+ const [currentTab, setCurrentTab] = useState("일정 제목 입력");
+
+ const handleTab = (value: string) => {
+ setCurrentTab(value);
+ };
+
+ useEffect(() => {
+ switch (currentProgress) {
+ case 2:
+ if (BASIC_INFO_TAG.includes(currentTab)) return;
+ return setCurrentTab("일정 제목 입력");
+ case 3:
+ if (TAG_N_TEMPLATE_TAG.includes(currentTab)) return;
+ return setCurrentTab("태그");
+ case 5:
+ if (FINISH_WRITING_TAG.includes(currentTab)) return;
+ return setCurrentTab("공개범위 설정");
+ default:
+ return setCurrentTab("");
+ }
+ }, [currentProgress, currentTab]);
+
return (
-
-
-
-
+
+
+
+
);
};
diff --git a/src/create-schedule/components/PlanTitleInput.tsx b/src/create-schedule/components/PlanTitleInput.tsx
index c1d294d7..b3a29f51 100644
--- a/src/create-schedule/components/PlanTitleInput.tsx
+++ b/src/create-schedule/components/PlanTitleInput.tsx
@@ -12,13 +12,14 @@ const PlanTitleInput = () => {
};
return (
-
+
handleTitle(value)}
/>
diff --git a/src/create-schedule/components/RemainContent.tsx b/src/create-schedule/components/RemainContent.tsx
index fdeec68b..68ddcc6e 100644
--- a/src/create-schedule/components/RemainContent.tsx
+++ b/src/create-schedule/components/RemainContent.tsx
@@ -1,32 +1,13 @@
import React from "react";
import { ScheduleCard } from "@shared/components";
+import { TemporarySchedule } from "@shared/types";
-const RemainContent = () => {
- const content = [
- {
- id: 1,
- imageSrc: "image",
- title: "베이커리 빵지순례",
- position: "서울시 연남동",
- createdAt: "23.10.23",
- },
- {
- id: 2,
- imageSrc: "image",
- title: "베이커리 빵지순례",
- position: "서울시 연남동",
- createdAt: "23.10.24",
- },
- {
- id: 3,
- imageSrc: "image",
- title: "베이커리 빵지순례",
- position: "서울시 연남동",
- createdAt: "23.10.25",
- },
- ];
+interface RemainContentProps {
+ temporary: TemporarySchedule[];
+}
- return
;
+const RemainContent = ({ temporary }: RemainContentProps) => {
+ return
;
};
export default RemainContent;
diff --git a/src/create-schedule/components/Remains.tsx b/src/create-schedule/components/Remains.tsx
index 4eedcc42..da1c6840 100644
--- a/src/create-schedule/components/Remains.tsx
+++ b/src/create-schedule/components/Remains.tsx
@@ -1,13 +1,17 @@
-import Continue from "./Continue";
+import { TemporarySchedule } from "@shared/types";
import RemainContent from "./RemainContent";
-const Remains = () => {
+interface RemainsProps {
+ temporary: TemporarySchedule[];
+}
+
+const Remains = ({ temporary }: RemainsProps) => {
return (
);
};
diff --git a/src/create-schedule/components/ScheduleNextButton.tsx b/src/create-schedule/components/ScheduleNextButton.tsx
index d512869c..2bece306 100644
--- a/src/create-schedule/components/ScheduleNextButton.tsx
+++ b/src/create-schedule/components/ScheduleNextButton.tsx
@@ -1,6 +1,8 @@
+import { postBasicInfo, setButtonDisabled } from "@create-schedule/util";
+import { useMemo } from "react";
import { useRecoilValue, useSetRecoilState } from "recoil";
import { useModal } from "@shared/hook";
-import { currentProgress, scheduleAnswers } from "@shared/recoil";
+import { currentScheduleProgress, scheduleAnswers } from "@shared/recoil";
interface ScheduleNextButtonProps {
value: string;
@@ -10,11 +12,12 @@ interface ScheduleNextButtonProps {
const ScheduleNextButton = ({ value, callType }: ScheduleNextButtonProps) => {
const { openAlert } = useModal();
const answer = useRecoilValue(scheduleAnswers);
- const setCurrentProgress = useSetRecoilState(currentProgress);
+ const setCurrentProgress = useSetRecoilState(currentScheduleProgress);
+ const disabled = useMemo(() => setButtonDisabled(callType, answer), [answer]);
const handleInputCheck = () => {
- const startDate = parseInt(answer.startedAt.replace(/\./g, ""));
- const endDate = parseInt(answer.endedAt.replace(/\./g, ""));
+ const startDate = parseInt(answer.startAt.replace(/\./g, ""));
+ const endDate = parseInt(answer.endAt.replace(/\./g, ""));
if (endDate - startDate < 0) {
openAlert({
@@ -28,9 +31,19 @@ const ScheduleNextButton = ({ value, callType }: ScheduleNextButtonProps) => {
return true;
};
- const handleCurrentProgress = () => {
+ const handleCurrentProgress = async () => {
if (callType === "basicInfo" && handleInputCheck()) {
- setCurrentProgress((prev) => prev + 1);
+ try {
+ const res = await postBasicInfo(answer);
+
+ if (res) {
+ sessionStorage.setItem("postId", res.data.id);
+ setCurrentProgress((prev) => prev + 1);
+ }
+ } catch (error) {
+ console.log(error);
+ return;
+ }
} else if (callType === "template") {
setCurrentProgress((prev) => prev + 1);
}
@@ -39,13 +52,20 @@ const ScheduleNextButton = ({ value, callType }: ScheduleNextButtonProps) => {
return (
<>
- 언제든 수정할 수 있습니다
+ {callType === "basicInfo" && disabled
+ ? "기본정보는 반드시 입력해주세요"
+ : "언제든 수정할 수 있습니다"}
>
);
diff --git a/src/create-schedule/components/ScheduleTagInput.tsx b/src/create-schedule/components/ScheduleTagInput.tsx
index c697bc04..c95b0a8a 100644
--- a/src/create-schedule/components/ScheduleTagInput.tsx
+++ b/src/create-schedule/components/ScheduleTagInput.tsx
@@ -8,7 +8,10 @@ const ScheduleTagInput = () => {
const { tag } = useRecoilValue(scheduleAnswers);
return (
-
+
diff --git a/src/create-schedule/components/ScheduleTagTemplate.tsx b/src/create-schedule/components/ScheduleTagTemplate.tsx
index f0847de7..ce58eab9 100644
--- a/src/create-schedule/components/ScheduleTagTemplate.tsx
+++ b/src/create-schedule/components/ScheduleTagTemplate.tsx
@@ -1,12 +1,16 @@
import { SCHEDULE_TITLE } from "@create-schedule/constants";
+import { TemplateSchedule } from "@shared/types";
import ScheduleNextButton from "./ScheduleNextButton";
import ScheduleTagInput from "./ScheduleTagInput";
import ScheduleTitle from "./ScheduleTitle";
import TagRecommend from "./TagRecommend";
-import TemplateButton from "./TemplateButton";
import TemplateRecommend from "./TemplateRecommend";
-const ScheduleTagTemplate = () => {
+interface ScheduleTagTemplateProps {
+ templates: TemplateSchedule[];
+}
+
+const ScheduleTagTemplate = ({ templates }: ScheduleTagTemplateProps) => {
return (
<>
@@ -14,7 +18,7 @@ const ScheduleTagTemplate = () => {
-
+
diff --git a/src/create-schedule/components/SelectCity.tsx b/src/create-schedule/components/SelectCity.tsx
index c4f33543..2a7bf038 100644
--- a/src/create-schedule/components/SelectCity.tsx
+++ b/src/create-schedule/components/SelectCity.tsx
@@ -4,15 +4,15 @@ import ScheduleTitle from "./ScheduleTitle";
const SelectCity = () => {
return (
-
+
-
+
-
+
);
};
diff --git a/src/create-schedule/components/SelectDate.tsx b/src/create-schedule/components/SelectDate.tsx
index ff6e34bf..08c70c7e 100644
--- a/src/create-schedule/components/SelectDate.tsx
+++ b/src/create-schedule/components/SelectDate.tsx
@@ -4,7 +4,7 @@ import ScheduleTitle from "./ScheduleTitle";
const SelectDate = () => {
return (
-
+
{
/>
diff --git a/src/create-schedule/components/SelectMainImage.tsx b/src/create-schedule/components/SelectMainImage.tsx
index 2c014267..a02da45a 100644
--- a/src/create-schedule/components/SelectMainImage.tsx
+++ b/src/create-schedule/components/SelectMainImage.tsx
@@ -1,38 +1,58 @@
+import axios from "axios";
import { ThumbnailSelectorProps } from "modalContent/ThumbnailSelector";
import Image from "next/image";
-import { useSetRecoilState } from "recoil";
+import { useRecoilState } from "recoil";
import { useModal } from "@shared/hook";
import { scheduleAnswers } from "@shared/recoil";
const SelectMainImage = () => {
- const setImageSrc = useSetRecoilState(scheduleAnswers);
+ const [{ thumbnail }, setThumbnail] = useRecoilState(scheduleAnswers);
const { openModal } = useModal();
+ const getImage = async (id: string) => {
+ try {
+ const image = await axios.get(`https://api.pexels.com/v1/photos/${id}`, {
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: process.env.NEXT_PUBLIC_IMAGE_API_KEY,
+ },
+ });
+ setThumbnail((prev) => ({ ...prev, thumbnail: image.data.src.large }));
+ } catch (error) {
+ // TODO: Error handling
+ console.log(error);
+ }
+ };
+
const handleModal = () => {
openModal
({
contentId: "thumbnailSelector",
isHeaderCloseBtn: true,
okCallback: (id: string) => {
- setImageSrc((prev) => ({ ...prev, imageSrc: id }));
+ getImage(id);
},
});
};
return (
-
+
-
- 이미지 선택하기
-
+ {!thumbnail && (
+
+ 이미지 선택하기
+
+ )}
);
diff --git a/src/create-schedule/components/SideBarMenuBox.tsx b/src/create-schedule/components/SideBarMenuBox.tsx
index 75f5a43d..991b3218 100644
--- a/src/create-schedule/components/SideBarMenuBox.tsx
+++ b/src/create-schedule/components/SideBarMenuBox.tsx
@@ -14,16 +14,15 @@ const SideBarMenuBox = ({
handleToggle,
}: SideBarMenuBoxProps) => {
return (
-
+
{title}
{isAccordion && (
- // TODO: rotate image, onclick
-
+
{
- const boxTitle = "태그 및 일정 템플릿";
+interface TagNTemplateProps {
+ currentProgress: number;
+ currentTab: string;
+ handleTab: (value: string) => void;
+}
+
+const TagNTemplate = ({
+ currentProgress,
+ currentTab,
+ handleTab,
+}: TagNTemplateProps) => {
const [isOpen, setIsOpen] = useState(false);
const handleToggle = () => {
setIsOpen((prev) => !prev);
};
+ useEffect(() => {
+ if (currentProgress === 3) {
+ setIsOpen(true);
+ }
+ }, [currentProgress]);
+
return (
<>
{isOpen && (
-
-
+ {TAG_N_TEMPLATE_TAG.map((title) => (
+
+ ))}
)}
>
diff --git a/src/create-schedule/components/Template.tsx b/src/create-schedule/components/Template.tsx
index 54bed351..b0a08c53 100644
--- a/src/create-schedule/components/Template.tsx
+++ b/src/create-schedule/components/Template.tsx
@@ -1,8 +1,12 @@
-import { templateContent } from "@create-schedule/constants";
import { ScheduleCard } from "@shared/components";
+import { TemplateSchedule } from "@shared/types";
-const Template = () => {
- return ;
+interface TemplateProps {
+ templates: TemplateSchedule[];
+}
+
+const Template = ({ templates }: TemplateProps) => {
+ return ;
};
export default Template;
diff --git a/src/create-schedule/components/TemplateButton.tsx b/src/create-schedule/components/TemplateButton.tsx
index 9b593c7c..0445faf4 100644
--- a/src/create-schedule/components/TemplateButton.tsx
+++ b/src/create-schedule/components/TemplateButton.tsx
@@ -1,5 +1,5 @@
import { useSetRecoilState } from "recoil";
-import { currentProgress } from "@shared/recoil";
+import { currentScheduleProgress } from "@shared/recoil";
import MakeScheduleButton from "./MakeScheduleButton";
interface TemplateButtonProps {
@@ -7,7 +7,7 @@ interface TemplateButtonProps {
}
const TemplateButton = ({ clickedContent }: TemplateButtonProps) => {
- const setCurrentProgress = useSetRecoilState(currentProgress);
+ const setCurrentProgress = useSetRecoilState(currentScheduleProgress);
const handleCurrentProgress = () => {
setCurrentProgress((prev) => prev + 1);
diff --git a/src/create-schedule/components/TemplateRecommend.tsx b/src/create-schedule/components/TemplateRecommend.tsx
index f11c1d45..dacd6c5b 100644
--- a/src/create-schedule/components/TemplateRecommend.tsx
+++ b/src/create-schedule/components/TemplateRecommend.tsx
@@ -1,16 +1,21 @@
import { SCHEDULE_TITLE } from "@create-schedule/constants";
+import { TemplateSchedule } from "@shared/types";
import ScheduleTitle from "./ScheduleTitle";
import Template from "./Template";
-const TemplateRecommend = () => {
+interface TemplateRecommendProps {
+ templates: TemplateSchedule[];
+}
+
+const TemplateRecommend = ({ templates }: TemplateRecommendProps) => {
return (
- <>
+
-
- >
+
+
);
};
diff --git a/src/create-schedule/components/index.ts b/src/create-schedule/components/index.ts
index 34b8e9f8..ada70af6 100644
--- a/src/create-schedule/components/index.ts
+++ b/src/create-schedule/components/index.ts
@@ -7,6 +7,7 @@ export { default as DateCityHandler } from "./DateCityHandler";
export { default as DateCityInput } from "./DateCityInput";
export { default as FillPlan } from "./FillPlan";
export { default as FinishWriting } from "./FinishWriting";
+export { default as LocationModal } from "./LocationModal";
export { default as MakeScheduleButton } from "./MakeScheduleButton";
export { default as MenuContent } from "./MenuContent";
export { default as MenuContentContainer } from "./MenuContentContainer";
diff --git a/src/create-schedule/constants/index.ts b/src/create-schedule/constants/index.ts
index b9d133e1..d79b3cc6 100644
--- a/src/create-schedule/constants/index.ts
+++ b/src/create-schedule/constants/index.ts
@@ -1,7 +1,7 @@
import { PlanSubTitle, PlanTitle } from "@shared/types";
export const TITLE: PlanTitle = {
- remains: "잠깐, 작성중이던 일정이 있어요",
+ temporary: "잠깐, 작성중이던 일정이 있어요",
nthPlan: (nickname: string, number: number) =>
`${nickname} 님의 ${number}번째 일정`,
tag: "태그 및 일정 템플릿",
@@ -19,7 +19,7 @@ export const SCHEDULE_TITLE = {
planTitle: "일정 제목",
mainImage: "대표 이미지",
date: "일정 시작일 ~ 종료일",
- city: "장소 선택",
+ location: "장소 선택",
tag: "카테고리 태그(#)",
tagRecommend: "이런 태그는 어떤가요?",
templateRecommend: (nickname: string) =>
@@ -30,36 +30,16 @@ export const SCHEDULE_SUBTITLE = {
mainImage:
"Chather 캐쳐 메인, 검색 결과, SNS 광고 등 여러 곳에서 노출할 대표 이미지를 등록해 주세요.",
date: "준비기간 및 모집기간 등 전체 일정을 고려해 설정해 주세요.",
- city: "일정을 수행할 위치를 선택해주세요.",
+ location: "일정을 수행할 위치를 선택해주세요.",
};
-export const templateContent = [
- {
- id: 1,
- imageSrc: "image",
- title: "베이커리 빵지순례",
- position: "서울시 연남동",
- requiredTime: "1일 이내",
- },
- {
- id: 2,
- imageSrc: "image",
- title: "카페에서 함께 공부해요",
- position: "서울시 연남동",
- requiredTime: "2~3일 일정",
- },
- {
- id: 3,
- imageSrc: "image",
- title: "베이커리 빵지순례",
- position: "가로수길",
- requiredTime: "1일 이내",
- },
- {
- id: 4,
- imageSrc: "image",
- title: "호캉스 일정",
- position: "남해",
- requiredTime: "2~3일 일정",
- },
+export const BASIC_INFO_TAG = [
+ "일정 제목 입력",
+ "대표 이미지 설정",
+ "시작일 종료일 설정",
+ "장소 선택",
];
+
+export const TAG_N_TEMPLATE_TAG = ["태그", "일정 템플릿"];
+
+export const FINISH_WRITING_TAG = ["공개범위 설정", "일정 소개"];
diff --git a/src/create-schedule/util/index.ts b/src/create-schedule/util/index.ts
new file mode 100644
index 00000000..3db001f1
--- /dev/null
+++ b/src/create-schedule/util/index.ts
@@ -0,0 +1,51 @@
+import axios from "axios";
+import { CREATE_SCHEDULE_PATH } from "@shared/constants";
+import { ScheduleAnswerType } from "@shared/types";
+
+export const postBasicInfo = async (answer: ScheduleAnswerType) => {
+ if (
+ answer.title &&
+ answer.thumbnail &&
+ answer.startAt &&
+ answer.endAt &&
+ answer.location
+ )
+ try {
+ const res = await axios.post(
+ `${process.env.NEXT_PUBLIC_BASE_URL}/${CREATE_SCHEDULE_PATH.temporary}`,
+ {
+ title: answer.title,
+ thumbnail: answer.thumbnail,
+ location: answer.location,
+ startAt: answer.startAt,
+ endAt: answer.endAt,
+ },
+ { headers: { "Content-Type": "application/json" } },
+ );
+
+ return res;
+ } catch (error) {
+ console.log(error);
+ }
+};
+
+export const setButtonDisabled = (
+ callType: "basicInfo" | "template",
+ answer: ScheduleAnswerType,
+) => {
+ if (callType === "basicInfo") {
+ if (
+ answer.title &&
+ answer.thumbnail &&
+ answer.startAt &&
+ answer.endAt &&
+ answer.location
+ ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+};
diff --git a/src/mock/browser.ts b/src/mock/browser.ts
index f429ff42..5f072eb0 100644
--- a/src/mock/browser.ts
+++ b/src/mock/browser.ts
@@ -1,5 +1,10 @@
import { setupWorker } from "msw/browser";
import { handlers } from "./handlers";
import { myScheduleHandlers } from "./handlers/mySchedule";
+import { basicInfoHandlers } from "./handlers/postBasicInfo";
-export const worker = setupWorker(...handlers, ...myScheduleHandlers);
+export const worker = setupWorker(
+ ...handlers,
+ ...myScheduleHandlers,
+ ...basicInfoHandlers,
+);
diff --git a/src/mock/data/basicInfo.ts b/src/mock/data/basicInfo.ts
new file mode 100644
index 00000000..aa49177c
--- /dev/null
+++ b/src/mock/data/basicInfo.ts
@@ -0,0 +1,3 @@
+export const BasicInfoData = {
+ id: 1,
+};
diff --git a/src/mock/data/template.ts b/src/mock/data/template.ts
new file mode 100644
index 00000000..2dded088
--- /dev/null
+++ b/src/mock/data/template.ts
@@ -0,0 +1,36 @@
+import { TemplateSchedule } from "@shared/types";
+
+export const templateContent: TemplateSchedule[] = [
+ {
+ id: 1,
+ thumbnailUrl: "image",
+ title: "베이커리 빵지순례",
+ location: "서울시 연남동",
+ days: "1일 이내",
+ schedules: [],
+ },
+ {
+ id: 2,
+ thumbnailUrl: "image",
+ title: "카페에서 함께 공부해요",
+ location: "서울시 연남동",
+ days: "2~3일 일정",
+ schedules: [],
+ },
+ {
+ id: 3,
+ thumbnailUrl: "image",
+ title: "베이커리 빵지순례",
+ location: "가로수길",
+ days: "1일 이내",
+ schedules: [],
+ },
+ {
+ id: 4,
+ thumbnailUrl: "image",
+ title: "호캉스 일정",
+ location: "남해",
+ days: "2~3일 일정",
+ schedules: [],
+ },
+];
diff --git a/src/mock/data/temporary.ts b/src/mock/data/temporary.ts
new file mode 100644
index 00000000..bcde07bc
--- /dev/null
+++ b/src/mock/data/temporary.ts
@@ -0,0 +1,25 @@
+import { TemporarySchedule } from "@shared/types";
+
+export const temporaryContent: TemporarySchedule[] = [
+ {
+ id: 1,
+ thumbnailUrl: "image",
+ title: "베이커리 빵지순례",
+ location: "서울시 연남동",
+ createdAt: new Date("2023-10-23"),
+ },
+ {
+ id: 2,
+ thumbnailUrl: "image",
+ title: "베이커리 빵지순례",
+ location: "서울시 연남동",
+ createdAt: new Date("2023-10-24"),
+ },
+ {
+ id: 3,
+ thumbnailUrl: "image",
+ title: "베이커리 빵지순례",
+ location: "서울시 연남동",
+ createdAt: new Date("2023-10-25"),
+ },
+];
diff --git a/src/mock/handlers/getTemplates.ts b/src/mock/handlers/getTemplates.ts
new file mode 100644
index 00000000..13a3e395
--- /dev/null
+++ b/src/mock/handlers/getTemplates.ts
@@ -0,0 +1,15 @@
+import { templateContent } from "mock/data/template";
+import { temporaryContent } from "mock/data/temporary";
+import { http } from "msw";
+import { CREATE_SCHEDULE_PATH } from "@shared/constants";
+
+const BASE_URL = "http://localhost:3000/api";
+
+export const templateHandlers = [
+ http.get(`${BASE_URL}/${CREATE_SCHEDULE_PATH.temporary}`, () => {
+ return new Response(JSON.stringify(temporaryContent));
+ }),
+ http.get(`${BASE_URL}/${CREATE_SCHEDULE_PATH.templates}`, () => {
+ return new Response(JSON.stringify(templateContent));
+ }),
+];
diff --git a/src/mock/handlers/postBasicInfo.ts b/src/mock/handlers/postBasicInfo.ts
new file mode 100644
index 00000000..089acebd
--- /dev/null
+++ b/src/mock/handlers/postBasicInfo.ts
@@ -0,0 +1,11 @@
+import { BasicInfoData } from "mock/data/basicInfo";
+import { http } from "msw";
+import { CREATE_SCHEDULE_PATH } from "@shared/constants";
+
+const BASE_URL = "http://localhost:3000/api";
+
+export const basicInfoHandlers = [
+ http.post(`${BASE_URL}/${CREATE_SCHEDULE_PATH.temporary}`, ({ request }) => {
+ if (request.body) return new Response(JSON.stringify(BasicInfoData));
+ }),
+];
diff --git a/src/mock/server.ts b/src/mock/server.ts
index 7b37f2ac..e90c897e 100644
--- a/src/mock/server.ts
+++ b/src/mock/server.ts
@@ -1,4 +1,5 @@
import { setupServer } from "msw/node";
import { handlers } from "./handlers";
+import { templateHandlers } from "./handlers/getTemplates";
-export const server = setupServer(...handlers);
+export const server = setupServer(...handlers, ...templateHandlers);
diff --git a/src/modalContent/CalendarSelector.tsx b/src/modalContent/CalendarSelector.tsx
index c9153417..92556523 100644
--- a/src/modalContent/CalendarSelector.tsx
+++ b/src/modalContent/CalendarSelector.tsx
@@ -5,7 +5,7 @@ import { useModal } from "@shared/hook";
import { scheduleAnswers } from "@shared/recoil";
interface CalendarSelectorProps {
- type: "startedAt" | "endedAt";
+ type: "startAt" | "endAt";
}
const CalendarSelector = ({ type }: CalendarSelectorProps) => {
diff --git a/src/modalContent/CitySelector.tsx b/src/modalContent/CitySelector.tsx
new file mode 100644
index 00000000..cb06dc2e
--- /dev/null
+++ b/src/modalContent/CitySelector.tsx
@@ -0,0 +1,44 @@
+import { LocationModal } from "@create-schedule/components";
+import { useRecoilState } from "recoil";
+import { useModal } from "@shared/hook";
+import { scheduleAnswers } from "@shared/recoil";
+
+interface CitySelectorProps {
+ callType: "first" | "second";
+}
+
+const CitySelector = ({ callType }: CitySelectorProps) => {
+ const { closeModal } = useModal();
+ const [answer, setAnswer] = useRecoilState(scheduleAnswers);
+
+ const handleLocation = (value: string) => {
+ if (callType === "first") {
+ setAnswer((prev) => ({ ...prev, location: value }));
+ closeModal();
+ return;
+ }
+
+ setAnswer((prev) => ({
+ ...prev,
+ location: `${prev.location.split(" ")[0]} ${value}`,
+ }));
+ closeModal();
+ return;
+ };
+
+ return (
+ <>
+ {callType === "first" ? (
+
+ ) : (
+
+ )}
+ >
+ );
+};
+
+export default CitySelector;
diff --git a/src/modalContent/index.tsx b/src/modalContent/index.tsx
index 769a22e4..cfcda0d7 100644
--- a/src/modalContent/index.tsx
+++ b/src/modalContent/index.tsx
@@ -1,5 +1,6 @@
import { ModalContentId } from "@shared/recoil/modal";
import CalendarSelector from "./CalendarSelector";
+import CitySelector from "./CitySelector";
import RecruitManage, { RecruitManageProps } from "./RecruitManage";
import ThumbnailSelector, { ThumbnailSelectorProps } from "./ThumbnailSelector";
@@ -15,9 +16,13 @@ const ModalContent = (modalProps: ModalContentProps) => {
case "RecruitManage":
return ;
case "calendarSelector_start":
- return ;
+ return ;
case "calendarSelector_end":
- return ;
+ return ;
+ case "citySelector_first":
+ return ;
+ case "citySelector_second":
+ return ;
default:
return <>>;
}
diff --git a/src/shared/components/ScheduleCard.tsx b/src/shared/components/ScheduleCard.tsx
index 729c221f..65e9d1f3 100644
--- a/src/shared/components/ScheduleCard.tsx
+++ b/src/shared/components/ScheduleCard.tsx
@@ -1,19 +1,10 @@
import { Continue, TemplateButton } from "@create-schedule/components";
import { useState } from "react";
-
-// TODO: 일정 타입 지정
-export interface Schedule {
- id: number;
- imageSrc: string;
- title: string;
- position: string;
- createdAt?: string;
- requiredTime?: string;
-}
+import { TemplateSchedule, TemporarySchedule } from "@shared/types";
interface ScheduleCardProps {
- content: Schedule[];
- callType: "remain" | "template";
+ content: TemporarySchedule[] | TemplateSchedule[];
+ callType: "temporary" | "template";
}
const ScheduleCard = ({ content, callType }: ScheduleCardProps) => {
@@ -35,24 +26,26 @@ const ScheduleCard = ({ content, callType }: ScheduleCardProps) => {
onClick={() => handleClick(index)}
>
- {_content.imageSrc}
+ {_content.thumbnailUrl}
{_content.title}
- {_content.position}
+ {_content.location}
{`${
- callType === "remain"
- ? `${_content.createdAt} 작성`
- : `${_content.requiredTime}`
+ callType === "temporary"
+ ? `${(_content as TemporarySchedule).createdAt} 작성` // TODO: Date format handling
+ : `${(_content as TemplateSchedule).days}`
}`}
diff --git a/src/shared/constants/index.ts b/src/shared/constants/index.ts
index d6241175..29c47322 100644
--- a/src/shared/constants/index.ts
+++ b/src/shared/constants/index.ts
@@ -8,3 +8,275 @@ export const KAKAO_LOGOUT_URL = "https://kapi.kakao.com/v1/user/logout";
export const NAVER_LOGOUT_URL = "https://nid.naver.com/nidlogin.logout";
export const DEFAULT_URL = "http://localhost:3000";
+
+export const CREATE_SCHEDULE_PATH = {
+ base: "schedules",
+ temporary: "schedules/temporary",
+ tag: "schedules/tag",
+ templates: "schedules/templates",
+ items: "schedules/items",
+};
+
+export const LOCATION = {
+ 서울특별시: [
+ "강남구",
+ "강동구",
+ "강북구",
+ "강서구",
+ "관악구",
+ "광진구",
+ "구로구",
+ "금천구",
+ "노원구",
+ "도봉구",
+ "동대문구",
+ "동작구",
+ "마포구",
+ "서대문구",
+ "서초구",
+ "성동구",
+ "성북구",
+ "송파구",
+ "양천구",
+ "영등포구",
+ "용산구",
+ "은평구",
+ "종로구",
+ "중구",
+ "중랑구",
+ ],
+ 경기도: [
+ "수원시 장안구",
+ "수원시 권선구",
+ "수원시 팔달구",
+ "수원시 영통구",
+ "성남시 수정구",
+ "성남시 중원구",
+ "성남시 분당구",
+ "의정부시",
+ "안양시 만안구",
+ "안양시 동안구",
+ "부천시",
+ "광명시",
+ "평택시",
+ "동두천시",
+ "안산시 상록구",
+ "안산시 단원구",
+ "고양시 덕양구",
+ "고양시 일산동구",
+ "고양시 일산서구",
+ "과천시",
+ "구리시",
+ "남양주시",
+ "오산시",
+ "시흥시",
+ "군포시",
+ "의왕시",
+ "하남시",
+ "용인시 처인구",
+ "용인시 기흥구",
+ "용인시 수지구",
+ "파주시",
+ "이천시",
+ "안성시",
+ "김포시",
+ "화성시",
+ "광주시",
+ "양주시",
+ "포천시",
+ "여주시",
+ "연천군",
+ "가평군",
+ "양평군",
+ ],
+ 인천광역시: [
+ "계양구",
+ "미추홀구",
+ "남동구",
+ "동구",
+ "부평구",
+ "서구",
+ "연수구",
+ "중구",
+ "강화군",
+ "옹진군",
+ ],
+ 강원특별자치도: [
+ "춘천시",
+ "원주시",
+ "강릉시",
+ "동해시",
+ "태백시",
+ "속초시",
+ "삼척시",
+ "홍천군",
+ "횡성군",
+ "영월군",
+ "평창군",
+ "정선군",
+ "철원군",
+ "화천군",
+ "양구군",
+ "인제군",
+ "고성군",
+ "양양군",
+ ],
+ 충청북도: [
+ "청주시 상당구",
+ "청주시 서원구",
+ "청주시 흥덕구",
+ "청주시 청원구",
+ "충주시",
+ "제천시",
+ "보은군",
+ "옥천군",
+ "영동군",
+ "증평군",
+ "진천군",
+ "괴산군",
+ "음성군",
+ "단양군",
+ ],
+ 충청남도: [
+ "천안시 동남구",
+ "천안시 서북구",
+ "공주시",
+ "보령시",
+ "아산시",
+ "서산시",
+ "논산시",
+ "계룡시",
+ "당진시",
+ "금산군",
+ "부여군",
+ "서천군",
+ "청양군",
+ "홍성군",
+ "예산군",
+ "태안군",
+ ],
+ 대전광역시: ["대덕구", "동구", "서구", "유성구", "중구"],
+ 세종특별자치시: ["세종시"],
+ 전라북도: [
+ "전주시 완산구",
+ "전주시 덕진구",
+ "군산시",
+ "익산시",
+ "정읍시",
+ "남원시",
+ "김제시",
+ "완주군",
+ "진안군",
+ "무주군",
+ "장수군",
+ "임실군",
+ "순창군",
+ "고창군",
+ "부안군",
+ ],
+ 전라남도: [
+ "목포시",
+ "여수시",
+ "순천시",
+ "나주시",
+ "광양시",
+ "담양군",
+ "곡성군",
+ "구례군",
+ "고흥군",
+ "보성군",
+ "화순군",
+ "장흥군",
+ "강진군",
+ "해남군",
+ "영암군",
+ "무안군",
+ "함평군",
+ "영광군",
+ "장성군",
+ "완도군",
+ "진도군",
+ "신안군",
+ ],
+ 광주광역시: ["광산구", "남구", "동구", "북구", "서구"],
+ 경상북도: [
+ "포항시 남구",
+ "포항시 북구",
+ "경주시",
+ "김천시",
+ "안동시",
+ "구미시",
+ "영주시",
+ "영천시",
+ "상주시",
+ "문경시",
+ "경산시",
+ "군위군",
+ "의성군",
+ "청송군",
+ "영양군",
+ "영덕군",
+ "청도군",
+ "고령군",
+ "성주군",
+ "칠곡군",
+ "예천군",
+ "봉화군",
+ "울진군",
+ "울릉군",
+ ],
+ 경상남도: [
+ "창원시 의창구",
+ "창원시 성산구",
+ "창원시 마산합포구",
+ "창원시 마산회원구",
+ "창원시 진해구",
+ "진주시",
+ "통영시",
+ "사천시",
+ "김해시",
+ "밀양시",
+ "거제시",
+ "양산시",
+ "의령군",
+ "함안군",
+ "창녕군",
+ "고성군",
+ "남해군",
+ "하동군",
+ "산청군",
+ "함양군",
+ "거창군",
+ "합천군",
+ ],
+ 부산광역시: [
+ "강서구",
+ "금정구",
+ "남구",
+ "동구",
+ "동래구",
+ "부산진구",
+ "북구",
+ "사상구",
+ "사하구",
+ "서구",
+ "수영구",
+ "연제구",
+ "영도구",
+ "중구",
+ "해운대구",
+ "기장군",
+ ],
+ 대구광역시: [
+ "남구",
+ "달서구",
+ "동구",
+ "북구",
+ "서구",
+ "수성구",
+ "중구",
+ "달성군",
+ ],
+ 울산광역시: ["남구", "동구", "북구", "중구", "울주군"],
+ 제주특별자치도: ["서귀포시", "제주시"],
+};
diff --git a/src/shared/recoil/createSchedule.tsx b/src/shared/recoil/createSchedule.tsx
index 318a3b2c..f5318bb7 100644
--- a/src/shared/recoil/createSchedule.tsx
+++ b/src/shared/recoil/createSchedule.tsx
@@ -1,12 +1,7 @@
import { atom } from "recoil";
-import { CurrentPageType, ScheduleAnswerType } from "@shared/types";
+import { ScheduleAnswerType } from "@shared/types";
-export const currentPageName = atom({
- key: "currentPage",
- default: "작성 중인 일정",
-});
-
-export const currentProgress = atom({
+export const currentScheduleProgress = atom({
key: "currentProgress",
default: 1,
});
@@ -15,10 +10,10 @@ export const scheduleAnswers = atom({
key: "scheduleAnswers",
default: {
title: "",
- imageSrc: "",
- startedAt: "",
- endedAt: "",
- city: "",
+ thumbnail: "",
+ startAt: "",
+ endAt: "",
+ location: "",
tag: [],
},
});
diff --git a/src/shared/recoil/modal.tsx b/src/shared/recoil/modal.tsx
index 892a6219..6388a36a 100644
--- a/src/shared/recoil/modal.tsx
+++ b/src/shared/recoil/modal.tsx
@@ -89,4 +89,6 @@ export type ModalContentId =
| "thumbnailSelector"
| "calendarSelector_start"
| "calendarSelector_end"
- | "RecruitManage";
+ | "RecruitManage"
+ | "citySelector_first"
+ | "citySelector_second";
diff --git a/src/shared/types/index.ts b/src/shared/types/index.ts
index 26e747c7..552e9260 100644
--- a/src/shared/types/index.ts
+++ b/src/shared/types/index.ts
@@ -38,7 +38,7 @@ export type CurrentPageType =
| "작성 마무리";
export interface PlanTitle {
- remains: string;
+ temporary: string;
nthPlan: (nickname: string, number: number) => string;
tag: string;
fill: string;
@@ -53,12 +53,65 @@ export interface PlanSubTitle {
export interface ScheduleAnswerType {
title: string;
- imageSrc: string;
- startedAt: string;
- endedAt: string;
- city: string;
+ thumbnail: string;
+ startAt: string;
+ endAt: string;
+ location: string;
tag: string[];
}
-export type CalendarSelectorType = "startedAt" | "endedAt";
+export type CalendarSelectorType = "startAt" | "endAt";
+
export type LoginType = "kakao" | "naver" | "catcher";
+
+export interface ScheduleCardSection {
+ id: number;
+ thumbnailUrl: string;
+ title: string;
+ location: string;
+}
+
+export interface ScheduleBasicInfo extends ScheduleCardSection {
+ startAt: Date;
+ endAt: Date;
+}
+
+export interface TemporarySchedule extends ScheduleCardSection {
+ createdAt: Date;
+}
+
+export interface TemplateSchedule extends ScheduleCardSection {
+ days: string;
+ schedules: TemplateDetail[];
+}
+
+export interface TemplateDetail {
+ id: number;
+ title: string;
+ category: string;
+ location: string;
+ description: string;
+ color: string;
+ startAt: Date;
+ endAt: Date;
+}
+
+export interface LocationType {
+ 서울특별시: string[];
+ 경기도: string[];
+ 인천광역시: string[];
+ 강원특별자치도: string[];
+ 충청북도: string[];
+ 충청남도: string[];
+ 대전광역시: string[];
+ 세종특별자치시: string[];
+ 전라북도: string[];
+ 전라남도: string[];
+ 광주광역시: string[];
+ 경상북도: string[];
+ 경상남도: string[];
+ 부산광역시: string[];
+ 대구광역시: string[];
+ 울산광역시: string[];
+ 제주특별자치도: string[];
+}