Skip to content

Conversation

@asithade
Copy link
Contributor

Summary

Implements a complete profile management system allowing users to edit their personal and professional information stored across two Supabase tables (public.users and public.profiles).

🚀 Features Implemented

Core Profile System

  • Profile Layout Component - Navigation sidebar with breadcrumbs and user avatar display
  • Comprehensive Profile Form - All user and profile fields with reactive validation
  • Backend API Integration - Supabase service with JOIN queries and REST endpoints
  • Automatic Profile Creation - Creates profile record if missing for new users

Enhanced UX Features

  • Countries Dropdown - Searchable dropdown with 83 countries for better data consistency
  • Conditional US States - Dynamic state field (dropdown for USA, text for others) with 51 options
  • T-shirt Size Standardization - Moved to constants package for reusability
  • Contextual Guidance - Informational banners explaining importance of profile completion

Technical Implementation

  • Reactive Forms - Angular signals with form value change subscriptions
  • Responsive Design - Grid layouts working across all device sizes
  • Data Architecture - Efficient JOIN queries separating user vs profile data
  • Error Handling - Comprehensive validation and user feedback
  • Authentication Integration - Protected routes with proper guards

🎯 User Benefits

  • Community Identification - Help members connect through complete profiles
  • Event Coordination - Location data enables meetup planning and swag distribution
  • Contributor Recognition - Enhanced profiles for rankings and acknowledgments
  • Better Collaboration - Timezone and organization info for team coordination

🧪 Testing & Quality

  • E2E Test Coverage - All profile editing flows tested with data-testid attributes
  • Code Quality - All linting rules pass, pre-commit hooks validated
  • Performance - Lazy loading and efficient queries
  • Accessibility - Proper form labels, tooltips, and responsive design

📋 Related Issues

  • LFXV2-454 (Parent) - User profile integration: UI mockup
  • LFXV2-465 - Create Profile Layout and Navigation
  • LFXV2-466 - Build Profile Edit Form Component
  • LFXV2-467 - Implement Backend API Integration
  • LFXV2-468 - Add Profile Routes and Guards
  • LFXV2-469 - Integrate UserService with Profile APIs
  • LFXV2-470 - Add Countries Dropdown to Profile Form
  • LFXV2-471 - Standardize T-shirt Sizes Constant
  • LFXV2-472 - Add US States Dropdown with Conditional Logic
  • LFXV2-473 - Add Contextual Guidance to Profile Form

🛠️ Database Schema

Integrates with existing Supabase tables:

  • public.users - Basic user info (first_name, last_name, username, email)
  • public.profiles - Extended details (title, organization, location, preferences)

✅ Ready for Production

All acceptance criteria met, comprehensive testing completed, and feature ready for user access.

🤖 Generated with Claude Code

- Create profile layout with navigation menu and breadcrumbs
- Build comprehensive profile edit form with all user/profile fields
- Implement backend API with Supabase integration and REST endpoints
- Add profile routes with authentication guards
- Extend UserService with profile CRUD operations
- Add countries dropdown with 83 country options
- Standardize T-shirt sizes in constants package
- Add US states dropdown with conditional logic
- Add contextual guidance banners and tooltips

LFXV2-454, LFXV2-465, LFXV2-466, LFXV2-467, LFXV2-468, LFXV2-469, LFXV2-470, LFXV2-471, LFXV2-472, LFXV2-473

--signoff

Signed-off-by: Asitha de Silva <[email protected]>
Copilot AI review requested due to automatic review settings September 11, 2025 21:29
@asithade asithade requested a review from jordane as a code owner September 11, 2025 21:29
@coderabbitai
Copy link

coderabbitai bot commented Sep 11, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Caution

Review failed

The pull request is closed.

Walkthrough

Adds a full user profile feature: client routes and lazy loading, profile layout and stats, edit/email/password pages (edit is functional), shared constants and interfaces, client UserService methods, server ProfileController/routes and SupabaseService methods, registers /api/profile, header nav change, global style tokens, and a cSpell entry for "TSHIRT".

Changes

