refactor(create collection modal): use ModalTemplate & v-model

This commit is contained in:
DecDuck
2025-01-28 12:26:12 +11:00
parent eea8f82bf9
commit 934c176974

View File

@ -1,118 +1,100 @@
<template>
<TransitionRoot appear :show="show" as="template">
<Dialog as="div" @close="$emit('close')" class="relative z-50">
<TransitionChild
as="template"
enter="duration-300 ease-out"
enter-from="opacity-0"
enter-to="opacity-100"
leave="duration-200 ease-in"
leave-from="opacity-100"
leave-to="opacity-0"
>
<div class="fixed inset-0 bg-zinc-950/80" aria-hidden="true" />
</TransitionChild>
<div class="fixed inset-0 overflow-y-auto">
<div class="flex min-h-full items-center justify-center p-4 text-center">
<TransitionChild
as="template"
enter="duration-300 ease-out"
enter-from="opacity-0 scale-95"
enter-to="opacity-100 scale-100"
leave="duration-200 ease-in"
leave-from="opacity-100 scale-100"
leave-to="opacity-0 scale-95"
>
<DialogPanel class="w-full max-w-md transform overflow-hidden rounded-2xl bg-zinc-900 p-6 text-left align-middle shadow-xl transition-all">
<DialogTitle as="h3" class="text-lg font-medium leading-6 text-white">
Create Collection
</DialogTitle>
<div class="mt-2">
<input
type="text"
v-model="collectionName"
placeholder="Collection name"
class="block w-full rounded-md border-0 bg-zinc-800 py-1.5 text-white shadow-sm ring-1 ring-inset ring-zinc-700 placeholder:text-zinc-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6"
/>
</div>
<div class="mt-4 flex justify-end gap-x-2">
<button
type="button"
@click="$emit('close')"
class="inline-flex justify-center rounded-md border border-transparent px-4 py-2 text-sm font-medium text-zinc-400 hover:text-zinc-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
>
Cancel
</button>
<LoadingButton
:loading="isCreating"
:disabled="!collectionName"
@click="createCollection"
class="inline-flex items-center rounded-md bg-white/10 px-3 py-2 text-sm font-semibold font-display text-white hover:bg-white/20 disabled:opacity-50 disabled:cursor-not-allowed"
>
Create
</LoadingButton>
</div>
</DialogPanel>
</TransitionChild>
</div>
<ModalTemplate v-model="open">
<template #default>
<DialogTitle as="h3" class="text-lg font-medium leading-6 text-white">
Create Collection
</DialogTitle>
<div class="mt-2">
<input
type="text"
v-model="collectionName"
placeholder="Collection name"
class="block w-full rounded-md border-0 bg-zinc-800 py-1.5 text-white shadow-sm ring-1 ring-inset ring-zinc-700 placeholder:text-zinc-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6"
/>
</div>
</Dialog>
</TransitionRoot>
</template>
<template #buttons="{ close }">
<button
type="button"
@click="() => close()"
class="inline-flex justify-center rounded-md border border-transparent px-4 py-2 text-sm font-medium text-zinc-400 hover:text-zinc-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
>
Cancel
</button>
<LoadingButton
:loading="createCollectionLoading"
:disabled="!collectionName"
@click="() => createCollection()"
class="inline-flex items-center rounded-md bg-white/10 px-3 py-2 text-sm font-semibold font-display text-white hover:bg-white/20 disabled:opacity-50 disabled:cursor-not-allowed"
>
Create
</LoadingButton>
</template>
</ModalTemplate>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { ref } from "vue";
import {
TransitionRoot,
TransitionChild,
Dialog,
DialogPanel,
DialogTitle,
} from '@headlessui/vue';
} from "@headlessui/vue";
import ModalTemplate from "~/drop-base/components/ModalTemplate.vue";
const props = defineProps<{
show: boolean
gameId?: string
gameId?: string;
}>();
const emit = defineEmits<{
close: []
created: [collectionId: string]
created: [collectionId: string];
}>();
const collectionName = ref('');
const isCreating = ref(false);
const open = defineModel<boolean>();
const collectionName = ref("");
const createCollectionLoading = ref(false);
async function createCollection() {
if (!collectionName.value || createCollectionLoading.value) return;
const createCollection = async () => {
if (!collectionName.value || isCreating.value) return;
try {
isCreating.value = true;
createCollectionLoading.value = true;
// Create the collection
const response = await $fetch('/api/v1/collection', {
method: 'POST',
body: { name: collectionName.value }
const response = await $fetch("/api/v1/collection", {
method: "POST",
body: { name: collectionName.value },
});
// Add the game if provided
if (props.gameId) {
await $fetch(`/api/v1/collection/${response.id}/entry`, {
method: 'POST',
body: { id: props.gameId }
method: "POST",
body: { id: props.gameId },
});
}
// Reset and emit
collectionName.value = '';
emit('created', response.id);
emit('close');
collectionName.value = "";
open.value = false;
emit("created", response.id);
} catch (error) {
console.error('Failed to create collection:', error);
console.error("Failed to create collection:", error);
createModal(
ModalType.Notification,
{
title: "Failed to create collection",
description: `Drop couldn't create your collection: ${error}`,
},
(_, c) => c()
);
} finally {
isCreating.value = false;
createCollectionLoading.value = false;
}
};
</script>
}
</script>