initial: bootstrap from BukidBountyApp base

This commit is contained in:
Jonathan Sykes
2026-06-06 18:43:00 +08:00
commit eb4a5731fb
5674 changed files with 160857 additions and 0 deletions

View File

@@ -0,0 +1,148 @@
---
task: Create HomeStoreManager.vue — a dedicated Store Manager home dashboard — and wire it into Home.vue
cycles: 5
context: true
private: false
started: 2026-05-16T00:00:00Z
finished: 2026-05-16T00:02:00Z
---
## files
- `resources/js/Pages/Home.vue` [lines 67-69] — STORE_MANAGER currently mapped to `HomeShared`; change to new `HomeStoreManager`
- `resources/js/Pages/Fragments/Home/HomeStoreManager.vue` — NEW FILE to create
- `resources/js/Pages/Fragments/Home/HomeStoreOwner.vue` — primary reference pattern to follow (BalanceBox + ServiceButtonGrid + openPos logic)
- `resources/js/Pages/Fragments/Home/HomeShared.vue` [lines 56-93] — has `openPos()` store-select logic; copy this exact pattern
- `resources/js/Components/Core/Stats/BalanceBox.vue` — props: `stats[]`, `footerItems[]`, `boxStyle`
- `resources/js/Components/Core/Services/ServiceButtonGrid.vue` — prop: `items[]` with `icon`, `title`, `pagename|action`
- `resources/js/Components/Core/Services/SideTextButtonList.vue` — quick text actions
- `resources/js/Components/Core/Skeleton/HomeSkeleton.vue` — loading skeleton
- `resources/js/composables/usePageData.js``fetchPageData(url, payload)`
- `routes/web.php` [lines 76-135] — `/home-data` — already returns `transactions_today_no`, `cash_flow_today_php`; also returns `my_stores_no` scoped to store_managers pivot
- `app/Http/Controllers/Support/VueRouteMap.php` — must confirm `ManageStoresAdmin`, `PosMain`, `PosHistory`, `PosAccessKeys`, `ManageProductsAdmin` allow `store manager`
## steps
1. **`routes/web.php` @ `/home-data`** — The existing `$myStoresCount` for non-Big3 only counts `owner_id` stores (line ~113). Update to also count stores where the user is in the `store_managers` pivot, so STORE_MANAGER sees the correct count:
```php
$myStoresCount = !$isBig3 && $user
? \App\Models\Market\Store::where('owner_id', $user->id)
->orWhereHas('managers', fn($q) => $q->where('user_id', $user->id))
->count()
: $storeCount;
```
This change is backward-compatible (STORE_OWNER still works, now STORE_MANAGER also gets a nonzero count).
2. **Create `resources/js/Pages/Fragments/Home/HomeStoreManager.vue`** with this structure:
**Script (setup):**
- Imports: `ref, onMounted, h`, `usePageData`, `useNavigate`, `useAuth`, `useModal`, `BalanceBox`, `ServiceButtonGrid`, `SideTextButtonList`, `HomeSkeleton`, `axios`
- `stats` ref:
```js
[
{ title: 'Transactions', number: 0, unit: 'Today', align: 'left', numberId: 'transactions_today_no' },
{ title: 'Cash Flow', number: '0.00', unit: 'PHP Today', align: 'left', numberId: 'cash_flow_today_php' },
{ title: 'My Stores', number: 0, unit: 'Assigned', align: 'right', numberId: 'my_stores_no' },
]
```
- `balanceFooterItems` ref:
```js
[
{ title: 'Open POS', icon: '<pos-icon-url>', action: 'openPos' },
{ title: 'My Stores', icon: '<store-icon-url>', pagename: 'ManageStoresAdmin' },
]
```
- `services` array (8 tiles):
1. `{ icon:'<pos icon>', title:'Open POS', action:'openPos' }`
2. `{ icon:'<inventory icon>', title:'Inventory', pagename:'ManageProductsAdmin' }`
3. `{ icon:'<history icon>', title:'POS History', action:'openPosHistory' }`
4. `{ icon:'<store icon>', title:'Manage Stores', pagename:'ManageStoresAdmin' }`
5. `{ icon:'<product icon>', title:'Add Product', pagename:'CreateProductStoreOwner' }`
6. `{ icon:'<key icon>', title:'POS Keys', pagename:'PosAccessKeys' }`
7. `{ icon:'<customers icon>', title:'Customers', action:'viewCustomers' }`
8. `{ icon:'<report icon>', title:'Reports', pagename:'ListReports' }`
- `quickActions` array (SideTextButtonList items):
- `{ text:'Onboard New User', pagename:'CreateUser', icon:'...' }`
- `{ text:'My Personal Profile', pagename:'UserInfoEdit', icon:'...' }`
- `{ text:'Add Transaction', pagename:'AddTransaction', icon:'...' }`
- `openPos()` — identical copy of the logic in `HomeShared.vue` lines 77-92:
- POST to `/ListStores/MyStores/data`
- If 0 stores → modal warn
- If 1 store → navigate to `PosMain` with `target: stores[0].hashkey`
- If >1 → `showStoreSelectModal(stores)` with per-store buttons
- `openPosHistory()` — same store-picker logic but navigates to `PosHistory` with the store's hashkey
- `viewCustomers()` — navigate to `ManageStoresAdmin` (customers are visible per-store there)
- `applyStats()` — standard pattern from HomeStoreOwner
- `onMounted` → `fetchPageData('/home-data', {})` then `applyStats()`
**Template:**
```html
<div class="home-fragment pb-5">
<HomeSkeleton v-if="loading" />
<template v-else>
<BalanceBox :stats="stats" :footerItems="balanceFooterItems" @footer-click="handleItemClick" />
<div class="tf-container mt-4">
<h5 class="fw_7 mb-3">Store Manager Tools</h5>
<ServiceButtonGrid :items="services" @item-click="handleItemClick" />
</div>
<div class="tf-container mt-4">
<h5 class="fw_7 mb-3">Quick Actions</h5>
<SideTextButtonList :items="quickActions" @item-click="handleItemClick" />
</div>
</template>
</div>
```
**Style:** No `bg-white`/`bg-light`/`text-dark`. Theme-aware only.
3. **`resources/js/Pages/Home.vue`** — Add import line: `import HomeStoreManager from './Fragments/Home/HomeStoreManager.vue';`
— Change lines 67-69 from `<HomeShared title="Store Manager" />` to `<HomeStoreManager />`.
4. **`app/Http/Controllers/Support/VueRouteMap.php`** — Confirm all pages used by this dashboard have `'store manager'` in their `allowedUserTypes`. Required pages: `ManageStoresAdmin`, `ManageProductsAdmin`, `CreateProductStoreOwner`, `PosAccessKeys`, `PosHistory`, `ListReports`, `AddTransaction`, `CreateUser`, `UserInfoEdit`. Add `'store manager'` to any that are missing it.
5. **`app/Http/Controllers/Helpers/Permissions/UserPermissions.php`** — Confirm `STORE_MANAGER` has these actions in `roles()`:
- `ViewTransactions` (for Reports)
- `ViewAccountingReports` (for ListReports)
- `CreatePosAccessKey`, `DeletePosAccessKey`, `TogglePosAccessKey`
- `CreateProductForOwnStore`, `AddProducttoOwnStore`
Add any that are missing.
## context
```
// HomeShared.vue openPos() pattern (lines 77-92):
const openPos = async () => {
try {
const { data: stores } = await axios.post('/ListStores/MyStores/data', {});
if (!stores || stores.length === 0) {
modal.quickDismiss({ title: 'No Store Found', body: 'You have no active stores assigned to your account.' });
return;
}
if (stores.length === 1) {
navigate({ page: 'PosMain', props: { target: stores[0].hashkey } });
return;
}
showStoreSelectModal(stores);
} catch (e) {
modal.quickDismiss({ title: 'Error', body: 'Could not load your stores. Please try again.' });
}
};
// Home.vue lines 67-69 currently:
// <template v-else-if="isStoreManager">
// <HomeShared title="Store Manager" />
// </template>
// /home-data stats keys available: transactions_today_no, cash_flow_today_php, my_stores_no
// CDN icon URLs in use (from HomeStoreOwner.vue):
// POS key: https://cdn.jsdelivr.net/gh/.../a/5b5ef88c0ad1.svg
// Store: https://cdn.jsdelivr.net/gh/.../a/85605eacd4c8.bin
// Product: https://cdn.jsdelivr.net/gh/.../a/f0a0193d728e.bin
// Import: https://cdn.jsdelivr.net/gh/.../a/ef1a9a079a2d.svg
// Reports: https://cdn.jsdelivr.net/gh/.../a/f87407046b18.bin
// Profile: https://cdn.jsdelivr.net/gh/.../a/ac7a1cebe580.bin
// AddTxn: https://cdn.jsdelivr.net/gh/.../a/c9fd442fe676.bin
// Users: https://cdn.jsdelivr.net/gh/.../a/516ed2aaaa4c.bin
```
## notes
- dictionary: `ai-docs/dictionary.md`
- linters: none detected
- constraints: Do NOT give store manager access to global product editing or user-type creation beyond their hierarchy. The `openPos` logic must re-use the exact same store-picker modal pattern from HomeShared. Use CDN icon URLs already in the project — do not introduce new external URLs. No `bg-white` or hardcoded colors.