Files
scrum-poker-internal/resources/js/components/rooms/RoomHeader.vue
T

144 lines
4.8 KiB
Vue

<script setup lang="ts">
import { Link, useHttp } from '@inertiajs/vue3';
import { Check, Copy } from '@lucide/vue';
import { ref, watch } from 'vue';
import { Checkbox } from '@/components/ui/checkbox';
import { favorite } from '@/routes/room';
import { update as updatePermissions } from '@/routes/room/permissions';
import type { RoomHeaderEmits, RoomHeaderProps } from '@/types/room';
const props = defineProps<RoomHeaderProps>();
const emit = defineEmits<RoomHeaderEmits>();
const copied = ref(false);
const allowParticipantControls = ref(props.allowParticipantControls);
const permissionRequest = useHttp(() => updatePermissions(props.id), {
allow_participant_controls: props.allowParticipantControls,
});
watch(
() => props.allowParticipantControls,
(value) => {
allowParticipantControls.value = value;
if (!permissionRequest.processing) {
permissionRequest.allow_participant_controls = value;
}
},
);
async function copyInviteLink(): Promise<void> {
const inviteUrl = new URL('/room/join', window.location.origin);
inviteUrl.searchParams.set('join_code', props.join_code);
await navigator.clipboard.writeText(inviteUrl.toString());
copied.value = true;
window.setTimeout(() => {
copied.value = false;
}, 1_800);
}
function updateParticipantControls(value: boolean): void {
if (permissionRequest.processing) {
return;
}
const previousValue = allowParticipantControls.value;
allowParticipantControls.value = value;
permissionRequest.allow_participant_controls = value;
void permissionRequest.submit({
onError: () => {
allowParticipantControls.value = previousValue;
permissionRequest.allow_participant_controls = previousValue;
},
});
}
</script>
<template>
<header
class="mx-auto flex w-full max-w-6xl flex-col gap-4 sm:flex-row sm:items-center sm:justify-between"
>
<div>
<h1 class="text-2xl font-bold sm:text-3xl">
{{ title ?? 'Scrum Poker' }}
</h1>
<Link
v-if="canFavorite"
:href="favorite(id)"
method="post"
as="button"
class="mt-2 inline-flex items-center gap-2"
>
<span>Favorit</span>
<span class="material-icons" aria-hidden="true">
{{ is_favorite ? 'favorite' : 'favorite_border' }}
</span>
</Link>
</div>
<div class="flex flex-col items-end gap-2">
<button
type="button"
class="flex w-fit items-center gap-3 rounded-xl border border-slate-700 bg-slate-800 px-4 py-2.5 text-left transition hover:bg-slate-700 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-cyan-300"
@click="copyInviteLink"
>
<span>
<span
class="block text-sm tracking-[0.18em] text-slate-400"
>
Raumcode
</span>
<strong class="font-mono text-lg tracking-[0.2em]">
{{ join_code }}
</strong>
</span>
<Check v-if="copied" class="size-5 text-emerald-300" />
<Copy v-else class="size-5 text-slate-300" />
</button>
<label
v-if="isModerator"
for="participant-controls"
class="flex cursor-pointer items-center gap-2 text-sm text-slate-300"
>
<Checkbox
id="participant-controls"
:model-value="allowParticipantControls"
:disabled="permissionRequest.processing"
@update:model-value="
updateParticipantControls($event === true)
"
/>
<span>Alle dürfen die Runde steuern</span>
</label>
<p
v-if="permissionRequest.errors.allow_participant_controls"
class="max-w-xs text-right text-sm text-rose-300"
role="alert"
>
{{ permissionRequest.errors.allow_participant_controls }}
</p>
<label
for="presenter-mode"
class="flex cursor-pointer items-center gap-2 text-sm text-slate-300"
>
<Checkbox
id="presenter-mode"
:model-value="presenterMode"
@update:model-value="
emit('update:presenterMode', $event === true)
"
/>
<span>Präsentatormodus</span>
</label>
</div>
</header>
</template>