# Story 7.4: My Profile View ## Epic Reference **Epic 7:** Client Dashboard ## Dependencies - **Epic 2:** User Management (user model with all client profile fields must exist) - **Story 7.1:** Client Dashboard Overview (layout and navigation context) ## User Story As a **client**, I want **to view my profile information**, So that **I can verify my account details are correct**. ## Prerequisites ### Required User Model Fields The `users` table must include these columns (from Epic 2): | Column | Type | Description | |--------|------|-------------| | `user_type` | enum('individual','company') | Distinguishes client type | | `name` | string | Full name (individual) or company name | | `national_id` | string | National ID for individuals | | `email` | string | Email address | | `phone` | string | Phone number | | `preferred_language` | enum('ar','en') | User's language preference | | `company_name` | string, nullable | Company name (company clients) | | `company_cert_number` | string, nullable | Company registration number | | `contact_person_name` | string, nullable | Contact person (company clients) | | `contact_person_id` | string, nullable | Contact person's ID | | `created_at` | timestamp | Account creation date | ## Acceptance Criteria ### Individual Client Profile - [ ] Full name displayed - [ ] National ID displayed - [ ] Email address displayed - [ ] Phone number displayed - [ ] Preferred language displayed - [ ] Account created date displayed ### Company Client Profile - [ ] Company name displayed - [ ] Company certificate/registration number displayed - [ ] Contact person name displayed - [ ] Contact person ID displayed - [ ] Email address displayed - [ ] Phone number displayed - [ ] Preferred language displayed - [ ] Account created date displayed ### Features - [ ] Account type indicator (Individual/Company badge) - [ ] No edit capabilities (read-only view) - [ ] Message: "Contact admin to update your information" - [ ] Logout button with confirmation redirect ## Technical Notes ### File Location ``` resources/views/livewire/client/profile.blade.php ``` ### Route ```php // In routes/web.php (client authenticated routes) Route::get('/client/profile', \Livewire\Volt\Volt::route('client.profile'))->name('client.profile'); ``` ### Component Implementation ```php auth()->user(), ]; } public function logout(): void { auth()->logout(); session()->invalidate(); session()->regenerateToken(); $this->redirect(route('login')); } }; ?>
{{ __('client.my_profile') }} {{ $user->user_type === 'individual' ? __('profile.individual_account') : __('profile.company_account') }}
@if($user->user_type === 'individual')
{{ __('profile.full_name') }}
{{ $user->name }}
{{ __('profile.national_id') }}
{{ $user->national_id }}
{{ __('profile.email') }}
{{ $user->email }}
{{ __('profile.phone') }}
{{ $user->phone }}
{{ __('profile.preferred_language') }}
{{ $user->preferred_language === 'ar' ? __('profile.arabic') : __('profile.english') }}
{{ __('profile.member_since') }}
{{ $user->created_at->translatedFormat('F j, Y') }}
@else
{{ __('profile.company_name') }}
{{ $user->company_name }}
{{ __('profile.registration_number') }}
{{ $user->company_cert_number }}
{{ __('profile.contact_person') }}
{{ $user->contact_person_name }}
{{ __('profile.contact_person_id') }}
{{ $user->contact_person_id }}
{{ __('profile.email') }}
{{ $user->email }}
{{ __('profile.phone') }}
{{ $user->phone }}
{{ __('profile.preferred_language') }}
{{ $user->preferred_language === 'ar' ? __('profile.arabic') : __('profile.english') }}
{{ __('profile.member_since') }}
{{ $user->created_at->translatedFormat('F j, Y') }}
@endif
{{ __('client.contact_admin_to_update') }} {{ __('auth.logout') }}
``` ### Required Translation Keys Add to `lang/en/client.php`: ```php 'my_profile' => 'My Profile', 'contact_admin_to_update' => 'Contact admin to update your information', ``` Add to `lang/en/profile.php`: ```php 'full_name' => 'Full Name', 'national_id' => 'National ID', 'email' => 'Email Address', 'phone' => 'Phone Number', 'preferred_language' => 'Preferred Language', 'member_since' => 'Member Since', 'company_name' => 'Company Name', 'registration_number' => 'Registration Number', 'contact_person' => 'Contact Person', 'contact_person_id' => 'Contact Person ID', 'individual_account' => 'Individual Account', 'company_account' => 'Company Account', 'arabic' => 'Arabic', 'english' => 'English', ``` Add to `lang/en/auth.php`: ```php 'logout' => 'Logout', ``` Create corresponding Arabic translations in `lang/ar/` files. ## Test Scenarios ### Unit/Feature Tests Create `tests/Feature/Client/ProfileTest.php`: ```php use App\Models\User; use Livewire\Volt\Volt; test('client can view individual profile page', function () { $user = User::factory()->individual()->create(); $this->actingAs($user) ->get(route('client.profile')) ->assertOk() ->assertSeeLivewire('client.profile'); }); test('individual profile displays all required fields', function () { $user = User::factory()->individual()->create([ 'name' => 'Test User', 'national_id' => '123456789', 'email' => 'test@example.com', 'phone' => '+970599999999', 'preferred_language' => 'en', ]); Volt::test('client.profile') ->actingAs($user) ->assertSee('Test User') ->assertSee('123456789') ->assertSee('test@example.com') ->assertSee('+970599999999') ->assertSee('English'); }); test('company profile displays all required fields', function () { $user = User::factory()->company()->create([ 'company_name' => 'Test Company', 'company_cert_number' => 'REG-12345', 'contact_person_name' => 'John Doe', 'contact_person_id' => '987654321', 'email' => 'company@example.com', 'phone' => '+970599888888', 'preferred_language' => 'ar', ]); Volt::test('client.profile') ->actingAs($user) ->assertSee('Test Company') ->assertSee('REG-12345') ->assertSee('John Doe') ->assertSee('987654321') ->assertSee('company@example.com'); }); test('profile page shows correct account type badge', function () { $individual = User::factory()->individual()->create(); $company = User::factory()->company()->create(); Volt::test('client.profile') ->actingAs($individual) ->assertSee(__('profile.individual_account')); Volt::test('client.profile') ->actingAs($company) ->assertSee(__('profile.company_account')); }); test('profile page has no edit functionality', function () { $user = User::factory()->individual()->create(); Volt::test('client.profile') ->actingAs($user) ->assertDontSee('Edit') ->assertDontSee('Update') ->assertDontSee('wire:model'); }); test('profile page shows contact admin message', function () { $user = User::factory()->individual()->create(); Volt::test('client.profile') ->actingAs($user) ->assertSee(__('client.contact_admin_to_update')); }); test('logout button logs out user and redirects to login', function () { $user = User::factory()->individual()->create(); Volt::test('client.profile') ->actingAs($user) ->call('logout') ->assertRedirect(route('login')); $this->assertGuest(); }); test('unauthenticated users cannot access profile', function () { $this->get(route('client.profile')) ->assertRedirect(route('login')); }); ``` ### User Factory States Required Ensure `database/factories/UserFactory.php` has these states: ```php public function individual(): static { return $this->state(fn (array $attributes) => [ 'user_type' => 'individual', 'national_id' => fake()->numerify('#########'), 'company_name' => null, 'company_cert_number' => null, 'contact_person_name' => null, 'contact_person_id' => null, ]); } public function company(): static { return $this->state(fn (array $attributes) => [ 'user_type' => 'company', 'company_name' => fake()->company(), 'company_cert_number' => fake()->numerify('REG-#####'), 'contact_person_name' => fake()->name(), 'contact_person_id' => fake()->numerify('#########'), 'national_id' => null, ]); } ``` ## Definition of Done - [ ] Individual profile displays all fields correctly - [ ] Company profile displays all fields correctly - [ ] Account type badge shows correctly for both types - [ ] No edit functionality present (read-only) - [ ] Contact admin message displayed - [ ] Logout button works and redirects to login - [ ] All test scenarios pass - [ ] Bilingual support (AR/EN) working - [ ] Responsive design on mobile - [ ] Code formatted with Pint ## Estimation **Complexity:** Low | **Effort:** 2-3 hours ## Notes - Date formatting uses `translatedFormat()` for locale-aware display - Ensure the User model has `$casts` for `created_at` as datetime - The `bg-cream` and `text-charcoal` classes should be defined in Tailwind config per project design system