From 00c14db0c0c2614449783566cc9e6bf76a288fe2 Mon Sep 17 00:00:00 2001 From: YINGMEI Date: Sun, 29 Dec 2024 02:33:50 +0900 Subject: [PATCH] feat: connect apiFnd005 --- .../src/feature/funding/funding.controller.ts | 7 +- .../src/feature/funding/funding.service.ts | 6 +- .../src/api/funding/endpoint/apiFnd005.ts | 11 +-- .../web/src/app/manage-club/funding/page.tsx | 47 ++++++++----- packages/web/src/constants/tableTagList.ts | 28 ++++---- .../components/NewFundingListSection.tsx | 21 +++++- .../_atomic/NewFundingListTable.tsx | 33 ++++----- .../funding/services/useGetNewFundingList.ts | 39 +++++++++++ .../manage-club/funding/types/funding.ts | 14 ++++ .../services/_mock/mockManageClub.ts | 67 ++++++++++--------- 10 files changed, 181 insertions(+), 92 deletions(-) create mode 100644 packages/web/src/features/manage-club/funding/services/useGetNewFundingList.ts diff --git a/packages/api/src/feature/funding/funding.controller.ts b/packages/api/src/feature/funding/funding.controller.ts index e3dd8012f..28e72e811 100644 --- a/packages/api/src/feature/funding/funding.controller.ts +++ b/packages/api/src/feature/funding/funding.controller.ts @@ -6,6 +6,7 @@ import { Param, Post, Put, + Query, UsePipes, } from "@nestjs/common"; import apiFnd001, { @@ -26,7 +27,7 @@ import apiFnd004, { ApiFnd004ResponseOk, } from "@sparcs-clubs/interface/api/funding/endpoint/apiFnd004"; import apiFnd005, { - ApiFnd005RequestBody, + ApiFnd005RequestQuery, ApiFnd005ResponseOk, } from "@sparcs-clubs/interface/api/funding/endpoint/apiFnd005"; import apiFnd006, { @@ -102,9 +103,9 @@ export default class FundingController { @UsePipes(new ZodPipe(apiFnd005)) async getStudentFundings( @GetStudent() user: GetStudent, - @Body() body: ApiFnd005RequestBody, + @Query() query: ApiFnd005RequestQuery, ): Promise { - return this.fundingService.getStudentFundings(user.studentId, body); + return this.fundingService.getStudentFundings(user.studentId, query); } @Student() diff --git a/packages/api/src/feature/funding/funding.service.ts b/packages/api/src/feature/funding/funding.service.ts index ddf6cade8..639ca20f0 100644 --- a/packages/api/src/feature/funding/funding.service.ts +++ b/packages/api/src/feature/funding/funding.service.ts @@ -10,7 +10,7 @@ import { ApiFnd003RequestParam, } from "@sparcs-clubs/interface/api/funding/endpoint/apiFnd003"; import { ApiFnd004RequestParam } from "@sparcs-clubs/interface/api/funding/endpoint/apiFnd004"; -import { ApiFnd005RequestBody } from "@sparcs-clubs/interface/api/funding/endpoint/apiFnd005"; +import { ApiFnd005RequestQuery } from "@sparcs-clubs/interface/api/funding/endpoint/apiFnd005"; import { ApiFnd006RequestBody, ApiFnd006RequestParam, @@ -264,7 +264,7 @@ export default class FundingService { return this.fundingRepository.deleteStudentFunding(param.id); } - async getStudentFundings(studentId: number, body: ApiFnd005RequestBody) { + async getStudentFundings(studentId: number, query: ApiFnd005RequestQuery) { const user = await this.userPublicService.getStudentById({ id: studentId }); if (!user) { throw new HttpException("Student not found", HttpStatus.NOT_FOUND); @@ -276,7 +276,7 @@ export default class FundingService { const fundings = await this.fundingRepository.selectFundingsSemesterByClubId( - body.clubId, + query.clubId, thisSemester, ); diff --git a/packages/interface/src/api/funding/endpoint/apiFnd005.ts b/packages/interface/src/api/funding/endpoint/apiFnd005.ts index bd7f80627..a69139e74 100644 --- a/packages/interface/src/api/funding/endpoint/apiFnd005.ts +++ b/packages/interface/src/api/funding/endpoint/apiFnd005.ts @@ -8,17 +8,17 @@ import { FundingOrderStatusEnum } from "@sparcs-clubs/interface/common/enum/fund * @description 현재 학기의 지원금 신청을 조회합니다. */ -const url = "/student/fundings"; +const url = () => "/student/fundings"; const method = "GET"; const requestParam = z.object({}); -const requestQuery = z.object({}); - -const requestBody = z.object({ +const requestQuery = z.object({ clubId: z.coerce.number().int().min(1), }); +const requestBody = z.object({}); + const responseBodyMap = { [HttpStatusCode.Ok]: z.object({ fundings: z.array( @@ -26,6 +26,7 @@ const responseBodyMap = { id: z.coerce.number().int().min(1), fundingOrderStatusEnumId: z.nativeEnum(FundingOrderStatusEnum), activityName: z.coerce.string().max(255), + name: z.coerce.string().max(255), expenditureAmount: z.coerce.number().int().min(0), approvedAmount: z.coerce.number().int().min(0).optional(), }), @@ -53,8 +54,8 @@ type ApiFnd005ResponseOk = z.infer<(typeof apiFnd005.responseBodyMap)[200]>; export default apiFnd005; export type { + ApiFnd005RequestBody, ApiFnd005RequestParam, ApiFnd005RequestQuery, - ApiFnd005RequestBody, ApiFnd005ResponseOk, }; diff --git a/packages/web/src/app/manage-club/funding/page.tsx b/packages/web/src/app/manage-club/funding/page.tsx index d28d89197..c9fac7540 100644 --- a/packages/web/src/app/manage-club/funding/page.tsx +++ b/packages/web/src/app/manage-club/funding/page.tsx @@ -2,6 +2,9 @@ import React from "react"; +import { ApiClb015ResponseOk } from "@sparcs-clubs/interface/api/club/endpoint/apiClb015"; + +import AsyncBoundary from "@sparcs-clubs/web/common/components/AsyncBoundary"; import FlexWrapper from "@sparcs-clubs/web/common/components/FlexWrapper"; import PageHead from "@sparcs-clubs/web/common/components/PageHead"; import { @@ -11,23 +14,33 @@ import { } from "@sparcs-clubs/web/constants/manageClubFunding"; import NewFundingListSection from "@sparcs-clubs/web/features/manage-club/funding/components/NewFundingListSection"; import PastFundingListSection from "@sparcs-clubs/web/features/manage-club/funding/components/PastFundingListSection"; +import { useGetMyManageClub } from "@sparcs-clubs/web/features/manage-club/services/getMyManageClub"; + +const Funding: React.FC = () => { + const { data, isLoading, isError } = useGetMyManageClub() as { + data: ApiClb015ResponseOk; + isLoading: boolean; + isError: boolean; + }; -const Funding: React.FC = () => ( - - - {/* TODO: API 구현 이후엔 테이블 데이터 전부 프레임에서 주입해줄 것! */} - - - -); + return ( + + + + + + + + ); +}; export default Funding; diff --git a/packages/web/src/constants/tableTagList.ts b/packages/web/src/constants/tableTagList.ts index c86b6210a..057f7bd3c 100644 --- a/packages/web/src/constants/tableTagList.ts +++ b/packages/web/src/constants/tableTagList.ts @@ -4,6 +4,7 @@ import { } from "@sparcs-clubs/interface/common/enum/activity.enum"; import { ActivityCertificateOrderStatusEnum } from "@sparcs-clubs/interface/common/enum/activityCertificate.enum"; import { CommonSpaceUsageOrderStatusEnum } from "@sparcs-clubs/interface/common/enum/commonSpace.enum"; +import { FundingOrderStatusEnum } from "@sparcs-clubs/interface/common/enum/funding.enum"; import { PromotionalPrintingOrderStatusEnum } from "@sparcs-clubs/interface/common/enum/promotionalPrinting.enum"; import { RegistrationStatusEnum, @@ -16,7 +17,6 @@ import { DivisionType } from "@sparcs-clubs/web/types/divisions.types"; import { TagColor } from "../common/components/Tag"; import { ActivityProfessorApprovalEnum, - FundingStatusEnum, MemberStatusEnum, } from "../features/manage-club/services/_mock/mockManageClub"; import { StatusDetail } from "../utils/getTagDetail"; @@ -92,12 +92,12 @@ const MemTagList: { }; const FundingTagList: { - [key in FundingStatusEnum]: StatusDetail; + [key in FundingOrderStatusEnum]: StatusDetail; } = { - [FundingStatusEnum.Applied]: { text: "신청", color: "BLUE" }, - [FundingStatusEnum.Committee]: { text: "운위", color: "YELLOW" }, - [FundingStatusEnum.Approved]: { text: "승인", color: "GREEN" }, - [FundingStatusEnum.Rejected]: { text: "반려", color: "RED" }, + [FundingOrderStatusEnum.Applied]: { text: "신청", color: "BLUE" }, + [FundingOrderStatusEnum.Committee]: { text: "운위", color: "YELLOW" }, + [FundingOrderStatusEnum.Approved]: { text: "승인", color: "GREEN" }, + [FundingOrderStatusEnum.Rejected]: { text: "반려", color: "RED" }, }; // TODO: interface enum 사용 @@ -187,17 +187,17 @@ const DivisionTypeTagList: { [key in DivisionType]: StatusDetail } = { export { AcfTagList, + ActStatusTagList, + ActTypeTagList, + ApplyTagList, CmsTagList, - PrtTagList, - RntTagList, + DivisionTypeTagList, + FundingTagList, MemTagList, - ApplyTagList, - ActStatusTagList, ProfessorApprovalTagList, ProfessorIsApprovedTagList, - ActTypeTagList, - FundingTagList, - RegistrationTypeTagList, + PrtTagList, RegistrationStatusTagList, - DivisionTypeTagList, + RegistrationTypeTagList, + RntTagList, }; diff --git a/packages/web/src/features/manage-club/funding/components/NewFundingListSection.tsx b/packages/web/src/features/manage-club/funding/components/NewFundingListSection.tsx index cabb40298..ab9f7c5e0 100644 --- a/packages/web/src/features/manage-club/funding/components/NewFundingListSection.tsx +++ b/packages/web/src/features/manage-club/funding/components/NewFundingListSection.tsx @@ -6,6 +6,7 @@ import { useRouter } from "next/navigation"; import styled from "styled-components"; +import AsyncBoundary from "@sparcs-clubs/web/common/components/AsyncBoundary"; import IconButton from "@sparcs-clubs/web/common/components/Buttons/IconButton"; import FlexWrapper from "@sparcs-clubs/web/common/components/FlexWrapper"; import FoldableSectionTitle from "@sparcs-clubs/web/common/components/FoldableSectionTitle"; @@ -17,6 +18,8 @@ import { newFundingOrderButtonText, } from "@sparcs-clubs/web/constants/manageClubFunding"; +import useGetNewFundingList from "../services/useGetNewFundingList"; + import NewFundingListTable from "./_atomic/NewFundingListTable"; const NewFundingOrderButtonRow = styled.div` @@ -35,12 +38,20 @@ const NewFundingOrderButtonRow = styled.div` flex-grow: 0; */ `; -const NewFundingListSection: React.FC = () => { +const NewFundingListSection: React.FC<{ clubId: number }> = ({ clubId }) => { const router = useRouter(); const createFundingClick = () => { router.push(`/manage-club/funding/create`); }; + const { + data: newFundingList, + isLoading: isLoadingNewFundingList, + isError: isErrorNewFundingList, + } = useGetNewFundingList({ + clubId, + }); + return ( @@ -51,8 +62,12 @@ const NewFundingListSection: React.FC = () => { {newFundingOrderButtonText} - {/* TODO: ManageClubFundingMainFrame으로부터 주입받은 테이블 데이터 전달하기 */} - + + + ); diff --git a/packages/web/src/features/manage-club/funding/components/_atomic/NewFundingListTable.tsx b/packages/web/src/features/manage-club/funding/components/_atomic/NewFundingListTable.tsx index 38bb0fae1..fcb078d01 100644 --- a/packages/web/src/features/manage-club/funding/components/_atomic/NewFundingListTable.tsx +++ b/packages/web/src/features/manage-club/funding/components/_atomic/NewFundingListTable.tsx @@ -14,16 +14,17 @@ import Tag from "@sparcs-clubs/web/common/components/Tag"; import { numberToKrWon } from "@sparcs-clubs/web/constants/manageClubFunding"; import { FundingTagList } from "@sparcs-clubs/web/constants/tableTagList"; -import { - Funding, - mockupManageFunding, -} from "@sparcs-clubs/web/features/manage-club/services/_mock/mockManageClub"; +import { NewFundingData } from "@sparcs-clubs/web/features/manage-club/funding/types/funding"; import { getTagDetail } from "@sparcs-clubs/web/utils/getTagDetail"; -const columnHelper = createColumnHelper(); +interface NewFundingListTableProps { + newFundingList?: NewFundingData[]; +} + +const columnHelper = createColumnHelper(); const columns = [ - columnHelper.accessor("status", { + columnHelper.accessor("fundingOrderStatusEnumId", { header: "상태", cell: info => { const { color, text } = getTagDetail(info.getValue(), FundingTagList); @@ -31,17 +32,17 @@ const columns = [ }, size: 10, }), - columnHelper.accessor("name", { + columnHelper.accessor("activityName", { header: "활동명", cell: info => info.getValue(), size: 45, }), - columnHelper.accessor("itemName", { + columnHelper.accessor("name", { header: "항목명", cell: info => info.getValue(), size: 15, }), - columnHelper.accessor("requestedAmount", { + columnHelper.accessor("expenditureAmount", { header: "신청 금액", cell: info => `${info.getValue().toLocaleString("ko-KR")}원`, size: 15, @@ -56,10 +57,12 @@ const columns = [ }), ]; -const NewFundingListTable: React.FC = () => { +const NewFundingListTable: React.FC = ({ + newFundingList = [], +}) => { const table = useReactTable({ columns, - data: mockupManageFunding, + data: newFundingList, getCoreRowModel: getCoreRowModel(), enableSorting: false, }); @@ -67,7 +70,7 @@ const NewFundingListTable: React.FC = () => { return ( @@ -75,15 +78,15 @@ const NewFundingListTable: React.FC = () => { {numberToKrWon( - mockupManageFunding.reduce( - (acc, data) => acc + data.requestedAmount, + newFundingList.reduce( + (acc, data) => acc + data.expenditureAmount, 0, ), )} {numberToKrWon( - mockupManageFunding.reduce( + newFundingList.reduce( (acc, data) => acc + (data.approvedAmount ?? 0), 0, ), diff --git a/packages/web/src/features/manage-club/funding/services/useGetNewFundingList.ts b/packages/web/src/features/manage-club/funding/services/useGetNewFundingList.ts new file mode 100644 index 000000000..3706d509b --- /dev/null +++ b/packages/web/src/features/manage-club/funding/services/useGetNewFundingList.ts @@ -0,0 +1,39 @@ +import apiFnd005, { + ApiFnd005RequestQuery, + ApiFnd005ResponseOk, +} from "@sparcs-clubs/interface/api/funding/endpoint/apiFnd005"; +import { useQuery } from "@tanstack/react-query"; + +import { mockupManageFunding } from "@sparcs-clubs/web/features/manage-club/services/_mock/mockManageClub"; +import { + axiosClientWithAuth, + defineAxiosMock, +} from "@sparcs-clubs/web/lib/axios"; + +export const newActivityReportListQueryKey = (clubId: number) => [ + apiFnd005.url(), + clubId, +]; + +const useGetNewFundingList = (query: ApiFnd005RequestQuery) => + useQuery({ + queryKey: newActivityReportListQueryKey(query.clubId), + queryFn: async (): Promise => { + const { data } = await axiosClientWithAuth.get(apiFnd005.url(), { + params: query, + }); + + return apiFnd005.responseBodyMap[200].parse(data); + }, + }); + +export default useGetNewFundingList; + +defineAxiosMock(mock => { + mock.onGet(apiFnd005.url()).reply(() => [ + 200, + { + fundings: mockupManageFunding, + }, + ]); +}); diff --git a/packages/web/src/features/manage-club/funding/types/funding.ts b/packages/web/src/features/manage-club/funding/types/funding.ts index fff68a71e..b174833c3 100644 --- a/packages/web/src/features/manage-club/funding/types/funding.ts +++ b/packages/web/src/features/manage-club/funding/types/funding.ts @@ -1,3 +1,5 @@ +import { FundingOrderStatusEnum } from "@sparcs-clubs/interface/common/enum/funding.enum"; + import { Participant } from "@sparcs-clubs/web/types/participant"; export interface FundingInterface { @@ -62,3 +64,15 @@ export interface FundingInterface { isEtcExpense: boolean; etcExpenseExplanation?: string; } + +export interface PastFundingData { + id: number; + activityName: string; + name: string; + expenditureAmount: number; + approvedAmount?: number; +} + +export interface NewFundingData extends PastFundingData { + fundingOrderStatusEnumId: FundingOrderStatusEnum; +} diff --git a/packages/web/src/features/manage-club/services/_mock/mockManageClub.ts b/packages/web/src/features/manage-club/services/_mock/mockManageClub.ts index 27fdaf8de..3921541b1 100644 --- a/packages/web/src/features/manage-club/services/_mock/mockManageClub.ts +++ b/packages/web/src/features/manage-club/services/_mock/mockManageClub.ts @@ -1,5 +1,6 @@ import { ActivityCertificateOrderStatusEnum } from "@sparcs-clubs/interface/common/enum/activityCertificate.enum"; import { CommonSpaceUsageOrderStatusEnum } from "@sparcs-clubs/interface/common/enum/commonSpace.enum"; +import { FundingOrderStatusEnum } from "@sparcs-clubs/interface/common/enum/funding.enum"; import { PromotionalPrintingOrderStatusEnum, PromotionalPrintingSizeEnum, @@ -7,6 +8,8 @@ import { import { RegistrationApplicationStudentStatusEnum } from "@sparcs-clubs/interface/common/enum/registration.enum"; import { RentalOrderStatusEnum } from "@sparcs-clubs/interface/common/enum/rental.enum"; +import { NewFundingData } from "@sparcs-clubs/web/features/manage-club/funding/types/funding"; + import type { ApiAcf003ResponseOk } from "@sparcs-clubs/interface/api/activity-certificate/endpoint/apiAcf003"; import type { ApiClb004ResponseOK } from "@sparcs-clubs/interface/api/club/endpoint/apiClb004"; import type { ApiClb010ResponseOk } from "@sparcs-clubs/interface/api/club/endpoint/apiClb010"; @@ -188,54 +191,54 @@ const mockupManageMems: ApiReg008ResponseOk["applies"][0][] = [ }, ]; -const mockupManageFunding: Funding[] = [ +const mockupManageFunding: NewFundingData[] = [ { id: 1, - status: 1, + fundingOrderStatusEnumId: FundingOrderStatusEnum.Applied, name: "개발개발한 어떠한 활동", - itemName: "모니터", - requestedAmount: 300000, - approvedAmount: null, + activityName: "모니터", + expenditureAmount: 300000, + approvedAmount: undefined, }, { id: 2, - status: 1, + fundingOrderStatusEnumId: FundingOrderStatusEnum.Applied, name: "개발개발한 어떠한 활동", - itemName: "모니터", - requestedAmount: 300000, - approvedAmount: null, + activityName: "모니터", + expenditureAmount: 300000, + approvedAmount: undefined, }, { id: 3, - status: 2, + fundingOrderStatusEnumId: FundingOrderStatusEnum.Committee, name: "개발개발한 어떠한 활동", - itemName: "모니터", - requestedAmount: 300000, - approvedAmount: null, + activityName: "모니터", + expenditureAmount: 300000, + approvedAmount: undefined, }, { id: 4, - status: 4, + fundingOrderStatusEnumId: FundingOrderStatusEnum.Rejected, name: "개발개발한 어떠한 활동", - itemName: "모니터", - requestedAmount: 300000, - approvedAmount: null, + activityName: "모니터", + expenditureAmount: 300000, + approvedAmount: 0, }, { id: 5, - status: 3, + fundingOrderStatusEnumId: FundingOrderStatusEnum.Approved, name: "개발개발한 어떠한 활동", - itemName: "모니터", - requestedAmount: 300000, + activityName: "모니터", + expenditureAmount: 300000, approvedAmount: 300000, }, { id: 6, - status: 3, - name: "2024년도 봄학기 MT", - itemName: "모니터", - requestedAmount: 300000, - approvedAmount: 0, + fundingOrderStatusEnumId: FundingOrderStatusEnum.Approved, + name: "개발개발한 어떠한 활동", + activityName: "모니터", + expenditureAmount: 300000, + approvedAmount: 100000, }, ]; @@ -616,14 +619,14 @@ const mockupManageCms: ApiCms006ResponseOk = { }; export { - mockupManageReport, + mockClubDescription, + mockClubMembers, + mockupManageAcf, + mockupManageCms, mockupManageFunding, - mockupPastManageFunding, mockupManageMems, - mockupManageAcf, - mockupManageRental, mockupManagePrint, - mockupManageCms, - mockClubDescription, - mockClubMembers, + mockupManageRental, + mockupManageReport, + mockupPastManageFunding, };