8.1 KiB
task, cycles, context, private, started, finished
| task | cycles | context | private | started | finished |
|---|---|---|---|---|---|
| Create HomeStoreManager.vue — a dedicated Store Manager home dashboard — and wire it into Home.vue | 5 | true | false | 2026-05-16T00:00:00Z | 2026-05-16T00:02:00Z |
files
resources/js/Pages/Home.vue[lines 67-69] — STORE_MANAGER currently mapped toHomeShared; change to newHomeStoreManagerresources/js/Pages/Fragments/Home/HomeStoreManager.vue— NEW FILE to createresources/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] — hasopenPos()store-select logic; copy this exact patternresources/js/Components/Core/Stats/BalanceBox.vue— props:stats[],footerItems[],boxStyleresources/js/Components/Core/Services/ServiceButtonGrid.vue— prop:items[]withicon,title,pagename|actionresources/js/Components/Core/Services/SideTextButtonList.vue— quick text actionsresources/js/Components/Core/Skeleton/HomeSkeleton.vue— loading skeletonresources/js/composables/usePageData.js—fetchPageData(url, payload)routes/web.php[lines 76-135] —/home-data— already returnstransactions_today_no,cash_flow_today_php; also returnsmy_stores_noscoped to store_managers pivotapp/Http/Controllers/Support/VueRouteMap.php— must confirmManageStoresAdmin,PosMain,PosHistory,PosAccessKeys,ManageProductsAdminallowstore manager
steps
-
routes/web.php@/home-data— The existing$myStoresCountfor non-Big3 only countsowner_idstores (line ~113). Update to also count stores where the user is in thestore_managerspivot, so STORE_MANAGER sees the correct count:$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).
-
Create
resources/js/Pages/Fragments/Home/HomeStoreManager.vuewith this structure:Script (setup):
- Imports:
ref, onMounted, h,usePageData,useNavigate,useAuth,useModal,BalanceBox,ServiceButtonGrid,SideTextButtonList,HomeSkeleton,axios statsref:[ { 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' }, ]balanceFooterItemsref:[ { title: 'Open POS', icon: '<pos-icon-url>', action: 'openPos' }, { title: 'My Stores', icon: '<store-icon-url>', pagename: 'ManageStoresAdmin' }, ]servicesarray (8 tiles):{ icon:'<pos icon>', title:'Open POS', action:'openPos' }{ icon:'<inventory icon>', title:'Inventory', pagename:'ManageProductsAdmin' }{ icon:'<history icon>', title:'POS History', action:'openPosHistory' }{ icon:'<store icon>', title:'Manage Stores', pagename:'ManageStoresAdmin' }{ icon:'<product icon>', title:'Add Product', pagename:'CreateProductStoreOwner' }{ icon:'<key icon>', title:'POS Keys', pagename:'PosAccessKeys' }{ icon:'<customers icon>', title:'Customers', action:'viewCustomers' }{ icon:'<report icon>', title:'Reports', pagename:'ListReports' }
quickActionsarray (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 inHomeShared.vuelines 77-92:- POST to
/ListStores/MyStores/data - If 0 stores → modal warn
- If 1 store → navigate to
PosMainwithtarget: stores[0].hashkey - If >1 →
showStoreSelectModal(stores)with per-store buttons
- POST to
openPosHistory()— same store-picker logic but navigates toPosHistorywith the store's hashkeyviewCustomers()— navigate toManageStoresAdmin(customers are visible per-store there)applyStats()— standard pattern from HomeStoreOwneronMounted→fetchPageData('/home-data', {})thenapplyStats()
Template:
<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. - Imports:
-
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 />. -
app/Http/Controllers/Support/VueRouteMap.php— Confirm all pages used by this dashboard have'store manager'in theirallowedUserTypes. Required pages:ManageStoresAdmin,ManageProductsAdmin,CreateProductStoreOwner,PosAccessKeys,PosHistory,ListReports,AddTransaction,CreateUser,UserInfoEdit. Add'store manager'to any that are missing it. -
app/Http/Controllers/Helpers/Permissions/UserPermissions.php— ConfirmSTORE_MANAGERhas these actions inroles():ViewTransactions(for Reports)ViewAccountingReports(for ListReports)CreatePosAccessKey,DeletePosAccessKey,TogglePosAccessKeyCreateProductForOwnStore,AddProducttoOwnStoreAdd 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
openPoslogic 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. Nobg-whiteor hardcoded colors.