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,68 @@
# TODO: Add Backend Interception for Disabled Pages
## Problem Statement
Pages disabled through the Ultimate Console are still accessible via direct URL `/p/{page}/s/{data}`. The `VueRouteMap` already has disabled page checks, but `viewHelperController` does not.
## Implementation Plan
### Step 1: Add Disabled Page Check to viewHelperController
- **File:** `app/Http/Controllers/viewHelperController.php`
- **Method:** `servePageFragmentUnified()`
- **Changes:**
- Add check for `disabled_pages` system setting at the start of the method
- Retrieve disabled pages list using `SystemSetting::getValue('disabled_pages', [])`
- Check if current page name is in the disabled list (case-insensitive)
- If disabled and user is not Ultimate type, return redirect to `/` or 403 error
- Allow Ultimate users to still access disabled pages (for fixing settings)
### Step 2: Add Helper Method for Disabled Page Checking
- **File:** `app/Http/Controllers/viewHelperController.php`
- **New Method:** `isPageDisabled(string $pageName): bool`
- **Purpose:** Centralized logic to check if a page is disabled
- **Logic:**
- Get `disabled_pages` from SystemSetting
- Compare page name case-insensitively
- Return true if disabled, false otherwise
### Step 3: Add Helper Method for Access Permission
- **File:** `app/Http/Controllers/viewHelperController.php`
- **New Method:** `canAccessDisabledPage(): bool`
- **Purpose:** Check if current user can access disabled pages
- **Logic:**
- Check if user is authenticated
- Check if user has Ultimate account type
- Return true only for Ultimate users
### Step 4: Update servePageFragmentUnified Method
- **Location:** After user authentication check, before viewMap lookup
- **Logic Flow:**
1. Check if page is disabled using `isPageDisabled()`
2. If disabled, check if user can access using `canAccessDisabledPage()`
3. If user cannot access, return appropriate response:
- Option A: Redirect to `/` (consistent with VueRouteMap)
- Option B: Return 403 Forbidden with message
4. If user can access (Ultimate), continue normal flow
### Step 5: Handle Edge Cases
- Ensure case-insensitive matching for page names
- Handle null/empty disabled_pages gracefully
- Maintain backward compatibility with existing functionality
- Ensure public pages are not affected by this check
### Step 6: Testing Considerations
- Test with disabled page list containing various page names
- Test with Ultimate user accessing disabled page
- Test with non-Ultimate user accessing disabled page
- Test with empty disabled_pages setting
- Test with case variations in page names
## Files to Modify
1. `app/Http/Controllers/viewHelperController.php` - Main changes
## Dependencies
- `App\Models\SystemSetting` - For retrieving disabled_pages setting
- `App\Enums\UserTypes` - For checking Ultimate user type
- `Hypervel\Support\Facades\Auth` - For user authentication
## Expected Outcome
After implementation, pages disabled in the Ultimate Console will be inaccessible via direct URL `/p/{page}/s/{data}` for non-Ultimate users, while Ultimate users retain access to fix settings.

View File

@@ -0,0 +1,5 @@
# URL Argument and Routing Fixes
- [ ] Update `resources/js/composables/useUrlArgument.js` to correctly match `--h` (no colon) format instead of `--h:` for hashkey URLs.
- [ ] Update `app/Support/RouteArgumentParser.php` in `decodeHashValue` to perform `urldecode` after `base64_decode`, mirroring frontend's `encodeURIComponent`.
- [ ] Test direct navigation to a store market page to verify that the store is successfully found.

View File

@@ -0,0 +1,4 @@
- [ ] Modify `resources/js/stores/ui.js` to ensure `refreshSettings` properly updates `lastSynced`.
- [ ] Update `resources/js/Pages/UltimateConsole.vue` to use `useUIStore` and trigger a sync/refresh after toggling page status.
- [ ] Adjust `resources/js/composables/Core/useNavigate.js` to use a much shorter cache threshold (e.g., 30s) or ensure it always uses the store's freshest state.
- [ ] Verify immediate page access after enabling in the admin console. Build and restart per standard rules.

View File

@@ -0,0 +1,4 @@
- [ ] Fix signature mismatch in `CooperativeController@getCooperative` to retrieve `hashkey` from request body
- [ ] Ensure `ViewOrganizations` permission is properly assigned to the target user role
- [ ] Perform `npm run build` to update compiled assets
- [ ] Restart `bukidbountyapp` Docker container to apply changes

View File

