Skip to content

Commit

Permalink
Merge pull request #42 from dnd-side-project/feature/create-festival
Browse files Browse the repository at this point in the history
페스티벌 생성 로직 구현
  • Loading branch information
froggy1014 authored Aug 31, 2024
2 parents 0a9138f + 2446e78 commit ce0b43b
Show file tree
Hide file tree
Showing 51 changed files with 1,092 additions and 151 deletions.
6 changes: 5 additions & 1 deletion auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,11 @@ const config = {
accessToken: account?.access_token,
};

const response = await postOauthLogin(body);
let response: JWT = token;

if (!Object.hasOwn(token, "isProfileRegistered")) {
response = await postOauthLogin(body);
}

token.accessToken = response?.accessToken;
token.refreshToken = response.refreshToken;
Expand Down
28 changes: 28 additions & 0 deletions src/apis/festivals/createFestival/createFestival.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import instance from "@/apis/instance";
import FIESTA_ENDPOINTS from "@/config/apiEndpoints";
import { CreateFestivalType } from "@/validations/CreateFestivalSchema";

import { CreateFestivalResponse } from "./createFestivalType";

const ENDPOINT = FIESTA_ENDPOINTS.festivals.base;

export async function createFestival(payload: CreateFestivalType) {
const { images, ...rest } = payload;
const formData = new FormData();

formData.append(
"data",
new Blob([JSON.stringify(rest)], { type: "application/json" }),
);

images?.forEach((image: File) => {
formData.append("images", image);
});

const { data } = await instance.post<CreateFestivalResponse>(
ENDPOINT,
formData,
);

return data;
}
4 changes: 4 additions & 0 deletions src/apis/festivals/createFestival/createFestivalType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface CreateFestivalResponse {
festivalId: number;
isPending: boolean;
}
33 changes: 21 additions & 12 deletions src/apis/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,19 @@ type FiestaFetchOptions = Omit<RequestInit, "body">;

