Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,164 +12,148 @@
}

@if (committees() && !committeesLoading()) {
<div class="grid grid-cols-1 lg:grid-cols-4 gap-6 items-stretch">
<div class="lg:col-span-3 items-stretch h-full">
<lfx-card header="Committees" styleClass="h-full" class="h-full">
<!-- Search and Filter Controls -->
<div class="flex flex-col sm:flex-row gap-4 mb-6">
<!-- Search Input -->
<div class="flex-1">
<lfx-input-text
[form]="searchForm"
control="search"
placeholder="Search committees..."
icon="fa-light fa-search"
styleClass="w-full"
size="small"></lfx-input-text>
</div>
<div class="flex flex-col gap-6">
<div class="flex items-center justify-between p-4 border-b border-gray-100">
<div>
<h2 class="text-[16px] font-bold text-gray-900">Committee Management</h2>
<p class="text-[12px] font-normal text-gray-500 mt-1">
Manage committees, their settings, and organizational structure. Sub-committees are indicated with indentation.
</p>
</div>
<lfx-button
label="New Committee"
icon="fa-light fa-plus"
severity="primary"
(onClick)="openCreateDialog()"
size="small"
data-testid="committee-new-cta">
</lfx-button>
</div>

<!-- Category Filter Dropdown -->
<div class="w-full sm:w-64">
<lfx-select
[form]="searchForm"
control="category"
size="small"
[options]="categories()"
placeholder="Select Category"
[showClear]="true"
styleClass="w-full"
(onChange)="onCategoryChange($event.value)"></lfx-select>
<!-- Statistics Cards -->
<div class="grid grid-cols-1 md:grid-cols-4 gap-3 w-full">
<lfx-card styleClass="bg-white border border-gray-100 shadow-sm h-full" data-testid="stats-total-committees">
<div class="p-3">
<div class="text-[10px] text-gray-500 font-normal mb-1">Total Committees</div>
<div class="flex items-center gap-2">
<span class="text-[24px] text-gray-900 font-normal">{{ totalCommittees() }}</span>
<div class="flex items-center gap-1 text-emerald-600">
<i class="fa-light fa-trending-up text-[8px]"></i>
<span class="text-[10px] font-medium">+2 this week</span>
</div>
</div>
</div>
</lfx-card>

@if (committees().length > 0) {
<!-- Committees Table -->
<lfx-table
[value]="filteredCommittees()"
[paginator]="true"
[totalRecords]="totalRecords()"
[rowsPerPageOptions]="[10, 25, 50]"
[showCurrentPageReport]="true"
currentPageReportTemplate="Showing {first} to {last} of {totalRecords} committees"
(onPage)="onPageChange($event)"
styleClass="p-datatable-sm animate-fade-in-up">
<!-- Header Template -->
<ng-template #header>
<tr>
<th>
<span class="text-sm font-sans text-gray-500">Name</span>
</th>
<th>
<span class="text-sm font-sans text-gray-500">Type</span>
</th>
<th>
<div class="flex justify-center">
<span class="text-sm font-sans text-gray-500">Members</span>
</div>
</th>
<th>
<div class="flex justify-center">
<span class="text-sm font-sans text-gray-500">Voting</span>
</div>
</th>
<th>
<div class="flex justify-center">
<span class="text-sm font-sans text-gray-500">Public</span>
</div>
</th>
<th>
<div class="flex justify-end">
<span class="text-sm font-sans text-gray-500">Last Updated</span>
</div>
</th>
<th style="width: 80px">
<div class="flex justify-center">
<span class="text-sm font-sans text-gray-500">Actions</span>
</div>
</th>
</tr>
</ng-template>

<!-- Body Template -->
<ng-template #body let-committee>
<tr>
<td>
<a [routerLink]="['/project', project()?.slug, 'committees', committee.id]" class="text-primary hover:text-primary-600 font-medium text-sm">
{{ committee.name }}
</a>
</td>
<td>
<span class="text-sm font-sans text-gray-500">{{ committee.category || 'Uncategorized' }}</span>
</td>
<td class="text-center">
<span class="text-sm font-sans text-gray-500"> {{ committee.total_members || 0 }} </span>
</td>
<td class="text-center">
<span class="text-sm font-sans text-gray-500"> {{ committee.enable_voting ? 'Yes' : 'No' }} </span>
</td>
<td class="text-center">
<i class="fa-light fa-circle-check text-green-500" *ngIf="committee.public_enabled"></i>
<i class="fa-light fa-circle-xmark text-red-500" *ngIf="!committee.public_enabled"></i>
</td>
<td class="text-right">
<span class="text-sm font-sans text-gray-500"> {{ formatDate(committee.updated_at) }} </span>
</td>
<td class="text-center relative">
<lfx-button
icon="fa-light fa-ellipsis-vertical"
[text]="true"
[rounded]="true"
size="small"
severity="secondary"
(click)="toggleActionMenu($event, committee, actionMenu)"></lfx-button>
</td>
</tr>
</ng-template>

<!-- Empty Message Template -->
<ng-template #emptymessage>
<tr>
<td colspan="7" class="text-center py-8">
<div class="flex flex-col items-center gap-2">
<i class="fa-light fa-users text-4xl text-gray-400"></i>
<p class="text-gray-600">No committees found</p>
<p class="text-sm text-gray-500">Try adjusting your search or filters</p>
</div>
</td>
</tr>
</ng-template>
</lfx-table>

<!-- Single action menu for all committees -->
<lfx-menu #actionMenu [model]="actionMenuItems" [popup]="true"></lfx-menu>
<lfx-card styleClass="bg-white border border-gray-100 shadow-sm h-full" data-testid="stats-public-committees">
<div class="p-3">
<div class="text-[10px] text-gray-500 font-normal mb-1">Public Committees</div>
<div class="flex items-center gap-2">
<span class="text-[24px] text-gray-900 font-normal">{{ publicCommittees() }}</span>
<div class="inline-flex items-center gap-1 px-1.5 py-0.5 rounded bg-blue-100 text-blue-600 border border-blue-200">
<span class="text-[9px] font-medium"
>{{ totalCommittees() > 0 ? ((publicCommittees() / totalCommittees()) * 100 | number: '1.0-0') : 0 }}% of total</span
>
</div>
</div>
</div>
</lfx-card>

<!-- Confirmation dialog -->
<p-confirmDialog></p-confirmDialog>
} @else {
<div class="flex justify-center items-center h-full">
<div class="text-center py-8">
<i class="fa-light fa-people-group text-4xl text-gray-400 mb-4"></i>
<h3 class="text-lg font-medium text-gray-900 mb-2">No Committees Yet</h3>
<p class="text-gray-600 mb-4">This project doesn't have any committees yet.</p>
<lfx-button label="Add First Committee" icon="fa-light fa-people-group" severity="secondary" (onClick)="openCreateDialog()"></lfx-button>
<lfx-card styleClass="bg-white border border-gray-100 shadow-sm h-full" data-testid="stats-active-voting">
<div class="p-3">
<div class="text-[10px] text-gray-500 font-normal mb-1">Active Voting</div>
<div class="flex items-center gap-2">
<span class="text-[24px] text-gray-900 font-normal">{{ activeVoting() }}</span>
<div class="inline-flex items-center gap-1 px-1.5 py-0.5 rounded bg-green-100 text-green-600 border border-green-200">
<span class="text-[9px] font-medium">Voting enabled</span>
</div>
</div>
}
</div>
</lfx-card>

<lfx-card styleClass="bg-white border border-gray-100 shadow-sm h-full items-center" data-testid="stats-upcoming-meeting">
<div class="p-3">
<div class="text-[10px] text-gray-500 font-normal mb-1">Upcoming Meeting</div>
<lfx-upcoming-committee-meeting></lfx-upcoming-committee-meeting>
</div>
</lfx-card>
</div>
<div class="lg:col-span-1 items-stretch flex flex-col">
<div class="sticky top-24">
<lfx-card header="Quick Actions">
<lfx-menu [model]="menuItems" styleClass="border-none"></lfx-menu>
</lfx-card>

<div class="flex flex-col gap-4 mt-6">
<lfx-card header="Upcoming Meeting" styleClass="h-full" class="h-full">
<lfx-upcoming-committee-meeting></lfx-upcoming-committee-meeting>
</lfx-card>
<!-- Committee Management Section -->
<lfx-card styleClass="h-full" class="h-full">
<!-- Search and Filter Controls -->
<div class="flex flex-col sm:flex-row gap-4 mb-6 p-4">
<!-- Search Input -->
<div class="flex-1">
<lfx-input-text
[form]="searchForm"
control="search"
placeholder="Search committees..."
icon="fa-light fa-search"
styleClass="w-full"
size="small"
data-testid="committee-search-input"></lfx-input-text>
</div>

<!-- Committee Type Filter Dropdown -->
<div class="w-full sm:w-64">
<lfx-select
[form]="searchForm"
control="category"
size="small"
[options]="categories()"
placeholder="Select Committee Type"
[showClear]="true"
styleClass="w-full"
(onChange)="onCategoryChange($event.value)"
data-testid="committee-type-filter"></lfx-select>
</div>

<!-- Voting Status Filter Dropdown -->
<div class="w-full sm:w-64">
<lfx-select
[form]="searchForm"
control="votingStatus"
size="small"
[options]="votingStatusOptions()"
placeholder="Select Voting Status"
[showClear]="true"
styleClass="w-full"
(onChange)="onVotingStatusChange($event.value)"
data-testid="committee-voting-status-filter"></lfx-select>
</div>
</div>
</div>

@if (committees().length > 0) {
<!-- Committee Table -->
<div class="px-4 pb-4">
<lfx-committee-table
[committees]="filteredCommittees()"
(editCommittee)="onEditCommittee($event)"
(deleteCommittee)="onDeleteCommittee($event)"
(viewCommittee)="onViewCommittee($event)"
data-testid="committee-dashboard-table">
</lfx-committee-table>
</div>

<!-- Confirmation dialog -->
<p-confirmDialog></p-confirmDialog>
} @else {
<div class="flex justify-center items-center h-full p-4">
<div class="text-center py-8">
<i class="fa-light fa-people-group text-4xl text-gray-400 mb-4"></i>
<h3 class="text-lg font-medium text-gray-900 mb-2">No Committees Yet</h3>
<p class="text-gray-600 mb-4">This project doesn't have any committees yet.</p>
<lfx-button
label="Add First Committee"
icon="fa-light fa-people-group"
severity="secondary"
(onClick)="openCreateDialog()"
data-testid="committee-add-first"></lfx-button>
</div>
</div>
}
</lfx-card>
</div>
}
</div>
Loading
Loading