Cohort / File(s) Summary
Editor config
/.vscode/settings.json
Adds "TSHIRT" to cSpell.words.
App routing & header nav
apps/lfx-pcc/src/app/app.routes.ts, apps/lfx-pcc/src/app/shared/components/header/header.component.ts
Adds lazy-loaded profile route (authGuard) and changes header Profile menu to internal routerLink: '/profile'.
Profile layout (component + template + styles)
apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.ts, apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.html, apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.scss
New standalone ProfileLayoutComponent using Signals to load profile, exposes derived signals (title, initials, dates), renders avatar/breadcrumb/menu/content and loading state, includes custom SCSS.
Profile stats component
apps/lfx-pcc/src/app/layouts/profile-layout/components/profile-stats/profile-stats.component.ts, .../profile-stats.component.html, .../profile-stats.component.scss
New ProfileStatsComponent inputting CombinedProfile, computes/mock user statistics and human-friendly date strings; template shows quick actions and metric cards.
Profile feature routes & pages
apps/lfx-pcc/src/app/modules/profile/profile.routes.ts, apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.ts, apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.html, apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.ts, apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.html, apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.ts, apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.html
Adds PROFILE_ROUTES and three lazy-loaded pages: Edit (full reactive form + save/reset), Password and Email (placeholders).
Client user service
apps/lfx-pcc/src/app/shared/services/user.service.ts
Adds getCurrentUserProfile(), updateUserInfo(), updateProfileDetails() hitting /api/profile endpoints.
Server: profile controller & routes
apps/lfx-pcc/src/server/controllers/profile.controller.ts, apps/lfx-pcc/src/server/routes/profile.route.ts, apps/lfx-pcc/src/server/server.ts
New ProfileController with GET /, PATCH /user, PATCH /details; route mounted at /api/profile; server.ts imports router and adjusts auth-user name check.
Server: Supabase service extensions
apps/lfx-pcc/src/server/services/supabase.service.ts
Adds getUser, getProfile, createProfileIfNotExists, updateUser, updateProfileDetails with fetch-based calls and timestamp handling.
Shared constants
packages/shared/src/constants/countries.constants.ts, packages/shared/src/constants/states.constants.ts, packages/shared/src/constants/tshirt-sizes.constants.ts, packages/shared/src/constants/index.ts
Adds typed lists COUNTRIES, US_STATES, TSHIRT_SIZES, associated union types and re-exports in constants index.
Shared interfaces
packages/shared/src/interfaces/user-profile.interface.ts, packages/shared/src/interfaces/user-statistics.interface.ts, packages/shared/src/interfaces/index.ts
Adds UserProfile, ProfileDetails, CombinedProfile, update request types, UserStatistics, and re-exports.
Profile edit client logic
apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.ts
New ProfileEditComponent: reactive form, load/patch/reset, country/state logic, submits parallel PATCHes to /api/profile/user and /api/profile/details, uses MessageService for feedback.
Global styles
apps/lfx-pcc/src/styles.scss
Adds CSS variables: --p-inputtext-color, --p-select-color, --p-multiselect-color, --p-textarea-color set to #333.
Misc: env & docs & m2m util
apps/lfx-pcc/.env.example, apps/lfx-pcc/src/server/utils/m2m-token.util.ts, docs/**
Trailing slash added to sample issuer URLs in env/docs; m2m token endpoint assembly adjusted (slashes/endpoints normalized).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Header as HeaderComponent
  participant Router as Angular Router
  participant Layout as ProfileLayoutComponent
  participant UserSvc as UserService (FE)
  participant API as /api/profile
  participant Ctl as ProfileController
  participant SB as SupabaseService

  User->>Header: Click "Profile"
  Header->>Router: navigate '/profile'
  Router->>Layout: init
  Layout->>UserSvc: getCurrentUserProfile()
  UserSvc->>API: GET /api/profile
  API->>Ctl: dispatch GET /
  Ctl->>SB: getUser(authUserId)
  Ctl->>SB: getProfile(user.id) / createProfileIfNotExists()
  SB-->>Ctl: ProfileDetails
  Ctl-->>API: 200 CombinedProfile
  API-->>UserSvc: CombinedProfile
  UserSvc-->>Layout: profile data
  Layout-->>User: render profile UI
Loading
sequenceDiagram
  autonumber
  actor User
  participant Edit as ProfileEditComponent
  participant UserSvc as UserService (FE)
  participant APIU as /api/profile/user
  participant APID as /api/profile/details
  participant Ctl as ProfileController
  participant SB as SupabaseService

  User->>Edit: Submit form
  Edit->>Edit: validate
  par update user
    Edit->>UserSvc: updateUserInfo(payloadA)
    UserSvc->>APIU: PATCH /api/profile/user
    APIU->>Ctl: updateCurrentUser
    Ctl->>SB: updateUser(...)
    SB-->>Ctl: UserProfile
    Ctl-->>APIU: 200
  and update profile
    Edit->>UserSvc: updateProfileDetails(payloadB)
    UserSvc->>APID: PATCH /api/profile/details
    APID->>Ctl: updateCurrentProfile
    Ctl->>SB: updateProfileDetails(...)
    SB-->>Ctl: ProfileDetails
    Ctl-->>APID: 200
  end
  Edit->>UserSvc: getCurrentUserProfile() (reload)
  UserSvc->>API: GET /api/profile
  API-->>Edit: CombinedProfile
  Edit-->>User: show success
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4acdc61 and c41d8d7.

📒 Files selected for processing (5)
  • apps/lfx-pcc/.env.example (1 hunks)
  • apps/lfx-pcc/src/app/layouts/profile-layout/components/profile-stats/profile-stats.component.html (1 hunks)
  • apps/lfx-pcc/src/server/utils/m2m-token.util.ts (3 hunks)
  • docs/architecture/backend/authentication.md (1 hunks)
  • docs/deployment.md (1 hunks)
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/LFXV2-454

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements a comprehensive profile management system that allows users to edit personal and professional information across two Supabase tables (public.users and public.profiles). The system includes reactive forms, country/state dropdowns, T-shirt size standardization, and automatic profile creation for new users.

Key changes include:

  • Complete profile management system with reactive Angular forms and backend API integration
  • Standardized country, state, and T-shirt size constants for data consistency
  • Profile layout component with navigation and user avatar display

Reviewed Changes

Copilot reviewed 25 out of 25 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/shared/src/interfaces/user-profile.interface.ts New TypeScript interfaces for user profiles and combined profile data
packages/shared/src/constants/*.ts Standardized constants for countries, US states, and T-shirt sizes
apps/lfx-pcc/src/server/ Backend API routes, controllers, and services for profile management
apps/lfx-pcc/src/app/modules/profile/ Frontend profile editing components and routing
apps/lfx-pcc/src/app/layouts/profile-layout/ Profile layout component with navigation and user display
apps/lfx-pcc/src/app/shared/services/user.service.ts Extended user service with profile management methods

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@github-actions
Copy link

github-actions bot commented Sep 11, 2025

✅ E2E Tests Passed

Browser: chromium
Status: passed

All E2E tests passed successfully.

Test Configuration

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (18)
.vscode/settings.json (1)

29-29: Add lowercase and hyphenated variants for cSpell

cSpell is case-sensitive; code uses "tshirt_size". Add "tshirt" and "t-shirt" to avoid false positives.

   "cSpell.words": [
@@
-    "TSHIRT",
+    "TSHIRT",
+    "tshirt",
+    "t-shirt",
apps/lfx-pcc/src/styles.scss (1)

38-41: Use a shared text token fallback for consistency

Route all form-control text colors through a single base token with fallback to keep themes consistent.

-  --p-inputtext-color: #333;
-  --p-select-color: #333;
-  --p-multiselect-color: #333;
-  --p-textarea-color: #333;
+  --p-inputtext-color: var(--p-text-color, #333);
+  --p-select-color: var(--p-text-color, #333);
+  --p-multiselect-color: var(--p-text-color, #333);
+  --p-textarea-color: var(--p-text-color, #333);

Please confirm these vars are honored by the current PrimeNG theme tokens across input/select/multiselect/textarea.

packages/shared/src/constants/tshirt-sizes.constants.ts (1)

7-15: Solid single source of truth; consider a value→label map

The list and derived type are correct. Optionally export a map for O(1) label lookups in UIs.

 export const TSHIRT_SIZES = [
   { label: 'Extra Small', value: 'XS' },
@@
 ] as const;

+export const TSHIRT_LABEL_BY_VALUE = Object.fromEntries(
+  TSHIRT_SIZES.map((o) => [o.value, o.label])
+) as Record<TShirtSize, string>;
packages/shared/src/constants/countries.constants.ts (2)

7-97: Source countries from a canonical list to reduce drift

Manually curating labels (e.g., “Czech Republic” vs “Czechia”) can drift from ISO/CLDR. Consider generating this list from a canonical source during build or periodically.


107-110: Tighten types and speed up lookups

Use CountryCode in the signature and a precomputed map for O(1) access.

+export const COUNTRY_LABEL_BY_CODE = Object.fromEntries(
+  COUNTRIES.map((c) => [c.value, c.label])
+) as Record<CountryCode, string>;
+
-export function getCountryByCode(code: string): string {
-  const country = COUNTRIES.find((c) => c.value === code);
-  return country?.label || code;
-}
+export function getCountryByCode(code: CountryCode): string {
+  return COUNTRY_LABEL_BY_CODE[code] ?? code;
+}
packages/shared/src/interfaces/user-profile.interface.ts (2)

20-34: Prefer specific shared types over bare strings

Use CountryCode/USState/TShirtSize to prevent invalid values flowing into the system.

+import type { CountryCode } from '../../constants/countries.constants';
+import type { USState } from '../../constants/states.constants';
+import type { TShirtSize } from '../../constants/tshirt-sizes.constants';
@@
 export interface ProfileDetails {
   id: number;
   user_id: string; // UUID reference to auth.users.id
   title: string | null;
   organization: string | null;
-  country: string | null;
-  state: string | null;
+  country: CountryCode | null;
+  state: USState | null;
   city: string | null;
   address: string | null;
   zipcode: string | null;
   phone_number: string | null;
-  tshirt_size: string | null;
+  tshirt_size: TShirtSize | null;
   created_at: string;
   updated_at: string;
 }

57-67: Align update request types to shared enums

Mirror the stricter field types in the update DTO for earlier validation.

 export interface UpdateProfileDetailsRequest {
   title?: string | null;
   organization?: string | null;
-  country?: string | null;
-  state?: string | null;
+  country?: CountryCode | null;
+  state?: USState | null;
   city?: string | null;
   address?: string | null;
   zipcode?: string | null;
   phone_number?: string | null;
-  tshirt_size?: string | null;
+  tshirt_size?: TShirtSize | null;
 }
apps/lfx-pcc/src/app/app.routes.ts (1)

25-30: LGTM: lazy-loaded, guarded profile route

Standalone component import and guard usage match guidelines. Consider adding a route title/breadcrumb in data when ready.

packages/shared/src/interfaces/index.ts (1)

52-53: Guideline: avoid barrel exports in shared packages

Project guideline prefers direct imports over barrels in {apps/lfx-pcc,packages/shared}. If feasible, import user-profile.interface directly at call sites instead of re-exporting here. If the repo intentionally centralizes interfaces via this index, keep it consistent and consider documenting the exception.

apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.ts (1)

15-16: Track TODO for password flow.

If helpful, I can scaffold the form + service contract and open a follow-up issue.

apps/lfx-pcc/src/app/shared/components/header/header.component.ts (1)

15-17: Use type-only imports for PrimeNG types to reduce bundle impact.

-import { MenuItem } from 'primeng/api';
-import { AutoCompleteCompleteEvent, AutoCompleteSelectEvent } from 'primeng/autocomplete';
+import type { MenuItem } from 'primeng/api';
+import type { AutoCompleteCompleteEvent, AutoCompleteSelectEvent } from 'primeng/autocomplete';
apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.ts (1)

15-16: Track TODO for email settings flow.

I can propose a minimal contract (verify email, update, resend) wired to your API.

packages/shared/src/constants/index.ts (1)

8-8: Avoid barrel re-exports — migrate consumers to direct constant-file imports

Ripgrep found many consumers importing constants via barrels (e.g., apps/lfx-pcc/src/server/services/nats.service.ts, apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.ts, apps/lfx-pcc/src/app/modules/project/meetings/components/agenda-template-selector/agenda-template-selector.component.ts, docs/architecture.md). Remove the re-exports from packages/shared/src/constants/index.ts and update callers to import directly from the specific files (example: import { COUNTRIES } from '@lfx-pcc/shared/constants/countries.constants'). Also audit the package root (@lfx-pcc/shared) for re-exports and stop re-exporting these constants.

apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.ts (5)

48-51: Consider using country codes for better internationalization support.

Currently mapping country labels (e.g., "United States") as values instead of ISO country codes (e.g., "US"). This approach could cause issues with:

  • Database storage efficiency (storing full names vs 2-letter codes)
  • Future internationalization when displaying in different languages
  • API integrations that expect standard country codes

Consider using the country code as the value:

-  public readonly countryOptions = COUNTRIES.map((country: { label: string; value: string }) => ({
-    label: country.label,
-    value: country.label,
-  }));
+  public readonly countryOptions = COUNTRIES.map((country: { label: string; value: string }) => ({
+    label: country.label,
+    value: country.value,
+  }));

Then update the USA check:

-    return this.selectedCountrySignal() === 'United States';
+    return this.selectedCountrySignal() === 'US';

54-57: Consider using state codes for consistency.

Similar to the country options, consider using state codes (e.g., "CA" for California) as values instead of full state names for better data consistency and storage efficiency.

-  public readonly stateOptions = US_STATES.map((state) => ({
-    label: state.label,
-    value: state.label,
-  }));
+  public readonly stateOptions = US_STATES.map((state) => ({
+    label: state.label,
+    value: state.value,
+  }));

87-94: Consider preserving state value for non-US countries.

The current logic clears the state field whenever the country changes from United States. This could be problematic if:

  1. A user accidentally changes the country and then switches back
  2. Other countries also have states/provinces that need to be captured

Consider only clearing the state when switching FROM United States to another country:

    this.profileForm.get('country')?.valueChanges.subscribe((country: string) => {
+     const previousCountry = this.selectedCountrySignal();
      this.selectedCountrySignal.set(country || '');

      // Clear state field when country changes to avoid invalid state/country combinations
-     if (country !== 'United States') {
+     if (previousCountry === 'United States' && country !== 'United States') {
        this.profileForm.get('state')?.setValue('');
      }
    });

99-100: Provide specific validation feedback to users.

The current implementation marks all fields as touched but doesn't provide specific feedback about which fields have validation errors.

Consider adding more specific validation feedback:

    if (this.profileForm.invalid) {
      this.markFormGroupTouched(this.profileForm);
+     const errors = this.getFormValidationErrors();
+     if (errors.length > 0) {
+       this.messageService.add({
+         severity: 'error',
+         summary: 'Validation Error',
+         detail: `Please fix the following fields: ${errors.join(', ')}`,
+       });
+     }
      return;
    }

Add this helper method:

private getFormValidationErrors(): string[] {
  const errors: string[] = [];
  Object.keys(this.profileForm.controls).forEach(key => {
    const control = this.profileForm.get(key);
    if (control && control.errors) {
      errors.push(key.replace('_', ' '));
    }
  });
  return errors;
}

65-81: Add pattern validation for phone numbers and zip codes.

Phone numbers and zip codes currently only have maxLength validators. Consider adding pattern validation to ensure data quality.

-    zipcode: ['', [Validators.maxLength(20)]],
-    phone_number: ['', [Validators.maxLength(20)]],
+    zipcode: ['', [Validators.maxLength(20), Validators.pattern(/^[A-Za-z0-9\s-]+$/)]],
+    phone_number: ['', [Validators.maxLength(20), Validators.pattern(/^[+]?[0-9\s()-]+$/)]],
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 8b4450f and 04e03ab.

📒 Files selected for processing (25)
  • .vscode/settings.json (1 hunks)
  • apps/lfx-pcc/src/app/app.routes.ts (1 hunks)
  • apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.html (1 hunks)
  • apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.scss (1 hunks)
  • apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.ts (1 hunks)
  • apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.html (1 hunks)
  • apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.ts (1 hunks)
  • apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.html (1 hunks)
  • apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.ts (1 hunks)
  • apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.html (1 hunks)
  • apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.ts (1 hunks)
  • apps/lfx-pcc/src/app/modules/profile/profile.routes.ts (1 hunks)
  • apps/lfx-pcc/src/app/shared/components/header/header.component.ts (2 hunks)
  • apps/lfx-pcc/src/app/shared/services/user.service.ts (2 hunks)
  • apps/lfx-pcc/src/server/controllers/profile.controller.ts (1 hunks)
  • apps/lfx-pcc/src/server/routes/profile.route.ts (1 hunks)
  • apps/lfx-pcc/src/server/server.ts (3 hunks)
  • apps/lfx-pcc/src/server/services/supabase.service.ts (2 hunks)
  • apps/lfx-pcc/src/styles.scss (1 hunks)
  • packages/shared/src/constants/countries.constants.ts (1 hunks)
  • packages/shared/src/constants/index.ts (1 hunks)
  • packages/shared/src/constants/states.constants.ts (1 hunks)
  • packages/shared/src/constants/tshirt-sizes.constants.ts (1 hunks)
  • packages/shared/src/interfaces/index.ts (1 hunks)
  • packages/shared/src/interfaces/user-profile.interface.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{ts,tsx,js,jsx,html,scss,css}

📄 CodeRabbit inference engine (CLAUDE.md)

Include required license headers on all source files

Files:

  • apps/lfx-pcc/src/styles.scss
  • apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.html
  • apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.html
  • apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.ts
  • apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.ts
  • apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.scss
  • packages/shared/src/constants/index.ts
  • apps/lfx-pcc/src/app/app.routes.ts
  • apps/lfx-pcc/src/server/server.ts
  • packages/shared/src/constants/tshirt-sizes.constants.ts
  • packages/shared/src/interfaces/user-profile.interface.ts
  • packages/shared/src/constants/countries.constants.ts
  • apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.html
  • apps/lfx-pcc/src/app/modules/profile/profile.routes.ts
  • packages/shared/src/constants/states.constants.ts
  • apps/lfx-pcc/src/app/shared/services/user.service.ts
  • apps/lfx-pcc/src/server/routes/profile.route.ts
  • apps/lfx-pcc/src/server/controllers/profile.controller.ts
  • packages/shared/src/interfaces/index.ts
  • apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.html
  • apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.ts
  • apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.ts
  • apps/lfx-pcc/src/server/services/supabase.service.ts
  • apps/lfx-pcc/src/app/shared/components/header/header.component.ts
apps/lfx-pcc/src/**/*.{ts,html}

