feat: Add attendance options dropdown
parent
a2712504e2
commit
f0e2e28d65
|
@ -271,7 +271,7 @@ hr {
|
|||
/*box-shadow: 0 0 4px var(--text);*/
|
||||
}
|
||||
|
||||
div[role="menu"] {
|
||||
[role="menu"] {
|
||||
background-color: var(--base);
|
||||
border: 1px solid var(--overlay-0);
|
||||
border-radius: 4px;
|
||||
|
@ -279,22 +279,22 @@ div[role="menu"] {
|
|||
min-width: 8rem;
|
||||
}
|
||||
|
||||
div[role="menu"] button {
|
||||
[role="menu"] button {
|
||||
background-color: var(--base);
|
||||
width: 100%;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
div[role="menu"] button.destructive {
|
||||
[role="menu"] button.destructive {
|
||||
color: var(--destructive);
|
||||
}
|
||||
|
||||
div[role="menu"] button.destructive:hover {
|
||||
[role="menu"] button.destructive:hover {
|
||||
background-color: var(--destructive);
|
||||
color: var(--base);
|
||||
}
|
||||
|
||||
div[role="menu"] button > i.bi.margin {
|
||||
[role="menu"] button > i.bi.margin {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
/*
|
||||
|
@ -309,7 +309,7 @@ div[role="menu"] div[role="menuitem"]:last-child button {
|
|||
}
|
||||
*/
|
||||
|
||||
div[role="menu"] button:hover {
|
||||
[role="menu"] button:hover {
|
||||
background-color: var(--surface-0);
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ export { OpenAPI } from './core/OpenAPI';
|
|||
export type { OpenAPIConfig } from './core/OpenAPI';
|
||||
|
||||
export type { AddPlayerJson } from './models/AddPlayerJson';
|
||||
export type { AttendanceJson } from './models/AttendanceJson';
|
||||
export type { AvailabilitySchema } from './models/AvailabilitySchema';
|
||||
export type { CreateEventJson } from './models/CreateEventJson';
|
||||
export type { CreateTeamJson } from './models/CreateTeamJson';
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
/* generated using openapi-typescript-codegen -- do not edit */
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export type AttendanceJson = {
|
||||
confirm: boolean;
|
||||
};
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type { AddPlayerJson } from '../models/AddPlayerJson';
|
||||
import type { AttendanceJson } from '../models/AttendanceJson';
|
||||
import type { CreateEventJson } from '../models/CreateEventJson';
|
||||
import type { CreateTeamJson } from '../models/CreateTeamJson';
|
||||
import type { EditMemberRolesJson } from '../models/EditMemberRolesJson';
|
||||
|
@ -197,11 +198,13 @@ export class DefaultService {
|
|||
/**
|
||||
* attend_event <PUT>
|
||||
* @param eventId
|
||||
* @param requestBody
|
||||
* @returns EventWithPlayerSchema OK
|
||||
* @throws ApiError
|
||||
*/
|
||||
public attendEvent(
|
||||
eventId: number,
|
||||
requestBody?: AttendanceJson,
|
||||
): CancelablePromise<EventWithPlayerSchema> {
|
||||
return this.httpRequest.request({
|
||||
method: 'PUT',
|
||||
|
@ -209,6 +212,8 @@ export class DefaultService {
|
|||
path: {
|
||||
'event_id': eventId,
|
||||
},
|
||||
body: requestBody,
|
||||
mediaType: 'application/json',
|
||||
errors: {
|
||||
422: `Unprocessable Content`,
|
||||
},
|
||||
|
|
|
@ -6,6 +6,7 @@ import { useTeamsEventsStore } from "@/stores/teams/events";
|
|||
import moment from "moment";
|
||||
import { computed } from "vue";
|
||||
import EventCardDropdown from "./EventCardDropdown.vue";
|
||||
import EventConfirmButton from "./EventConfirmButton.vue";
|
||||
const teamsStore = useTeamsStore();
|
||||
const rosterStore = useRosterStore();
|
||||
const teamEventsStore = useTeamsEventsStore();
|
||||
|
@ -46,16 +47,13 @@ function attend() {
|
|||
teamEventsStore.attendEvent(props.event.event.id);
|
||||
}
|
||||
|
||||
function unattend() {
|
||||
teamEventsStore.unattendEvent(props.event.event.id);
|
||||
function pending() {
|
||||
console.log("pending");
|
||||
teamEventsStore.attendEvent(props.event.event.id, false);
|
||||
}
|
||||
|
||||
function attendOrUnattend() {
|
||||
if (props.event.playerEvent?.hasConfirmed) {
|
||||
unattend();
|
||||
} else {
|
||||
attend();
|
||||
}
|
||||
function unattend() {
|
||||
teamEventsStore.unattendEvent(props.event.event.id);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -87,30 +85,12 @@ function attendOrUnattend() {
|
|||
<em v-else class="subtext">No description provided.</em>
|
||||
</div>
|
||||
<div class="button-group">
|
||||
<button
|
||||
@click="attendOrUnattend()"
|
||||
v-if="event.playerEvent"
|
||||
:class="{
|
||||
'class-info': true,
|
||||
'confirmed': event.playerEvent.hasConfirmed,
|
||||
}"
|
||||
>
|
||||
<template v-if="!event.playerEvent.hasConfirmed">
|
||||
<i class="bi bi-check2" />
|
||||
Confirm
|
||||
</template>
|
||||
<template v-else>
|
||||
<i class="bi bi-check2-all" />
|
||||
Confirmed
|
||||
</template>
|
||||
<span v-if="event.playerEvent.role">
|
||||
as {{ rosterStore.roleNames[event.playerEvent.role.role] }}
|
||||
</span>
|
||||
</button>
|
||||
<button @click="attend" v-else>
|
||||
<i class="bi bi-check2" />
|
||||
Attend
|
||||
</button>
|
||||
<EventConfirmButton
|
||||
:playerEvent="event.playerEvent"
|
||||
@attend="attend"
|
||||
@pending="pending"
|
||||
@unattend="unattend"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -193,9 +173,4 @@ h3 {
|
|||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
button.confirmed {
|
||||
background-color: var(--text);
|
||||
color: var(--base);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
<script setup lang="ts">
|
||||
import type { PlayerEventRolesSchema } from "@/client";
|
||||
import { useRosterStore } from "@/stores/roster";
|
||||
import {
|
||||
DropdownMenuRoot,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuItemIndicator,
|
||||
} from "radix-vue";
|
||||
import { computed } from "vue";
|
||||
|
||||
const rosterStore = useRosterStore();
|
||||
|
||||
const props = defineProps<{
|
||||
playerEvent: PlayerEventRolesSchema | null;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
attend: [],
|
||||
unattend: [],
|
||||
pending: [],
|
||||
}>();
|
||||
|
||||
function attendOrUnattend() {
|
||||
if (props.playerEvent?.hasConfirmed) {
|
||||
emit("unattend");
|
||||
} else {
|
||||
emit("attend");
|
||||
}
|
||||
}
|
||||
|
||||
const confirmationOptions = ["Attending", "Pending", "Not attending"];
|
||||
|
||||
const selectedOption = computed({
|
||||
get() {
|
||||
if (props.playerEvent?.hasConfirmed) {
|
||||
return "Attending";
|
||||
} else if (props.playerEvent?.hasConfirmed === false) {
|
||||
return "Pending";
|
||||
} else {
|
||||
return "Not attending";
|
||||
}
|
||||
},
|
||||
set(value: string) {
|
||||
console.log(value);
|
||||
if (value === "Attending") {
|
||||
emit("attend");
|
||||
} else if (value === "Not attending") {
|
||||
emit("unattend");
|
||||
} else {
|
||||
emit("pending");
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="{
|
||||
'event-confirm-button': true,
|
||||
'confirmed': playerEvent?.hasConfirmed,
|
||||
}"
|
||||
>
|
||||
<button
|
||||
@click="attendOrUnattend()"
|
||||
v-if="playerEvent"
|
||||
class="class-info left recolor"
|
||||
>
|
||||
<template v-if="!playerEvent.hasConfirmed">
|
||||
<i class="bi bi-check2" />
|
||||
Confirm
|
||||
</template>
|
||||
<template v-else>
|
||||
<i class="bi bi-check2-all" />
|
||||
Attending
|
||||
</template>
|
||||
<span v-if="playerEvent.role">
|
||||
as {{ rosterStore.roleNames[playerEvent.role.role] }}
|
||||
</span>
|
||||
</button>
|
||||
<button v-else @click="emit('attend')" class="left">
|
||||
<i class="bi bi-check2" />
|
||||
Attend
|
||||
</button>
|
||||
<DropdownMenuRoot>
|
||||
<DropdownMenuTrigger className="right recolor">
|
||||
<i class="bi bi-caret-down-fill" />
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuRadioGroup v-model="selectedOption">
|
||||
<DropdownMenuRadioItem
|
||||
v-for="option in confirmationOptions"
|
||||
as="button"
|
||||
:value="option"
|
||||
>
|
||||
<DropdownMenuItemIndicator>
|
||||
<i class="bi bi-check" />
|
||||
</DropdownMenuItemIndicator>
|
||||
{{ option }}
|
||||
</DropdownMenuRadioItem>
|
||||
</DropdownMenuRadioGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuRoot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.event-confirm-button {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.left {
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
.right {
|
||||
border-radius: 0 4px 4px 0;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
.confirmed button.recolor {
|
||||
background-color: var(--text);
|
||||
color: var(--base);
|
||||
}
|
||||
</style>
|
|
@ -21,12 +21,15 @@ export const useTeamsEventsStore = defineStore("teamsEvents", () => {
|
|||
);
|
||||
}
|
||||
|
||||
async function attendEvent(eventId: number) {
|
||||
return client.default.attendEvent(eventId)
|
||||
async function attendEvent(eventId: number, confirm = true) {
|
||||
return client.default.attendEvent(eventId, {
|
||||
confirm,
|
||||
})
|
||||
.then((response) => {
|
||||
let index = teamEvents[response.event.teamId]
|
||||
.findIndex((event) => event.event.id == response.event.id);
|
||||
teamEvents[response.event.teamId][index] = response;
|
||||
return response;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -143,6 +143,9 @@ def create_event(player_team: PlayerTeam, team_id: int, json: CreateEventJson, *
|
|||
|
||||
return EventSchema.from_model(event).dict(by_alias=True), 200
|
||||
|
||||
class AttendanceJson(BaseModel):
|
||||
confirm: bool
|
||||
|
||||
@api_events.put("/<int:event_id>/attendance")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
|
@ -151,7 +154,7 @@ def create_event(player_team: PlayerTeam, team_id: int, json: CreateEventJson, *
|
|||
operation_id="attend_event",
|
||||
)
|
||||
@requires_authentication
|
||||
def attend_event(player: Player, event_id: int, **_):
|
||||
def attend_event(player: Player, event_id: int, json: AttendanceJson, **_):
|
||||
event = db.session.query(Event).where(Event.id == event_id).one_or_none()
|
||||
|
||||
if not event:
|
||||
|
@ -175,7 +178,7 @@ def attend_event(player: Player, event_id: int, **_):
|
|||
player_event.player_id = player.steam_id
|
||||
db.session.add(player_event)
|
||||
|
||||
player_event.has_confirmed = True
|
||||
player_event.has_confirmed = json.confirm
|
||||
|
||||
db.session.commit()
|
||||
|
||||
|
|
Loading…
Reference in New Issue