Skip to content

Commit

Permalink
Merge pull request #39 from team-Ollie/16-fix-final-home,mypage,admin
Browse files Browse the repository at this point in the history
fix: 변경된 DTO에 따라 API 수정, 기타 오류 수정
  • Loading branch information
iOdiO89 authored Jul 2, 2024
2 parents 48a3ad8 + ad569f4 commit 7b179b3
Show file tree
Hide file tree
Showing 20 changed files with 571 additions and 74 deletions.
13 changes: 11 additions & 2 deletions apis/admin.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
import { CalendarDate } from "./calendar";
import client, { ResponseBody } from "./client";
import client, { ResponseBody, ResponseBody2 } from "./client";

export interface Program {
name: string;
dueDate: CalendarDate;
openDate: CalendarDate;
location: string;
locatedPlace: string;
category: string;
host: string;
schedule: string;
description: string;
}

async function postAttendanceCode(challengeIdx: number): Promise<ResponseBody> {
interface PostAttendanceCodeBody extends ResponseBody2 {
result: {
code: number;
};
}

async function postAttendanceCode(
challengeIdx: number,
): Promise<PostAttendanceCodeBody> {
const { data } = await client.post(`/challenges/attendance/${challengeIdx}`);
return data;
}
Expand Down
6 changes: 3 additions & 3 deletions apis/challenge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ interface GetMyChallengeListResponse extends ResponseBody {
export interface Challenge {
challengeIdx: number;
name: string;
participantsNum: number;
location: string;
participantsCount: number;
locatedPlace: string;
schedule: string;
attendanceRate: number;
myAttendanceRate: number;
totalAttendanceRate: number;
}
interface GetChallengeAdsResponse extends ResponseBody2 {
Expand Down
12 changes: 0 additions & 12 deletions apis/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,6 @@ const getTokenFromLocalStorage = () => {
return accessToken;
};

export const setIsAdminAtLocalStorage = (is_admin: string) => {
localStorage.setItem("is_admin", is_admin);
};

const getIsAdminFromLocalStorage = () => {
const isAdmin = localStorage.getItem("is_admin");
if (!isAdmin) {
return null;
}
return isAdmin;
};

const client = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL,
withCredentials: true,
Expand Down
2 changes: 1 addition & 1 deletion apis/hooks/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ function usePostAttendanceCode(challengeIdx: number) {
const { mutate } = useMutation({
mutationKey: ["postAttendanceCode", challengeIdx],
mutationFn: () => postAttendanceCode(challengeIdx),
onSuccess: (data) => window.alert(`인증번호: ${data}`),
onSuccess: (data) => window.alert(`인증번호: ${data.result.code}`),
onError: () => window.alert("에러 발생. 앱 관리자에게 문의해주세요."),
});

Expand Down
10 changes: 6 additions & 4 deletions apis/hooks/challenge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ function useGetChallengeSearch(keyword: string) {
const { data } = useQuery({
queryKey: ["getChallengeSearch", keyword],
queryFn: () => getChallengeSearch(keyword),
enabled: keyword.trim().length !== 0,
});

return { data };
Expand All @@ -65,11 +64,14 @@ function usePostNewChallenge(
return { mutate };
}

function usePostAttendance() {
function usePostAttendance(challengeIdx: number) {
const queryClient = useQueryClient();
const { mutate } = useMutation({
mutationKey: ["postAttendance"],
mutationFn: (body: AttendanceRequestBody) => postAttendance(body),
mutationKey: ["postAttendance", challengeIdx],
mutationFn: (attendanceCode: string) =>
postAttendance({ challengeIdx, attendanceCode }),
onSuccess: () => window.alert("챌린지가 성공적으로 인증되었습니다."),
onError: () => window.alert("다시 시도해주세요."),
});

return { mutate };
Expand Down
2 changes: 1 addition & 1 deletion apis/hooks/mypage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function usePatchLogout() {
localStorage.removeItem("access_token");
router.push("/main");
},
onError: () => router.push("/404"),
onError: () => router.push("/main"),
});

return { mutate };
Expand Down
7 changes: 4 additions & 3 deletions components/home/adminChallenge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,20 @@ const AdminChallenge: NextPage<ChallengeProps> = ({
return (
<FlexBox direction="col" className="p-4 w-full rounded-lg border gap-4">
<FlexBox direction="col" className="w-full gap-1">
<FlexBox className="w-full justify-between items-start">
<FlexBox className="w-full items-start">
<div className="h2">{challengeInfo.name}</div>
</FlexBox>
<div className="h4 self-start">
{challengeInfo.location} | {challengeInfo.schedule}
{challengeInfo.locatedPlace ? `${challengeInfo.locatedPlace} | ` : ""}
매주 {challengeInfo.schedule}요일
</div>
</FlexBox>
<FlexBox direction="col" className="w-full gap-2">
<FlexBox className="gap-1 w-full">
<div className="h5 text-grey-500">전체달성률</div>
<div className="h3">
{challengeInfo.totalAttendanceRate}%(
{challengeInfo.participantsNum})
{challengeInfo.participantsCount}명 참여 중)
</div>
</FlexBox>
<FlexBox className="w-full gap-2">
Expand Down
19 changes: 16 additions & 3 deletions components/home/certifyModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import FlexBox from "../Flexbox";
import TextInput from "../Input";
import { useState } from "react";
import CloseIcon from "@/public/svgs/Close.svg";
import { usePostAttendance } from "@/apis/hooks/challenge";
import { useAtom } from "jotai";
import { challengeIdxAtom } from "@/utils/atom";

interface CertifyModalProps {
setIsModalVisible: React.Dispatch<React.SetStateAction<boolean>>;
Expand All @@ -19,9 +22,19 @@ export default function CertifyModal({
text: "",
});

const [challengeIdx] = useAtom(challengeIdxAtom);
const { mutate } = usePostAttendance(challengeIdx);

const onCertify = () => {
setIsModalVisible(false);
notify("챌린지가 성공적으로 인증되었습니다.");
if (number.length === 0)
setNumError({
status: true,
text: "인증번호가 입력되지 않았습니다.",
});
else {
mutate(number);
setIsModalVisible(false);
}
};

return (
Expand All @@ -32,7 +45,7 @@ export default function CertifyModal({
<CloseIcon width={20} height={20} />
</div>
</FlexBox>
<FlexBox className="w-full gap-1 mb-3">
<FlexBox className="w-full gap-1 mb-3">
<TextInput
value={number}
setValue={setNumber}
Expand Down
17 changes: 13 additions & 4 deletions components/home/challenge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { NextPage } from "next";
import FlexBox from "../Flexbox";
import { useRouter } from "next/router";
import { Challenge as ChallengeType } from "@/apis/challenge";
import { useAtom } from "jotai";
import { challengeIdxAtom } from "@/utils/atom";

interface ChallengeProps {
setIsModalVisible: React.Dispatch<React.SetStateAction<boolean>>;
Expand All @@ -13,6 +15,12 @@ const Challenge: NextPage<ChallengeProps> = ({
challengeInfo,
}) => {
const router = useRouter();
const [, setChallengeIdx] = useAtom(challengeIdxAtom);

const onClickCertifyBtn = () => {
setChallengeIdx(challengeInfo.challengeIdx);
setIsModalVisible(true);
};

return (
<FlexBox direction="col" className="p-4 w-full rounded-lg border gap-4">
Expand All @@ -24,11 +32,12 @@ const Challenge: NextPage<ChallengeProps> = ({
<FlexBox className="w-full justify-between items-start">
<div className="h2">{challengeInfo.name}</div>
<div className="h4 text-grey-500">
{challengeInfo.participantsNum}명 참여 중
{challengeInfo.participantsCount}명 참여 중
</div>
</FlexBox>
<div className="h4 self-start">
{challengeInfo.location} | {challengeInfo.schedule}
{challengeInfo.locatedPlace ? `${challengeInfo.locatedPlace} | ` : ""}
매주 {challengeInfo.schedule}요일
</div>
</FlexBox>
<FlexBox direction="col" className="w-full gap-1">
Expand All @@ -38,7 +47,7 @@ const Challenge: NextPage<ChallengeProps> = ({
>
<FlexBox className="gap-1">
<div className="h5 text-grey-500">개인달성률</div>
<div className="h3">{challengeInfo.attendanceRate}%</div>
<div className="h3">{challengeInfo.myAttendanceRate}%</div>
</FlexBox>
<FlexBox className="gap-1">
<div className="h5 text-grey-500">전체달성률</div>
Expand All @@ -47,7 +56,7 @@ const Challenge: NextPage<ChallengeProps> = ({
</FlexBox>
<div
className="w-full border border-main-color rounded-lg py-2 text-center text-main-color h2"
onClick={() => setIsModalVisible(true)}
onClick={onClickCertifyBtn}
>
인증하기
</div>
Expand Down
3 changes: 2 additions & 1 deletion components/home/searchResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export default function SearchResult({
<FlexBox direction="col" className="gap-1 items-start">
<div className="h3">{challengeInfo.name}</div>
<div className="h4 text-grey-700">
{challengeInfo.location} | {challengeInfo.schedule}
{challengeInfo.locatedPlace ? `${challengeInfo.locatedPlace} | ` : ""}{" "}
매주 {challengeInfo.schedule}요일
</div>
</FlexBox>
<div className="h2 text-main-color p-2" onClick={onClick}>
Expand Down
2 changes: 2 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ const nextConfig = {
env: {
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,
},

transpilePackages: ["jotai-devtools"],
};

module.exports = nextConfig;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"embla-carousel-react": "^8.1.3",
"gh-pages": "^6.1.1",
"jotai": "^2.8.3",
"jotai-devtools": "^0.10.0",
"lottie-web": "^5.12.2",
"moment": "^2.30.1",
"next": "12.3.4",
Expand Down
18 changes: 12 additions & 6 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,22 @@ import RootLayout from "@/components/Layout";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { AppProps } from "next/app";
import { DevTools } from "jotai-devtools";
import "jotai-devtools/styles.css";
import { Provider } from "jotai";

const queryClient = new QueryClient();

export default function App({ Component, pageProps }: AppProps) {
return (
<QueryClientProvider client={queryClient}>
<RootLayout>
<Component {...pageProps} />
</RootLayout>
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
<Provider>
<QueryClientProvider client={queryClient}>
<RootLayout>
<Component {...pageProps} />
</RootLayout>
<ReactQueryDevtools initialIsOpen={false} />
<DevTools />
</QueryClientProvider>
</Provider>
);
}
24 changes: 15 additions & 9 deletions pages/challenge/add.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,24 @@ import dayjs from "dayjs";
import { NextPage } from "next";
import { useEffect, useState } from "react";
import "dayjs/locale/ko";
import { useAtom } from "jotai";
import { centerNameAtom } from "@/utils/atom";
dayjs.locale("ko");

const AddChallenge: NextPage = () => {
const [name, setName] = useState<string>("");
const [startDate, setStartDate] = useState<string>("");
const [endDate, setEndDate] = useState<string>("");
const [location, setLocation] = useState<string>("");
const [location, setLocation] = useState<string>(""); // 지역태그
const [category, setCategory] = useState<string>("");
const [host, setHost] = useState<string>("");
const [place, setPlace] = useState<string>("");
const [phoneNum, setPhoneNum] = useState<string>("");
const [detail, setDetail] = useState<string>("");

const { mutate } = usePostProgram();

const [centerName] = useAtom(centerNameAtom);

const registerProgram = () => {
mutate({
name,
Expand All @@ -36,9 +40,10 @@ const AddChallenge: NextPage = () => {
month: Number(dayjs(startDate).format("M")),
day: Number(dayjs(startDate).format("D")),
},
location: location,
category: category,
host: host,
location,
locatedPlace: place,
category,
host: centerName,
schedule: dayjs(endDate).format("ddd"),
description:
detail.trim().length === 0
Expand Down Expand Up @@ -78,11 +83,12 @@ const AddChallenge: NextPage = () => {
isError={false}
/>
<ChallengeInput
title="주최 기관"
title="장소"
inputType="text"
value={host}
setValue={setHost}
value={place}
setValue={setPlace}
isError={false}
placeholder="프로그램 시행 장소"
/>
<ChallengeInput
title="담당자 전화번호"
Expand Down Expand Up @@ -112,7 +118,7 @@ const AddChallenge: NextPage = () => {
endDate.length === 0 ||
location.length === 0 ||
category.length === 0 ||
host.length === 0 ||
place.length === 0 ||
phoneNum.length === 0
}
/>
Expand Down
2 changes: 1 addition & 1 deletion pages/challenge/join.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import CheckIcon from "@/public/svgs/Check.svg";
const JoinChallenge: NextPage = () => {
const [keyword, setKeyword] = useState<string>("");

const { data } = useGetChallengeSearch(keyword);
const { data } = useGetChallengeSearch(keyword.trim());

const notify = (title: string) => {
toast.success(`${title}에 성공적으로 참여하셨습니다.`, {
Expand Down
2 changes: 0 additions & 2 deletions pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import FlexBox from "@/components/Flexbox";
import { ToastContainer, Zoom, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import CheckIcon from "@/public/svgs/Check.svg";
import { atom, useAtomValue } from "jotai";
import { isAdminAtom } from "@/utils/atom";

const Home: NextPage = () => {
const notify = (msg: string) => {
Expand Down
Loading

0 comments on commit 7b179b3

Please sign in to comment.