initial: bootstrap from BukidBountyApp base

This commit is contained in:
Jonathan Sykes
2026-06-06 18:43:00 +08:00
commit eb4a5731fb
5674 changed files with 160857 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
---
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