@@ -66,5 +60,5 @@ const EditContent = () => {
export default EditContent;
const postTypeGuard = (obj: { [a: string]: any }, key: string): key is PostValueType => {
- return !!obj[key];
+ return typeof obj[key] !== undefined;
};
diff --git a/app/(route)/(header)/event/[eventId]/edit/_components/InitButton.tsx b/app/(route)/(header)/event/[eventId]/edit/_components/InitButton.tsx
new file mode 100644
index 00000000..a32d3200
--- /dev/null
+++ b/app/(route)/(header)/event/[eventId]/edit/_components/InitButton.tsx
@@ -0,0 +1,13 @@
+interface Props {
+ onClick?: () => void;
+}
+
+const InitButton = ({ onClick }: Props) => {
+ return (
+
+ );
+};
+
+export default InitButton;
diff --git a/app/(route)/(header)/event/[eventId]/edit/page.tsx b/app/(route)/(header)/event/[eventId]/edit/page.tsx
index 68253369..3ed89a0f 100644
--- a/app/(route)/(header)/event/[eventId]/edit/page.tsx
+++ b/app/(route)/(header)/event/[eventId]/edit/page.tsx
@@ -4,32 +4,38 @@ import { PostType } from "@/(route)/post/page";
import { instance } from "app/_api/api";
import { format } from "date-fns";
import { useParams } from "next/navigation";
-import { useEffect, useState } from "react";
+import { Suspense, useEffect, useState } from "react";
import GenericFormProvider from "@/components/GenericFormProvider";
+import { useAuth } from "@/hooks/useAuth";
+import { useStore } from "@/store/index";
import EditContent from "./_components/EditContent";
let INITIAL_DATA: PostType;
const Edit = () => {
+ // const session = useAuth("/signin");
const { eventId } = useParams();
const [init, setInit] = useState(false);
+ const { setWriterId } = useStore((state) => ({ setWriterId: state.setWriterId }));
useEffect(() => {
const fetchData = async () => {
const data = await instance.get(`/event/${eventId}`);
- const { address, addressDetail, description, endDate, startDate, eventImages, eventTags, eventUrl, eventType, organizerSns, placeName, snsType, targetArtists } = data;
+ const { address, addressDetail, description, endDate, startDate, eventImages, eventTags, eventUrl, eventType, organizerSns, placeName, snsType, targetArtists, userId } =
+ data;
const artistNames: string[] = targetArtists.map(({ artistName }: { artistName: string }) => artistName);
const artists = targetArtists.map(({ artistId }: { artistId: string }) => artistId);
const tags = eventTags.map(({ tagName }: { tagName: string }) => tagName);
const imgList = eventImages.map(({ imageUrl }: { imageUrl: string }) => imageUrl);
+ setWriterId(userId);
INITIAL_DATA = {
placeName,
eventType,
- groupId: targetArtists[0].groupId,
- groupName: targetArtists[0].groupName,
+ groupId: targetArtists[0].groupId || "",
+ groupName: targetArtists[0].groupId ? targetArtists[0].groupName : targetArtists[0].artistName,
artists,
- artistNames,
+ artistNames: targetArtists[0].groupId ? artistNames : [],
startDate: format(startDate, "yyyy.MM.dd"),
endDate: format(endDate, "yyyy.MM.dd"),
address,
@@ -49,7 +55,7 @@ const Edit = () => {
return (
{init && (
-
+
)}
diff --git a/app/(route)/post/_components/DetailInfo.tsx b/app/(route)/post/_components/DetailInfo.tsx
index df13cf31..c962e4a8 100644
--- a/app/(route)/post/_components/DetailInfo.tsx
+++ b/app/(route)/post/_components/DetailInfo.tsx
@@ -19,7 +19,9 @@ const DetailInfo = () => {
-
100}>작성 완료
+
100}>
+ 작성 완료
+
);
};
diff --git a/app/(route)/post/_components/_inputs/DetailInput.tsx b/app/(route)/post/_components/_inputs/DetailInput.tsx
index d650100e..224af18a 100644
--- a/app/(route)/post/_components/_inputs/DetailInput.tsx
+++ b/app/(route)/post/_components/_inputs/DetailInput.tsx
@@ -1,3 +1,4 @@
+import InitButton from "@/(route)/(header)/event/[eventId]/edit/_components/InitButton";
import { useEffect, useState } from "react";
import { useFormContext } from "react-hook-form";
import WarningCheck from "@/components/WarningCheck";
@@ -32,10 +33,10 @@ const DetailInput = () => {
return (
<>
-
+
이미지
{validateEdit(typeof defaultValues?.eventImages !== "undefined" && checkArrUpdate(defaultValues?.eventImages, imgList)) && (
-
수정됨
+
setImgList(defaultValues?.eventImages as (string | File)[])} />
)}
@@ -51,6 +52,7 @@ const DetailInput = () => {
rules={{ maxLength: 100 }}
hasLimit
isEdit={validateEdit(defaultValues?.description !== getValues("description"))}
+ onInit={() => setValue("description", defaultValues?.description || "")}
>
상세 내용
diff --git a/app/(route)/post/_components/_inputs/MainInput.tsx b/app/(route)/post/_components/_inputs/MainInput.tsx
index 8a136500..cc0bc95c 100644
--- a/app/(route)/post/_components/_inputs/MainInput.tsx
+++ b/app/(route)/post/_components/_inputs/MainInput.tsx
@@ -1,3 +1,4 @@
+import InitButton from "@/(route)/(header)/event/[eventId]/edit/_components/InitButton";
import { useFormContext } from "react-hook-form";
import AddressBottomSheet from "@/components/bottom-sheet/AddressBottomSheet";
import CalenderBottomSheet from "@/components/bottom-sheet/CalendarBottomSheet";
@@ -19,7 +20,13 @@ const MainInput = () => {
return (
<>
-
+ setValue("placeName", defaultValues?.placeName || "")}
+ >
장소 이름
@@ -30,15 +37,26 @@ const MainInput = () => {
onKeyDown={(event) => handleEnterDown(event, () => openBottomSheet("address"))}
onClick={() => openBottomSheet("address")}
isEdit={validateEdit(defaultValues?.address !== address || defaultValues?.addressDetail !== addressDetail)}
+ onInit={() => {
+ setValue("address", defaultValues?.address || "");
+ setValue("addressDetail", defaultValues?.addressDetail || "");
+ }}
>
주소
-
+
기간
- {validateEdit(defaultValues?.startDate !== startDate || defaultValues?.endDate !== endDate) &&
수정됨
}
+ {validateEdit(defaultValues?.startDate !== startDate || defaultValues?.endDate !== endDate) && (
+
{
+ setValue("startDate", defaultValues?.startDate || "");
+ setValue("endDate", defaultValues?.endDate || "");
+ }}
+ />
+ )}
diff --git a/app/(route)/post/_components/_inputs/StarInput.tsx b/app/(route)/post/_components/_inputs/StarInput.tsx
index 2dcb9678..8d05862f 100644
--- a/app/(route)/post/_components/_inputs/StarInput.tsx
+++ b/app/(route)/post/_components/_inputs/StarInput.tsx
@@ -1,3 +1,4 @@
+import InitButton from "@/(route)/(header)/event/[eventId]/edit/_components/InitButton";
import { useFormContext } from "react-hook-form";
import EventTypeBottomSheet from "@/components/bottom-sheet/EventTypeBottomSheet";
import StarBottomSheet from "@/components/bottom-sheet/StarBottomSheet";
@@ -12,20 +13,28 @@ const StarInput = () => {
const { bottomSheet, openBottomSheet, closeBottomSheet, refs } = useBottomSheet();
const {
+ setValue,
formState: { defaultValues },
watch,
} = useFormContext
();
const { eventType, groupId, artistNames, artists } = watch();
const isNotMember = groupId && artistNames.length === 0;
+ const handleArtistInit = () => {
+ setValue("groupId", defaultValues?.groupId || "");
+ setValue("groupName", defaultValues?.groupName || "");
+ setValue("artists", defaultValues?.artists as string[]);
+ setValue("artistNames", defaultValues?.artistNames as string[]);
+ };
+
return (
<>
-
+
@@ -54,6 +63,8 @@ const StarInput = () => {
onClick={() => openBottomSheet("event")}
onKeyDown={(event) => handleEnterDown(event, () => openBottomSheet("event"))}
isEdit={validateEdit(defaultValues?.eventType !== eventType)}
+ onInit={() => setValue("eventType", defaultValues?.eventType || "카페")}
+ noButton
>
행사 유형
diff --git a/app/(route)/post/_components/_inputs/SubInput.tsx b/app/(route)/post/_components/_inputs/SubInput.tsx
index 94728cd5..1007ab8e 100644
--- a/app/(route)/post/_components/_inputs/SubInput.tsx
+++ b/app/(route)/post/_components/_inputs/SubInput.tsx
@@ -1,3 +1,4 @@
+import InitButton from "@/(route)/(header)/event/[eventId]/edit/_components/InitButton";
import { useEffect, useState } from "react";
import { useFormContext } from "react-hook-form";
import ChipButton from "@/components/chip/ChipButton";
@@ -45,6 +46,10 @@ const SubInput = () => {
name="organizerSns"
placeholder="sns 계정을 입력해주세요."
isEdit={validateEdit(defaultValues?.organizerSns !== organizerSns || defaultValues.snsType !== snsType)}
+ onInit={() => {
+ setSnsType(defaultValues?.snsType || "트위터");
+ setValue("organizerSns", defaultValues?.organizerSns || "");
+ }}
>
주최자
@@ -64,13 +69,20 @@ const SubInput = () => {
))}
-
+ setValue("eventUrl", defaultValues?.eventUrl || "")}
+ >
링크
-
+
특전
- {validateEdit(typeof defaultValues?.tags !== "undefined" && checkArrUpdate(defaultValues?.tags, giftList)) &&
수정됨
}
+ {validateEdit(typeof defaultValues?.tags !== "undefined" && checkArrUpdate(defaultValues?.tags, giftList)) && (
+
setGiftList(defaultValues?.tags as string[])} />
+ )}
{GIFT_LIST.map((gift) => (
diff --git a/app/(route)/post/page.tsx b/app/(route)/post/page.tsx
index 7b0944c2..5be58fdf 100644
--- a/app/(route)/post/page.tsx
+++ b/app/(route)/post/page.tsx
@@ -2,6 +2,7 @@
import GenericFormProvider from "@/components/GenericFormProvider";
import MobileHeader from "@/components/header/MobileHeader";
+import { useAuth } from "@/hooks/useAuth";
import { useFunnel } from "@/hooks/useFunnel";
import { PostStepNameType } from "@/types/index";
import DetailInfo from "./_components/DetailInfo";
@@ -39,6 +40,7 @@ export type PostType = Omit {
+ // const session = useAuth("/signin");
const { Funnel, Step, setStep, currentStep } = useFunnel(POST_STEPS);
const handlePrevClick = () => {
@@ -48,7 +50,7 @@ const Post = () => {
return (
<>
-
+
diff --git a/app/_api/api.ts b/app/_api/api.ts
index 3d760fd4..9f7160cc 100644
--- a/app/_api/api.ts
+++ b/app/_api/api.ts
@@ -8,12 +8,10 @@ const STR_RES_ENDPOINT = ["/file/upload", "/event/update/application"];
export class Api {
private baseUrl;
private queryString;
- private accessToken;
- constructor(token?: string) {
+ constructor() {
this.baseUrl = "";
this.queryString = "";
- this.accessToken = token;
}
private makeError(result: any) {
@@ -40,11 +38,7 @@ export class Api {
if (queryObj) {
this.makeQueryString(queryObj);
}
- const res = await fetch(queryObj ? this.baseUrl + this.queryString : this.baseUrl, {
- headers: {
- Authorization: `Bearer ${this.accessToken}`,
- },
- });
+ const res = await fetch(queryObj ? this.baseUrl + this.queryString : this.baseUrl);
const result = await res.json();
this.makeError(result);
@@ -61,10 +55,8 @@ export class Api {
body: endPoint === "/file/upload" ? (body as any) : JSON.stringify(body),
headers: {
...(endPoint === "/file/upload" || endPoint === "/reviews" ? {} : { "Content-Type": "application/json" }),
- Authorization: `Bearer ${this.accessToken}`,
credentials: "include",
},
- credentials: "include",
});
const result = STR_RES_ENDPOINT.includes(endPoint) ? await res.text() : await res.json();
this.makeError(result);
@@ -79,7 +71,6 @@ export class Api {
body: JSON.stringify(body),
headers: {
"Content-type": "application/json",
- Authorization: `Bearer ${this.accessToken}`,
},
});
const result = await res.json();
@@ -93,9 +84,6 @@ export class Api {
const res = await fetch(this.baseUrl, {
method: "DELETE",
body: JSON.stringify(body),
- headers: {
- Authorization: `Bearer ${this.accessToken}`,
- },
});
const result = await res.json();
this.makeError(result);
diff --git a/app/_components/ArtistList.tsx b/app/_components/ArtistList.tsx
deleted file mode 100644
index 0e7d336c..00000000
--- a/app/_components/ArtistList.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import { ReactNode } from "react";
-
-interface Props {
- render: () => ReactNode;
-}
-
-const ArtistList = ({ render }: Props) => {
- return {render()}
;
-};
-
-export default ArtistList;
diff --git a/app/_components/GenericFormProvider.tsx b/app/_components/GenericFormProvider.tsx
index f4761a0b..daa6cf08 100644
--- a/app/_components/GenericFormProvider.tsx
+++ b/app/_components/GenericFormProvider.tsx
@@ -2,9 +2,14 @@ import { instance } from "app/_api/api";
import { useParams, usePathname, useRouter } from "next/navigation";
import React from "react";
import { FieldValues, FormProvider, UseFormProps, useForm } from "react-hook-form";
+import toast from "react-hot-toast";
import { useModal } from "@/hooks/useModal";
+import { useSession } from "@/store/session/cookies";
import { handleSignupSubmit } from "@/utils/handleSignupSubmit";
-import { handlePostSubmit, submitEditApplication } from "@/utils/submitPost";
+import { handlePostSubmit, submitEditApplication, submitEditWriter } from "@/utils/submitPost";
+import { EditErrMsgType, PostErrMsgType } from "@/types/errorMsgType";
+import { EDIT_ERR_MSG, POST_ERR_MSG } from "@/constants/errorMsg";
+import { useStore } from "../_store";
import AlertModal from "./modal/AlertModal";
interface GenericFormProps {
@@ -13,26 +18,45 @@ interface GenericFormProps {
}
const GenericFormProvider = ({ children, formOptions }: GenericFormProps) => {
- const { editId, eventId } = useParams();
+ const { eventId } = useParams();
const { modal, openModal, closeModal } = useModal();
const router = useRouter();
const methods = useForm(formOptions);
const path = usePathname();
+ const { writerId } = useStore((state) => ({ writerId: state.writerId }));
const onSubmit = async () => {
const userInputValue = methods.getValues();
const defaultValue = methods.formState.defaultValues;
+ const session = useSession();
+ if (!session) return;
if (path === "/post") {
- const res = await handlePostSubmit(userInputValue, instance);
- router.push(`/event/${res.eventId}`);
+ try {
+ const res = await handlePostSubmit(userInputValue, instance, session.user.userId);
+ router.push(`/event/${res.eventId}`);
+ } catch (err: any) {
+ toast.error(POST_ERR_MSG[err.message as PostErrMsgType], { className: "text-16 font-500 !text-red" });
+ if (err.message === "Unauthorized") {
+ return router.push("/signin");
+ }
+ }
}
if (path === `/event/${eventId}/edit`) {
- //작성 유저
- // const res = await submitEditWriter(methods.getValues(), instance, eventId);
- //신청 유저
- await submitEditApplication(instance, defaultValue, userInputValue, eventId);
- openModal("endEdit");
+ try {
+ if (writerId === session.user.userId) {
+ await submitEditWriter(methods.getValues(), instance, session.user.userId, eventId);
+ openModal("editWriter");
+ } else {
+ await submitEditApplication(instance, defaultValue, userInputValue, session.user.userId, eventId);
+ openModal("editApprove");
+ }
+ } catch (err: any) {
+ toast.error(EDIT_ERR_MSG[err.message as EditErrMsgType], { className: "text-16 font-500 !text-red" });
+ if (err.message === "Unauthorized") {
+ return router.push("/signin");
+ }
+ }
}
if (path === "/signup") {
const res = await handleSignupSubmit(userInputValue, instance);
@@ -45,16 +69,15 @@ const GenericFormProvider = ({ children, formOptions }: G
return (
- {modal === "endEdit" && (
- router.push(`/event/${eventId}`)}>
+ {modal === "editApprove" && (
+ router.replace(`/event/${eventId}/approve`)}>
수정사항은 사용자 3인 이상의
승인 후에 반영됩니다.
)}
- {modal === "endEdit" && (
- router.push(`/event/${eventId}`)}>
- 수정사항은 사용자 3인 이상의
-
승인 후에 반영됩니다.
+ {modal === "editWriter" && (
+ router.replace(`/event/${eventId}`)}>
+ 수정이 완료되었습니다.
)}
diff --git a/app/_components/bottom-sheet/EventTypeBottomSheet.tsx b/app/_components/bottom-sheet/EventTypeBottomSheet.tsx
index 9fd19493..92cc4c57 100644
--- a/app/_components/bottom-sheet/EventTypeBottomSheet.tsx
+++ b/app/_components/bottom-sheet/EventTypeBottomSheet.tsx
@@ -16,12 +16,12 @@ const EventTypeBottomSheet = ({ closeBottomSheet, refs }: BottomSheetBaseType) =
return (
행사 유형 선택
-
+
{EVENT_TYPE_LIST.map((event) => (
- handleEventClick(event)}
- className="hover:bg-main-pink-50 cursor-pointer border-b border-gray-50 px-24 py-20 text-16 font-500 text-gray-900"
+ className="cursor-pointer border-b border-gray-50 px-24 py-20 text-16 font-500 text-gray-900 hover:bg-main-pink-50"
>
{event}
diff --git a/app/_components/bottom-sheet/StarBottomSheet.tsx b/app/_components/bottom-sheet/StarBottomSheet.tsx
index 5815a088..d742fb5e 100644
--- a/app/_components/bottom-sheet/StarBottomSheet.tsx
+++ b/app/_components/bottom-sheet/StarBottomSheet.tsx
@@ -1,14 +1,13 @@
+import LoadingDot from "@/(route)/(bottom-nav)/signin/_components/LoadingDot";
import { PostType } from "@/(route)/post/page";
-import { useQuery } from "@tanstack/react-query";
import { instance } from "app/_api/api";
import { Dispatch, SetStateAction, useEffect } from "react";
import { useFormContext } from "react-hook-form";
+import { useFetchGroupSolo } from "@/hooks/useFetchGroupSolo";
import { useFetchMember } from "@/hooks/useFetchMember";
-import { useSearch } from "@/hooks/useSearch";
-import { BottomSheetBaseType } from "@/types/index";
+import { BottomSheetBaseType, GroupAndSoloType, MemberDataType } from "@/types/index";
import BackIcon from "@/public/icon/arrow-left_lg.svg";
import ArtistCard from "../ArtistCard";
-import ArtistList from "../ArtistList";
import SearchInput from "../input/SearchInput";
import BottomSheet from "./BottomSheetMaterial";
@@ -19,18 +18,7 @@ interface Props extends BottomSheetBaseType {
const StarBottomSheet = ({ closeBottomSheet, refs, isFirst = false }: Props) => {
const { setValue, getValues, watch } = useFormContext();
const { groupName, artistNames } = watch();
- const {
- data: groupData,
- isSuccess,
- isLoading,
- refetch: refetchGroup,
- } = useQuery({
- queryKey: ["group"],
- queryFn: async () => {
- return instance.get("/group/solo", { size: 12, page: 1, keyword: keyword });
- },
- });
- const { keyword, setKeyword } = useSearch(refetchGroup);
+ const { setKeyword, groupList, containerRef, isSuccess, isLoading } = useFetchGroupSolo(instance);
const { groupId, setGroupId, isLoading: isMemberLoading, isSuccess: isMemberSuccess, data: memberData } = useFetchMember(instance, getValues, isFirst);
const handleFirstDepthClick = (type: string, id: string, name: string) => {
@@ -71,49 +59,53 @@ const StarBottomSheet = ({ closeBottomSheet, refs, isFirst = false }: Props) =>
return (
아티스트 선택
-
+
{groupId ? (
- {isMemberLoading &&
멤버 로딩중
}
+ {isMemberLoading && (
+
+
+
+ )}
{isMemberSuccess &&
(memberData.length === 0 ? (
-
데이터가 없어요ㅠㅠ
+
아직 데이터가 없어요💦
) : (
-
(
- <>
- {memberData.map(({ id, artistName, artistImage }: any) => (
- handleMemberClick(id, artistName)}>
- {artistName}
-
- ))}
- >
- )}
- />
+
+
+ {memberData.map(({ id, artistName, artistImage }: MemberDataType) => (
+
handleMemberClick(id, artistName)}>
+ {artistName}
+
+ ))}
+
+
))}
) : (
<>
- {isLoading &&
데이터 로딩중 ~~
}
+ {isLoading && (
+
+
+
+ )}
{isSuccess && (
-
(
- <>
- {groupData.groupAndSoloList.map(({ id, image, name, type }: any) => (
- handleFirstDepthClick(type, id, name)}
- >
- {name}
-
- ))}
- >
- )}
- />
+
+
+ {groupList.map(({ id, image, name, type }: GroupAndSoloType) => (
+
handleFirstDepthClick(type, id, name)}
+ >
+ {name}
+
+ ))}
+
+
)}
>
)}
diff --git a/app/_components/input/InputArea.tsx b/app/_components/input/InputArea.tsx
index 5a76c7ec..1f2944c5 100644
--- a/app/_components/input/InputArea.tsx
+++ b/app/_components/input/InputArea.tsx
@@ -1,3 +1,4 @@
+import InitButton from "@/(route)/(header)/event/[eventId]/edit/_components/InitButton";
import classNames from "classnames";
import { KeyboardEvent, ReactNode } from "react";
import { FieldPath, FieldValues, UseControllerProps, useController } from "react-hook-form";
@@ -9,20 +10,21 @@ interface Prop {
isEdit?: boolean;
height?: number;
hasLimit?: boolean;
+ onInit?: () => void;
}
type Function = = FieldPath>(
prop: UseControllerProps & Prop,
) => ReactNode;
-const InputArea: Function = ({ children, placeholder, onKeyDown, isEdit, hasLimit = false, ...control }) => {
+const InputArea: Function = ({ children, placeholder, onKeyDown, isEdit, hasLimit = false, onInit, ...control }) => {
const { field } = useController(control);
return (
-