WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit aa69e42

Browse files
Strehkm1212e
andauthored
✨ feature: Add postal and payment stats (#181)
* ✨ feat: stats for ConferenceStatsu * 🧼 format & lint * 🧹 chore * 🐞 fix: update gql file --------- Co-authored-by: Tade Strehk <[email protected]> Co-authored-by: m1212e <[email protected]>
1 parent 5fe2960 commit aa69e42

File tree

9 files changed

+216
-4
lines changed

9 files changed

+216
-4
lines changed

.github/workflows/build_run.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
- name: Checkout
1111
uses: actions/checkout@v4
1212
- uses: oven-sh/setup-bun@v2
13-
- run: bun install
13+
- run: bun install --frozen-lockfile
1414
- run: bun run build
1515
- run: bun run check
1616
- run: |

bun.lockb

0 Bytes
Binary file not shown.

schema.graphql

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2690,6 +2690,7 @@ type StatisticsResult {
26902690
diet: StatisticsResultRegisteredParticipantDiet!
26912691
gender: StatisticsResultRegisteredParticipantGender!
26922692
registered: StatisticsResultRegistered!
2693+
status: StatisticsResultRegisteredParticipantStatus!
26932694
}
26942695

26952696
type StatisticsResultCountdowns {
@@ -2757,6 +2758,22 @@ type StatisticsResultRegisteredParticipantGenderVariations {
27572758
noStatement: Int!
27582759
}
27592760

2761+
type StatisticsResultRegisteredParticipantStatus {
2762+
didAttend: Int!
2763+
paymentStatus: StatisticsResultRegisteredParticipantStatusPayment!
2764+
postalStatus: StatisticsResultRegisteredParticipantStatusPostalRegistration!
2765+
}
2766+
2767+
type StatisticsResultRegisteredParticipantStatusPayment {
2768+
done: Int!
2769+
problem: Int!
2770+
}
2771+
2772+
type StatisticsResultRegisteredParticipantStatusPostalRegistration {
2773+
done: Int!
2774+
problem: Int!
2775+
}
2776+
27602777
type StatisticsResultRegisteredSingleParticipants {
27612778
applied: Int!
27622779
byRole: [StatisticsResultRegisteredSingleParticipantsByRole!]!

src/api/resolvers/modules/conference/statistics.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { requireToBeConferenceAdmin } from '$api/services/requireUserToBeConferenceAdmin';
22
import { conferenceStats } from '$api/services/stats';
33
import { db } from '$db/db';
4+
import { payment, postalRegistration } from '$lib/paraglide/messages';
45
import { builder } from '../../builder';
56

67
const dietVariations = builder.simpleObject('StatisticsResultRegisteredParticipantDietVariations', {
@@ -137,6 +138,32 @@ const StatisticsResult = builder.simpleObject('StatisticsResult', {
137138
})
138139
})
139140
})
141+
}),
142+
status: t.field({
143+
type: t.builder.simpleObject('StatisticsResultRegisteredParticipantStatus', {
144+
fields: (t) => ({
145+
postalStatus: t.field({
146+
type: t.builder.simpleObject(
147+
'StatisticsResultRegisteredParticipantStatusPostalRegistration',
148+
{
149+
fields: (t) => ({
150+
done: t.int(),
151+
problem: t.int()
152+
})
153+
}
154+
)
155+
}),
156+
paymentStatus: t.field({
157+
type: t.builder.simpleObject('StatisticsResultRegisteredParticipantStatusPayment', {
158+
fields: (t) => ({
159+
done: t.int(),
160+
problem: t.int()
161+
})
162+
})
163+
}),
164+
didAttend: t.int()
165+
})
166+
})
140167
})
141168
})
142169
});
@@ -152,7 +179,7 @@ builder.queryFields((t) => {
152179
const user = ctx.permissions.getLoggedInUserOrThrow();
153180
await requireToBeConferenceAdmin({ conferenceId: args.conferenceId, user });
154181

155-
const { countdowns, registrationStatistics, ageStatistics, diet, gender } =
182+
const { countdowns, registrationStatistics, ageStatistics, diet, gender, status } =
156183
await conferenceStats({
157184
db,
158185
conferenceId: args.conferenceId
@@ -169,7 +196,8 @@ builder.queryFields((t) => {
169196
key: k,
170197
value: v
171198
}))
172-
}
199+
},
200+
status
173201
};
174202
}
175203
})

