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 21b2754

Browse files
authored
Merge pull request #175 from DeutscheModelUnitedNations/export-feature-for-committees
✨ Feature: Export feature for committee members
2 parents fbb6501 + ad23bc1 commit 21b2754

File tree

6 files changed

+135
-8
lines changed

6 files changed

+135
-8
lines changed

schema.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ input BoolWithAggregatesFilter {
3535
type Committee {
3636
abbreviation: String!
3737
conference: Conference!
38+
delegationMembers: [DelegationMember!]!
3839
id: ID!
3940
name: String!
4041
nations: [Nation!]!

src/api/resolvers/modules/committee.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { builder } from '../builder';
22
import {
33
CommitteeAbbreviationFieldObject,
44
CommitteeConferenceFieldObject,
5+
CommitteeDelegationMembersFieldObject,
56
CommitteeIdFieldObject,
67
CommitteeNameFieldObject,
78
CommitteeNumOfSeatsPerDelegationFieldObject,
@@ -22,6 +23,11 @@ builder.prismaObject('Committee', {
2223
query: (_args, ctx) => ({
2324
where: ctx.permissions.allowDatabaseAccessTo('list').Nation
2425
})
26+
}),
27+
delegationMembers: t.relation('delegationMembers', {
28+
query: (_args, ctx) => ({
29+
where: ctx.permissions.allowDatabaseAccessTo('list').DelegationMember
30+
})
2531
})
2632
})
2733
});

src/i18n/de.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,5 +569,7 @@
569569
"country": "Land",
570570
"general": "Allgemeines",
571571
"communication": "Kommunikation",
572-
"conferenceStatusDescription": "<p>Der Konferenzstatus bestimmt, was die Teilnehmenden in der App sehen und tun können. Er sollte immer nur \"vorwärts\" geändert werden. Auch wenn bei einem Rückschritt keine Daten verloren gehen, kann es doch einerseits zu Verwirrungen bei den Teilnehmenden führen und andererseits in der App zu unerwartetem Verhalten führen.</p><p>Der Konferenzstatus orientiert sich an den Phasen einer Konferenz. Die Möglichkeiten sind:</p><ul><li><strong>Vor Anmeldestart</strong>: Die Konferenz wurde angelegt,die Anmeldephase aber noch nicht gestartet. Es können alle Vorbereitungen getroffen werden, die Anmeldung ist aber noch nicht möglich und die Konferenz nach außen hin auch noch nicht sichtbar.</li><li><strong>Anmeldephase</strong>: Die Anmeldung ist möglich, bis das Datum für das Ende der Anmeldung erreicht ist. Dann wird die Anmeldephase automatisch beendet. Nun kann die Zuteilung vorgenommen und auch schon angewendet werden. Solange der Konferenzstatus noch \"Anmeldephase\"ist,können die Teilnehmenden ihre Zuweisung noch nicht sehen.</li><li><strong>Vorbereitung</strong>: Wenn die Zuteilung abgeschlossen istundmandie Ergebnisse bekannt geben möchte, kann der Konferenz status auf \"Vorbereitung\" gesetzt werden. Dieser Status sollte bis zu Beginnder Konferenz bestehen bleiben. Die Teilnehmenden bekommen Informationen zur postalischen Anmeldung und der Beitragszahlung angezeigt und können auf Materialien und Infos (weiter unten) zugreifen.</li><li><strong>Aktive Konferenz</strong>: Dieser Status sollte kurz vor Beginnder Konferenz gesetzt werden.</li><li><strong>Nach der Konferenz</strong>: Nach der Konferenz kann der Status auf \"Nach der Konferenz\" gesetzt werden. Vorher sollte eingetragen werden, wer von den Teilnehmenden anwesend war und ein Zertifikat erhalten soll. Mit diesem Status können die Teilnehmenden ihre Zertifikate herunterladen.</li></ul>"
572+
"conferenceStatusDescription": "<p>Der Konferenzstatus bestimmt, was die Teilnehmenden in der App sehen und tun können. Er sollte immer nur \"vorwärts\" geändert werden. Auch wenn bei einem Rückschritt keine Daten verloren gehen, kann es doch einerseits zu Verwirrungen bei den Teilnehmenden führen und andererseits in der App zu unerwartetem Verhalten führen.</p><p>Der Konferenzstatus orientiert sich an den Phasen einer Konferenz. Die Möglichkeiten sind:</p><ul><li><strong>Vor Anmeldestart</strong>: Die Konferenz wurde angelegt,die Anmeldephase aber noch nicht gestartet. Es können alle Vorbereitungen getroffen werden, die Anmeldung ist aber noch nicht möglich und die Konferenz nach außen hin auch noch nicht sichtbar.</li><li><strong>Anmeldephase</strong>: Die Anmeldung ist möglich, bis das Datum für das Ende der Anmeldung erreicht ist. Dann wird die Anmeldephase automatisch beendet. Nun kann die Zuteilung vorgenommen und auch schon angewendet werden. Solange der Konferenzstatus noch \"Anmeldephase\"ist,können die Teilnehmenden ihre Zuweisung noch nicht sehen.</li><li><strong>Vorbereitung</strong>: Wenn die Zuteilung abgeschlossen istundmandie Ergebnisse bekannt geben möchte, kann der Konferenz status auf \"Vorbereitung\" gesetzt werden. Dieser Status sollte bis zu Beginnder Konferenz bestehen bleiben. Die Teilnehmenden bekommen Informationen zur postalischen Anmeldung und der Beitragszahlung angezeigt und können auf Materialien und Infos (weiter unten) zugreifen.</li><li><strong>Aktive Konferenz</strong>: Dieser Status sollte kurz vor Beginnder Konferenz gesetzt werden.</li><li><strong>Nach der Konferenz</strong>: Nach der Konferenz kann der Status auf \"Nach der Konferenz\" gesetzt werden. Vorher sollte eingetragen werden, wer von den Teilnehmenden anwesend war und ein Zertifikat erhalten soll. Mit diesem Status können die Teilnehmenden ihre Zertifikate herunterladen.</li></ul>",
573+
"downloadCommitteeData": "Daten für das Gremium \"{committee}\" herunterladen",
574+
"alpha3Code": "ISO Alpha 3 Code"
573575
}

