Skip to content

Commit

Permalink
Merge pull request #1367 from academic-relations/1358-impl-executive-…
Browse files Browse the repository at this point in the history
…activity-report-charged-page

impl executive activity report charged page
  • Loading branch information
wjeongchoi authored Feb 4, 2025
2 parents d40898b + bef61e7 commit ac90589
Show file tree
Hide file tree
Showing 13 changed files with 505 additions and 71 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"use client";

import React, { useEffect, useState } from "react";

import Custom404 from "@sparcs-clubs/web/app/not-found";
import AsyncBoundary from "@sparcs-clubs/web/common/components/AsyncBoundary";
import LoginRequired from "@sparcs-clubs/web/common/frames/LoginRequired";
import { useAuth } from "@sparcs-clubs/web/common/providers/AuthContext";
import ExecutiveActivityReportChargedFrame from "@sparcs-clubs/web/features/executive/activity-report/frames/ExecutiveActivityReportChargedFrame";

const ExecutiveActivityReport = () => {
const { isLoggedIn, login, profile } = useAuth();
const [loading, setLoading] = useState(true);

useEffect(() => {
if (isLoggedIn !== undefined || profile !== undefined) {
setLoading(false);
}
}, [isLoggedIn, profile]);

if (loading) {
return <AsyncBoundary isLoading={loading} isError />;
}

if (!isLoggedIn) {
return <LoginRequired login={login} />;
}

if (profile?.type !== "executive") {
return <Custom404 />;
}

return <ExecutiveActivityReportChargedFrame />;
};

export default ExecutiveActivityReport;
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React, { useMemo } from "react";

import { ApiAct028ResponseOk } from "@sparcs-clubs/interface/api/activity/endpoint/apiAct028";
import {
createColumnHelper,
getCoreRowModel,
useReactTable,
} from "@tanstack/react-table";

import FlexWrapper from "@sparcs-clubs/web/common/components/FlexWrapper";
import MoreDetailTitle from "@sparcs-clubs/web/common/components/MoreDetailTitle";
import Table from "@sparcs-clubs/web/common/components/Table";
import Tag from "@sparcs-clubs/web/common/components/Tag";
import {
ActStatusTagList,
ActTypeTagList,
} from "@sparcs-clubs/web/constants/tableTagList";
import { formatDateTime } from "@sparcs-clubs/web/utils/Date/formatDate";
import { getTagDetail } from "@sparcs-clubs/web/utils/getTagDetail";

import { sortActivitiesByStatusAndCommentedDate } from "../utils/sortActivities";

const columnHelper =
createColumnHelper<ApiAct028ResponseOk["activities"][number]>();
const columns = [
columnHelper.accessor("name", {
header: "활동명",
cell: info => info.getValue(),
size: 400,
}),
columnHelper.accessor("activityTypeEnum", {
header: "활동 분류",
cell: info => {
const { color, text } = getTagDetail(info.getValue(), ActTypeTagList);
return <Tag color={color}>{text}</Tag>;
},
size: 248,
}),
columnHelper.accessor("commentedAt", {
header: "검토 일시",
cell: info => {
const date = info.getValue();
return date ? formatDateTime(date) : "-";
},
size: 220,
}),
columnHelper.accessor(row => row.commentedExecutive?.name, {
header: "최종 검토자",
cell: info => info.getValue() || "-",
size: 120,
}),
columnHelper.accessor("activityStatusEnum", {
header: "상태",
cell: info => {
const { color, text } = getTagDetail(info.getValue(), ActStatusTagList);
return <Tag color={color}>{text}</Tag>;
},
size: 120,
}),
];

const ActivityReportChargedClubTable: React.FC<{
activities: ApiAct028ResponseOk["activities"];
}> = ({ activities }) => {
const { length } = activities;

const sortedActivities = useMemo(
() => sortActivitiesByStatusAndCommentedDate(activities),
[activities],
);

const table = useReactTable({
data: sortedActivities,
columns,
getCoreRowModel: getCoreRowModel(),
enableSorting: false,
});

return (
<FlexWrapper direction="column" gap={16}>
<MoreDetailTitle
title={`${activities[0]?.club?.name || ""} (${length}개)`}
moreDetail="내역 더보기"
moreDetailPath={`/executive/activity-report/club/${activities[0]?.club?.id}`}
/>
<Table
table={table}
rowLink={row => `/executive/activity-report/${row.id}`}
/>
</FlexWrapper>
);
};

