Fixes from template

This commit is contained in:
2026-06-25 00:38:47 -07:00
parent d134b480a0
commit bf1d82fa19
24 changed files with 162 additions and 323 deletions
@@ -46,7 +46,7 @@
import { computed } from "vue"
import { useDisplay } from "vuetify"
import HeaderActionsCard from "@/components/shared/cards/HeaderActionsCard.vue"
import HeaderActionsCard from "@/components/common/HeaderActionsCard.vue"
const props = withDefaults(
defineProps<{
@@ -0,0 +1,104 @@
<template>
<v-text-field
ref="textField"
:model-value="modelValue"
:label="label"
:rules="[...rules, valueMustBeUnique]"
@update:model-value="updateModelValue"
>
<template #append-inner>
<v-icon
v-if="isNil(isUniqueValue)"
:title="uniqueValidationMessage"
>mdi-progress-clock</v-icon
>
<v-progress-circular
v-else-if="isCheckingUniqueness"
size="18"
width="2"
indeterminate
color="primary"
/>
<v-icon
v-else-if="isUniqueValue === true"
:title="isUniqueMessage"
color="success"
>mdi-check-circle-outline</v-icon
>
<v-icon
v-else
color="warning"
:title="isNotUniqueMessage"
>mdi-alert-circle-outline</v-icon
>
</template>
</v-text-field>
</template>
<script setup lang="ts">
import { ref } from "vue"
import { debounce, isEmpty, isNil } from "lodash"
import { VTextField } from "vuetify/components"
const props = withDefaults(
defineProps<{
modelValue: string | null | undefined
label: string
checkAvailability: (value: string) => Promise<boolean>
rules?: VTextField["rules"]
uniqueValidationMessage?: string
isUniqueMessage?: string
isNotUniqueMessage?: string
}>(),
{
rules: () => [],
uniqueValidationMessage: "Value must be unique",
isUniqueMessage: "Value is unique",
isNotUniqueMessage: "Value is not unique",
}
)
const emit = defineEmits<{
"update:modelValue": [value: string]
}>()
const isUniqueValue = ref<boolean | null>(null)
const isCheckingUniqueness = ref(false)
const textField = ref<InstanceType<typeof VTextField> | null>(null)
async function updateModelValue(value: string) {
emit("update:modelValue", value)
await debouncedCheckValueIsUnique(value)
}
async function checkValueIsUnique(value: string | null | undefined) {
if (isNil(value) || isEmpty(value)) return null
isCheckingUniqueness.value = true
try {
const result = await props.checkAvailability(value)
isUniqueValue.value = result
await textField.value?.validate(false)
return result
} catch (error) {
console.error(error)
return false
} finally {
isCheckingUniqueness.value = false
}
}
const debouncedCheckValueIsUnique = debounce(checkValueIsUnique, 500)
function valueMustBeUnique() {
if (isUniqueValue.value === true || isUniqueValue.value === null) return true
return props.uniqueValidationMessage
}
defineExpose({
validate: () => checkValueIsUnique(props.modelValue),
})
</script>
@@ -0,0 +1,34 @@
<template>
<UniqueTextField
ref="uniqueTextField"
v-model="userEmail"
label="Email"
:check-availability="checkEmailAvailability"
unique-validation-message="User email must be unique"
is-unique-message="User email is available"
is-not-unique-message="User email is already taken"
/>
</template>
<script setup lang="ts">
import { ref } from "vue"
import usersApi from "@/api/users-api"
import UniqueTextField from "@/components/common/UniqueTextField.vue"
const userEmail = defineModel<string | null | undefined>({
required: true,
})
async function checkEmailAvailability(email: string) {
const { users } = await usersApi.list({
where: {
email,
},
})
return users.length === 0
}
const uniqueTextField = ref<InstanceType<typeof UniqueTextField> | null>(null)
</script>