Skip to content

Commit

Permalink
Merge branch 'dev' into chore/#163-casper-custom-folder
Browse files Browse the repository at this point in the history
  • Loading branch information
jhj2713 committed Aug 18, 2024
2 parents 35e66d5 + 3da2799 commit 1fcef46
Show file tree
Hide file tree
Showing 71 changed files with 2,000 additions and 302 deletions.
3 changes: 3 additions & 0 deletions client/public/assets/icons/arrow-line-left.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
5 changes: 5 additions & 0 deletions client/public/assets/icons/reload.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added client/public/assets/rush/two-car.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
131 changes: 131 additions & 0 deletions client/src/apis/rushAPI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import {
GetRushBalanceResponse,
GetRushOptionResultResponse,
GetRushResultResponse,
GetRushUserParticipationStatusResponse,
GetTodayRushEventResponse,
GetTotalRushEventsResponse,
RushEventStatusCodeResponse,
} from "@/types/rushApi";
import { fetchWithTimeout } from "@/utils/fetchWithTimeout.ts";

const baseURL = `${import.meta.env.VITE_API_URL}/event/rush`;
const headers = {
"Content-Type": "application/json",
};

export const RushAPI = {
async getRush(): Promise<GetTotalRushEventsResponse> {
try {
const response = await fetchWithTimeout(`${baseURL}`, {
method: "GET",
headers: headers,
});
return response.json();
} catch (error) {
console.error("Error:", error);
throw error;
}
},
async getRushUserParticipationStatus(
token: string
): Promise<GetRushUserParticipationStatusResponse> {
try {
const response = await fetchWithTimeout(`${baseURL}/applied`, {
method: "GET",
headers: { ...headers, Authorization: `Bearer ${token}` },
});
return response.json();
} catch (error) {
console.error("Error:", error);
throw error;
}
},
async getTodayRushEvent(token: string): Promise<GetTodayRushEventResponse> {
try {
const response = await fetchWithTimeout(`${baseURL}/today`, {
method: "GET",
headers: { ...headers, Authorization: `Bearer ${token}` },
});
return response.json();
} catch (error) {
console.error("Error:", error);
throw error;
}
},
async postSelectedRushOptionApply(
token: string,
optionId: number
): Promise<RushEventStatusCodeResponse> {
try {
const response = await fetchWithTimeout(`${baseURL}/options/${optionId}/apply`, {
method: "POST",
headers: { ...headers, Authorization: `Bearer ${token}` },
});

if (response.status === 204 || response.status === 404) {
return response.status;
}

throw new Error(`Unexpected response status: ${response.status}`);
} catch (error) {
console.error("Error:", error);
throw error;
}
},
async getRushOptionResult(
token: string,
optionId: number
): Promise<GetRushOptionResultResponse> {
try {
const response = await fetchWithTimeout(`${baseURL}/options/${optionId}/result`, {
method: "GET",
headers: { ...headers, Authorization: `Bearer ${token}` },
});
return response.json();
} catch (error) {
console.error("Error:", error);
throw error;
}
},
async getRushBalance(token: string): Promise<GetRushBalanceResponse> {
try {
const response = await fetchWithTimeout(`${baseURL}/balance`, {
method: "GET",
headers: { ...headers, Authorization: `Bearer ${token}` },
});
return response.json();
} catch (error) {
console.error("Error:", error);
throw error;
}
},
async getRushResult(token: string): Promise<GetRushResultResponse> {
try {
const response = await fetchWithTimeout(`${baseURL}/result`, {
method: "GET",
headers: { ...headers, Authorization: `Bearer ${token}` },
});
return response.json();
} catch (error) {
console.error("Error:", error);
throw error;
}
},
async getRushTodayEventTest(): Promise<RushEventStatusCodeResponse> {
try {
const response = await fetchWithTimeout(`${baseURL}/today/test`, {
method: "GET",
headers: headers,
});
if (response.status === 204 || response.status === 404) {
return response.status;
}

throw new Error(`Unexpected response status: ${response.status}`);
} catch (error) {
console.error("Error:", error);
throw error;
}
},
};
22 changes: 22 additions & 0 deletions client/src/apis/totalAPI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { GetTotalEventDateResponse } from "@/types/totalApi.ts";
import { fetchWithTimeout } from "@/utils/fetchWithTimeout.ts";

const baseURL = `${import.meta.env.VITE_API_URL}/event/total`;
const headers = {
"Content-Type": "application/json",
};