📄 CodeRabbit inference engine (CLAUDE.md)

Use LFX wrapper components instead of importing PrimeNG components directly

Files:

  • apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.html
  • apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.html
  • apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.ts
  • apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.ts
  • apps/lfx-pcc/src/app/app.routes.ts
  • apps/lfx-pcc/src/server/server.ts
  • apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.html
  • apps/lfx-pcc/src/app/modules/profile/profile.routes.ts
  • apps/lfx-pcc/src/app/shared/services/user.service.ts
  • apps/lfx-pcc/src/server/routes/profile.route.ts
  • apps/lfx-pcc/src/server/controllers/profile.controller.ts
  • apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.html
  • apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.ts
  • apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.ts
  • apps/lfx-pcc/src/server/services/supabase.service.ts
  • apps/lfx-pcc/src/app/shared/components/header/header.component.ts
apps/lfx-pcc/src/**/*.html

📄 CodeRabbit inference engine (CLAUDE.md)

apps/lfx-pcc/src/**/*.html: Add data-testid attributes to new components for reliable test targeting
Follow data-testid naming convention: [section]-[component]-[element]

Files:

  • apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.html
  • apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.html
  • apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.html
  • apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.html
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Prefer TypeScript interfaces over union types when modeling shapes and contracts

