From c45553e9c1b1fbb08e92737833e66ba8357004f2 Mon Sep 17 00:00:00 2001 From: Rafael Martins Date: Sun, 2 Aug 2026 16:30:20 -0300 Subject: [PATCH] refactor: hoist regime and duration rules into lib The regime list was declared in three places and the HH:MM mask rules lived inside JourneyForm, so nothing else could reuse either. Also exports the label classes so a fieldset legend can match a Label. Co-Authored-By: Claude Opus 5 --- __tests__/duration.test.ts | 23 +++++++++++++++++ components/atoms/label.tsx | 14 +++-------- components/organisms/journey-form.tsx | 12 ++------- hooks/use-salary-calculator.ts | 10 +++++--- lib/duration.ts | 12 +++++++++ lib/payroll.ts | 36 +++++++++++++++++++++++++++ 6 files changed, 84 insertions(+), 23 deletions(-) diff --git a/__tests__/duration.test.ts b/__tests__/duration.test.ts index 823b62c..4720d09 100644 --- a/__tests__/duration.test.ts +++ b/__tests__/duration.test.ts @@ -4,6 +4,8 @@ import { formatHoursAndMinutes, formatPaddedDuration, formatSignedHoursAndMinutes, + isRealDuration, + minutesToHours, minutesToSeconds, parsePaddedDuration, splitHoursAndMinutes, @@ -65,3 +67,24 @@ describe("minutesToSeconds", () => { expect(minutesToSeconds(90)).toBe(5400); }); }); + +describe("minutesToHours", () => { + it("converts minutes to fractional hours", () => { + expect(minutesToHours(0)).toBe(0); + expect(minutesToHours(528)).toBeCloseTo(8.8, 10); + }); +}); + +describe("isRealDuration", () => { + it("accepts durations inside a day", () => { + expect(isRealDuration("00:00")).toBe(true); + expect(isRealDuration("08:48")).toBe(true); + expect(isRealDuration("23:59")).toBe(true); + }); + + it("rejects impossible hours and minutes", () => { + expect(isRealDuration("24:00")).toBe(false); + expect(isRealDuration("08:60")).toBe(false); + expect(isRealDuration("ab:cd")).toBe(false); + }); +}); diff --git a/components/atoms/label.tsx b/components/atoms/label.tsx index 4080edd..bbce49d 100644 --- a/components/atoms/label.tsx +++ b/components/atoms/label.tsx @@ -1,17 +1,11 @@ import * as React from "react"; import { cn } from "@/lib/utils"; +export const labelClasses = + "flex items-center gap-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-neutral-500 dark:text-neutral-400"; + const Label = React.forwardRef>( - ({ className, ...props }, ref) => ( -