7.4 KiB
task, cycles, context, private, started, finished
| task | cycles | context | private | started | finished |
|---|---|---|---|---|---|
| Fix "Open POS" on HomeStoreOwner and HomeShared (StoreManager) to pass the store hashkey to PosMain. If user has one store, navigate directly with its hashkey. If multiple stores, show a store selection modal first. | 5 | true | false | 2026-05-16T00:00:00Z | 2026-05-16T00:01:00Z |
files
- resources/js/Pages/Fragments/Home/HomeStoreOwner.vue [lines 30-32, 115-123] — defines balanceFooterItems with pagename:'PosMain' (no target prop), handleItemClick navigates without store hashkey
- resources/js/Pages/Fragments/Home/HomeShared.vue — StoreManager home; no POS button at all; needs Open POS added with same multi-store logic
- resources/js/Pages/Home.vue [lines 62-69] — routes isStoreOwner→HomeStoreOwner, isStoreManager→HomeShared
- resources/js/Pages/PosMain.vue [lines 18-21] — expects
targetprop (store or session hashkey) andaccess_keyprop; withouttargetusePosSession cannot initialize the store - resources/js/composables/Market/usePosSession.js [lines 25-47] — initialize() reads
props.targetas hashkey; if null, storeHash stays null and store products never load - app/Http/Controllers/Market/StoreController.php [lines 1143-1206] —
listStoresForCurrentUser()returns [{hashkey, name, category, role}] for owner+manager - routes/web.php [line 484] — POST /ListStores/MyStores/data → StoreController@listStoresForCurrentUser (auth+module:stores middleware)
steps
Step 1 — HomeStoreOwner.vue: fetch stores and smart-navigate on "Open POS"
- Add
axiosis already imported. Add aloadingStoresref. - Replace the
balanceFooterItems"Open POS" item — keeppagename: 'PosMain'but addaction: 'openPos'to differentiate from direct navigation. - Write an
openPos()async function: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; } // Multiple stores: show selection modal showStoreSelectModal(stores); } catch (e) { modal.quickDismiss({ title: 'Error', body: 'Could not load your stores. Please try again.' }); } }; - Write
showStoreSelectModal(stores)usingmodal.open()with a rendered list of store buttons (useh()from vue). On store click:modal.hideModal()thennavigate({ page: 'PosMain', props: { target: store.hashkey } }). - In
handleItemClick, interceptitem.action === 'openPos'before the pagename check and callopenPos(). - Update the
balanceFooterItemsentry to useaction: 'openPos'instead of/alongsidepagename: 'PosMain'.
Exact change to balanceFooterItems (line 30):
// Before:
{ title: 'Open POS', icon: '...', pagename: 'PosMain' },
// After:
{ title: 'Open POS', icon: '...', action: 'openPos' },
Exact change to handleItemClick (lines 115-123):
const handleItemClick = async (item) => {
if (item?.action === 'chooseCreateStoreMode') {
openCreateStoreChooser();
return;
}
if (item?.action === 'openPos') {
await openPos();
return;
}
if (item?.pagename) {
navigate({ page: item.pagename, props: { data: item.pagestring || '' } });
}
};
Step 2 — HomeShared.vue: add Open POS button for StoreManager role
- Import
computed(already imported),axios,useModal, andhfrom vue. - Check if current role is
STORE_MANAGER(userolefromuseAuth()). - Add an
openPosfunction identical in logic to Step 1. - Add
showStoreSelectModal(stores)function identical to Step 1. - Add a computed
posServicesthat returns an "Open POS" button only whenrole.value === UserTypes.STORE_MANAGER(or always show for manager; the page is already role-gated). - In the template, add
<ServiceButtonGrid :items="posItems" @item-click="handlePosClick" />or extendservicesto include the POS button — prefer extendingserviceswithaction: 'openPos'for managers. - Alternatively, add "Open POS" as a
quickActionsItemsentry with roles[UserTypes.STORE_MANAGER]and handle it inhandleItemClickwith the sameopenPoslogic.
Simplest approach: extend quickActionsItems with:
{
text: 'Open POS',
action: 'openPos',
icon: 'https://cdn.jsdelivr.net/gh/telemagnadon/obj-vault-3a@v2026.05.14-vendor-2/a/5b5ef88c0ad1.svg',
roles: [UserTypes.STORE_MANAGER],
},
And update handleItemClick to check item.action === 'openPos'.
Step 3 — Verify no backend changes needed
The endpoint POST /ListStores/MyStores/data already:
- Returns
[{hashkey, name, category, role}]for the current user's stores (owner or manager) - Has
authmiddleware (user must be logged in) - Covers both STORE_OWNER and STORE_MANAGER via the query in
listStoresForCurrentUser()
No backend changes needed.
context
HomeStoreOwner.vue — balanceFooterItems (line 30):
const balanceFooterItems = ref([
{ title: 'Open POS', icon: '...svg', pagename: 'PosMain' }, // BUG: no target/hashkey
{ title: 'My Stores', icon: '...bin', pagename: 'ManageStoresAdmin' },
]);
HomeStoreOwner.vue — handleItemClick (lines 115-123):
const handleItemClick = (item) => {
if (item?.action === 'chooseCreateStoreMode') {
openCreateStoreChooser();
return;
}
if (item?.pagename) {
navigate({ page: item.pagename, props: { data: item.pagestring || '' } });
}
};
→ Navigates to PosMain without target prop. usePosSession.initialize() then has props.target = null, storeHash stays null, products never load, session can't start.
PosMain.vue props (lines 18-21):
const props = defineProps({
target: { type: String, default: null }, // Session hashkey
access_key: { type: String, default: null },
});
usePosSession.js initialize() (lines 25-47):
const hashkey = props.target; // null when coming from HomeStoreOwner
if (hashkey) {
await posStore.loadSession(hashkey, accessKey);
// ...
}
await posStore.fetchProducts(accessKey, storeHash.value); // storeHash is null
StoreController@listStoresForCurrentUser returns (lines 1197-1202):
return [
'hashkey' => $store->hashkey,
'name' => $store->name,
'category' => $store->category,
'role' => $role, // 'owner' or 'manager'
];
HomeShared.vue — StoreManager currently has NO POS button. It only shows Market, My Wallet, Shipments in services and generic quickActions. The store manager use-case is identical to store owner: fetch their stores, navigate with hashkey.
useModal available functions: open({ title, body, footer }), quickDismiss({ title, body }), yesNoModal(...), hideModal(). Use open() with h() to render store list.
notes
- dictionary: none
- linters: eslint:no, phpcs:no, tsc:no
- constraints: Use existing
/ListStores/MyStores/dataPOST endpoint (already exists, no new backend route needed). Modal store list should show store name and category. Useh()(already importable from vue) to build modal body for store selection. TheuseModalcomposable'sopen()accepts a Vue render function or component asbody.