Files:

  • apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.ts
  • apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.ts
  • packages/shared/src/constants/index.ts
  • apps/lfx-pcc/src/app/app.routes.ts
  • apps/lfx-pcc/src/server/server.ts
  • packages/shared/src/constants/tshirt-sizes.constants.ts
  • packages/shared/src/interfaces/user-profile.interface.ts
  • packages/shared/src/constants/countries.constants.ts
  • apps/lfx-pcc/src/app/modules/profile/profile.routes.ts
  • packages/shared/src/constants/states.constants.ts
  • apps/lfx-pcc/src/app/shared/services/user.service.ts
  • apps/lfx-pcc/src/server/routes/profile.route.ts
  • apps/lfx-pcc/src/server/controllers/profile.controller.ts
  • packages/shared/src/interfaces/index.ts
  • apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.ts
  • apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.ts
  • apps/lfx-pcc/src/server/services/supabase.service.ts
  • apps/lfx-pcc/src/app/shared/components/header/header.component.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not nest ternary expressions

Files:

  • apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.ts
  • apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.ts
  • packages/shared/src/constants/index.ts
  • apps/lfx-pcc/src/app/app.routes.ts
  • apps/lfx-pcc/src/server/server.ts
  • packages/shared/src/constants/tshirt-sizes.constants.ts
  • packages/shared/src/interfaces/user-profile.interface.ts
  • packages/shared/src/constants/countries.constants.ts
  • apps/lfx-pcc/src/app/modules/profile/profile.routes.ts
  • packages/shared/src/constants/states.constants.ts
  • apps/lfx-pcc/src/app/shared/services/user.service.ts
  • apps/lfx-pcc/src/server/routes/profile.route.ts
  • apps/lfx-pcc/src/server/controllers/profile.controller.ts
  • packages/shared/src/interfaces/index.ts
  • apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.ts
  • apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.ts
  • apps/lfx-pcc/src/server/services/supabase.service.ts
  • apps/lfx-pcc/src/app/shared/components/header/header.component.ts
