@@ -42,15 +42,19 @@ import { useQuery } from "@pinia/colada";
4242import { getAllCompanies } from " @/api/companies" ;
4343import { getAllSpeakers } from " @/api/speakers" ;
4444import { getAllMembers } from " @/api/members" ;
45- import type { Company , CompanyParticipation } from " @/dto/companies" ;
46- import type { Speaker , SpeakerParticipation } from " @/dto/speakers" ;
45+ import type { Company } from " @/dto/companies" ;
46+ import type { Speaker } from " @/dto/speakers" ;
4747import type { Member } from " @/dto/members" ;
4848import { useEventStore } from " @/stores/event" ;
4949import LeaderboardCard from " @/components/Leaderboard/LeaderboardCard.vue" ;
5050import { humanReadableParticipationStatus } from " @/dto" ;
5151// icons are used inside LeaderboardCard
5252
53- const BOT_ACCOUNTS = new Set ([" ToolBot!" , " zzPartnerships" ]);
53+ const BOT_ACCOUNTS = new Set ([
54+ " ToolBot!" ,
55+ " zzPartnerships" ,
56+ " zzPartnernerships" ,
57+ ]);
5458
5559const eventStore = useEventStore ();
5660const selectedStatus = ref <string >(" " );
@@ -105,17 +109,26 @@ function computeRanks(rows: LeaderRow[]): RankedLeaderRow[] {
105109 return ranked ;
106110}
107111
108- const companyLeaderboard = computed <RankedLeaderRow []>(() => {
112+ // Generic helper to build leaderboards from any collection (companies or speakers)
113+ function computeLeaderboardFrom<
114+ TItem ,
115+ TParticipation extends { event? : number ; status? : string ; member? : unknown },
116+ >(
117+ items : TItem [],
118+ getParticipations : (it : TItem ) => TParticipation [] | undefined ,
119+ getName : (it : TItem ) => string ,
120+ botSet = BOT_ACCOUNTS ,
121+ ): RankedLeaderRow [] {
109122 const rows = new Map <string , LeaderRow >();
110123 const eventId = eventStore .selectedEvent ?.id ;
111- const companies = ( companiesData . value ?. data || []) as Company [];
112- companies .forEach ((c : Company ) => {
113- (c . participations || []).forEach ((p : CompanyParticipation ) => {
124+
125+ items .forEach ((it : TItem ) => {
126+ (getParticipations ( it ) || []).forEach ((p : TParticipation ) => {
114127 if (p .event !== eventId ) return ;
115128 if (selectedStatus .value && p .status !== selectedStatus .value ) return ;
116129 if (! p .member ) return ;
117130 const id = p .member as string ;
118- const entry =
131+ const entry: LeaderRow =
119132 rows .get (id ) ||
120133 ({
121134 memberId: id ,
@@ -124,7 +137,7 @@ const companyLeaderboard = computed<RankedLeaderRow[]>(() => {
124137 member: { id , name: " Unknown" , img: " " , sinfoid: " " } as Member ,
125138 } as LeaderRow );
126139 entry .count += 1 ;
127- entry .items .push (c . name );
140+ entry .items .push (getName ( it ) );
128141 rows .set (id , entry );
129142 });
130143 });
@@ -141,52 +154,28 @@ const companyLeaderboard = computed<RankedLeaderRow[]>(() => {
141154 const filtered = arr .filter ((r ) => {
142155 const name = (r .member ?.name || " " ) as string ;
143156 const sinfoid = (r .member ?.sinfoid || " " ) as string ;
144- return ! BOT_ACCOUNTS .has (name ) && ! BOT_ACCOUNTS .has (sinfoid );
157+ return ! botSet .has (name ) && ! botSet .has (sinfoid );
145158 });
146159
147160 return computeRanks (filtered );
161+ }
162+
163+ const companyLeaderboard = computed <RankedLeaderRow []>(() => {
164+ const companies = (companiesData .value ?.data || []) as Company [];
165+ return computeLeaderboardFrom (
166+ companies ,
167+ (c : Company ) => c .participations ,
168+ (c : Company ) => c .name ,
169+ );
148170});
149171
150172const speakerLeaderboard = computed <RankedLeaderRow []>(() => {
151- const rows = new Map <string , LeaderRow >();
152- const eventId = eventStore .selectedEvent ?.id ;
153173 const speakers = (speakersData .value ?.data || []) as Speaker [];
154- speakers .forEach ((s : Speaker ) => {
155- (s .participations || []).forEach ((p : SpeakerParticipation ) => {
156- if (p .event !== eventId ) return ;
157- if (selectedStatus .value && p .status !== selectedStatus .value ) return ;
158- if (! p .member ) return ;
159- const id = p .member as string ;
160- const entry =
161- rows .get (id ) ||
162- ({
163- memberId: id ,
164- count: 0 ,
165- items: [] as string [],
166- member: { id , name: " Unknown" , img: " " , sinfoid: " " } as Member ,
167- } as LeaderRow );
168- entry .count += 1 ;
169- entry .items .push (s .name );
170- rows .set (id , entry );
171- });
172- });
173-
174- const arr = Array .from (rows .values ());
175- arr .forEach ((r ) => {
176- r .member =
177- membersData .value ?.data ?.find ((m : Member ) => m .id === r .memberId ) ||
178- ({ id: r .memberId , name: " Unknown" , img: " " , sinfoid: " " } as Member );
179- });
180-
181- // filter out bot accounts by name or sinfoid
182- const bots = new Set ([" ToolBot!" , " zzPartnernerships" ]);
183- const filtered = arr .filter ((r ) => {
184- const name = (r .member ?.name || " " ) as string ;
185- const sinfoid = (r .member ?.sinfoid || " " ) as string ;
186- return ! bots .has (name ) && ! bots .has (sinfoid );
187- });
188-
189- return computeRanks (filtered );
174+ return computeLeaderboardFrom (
175+ speakers ,
176+ (s : Speaker ) => s .participations ,
177+ (s : Speaker ) => s .name ,
178+ );
190179});
191180 </script >
192181
0 commit comments