Skip to content

Commit

Permalink
Merge pull request #121 from softeerbootcamp4th/feat/#120-error-handling
Browse files Browse the repository at this point in the history
[Feat] 에러 핸들링 구현
  • Loading branch information
jhj2713 authored Aug 9, 2024
2 parents 37c9ecb + 19f99ff commit 81f7e29
Show file tree
Hide file tree
Showing 18 changed files with 354 additions and 161 deletions.
7 changes: 7 additions & 0 deletions client/public/assets/icons/casper-error.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion client/src/apis/authAPI.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { PostAuthRequestBody, PostAuthResponse } from "@/types/authApi";
import { fetchWithTimeout } from "@/utils/fetchWithTimeout";

const baseURL = `${import.meta.env.VITE_API_URL}/event/auth`;
const headers = {
Expand All @@ -8,7 +9,7 @@ const headers = {
export const AuthAPI = {
async getAuthToken(body: PostAuthRequestBody): Promise<PostAuthResponse> {
try {
const response = await fetch(`${baseURL}`, {
const response = await fetchWithTimeout(`${baseURL}`, {
method: "POST",
headers: headers,
body: JSON.stringify(body),
Expand Down
9 changes: 5 additions & 4 deletions client/src/apis/lotteryAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
PostCasperRequestBody,
PostCasperResponse,
} from "@/types/lotteryApi";
import { fetchWithTimeout } from "../utils/fetchWithTimeout";

const baseURL = `${import.meta.env.VITE_API_URL}/event/lottery`;
const headers = {
Expand All @@ -14,7 +15,7 @@ const headers = {
export const LotteryAPI = {
async getLottery(): Promise<GetLotteryResponse> {
try {
const response = await fetch(`${baseURL}`, {
const response = await fetchWithTimeout(`${baseURL}`, {
method: "GET",
headers: headers,
});
Expand All @@ -26,7 +27,7 @@ export const LotteryAPI = {
},
async getCasperList(): Promise<GetCasperListResponse> {
try {
const response = await fetch(`${baseURL}/caspers`, {
const response = await fetchWithTimeout(`${baseURL}/caspers`, {
method: "GET",
headers: headers,
});
Expand All @@ -38,7 +39,7 @@ export const LotteryAPI = {
},
async getApplyCount(token: string): Promise<GetApplyCountResponse> {
try {
const response = await fetch(`${baseURL}/applied`, {
const response = await fetchWithTimeout(`${baseURL}/applied`, {
method: "GET",
headers: { ...headers, Authorization: `Bearer ${token}` },
});
Expand All @@ -50,7 +51,7 @@ export const LotteryAPI = {
},
async postCasper(token: string, body: PostCasperRequestBody): Promise<PostCasperResponse> {
try {
const response = await fetch(`${baseURL}/casperBot`, {
const response = await fetchWithTimeout(`${baseURL}/casperBot`, {
method: "POST",
headers: { ...headers, Authorization: `Bearer ${token}` },
body: JSON.stringify(body),
Expand Down
6 changes: 0 additions & 6 deletions client/src/components/PopUp/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { FormEvent, useCallback, useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { PHONE_NUMBER_FORMAT, formatPhoneNumber } from "@/utils/formatPhoneNumber";
import CTAButton from "../CTAButton";
import CheckBox from "../CheckBox";
Expand All @@ -10,18 +9,14 @@ export interface PopUpProps {
handlePhoneNumberChange: (val: string) => void;
handlePhoneNumberConfirm: (val: string) => void;
handleClose: () => void;
confirmUrl: string;
}

export default function PopUp({
phoneNumber = "",
handlePhoneNumberChange,
handlePhoneNumberConfirm,
handleClose,
confirmUrl,
}: PopUpProps) {
const navigate = useNavigate();

const [isUserInfoCheck, setIsUserInfoCheck] = useState(true);
const [isMarketingInfoCheck, setIsMarketingInfoCheck] = useState(true);
const [canConfirm, setCanConfirm] = useState(false);
Expand Down Expand Up @@ -51,7 +46,6 @@ export default function PopUp({
const handleConfirm = (e: FormEvent) => {
e.preventDefault();
handlePhoneNumberConfirm(phoneNumber);
navigate(confirmUrl);
};

return (
Expand Down
121 changes: 70 additions & 51 deletions client/src/features/CasperCustom/CasperCustomFinish.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from "react";
import { useEffect, useRef } from "react";
import { motion } from "framer-motion";
import { useCookies } from "react-cookie";
import { Link } from "react-router-dom";
Expand All @@ -9,7 +9,10 @@ import { MAX_APPLY } from "@/constants/CasperCustom/customStep";
import { DISSOLVE } from "@/constants/animation";
import useCasperCustomDispatchContext from "@/hooks/useCasperCustomDispatchContext";
import useCasperCustomStateContext from "@/hooks/useCasperCustomStateContext";
import useFetch from "@/hooks/useFetch";
import ErrorBoundary from "@/pages/ErrorBoundary";
import { CASPER_ACTION } from "@/types/casperCustom";
import { GetApplyCountResponse } from "@/types/lotteryApi";
import { saveDomImage } from "@/utils/saveDomImage";
import { SCROLL_MOTION } from "../../constants/animation";
import { Battery } from "./Battery";
Expand All @@ -18,29 +21,34 @@ import ArrowIcon from "/public/assets/icons/arrow.svg?react";

interface CasperCustomFinishProps {
handleResetStep: () => void;
unblockNavigation: () => void;
}

export function CasperCustomFinish({ handleResetStep }: CasperCustomFinishProps) {
export function CasperCustomFinish({
handleResetStep,
unblockNavigation,
}: CasperCustomFinishProps) {
const [cookies] = useCookies([COOKIE_TOKEN_KEY]);

const {
data: applyCountData,
isError: isErrorgetApplyCount,
fetchData: getApplyCount,
} = useFetch<GetApplyCountResponse>(() => LotteryAPI.getApplyCount(cookies[COOKIE_TOKEN_KEY]));

const dispatch = useCasperCustomDispatchContext();
const { casperName } = useCasperCustomStateContext();

const casperCustomRef = useRef<HTMLDivElement>(null);

const [applyCount, setApplyCount] = useState<number>(0);

useEffect(() => {
if (!cookies[COOKIE_TOKEN_KEY]) {
return;
}
getApplyCount();
}, []);

const getApplyCount = async () => {
const data = await LotteryAPI.getApplyCount(cookies[COOKIE_TOKEN_KEY]);
setApplyCount(data.appliedCount);
};
unblockNavigation();
getApplyCount();
}, [cookies]);

const handleSaveImage = () => {
if (!casperCustomRef.current) {
Expand All @@ -56,51 +64,62 @@ export function CasperCustomFinish({ handleResetStep }: CasperCustomFinishProps)
};

return (
<motion.div className="mt-[60px] flex flex-col items-center" {...SCROLL_MOTION(DISSOLVE)}>
<div className="flex items-center gap-[107px]">
<div>
<div ref={casperCustomRef}>
<MyCasperCardFront casperName={casperName} hasRandomButton={false} />
</div>

<div className="flex gap-500 h-body-1-bold text-n-white mt-[30px]">
<button
className="py-[18px] rounded-[48px] border border-n-white flex-1 bg-n-white/[.24]"
onClick={handleSaveImage}
>
이미지 저장
</button>
<button
className="py-[18px] rounded-[48px] border border-n-white flex-1 bg-n-white/[.24]"
onClick={handleReset}
>
다시 만들기
</button>
</div>
</div>

<div className="flex flex-col items-center gap-[56px]">
<div className="flex flex-col items-center gap-800">
<p className="text-n-neutral-500">응모한 횟수</p>

<Battery applyCount={applyCount} />
<ErrorBoundary isError={isErrorgetApplyCount}>
<motion.div
className="mt-[60px] flex flex-col items-center"
{...SCROLL_MOTION(DISSOLVE)}
>
<div className="flex items-center gap-[107px]">
<div>
<div ref={casperCustomRef}>
<MyCasperCardFront casperName={casperName} hasRandomButton={false} />
</div>

<div className="flex items-center gap-300">
<h2 className="h-heading-2-bold text-n-white">{applyCount}</h2>{" "}
<p className="h-body-2-regular text-n-neutral-300">/{MAX_APPLY}</p>
<div className="flex gap-500 h-body-1-bold text-n-white mt-[30px]">
<button
className="py-[18px] rounded-[48px] border border-n-white flex-1 bg-n-white/[.24]"
onClick={handleSaveImage}
>
이미지 저장
</button>
<button
className="py-[18px] rounded-[48px] border border-n-white flex-1 bg-n-white/[.24]"
onClick={handleReset}
>
다시 만들기
</button>
</div>
</div>

<CTAButton label="이벤트 공유해서 추가 응모하기" />
<div className="flex flex-col items-center gap-[56px]">
{applyCountData && (
<div className="flex flex-col items-center gap-800">
<p className="text-n-neutral-500">응모한 횟수</p>

<Battery applyCount={applyCountData.appliedCount} />

<div className="flex items-center gap-300">
<h2 className="h-heading-2-bold text-n-white">
{applyCountData.appliedCount}
</h2>{" "}
<p className="h-body-2-regular text-n-neutral-300">
/{MAX_APPLY}
</p>
</div>
</div>
)}

<CTAButton label="이벤트 공유해서 추가 응모하기" />
</div>
</div>
</div>

<Link className="flex gap-300 mt-[60px] group" to="/lottery/show-case">
<p className="h-body-1-regular text-n-white group-hover:underline">
다른 사람들의 스마일 로봇 뱃지 보러가기
</p>
<ArrowIcon stroke="#ffffff" />
</Link>
</motion.div>

<Link className="flex gap-300 mt-[60px] group" to="/lottery/show-case">
<p className="h-body-1-regular text-n-white group-hover:underline">
다른 사람들의 스마일 로봇 뱃지 보러가기
</p>
<ArrowIcon stroke="#ffffff" />
</Link>
</motion.div>
</ErrorBoundary>
);
}
9 changes: 7 additions & 2 deletions client/src/features/CasperCustom/CasperCustomFinishing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,18 @@ export function CasperCustomFinishing({ navigateNextStep }: CasperCustomFinishin
useEffect(() => {
showToast();

setTimeout(() => {
const flipTimer = setTimeout(() => {
setIsFlipped(true);
}, 3000);

setTimeout(() => {
const navigateTimer = setTimeout(() => {
navigateNextStep();
}, 6000);

return () => {
clearTimeout(flipTimer);
clearTimeout(navigateTimer);
};
}, []);

return (
Expand Down
Loading

0 comments on commit 81f7e29

Please sign in to comment.