Skip to content

Commit 6607e35

Browse files
JoshXL23Joshua GonsalvesDropheart
authored
feat(volunteer): volunteer page (#208)
Co-authored-by: Joshua Gonsalves <[email protected]> Co-authored-by: Dropheart <[email protected]> Co-authored-by: jay <[email protected]>
1 parent ba6233d commit 6607e35

26 files changed

+2661
-358
lines changed

app/pages/index.vue

+20-7
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,26 @@
44
<img class="mx-auto w-[50px]" src="~/assets/icon_cube.svg" />
55
<h1
66
class="font-ichack mt-7 text-center text-[clamp(2rem,6vw,2.5rem)] md:text-4xl">
7-
Get Ready...
7+
You're almost there!
88
</h1>
99
<p
1010
class="mt-5 text-center text-[clamp(1.2rem,3vw,1.25rem)] text-gray-200 md:text-xl">
11-
Come back here soon for your dashboard, profiles, teams, and more! For
12-
now...
11+
Link your wristband for your IC Hack '25 to get started.
1312
</p>
1413
<div class="h-5"></div>
15-
<Discord
14+
<Discordf
1615
:linked-discord="profile.discord_id != null"
1716
@unlinked="profile.discord_id = null" />
18-
<div class="h-[75px] md:h-[110px]"></div>
17+
18+
<div class="flex w-full justify-center">
19+
<NuxtLink
20+
class="max-w-fit rounded-xl bg-white px-2 py-2 text-lg font-bold text-black"
21+
to="/link">
22+
Link Your Wristband
23+
</NuxtLink>
24+
</div>
25+
26+
<div class="h-[30px] md:h-[70px]"></div>
1927
<img class="mx-auto w-[500px]" src="~/assets/divider3.svg" />
2028
<p class="mt-7 text-center text-gray-200 md:text-xl">
2129
Add your IC Hack '25 event ticket to your digital wallet to be ready for
@@ -34,10 +42,15 @@
3442
:qr-text="profile.id" />
3543
</div>
3644
<div class="h-5"></div>
37-
<p class="mt-3 max-w-[32rem] text-center text-sm text-gray-400">
45+
<NuxtLink
46+
class="mt-2 max-w-fit rounded-xl bg-white px-2 py-2 text-lg font-bold text-black"
47+
to="/ticket">
48+
Your Ticket
49+
</NuxtLink>
50+
<!-- <p class="mt-3 max-w-[32rem] text-center text-sm text-gray-400">
3851
Don't worry if you don't have a digital wallet set up - you'll be able to
3952
access your entry ticket right here on the day.
40-
</p>
53+
</p> -->
4154
</div>
4255
<div class="h-20"></div>
4356
</template>

app/pages/link.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
</template>
5858

5959
<script lang="ts" setup>
60-
definePageMeta({ middleware: 'require-auth' });
60+
definePageMeta({ middleware: 'require-auth', layout: 'no-sidebar' });
6161
6262
import { usePermission } from '@vueuse/core';
6363
import { ref, watch } from 'vue';

bun.lock

+397-333
Large diffs are not rendered by default.

nuxt.config.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,12 @@ export default defineNuxtConfig({
2626
}
2727
],
2828

29-
extends: ['packages/admin', 'packages/common', 'packages/ui25'],
29+
extends: [
30+
'packages/admin',
31+
'packages/common',
32+
'packages/ui25',
33+
'packages/volunteer'
34+
],
3035

3136
app: {
3237
rootAttrs: {

packages/admin/components/Toolbar.vue

+5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ const menu = [
1919
{ label: 'Team', to: '/admin/team', icon: 'heroicons:users' }
2020
],
2121
[
22+
{
23+
label: 'Volunteer Dashboard',
24+
to: '/volunteer',
25+
icon: 'heroicons:user-circle'
26+
},
2227
{
2328
label: 'Logout',
2429
icon: 'websymbol:logout',

packages/common/composables/useEvents.ts

+20-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,26 @@ export default function () {
2525
});
2626
};
2727

28+
const checkIn = async (
29+
eventId: number,
30+
userId: string
31+
): Promise<Result<void, Error>> => {
32+
return Result.try(async () => {
33+
const res = await client.event['check-in'].$post({
34+
json: {
35+
eventId: eventId,
36+
userId: userId
37+
}
38+
});
39+
if (!res.ok) {
40+
throw new Error(await res.text());
41+
}
42+
return Result.ok();
43+
});
44+
};
45+
2846
return {
29-
getEvents
47+
getEvents,
48+
checkIn
3049
};
3150
}

packages/common/composables/useQR.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,23 @@ export const useQR = () => {
2525
const errorMessage = await result.text();
2626
throw new Error(errorMessage);
2727
}
28-
2928
return Result.ok();
3029
});
3130
};
3231

