4.0 KiB
Management Change Duration Minutes Review
1. Summary
This round starts the migration of training duration handling from decimal hours to total minutes with backward compatibility. The core training-records create/edit/review flow now accepts minute-based values, stores both minute and legacy decimal fields, and displays Thai duration text in the main training record UI.
2. Database Changes
Added new nullable minute-based fields:
training_records.submitted_minutestraining_records.approved_minutestraining_policies.total_target_minutestraining_policies.k_target_minutestraining_policies.s_target_minutestraining_policies.a_target_minutesemployee_training_targets.total_target_minutesemployee_training_targets.k_target_minutesemployee_training_targets.s_target_minutesemployee_training_targets.a_target_minutes
Migration file:
drizzle/0012_change_duration_minutes.sql
3. Migration Strategy
The migration keeps legacy decimal columns and backfills new minute columns using:
ROUND(hours * 60)ROUND(approved_hours * 60)ROUND(total_hours * 60)ROUND(k_hours * 60)ROUND(s_hours * 60)ROUND(a_hours * 60)
This allows old code paths to keep working while new UI/API paths move to minutes.
4. Duration Picker UI
Added:
src/components/ui/duration-picker.tsx
Behavior:
- two dropdowns:
ชั่วโมงandนาที - hour range
00to30 - minute step
00,15,30,45 - no AM/PM
- no
Datestorage - helper display in
HH:MM
5. Storage Behavior
Updated the training record flow so that:
- form submit sends
submittedMinutes - review submit sends
approvedMinutes - route handlers write new minute fields
- route handlers still write decimal
hoursandapproved_hoursfor compatibility
The compatibility helper is:
getDurationMinutes(minutesField, legacyHoursField)
6. Display Formatting
Added shared helpers in:
src/features/training-records/utils/time-utils.ts
Helpers:
formatDurationThai(minutes)formatDurationHHMM(minutes)decimalHoursToMinutes(hours)minutesToDecimalHours(minutes)getDurationMinutes(minutesField, legacyHoursField)
Main updated displays:
- training record form
- training record review page
- training record table
- pending review table
7. Dashboard Impact
Not fully migrated yet.
Current state:
- the training record source data now exposes
submitted_minutesandapproved_minutes - dashboard aggregate logic in
src/features/overview/server/overview-data.tsstill sums legacy decimal hour columns
Required next step:
- switch aggregate expressions to minute-first calculations with decimal fallback only when minute fields are null
8. Reports Impact
Not fully migrated yet.
Current state:
- training record API now exposes minute fields
- report dataset and exports still primarily rely on decimal hour aggregations
Required next step:
- update
src/features/reports/server/report-data.tsand export formatters to sum/display minutes consistently
9. Backward Compatibility
Compatibility is preserved by:
- keeping old decimal DB columns
- still writing
hours/approved_hours - deriving minute display from minute columns first, then decimal fallback
This reduces breakage during staged migration.
10. Manual Test Checklist
00:15saves15minutes.01:45saves105minutes.02:00saves120minutes.30:00saves1800minutes.00:00is blocked.- More than
30:00is blocked. - Training history shows
1 ชั่วโมง 45 นาที. - Dashboard sums minutes correctly.
- Reports export minutes correctly.
- Legacy decimal hours still display correctly.
- No AM/PM appears anywhere.
11. Known Limitations
- Overview, reports, employee directory, notifications, and audit log text are not fully migrated to minute-first calculations yet.
- Training policy and employee target UI still use hour-based contracts even though DB minute columns are prepared.
- Export Excel/PDF paths were not updated in this round.