Skip to content

Commit 928ab37

Browse files
authored
refactor(meetings): migrate to global architecture (#161)
* fix(meetings): load past and upcoming meetings separately (LFXV2-757) Fixed recurring meetings incorrectly showing as past by refactoring to use separate API endpoints for upcoming and past meetings: - Load upcoming meetings via getMeetingsByProject() - Load past meetings via getPastMeetingsByProject() - React to timeFilter changes to call appropriate endpoint - Hide RSVP button for non-organizers on past meetings - Removed client-side time filtering (handled by API) This ensures proper meeting categorization and enables accurate counts for both upcoming and past meetings. Generated with [Claude Code](https://claude.ai/code) Signed-off-by: Asitha de Silva <[email protected]> * feat(ssr): migrate project context to SSR-compatible cookies (LFXV2-757) Migrated project selection persistence from localStorage to cookies using ngx-cookie-service-ssr for full SSR compatibility: Project Context Changes: - Replace localStorage with SsrCookieService - Cookies work on both server and client-side - 30-day expiration, SameSite=Lax security - Fixes project context being null during SSR Meeting/Committee Dashboard Fixes: - Use combineLatest to prevent duplicate API calls - Lazy load data only for active tabs - Fix loading states to prevent "No data found" flash - Add project existence check to empty states - Remove counters from filter buttons UI Improvements: - Hide RSVP buttons for non-organizers on past meetings - Improve label consistency in committee form This enables data fetching during SSR when project is selected, eliminating loading delays and improving initial render performance. Generated with [Claude Code](https://claude.ai/code) Signed-off-by: Asitha de Silva <[email protected]> * refactor(meetings): migrate to global architecture - Moved meetings module from /project/:slug/meetings to /meetings for improved UX - Relocated all meeting components from modules/project/meetings to modules/meetings - Added new routes: /meetings/create and /meetings/:id/edit for meeting management - Updated meeting-card component to use global meeting routes - Fixed meeting-card registrant toggle to not show add button for past meetings - Added feature flag service to sidebar for role selector control - Reordered meeting features constants to prioritize AI Summary feature BREAKING CHANGE: Meeting routes moved from project-scoped to global scope LFXV2-757 LFXV2-760 LFXV2-761 LFXV2-762 Generated with [Claude Code](https://claude.ai/code) Signed-off-by: Asitha de Silva <[email protected]> --------- Signed-off-by: Asitha de Silva <[email protected]>
1 parent fcef70a commit 928ab37

File tree

53 files changed

+216
-785
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+216
-785
lines changed

apps/lfx-one/src/app/modules/committees/committee-dashboard/committee-dashboard.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,14 @@ <h1 class="font-inter text-xl font-semibold">{{ committeeLabelPlural }}</h1>
7474

7575
<!-- Content Area - Table or Cards -->
7676
<div class="w-full">
77-
@if (filteredCommittees().length === 0) {
77+
@if (filteredCommittees().length === 0 && project()?.projectId) {
7878
<div class="text-center py-12">
7979
<div class="bg-muted/50 rounded-lg p-8">
8080
<i class="fa-light fa-people-group text-5xl text-muted-foreground mb-4"></i>
8181
<h3 class="text-muted-foreground">No {{ committeeLabelPlural.toLowerCase() }} found</h3>
8282
</div>
8383
</div>
84-
} @else {
84+
} @else if (filteredCommittees().length > 0) {
8585
<lfx-committee-table
8686
[committees]="filteredCommittees()"
8787
[canManageCommittee]="canCreateGroup()"

apps/lfx-one/src/app/modules/committees/committee-dashboard/committee-dashboard.component.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { CommitteeService } from '@services/committee.service';
1616
import { PersonaService } from '@services/persona.service';
1717
import { ConfirmationService, MessageService } from 'primeng/api';
1818
import { ConfirmDialogModule } from 'primeng/confirmdialog';
19-
import { BehaviorSubject, catchError, debounceTime, distinctUntilChanged, merge, of, startWith, switchMap, tap } from 'rxjs';
19+
import { BehaviorSubject, catchError, combineLatest, debounceTime, distinctUntilChanged, finalize, of, startWith, switchMap } from 'rxjs';
2020

2121
import { CommitteeTableComponent } from '../components/committee-table/committee-table.component';
2222

@@ -230,25 +230,20 @@ export class CommitteeDashboardComponent {
230230
const project$ = toObservable(this.project);
231231

232232
return toSignal(
233-
merge(
234-
project$, // Triggers on project context changes
235-
this.refresh // Triggers on manual refresh
236-
).pipe(
237-
tap(() => this.committeesLoading.set(true)),
238-
switchMap(() => {
239-
const project = this.project();
233+
combineLatest([project$, this.refresh]).pipe(
234+
switchMap(([project]) => {
240235
if (!project?.projectId) {
241236
this.committeesLoading.set(false);
242237
return of([]);
243238
}
244239

240+
this.committeesLoading.set(true);
245241
return this.committeeService.getCommitteesByProject(project.projectId).pipe(
246242
catchError((error) => {
247243
console.error('Failed to load committees:', error);
248-
this.committeesLoading.set(false);
249244
return of([]);
250245
}),
251-
tap(() => this.committeesLoading.set(false))
246+
finalize(() => this.committeesLoading.set(false))
252247
);
253248
})
254249
),

apps/lfx-one/src/app/modules/committees/components/committee-form/committee-form.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ export class CommitteeFormComponent {
8080
value: committee.uid,
8181
}));
8282

83-
// Add "No Parent Committee" option at the beginning
84-
return [{ label: 'No Parent Committee', value: null }, ...options];
83+
// Add "No Parent Group" option at the beginning
84+
return [{ label: 'No Parent ' + this.committeeLabel, value: null }, ...options];
8585
});
8686
}
8787
}

apps/lfx-one/src/app/modules/project/meetings/components/agenda-template-selector/agenda-template-selector.component.html renamed to apps/lfx-one/src/app/modules/meetings/components/agenda-template-selector/agenda-template-selector.component.html

File renamed without changes.

apps/lfx-one/src/app/modules/project/meetings/components/agenda-template-selector/agenda-template-selector.component.ts renamed to apps/lfx-one/src/app/modules/meetings/components/agenda-template-selector/agenda-template-selector.component.ts

File renamed without changes.

apps/lfx-one/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.html renamed to apps/lfx-one/src/app/modules/meetings/components/meeting-committee-modal/meeting-committee-modal.component.html

File renamed without changes.

apps/lfx-one/src/app/modules/project/meetings/components/meeting-committee-modal/meeting-committee-modal.component.ts renamed to apps/lfx-one/src/app/modules/meetings/components/meeting-committee-modal/meeting-committee-modal.component.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { VOTING_STATUSES } from '@lfx-one/shared';
1212
import { Committee, CommitteeMember, Meeting } from '@lfx-one/shared/interfaces';
1313
import { CommitteeService } from '@services/committee.service';
1414
import { MeetingService } from '@services/meeting.service';
15-
import { ProjectService } from '@services/project.service';
15+
import { ProjectContextService } from '@services/project-context.service';
1616
import { MessageService } from 'primeng/api';
1717
import { DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';
1818
import { TooltipModule } from 'primeng/tooltip';
@@ -35,8 +35,8 @@ export class MeetingCommitteeModalComponent {
3535
private readonly config = inject(DynamicDialogConfig);
3636
private readonly committeeService = inject(CommitteeService);
3737
private readonly meetingService = inject(MeetingService);
38-
private readonly projectService = inject(ProjectService);
3938
private readonly messageService = inject(MessageService);
39+
private readonly projectContextService = inject(ProjectContextService);
4040

4141
// Inputs
4242
public readonly meeting: Meeting = this.config.data.meeting;
@@ -60,7 +60,7 @@ export class MeetingCommitteeModalComponent {
6060

6161
// Load committees using toSignal
6262
public committees: Signal<Committee[]> = toSignal(
63-
this.committeeService.getCommitteesByProject(this.projectService.project()?.uid || '').pipe(
63+
this.committeeService.getCommitteesByProject(this.projectContextService.getProjectId() || '').pipe(
6464
tap(() => this.committeesLoading.set(false)),
6565
catchError((error) => {
6666
console.error('Failed to load committees:', error);

apps/lfx-one/src/app/modules/project/meetings/components/meeting-details/meeting-details.component.html renamed to apps/lfx-one/src/app/modules/meetings/components/meeting-details/meeting-details.component.html

File renamed without changes.

apps/lfx-one/src/app/modules/project/meetings/components/meeting-details/meeting-details.component.ts renamed to apps/lfx-one/src/app/modules/meetings/components/meeting-details/meeting-details.component.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { GenerateAgendaRequest, MeetingTemplate } from '@lfx-one/shared';
1717
import { TIMEZONES } from '@lfx-one/shared/constants';
1818
import { getWeekOfMonth } from '@lfx-one/shared/utils';
1919
import { MeetingService } from '@services/meeting.service';
20-
import { ProjectService } from '@services/project.service';
20+
import { ProjectContextService } from '@services/project-context.service';
2121
import { MessageService } from 'primeng/api';
2222
import { TooltipModule } from 'primeng/tooltip';
2323
import { finalize, take, tap } from 'rxjs';
@@ -46,9 +46,9 @@ import { MeetingRecurrencePatternComponent } from '../meeting-recurrence-pattern
4646
templateUrl: './meeting-details.component.html',
4747
})
4848
export class MeetingDetailsComponent implements OnInit {
49-
private readonly projectService = inject(ProjectService);
5049
private readonly meetingService = inject(MeetingService);
5150
private readonly messageService = inject(MessageService);
51+
private readonly projectContextService = inject(ProjectContextService);
5252

5353
// Form group input from parent
5454
public readonly form = input.required<FormGroup>();
@@ -172,7 +172,7 @@ export class MeetingDetailsComponent implements OnInit {
172172

173173
public async generateAiAgenda(): Promise<void> {
174174
const context = this.form().get('aiPrompt')?.value;
175-
const currentProject = this.projectService.project();
175+
const currentProject = this.projectContextService.selectedProject();
176176
const form = this.form();
177177
const title = form.get('title')?.value;
178178
const meetingType = form.get('meeting_type')?.value;

apps/lfx-one/src/app/modules/project/meetings/components/meeting-modal/meeting-modal.component.html renamed to apps/lfx-one/src/app/modules/meetings/components/meeting-modal/meeting-modal.component.html

File renamed without changes.

0 commit comments

Comments
 (0)