|
@@ -136,7 +136,7 @@
|
|
|
|
|
|
|
|
<div class="field-group">
|
|
<div class="field-group">
|
|
|
<label class="field-label">CPF</label>
|
|
<label class="field-label">CPF</label>
|
|
|
- <div class="field-input-wrap">
|
|
|
|
|
|
|
+ <div :class="['field-input-wrap', { 'field-error': errors.cpf }]">
|
|
|
<span class="material-icons field-icon">badge</span>
|
|
<span class="material-icons field-icon">badge</span>
|
|
|
<input
|
|
<input
|
|
|
:value="form.cpf"
|
|
:value="form.cpf"
|
|
@@ -145,32 +145,37 @@
|
|
|
maxlength="14"
|
|
maxlength="14"
|
|
|
class="field-input"
|
|
class="field-input"
|
|
|
@input="handleCPF"
|
|
@input="handleCPF"
|
|
|
|
|
+ @blur="onCPFBlur"
|
|
|
>
|
|
>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="field-group">
|
|
<div class="field-group">
|
|
|
<label class="field-label">E-mail</label>
|
|
<label class="field-label">E-mail</label>
|
|
|
- <div class="field-input-wrap">
|
|
|
|
|
|
|
+ <div :class="['field-input-wrap', { 'field-error': errors.email }]">
|
|
|
<span class="material-icons field-icon">email</span>
|
|
<span class="material-icons field-icon">email</span>
|
|
|
<input
|
|
<input
|
|
|
v-model="form.email"
|
|
v-model="form.email"
|
|
|
type="email"
|
|
type="email"
|
|
|
placeholder="nome@conta.com"
|
|
placeholder="nome@conta.com"
|
|
|
class="field-input"
|
|
class="field-input"
|
|
|
|
|
+ @blur="onEmailBlur"
|
|
|
>
|
|
>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="field-group">
|
|
<div class="field-group">
|
|
|
<label class="field-label">Telefone</label>
|
|
<label class="field-label">Telefone</label>
|
|
|
- <div class="field-input-wrap">
|
|
|
|
|
|
|
+ <div :class="['field-input-wrap', { 'field-error': errors.telefone }]">
|
|
|
<span class="material-icons field-icon">phone</span>
|
|
<span class="material-icons field-icon">phone</span>
|
|
|
<input
|
|
<input
|
|
|
- v-model="form.telefone"
|
|
|
|
|
|
|
+ :value="form.telefone"
|
|
|
type="tel"
|
|
type="tel"
|
|
|
- placeholder="00000000"
|
|
|
|
|
|
|
+ placeholder="(00) 00000-0000"
|
|
|
|
|
+ maxlength="15"
|
|
|
class="field-input"
|
|
class="field-input"
|
|
|
|
|
+ @input="handlePhone"
|
|
|
|
|
+ @blur="onPhoneBlur"
|
|
|
>
|
|
>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -299,10 +304,54 @@ const formatCPF = (value: string): string => {
|
|
|
.slice(0, 14)
|
|
.slice(0, 14)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+const validateCPF = (cpf: string): boolean => {
|
|
|
|
|
+ const d = cpf.replace(/\D/g, '')
|
|
|
|
|
+ if (d.length !== 11 || /^(\d)\1{10}$/.test(d)) return false
|
|
|
|
|
+ const calc = (n: number): number => {
|
|
|
|
|
+ let sum = 0
|
|
|
|
|
+ for (let i = 0; i < n; i++) sum += parseInt(d.charAt(i)) * (n + 1 - i)
|
|
|
|
|
+ const rem = sum % 11
|
|
|
|
|
+ return rem < 2 ? 0 : 11 - rem
|
|
|
|
|
+ }
|
|
|
|
|
+ return calc(9) === parseInt(d.charAt(9)) && calc(10) === parseInt(d.charAt(10))
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const validateEmail = (email: string): boolean =>
|
|
|
|
|
+ /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
|
|
|
|
|
+
|
|
|
|
|
+const formatPhone = (value: string): string =>
|
|
|
|
|
+ value
|
|
|
|
|
+ .replace(/\D/g, '')
|
|
|
|
|
+ .replace(/^(\d{2})(\d)/, '($1) $2')
|
|
|
|
|
+ .replace(/(\d{5})(\d{1,4})$/, '$1-$2')
|
|
|
|
|
+ .slice(0, 15)
|
|
|
|
|
+
|
|
|
|
|
+const errors = reactive({ cpf: '', email: '', telefone: '' })
|
|
|
|
|
+
|
|
|
const handleCPF = (e: Event) => {
|
|
const handleCPF = (e: Event) => {
|
|
|
form.cpf = formatCPF((e.target as HTMLInputElement).value)
|
|
form.cpf = formatCPF((e.target as HTMLInputElement).value)
|
|
|
|
|
+ if (errors.cpf) errors.cpf = ''
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+const handlePhone = (e: Event) => {
|
|
|
|
|
+ form.telefone = formatPhone((e.target as HTMLInputElement).value)
|
|
|
|
|
+ if (errors.telefone) errors.telefone = ''
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const onCPFBlur = () => {
|
|
|
|
|
+ errors.cpf = form.cpf && !validateCPF(form.cpf) ? 'CPF inválido' : ''
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const onEmailBlur = () => {
|
|
|
|
|
+ errors.email = form.email && !validateEmail(form.email) ? 'E-mail inválido' : ''
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const onPhoneBlur = () => {
|
|
|
|
|
+ errors.telefone = form.telefone && form.telefone.replace(/\D/g, '').length < 10 ? 'Telefone inválido' : ''
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+watch(() => form.email, () => { if (errors.email) errors.email = '' })
|
|
|
|
|
+
|
|
|
const { registerLandingUser } = useRegisterApi()
|
|
const { registerLandingUser } = useRegisterApi()
|
|
|
|
|
|
|
|
const isLoading = ref(false)
|
|
const isLoading = ref(false)
|
|
@@ -312,9 +361,15 @@ const errorMessage = ref('')
|
|
|
|
|
|
|
|
const resetForm = () => {
|
|
const resetForm = () => {
|
|
|
Object.assign(form, { nomeCompleto: '', cpf: '', email: '', telefone: '', cargo: '', setor: '' })
|
|
Object.assign(form, { nomeCompleto: '', cpf: '', email: '', telefone: '', cargo: '', setor: '' })
|
|
|
|
|
+ Object.assign(errors, { cpf: '', email: '', telefone: '' })
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const handleSubmit = async () => {
|
|
const handleSubmit = async () => {
|
|
|
|
|
+ errors.cpf = form.cpf && !validateCPF(form.cpf) ? 'CPF inválido' : ''
|
|
|
|
|
+ errors.email = form.email && !validateEmail(form.email) ? 'E-mail inválido' : ''
|
|
|
|
|
+ errors.telefone = form.telefone && form.telefone.replace(/\D/g, '').length < 10 ? 'Telefone inválido' : ''
|
|
|
|
|
+ if (errors.cpf || errors.email || errors.telefone) return
|
|
|
|
|
+
|
|
|
isLoading.value = true
|
|
isLoading.value = true
|
|
|
showError.value = false
|
|
showError.value = false
|
|
|
|
|
|
|
@@ -456,6 +511,9 @@ onMounted(() => {
|
|
|
.field-input-wrap:focus-within {
|
|
.field-input-wrap:focus-within {
|
|
|
border-color: #661d75;
|
|
border-color: #661d75;
|
|
|
}
|
|
}
|
|
|
|
|
+.field-input-wrap.field-error {
|
|
|
|
|
+ border-color: #dc2626;
|
|
|
|
|
+}
|
|
|
.field-icon {
|
|
.field-icon {
|
|
|
font-size: 1.125rem;
|
|
font-size: 1.125rem;
|
|
|
color: #b6b6b6;
|
|
color: #b6b6b6;
|