Files
Inventory/frontend/app/components/form/FieldPhone.vue
Matthieu 974a4a0781 refactor : merge Inventory_frontend submodule into frontend/ directory
Merges the full git history of Inventory_frontend into the monorepo
under frontend/. Removes the submodule in favor of a unified repo.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 14:17:57 +02:00

114 lines
3.1 KiB
Vue

<template>
<div class="form-control">
<label v-if="label" class="label" :for="inputId">
<span class="label-text">{{ label }}</span>
<span v-if="required" class="label-text-alt text-error">*</span>
</label>
<input
:id="inputId"
:value="modelValue"
type="tel"
class="input input-bordered"
:class="{ 'input-error': Boolean(errorMessage) }"
:placeholder="placeholder"
:required="required"
:disabled="disabled"
:name="name"
:autocomplete="autocomplete"
:pattern="PHONE_INPUT_PATTERN"
inputmode="tel"
:aria-invalid="Boolean(errorMessage)"
:aria-describedby="describedBy"
@input="onInput"
@blur="onBlur"
@focus="(event) => emit('focus', event)"
/>
<p v-if="help" :id="helpId" class="mt-2 text-xs text-base-content/50">
{{ help }}
</p>
<p v-if="errorMessage" :id="errorId" class="mt-2 text-xs text-error">
{{ errorMessage }}
</p>
</div>
</template>
<script setup lang="ts">
import { computed, useId } from 'vue'
import { formatPhone } from '~/utils/formatters/phone'
import { PHONE_INPUT_PATTERN, PHONE_VALIDATION_ERROR, phoneSchema } from '~/shared/validation/phone'
type Emits = {
(event: 'update:modelValue', value: string): void
(event: 'blur', value: FocusEvent): void
(event: 'focus', value: FocusEvent): void
}
const emit = defineEmits<Emits>()
const props = withDefaults(
defineProps<{
modelValue: string
label?: string
required?: boolean
error?: string | null
help?: string | null
placeholder?: string
disabled?: boolean
name?: string
id?: string
autocomplete?: string
normalizeOnBlur?: boolean
validateOnBlur?: boolean
}>(),
{
modelValue: '',
label: 'Téléphone',
required: false,
error: null,
help: null,
placeholder: 'Ex: 06 00 00 00 00',
disabled: false,
name: undefined,
id: undefined,
autocomplete: 'tel',
normalizeOnBlur: false,
validateOnBlur: false,
}
)
const fallbackId = useId()
const inputId = computed(() => props.id || fallbackId)
const helpId = computed(() => (props.help ? `${inputId.value}-help` : undefined))
const errorMessage = computed(() => props.error || null)
const errorId = computed(() => (errorMessage.value ? `${inputId.value}-error` : undefined))
const describedBy = computed(() => [helpId.value, errorId.value].filter(Boolean).join(' ') || undefined)
const onInput = (event: Event) => {
const target = event.target as HTMLInputElement
emit('update:modelValue', target.value)
}
const onBlur = (event: FocusEvent) => {
const target = event.target as HTMLInputElement
if (props.normalizeOnBlur) {
const formatted = formatPhone(target.value)
if (formatted !== target.value) {
target.value = formatted
emit('update:modelValue', formatted)
}
}
if (props.validateOnBlur && !errorMessage.value) {
const validation = phoneSchema.validate(target.value)
if (!validation.valid) {
target.setCustomValidity(PHONE_VALIDATION_ERROR)
} else {
target.setCustomValidity('')
}
}
emit('blur', event)
}
</script>