Pārlūkot izejas kodu

feat: :sparkles: feat (landing) adicionadas validacoes e redirecionamento para serprati digital

foram adicionadas validacoes nos campos de associacao e foi adicionado o redirecionamento para o sistema da serprati digital

fase:dev | origin:escopo
Gustavo Zanatta 1 mēnesi atpakaļ
vecāks
revīzija
8831ab9d74
2 mainītis faili ar 64 papildinājumiem un 6 dzēšanām
  1. 1 1
      app/components/AppHeader.vue
  2. 63 5
      app/pages/index.vue

+ 1 - 1
app/components/AppHeader.vue

@@ -48,7 +48,7 @@ const scrollTo = (id: string) => {
 }
 
 const handleEntrar = () => {
-  console.log('redirecionando para pagina de entrar')
+  window.open('https://serpratidigital.softpar.inf.br/', '_blank')
 }
 </script>
 

+ 63 - 5
app/pages/index.vue

@@ -136,7 +136,7 @@
 
                 <div class="field-group">
                   <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>
                     <input
                       :value="form.cpf"
@@ -145,32 +145,37 @@
                       maxlength="14"
                       class="field-input"
                       @input="handleCPF"
+                      @blur="onCPFBlur"
                     >
                   </div>
                 </div>
 
                 <div class="field-group">
                   <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>
                     <input
                       v-model="form.email"
                       type="email"
                       placeholder="nome@conta.com"
                       class="field-input"
+                      @blur="onEmailBlur"
                     >
                   </div>
                 </div>
 
                 <div class="field-group">
                   <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>
                     <input
-                      v-model="form.telefone"
+                      :value="form.telefone"
                       type="tel"
-                      placeholder="00000000"
+                      placeholder="(00) 00000-0000"
+                      maxlength="15"
                       class="field-input"
+                      @input="handlePhone"
+                      @blur="onPhoneBlur"
                     >
                   </div>
                 </div>
@@ -299,10 +304,54 @@ const formatCPF = (value: string): string => {
     .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) => {
   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 isLoading = ref(false)
@@ -312,9 +361,15 @@ const errorMessage = ref('')
 
 const resetForm = () => {
   Object.assign(form, { nomeCompleto: '', cpf: '', email: '', telefone: '', cargo: '', setor: '' })
+  Object.assign(errors, { cpf: '', email: '', telefone: '' })
 }
 
 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
   showError.value = false
 
@@ -456,6 +511,9 @@ onMounted(() => {
 .field-input-wrap:focus-within {
   border-color: #661d75;
 }
+.field-input-wrap.field-error {
+  border-color: #dc2626;
+}
 .field-icon {
   font-size: 1.125rem;
   color: #b6b6b6;