export default ActivityReportChargedClubTable;
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React, { useMemo } from "react";

import { ApiAct028ResponseOk } from "@sparcs-clubs/interface/api/activity/endpoint/apiAct028";
import {
createColumnHelper,
getCoreRowModel,
useReactTable,
} from "@tanstack/react-table";

import FlexWrapper from "@sparcs-clubs/web/common/components/FlexWrapper";
import Table from "@sparcs-clubs/web/common/components/Table";
import Tag from "@sparcs-clubs/web/common/components/Tag";
import Typography from "@sparcs-clubs/web/common/components/Typography";
import {
ActStatusTagList,
ActTypeTagList,
} from "@sparcs-clubs/web/constants/tableTagList";
import { formatDateTime } from "@sparcs-clubs/web/utils/Date/formatDate";
import { getTagDetail } from "@sparcs-clubs/web/utils/getTagDetail";

import { sortActivitiesByStatusAndCommentedDate } from "../utils/sortActivities";

const columnHelper =
createColumnHelper<ApiAct028ResponseOk["activities"][number]>();
const columns = [
columnHelper.accessor("club.name", {
header: "동아리",
cell: info => info.getValue(),
size: 200,
}),
columnHelper.accessor("name", {
header: "활동명",
cell: info => info.getValue(),
size: 252,
}),
columnHelper.accessor("activityTypeEnum", {
header: "활동 분류",
cell: info => {
const { color, text } = getTagDetail(info.getValue(), ActTypeTagList);
return <Tag color={color}>{text}</Tag>;
},
size: 248,
}),
columnHelper.accessor("commentedAt", {
header: "검토 일시",
cell: info => {
const date = info.getValue();
return date ? formatDateTime(date) : "-";
},
size: 220,
}),
columnHelper.accessor(row => row.chargedExecutive?.name, {
header: "담당자",
cell: info =>
info.getValue() || (
<Typography color="GRAY.300" fs={16} lh={24}>
(미정)
</Typography>
),
size: 120,
}),
columnHelper.accessor("activityStatusEnum", {
header: "상태",
cell: info => {
const { color, text } = getTagDetail(info.getValue(), ActStatusTagList);
return <Tag color={color}>{text}</Tag>;
},
size: 120,
}),
];

const ActivityReportChargedOtherTable: React.FC<{
activities: ApiAct028ResponseOk["activities"];
}> = ({ activities }) => {
const { length } = activities;

const sortedActivities = useMemo(
() => sortActivitiesByStatusAndCommentedDate(activities),
[activities],
);

const table = useReactTable({
data: sortedActivities,
columns,
getCoreRowModel: getCoreRowModel(),
enableSorting: false,
});

return (
<FlexWrapper direction="column" gap={16}>
<Typography fs={20} lh={24} fw="MEDIUM">
담당자가 아님 ({length}개)
</Typography>
<Table
table={table}
rowLink={row => `/executive/activity-report/${row.id}`}
/>
</FlexWrapper>
);
};

export default ActivityReportChargedOtherTable;
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from "react";

import { ApiAct028ResponseOk } from "@sparcs-clubs/interface/api/activity/endpoint/apiAct028";
import { ActivityStatusEnum } from "@sparcs-clubs/interface/common/enum/activity.enum";

import ActivityReportStatisticContent from "./_atomic/ActivityReportStatisticContent";

const ActivityReportChargedStatistic: React.FC<{
activities: ApiAct028ResponseOk["activities"];
}> = ({ activities }) => {
const pendingTotalCount = activities.filter(
activity => activity.activityStatusEnum === ActivityStatusEnum.Applied,
).length;
const approvedTotalCount = activities.filter(
activity => activity.activityStatusEnum === ActivityStatusEnum.Approved,
).length;
const rejectedTotalCount = activities.filter(
activity => activity.activityStatusEnum === ActivityStatusEnum.Rejected,
).length;

return (
<ActivityReportStatisticContent
pendingTotalCount={pendingTotalCount}
approvedTotalCount={approvedTotalCount}
rejectedTotalCount={rejectedTotalCount}
/>
);
};

