Skip to content

Commit 40afaa7

Browse files
committed
feat: add team selection filter to MembersCompanies component
1 parent c224cbb commit 40afaa7

File tree

2 files changed

+57
-7
lines changed

2 files changed

+57
-7
lines changed

frontend/src/components/companies/MembersCompanies.vue

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,28 @@
44
<CreateCompanyDialogTrigger />
55
</div>
66

7-
<ParticipationFilters
8-
v-model:selected="selectedStatus"
9-
v-model:selected-package="selectedPackage"
10-
:packages="packages"
11-
/>
7+
<div class="flex flex-wrap gap-3 mb-4 items-center">
8+
<ParticipationFilters
9+
v-model:selected="selectedStatus"
10+
v-model:selected-package="selectedPackage"
11+
:packages="packages"
12+
/>
13+
<Select v-model="selectedTeamId">
14+
<SelectTrigger class="w-52">
15+
<SelectValue placeholder="All teams" />
16+
</SelectTrigger>
17+
<SelectContent>
18+
<SelectItem value="all">All teams</SelectItem>
19+
<SelectItem
20+
v-for="team in coordinationTeams"
21+
:key="team.id"
22+
:value="team.id"
23+
>
24+
{{ team.name }}
25+
</SelectItem>
26+
</SelectContent>
27+
</Select>
28+
</div>
1229

1330
<div
1431
v-if="!membersSorted.length && companiesLoading"
@@ -23,8 +40,9 @@
2340

2441
<DynamicScroller
2542
v-else
43+
:key="selectedTeamId"
2644
:items="membersSorted"
27-
class="h-100"
45+
page-mode
2846
:min-item-size="1"
2947
>
3048
<template #default="{ item }">
@@ -70,6 +88,7 @@
7088
<script setup lang="ts">
7189
import type { Company, CompanyParticipation } from "@/dto/companies";
7290
import type { Member } from "@/dto/members";
91+
import type { CoordinationTeam } from "@/dto/coordinationTeams";
7392
import MemberWithAvatar from "@/components/members/MemberWithAvatar.vue";
7493
import { DynamicScroller } from "vue-virtual-scroller";
7594
import { useInsertionSort, useSortByParticipationStatus } from "@/lib/utils";
@@ -82,17 +101,34 @@ import { useParticipationFilter } from "@/composables/useParticipationFilter";
82101
import type { ObjectID, ParticipationStatus } from "@/dto";
83102
import ParticipationFilters from "@/components/ParticipationFilters.vue";
84103
import { useEventPackagesQuery } from "@/mutations/packages";
104+
import {
105+
Select,
106+
SelectContent,
107+
SelectItem,
108+
SelectTrigger,
109+
SelectValue,
110+
} from "@/components/ui/select";
85111
86112
const props = defineProps<{
87113
companies: Company[];
88114
companiesLoading?: boolean;
89115
members: Member[];
90116
eventId: number;
117+
coordinationTeams?: CoordinationTeam[];
91118
}>();
92119
93120
// TODO shift me to top
94121
const membersSorted = computed(() => {
95-
return [...props.members]?.sort((a, b) => a.name.localeCompare(b.name));
122+
const sorted = [...props.members]?.sort((a, b) =>
123+
a.name.localeCompare(b.name),
124+
);
125+
if (!selectedTeamId.value || selectedTeamId.value === "all") return sorted;
126+
const team = props.coordinationTeams?.find(
127+
(t) => t.id === selectedTeamId.value,
128+
);
129+
if (!team) return sorted;
130+
const teamMemberSet = new Set(team.coordinatedMembers);
131+
return sorted.filter((m) => teamMemberSet.has(m.id));
96132
});
97133
98134
const membersMap = computed(() => {
@@ -105,6 +141,11 @@ const membersMap = computed(() => {
105141
);
106142
});
107143
144+
// Set of member IDs visible after team filtering
145+
const visibleMemberIds = computed(
146+
() => new Set(membersSorted.value.map((m) => m.id)),
147+
);
148+
108149
interface CompanyWithParticipation extends Company {
109150
participation: CompanyParticipation;
110151
}
@@ -118,6 +159,7 @@ const participations = computed(() =>
118159
if (currParticipation && currParticipation.member in membersMap.value!) {
119160
const member = membersMap.value?.[currParticipation.member];
120161
if (!member) return acc; // Skip if member not found
162+
if (!visibleMemberIds.value.has(member.id)) return acc; // skip filtered-out members
121163
122164
if (!acc.has(member.id)) acc.set(member.id, []);
123165
@@ -138,6 +180,7 @@ const participations = computed(() =>
138180
139181
const selectedStatus = ref<ParticipationStatus | null>(null);
140182
const selectedPackage = ref<ObjectID | null>(null);
183+
const selectedTeamId = ref<string>("all");
141184
142185
// Fetch packages for filter, pre-filtered by current event
143186
const { data: packages } = useEventPackagesQuery();

frontend/src/views/Dashboard/Companies/CompaniesView.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
:companies-loading="isCompaniesLoading"
55
:members="membersList?.data || []"
66
:event-id="eventStore.selectedEvent?.id || 0"
7+
:coordination-teams="coordinationTeamsList?.data || []"
78
/>
89
</template>
910

@@ -16,6 +17,7 @@ import { useEventStore } from "@/stores/event";
1617
import { getAllMembers } from "@/api/members";
1718
import type { AllMembersFilter } from "@/dto/members";
1819
import MembersCompanies from "@/components/companies/MembersCompanies.vue";
20+
import { getAllCoordinationTeams } from "@/api/coordinationTeams";
1921
2022
const eventStore = useEventStore();
2123
const companiesFilters = computed<AllCompaniesFilter>(() => ({
@@ -35,4 +37,9 @@ const { data: membersList } = useQuery({
3537
key: () => ["members", JSON.stringify(membersFilters.value)],
3638
query: () => getAllMembers(membersFilters.value),
3739
});
40+
41+
const { data: coordinationTeamsList } = useQuery({
42+
key: ["coordinationTeams"],
43+
query: () => getAllCoordinationTeams(),
44+
});
3845
</script>

0 commit comments

Comments
 (0)