export class CreateFiestaFetch {
private baseUrl: string;
private authEnabled: boolean;

constructor(baseUrl: string, authEnabled: boolean = false) {
constructor(baseUrl: string) {
this.baseUrl = baseUrl;
this.authEnabled = authEnabled;
}

private async fetch(url: string, method: Method, options: RequestInit) {
const defaultOptions: RequestInit = {
headers: {
"Content-Type": "application/json",
},
headers: {},
};

let userSession: Session | null = null;
if (this.authEnabled) {
userSession = await this.getUserSession();
}

userSession = await this.getUserSession();

try {
const finalOptions = {
Expand Down Expand Up @@ -125,8 +120,22 @@ export class CreateFiestaFetch {
url: string,
body = {},
options: FiestaFetchOptions = {},
): Promise<FiestaResponse<T>> =>
this.fetch(url, "POST", { body: JSON.stringify(body), ...options });
): Promise<FiestaResponse<T>> => {
const isFormData = body instanceof FormData;
const finalOptions = isFormData
? {
body,
...options,
}
: {
body: JSON.stringify(body),
headers: {
"Content-Type": "application/json",
},
};

return this.fetch(url, "POST", finalOptions);
};

public put = async <T>(
url: string,
Expand All @@ -141,6 +150,6 @@ export class CreateFiestaFetch {
): Promise<FiestaResponse<T>> => this.fetch(url, "DELETE", options);
}

const instance = new CreateFiestaFetch(env.NEXT_PUBLIC_BASE_URL, true);
const instance = new CreateFiestaFetch(env.NEXT_PUBLIC_BASE_URL);

export default instance;
4 changes: 4 additions & 0 deletions src/apis/onboarding/onboarding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
export const getMoods = async () => {
const endpoint = FIESTA_ENDPOINTS.festivals.moods;
const { data } = await instance.get<Array<FestivalMood>>(endpoint, {
cache: "force-cache",
next: {
tags: festivalOnBoarding.all,
},
Expand All @@ -25,6 +26,7 @@ export const getMoods = async () => {
export const getCategories = async () => {
const endpoint = FIESTA_ENDPOINTS.festivals.categories;
const { data } = await instance.get<Array<FestivalCategory>>(endpoint, {
cache: "force-cache",
next: {
tags: festivalOnBoarding.all,
},
Expand All @@ -35,6 +37,7 @@ export const getCategories = async () => {
export const getCompanions = async () => {
const endpoint = FIESTA_ENDPOINTS.festivals.companions;
const { data } = await instance.get<Array<FestivalCompanion>>(endpoint, {
cache: "force-cache",
next: {
tags: festivalOnBoarding.all,
},
Expand All @@ -46,6 +49,7 @@ export const getCompanions = async () => {
export const getPriority = async () => {
const endpoint = FIESTA_ENDPOINTS.festivals.priorities;
const { data } = await instance.get<Array<FestivalPriority>>(endpoint, {
cache: "force-cache",
next: {
tags: festivalOnBoarding.all,
},
Expand Down
5 changes: 1 addition & 4 deletions src/apis/review/topReviews/topReviewsType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ export interface TopReview {
festivalName: string;
content: string;
rating: number;
images?: {
imageId: number;
imageUrl: string;
};
thumbnailImage?: string;
keywords: {
keywordId: number;
keyword: string;
Expand Down
30 changes: 30 additions & 0 deletions src/app/(home)/festivals/new/_components/CreateFestivalButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { FC } from "react";

import { BasicButton } from "@/components/core/Button";

interface Props {
totalStep: number;
currentStep: number;
onNext: () => void;
disabled?: boolean;
}

const CreateFestivalButton: FC<Props> = ({
currentStep,
totalStep,
onNext,
disabled,
}) => {
return (
<div className="fixed bottom-[8px] w-full max-w-none px-[16px] lg:max-w-[450px]">
<BasicButton
type={totalStep === currentStep ? "submit" : "button"}
label={currentStep === 1 ? "다음" : "페스티벌 등록하기"}
onClick={onNext}
disabled={disabled}
/>
</div>
);
};

export default CreateFestivalButton;
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React from "react";
import { Controller, useFormContext } from "react-hook-form";

import { DescriptionInput, TextInput } from "@/components/core/Input";
import ImageUploader from "@/components/imageUploader/ImageUploader";
import { CREATE_FESTIVAL_SETTING } from "@/config";
import { CreateFestivalType } from "@/validations/CreateFestivalSchema";

const CreateFestivalFirstStep = () => {
const {
control,
formState: { dirtyFields },
} = useFormContext<CreateFestivalType>();

return (
<section className=" flex w-full flex-col gap-[32px]">
<Controller
control={control}
name="name"
render={({ field: { onChange, value }, formState: { errors } }) => (
<TextInput
label="페스티벌 명"
placeholder="페스티벌 명을 입력해주세요."
value={value}
onChange={onChange}
currentLength={value?.length ?? 0}
maxLength={30}
error={errors.name?.message}
/>
)}
/>

<Controller
control={control}
name="images"
render={({ field: { onChange, value }, formState: { errors } }) => (
<ImageUploader
label="대표 이미지"
value={value}
onChange={onChange}
accept={CREATE_FESTIVAL_SETTING.ACCEPTED_IMAGE_TYPES.map(
(format) => "." + format,
).join(", ")}
/>
)}
/>

<Controller
control={control}
name="description"
render={({ field: { onChange, value }, formState: { errors } }) => (
<DescriptionInput
label="상세설명"
placeholder="페스티벌 설명을 작성해주세요."
value={value}
onChange={onChange}
currentLength={value?.length ?? 0}
maxLength={300}
error={errors.description?.message}
/>
)}
/>
</section>
);
};

export default CreateFestivalFirstStep;
Loading

0 comments on commit ce0b43b

Please sign in to comment.