From 410a3204b107907ed84416ce0bd9b2083f29ebab Mon Sep 17 00:00:00 2001 From: l2juhan Date: Mon, 4 May 2026 22:08:46 +0900 Subject: [PATCH 1/2] =?UTF-8?q?[Fix]=20=EC=A3=BC=EA=B0=84/=EC=9B=94?= =?UTF-8?q?=EA=B0=84=20=EC=BA=98=EB=A6=B0=EB=8D=94=20=EC=B4=9D=20=EA=B7=BC?= =?UTF-8?q?=EB=AC=B4=EC=8B=9C=EA=B0=84=C2=B7=EC=98=88=EC=83=81=20=EA=B7=BC?= =?UTF-8?q?=EB=AC=B4=EB=B9=84=20=EA=B3=84=EC=82=B0=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#55)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../worker/WorkerMonthlyCalendarScreen.tsx | 8 +++-- .../worker/WorkerWeeklyCalendarScreen.tsx | 12 +++---- src/utils/workSummary.ts | 31 +++++++++++++++++++ 3 files changed, 40 insertions(+), 11 deletions(-) create mode 100644 src/utils/workSummary.ts diff --git a/src/screens/worker/WorkerMonthlyCalendarScreen.tsx b/src/screens/worker/WorkerMonthlyCalendarScreen.tsx index 38d6034..4c7d14b 100644 --- a/src/screens/worker/WorkerMonthlyCalendarScreen.tsx +++ b/src/screens/worker/WorkerMonthlyCalendarScreen.tsx @@ -20,6 +20,7 @@ import useCorrectionRequest from "../../hooks/worker/useCorrectionRequest"; import { useLogoutHandler } from "../../hooks/common/useLogoutHandler"; import { WorkerStackParamList } from "../../navigation/WorkerStack"; import { colors } from "../../constants/colors"; +import { calculateWorkSummary } from "../../utils/workSummary"; const WorkerMonthlyCalendarScreen: React.FC = ({ navigation }: any) => { const [isDrawerVisible, setIsDrawerVisible] = useState(false); @@ -114,9 +115,10 @@ const WorkerMonthlyCalendarScreen: React.FC = ({ navigation }: any) => { // 월간 요약 계산 (근무 총 시간/급여) const monthLabel = `${month + 1}월`; - const totalMinutes = works.reduce((sum, w) => sum + w.totalWorkMinutes, 0); - const totalHours = Math.round((totalMinutes / 60) * 10) / 10; - const estimatedPay = works.reduce((sum, w) => sum + (w.totalSalary ?? 0), 0); + const { totalHours, estimatedPay } = useMemo( + () => calculateWorkSummary(works), + [works] + ); return ( diff --git a/src/screens/worker/WorkerWeeklyCalendarScreen.tsx b/src/screens/worker/WorkerWeeklyCalendarScreen.tsx index 85d1581..3e982da 100644 --- a/src/screens/worker/WorkerWeeklyCalendarScreen.tsx +++ b/src/screens/worker/WorkerWeeklyCalendarScreen.tsx @@ -31,6 +31,7 @@ import { getWeekLabel, getWeekRange, } from "../../utils/date"; +import { calculateWorkSummary } from "../../utils/workSummary"; type Props = NativeStackScreenProps; @@ -128,14 +129,9 @@ const WorkerWeeklyCalendarScreen: React.FC = ({ navigation }) => { } = useCorrectionRequest(); // 주간 요약 계산 - const totalMinutes = works.reduce( - (sum, w) => sum + w.totalWorkMinutes, - 0 - ); - const totalHours = Math.round((totalMinutes / 60) * 10) / 10; - const estimatedPay = works.reduce( - (sum, w) => sum + (w.totalSalary ?? 0), - 0 + const { totalHours, estimatedPay } = useMemo( + () => calculateWorkSummary(works), + [works] ); return ( diff --git a/src/utils/workSummary.ts b/src/utils/workSummary.ts new file mode 100644 index 0000000..4c75409 --- /dev/null +++ b/src/utils/workSummary.ts @@ -0,0 +1,31 @@ +import type { WorkItem } from "../types/worker.types"; + +export interface WorkSummary { + totalHours: number; + estimatedPay: number; +} + +/** + * 근무 목록에서 요약(총 근무시간, 예상 근무비) 계산. + * - 총 근무시간: COMPLETED 근무의 totalWorkMinutes 합산 + * - 예상 근무비: COMPLETED는 totalSalary, SCHEDULED는 hourlyWage × 시간으로 추정 (DELETED 제외) + * 세금/보험은 고려하지 않는 단순 추정치. + */ +export const calculateWorkSummary = (works: WorkItem[]): WorkSummary => { + let completedMinutes = 0; + let estimatedPay = 0; + + for (const work of works) { + if (work.status === "COMPLETED") { + completedMinutes += work.totalWorkMinutes; + estimatedPay += work.totalSalary ?? 0; + } else if (work.status === "SCHEDULED") { + const hourlyWage = work.hourlyWage ?? 0; + estimatedPay += Math.round((hourlyWage * work.totalWorkMinutes) / 60); + } + } + + const totalHours = Math.round((completedMinutes / 60) * 10) / 10; + + return { totalHours, estimatedPay }; +}; From 9b8785265fde6503dd167ddec52e9852ea413c24 Mon Sep 17 00:00:00 2001 From: l2juhan Date: Wed, 6 May 2026 17:13:56 +0900 Subject: [PATCH 2/2] =?UTF-8?q?[Fix]=20=EB=B0=B1=EC=97=94=EB=93=9C=20#177?= =?UTF-8?q?=20=EB=B0=98=EC=98=81:=20SCHEDULED=20totalSalary=20=EC=A7=81?= =?UTF-8?q?=EC=A0=91=20=EC=82=AC=EC=9A=A9=EC=9C=BC=EB=A1=9C=20=EB=8B=A8?= =?UTF-8?q?=EC=88=9C=ED=99=94=20(#55)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/workSummary.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/utils/workSummary.ts b/src/utils/workSummary.ts index 4c75409..af2314c 100644 --- a/src/utils/workSummary.ts +++ b/src/utils/workSummary.ts @@ -6,23 +6,22 @@ export interface WorkSummary { } /** - * 근무 목록에서 요약(총 근무시간, 예상 근무비) 계산. + * 근무 목록에서 요약(총 근무시간, 예상 근무비) 계산. DELETED 근무는 두 값 모두 제외. * - 총 근무시간: COMPLETED 근무의 totalWorkMinutes 합산 - * - 예상 근무비: COMPLETED는 totalSalary, SCHEDULED는 hourlyWage × 시간으로 추정 (DELETED 제외) - * 세금/보험은 고려하지 않는 단순 추정치. + * - 예상 근무비: COMPLETED + SCHEDULED의 totalSalary 합산 + * (백엔드가 SCHEDULED도 totalSalary를 계산해 반환 — PayCheck-backend#177) */ export const calculateWorkSummary = (works: WorkItem[]): WorkSummary => { let completedMinutes = 0; let estimatedPay = 0; for (const work of works) { + if (work.status === "DELETED") continue; + if (work.status === "COMPLETED") { completedMinutes += work.totalWorkMinutes; - estimatedPay += work.totalSalary ?? 0; - } else if (work.status === "SCHEDULED") { - const hourlyWage = work.hourlyWage ?? 0; - estimatedPay += Math.round((hourlyWage * work.totalWorkMinutes) / 60); } + estimatedPay += work.totalSalary ?? 0; } const totalHours = Math.round((completedMinutes / 60) * 10) / 10;