Integrated attendance system
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import type { CalendarEvent } from '@shared/types/calendar'
|
||||
import type { CalendarEvent, CalendarSignup } from '@shared/types/calendar'
|
||||
import { Clock, MapPin, User, X } from 'lucide-vue-next';
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import ButtonGroup from '../ui/button-group/ButtonGroup.vue';
|
||||
import Button from '../ui/button/Button.vue';
|
||||
import { CalendarAttendance, setCalendarEventAttendance } from '@/api/calendar';
|
||||
|
||||
const props = defineProps<{
|
||||
event: CalendarEvent | null
|
||||
@@ -32,6 +33,11 @@ const whenText = computed(() => {
|
||||
? `${startFmt.format(s)} – ${endFmt.format(e)}`
|
||||
: `${startFmt.format(s)}`
|
||||
})
|
||||
|
||||
const attending = computed<CalendarSignup[]>(() => { return activeEvent.value.eventSignups.filter((s) => s.status == CalendarAttendance.Attending) })
|
||||
const maybe = computed<CalendarSignup[]>(() => { return activeEvent.value.eventSignups.filter((s) => s.status == CalendarAttendance.Maybe) })
|
||||
const declined = computed<CalendarSignup[]>(() => { return activeEvent.value.eventSignups.filter((s) => s.status == CalendarAttendance.NotAttending) })
|
||||
const viewedState = ref<CalendarAttendance>(CalendarAttendance.Attending);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -48,23 +54,26 @@ const whenText = computed(() => {
|
||||
</button>
|
||||
</div>
|
||||
<!-- Body -->
|
||||
<div class="flex-1 min-h-0 overflow-y-auto px-4 py-4 space-y-6">
|
||||
<div class="flex-1 flex flex-col items-center min-h-0 overflow-y-auto px-4 py-4 space-y-6">
|
||||
<section>
|
||||
<ButtonGroup>
|
||||
<Button variant="outline">Going</Button>
|
||||
<Button variant="outline">Maybe</Button>
|
||||
<Button variant="outline">Declined</Button>
|
||||
<Button variant="outline"
|
||||
@click="setCalendarEventAttendance(activeEvent.id, CalendarAttendance.Attending)">Going</Button>
|
||||
<Button variant="outline"
|
||||
@click="setCalendarEventAttendance(activeEvent.id, CalendarAttendance.Maybe)">Maybe</Button>
|
||||
<Button variant="outline"
|
||||
@click="setCalendarEventAttendance(activeEvent.id, CalendarAttendance.NotAttending)">Declined</Button>
|
||||
</ButtonGroup>
|
||||
</section>
|
||||
<!-- When -->
|
||||
<section v-if="whenText" class="space-y-2">
|
||||
<section v-if="whenText" class="space-y-2 w-full">
|
||||
<div class="inline-flex items-center gap-2 rounded-md border px-2.5 py-1.5 text-sm">
|
||||
<Clock class="size-4 opacity-80" />
|
||||
<span class="font-medium">{{ whenText }}</span>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Quick meta chips -->
|
||||
<section class="flex flex-wrap gap-2">
|
||||
<section class="flex flex-wrap gap-2 w-full">
|
||||
<span class="inline-flex items-center gap-1.5 rounded-md border px-2 py-1 text-xs">
|
||||
<MapPin class="size-3.5 opacity-80" />
|
||||
<span class="font-medium">{{ activeEvent.location || "Unknown" }}</span>
|
||||
@@ -76,18 +85,38 @@ const whenText = computed(() => {
|
||||
</span>
|
||||
</section>
|
||||
<!-- Description -->
|
||||
<section class="space-y-2">
|
||||
<section class="space-y-2 w-full">
|
||||
<p class="text-lg font-semibold">Description</p>
|
||||
<p class="border bg-muted/50 px-3 py-2 rounded-lg min-h-24 my-2">
|
||||
{{ activeEvent.description }}
|
||||
</p>
|
||||
</section>
|
||||
<!-- Attendance -->
|
||||
<section class="space-y-2">
|
||||
<section class="space-y-2 w-full">
|
||||
<p class="text-lg font-semibold">Attendance</p>
|
||||
<!-- <p class="border bg-muted/50 px-3 py-2 rounded-lg min-h-24 my-2">
|
||||
{{ activeEvent.description }}
|
||||
</p> -->
|
||||
<div class="flex flex-col border bg-muted/50 rounded-lg min-h-24 my-2">
|
||||
<div class="flex w-full pt-2 border-b *:w-full *:text-center *:pb-1 *:cursor-pointer">
|
||||
<label :class="viewedState === CalendarAttendance.Attending ? 'border-b-3 border-foreground' : 'mb-[2px]'"
|
||||
@click="viewedState = CalendarAttendance.Attending">Going {{ attending.length }}</label>
|
||||
<label :class="viewedState === CalendarAttendance.Maybe ? 'border-b-3 border-foreground' : 'mb-[2px]'"
|
||||
@click="viewedState = CalendarAttendance.Maybe">Maybe {{ maybe.length }}</label>
|
||||
<label
|
||||
:class="viewedState === CalendarAttendance.NotAttending ? 'border-b-3 border-foreground' : 'mb-[2px]'"
|
||||
@click="viewedState = CalendarAttendance.NotAttending">Declined {{ declined.length
|
||||
}}</label>
|
||||
</div>
|
||||
<div class="px-5 py-4 min-h-28">
|
||||
<div v-if="viewedState === CalendarAttendance.Attending" v-for="person in attending">
|
||||
<p>{{ person.member_name }}</p>
|
||||
</div>
|
||||
<div v-if="viewedState === CalendarAttendance.Maybe" v-for="person in maybe">
|
||||
<p>{{ person.member_name }}</p>
|
||||
</div>
|
||||
<div v-if="viewedState === CalendarAttendance.NotAttending" v-for="person in declined">
|
||||
<p>{{ person.member_name }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<!-- Footer (optional actions) -->
|
||||
|
||||
Reference in New Issue
Block a user