<script setup lang="ts"> import { RoleEnum, type UserIn, type UserOutExtended } from "@/client"; import { onMounted, reactive, ref } from "vue"; import { Modal, Toast } from "bootstrap"; import BootstrapModal from "@/components/modals/BootstrapModal.vue"; import { useUserStore } from "@/stores/users"; import BootstrapToast from "@/components/BootstrapToast.vue"; let modal: Modal | null = null; const createUserForm = ref<HTMLFormElement | undefined>(undefined); let successToast: Toast | undefined; let errorToast: Toast | undefined; const userRepository = useUserStore(); const formState = reactive<{ loading: boolean; user: UserIn; errorMessage?: string; registeredUserName: string; validated: boolean; }>({ loading: false, errorMessage: "", validated: false, registeredUserName: "", user: { display_name: "", email: "", roles: [RoleEnum.USER], }, }); const props = defineProps<{ modalId: string; }>(); const emit = defineEmits<{ (e: "user-created", user: UserOutExtended): void; }>(); function createUser() { formState.validated = true; if (createUserForm.value?.checkValidity()) { formState.loading = true; formState.registeredUserName = formState.user.display_name; userRepository .inviteUser(formState.user) .then((user) => { emit("user-created", user); formState.validated = false; formState.user = { display_name: "", email: "", roles: [RoleEnum.USER], }; successToast?.show(); modal?.hide(); }) .catch((err) => { formState.errorMessage = err.body?.detail; errorToast?.show(); }) .finally(() => { formState.loading = false; }); } } onMounted(() => { modal = Modal.getOrCreateInstance(`#${props.modalId}`); successToast = new Toast("#create-user-success-toast"); errorToast = new Toast("#create-user-error-toast"); }); </script> <template> <bootstrap-toast toast-id="create-user-success-toast"> Successfully invited user {{ formState.registeredUserName }} </bootstrap-toast> <bootstrap-toast toast-id="create-user-error-toast" color-class="danger"> <template #default >Couldn't invite user {{ formState.registeredUserName }} </template> <template #body>Error: {{ formState.errorMessage }}</template> </bootstrap-toast> <bootstrap-modal :modalId="props.modalId" :static-backdrop="true" modal-label="Create user" > <template #header>Invite a user</template> <template #body> <form id="create-user-form" @submit.prevent="createUser()" :class="{ 'was-validated': formState.validated }" ref="createUserForm" novalidate > <div class="mb-3"> <label for="create-user-name" class="form-label">Name</label> <input type="text" class="form-control" id="create-user-name" minlength="3" maxlength="256" required placeholder="John Doe" v-model="formState.user.display_name" /> <div class="invalid-feedback">Please choose a name.</div> </div> <div class="mb-3"> <label for="create-user-email" class="form-label" >Email address</label > <input type="email" class="form-control" id="create-user-email" required placeholder="name@example.com" minlength="3" maxlength="256" v-model="formState.user.email" /> <div class="invalid-feedback"> Please provide a valid email address. </div> </div> <div class="mb-3"> <div class="mb-1">Roles:</div> <div class="form-check" v-for="role in Object.values(RoleEnum)" :key="role" > <input class="form-check-input" type="checkbox" :value="role" :id="`create-user-role-${role}`" v-model="formState.user.roles" /> <label class="form-check-label" :for="`create-user-role-${role}`"> {{ role.toUpperCase() }} </label> </div> </div> </form> </template> <template #footer> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal"> Close </button> <button type="submit" form="create-user-form" class="btn btn-primary" :disabled="formState.loading" > Save </button> </template> </bootstrap-modal> </template> <style scoped></style>