export const TotalAPI = {
async getTotal(): Promise<GetTotalEventDateResponse> {
try {
const response = await fetchWithTimeout(`${baseURL}`, {
method: "GET",
headers: headers,
});
return response.json();
} catch (error) {
console.error("Error:", error);
throw error;
}
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ export function Background({ children }: PropsWithChildren) {
<div className="absolute top-0 right-[35px] w-[800px] h-[390px] rounded-[29px] overflow-hidden bg-n-white/[.16] z-5">
<div className="w-1/2 h-full float-left bg-gradient-green blur-[40px]" />
</div>
{children}
<div className="flex flex-col gap-6 justify-center items-center w-[800px] h-[390px] bg-n-white rounded-[29px] relative z-20">
{children}
</div>
</motion.div>
);
}
4 changes: 2 additions & 2 deletions client/src/components/CTAButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { memo } from "react";
import { VariantProps, cva } from "class-variance-authority";
import { Link } from "react-router-dom";
import "@/index.css";
import ArrowIcon from "/public/assets/icons/arrow.svg?react";
import ArrowRightIcon from "/public/assets/icons/arrow-line-right.svg?react";
import ShareIcon from "/public/assets/icons/share.svg?react";

const BUTTON_STATUS: Record<string, ButtonStatusType> = {
Expand Down Expand Up @@ -61,7 +61,7 @@ function CTAButton({
const content = (
<>
{label}
{hasArrowIcon && <ArrowIcon stroke={strokeColor} />}
{hasArrowIcon && <ArrowRightIcon stroke={strokeColor} />}
{hasShareIcon && <ShareIcon stroke={strokeColor} />}
</>
);
Expand Down
3 changes: 2 additions & 1 deletion client/src/components/Category/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { cva } from "class-variance-authority";

export interface CategoryProps {
children: ReactNode;
type: "basic" | "limited";
type: "basic" | "limited" | "selected";
}

const categoryVariants = cva(`w-fit px-300 py-200 rounded-1000 text-n-white h-body-2-regular`, {
variants: {
type: {
basic: "bg-n-neutral-500",
limited: "bg-s-red",
selected: "bg-s-blue",
},
},
});
Expand Down
133 changes: 81 additions & 52 deletions client/src/components/Notice/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
import React, { memo } from "react";
import React, { memo, useEffect, useMemo } from "react";
import { LotteryAPI } from "@/apis/lotteryAPI.ts";
import { RushAPI } from "@/apis/rushAPI.ts";
import useFetch from "@/hooks/useFetch.ts";
import { GetLotteryResponse } from "@/types/lotteryApi.ts";
import { GetTotalRushEventsResponse } from "@/types/rushApi.ts";
import { formatEventDate } from "@/utils/formatDate.ts";

interface EventDetails {
interface EventDateDetails {
startDate: string;
endDate: string;
days: number;
activePeriod: number;
}

interface EventData {
[key: string]: EventDetails;
export type EventType = "rush" | "lottery";

export interface EventDateData {
rush?: EventDateDetails;
lottery?: EventDateDetails;
}

const mapToEventDateDetails = (
data: GetLotteryResponse | GetTotalRushEventsResponse
): EventDateDetails => ({
startDate: data.eventStartDate,
endDate: data.eventEndDate,
activePeriod: data.activePeriod,
});

interface SectionProps {
title: string;
items: string[];
Expand All @@ -28,57 +45,69 @@ const Section: React.FC<SectionProps> = ({ title, items, indentedIndices = [] })
);

function Notice() {
const eventDetails: EventData = {
// TODO: 임시 데이터 -> API로 변경 필요
badgeDraw: {
startDate: "2024.08.23.",
endDate: "2024.09.05.",
days: 14,
},
balanceGame: {
startDate: "2024.08.31.",
endDate: "2024.09.05.",
days: 6,
},
};
const formatEventItem = (eventName: string, eventKey: keyof EventData) => {
const event = eventDetails[eventKey];
if (event) {
return `${eventName} : ${event.startDate} ~ ${event.endDate} (${event.days}일)`;
}
return `${eventName} : 날짜를 불러오는 중입니다...`;
};
const {
data: rushEventDetails,
isSuccess: isSuccessRush,
fetchData: getRushEventData,
} = useFetch<EventDateDetails>(() => RushAPI.getRush().then(mapToEventDateDetails));

const {
data: lotteryEventDetails,
isSuccess: isSuccessLottery,
fetchData: getLotteryEventData,
} = useFetch<EventDateDetails>(() => LotteryAPI.getLottery().then(mapToEventDateDetails));

useEffect(() => {
getRushEventData();
getLotteryEventData();
}, []);

const eventDateData: EventDateData = useMemo(() => {
const eventData: EventDateData = {};

if (rushEventDetails) eventData.rush = rushEventDetails;
if (lotteryEventDetails) eventData.lottery = lotteryEventDetails;

return eventData;
}, [rushEventDetails, lotteryEventDetails]);

const isValidData =
isSuccessRush && isSuccessLottery && rushEventDetails && lotteryEventDetails;

return (
<div className="w-full h-[756px] flex flex-col gap-y-5 bg-n-neutral-100 py-20 px-[180px] text-n-black snap-center">
<h3 className="!leading-9 h-heading-3-bold">유의사항</h3>
<Section
title="이벤트 참여"
items={[
"이벤트 기간",
formatEventItem("캐스퍼봇 뱃지 추첨 이벤트", "badgeDraw"),
formatEventItem("선착순 밸런스 게임 이벤트", "balanceGame"),
"선착순 밸런스 게임 이벤트는 이벤트 기간 내 매일 하루에 한 번씩, 기간 내 최대 6번 참여 가능합니다.",
"이벤트 참여 시 당첨자 연락을 위해 전화번호 기재와 개인정보 수집 동의, 마케팅 정보 수신 동의가 필수로 요구됩니다.",
"본 이벤트에서 제작해주신 캐스퍼봇 이미지는 추후 마케팅에 이용될 수 있습니다.",
"해당 이벤트는 내부 사정으로 인해 별도 공지 없이 이벤트가 조기 종료될 수 있습니다.",
]}
indentedIndices={[1, 2]}
/>
<Section
title="경품 관련 유의사항"
items={[
"이벤트 당첨자에게는 기재된 전화번호로 추후 문자메시지를 통해 연락이 전달됩니다.",
"미성년자의 경우 이벤트 경품에 따라 수령시 보호자의 동의가 필요할 수 있습니다.",
"야구 예매권은 티켓링크에서 사용 가능하며, 3만원 이하 좌석만 예매 가능합니다.",
"5만원 이상 경품에 대한 제세공과금은 현대자동차에서 부담하며, 제세공과금 납부 및 신고를 위한 세부 내용은 대상자에 따라 개별 안내됩니다.",
"비정상적이거나 불법적인 방법으로 본 이벤트에 참여하신 경우 당첨이 취소되거나 경품 환수 조치될 수 있습니다.",
]}
/>
<Section
title="이벤트 관련 문의"
items={["casper_electric_arrivalevent@event.co.kr"]}
/>
{isValidData && (
<>
<Section
title="이벤트 참여"
items={[
"이벤트 기간",
formatEventDate("캐스퍼봇 뱃지 추첨 이벤트", "rush", eventDateData),
formatEventDate("선착순 밸런스 게임 이벤트", "lottery", eventDateData),
"선착순 밸런스 게임 이벤트는 이벤트 기간 내 매일 하루에 한 번씩, 기간 내 최대 6번 참여 가능합니다.",
"이벤트 참여 시 당첨자 연락을 위해 전화번호 기재와 개인정보 수집 동의, 마케팅 정보 수신 동의가 필수로 요구됩니다.",
"본 이벤트에서 제작해주신 캐스퍼봇 이미지는 추후 마케팅에 이용될 수 있습니다.",
"해당 이벤트는 내부 사정으로 인해 별도 공지 없이 이벤트가 조기 종료될 수 있습니다.",
]}
indentedIndices={[1, 2]}
/>
<Section
title="경품 관련 유의사항"
items={[
"이벤트 당첨자에게는 기재된 전화번호로 추후 문자메시지를 통해 연락이 전달됩니다.",
"미성년자의 경우 이벤트 경품에 따라 수령시 보호자의 동의가 필요할 수 있습니다.",
"야구 예매권은 티켓링크에서 사용 가능하며, 3만원 이하 좌석만 예매 가능합니다.",
"5만원 이상 경품에 대한 제세공과금은 현대자동차에서 부담하며, 제세공과금 납부 및 신고를 위한 세부 내용은 대상자에 따라 개별 안내됩니다.",
"비정상적이거나 불법적인 방법으로 본 이벤트에 참여하신 경우 당첨이 취소되거나 경품 환수 조치될 수 있습니다.",
]}
/>
<Section
title="이벤트 관련 문의"
items={["casper_electric_arrivalevent@event.co.kr"]}
/>
</>
)}
</div>
);
}
Expand Down
Loading

0 comments on commit 1fcef46

Please sign in to comment.