feat: register T1 (pending, verify)
This commit is contained in:
1 parent
3c3f7c6194
commit
4e41d60142
29 files changed
+2162
-42
No files matched your search
@@ -0,0 +1,118 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, ref, watch } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
title: string
|
||||
description: string
|
||||
confirmLabel: string
|
||||
cancelLabel: string
|
||||
pendingLabel: string
|
||||
tone: 'danger' | 'neutral'
|
||||
action: () => Promise<void>
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{ close: [confirmed: boolean] }>()
|
||||
|
||||
const open = defineModel<boolean>('open', { default: true })
|
||||
const pending = ref(false)
|
||||
const error = ref('')
|
||||
const cancelButton = ref<{ $el: HTMLElement } | null>(null)
|
||||
let settled = false
|
||||
|
||||
const confirmColor = computed(() => (props.tone === 'danger' ? 'error' : 'primary'))
|
||||
const confirmText = computed(() => (pending.value ? props.pendingLabel : props.confirmLabel))
|
||||
|
||||
onMounted(async () => {
|
||||
await nextTick()
|
||||
cancelButton.value?.$el?.focus()
|
||||
})
|
||||
|
||||
function settle(confirmed: boolean) {
|
||||
if (settled) {
|
||||
return
|
||||
}
|
||||
settled = true
|
||||
open.value = false
|
||||
emit('close', confirmed)
|
||||
}
|
||||
|
||||
watch(open, (value) => {
|
||||
if (!value) {
|
||||
settle(false)
|
||||
}
|
||||
})
|
||||
|
||||
async function onConfirm() {
|
||||
if (pending.value) {
|
||||
return
|
||||
}
|
||||
pending.value = true
|
||||
error.value = ''
|
||||
try {
|
||||
await props.action()
|
||||
settle(true)
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err.message : 'Something went wrong. Try again.'
|
||||
} finally {
|
||||
pending.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function onCancel() {
|
||||
if (pending.value) {
|
||||
return
|
||||
}
|
||||
settle(false)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UModal
|
||||
v-model:open="open"
|
||||
:title="title"
|
||||
:description="description"
|
||||
:dismissible="!pending"
|
||||
:close="false"
|
||||
:content="{ role: 'alertdialog', 'aria-busy': pending ? 'true' : undefined }"
|
||||
:ui="{
|
||||
content:
|
||||
'max-sm:!inset-x-0 max-sm:!bottom-0 max-sm:!top-auto max-sm:!left-0 max-sm:!right-0 max-sm:!translate-x-0 max-sm:!translate-y-0 max-sm:!w-full max-sm:!max-w-none',
|
||||
}"
|
||||
>
|
||||
<template v-if="error" #body>
|
||||
<UAlert
|
||||
color="error"
|
||||
icon="i-lucide-circle-x"
|
||||
:description="error"
|
||||
variant="soft"
|
||||
:close="false"
|
||||
role="alert"
|
||||
/>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div class="flex w-full flex-col-reverse gap-2 sm:flex-row sm:justify-end">
|
||||
<UButton
|
||||
ref="cancelButton"
|
||||
color="neutral"
|
||||
variant="outline"
|
||||
block
|
||||
class="sm:w-auto"
|
||||
:disabled="pending"
|
||||
@click="onCancel"
|
||||
>
|
||||
{{ cancelLabel }}
|
||||
</UButton>
|
||||
<UButton
|
||||
:color="confirmColor"
|
||||
:loading="pending"
|
||||
:disabled="pending"
|
||||
block
|
||||
class="sm:w-auto"
|
||||
@click="onConfirm"
|
||||
>
|
||||
{{ confirmText }}
|
||||
</UButton>
|
||||
</div>
|
||||
</template>
|
||||
</UModal>
|
||||
</template>
|
||||
Reference in new issue
Block a user