Teren-app/REPORTS_FRONTEND_REWORK_PLAN.md
2026-01-02 12:32:20 +01:00

529 lines
16 KiB
Markdown

# Reports Frontend Rework Plan
## Overview
This plan outlines the modernization of Reports frontend pages (`Index.vue` and `Show.vue`) using shadcn-vue components and AppCard containers, following the same patterns established in the Settings pages rework.
## Current State Analysis
### Reports/Index.vue (30 lines)
**Current Implementation:**
- Simple grid layout with native divs
- Report cards: `border rounded-lg p-4 bg-white shadow-sm hover:shadow-md`
- Grid: `md:grid-cols-2 lg:grid-cols-3`
- Each card shows: name (h2), description (p), Link to report
- **No shadcn-vue components used**
**Identified Issues:**
- Native HTML/Tailwind instead of shadcn-vue Card
- Inconsistent with Settings pages styling
- No icons for visual interest
- Basic hover effects only
### Reports/Show.vue (314 lines)
**Current Implementation:**
- Complex page with filters, export buttons, and data table
- Header section: title, description, export buttons (lines 190-196)
- Buttons: `px-3 py-2 rounded bg-gray-200 hover:bg-gray-300`
- Filter section: grid layout `md:grid-cols-4` (lines 218-270)
- Native inputs: `border rounded px-2 py-1`
- Native selects: `border rounded px-2 py-1`
- DatePicker component (already working)
- Filter buttons: Apply (`bg-indigo-600`) and Reset (`bg-gray-100`)
- Data table: DataTableServer component (lines 285-300)
- Formatting functions: formatNumberEU, formatDateEU, formatDateTimeEU, formatCell
**Identified Issues:**
- No Card containers for sections
- Native buttons instead of shadcn Button
- Native input/select elements instead of shadcn Input/Select
- No visual separation between sections
- Filter section could be extracted to partial
## Target Architecture
### Pattern Reference from Settings Pages
**Settings/Index.vue Pattern:**
```vue
<Card class="hover:shadow-lg transition-shadow">
<CardHeader>
<div class="flex items-center gap-2">
<component :is="icon" class="h-5 w-5 text-muted-foreground" />
<CardTitle>Title</CardTitle>
</div>
<CardDescription>Description</CardDescription>
</CardHeader>
<CardContent>
<Button variant="ghost">Action </Button>
</CardContent>
</Card>
```
**Settings/Archive/Index.vue Pattern:**
- Uses AppCard for main container
- Extracted partials: ArchiveRuleCard, CreateRuleForm, EditRuleForm
- Alert components for warnings
- Badge components for status indicators
## Implementation Plan
### Phase 1: Reports/Index.vue Rework (Simple)
**Goal:** Replace native divs with shadcn-vue Card components, add icons
**Changes:**
1. **Import shadcn-vue components:**
```js
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/Components/ui/card";
import { Button } from "@/Components/ui/button";
import { BarChart3, FileText, Activity, Users, TrendingUp, Calendar } from "lucide-vue-next";
```
2. **Add icon mapping for reports:**
```js
const reportIcons = {
'contracts': FileText,
'field': TrendingUp,
'activities': Activity,
// fallback icon
default: BarChart3,
};
function getReportIcon(category) {
return reportIcons[category] || reportIcons.default;
}
```
3. **Replace report card structure:**
- Remove native `<div class="border rounded-lg p-4 bg-white shadow-sm hover:shadow-md">`
- Use `<Card class="hover:shadow-lg transition-shadow cursor-pointer">`
- Structure:
```vue
<Card>
<CardHeader>
<div class="flex items-center gap-2">
<component :is="getReportIcon(report.category)" class="h-5 w-5 text-muted-foreground" />
<CardTitle>{{ report.name }}</CardTitle>
</div>
<CardDescription>{{ report.description }}</CardDescription>
</CardHeader>
<CardContent>
<Link :href="route('reports.show', report.slug)">
<Button variant="ghost" size="sm" class="w-full justify-start">
Odpri →
</Button>
</Link>
</CardContent>
</Card>
```
4. **Update page header:**
- Wrap in proper container with consistent spacing
- Match Settings/Index.vue header style
**Estimated Changes:**
- Lines: 30 → ~65 lines (with imports and icon logic)
- Files modified: 1 (Index.vue)
- Files created: 0
**Risk Level:** Low (simple page, straightforward replacement)
---
### Phase 2: Reports/Show.vue Rework - Structure (Medium)
**Goal:** Add Card containers for sections, replace native buttons
**Changes:**
1. **Import shadcn-vue components:**
```js
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/Components/ui/card";
import { Button } from "@/Components/ui/button";
import { Input } from "@/Components/ui/input";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/Components/ui/select";
import { Label } from "@/Components/ui/label";
import { Badge } from "@/Components/ui/badge";
import { Separator } from "@/Components/ui/separator";
import { Download, Filter, RotateCcw } from "lucide-vue-next";
```
2. **Wrap header + export buttons in Card:**
```vue
<Card class="mb-6">
<CardHeader>
<div class="flex items-start justify-between">
<div>
<CardTitle>{{ name }}</CardTitle>
<CardDescription v-if="description">{{ description }}</CardDescription>
</div>
<div class="flex gap-2">
<Button variant="outline" size="sm" @click="exportFile('csv')">
<Download class="mr-2 h-4 w-4" />
CSV
</Button>
<Button variant="outline" size="sm" @click="exportFile('pdf')">
<Download class="mr-2 h-4 w-4" />
PDF
</Button>
<Button variant="outline" size="sm" @click="exportFile('xlsx')">
<Download class="mr-2 h-4 w-4" />
Excel
</Button>
</div>
</div>
</CardHeader>
</Card>
```
3. **Wrap filters in Card:**
```vue
<Card class="mb-6">
<CardHeader>
<div class="flex items-center gap-2">
<Filter class="h-5 w-5 text-muted-foreground" />
<CardTitle>Filtri</CardTitle>
</div>
</CardHeader>
<CardContent>
<!-- Filter grid here -->
<div class="grid gap-4 md:grid-cols-4">
<!-- Filter inputs -->
</div>
<Separator class="my-4" />
<div class="flex gap-2">
<Button @click="applyFilters">
<Filter class="mr-2 h-4 w-4" />
Prikaži
</Button>
<Button variant="outline" @click="resetFilters">
<RotateCcw class="mr-2 h-4 w-4" />
Ponastavi
</Button>
</div>
</CardContent>
</Card>
```
4. **Wrap DataTableServer in Card:**
```vue
<Card>
<CardHeader>
<CardTitle>Rezultati</CardTitle>
<CardDescription>
Skupaj {{ meta?.total || 0 }} {{ meta?.total === 1 ? 'rezultat' : 'rezultatov' }}
</CardDescription>
</CardHeader>
<CardContent>
<DataTableServer
<!-- props -->
/>
</CardContent>
</Card>
```
5. **Replace all native buttons with shadcn Button:**
- Export buttons: `variant="outline" size="sm"`
- Apply filter button: default variant
- Reset button: `variant="outline"`
**Estimated Changes:**
- Lines: 314 → ~350 lines (with imports and Card wrappers)
- Files modified: 1 (Show.vue)
- Files created: 0
- **Keep formatting functions unchanged** (working correctly)
**Risk Level:** Low-Medium (more complex but no logic changes)
---
### Phase 3: Reports/Show.vue - Replace Native Inputs (Medium)
**Goal:** Replace native input/select elements with shadcn-vue components
**Changes:**
1. **Replace date inputs:**
```vue
<!-- Keep DatePicker as-is (already working) -->
<div class="space-y-2">
<Label>{{ inp.label || inp.key }}</Label>
<DatePicker
v-model="filters[inp.key]"
format="dd.MM.yyyy"
placeholder="Izberi datum"
/>
</div>
```
2. **Replace text/number inputs:**
```vue
<div class="space-y-2">
<Label>{{ inp.label || inp.key }}</Label>
<Input
v-model="filters[inp.key]"
:type="inp.type === 'integer' ? 'number' : 'text'"
placeholder="Vnesi vrednost"
/>
</div>
```
3. **Replace select inputs (user/client):**
```vue
<div class="space-y-2">
<Label>{{ inp.label || inp.key }}</Label>
<Select v-model="filters[inp.key]">
<SelectTrigger>
<SelectValue placeholder="— brez —" />
</SelectTrigger>
<SelectContent>
<SelectItem :value="null">— brez —</SelectItem>
<SelectItem v-for="u in userOptions" :key="u.id" :value="u.id">
{{ u.name }}
</SelectItem>
</SelectContent>
</Select>
<div v-if="userLoading" class="text-xs text-muted-foreground">Nalagam…</div>
</div>
```
4. **Update filter grid layout:**
- Change from `md:grid-cols-4` to `md:grid-cols-2 lg:grid-cols-4`
- Use `space-y-2` for label/input spacing
- Consistent gap: `gap-4`
**Estimated Changes:**
- Lines: ~350 → ~380 lines (shadcn Input/Select have more markup)
- Files modified: 1 (Show.vue)
- Files created: 0
**Risk Level:** Medium (v-model binding changes, test thoroughly)
---
### Phase 4: Optional - Extract Filter Section Partial (Optional)
**Goal:** Reduce Show.vue complexity by extracting filter logic
**Decision Criteria:**
- If filter section exceeds ~80 lines → extract to partial
- If multiple filter types need separate handling → extract
**Potential Partial Structure:**
```
resources/js/Pages/Reports/Partials/
FilterSection.vue
```
**FilterSection.vue:**
- Props: `inputs`, `filters` (reactive object), `userOptions`, `clientOptions`, `loading states`
- Emits: `@apply`, `@reset`
- Contains: entire filter grid + buttons
**Benefits:**
- Show.vue reduced from ~380 lines to ~300 lines
- Filter logic isolated and reusable
- Easier to maintain filter types
**Risks:**
- Adds complexity with props/emits
- Might not be worth it if filter logic is simple
**Recommendation:** Evaluate after Phase 3 completion. If filter section is clean and under 80 lines, skip this phase.
---
## Component Inventory
### shadcn-vue Components Needed
**Already Installed (verify):**
- Card, CardHeader, CardTitle, CardDescription, CardContent
- Button
- Input
- Select, SelectTrigger, SelectValue, SelectContent, SelectItem
- Label
- Badge
- Separator
**Need to Check:**
- lucide-vue-next icons (Download, Filter, RotateCcw, BarChart3, FileText, Activity, TrendingUp, Calendar)
### Custom Components
- AppCard (if needed for consistency)
- DatePicker (already working, keep as-is)
- DataTableServer (keep as-is)
---
## Testing Checklist
### Reports/Index.vue Testing:
- [ ] Cards display with correct icons
- [ ] Card hover effects work
- [ ] Links navigate to correct report
- [ ] Grid layout responsive (2 cols MD, 3 cols LG)
- [ ] Icons match report categories
### Reports/Show.vue Testing:
- [ ] Header Card displays title, description, export buttons
- [ ] Export buttons work (CSV, PDF, Excel)
- [ ] Filter Card displays all filter inputs correctly
- [ ] Date filters use DatePicker component
- [ ] User/Client selects load options async
- [ ] Apply filters button triggers report refresh
- [ ] Reset button clears all filters
- [ ] DataTableServer Card displays results
- [ ] Formatting functions work (dates, numbers, currencies)
- [ ] Pagination works
- [ ] All 6 reports render correctly:
- [ ] active-contracts
- [ ] field-jobs-completed
- [ ] decisions-counts
- [ ] segment-activity-counts
- [ ] actions-decisions-counts
- [ ] activities-per-period
---
## Implementation Order
### Step 1: Reports/Index.vue (30 min)
1. Import shadcn-vue components + icons
2. Add icon mapping function
3. Replace native divs with Card structure
4. Test navigation and layout
5. Verify responsive grid
### Step 2: Reports/Show.vue - Structure (45 min)
1. Import shadcn-vue components + icons
2. Wrap header + exports in Card
3. Wrap filters in Card
4. Wrap DataTableServer in Card
5. Replace all native buttons
6. Test all 6 reports
### Step 3: Reports/Show.vue - Inputs (60 min)
1. Replace text/number inputs with shadcn Input
2. Replace select inputs with shadcn Select
3. Add Label components
4. Test v-model bindings
5. Test async user/client loading
6. Test filter apply/reset
7. Verify all filter types work
### Step 4: Optional Partial Extraction (30 min, if needed)
1. Create FilterSection.vue partial
2. Move filter logic to partial
3. Set up props/emits
4. Test with all reports
### Step 5: Final Testing (30 min)
1. Test complete workflow (Index → Show → Filters → Export)
2. Verify all 6 reports
3. Test responsive layouts (mobile, tablet, desktop)
4. Check formatting consistency
5. Verify no regressions
**Total Estimated Time:** 2.5 - 3.5 hours
---
## Risk Assessment
### Low Risk:
- Index.vue rework (simple structure, straightforward replacement)
- Adding Card containers to Show.vue
- Replacing native buttons with shadcn Button
### Medium Risk:
- Replacing native inputs with shadcn Input/Select
- v-model bindings might need adjustments
- Async select loading needs testing
- Number input behavior might differ
### Mitigation Strategies:
1. Test each phase incrementally
2. Keep formatting functions unchanged (already working)
3. Test v-model bindings immediately after input replacement
4. Verify async loading with console logs
5. Test all 6 reports after each phase
6. Keep git commits small and atomic
---
## Success Criteria
### Functional Requirements:
✅ All reports navigate from Index page
✅ All filters work correctly (date, text, number, user select, client select)
✅ Apply filters refreshes report data
✅ Reset filters clears all inputs
✅ Export buttons generate CSV/PDF/Excel files
✅ DataTableServer displays results correctly
✅ Pagination works
✅ Formatting functions work (dates, numbers)
### Visual Requirements:
✅ Consistent Card-based layout
✅ shadcn-vue components throughout
✅ Icons for visual interest
✅ Hover effects on cards
✅ Proper spacing and alignment
✅ Responsive layout (mobile, tablet, desktop)
✅ Matches Settings pages style
### Code Quality:
✅ No code duplication
✅ Clean component imports
✅ Consistent naming conventions
✅ Proper TypeScript/Vue 3 patterns
✅ Formatting functions unchanged
✅ No regressions in functionality
---
## Notes
- **DatePicker component:** Already working, imported correctly, no changes needed
- **Formatting functions:** Keep unchanged (formatNumberEU, formatDateEU, formatDateTimeEU, formatCell)
- **DataTableServer:** Keep as-is, already working well
- **Async loading:** User/client select loading works, just needs shadcn Select wrapper
- **Pattern consistency:** Follow Settings/Index.vue and Settings/Archive/Index.vue patterns
- **Icon usage:** Add icons to Index.vue for visual interest, use lucide-vue-next
- **Button variants:** Use `variant="outline"` for secondary actions, default for primary
---
## Post-Implementation
After completing all phases:
1. **Documentation:**
- Update this document with actual implementation notes
- Document any deviations from plan
- Note any unexpected issues
2. **Code Review:**
- Check for consistent component usage
- Verify no native HTML/CSS buttons/inputs remain
- Ensure proper import structure
3. **User Feedback:**
- Test with actual users
- Gather feedback on UI improvements
- Note any requested adjustments
4. **Performance:**
- Verify no performance regressions
- Check bundle size impact
- Monitor async loading times
---
## Conclusion
This plan provides a structured approach to modernizing the Reports frontend pages using shadcn-vue components. The phased approach allows for incremental testing and reduces risk. The estimated total time is 2.5-3.5 hours, with low to medium risk level.
**Recommendation:** Start with Phase 1 (Index.vue) as a proof of concept, then proceed to Phase 2 and 3 for Show.vue. Evaluate Phase 4 (partial extraction) after Phase 3 completion based on actual complexity.