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

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 target prop (store or session hashkey) and access_key prop; without target usePosSession cannot initialize the store
  • resources/js/composables/Market/usePosSession.js [lines 25-47] — initialize() reads props.target as 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"

  1. Add axios is already imported. Add a loadingStores ref.
  2. Replace the balanceFooterItems "Open POS" item — keep pagename: 'PosMain' but add action: 'openPos' to differentiate from direct navigation.
  3. 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.' });
        }
    };
    
  4. Write showStoreSelectModal(stores) using modal.open() with a rendered list of store buttons (use h() from vue). On store click: modal.hideModal() then navigate({ page: 'PosMain', props: { target: store.hashkey } }).
  5. In handleItemClick, intercept item.action === 'openPos' before the pagename check and call openPos().
  6. Update the balanceFooterItems entry to use action: 'openPos' instead of/alongside pagename: '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

  1. Import computed (already imported), axios, useModal, and h from vue.
  2. Check if current role is STORE_MANAGER (use role from useAuth()).
  3. Add an openPos function identical in logic to Step 1.
  4. Add showStoreSelectModal(stores) function identical to Step 1.
  5. Add a computed posServices that returns an "Open POS" button only when role.value === UserTypes.STORE_MANAGER (or always show for manager; the page is already role-gated).
  6. In the template, add <ServiceButtonGrid :items="posItems" @item-click="handlePosClick" /> or extend services to include the POS button — prefer extending services with action: 'openPos' for managers.
  7. Alternatively, add "Open POS" as a quickActionsItems entry with roles [UserTypes.STORE_MANAGER] and handle it in handleItemClick with the same openPos logic.

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 auth middleware (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/data POST endpoint (already exists, no new backend route needed). Modal store list should show store name and category. Use h() (already importable from vue) to build modal body for store selection. The useModal composable's open() accepts a Vue render function or component as body.