@@ -0,0 +1,5 @@
- [ ] Fix fatal error in `app/Http/Controllers/Market/CooperativeController.php` by removing the redundant `createCooperative` definition.
- [ ] Modify `app/Http/Controllers/Support/VueRouteMap.php` to ensure `toCamelCase` returns PascalCase for better Vue component matching.
- [ ] Update `app/Http/Controllers/Helpers/Permissions/UserPermissions.php` to grant `ViewOrganizations` permission to the `OPERATOR` role.
- [ ] Improve error handling in `resources/js/Pages/CooperativeList.vue` to display a message when data loading fails.
- [ ] Execute `npm run build` and restart the `bukidbountyapp` Docker container to apply changes.

View File

@@ -0,0 +1,61 @@
# TODO: Fix URL-based Page Navigation (useNavigate URL Format Issue)
## Problem Summary
Pages return "page not found" when accessed via URL. The issue is a mismatch between how `useNavigate.js` generates URLs and how `VueRouteMap.php` parses them back to component names.
### Root Cause
- **Frontend** (`useNavigate.js`): Converts `CooperativeList``/cooperativelist` (no separators)
- **Backend** (`VueRouteMap.php`): Expects hyphenated format like `/cooperative-list` to properly convert back to `CooperativeList`
- **Result**: Component name mismatch → page not found
---
## Fix Steps
### Step 1: Fix Frontend URL Generation
**File**: `resources/js/composables/Core/useNavigate.js`
- [ ] Modify the URL generation logic to convert camelCase/PascalCase page names to kebab-case
- [ ] Change: `page.replace(/\./g, '/').toLowerCase()`
- [ ] To: Convert `CooperativeList``cooperative-list` (hyphenated kebab-case)
- [ ] Ensure all page navigations generate proper kebab-case URLs
### Step 2: Verify Backend Route Parsing
**File**: `app/Http/Controllers/Support/VueRouteMap.php`
- [ ] Verify `toCamelCase()` method properly converts kebab-case back to PascalCase
- [ ] Confirm: `cooperative-list``CooperativeList`
- [ ] Test with multi-word component names
### Step 3: Test URL Patterns
- [ ] Test direct URL access: `/cooperative-list` → loads `CooperativeList` component
- [ ] Test direct URL access: `/buy-view-product-market` → loads `BuyViewProductMarket` component
- [ ] Test URLs with hash parameters: `/edit-user--hHASHKEY`
- [ ] Test URLs with payload parameters: `/some-page--e:ENCODED_PAYLOAD`
### Step 4: Verify Browser Back/Forward Navigation
- [ ] Test popstate event handling with new URL format
- [ ] Ensure browser history works correctly with kebab-case URLs
### Step 5: Check Existing Routes
- [ ] Verify all routes in `VueRouteMap::$routes` array work with new URL format
- [ ] Ensure no broken links or navigation issues
---
## Expected Outcome
- All pages accessible via direct URL
- Browser refresh maintains current page
- Browser back/forward navigation works correctly
- URLs are clean and SEO-friendly (kebab-case)
## Files to Modify
1. `resources/js/composables/Core/useNavigate.js` - Fix URL generation
2. Potentially `resources/js/composables/useUrlEncoder.js` - If hash/payload encoding needs adjustment
## Testing Checklist
- [ ] Navigate to a page, copy URL, open in new tab → page loads correctly
- [ ] Refresh page while on a route → page stays on same route
- [ ] Browser back button works correctly
- [ ] URLs with hashkey parameters work
- [ ] URLs with payload parameters work

View File

@@ -0,0 +1,5 @@
- [ ] Add loading state guard to `startNewSession` and `completeTransaction` actions in `resources/js/stores/pos.js` to prevent race conditions.
- [ ] Update the "Confirm & Pay" button in `resources/js/Pages/PosMain.vue` to be disabled when `posStore.loading` is true and add a loading spinner.
- [ ] Modify the `getPosSessions` method in `app/Http/Controllers/Market/PosController.php` to exclude sessions with status `active` from the history records.
- [ ] Test the checkout flow to ensure that double-clicking the completion button does not trigger multiple new session initializations.
- [ ] Verify that the "empty transaction" is no longer visible in the POS History table upon completion of a sale.

View File

