saveCreditEntry and deleteCreditEntry were using apiFetch() which routes
to /api/admin.php, but credits_create/update/delete only exist in
/api/platforms.php — causing the Unknown action error on every save.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- resetGameForm() now called every time Game Management section is opened,
preventing stuck edit state (disabled slug, wrong form title)
- Added prominent Add New Game button at top of section (master admin only)
- DOMContentLoaded init ensures form state is correct on page load
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- DB: added is_deleted, deleted_at columns to platforms table
- Soft delete: archive button moves games to archived section instead of hard delete
- Archived section: master admin can restore (reactivates) or permanently delete
- Slug reuse: creating a game with an archived slug reactivates the old record
- New game form: master admin always sees add form + agent info; other admins hidden
- Edit: non-master admins have form card revealed on edit
- Delete/Add buttons: only visible to master admin
- api/platforms.php: public and admin_list queries exclude archived games
- api/admin.php: platforms_archived, platforms_restore, platforms_purge actions added
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause: saves went through admin.php which still used old console_url column
and had broken response using undefined $sent variable (always returned error).
- api/admin.php: platforms_create/update/delete fully rewritten with all agent
fields, master-admin gating, and correct json_encode responses
- api/admin.php: update now sets updated_at=NOW() on save
- admin/index.php: game cards show last-edited date (✏️ from updated_at)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Agent Info: master admin sees full edit form; other admins see view-only panel with Copy and Open URL buttons
- Credit Accounting: master admin can manage entries; other admins see total only (Manage Credits button hidden)
- API: credits_create/update/delete require master admin; platform update strips agent fields for non-master
- Players: suspend/delete buttons disabled when viewing master admin account (UI + JS guards)
- URL fields (Agent Link, Games Link): open-in-new-tab arrow button added in both edit and view modes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- DB: added sub_agent_login, sub_agent_password, cashier_login, cashier_password to platforms table
- API: create/update handle all 4 new fields
- Admin: Sub-Account and Cashier sections added inside Agent Info box; game list cards display all new fields
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- DB: renamed console_url to agent_link, added agent_login, agent_password, games_link, agent_guide to platforms table
- api/platforms.php: create/update now handles all 5 agent fields (admin-only)
- admin/index.php: game form has new Agent Info section (purple, admin-only styling); game list cards show all agent fields inline; JS saveGame/editGame/resetGameForm updated
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- pending_signups stat and list queries now filter username != __reset__
so active password-reset rows no longer inflate the signup counter or
appear in the admin pending-signups list
- send_password_reset now calls sendPasswordResetEmail() from mailer.php
instead of building a plain-text cybermailSend() call inline; the
wrapper sends a branded dark-theme HTML email matching the verification
email style
Previously the endpoint always returned success:true regardless of
whether the email was actually delivered. Now captures the bool return
value and returns success:false with an error message if CyberMail
fails, so the admin knows to retry rather than assuming delivery.
Handles the /reset_password.php?token=... URL generated by the
admin send_password_reset action. Flow:
- GET: validates token against pending_registrations (username=__reset__,
not expired), shows set-new-password form
- POST: re-validates token, enforces 6-char min + confirm match,
bcrypt-hashes the new password, updates users.password by email,
deletes the pending row to prevent reuse
- Invalid/expired token shows a clear error with link back to home
Matches the dark gaming aesthetic of verify.php.
The INSERT had two compounding bugs:
1. ".?" in the VALUES clause — a PHP dot inside a double-quoted string
is a literal character, not concatenation. MySQL saw it as a syntax
error and the INSERT always failed silently (no try/catch).
2. The token column had the literal string __reset__ hardcoded instead
of a ? placeholder, so even if the INSERT had run, the real random
token would never have been stored — the reset link always invalid.
Fix: VALUES ("__reset__","",?,?,?,?) with execute(alias,email,token,exp)
giving 4 placeholders for 4 params, all columns correctly bound.