src/api/services/stats.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ofAgeAtConference } from '$lib/services/ageChecker';
12
import type { PrismaClient } from '@prisma/client';
23

34
export async function conferenceStats({
@@ -516,11 +517,54 @@ export async function conferenceStats({
516517
}
517518
};
518519

520+
const conferenceStatusStats = await db.conferenceParticipantStatus.findMany({
521+
where: {
522+
conferenceId
523+
},
524+
select: {
525+
paymentStatus: true,
526+
termsAndConditions: true,
527+
guardianConsent: true,
528+
mediaConsent: true,
529+
didAttend: true,
530+
user: {
531+
select: {
532+
birthday: true
533+
}
534+
}
535+
}
536+
});
537+
538+
const status = {
539+
paymentStatus: {
540+
done: conferenceStatusStats.filter((s) => s.paymentStatus === 'DONE').length,
541+
problem: conferenceStatusStats.filter((s) => s.paymentStatus === 'PROBLEM').length
542+
},
543+
postalStatus: {
544+
done: conferenceStatusStats.filter(
545+
(s) =>
546+
s.termsAndConditions === 'DONE' &&
547+
(ofAgeAtConference(conference.startConference, s.user.birthday) ||
548+
s.guardianConsent === 'DONE') &&
549+
s.mediaConsent === 'DONE'
550+
).length,
551+
problem: conferenceStatusStats.filter(
552+
(s) =>
553+
s.termsAndConditions === 'PROBLEM' ||
554+
(!ofAgeAtConference(conference.startConference, s.user.birthday) &&
555+
s.guardianConsent === 'PROBLEM') ||
556+
s.mediaConsent === 'PROBLEM'
557+
).length
558+
},
559+
didAttend: conferenceStatusStats.filter((s) => s.didAttend).length
560+
};
561+
519562
return {
520563
countdowns,
521564
registrationStatistics,
522565
ageStatistics,
523566
diet,
524-
gender
567+
gender,
568+
status
525569
};
526570
}

src/routes/(authenticated)/management/[conferenceId]/stats/+page.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import NumberMatrix from './widgets/NumberMatrix.svelte';
2121
import DietMatrix from './widgets/DietMatrix.svelte';
2222
import GenderMatrix from './widgets/GenderMatrix.svelte';
23+
import Status from './widgets/Status.svelte';
2324
let { data }: { data: PageData } = $props();
2425
2526
onMount(() => {
@@ -65,6 +66,7 @@
6566
<IndividualRoles {data} />
6667
<DietMatrix {data} />
6768
<GenderMatrix {data} />
69+
<Status {data} />
6870
<section class="card col-span-2 bg-base-200 shadow-sm md:col-span-12">
6971
<div class="card-body">
7072
<h3 class="text-xl font-bold">{m.historyComparison()}</h3>

src/routes/(authenticated)/management/[conferenceId]/stats/+page.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,17 @@ const statsQuery = graphql(`
9393
supervisors
9494
total
9595
}
96+
status {
97+
postalStatus {
98+
done
99+
problem
100+
}
101+
paymentStatus {
102+
done
103+
problem
104+
}
105+
didAttend
106+
}
96107
}
97108
}
98109
`);

src/routes/(authenticated)/management/[conferenceId]/stats/stats.svelte.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export interface StatsType {
44
countdowns: Countdowns;
55
registered: Registered;
66
age: Age;
7+
status?: Status;
78
}
89

910
export interface Countdowns {
@@ -60,6 +61,17 @@ export interface StatsTypeHistoryEntry {
6061
conferenceId: string;
6162
}
6263

64+
export interface Status {
65+
postalStatus: StatusObject;
66+
paymentStatus: StatusObject;
67+
didAttend: number;
68+
}
69+
70+
export interface StatusObject {
71+
problem: number;
72+
done: number;
73+
}
74+
6375
// Filter (by applied, not applied)
6476

6577
let filter = $state<'all' | 'applied' | 'notApplied'>('all');
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<script lang="ts">
2+
import * as m from '$lib/paraglide/messages';
3+
import { registrationFilter, getHistory, getSelectedHistory } from '../stats.svelte';
4+
import StatsDesc from './StatsDesc.svelte';
5+
import type { PageData } from '../$types';
6+
let { data }: { data: PageData } = $props();
7+
let stats = $derived(data.stats);
8+
9+
let selectedHistory = $derived.by(() =>
10+
getHistory()?.find((x) => x.timestamp === getSelectedHistory())
11+
);
12+
</script>
13+
14+
<section class="card col-span-2 bg-base-200 shadow-sm md:col-span-12">
15+
<div class="card-body">
16+
<div class="overflow-x-auto">
17+
<table class="table">
18+
<thead>
19+
<tr>
20+
<th class="w-full">{m.status()}</th>
21+
<th class="text-center">
22+
<i class="fas fa-triangle-exclamation text-error"></i>
23+
</th>
24+
<th class="text-center">
25+
<i class="fas fa-check text-success"></i>
26+
</th>
27+
</tr>
28+
</thead>
29+
<tbody>
30+
<tr>
31+
<td>
32+
<i class="fa-duotone fa-envelopes-bulk mr-2 text-lg"></i>
33+
{m.postalRegistration()}
34+
</td>
35+
<td class="text-center">
36+
<span class="text-lg font-bold"> {stats.status.postalStatus.problem} </span>
37+
{#if selectedHistory}
38+
<StatsDesc
39+
currentValue={stats.status.postalStatus.problem}
40+
historicValue={selectedHistory?.stats.status?.postalStatus.problem}
41+
/>
42+
{/if}
43+
</td>
44+
<td class="text-center">
45+
<span class="text-lg font-bold">{stats.status.postalStatus.done}</span>
46+
{#if selectedHistory}
47+
<StatsDesc
48+
currentValue={stats.status.postalStatus.done}
49+
historicValue={selectedHistory?.stats.status?.postalStatus.done}
50+
/>
51+
{/if}
52+
</td>
53+
</tr>
54+
<tr>
55+
<td>
56+
<i class="fa-duotone fa-hand-holding-circle-dollar mr-2 text-lg"></i>
57+
{m.payment()}
58+
</td>
59+
<td class="text-center">
60+
<span class="text-lg font-bold"> {stats.status.paymentStatus.problem} </span>
61+
{#if selectedHistory}
62+
<StatsDesc
63+
currentValue={stats.status.paymentStatus.problem}
64+
historicValue={selectedHistory?.stats.status?.paymentStatus.problem}
65+
/>
66+
{/if}
67+
</td>
68+
<td class="text-center">
69+
<span class="text-lg font-bold">{stats.status.paymentStatus.done}</span>
70+
{#if selectedHistory}
71+
<StatsDesc
72+
currentValue={stats.status.paymentStatus.done}
73+
historicValue={selectedHistory?.stats.status?.paymentStatus.done}
74+
/>
75+
{/if}
76+
</td>
77+
</tr>
78+
<tr>
79+
<td>
80+
<i class="fa-duotone fa-file-certificate mr-2 text-lg"></i>
81+
{m.attendance()}
82+
</td>
83+
<td class="text-center"><i class="fa-duotone fa-slash"></i></td>
84+
<td class="text-center">
85+
<span class="text-lg font-bold">{stats.status.didAttend}</span>
86+
{#if selectedHistory}
87+
<StatsDesc
88+
currentValue={stats.status.didAttend}
89+
historicValue={selectedHistory?.stats.status?.didAttend}
90+
/>
91+
{/if}
92+
</td>
93+
</tr>
94+
</tbody>
95+
</table>
96+
</div>
97+
</div>
98+
</section>

0 commit comments

Comments
 (0)