Files
alla-tms/plans/change-duration-minutes.md
2026-07-16 09:53:14 +07:00

264 lines
4.5 KiB
Markdown

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:
1. ชั่วโมง
2. นาที
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:
1. Summary
2. Database Changes
3. Migration Strategy
4. Duration Picker UI
5. Storage Behavior
6. Display Formatting
7. Dashboard Impact
8. Reports Impact
9. Backward Compatibility
10. Manual Test Checklist
11. 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.