4.5 KiB
You are a Senior Full Stack Engineer.
Project: Training Management System (TMS)
Current task: Change training hours storage and display from decimal hours to duration minutes.
Requirement: Training duration must be stored and calculated as hours and minutes, not decimal hours.
Important constraints:
- Do NOT use AM/PM.
- Do NOT use clock TimePicker.
- Do NOT store Date object.
- Keep Thai UI.
- Keep responsive/mobile behavior.
- Minimal-impact changes only.
Business examples:
- 01:45 = 1 ชั่วโมง 45 นาที
- 00:15 = 15 นาที
- 02:00 = 2 ชั่วโมง
- 30:00 = 30 ชั่วโมง
Recommended storage: Store duration as total minutes.
Examples:
- 01:45 -> 105
- 00:15 -> 15
- 02:00 -> 120
- 30:00 -> 1800
Part 1: Database
Check current fields:
- submittedHours
- approvedHours
- targetHours
- kHours
- sHours
- aHours
If current DB stores decimal hours, add new minute-based fields if needed:
training_records:
- submittedMinutes integer
- approvedMinutes integer
employee_training_targets:
- totalTargetMinutes integer
- kTargetMinutes integer
- sTargetMinutes integer
- aTargetMinutes integer
training_policy:
- totalTargetMinutes integer
- kTargetMinutes integer
- sTargetMinutes integer
- aTargetMinutes integer
Important: Do not drop old decimal fields yet. Keep old fields for compatibility during migration.
Migration:
- Convert old decimal hours to minutes: minutes = ROUND(hours * 60)
Part 2: Duration Picker UI
Create or update component:
src/components/ui/duration-picker.tsx
Props:
- valueMinutes: number | null
- onChange: (minutes: number | null) => void
- maxHours?: number
- minuteStep?: number
- disabled?: boolean
UI:
- Two dropdowns:
- ชั่วโมง
- นาที
Hour options:
- 00 to 30
Minute options:
- 00
- 15
- 30
- 45
Display:
- --:-- when empty
- 00:15
- 01:45
- 02:00
- 30:00
Do not display:
- AM
- PM
Part 3: Form Behavior
In Create/Edit Training Record form:
Field:
- จำนวนชั่วโมงอบรม *
Use DurationPicker.
Save:
- submittedMinutes
Validation:
- required
-
0 minutes
- <= 1800 minutes
Thai messages:
- กรุณาระบุจำนวนชั่วโมงอบรม
- จำนวนชั่วโมงอบรมต้องมากกว่า 0 นาที
- จำนวนชั่วโมงอบรมต้องไม่เกิน 30 ชั่วโมง
Part 4: Display Formatting
Create helper functions:
formatDurationThai(minutes: number): string
Examples:
- 15 -> 15 นาที
- 60 -> 1 ชั่วโมง
- 105 -> 1 ชั่วโมง 45 นาที
- 120 -> 2 ชั่วโมง
- 1800 -> 30 ชั่วโมง
formatDurationHHMM(minutes: number): string
Examples:
- 15 -> 00:15
- 105 -> 01:45
- 120 -> 02:00
Part 5: Calculations
All dashboard/report calculations should use minutes:
- approvedMinutes
- pendingMinutes
- rejectedMinutes
- targetMinutes
When summing:
- SUM(minutes)
Do not sum decimal hours.
Part 6: K/S/A Targets
Targets should support minutes too.
Examples:
- K = 12 ชั่วโมง 30 นาที -> 750 minutes
- S = 10 ชั่วโมง -> 600 minutes
- A = 7 ชั่วโมง 30 นาที -> 450 minutes
Part 7: Backward Compatibility
If minute field is null:
- fallback to old decimal hour field: minutes = ROUND(hours * 60)
Use helper: getDurationMinutes(minutesField, legacyHoursField)
Part 8: Update all UI locations
Update:
- Training Record table
- Training Detail
- HRD Review
- Dashboard
- K/S/A Progress
- Employee Directory
- Reports
- Export Excel
- Export PDF
Display examples:
- 1 ชั่วโมง 45 นาที
- 15 นาที
- 2 ชั่วโมง
Part 9: Output Review File
Create: docs/management-change-duration-minutes-review.md
Include:
- Summary
- Database Changes
- Migration Strategy
- Duration Picker UI
- Storage Behavior
- Display Formatting
- Dashboard Impact
- Reports Impact
- Backward Compatibility
- Manual Test Checklist
- Known Limitations
Manual Test Checklist:
- 00:15 saves 15 minutes.
- 01:45 saves 105 minutes.
- 02:00 saves 120 minutes.
- 30:00 saves 1800 minutes.
- 00:00 is blocked.
- More than 30:00 is 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.
Return:
- Complete code changes with file paths.
- Migration command if required.
- Review file.