---
task: 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.
cycles: 5
context: true
private: false
started: 2026-05-16T00:00:00Z
finished: 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):**
```js
// Before:
{ title: 'Open POS', icon: '...', pagename: 'PosMain' },
// After:
{ title: 'Open POS', icon: '...', action: 'openPos' },
```

**Exact change to handleItemClick (lines 115-123):**
```js
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:
```js
{
    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):**
```js
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):**
```js
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):**
```js
const props = defineProps({
    target: { type: String, default: null }, // Session hashkey
    access_key: { type: String, default: null },
});
```

**usePosSession.js initialize() (lines 25-47):**
```js
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):**
```php
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`.
