commit
This commit is contained in:
263
plans/change-duration-minutes.md
Normal file
263
plans/change-duration-minutes.md
Normal file
@@ -0,0 +1,263 @@
|
||||
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.
|
||||
Reference in New Issue
Block a user