@@ -0,0 +1,83 @@
# TODO: Allow Users to Join Cooperatives via User Settings
## Overview
Implement functionality to allow users to join cooperatives stored in the user's `settings` JSON field, with a dedicated composable and controller for managing user additional details and enabling quick search of users by cooperative membership.
---
## Step 1: Database Schema Update
- [ ] Verify that `settings` field in `users` table is already JSON type (already exists and cast as array)
- [ ] No migration needed - `settings` field already supports array data
---
## Step 2: Create UserAdditionalDetailsController
- [ ] Create `app/Http/Controllers/UserManagement/UserAdditionalDetailsController.php`
- [ ] Implement `getDetails()` method - Retrieve user's additional details including cooperatives
- [ ] Implement `updateCooperatives()` method - Add/remove cooperatives from user settings
- [ ] Implement `searchUsersByCooperative()` method - Quick search for users by cooperative hashkey
- [ ] Implement `getUserCooperatives()` method - Get all cooperatives a user has joined
- [ ] Use ResponseHelper for consistent API responses
- [ ] Add proper authorization checks using UserPermissions
---
## Step 3: Create useUserAdditionalDetails Composable
- [ ] Create `resources/js/composables/useUserAdditionalDetails.js`
- [ ] Implement `fetchUserDetails()` - Fetch current user's additional details
- [ ] Implement `joinCooperative(cooperativeHash)` - Add cooperative to user's settings
- [ ] Implement `leaveCooperative(cooperativeHash)` - Remove cooperative from user's settings
- [ ] Implement `getJoinedCooperatives()` - Get list of cooperatives user has joined
- [ ] Implement `searchUsersByCooperative(cooperativeHash)` - Search users by cooperative
- [ ] Add loading states and error handling
- [ ] Follow existing composable patterns (useUserSettings.js as reference)
---
## Step 4: Register Routes
- [ ] Add routes in `routes/api.php` or appropriate route file:
- `POST /UserAdditionalDetails/Get` - Get user details
- `POST /UserAdditionalDetails/UpdateCooperatives` - Update cooperatives in settings
- `POST /UserAdditionalDetails/SearchByCooperative` - Search users by cooperative
- `POST /UserAdditionalDetails/GetCooperatives` - Get user's cooperatives
---
## Step 5: Update User Model (if needed)
- [ ] Verify `settings` field is in `$fillable` array (already present)
- [ ] Verify `settings` field is cast as `array` (already present)
- [ ] Add helper method `getCooperativesAttribute()` to easily access cooperatives from settings
- [ ] Add helper method `hasJoinedCooperative($cooperativeHash)` to check membership
---
## Step 6: Integration with Existing Cooperative System
- [ ] Ensure compatibility with existing `CooperativeController::joinCooperative()`
- [ ] When user joins via CooperativeController, also update user settings
- [ ] Maintain consistency between `cooperative_members` table and user settings
---
## Step 7: Testing & Validation
- [ ] Test joining a cooperative updates user settings correctly
- [ ] Test leaving a cooperative removes from user settings
- [ ] Test quick search returns correct users by cooperative
- [ ] Test authorization and permission checks
- [ ] Test edge cases (duplicate joins, non-existent cooperatives)
---
## Files to Create/Modify
1. **NEW**: `app/Http/Controllers/UserManagement/UserAdditionalDetailsController.php`
2. **NEW**: `resources/js/composables/useUserAdditionalDetails.js`
3. **MODIFY**: `routes/api.php` (or appropriate route file)
4. **MODIFY**: `app/Models/User.php` (add helper methods)
5. **MODIFY**: `app/Http/Controllers/Market/CooperativeController.php` (sync with settings)
---
## Technical Notes
- Cooperatives will be stored in `settings.cooperatives` as an array of hashkeys
- Example structure: `settings: { cooperatives: ['hash1', 'hash2', ...] }`
- Quick search should use JSON query to find users with specific cooperative in settings
- Follow existing patterns from `useUserSettings.js` and `CooperativeController.php`

View File

@@ -0,0 +1,8 @@
- [ ] Reduce the "Enroll New Farmer" button size and remove `w-100` in `CooperativeDetail.vue`.
- [ ] Import `SearchableTableWrapper` component in `CooperativeDetail.vue`.
- [ ] Add reactive variables for `searchQuery` and `tableDensity`.
- [ ] Implement a computed property `filteredMembers` to filter `cooperative.members` based on `searchQuery`.
- [ ] Replace the grid layout for members with `SearchableTableWrapper`.
- [ ] Define the member table structure (Full Name, Role, Actions/Chevron) inside the `table` slot of `SearchableTableWrapper`.
- [ ] Apply the density styles/classes to the table rows/cells.
- [ ] Ensure the "View Member" functionality is preserved for table rows.