78 lines
4.3 KiB
Markdown
78 lines
4.3 KiB
Markdown
---
|
|
task: ManageStoresAdmin page — show Delete and Assign Products actions for STORE_OWNER account type on stores they own
|
|
cycles: 5
|
|
context: true
|
|
private: false
|
|
started: 2026-05-17T08:00:00Z
|
|
finished: 2026-05-17T08:01:30Z
|
|
---
|
|
|
|
## files
|
|
- resources/js/Pages/ManageStoresAdmin.vue [lines 1-28, 88-125, 127-148, 242-263] — main page; action buttons gated by `canModifyStore(store)` → `!!store.user_can_manage`; currently only imports `isUltimate, isSuperOperator, isOperator` from useAuth; does not import `isStoreOwner`
|
|
- app/Http/Controllers/Market/StoreController.php [lines 1299-1350] — `listStores_Admin`: for non-Big3 users sets `$s->user_can_manage` as dynamic attribute via `->each()`; dynamic Eloquent attributes may not serialize reliably in Hypervel
|
|
- resources/js/composables/Core/useAuth.js [lines 106, 118-141] — exports `isStoreOwner` computed (role === STORE_OWNER); already available but not used in ManageStoresAdmin
|
|
|
|
## steps
|
|
1. In `ManageStoresAdmin.vue` line 16, add `isStoreOwner` to destructured `useAuth()` return
|
|
2. In `ManageStoresAdmin.vue`, update `canModifyStore` to also return true when `isStoreOwner.value` AND `store.user_can_manage` is truthy — or add a separate `isOwnerOf(store)` helper that checks `isStoreOwner.value && !!store.user_can_manage` as secondary gate on the action buttons
|
|
3. In `ManageStoresAdmin.vue` action buttons column (lines 247-254), change the `v-if` on Delete and Assign Products buttons to: `v-if="canModifyStore(store) || isStoreOwner"` is NOT correct (too broad); instead ensure `canModifyStore` works by fixing step 4 below
|
|
4. In `StoreController.php` `listStores_Admin` (around line 1317 and 1333), replace dynamic attribute assignment `$s->user_can_manage = ...` with `$s->setAttribute('user_can_manage', ...)` to guarantee it lands in the model's `$attributes` array and is included in the JSON response
|
|
5. Verify `listStores_Admin` correctly includes store owner stores: `$allowedUserIds = [$user->id, ...$user->getAllDescendants()]` — `owner_id` of the store must be in this list for store owners who created stores; no change needed if logic is already correct
|
|
|
|
## context
|
|
**ManageStoresAdmin.vue — useAuth import (line 16):**
|
|
```js
|
|
const { isUltimate, isSuperOperator, isOperator, user } = useAuth()
|
|
// missing: isStoreOwner
|
|
```
|
|
|
|
**canModifyStore function (lines 25-27):**
|
|
```js
|
|
const canModifyStore = (store) => {
|
|
return !!store.user_can_manage
|
|
}
|
|
```
|
|
|
|
**Action buttons (lines 242-254):**
|
|
```vue
|
|
<div class="d-flex justify-content-end gap-2">
|
|
<button @click="viewStore(store)" ...> <!-- no v-if, always shows -->
|
|
<button v-if="canModifyStore(store)" @click="navigate({page:'AddProductsToStore',...})"> <!-- Assign Products -->
|
|
<button v-if="canModifyStore(store)" @click="editStore(store)"> <!-- Edit -->
|
|
<button v-if="canModifyStore(store)" @click="deleteStore(store)"> <!-- Delete -->
|
|
</div>
|
|
```
|
|
|
|
**Backend listStores_Admin — non-Big3 path (StoreController.php ~1333):**
|
|
```php
|
|
->each(function ($s) use ($allowedUserIds) {
|
|
$s->user_can_manage = in_array($s->owner_id, $allowedUserIds) // dynamic property — may not serialize
|
|
|| in_array($s->manager_id, $allowedUserIds)
|
|
|| $s->managers->pluck('user_id')->intersect($allowedUserIds)->isNotEmpty();
|
|
unset($s->managers);
|
|
});
|
|
```
|
|
|
|
Fix: use `setAttribute`:
|
|
```php
|
|
$s->setAttribute('user_can_manage',
|
|
in_array($s->owner_id, $allowedUserIds)
|
|
|| in_array($s->manager_id, $allowedUserIds)
|
|
|| $s->managers->pluck('user_id')->intersect($allowedUserIds)->isNotEmpty()
|
|
);
|
|
```
|
|
|
|
Also fix the Big3 path (~line 1317):
|
|
```php
|
|
->each(fn($s) => $s->user_can_manage = true);
|
|
// change to:
|
|
->each(fn($s) => $s->setAttribute('user_can_manage', true));
|
|
```
|
|
|
|
## notes
|
|
- dictionary: none
|
|
- linters: eslint, tsc (check with `npm run type-check` or `tsc --noEmit` if available)
|
|
- constraints: Do not change route access control — store owners already have access to `/Admin/Stores/List`, `/Admin/Store/Delete`, `/Admin/Store/ToggleStatus` routes (middleware is only `module:stores`, not role-gated)
|
|
- The `deleteStore` and `assignProducts` functions in ManageStoresAdmin already handle the STORE_OWNER case correctly via `canModifyStore` guard — no logic change needed there
|
|
- `MyStores.vue` (at `/my-stores`) is a separate page not linked from HomeStoreOwner; ignore it for this task
|