32+
const getQr = (uuid: string): Promise<Result<Profile, Error>> => {
33+
return Result.try(async () => {
34+
const res = await client.qr[':uuid'].$get({
35+
param: { uuid: uuid }
36+
});
37+
if (!res.ok) throw new Error(await res.text());
38+
return await res.json();
39+
});
40+
};
41+
3342
return {
3443
deleteQR,
35-
getOwnQr
44+
getOwnQr,
45+
getQr
3646
};
3747
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<template>
2+
<template>
3+
<div>
4+
<UCard
5+
:ui="{
6+
background: success
7+
? 'bg-green-100 dark:bg-green-700'
8+
: 'bg-red-700 dark:bg-red-600'
9+
}">
10+
<template #header>
11+
<h1 class="font-ichack text-2xl">
12+
{{ success ? 'success' : 'failure' }}
13+
</h1>
14+
</template>
15+
<div class="flex flex-row text-lg">
16+
<div class="flex-1 text-center">
17+
<p><strong>Name:</strong></p>
18+
<p>{{ profile.name }}</p>
19+
</div>
20+
<div class="flex-1 text-center">
21+
<p><strong>Role:</strong></p>
22+
<p>{{ profile.role }}</p>
23+
</div>
24+
<div class="flex-1 text-center">
25+
<p><strong>Id:</strong></p>
26+
<p>{{ profile.id }}</p>
27+
</div>
28+
</div>
29+
<template class="bg-red items-center" #footer>
30+
<p class="font-archivo text-lg">
31+
{{ success ? 'checked in!' : `an error occured: ${errMsg}` }}
32+
</p>
33+
</template>
34+
</UCard>
35+
</div>
36+
</template>
37+
</template>
38+
39+
<script lang="ts" setup>
40+
import type { Profile } from '~~/shared/types';
41+
42+
type Props = {
43+
profile: Profile;
44+
success: boolean;
45+
errMsg: string | null;
46+
};
47+
defineProps<Props>();
48+
</script>
49+
50+
<style></style>
+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<template>
2+
<div>
3+
<UCard
4+
:ui="{
5+
background: success
6+
? 'bg-green-400 dark:bg-green-700'
7+
: 'bg-red-60 dark:bg-red-600'
8+
}">
9+
<template #header>
10+
<h1 class="font-ichack text-center text-xl">
11+
{{ success ? 'USER MAY EAT!' : `FAILED: ${errMsg}` }}
12+
</h1>
13+
</template>
14+
15+
<div
16+
class="flex w-full flex-col items-center justify-center rounded-3xl bg-red-600">
17+
<h2 class="text-1xl mr-2 font-bold">Dietary Requirements!</h2>
18+
<ul class="flex flex-row space-x-4">
19+
<li
20+
v-for="item in profile.dietary_restrictions"
21+
:key="item"
22+
class="text-2xl font-bold">
23+
{{ item }}
24+
</li>
25+
</ul>
26+
</div>
27+
28+
<template class="items-center" #footer>
29+
<div class="flex flex-row text-sm">
30+
<div class="flex-1 text-center">
31+
<p><strong>Name:</strong></p>
32+
<p>{{ profile.name }}</p>
33+
</div>
34+
<div class="flex-1 text-center">
35+
<p><strong>Role:</strong></p>
36+
<p>{{ profile.role }}</p>
37+
</div>
38+
<!-- <div class="flex-1 text-center text-xs">
39+
<p><strong>Id:</strong></p>
40+
<p>{{ profile.id }}</p>
41+
</div> -->
42+
</div>
43+
</template>
44+
</UCard>
45+
</div>
46+
</template>
47+
48+
<script lang="ts" setup>
49+
import { UCard } from '#components';
50+
import type { Profile } from '~~/shared/types';
51+
52+
type Props = {
53+
profile: Profile;
54+
success: boolean;
55+
errMsg: string | null;
56+
};
57+
58+
defineProps<Props>();
59+
</script>
60+
61+
<style></style>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<template>
2+
<UCard>
3+
<template #header>
4+
<div class="flex flex-row flex-wrap items-start justify-around space-x-2">
5+
<!-- Name Column -->
6+
<div class="flex min-w-max flex-col items-center">
7+
<!-- Label (optional, e.g. “Name”) -->
8+
<p class="font-archivo mb-1 text-sm text-gray-500">Name</p>
9+
<!-- Actual name -->
10+
<h1 class="font-archivo text-sm">{{ profile.name }}</h1>
11+
<!-- Pronouns in smaller gray text, if provided -->
12+
<p v-if="profile.pronouns" class="font-archivo text-sm text-gray-600">
13+
{{ profile.pronouns }}
14+
</p>
15+
</div>
16+
<!-- Email Column -->
17+
<div class="flex flex-col flex-wrap items-start">
18+
<!-- Label -->
19+
<p class="font-archivo mb-1 text-sm text-gray-500">Email</p>
20+
<!-- Value -->
21+
<p class="font-archivo text-sm">{{ profile.email }}</p>
22+
</div>
23+
24+
<!-- Role Column -->
25+
<div class="flex flex-col items-end">
26+
<!-- Label -->
27+
<p class="font-archivo mb-1 text-sm text-gray-500">Role</p>
28+
<!-- Value -->
29+
<p class="font-archivo text-sm">{{ profile.role }}</p>
30+
</div>
31+
</div>
32+
</template>
33+
34+
<div
35+
class="flex w-full flex-row items-start justify-between space-x-4 text-sm">
36+
<!-- Dietary Restrictions Column -->
37+
<div class="flex flex-col">
38+
<h3 class="mb-1 whitespace-nowrap font-semibold">
39+
Dietary Restrictions
40+
</h3>
41+
<!-- UL horizontally laid out -->
42+
<ul
43+
class="align-center flex flex-row flex-wrap justify-center space-x-2">
44+
<li v-for="diet in profile.dietary_restrictions" :key="diet">
45+
{{ diet }}
46+
</li>
47+
</ul>
48+
</div>
49+
50+
<!-- Meals Had Column -->
51+
<div class="flex flex-col text-center text-sm">
52+
<h3 class="mb-1 font-semibold">Meals Had</h3>
53+
<!-- UL horizontally laid out -->
54+
<ul
55+
class="align-center flex flex-row flex-wrap justify-center space-x-2">
56+
<li
57+
:class="{
58+
'text-green-500': profile.meals[0],
59+
'text-red-500': !profile.meals[0]
60+
}">
61+
Lunch-1
62+
</li>
63+
<li
64+
:class="{
65+
'text-green-500': profile.meals[1],
66+
'text-red-500': !profile.meals[1]
67+
}">
68+
Dinner
69+
</li>
70+
<li
71+
:class="{
72+
'text-green-500': profile.meals[2],
73+
'text-red-500': !profile.meals[2]
74+
}">
75+
Lunch-2
76+
</li>
77+
</ul>
78+
</div>
79+
</div>
80+
81+
<template #footer>
82+
<div class="flex w-full flex-row items-center justify-between">
83+
<p
84+
:class="{
85+
'text-green-500': !profile.photos_opt_out,
86+
'text-red-500': profile.photos_opt_out
87+
}">
88+
Photos Opt Out:
89+
{{ profile.photos_opt_out ? 'YES' : 'NO' }}
90+
</p>
91+
<p
92+
:class="{
93+
'text-green-500': profile.cvUploaded,
94+
'text-red-500': !profile.cvUploaded
95+
}">
96+
CV uploaded:
97+
{{ profile.cvUploaded ? 'YES' : 'NO' }}
98+
</p>
99+
</div>
100+
</template>
101+
</UCard>
102+
<div>
103+
<p v-if="profile" class="mt-1 w-full text-center text-sm text-gray-500">
104+
UserID: {{ profile.id }}
105+
</p>
106+
</div>
107+
</template>
108+
109+
<script lang="ts" setup>
110+
import type { Profile } from '~~/shared/types';
111+
112+
type Props = {
113+
profile: Profile;
114+
};
115+
defineProps<Props>();
116+
</script>
117+
118+
<style></style>

0 commit comments

Comments
 (0)