Files
BarangaySystem/.claude/plans/db3f8841a2ce6fbe5c0279ccba883ec9-complete.md
2026-06-06 18:43:00 +08:00

113 lines
8.3 KiB
Markdown

---
task: Redesign HomeCooperative.vue into a proper Coordinator/Cooperative-user dashboard and wire it into Home.vue
cycles: 5
context: true
private: false
started: 2026-05-16T00:00:00Z
finished: 2026-05-16T00:01:00Z
---
## files
- `resources/js/Pages/Home.vue` [lines 57-58] — COORDINATOR currently maps to `HomeShared`; must import and use `HomeCooperative` instead
- `resources/js/Pages/Fragments/Home/HomeCooperative.vue` — full rewrite: currently only a chapter/geo-map component, needs full dashboard
- `resources/js/Pages/Fragments/Home/HomeStoreOwner.vue` — reference pattern: BalanceBox + ServiceButtonGrid + HomeSkeleton
- `resources/js/Components/Core/Stats/BalanceBox.vue` — stat card component (props: `stats[]`, `footerItems[]`, emits `footer-click`)
- `resources/js/Components/Core/Services/ServiceButtonGrid.vue` — icon grid (prop: `items[]` with `icon`, `title`, `pagename` or `action`)
- `resources/js/Components/Core/Services/SideTextButtonList.vue` — text list of quick actions
- `resources/js/Components/Core/Skeleton/HomeSkeleton.vue` — loading skeleton
- `resources/js/composables/usePageData.js``fetchPageData(url, payload)` pattern
- `routes/web.php` [lines 76-135] — `/home-data` GET endpoint; must add COORDINATOR-scoped cooperative stats
- `app/Http/Controllers/Market/CooperativeController.php` — available methods: list, show, registerMember, publicRegisterMember
## steps
1. **`routes/web.php` @ `/home-data` closure** — After the existing `$myStoresCount` block (line ~114), add a COORDINATOR-specific stats block:
- Check `$acctType === UserTypes::COORDINATOR`
- Query `Organization::where('type','COOPERATIVE')->count()``cooperative_total_no`
- Query `CooperativeMember::whereHas('organization', fn($q)=>$q->where('created_by',$user->id))->count()``cooperative_members_no`
- Query `Organization::where('type','COOPERATIVE')->where('created_by',$user->id)->withCount('members')->count()``my_cooperatives_no`
- Add `pending_members_no`: count of `cooperative_members` with `created_at >= now()->subDays(7)` under the coordinator's cooperatives
- Include all four keys in `$props['props']['stats']` unconditionally (0 for non-coordinators is fine)
2. **`resources/js/Pages/Home.vue`** — Add import at top: `import HomeCooperative from './Fragments/Home/HomeCooperative.vue';`
— Change line 57-58 from `<HomeShared title="Coordinator" />` to `<HomeCooperative />`
3. **`resources/js/Pages/Fragments/Home/HomeCooperative.vue`** — Full rewrite. Preserve the chapter map as a collapsible section at the bottom. New structure:
**Script:**
- Imports: `ref, onMounted, computed, h`, `usePageData`, `useNavigate`, `useAuth`, `useModal`, `BalanceBox`, `ServiceButtonGrid`, `SideTextButtonList`, `HomeSkeleton`, and the existing `useChapters` (keep for map section)
- Stats ref: `[{ title:'Cooperatives', number:0, unit:'Total', numberId:'cooperative_total_no' }, { title:'Members', number:0, unit:'Enrolled', numberId:'cooperative_members_no' }, { title:'New (7d)', number:0, unit:'Members', numberId:'pending_members_no' }]`
- Footer items: `[{ title:'Cooperatives', icon:'<people icon url>', pagename:'CooperativeList' }, { title:'My Profile', icon:'<profile icon url>', pagename:'UserInfoEdit' }]`
- `services` array: 8 items:
1. `{ icon:'<people svg>', title:'Cooperatives', pagename:'CooperativeList' }`
2. `{ icon:'<person-plus svg>', title:'Register Member', pagename:'CooperativeMemberRegister' }` (needs active coop hash — use `action:'registerMember'` to prompt)
3. `{ icon:'<building svg>', title:'My Cooperative', action:'viewMyCoop' }`
4. `{ icon:'<bar-chart svg>', title:'Reports', pagename:'ListReports' }`
5. `{ icon:'<file-text svg>', title:'Documents', action:'viewDocs' }`
6. `{ icon:'<check-square svg>', title:'Resolutions', action:'viewResolutions' }`
7. `{ icon:'<people svg>', title:'Members', action:'viewMembers' }`
8. `{ icon:'<map svg>', title:'Chapter Map', action:'toggleMap' }`
- `quickActions` list items:
- `{ text:'Create Cooperative', pagename:'CreateCooperative', icon:'...' }`
- `{ text:'Member Ledger', pagename:'AccountingDashboard', icon:'...' }`
- `{ text:'Add Transaction', pagename:'AddTransaction', icon:'...' }`
- `{ text:'My Personal Profile', pagename:'UserInfoEdit', icon:'...' }`
- `activeOrgHash`: `computed(() => user.value?.settings?.cooperatives?.[0] ?? null)`
- `showMap`: `ref(false)` — toggled by `toggleMap` action
- `viewMyCoop()`: if `activeOrgHash.value`, navigate to `CooperativeDetail` with `target: activeOrgHash.value`; else `modal.quickDismiss({title:'No Cooperative', body:'You have not joined a cooperative yet.'})`
- `handleItemClick(item)`: dispatch on `item.action` or `navigate({ page: item.pagename })`
- On `onMounted`: `fetchPageData('/home-data', {})` then `applyStats()`
**Template:**
- `<HomeSkeleton v-if="loading" />`
- BalanceBox with cooperative stats and footer items, `@footer-click="handleItemClick"`
- `<h5>Cooperative Services</h5>` + `<ServiceButtonGrid :items="services" @item-click="handleItemClick" />`
- `<h5>Quick Actions</h5>` + `<SideTextButtonList :items="quickActions" @item-click="handleItemClick" />`
- Collapsible map section: `<button @click="showMap=!showMap">Chapter Map</button>` + `<div v-show="showMap">` containing the existing Leaflet map code (preserve all existing refs and lifecycle hooks, but only `initMap()` when `showMap` becomes true via `watch`)
**Style:** No `bg-white`/`bg-light`/`text-dark`. Use `var(--bg-card)`, `var(--text-primary)`. `:global(.dark-mode) .chapter-row { background: var(--bg-card) !important; }`.
4. **Icon URLs** — Reuse CDN URLs already in the project. Map to Font Awesome alternatives in the `icon` field or pick from existing `/assets/micons/` SVGs already used in `HomeUltimate.vue`. Acceptable: use `fas fa-*` class names as `icon` if `ServiceButtonGrid` supports icon class strings — check the component prop; if it only accepts URLs, use the same CDN icon URLs already referenced in `HomeShared.vue` and `HomeStoreOwner.vue` (people: `a/04d0e432a298.bin`, profile: `a/ac7a1cebe580.bin`, chart: `a/f87407046b18.bin`, docs: `a/c9fd442fe676.bin`).
5. **VueRouteMap check** — Confirm `CooperativeList`, `CooperativeDetail`, `CreateCooperative`, `CooperativeMemberRegister` all have `coordinator` in `allowedUserTypes`. If any are missing, add `'coordinator'` to their arrays in `app/Http/Controllers/Support/VueRouteMap.php`.
6. **UserPermissions check** — Confirm `UserTypes::COORDINATOR` has `ViewCooperatives`, `CreateCooperative`, `JoinCooperative`, `ViewAccountingReports` in `UserPermissions::roles()`. Add any missing ones.
## context
```
// routes/web.php ~line 92
$acctType = $user?->acct_type instanceof \App\Enums\UserTypes
? $user->acct_type
: \App\Enums\UserTypes::tryFrom($user?->acct_type ?? '');
// stats keys currently returned: total_users_no, active_stores_no, pending_orders_no,
// total_balance_php, total_transactions_no, total_transactions_php, projected_income_today,
// transactions_today_no, cash_flow_today_php, my_stores_no
// BalanceBox props:
// stats: Array<{ title, number, unit, align?, numberId? }>
// footerItems: Array<{ title, icon?, pagename?, action? }>
// boxStyle: string (CSS)
// ServiceButtonGrid: prop items[] = [{ icon: URL|string, title, pagename?, action? }]
// SideTextButtonList: prop items[] = [{ text, pagename?, action?, icon? }]
// usePageData: { data, loading, error, fetchPageData(url, payload) }
// applyStats pattern from HomeStoreOwner.vue:
// stats.value = stats.value.map(s => {
// const v = data.value?.stats[s.numberId];
// return v !== undefined ? { ...s, number: v } : s;
// });
// Home.vue line 57-58 currently:
// <template v-else-if="isCoordinator">
// <HomeShared title="Coordinator" />
// </template>
// Organization model: type='COOPERATIVE', created_by=user.id
// cooperative_members table: organization_id, user_id, created_at
// active coop hash from: user.value?.settings?.cooperatives[0]
```
## notes
- dictionary: `ai-docs/dictionary.md`
- linters: none detected
- constraints: No `bg-white`/`bg-light`/`text-dark` hardcoding; use theme CSS vars. Leaflet map is lazy (only init when `showMap=true`). All icon URLs must use CDN pattern already established in the project. COORDINATOR must appear in `allowedUserTypes` for coop pages.