- 10 Jul, 2026 2 commits
-
-
Mahmoud Aglan authored
Instances no longer hold WhatsApp API credentials. They send messages via the el-captain-manager messaging hub API using MESSAGING_HUB_URL and MESSAGING_HUB_KEY env vars. The hub handles Meta Graph API calls, rate limiting, and delivery tracking centrally. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Root cause: format_money() was used in 20+ views but never defined, causing silent fatal errors on every print attempt. Also simplified ReceiptController to render standalone HTML pages instead of depending on ReceiptTemplate records that may not exist in the DB. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 09 Jul, 2026 13 commits
-
-
Mahmoud Aglan authored
Cast config values to string with null-coalescing fallback, and add empty-string defaults to env() calls so instances without WhatsApp configured still boot without TypeError. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The demo_academy DB doesn't have organizations/users tables with those exact names. Use plain indexed columns instead. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- WhatsAppService: send text, template, image, document messages - Bulk send to groups/status/custom selections - Message log with status tracking (sent/delivered/read/failed) - Three Livewire pages: Send Message, Send Template, Message Log - Migration for whatsapp_messages table - Added 'whatsapp' channel to NotificationChannel enum - Wired into NotificationService for automated notifications - Sidebar section "واتساب" with 3 items - Config via WHATSAPP_PHONE_NUMBER_ID + WHATSAPP_ACCESS_TOKEN env vars Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Auto-seed default sections on first visit when none exist - Every section now shows skeleton placeholders when empty (branches, partners, pricing, trainers, stats, schedule) - Converted remaining dark sections to light theme (branches, trainers, pricing, contact, schedule) for consistency - Stats band keeps dark bg for visual contrast - Fresh deploy = beautiful skeleton website ready for client to imagine Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Fixes Route [inventory.purchase-orders.create] not defined error by adding the missing routes and creating PurchaseOrderForm + PurchaseOrderShow Livewire components with full Arabic UI. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Default background: white, text: dark gray, accent: blue - Hero/navbar/footer stay dark (branded primary color) - All sections show skeleton placeholder cards when no data exists - Removed all hard-coded oklch dark values from section views - Cards, testimonials, FAQ items now use white bg + subtle borders - Empty states show shimmer animation + "لم تُضف ... بعد" message Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Use null-coalescing for age_from/age_to/duration_months (columns don't exist yet) - Handle __PHP_Incomplete_Class from stale cache by re-fetching on type mismatch - Add cache:clear to deploy entrypoint to prevent stale cache after rebuilds Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Livewire's ExtendedCompilerEngine misparses @if inside <script> tags. Replaced inline Blade conditionals with @php block + json_encode. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Route / now serves academy public website (no auth required) - Dashboard moved to /dashboard - Login/Dashboard button added to website navbar (desktop + mobile) - Added "الموقع الإلكتروني" section to sidebar with all 9 CMS pages - Added missing inventory items (POs, Kits, Stock Counts) to sidebar - Configured explicit middleware redirects for guest/auth flows Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Add branch_id accessor to User model (resolves from role_user pivot) - Create AppliesRoleScope trait for one-liner scope enforcement - Enhance PermissionService: include head_trainer_id in group lookup, add training_programs and invoices table support for own_groups scope - Apply AppliesRoleScope to 16 list components: ParticipantList, GroupList, EnrollmentList, AttendanceList, InvoiceList, ProgramList, EvaluationList, CashSessionList, WalletList, AssignmentList, PersonList, FacilityList, ProductList, PurchaseOrderList, KitList, StockCountList Now trainers only see their assigned groups/participants, branch managers only see their branch data, parents only see their children, and receptionists are branch-scoped. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Detect on mount if user already has Trainer/Employee/Guardian records - Show green notice when record exists, amber warning when role implies record but none exists (orphan state) - Allow entity creation on save even without role change when entities are missing (repair orphaned users from before the redesign) - Disable create toggles when record already exists to prevent duplicates Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- CreateTrainerWizard: 9-step flow with activities, user account creation, and initial group assignment (was 6 disconnected steps) - CreateProgramWizard: 7-step flow with head trainer, schedule template, initial group, BasePrice record, facility (was 4 steps, no group/trainer) - NewRegistrationWizard: add parent account creation step so guardians can log in to the Parent Portal immediately - UserForm: role-aware prompts — assigning trainer role creates Trainer+Employee records, parent role links Guardian, staff creates Employee - EnrollmentForm: 3-panel guided experience with group cards, capacity bars, live price preview from PricingService, and schedule conflict detection - TrainerCredentialsGenerated event for async email delivery Closes the "isolated CRUD screens" problem — every entity creation now handles the full business workflow in a single transaction. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 07 Jul, 2026 3 commits
-
-
Mahmoud Aglan authored
- PurchaseOrderList: status filter, receive/cancel actions - KitList + KitForm: CRUD with dynamic components, assemble/disassemble - StockCountList + StockCountForm: warehouse picker, variance display - Register routes for all new inventory components - config/mail.php: add SSL stream options for self-signed cert bypass - Update gap-analysis.md to mark completed items Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Multi-tenant public website system: each academy gets a data-driven advertising site at /site/{slug} with 16 customizable sections, theme editor, gallery, testimonials, FAQ, news, partners, and contact form management. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
4 tiers in EGP: نسبة فقط (Free/12%), المبتدئ (1000/7.5%), المؤسسي (3500/5%), الاحترافي (10000/3.5%). Interactive slider shows total cost based on monthly collections volume, highlights the best-value plan dynamically. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 06 Jul, 2026 1 commit
-
-
Mahmoud Aglan authored
1. User form: add hint that email is used as login username 2. Dashboard low stock widget: only show products below min_stock_level (was showing all) 3. Dashboard attendance widget: link to filtered view showing only sessions without attendance 4. Trainer form: require at least one activity selected (validation + UI) 5. Cross-reference: show activities on trainer list, show trainers on activity cards Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 05 Jul, 2026 21 commits
-
-
Mahmoud Aglan authored
Laravel 13 base Controller has no AuthorizesRequests trait. Use Gate::authorize() facade instead. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Without branch filtering, the collection rate showed global stats even when viewing a specific branch. Now filters invoices by branch via their associated payments. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The revenue query filtered by invoice_items.branch_id which doesn't exist, causing 0 results when a branch is selected. Use payments.branch_id directly since payments already track their branch. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The template variable display used nested {{ '{{' }} syntax which confused Blade's compiler, causing an "Unclosed '(' does not match '}'" error. Use string concatenation with {!! !!} to output literal braces. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
11 Livewire screens: Home dashboard, Schedule (weekly), Attendance (monthly), Finances (invoice list + detail), Profile, Child Detail (with tabs), Evaluation Detail, Excuse Form, Notifications, and Programs browser. Custom parent layout with fixed bottom nav bar (5 tabs). Redirect parent role login to new portal. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Dashboard: - Primary action (new registration) is now a full-width hero card - Secondary actions are a compact 2x2 icon grid Registration wizard: - Mobile step indicator: compact progress bar + step name instead of cramped 5-circle stepper - Sticky bottom nav bar on mobile (fixed position, safe-area aware) so Back/Next are always reachable without scrolling - Activity selection uses horizontal scrollable pills on mobile - Desktop layout remains unchanged (sm: breakpoint gates all changes) Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
New instances and the service fallback now default to the academy paying the platform fee rather than adding it to the client's invoice. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
GroupStatus is a backed enum — need ->value to get the string for __(). Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The SystemSettingsForm only displayed settings already in the DB, so platform_fee_customer_pays was invisible. Switched the route to use the schema-driven Admin\SystemSettings component which always renders all defined settings with their defaults. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Quick actions now includes: new registration, enroll existing, collect payment, attendance. Below it a full "Creation Wizards" grid with buttons for every wizard (program, group, transfer, invoice, facility, employee, trainer, pricing rule, product, stock adjustment, cash session, setup). Each button is permission-gated and uses wire:navigate. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- CreateProductWizard: fix permission mismatch (products.create→inventory.create), add SKU uniqueness validation, redirect to list after success instead of dead-end - ProductForm: set branch_id on new products - ProductList: fix dynamic Tailwind classes (use full class strings for JIT) - GroupList: fix dynamic Tailwind status badge classes - POSTerminal: remove dead addProgram() method and unused imports - CSS: add safelist comment for dynamic color classes used via Blade interpolation Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- POS Terminal now shows products tab with addProduct() method (programs are enrolled via receptionist desk, not POS) - Product list and POS show branch products + academy-wide (null branch) - CreateProductWizard and ProductForm now set branch_id on create - Product model gets ManglesUniqueOnDelete for SKU collision prevention - Clicking a product in POS adds it to cart (or increments qty if exists) Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Add ManglesUniqueOnDelete trait that appends a timestamp suffix to unique fields (code, slug, sku, employee_number) when a record is soft-deleted, freeing the value for new records. Also make group code generation collision-resistant by checking withTrashed(). Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Programs: activate (draft/closed→active), close (active→closed) Groups: activate (forming/on_hold→active), pause (active→on_hold) Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- GroupSchedulePrintController used $this->authorize() but Laravel 13's base Controller has no AuthorizesRequests trait — switched to Gate::authorize() - Added deleteGroup() to GroupList with full cascade: sessions (attendance auto-cascades), schedules, enrollments, waitlists, then the group itself - Delete button with wire:confirm for Arabic confirmation prompt, gated behind groups.delete permission Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
1. ProgramForm now passes status to service — programs default 'active' (the property was set but never included in the data array, so the DB default 'draft' won) 2. Receptionist wizard now finds groups with branch_id=NULL (academy-wide programs) alongside branch-specific ones. Previously only exact branch match was checked, hiding programs created without a branch. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Programs with branch_id=NULL are academy-wide — they should be visible regardless of which branch is selected. The filter now uses WHERE branch_id = X OR branch_id IS NULL. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
training_groups.code is NOT NULL — the auto-created default group was missing it, causing a constraint violation. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The seeder was trying to set branch_id on the user, but that column doesn't exist on the users table (it's on participants/payments). Removed the branch assignment and unused Branch import. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The academy identity is now established by the seeder (from ACADEMY_NAME_EN, ACADEMY_NAME_AR env vars). The wizard no longer has an "Academy Profile" step. It starts directly at Branches (step 1) and only configures operational data: branches, activities, programs, facilities, groups, staff, settings. This enforces one-academy-per-instance: the academy exists before the wizard runs, and no user action can create or duplicate it. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
DatabaseSeeder now uses Academy::first() — never creates duplicates. If the wizard already created an academy, the seeder respects it and just ensures the env-var admin user is super_admin on that academy. FinancialAccountsSeeder no longer has a hardcoded 'el-captain' fallback; it skips gracefully if no academy exists yet. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-