--- 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 `` to `` 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:'', pagename:'CooperativeList' }, { title:'My Profile', icon:'', pagename:'UserInfoEdit' }]` - `services` array: 8 items: 1. `{ icon:'', title:'Cooperatives', pagename:'CooperativeList' }` 2. `{ icon:'', title:'Register Member', pagename:'CooperativeMemberRegister' }` (needs active coop hash — use `action:'registerMember'` to prompt) 3. `{ icon:'', title:'My Cooperative', action:'viewMyCoop' }` 4. `{ icon:'', title:'Reports', pagename:'ListReports' }` 5. `{ icon:'', title:'Documents', action:'viewDocs' }` 6. `{ icon:'', title:'Resolutions', action:'viewResolutions' }` 7. `{ icon:'', title:'Members', action:'viewMembers' }` 8. `{ icon:'', 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:** - `` - BalanceBox with cooperative stats and footer items, `@footer-click="handleItemClick"` - `
Cooperative Services
` + `` - `
Quick Actions
` + `` - Collapsible map section: `` + `
` 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: // // 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.