Skip to content

[IP-18]: User pages in the Core Module#595

Merged
nielsdrost7 merged 7 commits into
InvoicePlane:developfrom
KhawarMehfooz:18/user-pages
Jul 13, 2026
Merged

[IP-18]: User pages in the Core Module#595
nielsdrost7 merged 7 commits into
InvoicePlane:developfrom
KhawarMehfooz:18/user-pages

Conversation

@KhawarMehfooz

@KhawarMehfooz KhawarMehfooz commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Pull Request Checklist

Checklist

  • My code follows the code formatting guidelines.
  • I have tested my changes locally.
  • I selected the appropriate branch for this PR.
  • I have rebased my changes on top of the selected branch.
  • I included relevant documentation updates if necessary.
  • I have an accompanying issue ID for this pull request.

Description

Adds two self-service pages to the Company panel:

  • My Profile (/{tenant}/my-profile) — lets a logged-in user update their name, email (with re-verification), password, language, and avatar.
  • My Companies (/{tenant}/my-companies) — lists every company the user belongs to (name, search code, role) with a "Switch" action that sets the Filament tenant and redirects to that company's dashboard.

Implementation notes / deviations from the original spec, driven by the actual schema:

  • users has a single name column, not first_name/last_name — the form and UserService::updateProfile() use name.
  • Added a language column to users via migration (the existing user_profiles.user_language column is dead code with a broken company_id global scope, so it wasn't reused).
  • Avatar upload reuses the existing Upload model (uploadable morph) via a new User::avatarUpload() relation; User::getFilamentAvatarUrl() now falls back to the previously-unused ProfileImageFactory/Gravatar driver when no avatar is set.
  • Password confirmation field renamed to password_confirmation (from Filament's default passwordConfirmation) to match Laravel convention and the ticket's test scenarios.
  • EditProfile is registered as a normal tenant-scoped page rather than through Filament's ->profile() panel method — ->profile() registers routes outside the tenant route group, which broke sidebar navigation (UrlGenerationException: Missing required parameter: tenant) the moment the page had a link pointing to it. See fix commit for the route-registration override.
  • Enabled ->emailChangeVerification() on the Company panel, which was previously never turned on despite ->emailVerification() being set — without it, changing email would have silently saved the new address with no re-verification step.
  • Fixed two incidental, pre-existing bugs surfaced while testing this: AbstractCompanyPanelTestCase::testLivewire() called a non-existent withSession() method (dead code, unused until this PR's tests exercised it), and Modules/Core/resources/views/filament/admin/pages/settings.blade.php used internal Filament schema-component views (x-filament-schemas::form/::actions) directly instead of the standalone <form>/<x-filament::actions> equivalents, which throws once the compiled view cache is cleared.

Related Issue(s)

Closes #18

Motivation and Context

Users currently have no way to update their own name/email/password/avatar or see which companies they belong to without admin intervention. This adds that self-service capability to the Company panel.

Issue Type (Check one or more)

  • New feature
  • Bugfix

Screenshots

Edit Profile

Screenshot 2026-07-13 at 4 16 52 PM

My Companies

Screenshot 2026-07-13 at 4 18 38 PM

Summary by CodeRabbit

  • New Features

    • Added profile editing with language selection, avatar uploads, password updates, and email-change verification.
    • Added a “My Companies” page showing company roles and enabling quick company switching.
    • Added automatic avatar display with a fallback profile image.
    • Added language support for user profiles.
  • Bug Fixes

    • Improved password handling and validation during profile updates.
    • Fixed public storage access for uploaded avatars.
  • Translations

    • Added labels for profile updates, avatars, roles, company switching, and company listings.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (1)
Modules/Core/Tests/Feature/UserProfileTest.php (1)

15-17: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add #[Group] attributes and align method names with it_<verb>_<subject> convention.

Three test methods don't follow the it_<verb>_<subject> naming pattern required by the coding guidelines, and no #[Group] attributes are present on the class or methods. As per coding guidelines: "Use #[Group('smoke|crud|security|authentication|...')] attribute to organize tests by group" and "Use snake_case method names in tests following the pattern it_<verb>_<subject>".

♻️ Proposed naming and group fixes
 #[CoversClass(EditProfile::class)]
 #[CoversClass(MyCompanies::class)]
+#[Group('crud')]
 class UserProfileTest extends AbstractCompanyPanelTestCase
-    public function password_change_requires_matching_confirmation(): void
+    public function it_requires_matching_password_confirmation(): void
-    public function the_company_list_renders_for_the_authenticated_user(): void
+    public function it_renders_the_company_list_for_the_authenticated_user(): void
-    public function switching_sets_the_tenant_and_redirects_to_the_target_dashboard(): void
+    public function it_sets_the_tenant_and_redirects_on_company_switch(): void

Also applies to: 52-52, 83-83, 93-93

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Modules/Core/Tests/Feature/UserProfileTest.php` around lines 15 - 17, Add
#[Group(...)] attributes to UserProfileTest and/or its test methods to organize
these tests using the appropriate existing group categories, then rename the
three nonconforming test methods to snake_case names following the
it_<verb>_<subject> convention. Preserve each test’s behavior and choose groups
matching the scenarios covered by the methods.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Modules/Core/Filament/Company/Pages/Auth/EditProfile.php`:
- Around line 106-107: Replace the __() calls used for the password field label
and validationAttribute in the EditProfile form with trans(), preserving the
existing translation keys and field configuration.
- Around line 89-92: Update the email handling condition around
sendEmailChangeVerification() to require that $data['email'] differs from
$record->email, while retaining the existing feature flag and array_key_exists
checks. Continue unsetting email after processing so unchanged addresses are not
verified or persisted as email changes.

In `@Modules/Core/Services/UserService.php`:
- Around line 92-112: Update UserService::updateAvatar to retain the existing
avatar reference, replace the Upload record, and delete the previous stored
object only after a successful replacement. Add a clear/remove path for an empty
avatar that deletes the existing Upload and its file. In
EditProfile::handleRecordUpdate, treat an empty avatar as removal rather than no
change, and add regression coverage for both replacement and clearing, including
database and storage cleanup.

In `@public/build/manifest.json`:
- Line 3: Ensure the generated hashed CSS/JS assets referenced by
public/build/manifest.json are present under public/build by committing the
build outputs or regenerating the manifest to match the available files. Verify
all seven manifest entries resolve to existing assets and avoid leaving
references that produce 404 responses.

In `@public/storage`:
- Line 1: Remove the environment-specific absolute symlink at public/storage.
Leave public/storage absent from the committed repository and rely on deployment
to create it with php artisan storage:link, or replace it with a portable
relative symlink that preserves public access to storage/app/public.

---

Nitpick comments:
In `@Modules/Core/Tests/Feature/UserProfileTest.php`:
- Around line 15-17: Add #[Group(...)] attributes to UserProfileTest and/or its
test methods to organize these tests using the appropriate existing group
categories, then rename the three nonconforming test methods to snake_case names
following the it_<verb>_<subject> convention. Preserve each test’s behavior and
choose groups matching the scenarios covered by the methods.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ff625dd1-2420-4505-9d38-4055566a1d03

📥 Commits

Reviewing files that changed from the base of the PR and between ae7c593 and 158f251.

📒 Files selected for processing (20)
  • Modules/Core/Database/Migrations/2026_07_13_000000_add_language_to_users_table.php
  • Modules/Core/Filament/Company/Pages/Auth/EditProfile.php
  • Modules/Core/Filament/Company/Pages/MyCompanies.php
  • Modules/Core/Models/User.php
  • Modules/Core/Providers/CompanyPanelProvider.php
  • Modules/Core/Services/UserService.php
  • Modules/Core/Tests/AbstractCompanyPanelTestCase.php
  • Modules/Core/Tests/Feature/UserProfileTest.php
  • Modules/Core/resources/views/filament/admin/pages/settings.blade.php
  • Modules/Core/resources/views/filament/company/pages/my-companies.blade.php
  • public/build/assets/app-BA_uZO_d.css
  • public/build/assets/app-f1GSCnwV.js
  • public/build/assets/invoiceplane-BRKoI_Ls.css
  • public/build/assets/invoiceplane-blue-DySqjbYI.css
  • public/build/assets/nord-DE5VcrRz.css
  • public/build/assets/orange-CttdIaNv.css
  • public/build/assets/reddit-BXTru7AK.css
  • public/build/manifest.json
  • public/storage
  • resources/lang/en/ip.php
💤 Files with no reviewable changes (1)
  • public/build/assets/app-f1GSCnwV.js

Comment thread Modules/Core/Filament/Company/Pages/Auth/EditProfile.php
Comment thread Modules/Core/Filament/Company/Pages/Auth/EditProfile.php Outdated
Comment thread Modules/Core/Services/UserService.php
Comment thread public/build/manifest.json Outdated
Comment thread public/storage Outdated
KhawarMehfooz and others added 5 commits July 13, 2026 16:55
Build outputs are already gitignored via /public/build/, but this file
was force-added in an earlier commit. Keeping it tracked let it drift
out of sync with the (untracked) hashed assets it references, risking
404s on any checkout that hasn't run `yarn build` yet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The committed symlink pointed to an absolute, machine-specific path
(/var/www/InvoicePlane-v2/...), breaking on every other checkout.
Deployments should create it via `php artisan storage:link` instead.

Also fix the .gitignore pattern (drop trailing slash) since it only
matched directories and never actually caught the symlink, which is
how it got force-committed in the first place.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@InvoicePlane InvoicePlane deleted a comment from coderabbitai Bot Jul 13, 2026
@nielsdrost7 nielsdrost7 merged commit 93ec359 into InvoicePlane:develop Jul 13, 2026
1 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Core]: User pages in the Core Module

2 participants