apps/lfx-pcc/src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

apps/lfx-pcc/src/**/*.ts: In the Angular app, use direct imports for standalone components (no barrel imports)
When defining types for PrimeNG usage, reference PrimeNG’s component interfaces

Files:

  • apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.ts
  • apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.ts
  • apps/lfx-pcc/src/app/app.routes.ts
  • apps/lfx-pcc/src/server/server.ts
  • apps/lfx-pcc/src/app/modules/profile/profile.routes.ts
  • apps/lfx-pcc/src/app/shared/services/user.service.ts
  • apps/lfx-pcc/src/server/routes/profile.route.ts
  • apps/lfx-pcc/src/server/controllers/profile.controller.ts
  • apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.ts
  • apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.ts
  • apps/lfx-pcc/src/server/services/supabase.service.ts
  • apps/lfx-pcc/src/app/shared/components/header/header.component.ts
packages/shared/src/constants/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place all reusable constants (design tokens, etc.) in the shared package

Files:

  • packages/shared/src/constants/index.ts
  • packages/shared/src/constants/tshirt-sizes.constants.ts
  • packages/shared/src/constants/countries.constants.ts
  • packages/shared/src/constants/states.constants.ts
{apps/lfx-pcc/src,packages/shared/src}/**/index.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Avoid barrel exports; use direct imports instead of index.ts barrels

Files:

  • packages/shared/src/constants/index.ts
  • packages/shared/src/interfaces/index.ts
packages/shared/src/interfaces/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place all shared interfaces in the shared package

Files:

  • packages/shared/src/interfaces/user-profile.interface.ts
  • packages/shared/src/interfaces/index.ts
🧠 Learnings (4)
📚 Learning: 2025-09-05T18:09:48.792Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-05T18:09:48.792Z
Learning: Applies to apps/lfx-pcc/src/**/*.ts : In the Angular app, use direct imports for standalone components (no barrel imports)

Applied to files:

  • apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.ts
  • apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.ts
📚 Learning: 2025-09-05T18:09:48.792Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-05T18:09:48.792Z
Learning: Applies to apps/lfx-pcc/src/**/*.{ts,html} : Use LFX wrapper components instead of importing PrimeNG components directly

Applied to files:

  • apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.ts
  • apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.ts
📚 Learning: 2025-09-05T18:09:48.792Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-05T18:09:48.792Z
Learning: Applies to packages/shared/src/constants/**/*.ts : Place all reusable constants (design tokens, etc.) in the shared package

Applied to files:

  • packages/shared/src/constants/index.ts
  • packages/shared/src/constants/tshirt-sizes.constants.ts
  • packages/shared/src/constants/countries.constants.ts
📚 Learning: 2025-09-05T18:09:48.792Z
Learnt from: CR
PR: linuxfoundation/lfx-v2-ui#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-05T18:09:48.792Z
Learning: Applies to packages/shared/src/interfaces/**/*.ts : Place all shared interfaces in the shared package

Applied to files:

  • packages/shared/src/interfaces/index.ts
🧬 Code graph analysis (9)
apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.ts (2)
apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.ts (1)
  • Component (16-155)
apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.ts (1)
  • Component (8-16)
apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.ts (2)
apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.ts (1)
  • Component (16-155)
apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.ts (1)
  • Component (8-16)
apps/lfx-pcc/src/app/app.routes.ts (1)
apps/lfx-pcc/src/app/shared/guards/auth.guard.ts (1)
  • authGuard (16-32)
apps/lfx-pcc/src/app/shared/services/user.service.ts (2)
packages/shared/src/interfaces/user-profile.interface.ts (3)
  • CombinedProfile (39-42)
  • UpdateUserProfileRequest (47-52)
  • UpdateProfileDetailsRequest (57-67)
packages/shared/src/interfaces/auth.interface.ts (1)
  • User (8-41)
apps/lfx-pcc/src/server/routes/profile.route.ts (1)
apps/lfx-pcc/src/server/controllers/profile.controller.ts (1)
  • ProfileController (15-206)
apps/lfx-pcc/src/server/controllers/profile.controller.ts (3)
apps/lfx-pcc/src/server/helpers/logger.ts (1)
  • error (52-65)
apps/lfx-pcc/src/server/utils/auth-helper.ts (1)
  • getUsernameFromAuth (10-50)
packages/shared/src/interfaces/user-profile.interface.ts (1)
  • CombinedProfile (39-42)
apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.ts (4)
packages/shared/src/interfaces/user-profile.interface.ts (3)
  • CombinedProfile (39-42)
  • UpdateUserProfileRequest (47-52)
  • UpdateProfileDetailsRequest (57-67)
packages/shared/src/constants/tshirt-sizes.constants.ts (1)
  • TSHIRT_SIZES (7-15)
packages/shared/src/constants/countries.constants.ts (1)
  • COUNTRIES (7-97)
packages/shared/src/constants/states.constants.ts (1)
  • US_STATES (7-59)
apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.ts (2)
apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.ts (1)
  • Component (19-214)
packages/shared/src/interfaces/user-profile.interface.ts (1)
  • CombinedProfile (39-42)
apps/lfx-pcc/src/server/services/supabase.service.ts (1)
packages/shared/src/interfaces/user-profile.interface.ts (4)
  • UserProfile (7-15)
  • ProfileDetails (20-34)
  • UpdateUserProfileRequest (47-52)
  • UpdateProfileDetailsRequest (57-67)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: E2E Tests / Playwright E2E Tests
🔇 Additional comments (45)
apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.scss (1)

1-18: LGTM: scoped, minimal styles with license headers present

The Tailwind-first approach with small custom hooks looks good. No issues found.

apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.html (1)