src/i18n/en.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,5 +513,7 @@
513513
"communication": "Communication",
514514
"conferenceStatusParticipantRegistration": "Registration Phase",
515515
"conferenceStatusPreparation": "Preparation Phase",
516-
"conferenceStatusDescription": "<p>The conference status determines what participants can see and do in the app.It should only ever be changed \"forward\". Even though no data is lost whentaking a step back, it can lead to confusion among participants andpotentially cause unexpected behavior in the app.</p><p>The conference status is oriented around the phases of a conference. Thepossibilities are:</p><ul><li><strong>Before registration starts</strong>: The conference has been created,but the registration phase has not yet started. All preparations can bemade, but registration is not yet possible, and the conference is not yetvisible externally.</li><li><strong>Registration Phase</strong>: Registration is possible until the enddate for registration is reached. Then the registration phase isautomatically ended. Now allocation can be made and also already applied. Aslong as the conference status is still \"Registration Phase\", participantscannot yet see their assignment.</li><li><strong>Preparation Phase</strong>: When the allocation is complete and you wantto announce the results, the conference status can be set to \"Preparation Phase\".This status should remain until the beginning of the conference.Participants will be shown information about postal registration andcontribution payment and can access materials and information.</li><li><strong>Active Conference</strong>: This status should be set shortly beforethe start of the conference.</li><li><strong>After the Conference</strong>: After the conference, the status canbe set to \"After the Conference\". Before this, it should be recorded whoamong the participants was present and should receive a certificate. Withthis status, participants can download their certificates.</li></ul>"
516+
"conferenceStatusDescription": "<p>The conference status determines what participants can see and do in the app.It should only ever be changed \"forward\". Even though no data is lost whentaking a step back, it can lead to confusion among participants andpotentially cause unexpected behavior in the app.</p><p>The conference status is oriented around the phases of a conference. Thepossibilities are:</p><ul><li><strong>Before registration starts</strong>: The conference has been created,but the registration phase has not yet started. All preparations can bemade, but registration is not yet possible, and the conference is not yetvisible externally.</li><li><strong>Registration Phase</strong>: Registration is possible until the enddate for registration is reached. Then the registration phase isautomatically ended. Now allocation can be made and also already applied. Aslong as the conference status is still \"Registration Phase\", participantscannot yet see their assignment.</li><li><strong>Preparation Phase</strong>: When the allocation is complete and you wantto announce the results, the conference status can be set to \"Preparation Phase\".This status should remain until the beginning of the conference.Participants will be shown information about postal registration andcontribution payment and can access materials and information.</li><li><strong>Active Conference</strong>: This status should be set shortly beforethe start of the conference.</li><li><strong>After the Conference</strong>: After the conference, the status canbe set to \"After the Conference\". Before this, it should be recorded whoamong the participants was present and should receive a certificate. Withthis status, participants can download their certificates.</li></ul>",
517+
"downloadCommitteeData": "Download committee data for the {committee}",
518+
"alpha3Code": "ISO Alpha 3 Code"
517519
}

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

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import * as m from '$lib/paraglide/messages';
44
import { getFullTranslatedCountryNameFromISO3Code } from '$lib/services/nationTranslationHelper.svelte';
55
import type { PageData } from './$houdini';
6+
import DownloadCommitteeDataBtn from './DownloadCommitteeDataBtn.svelte';
67
78
let { data }: { data: PageData } = $props();
89
@@ -16,10 +17,17 @@
1617
<div class="flex w-full flex-col items-start gap-10 p-4">
1718
<section class="flex w-full flex-col items-start gap-4">
1819
<h1 class="text-2xl font-bold">{m.nationSeats()}</h1>
19-
2020
<div class="block w-full overflow-y-scroll md:contents">
2121
<table class="table table-pin-rows text-center">
2222
<thead>
23+
<tr>
24+
<td> </td>
25+
{#each committees as committee}
26+
<th>
27+
<DownloadCommitteeDataBtn {committee} />
28+
</th>
29+
{/each}
30+
</tr>
2331
<tr>
2432
<td><i class="fa-duotone fa-sigma"></i></td>
2533
{#each committees as committee}
@@ -91,12 +99,17 @@
9199
)}
92100
{#if assignedDelegationMember && assignedDelegationMember.length > 0}
93101
{#each assignedDelegationMember as member}
94-
<a
95-
class="btn btn-outline btn-sm"
96-
href={`/management/${data.conferenceId}/participants?filter=${member.user.id}`}
102+
<div
103+
class="tooltip"
104+
data-tip={`${member.user.given_name} ${member.user.family_name}`}
97105
>
98-
{member.user.given_name[0].toUpperCase()}{member.user.family_name[0].toUpperCase()}
99-
</a>
106+
<a
107+
class="btn btn-outline btn-sm"
108+
href={`/management/${data.conferenceId}/participants?filter=${member.user.id}`}
109+
>
110+
{member.user.given_name[0].toUpperCase()}{member.user.family_name[0].toUpperCase()}
111+
</a>
112+
</div>
100113
{/each}
101114
{:else}
102115
<i class="fas fa-dash text-gray-400"></i>
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<script lang="ts">
2+
import { graphql } from '$houdini';
3+
import * as m from '$lib/paraglide/messages';
4+
import { getFullTranslatedCountryNameFromISO3Code } from '$lib/services/nationTranslationHelper.svelte';
5+
6+
const getCommitteeUserData = graphql(`
7+
query getCommitteeUserData($id: String!) {
8+
findUniqueCommittee(where: { id: $id }) {
9+
id
10+
abbreviation
11+
name
12+
conference {
13+
id
14+
title
15+
}
16+
delegationMembers {
17+
id
18+
delegation {
19+
id
20+
assignedNation {
21+
alpha3Code
22+
alpha2Code
23+
}
24+
}
25+
user {
26+
id
27+
given_name
28+
family_name
29+
email
30+
}
31+
}
32+
}
33+
}
34+
`);
35+
36+
interface Props {
37+
committee: {
38+
id: string;
39+
abbreviation: string;
40+
[key: string]: any;
41+
};
42+
}
43+
44+
let { committee }: Props = $props();
45+
46+
let loading = $state(false);
47+
48+
const downloadCommitteeData = async () => {
49+
loading = true;
50+
const { data } = await getCommitteeUserData.fetch({ variables: { id: committee.id } });
51+
if (
52+
!data ||
53+
!data?.findUniqueCommittee ||
54+
!data?.findUniqueCommittee?.delegationMembers ||
55+
data?.findUniqueCommittee?.delegationMembers.length === 0
56+
) {
57+
alert('No data found');
58+
loading = false;
59+
}
60+
61+
const csv = [
62+
[m.alpha3Code(), m.nation(), m.firstName(), m.lastName(), m.email()],
63+
...data!
64+
.findUniqueCommittee!.delegationMembers.sort((a, b) => {
65+
if (
66+
!a.delegation.assignedNation?.alpha3Code ||
67+
!b.delegation.assignedNation?.alpha3Code
68+
) {
69+
return 0;
70+
}
71+
return a.delegation.assignedNation?.alpha3Code.localeCompare(
72+
b.delegation.assignedNation?.alpha3Code
73+
);
74+
})
75+
.map((member) => [
76+
member.delegation.assignedNation?.alpha3Code.toUpperCase(),
77+
member.delegation.assignedNation?.alpha3Code
78+
? getFullTranslatedCountryNameFromISO3Code(member.delegation.assignedNation?.alpha3Code)
79+
: '',
80+
member.user.given_name,
81+
member.user.family_name,
82+
member.user.email
83+
])
84+
]
85+
.map((row) => row.join(','))
86+
.join('\n');
87+
88+
const blob = new Blob([csv], { type: 'text/csv' });
89+
const url = window.URL.createObjectURL(blob);
90+
const a = document.createElement('a');
91+
a.href = url;
92+
a.download = `${data!.findUniqueCommittee!.conference.title.replace(' ', '_')}_${committee.abbreviation}_delegation_members.csv`;
93+
a.click();
94+
window.URL.revokeObjectURL(url);
95+
loading = false;
96+
};
97+
</script>
98+
99+
<div class="tooltip" data-tip={m.downloadCommitteeData({ committee: committee.abbreviation })}>
100+
<button class="btn btn-ghost btn-sm" aria-label="Download data" onclick={downloadCommitteeData}>
101+
<i class="fa-duotone {loading ? 'fa-spinner fa-spin' : 'fa-download'}"></i>
102+
</button>
103+
</div>

0 commit comments

Comments
 (0)