export default ActivityReportChargedStatistic;
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const ActivityReportClubStatistic: React.FC<
acc + (item.activityStatusEnum === ActivityStatusEnum.Rejected ? 1 : 0),
0,
);
const reviewdTotalCount = approvedTotalCount + rejectedTotalCount;
const reviewedTotalCount = approvedTotalCount + rejectedTotalCount;
const totalCount =
pendingTotalCount + approvedTotalCount + rejectedTotalCount;

Expand All @@ -67,8 +67,8 @@ const ActivityReportClubStatistic: React.FC<
검토율
</Typography>
<Typography fs={16} lh={20}>
{reviewdTotalCount}개 / {totalCount}개 (
{((reviewdTotalCount / totalCount) * 100).toFixed(1)}%)
{reviewedTotalCount}개 / {totalCount}개 (
{((reviewedTotalCount / totalCount) * 100).toFixed(1)}%)
</Typography>
</FlexWrapper>
<FlexWrapper direction="row" gap={20}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import React from "react";

import { Divider } from "@mui/material";
import { ApiAct023ResponseOk } from "@sparcs-clubs/interface/api/activity/endpoint/apiAct023";

import Card from "@sparcs-clubs/web/common/components/Card";
import FlexWrapper from "@sparcs-clubs/web/common/components/FlexWrapper";
import Tag from "@sparcs-clubs/web/common/components/Tag";
import Toggle from "@sparcs-clubs/web/common/components/Toggle";
import Typography from "@sparcs-clubs/web/common/components/Typography";
import { TotalContentsContainer } from "@sparcs-clubs/web/features/executive/register-member/components/StatusInfoFrame";
import ActivityReportStatisticContent from "./_atomic/ActivityReportStatisticContent";

interface ActivityReportStatisticProps {
activities: ApiAct023ResponseOk;
Expand All @@ -29,47 +23,13 @@ const ActivityReportStatistic: React.FC<ActivityReportStatisticProps> = ({
(acc, item) => acc + item.rejectedActivitiesCount,
0,
);
const reviewdTotalCount = approvedTotalCount + rejectedTotalCount;
const totalCount =
pendingTotalCount + approvedTotalCount + rejectedTotalCount;

return (
<Card gap={16} padding="16px" outline>
<Toggle label={<Typography>활동 보고서 통계</Typography>}>
<FlexWrapper direction="column" gap={8} style={{ width: "100%" }}>
<FlexWrapper direction="row" gap={20}>
<Typography fw="MEDIUM" fs={16} lh={20}>
검토율
</Typography>
<Typography>
{reviewdTotalCount}개 / {totalCount}개 (
{((reviewdTotalCount / totalCount) * 100).toFixed(1)}%)
</Typography>
</FlexWrapper>
<Divider />
<FlexWrapper direction="row" gap={40}>
<FlexWrapper direction="row" gap={20}>
<Tag color="GRAY">대기</Tag>
<TotalContentsContainer>
{pendingTotalCount}
</TotalContentsContainer>
</FlexWrapper>
<FlexWrapper direction="row" gap={20}>
<Tag color="GREEN">승인</Tag>
<TotalContentsContainer>
{approvedTotalCount}
</TotalContentsContainer>
</FlexWrapper>
<FlexWrapper direction="row" gap={20}>
<Tag color="RED">반려</Tag>
<TotalContentsContainer>
{rejectedTotalCount}
</TotalContentsContainer>
</FlexWrapper>
</FlexWrapper>
</FlexWrapper>
</Toggle>
</Card>
<ActivityReportStatisticContent
pendingTotalCount={pendingTotalCount}
approvedTotalCount={approvedTotalCount}
rejectedTotalCount={rejectedTotalCount}
/>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,11 @@ const ExecutiveActivityChargedTable: React.FC<
<Typography fs={16} lh={20} style={{ flex: 1, textAlign: "right" }}>
{countString}
</Typography>
<Table table={table} minWidth={800} />
<Table
table={table}
minWidth={800}
rowLink={row => `/executive/activity-report/charged/${row.executiveId}`}
/>
</FlexWrapper>
);
};
Expand Down
Loading

0 comments on commit ac90589

Please sign in to comment.