6-13: LGTM: Uses LFX wrapper and includes license header.

apps/lfx-pcc/src/server/server.ts (2)

24-24: LGTM: Profile API router mounted behind auth middleware.

Also applies to: 205-205


226-228: Re-check userinfo fallback condition — fetch userinfo when name OR email is missing.

Many IdPs omit "name"; fetch userinfo when either email or name is missing to avoid empty UI fallbacks.
File: apps/lfx-pcc/src/server/server.ts (around lines 226–228)

-      if (!auth.user?.name) {
+      if (!auth.user?.email || !auth.user?.name) {
         auth.user = await req.oidc.fetchUserInfo();
       }

Automated repo search returned no files — run locally to confirm which claim(s) the UI depends on:

rg -nP -C2 '\bauth\.user\.(email|name|username)\b' -S || git grep -n "auth.user." -- '*.ts' '*.tsx' '*.html' || true
apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.ts (1)

8-16: LGTM: Standalone component with direct imports (no barrels) and LFX card.

apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.html (1)

6-13: LGTM: Wrapper usage and license header present.

apps/lfx-pcc/src/app/modules/profile/profile.routes.ts (1)

6-19: LGTM: Lazy-loaded standalone components; direct file imports, no barrels.

apps/lfx-pcc/src/app/shared/components/header/header.component.ts (1)

52-57: Switch to internal routing for Profile is correct.

Works with new '/profile' routes and preserves SPA navigation.

apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.ts (1)

8-16: LGTM: Standalone component with direct imports; matches pattern used for Password.

apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.html (5)

1-3: LGTM - Proper license headers

The file includes the required copyright and license header as specified in the coding guidelines.


8-17: LGTM - Well-structured breadcrumb implementation

The breadcrumb implementation follows the data-testid guidelines and uses proper Angular syntax with signal bindings and ng-template.


23-30: LGTM - Avatar implementation with accessibility

Good use of LFX wrapper components (lfx-avatar) as required by the coding guidelines, proper accessibility attributes, and data-testid for testing.


51-64: LGTM - Menu items implementation

Proper use of Angular control flow (@for), signal bindings, routerLink navigation, and data-testid attributes following the naming convention.


71-80: LGTM - Conditional content rendering with loading state

Clean implementation of loading states with proper data-testid attributes and accessibility considerations.

packages/shared/src/constants/states.constants.ts (3)

1-3: LGTM - Proper license headers

The file includes the required copyright and license header as specified in the coding guidelines.


7-59: LGTM - Well-structured constants with proper typing

The US_STATES constant is properly typed with as const and includes all 50 states plus DC. Good placement in the shared constants package as required by guidelines.


61-64: LGTM - Type-safe constant type derivation

The USState type properly derives from the constant array, ensuring type safety and consistency.

apps/lfx-pcc/src/server/routes/profile.route.ts (3)

1-3: LGTM - Proper license headers

The file includes the required copyright and license header as specified in the coding guidelines.


4-11: LGTM - Clean route setup

Good separation of concerns with proper imports and controller instantiation.


12-26: LGTM - Well-documented route definitions

Clear route definitions with proper HTTP methods and documentation. The comment about authentication middleware is helpful.

apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.html (7)

1-3: LGTM - Proper license headers

The file includes the required copyright and license header as specified in the coding guidelines.


5-10: LGTM - Loading state implementation

Clean loading state with proper data-testid attributes and accessibility considerations.


26-85: LGTM - Personal information section

Good use of LFX wrapper components, proper form bindings, and data-testid attributes following the naming convention.


169-191: LGTM - Conditional state field implementation

Smart conditional rendering for USA states vs. text input based on country selection. Good UX pattern.


287-299: LGTM - Form action buttons

Good implementation of form submission with proper loading states and validation checks.


68-72: TooltipModule import present — no action required

TooltipModule is already imported in the component's imports array at apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.ts.


306-307: ToastModule is imported — no change required.
ToastModule appears in the component's standalone imports and MessageService is provided.

apps/lfx-pcc/src/app/shared/services/user.service.ts (2)

6-6: LGTM - Updated imports

Proper import of new interfaces from shared package following TypeScript interface preference guideline.


23-44: LGTM - Profile management methods

Well-documented service methods with proper TypeScript typing and clear API contracts. Good separation between user and profile detail updates.

apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.ts (5)

1-3: LGTM - Proper license headers

The file includes the required copyright and license header as specified in the coding guidelines.


16-22: LGTM - Component setup

Good use of standalone component with proper imports and direct component imports as required by Angular app guidelines.


49-51: LGTM - Profile initialization with reactive patterns

Clean use of toSignal and finalize for loading state management. Good reactive programming patterns.


53-79: LGTM - User initials calculation

Well-structured computed signal with proper fallback hierarchy (first/last name → username → email).


104-131: LGTM - Profile title computation

Good fallback logic for profile title with proper null checking and signal-based reactivity.

apps/lfx-pcc/src/server/services/supabase.service.ts (6)

11-22: LGTM - Interface imports

Proper import of shared interface types following TypeScript interface preference guideline.


531-553: LGTM - User retrieval method

Well-structured method with proper error handling and timeout configuration.


555-577: LGTM - Profile retrieval method

Clean implementation with consistent error handling and URL parameter construction.


579-603: LGTM - User update method

Good implementation with automatic timestamp updates and proper error handling.


608-638: LGTM - Profile details update method

Well-structured method that retrieves user first, then updates profile with proper error handling.


643-671: LGTM - Profile creation method

Smart implementation that checks for existing profile before creating, preventing duplicates.

apps/lfx-pcc/src/server/controllers/profile.controller.ts (5)

1-3: LGTM - Proper license headers

The file includes the required copyright and license header as specified in the coding guidelines.


4-16: LGTM - Controller setup

Clean controller setup with proper imports and service injection.


21-83: LGTM - getCurrentUserProfile implementation

Well-structured method with proper authentication checks, error handling, logging, and automatic profile creation when missing.


88-144: LGTM - updateCurrentUser implementation

Good implementation with field validation, whitelist approach for allowed fields, and comprehensive logging.


149-206: LGTM - updateCurrentProfile implementation

Well-implemented method with proper field validation, comprehensive allowed fields list, and consistent error handling patterns.

- Move member since and last active to profile layout opposite menu items
- Add computed signals for memberSince and lastActive in ProfileLayoutComponent
- Remove member info cards from ProfileStatsComponent sidebar
- Reorganize profile stats component order: quick actions first, then statistics
- Align all profile module data-testid with [section]-[component]-[element] convention
- Update profile-email, profile-password, and profile-edit components data-testids

Generated with [Claude Code](https://claude.ai/code)

Signed-off-by: Asitha de Silva <[email protected]>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

♻️ Duplicate comments (1)
apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.html (1)

168-191: Unique IDs for conditional State field + dynamic label ‘for’.
Prevents potential a11y/test flakiness and aligns with prior feedback.

-                <label for="state" class="block text-sm font-medium text-gray-700 mb-1">State/Province</label>
+                <label [attr.for]="isUSA() ? 'state-select' : 'state-input'" class="block text-sm font-medium text-gray-700 mb-1">State/Province</label>
                 @if (isUSA()) {
                   <lfx-select
                     size="small"
                     [form]="profileForm"
                     control="state"
                     [options]="stateOptions"
-                    id="state"
+                    id="state-select"
                     placeholder="Select your state"
                     styleClass="w-full"
                     [filter]="true"
                     data-testid="profile-edit-location-state-select">
                   </lfx-select>
                 } @else {
                   <lfx-input-text
                     size="small"
                     [form]="profileForm"
                     control="state"
-                    id="state"
+                    id="state-input"
                     placeholder="Enter your state or province"
                     styleClass="w-full"
                     data-testid="profile-edit-location-state-input">
                   </lfx-input-text>
                 }
🧹 Nitpick comments (9)
apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.html (3)

11-11: Add data-testid to form and card container for stable E2E hooks.
Minimal addition; improves test targeting at container level.

-    <form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
+    <form [formGroup]="profileForm" (ngSubmit)="onSubmit()" data-testid="profile-edit-form">
...
-      <lfx-card>
+      <lfx-card data-testid="profile-edit-card">

Also applies to: 26-26


239-247: Use inputmode for phone to improve mobile UX.
If lfx-input-text forwards arbitrary attributes, this enables numeric keypad.

-                <lfx-input-text
+                <lfx-input-text
                   size="small"
                   [form]="profileForm"
                   control="phone_number"
                   id="phone"
                   placeholder="Enter your phone number"
+                  inputmode="tel"
                   styleClass="w-full"
                   data-testid="profile-edit-location-phone">
                 </lfx-input-text>

6-9: Add live region semantics to loading state.
Improves screen reader announcement of loading.

-    <div class="flex flex-col gap-2 items-center justify-center py-12" data-testid="profile-edit-loading-container">
-      <i class="fa-light fa-circle-notch fa-spin text-4xl text-blue-400" data-testid="profile-edit-loading-spinner"></i>
-      <span class="ml-3 text-gray-600">Loading profile...</span>
+    <div class="flex flex-col gap-2 items-center justify-center py-12" role="status" aria-live="polite" data-testid="profile-edit-loading-container">
+      <i class="fa-light fa-circle-notch fa-spin text-4xl text-blue-400" aria-hidden="true" data-testid="profile-edit-loading-spinner"></i>
+      <span class="ml-3 text-gray-600">Loading profile...</span>
     </div>
apps/lfx-pcc/src/server/services/supabase.service.ts (2)

531-553: Add response body to error for easier diagnostics; optional: request single-object semantics

Including the server’s error text here matches patterns used elsewhere in this file and speeds up debugging. Optionally, consider using PostgREST single-object semantics to assert “exactly one row” when appropriate.

-    if (!response.ok) {
-      throw new Error(`Failed to fetch user profile: ${response.status} ${response.statusText}`);
-    }
+    if (!response.ok) {
+      const errorText = await response.text();
+      throw new Error(`Failed to fetch user profile: ${response.status} ${response.statusText}: ${errorText}`);
+    }

555-577: Mirror error handling style and surface server message

Return the response text on failure for consistency and better traceability.

-    if (!response.ok) {
-      throw new Error(`Failed to fetch profile details: ${response.status} ${response.statusText}`);
-    }
+    if (!response.ok) {
+      const errorText = await response.text();
+      throw new Error(`Failed to fetch profile details: ${response.status} ${response.statusText}: ${errorText}`);
+    }
apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.html (3)

40-41: Invalid Tailwind class ‘text-black-600’.
Use text-gray-600 for intended weight/tone.

-            <p class="text-black-600 text-sm mb-2" data-testid="profile-subtitle">
+            <p class="text-gray-600 text-sm mb-2" data-testid="profile-subtitle">

50-57: Anchors without href hurt a11y; prefer button or conditional link.
If no profile URL yet, render a button; when available, render an anchor with rel and target.

Example:

<!-- When URL available -->
<a [href]="githubUrl" target="_blank" rel="noopener noreferrer" aria-label="Open GitHub profile" data-testid="profile-github-profile">
  <i class="fa-brands fa-github ..."></i>
</a>

<!-- Fallback -->
<button type="button" aria-label="GitHub profile (not set)" class="text-sm text-gray-600 flex items-center gap-2" data-testid="profile-github-profile">
  <i class="fa-brands fa-github ..."></i>
</button>

118-121: Improve loading state a11y.
Expose status semantics and hide decorative spinner icon.

-    <div class="flex flex-col gap-2 items-center justify-center py-12" data-testid="profile-loading">
-      <i class="fa-light fa-circle-notch fa-spin text-4xl text-blue-400" data-testid="loading-spinner"></i>
+    <div class="flex flex-col gap-2 items-center justify-center py-12" data-testid="profile-loading" role="status" aria-live="polite" aria-busy="true" aria-label="Loading profile">
+      <i class="fa-light fa-circle-notch fa-spin text-4xl text-blue-400" data-testid="loading-spinner" aria-hidden="true"></i>
apps/lfx-pcc/src/app/layouts/profile-layout/components/profile-stats/profile-stats.component.ts (1)

38-57: Duplicate date-delta logic across components — extract to shared util.
Same logic exists in ProfileLayoutComponent; centralize to avoid drift.

Proposed shared util API:

export function formatMemberSince(createdAt: string, now = new Date()): string;
export function timeAgo(updatedAt: string, now = new Date()): string;

I can add packages/shared/src/utils/date-format.util.ts and update both callers.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 04e03ab and 4acdc61.

📒 Files selected for processing (11)
  • apps/lfx-pcc/src/app/layouts/profile-layout/components/profile-stats/profile-stats.component.html (1 hunks)
  • apps/lfx-pcc/src/app/layouts/profile-layout/components/profile-stats/profile-stats.component.scss (1 hunks)
  • apps/lfx-pcc/src/app/layouts/profile-layout/components/profile-stats/profile-stats.component.ts (1 hunks)
  • apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.html (1 hunks)
  • apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.ts (1 hunks)
  • apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.html (1 hunks)
  • apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.html (1 hunks)
  • apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.html (1 hunks)
  • apps/lfx-pcc/src/server/services/supabase.service.ts (2 hunks)
  • packages/shared/src/interfaces/index.ts (1 hunks)
  • packages/shared/src/interfaces/user-statistics.interface.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/lfx-pcc/src/app/layouts/profile-layout/components/profile-stats/profile-stats.component.scss
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/lfx-pcc/src/app/modules/profile/password/profile-password.component.html
  • packages/shared/src/interfaces/index.ts
  • apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.ts
  • apps/lfx-pcc/src/app/modules/profile/email/profile-email.component.html
🧰 Additional context used
📓 Path-based instructions (7)
apps/lfx-pcc/src/**/*.{ts,html}

📄 CodeRabbit inference engine (CLAUDE.md)

Use LFX wrapper components instead of importing PrimeNG components directly

Files:

  • apps/lfx-pcc/src/app/layouts/profile-layout/components/profile-stats/profile-stats.component.html
  • apps/lfx-pcc/src/app/layouts/profile-layout/components/profile-stats/profile-stats.component.ts
  • apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.html
  • apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.html
  • apps/lfx-pcc/src/server/services/supabase.service.ts
apps/lfx-pcc/src/**/*.html

📄 CodeRabbit inference engine (CLAUDE.md)

apps/lfx-pcc/src/**/*.html: Add data-testid attributes to new components for reliable test targeting
Follow data-testid naming convention: [section]-[component]-[element]

Files:

  • apps/lfx-pcc/src/app/layouts/profile-layout/components/profile-stats/profile-stats.component.html
  • apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.html
  • apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.html
**/*.{ts,tsx,js,jsx,html,scss,css}

📄 CodeRabbit inference engine (CLAUDE.md)

Include required license headers on all source files

Files:

  • apps/lfx-pcc/src/app/layouts/profile-layout/components/profile-stats/profile-stats.component.html
  • apps/lfx-pcc/src/app/layouts/profile-layout/components/profile-stats/profile-stats.component.ts
  • packages/shared/src/interfaces/user-statistics.interface.ts
  • apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.html
  • apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.html
  • apps/lfx-pcc/src/server/services/supabase.service.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Prefer TypeScript interfaces over union types when modeling shapes and contracts

Files:

  • apps/lfx-pcc/src/app/layouts/profile-layout/components/profile-stats/profile-stats.component.ts
  • packages/shared/src/interfaces/user-statistics.interface.ts
  • apps/lfx-pcc/src/server/services/supabase.service.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not nest ternary expressions

Files:

  • apps/lfx-pcc/src/app/layouts/profile-layout/components/profile-stats/profile-stats.component.ts
  • packages/shared/src/interfaces/user-statistics.interface.ts
  • apps/lfx-pcc/src/server/services/supabase.service.ts
apps/lfx-pcc/src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

apps/lfx-pcc/src/**/*.ts: In the Angular app, use direct imports for standalone components (no barrel imports)
When defining types for PrimeNG usage, reference PrimeNG’s component interfaces

Files:

  • apps/lfx-pcc/src/app/layouts/profile-layout/components/profile-stats/profile-stats.component.ts
  • apps/lfx-pcc/src/server/services/supabase.service.ts
packages/shared/src/interfaces/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place all shared interfaces in the shared package

Files:

  • packages/shared/src/interfaces/user-statistics.interface.ts
🧬 Code graph analysis (2)
apps/lfx-pcc/src/app/layouts/profile-layout/components/profile-stats/profile-stats.component.ts (3)
apps/lfx-pcc/src/app/layouts/profile-layout/profile-layout.component.ts (1)
  • Component (18-229)
packages/shared/src/interfaces/user-profile.interface.ts (1)
  • CombinedProfile (39-42)
packages/shared/src/interfaces/user-statistics.interface.ts (1)
  • UserStatistics (7-14)
apps/lfx-pcc/src/server/services/supabase.service.ts (1)
packages/shared/src/interfaces/user-profile.interface.ts (4)
  • UserProfile (7-15)
  • ProfileDetails (20-34)
  • UpdateUserProfileRequest (47-52)
  • UpdateProfileDetailsRequest (57-67)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: E2E Tests / Playwright E2E Tests
🔇 Additional comments (6)
apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.html (2)

1-2: License header present — good.
Complies with header/SPDX requirements.


307-308: Use LFX toast wrapper (or add data-testid) — p-toast found in 3 files

Guideline: use LFX wrapper components in apps/lfx-pcc and add data-testid attributes using [section]-[component]-[element]. Ripgrep shows no lfx-toast wrapper and these usages:

  • apps/lfx-pcc/src/app/modules/profile/edit/profile-edit.component.html:308 — replace with (or, if wrapper not available yet, add data-testid: ).
  • apps/lfx-pcc/src/app/modules/meeting/meeting.component.html:319 — replace with (or add ).
  • apps/lfx-pcc/src/app/app.component.html:3 — replace with (or ).

Either implement a central LFX toast wrapper and switch all usages, or add the data-testid now and follow up with a wrapper PR.

apps/lfx-pcc/src/server/services/supabase.service.ts (1)

11-11: Imports for profile management: LGTM

Types align with shared interfaces and match table shapes.

Also applies to: 15-15, 17-17, 21-21

packages/shared/src/interfaces/user-statistics.interface.ts (1)

7-14: LGTM — clear, minimal interface fits shared surface.
No issues spotted. Re-export usage in consumers looks correct.

apps/lfx-pcc/src/app/layouts/profile-layout/components/profile-stats/profile-stats.component.ts (2)

6-8: Import path check (FYI).
Interfaces come from shared barrel; fine. Keep using direct imports only for standalone components per guideline—CardComponent import already complies.


1-3: License header present and correct.

Signed-off-by: Asitha de Silva <[email protected]>
@asithade asithade merged commit 8a9d902 into main Sep 12, 2025
7 checks passed
@asithade asithade deleted the feat/LFXV2-454 branch September 12, 2025 00:35
@github-actions
Copy link

🧹 Deployment Removed

The deployment for PR #83 has been removed.

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.

3 participants