From d14fd9e2b75f2cbc57b11763461ab6e740d05bcd Mon Sep 17 00:00:00 2001 From: CaioMiranda12 Date: Tue, 25 Aug 2026 15:37:57 -0300 Subject: [PATCH 1/7] refactor: add new style on primary button --- src/components/ButtonPrimary.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/components/ButtonPrimary.tsx b/src/components/ButtonPrimary.tsx index 67ec0ff..44f8808 100644 --- a/src/components/ButtonPrimary.tsx +++ b/src/components/ButtonPrimary.tsx @@ -11,11 +11,7 @@ export function PrimaryButton({ children, isDisabled = false, onClick }: Primary ) From af5ff65a837b29c34f8df155ff68c5bd5099646c Mon Sep 17 00:00:00 2001 From: CaioMiranda12 Date: Tue, 25 Aug 2026 15:38:04 -0300 Subject: [PATCH 2/7] refactor: add new style on secondary button --- src/components/ButtonSecondary.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/components/ButtonSecondary.tsx b/src/components/ButtonSecondary.tsx index 54d358c..321c16a 100644 --- a/src/components/ButtonSecondary.tsx +++ b/src/components/ButtonSecondary.tsx @@ -16,11 +16,7 @@ export function SecondaryButton({ children, isDisabled = false, onClick, isActiv From 0255ca3622fe2c4d4d850391761d5cc464d243a5 Mon Sep 17 00:00:00 2001 From: CaioMiranda12 Date: Tue, 25 Aug 2026 15:38:21 -0300 Subject: [PATCH 3/7] feat: create password rules function util --- src/utils/passwordRules.ts | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/utils/passwordRules.ts diff --git a/src/utils/passwordRules.ts b/src/utils/passwordRules.ts new file mode 100644 index 0000000..ef9ac4d --- /dev/null +++ b/src/utils/passwordRules.ts @@ -0,0 +1,29 @@ +export interface PasswordRule { + label: string; + valid: boolean; +} + +export function getPasswordRules(password: string): PasswordRule[] { + return [ + { + label: "Mínimo 8 caracteres", + valid: password.length >= 8, + }, + { + label: "1 número", + valid: /\d/.test(password), + }, + { + label: "Letras maiúscula", + valid: /[A-Z]/.test(password), + }, + { + label: "Letra minúscula", + valid: /[a-z]/.test(password), + }, + { + label: "1 caractere especial", + valid: /[!@#$%^&*(),.?":{}|<>]/.test(password), + }, + ]; +} From ae1ea75998c102ef997edc7ad79871d5113c59b8 Mon Sep 17 00:00:00 2001 From: CaioMiranda12 Date: Tue, 25 Aug 2026 15:38:35 -0300 Subject: [PATCH 4/7] refactor: add new style on input component --- src/components/Input.tsx | 113 ++++++++++++++++++++++++++++----------- 1 file changed, 83 insertions(+), 30 deletions(-) diff --git a/src/components/Input.tsx b/src/components/Input.tsx index 6140aec..40cc5e5 100644 --- a/src/components/Input.tsx +++ b/src/components/Input.tsx @@ -2,8 +2,10 @@ import { formatCPF } from "@/utils/formatCpf"; import { formatPhone } from "@/utils/formatPhone"; import { useState } from "react"; import { Controller, type Control, type FieldErrors, type FieldValues, type Path } from "react-hook-form"; +import { BiCheck } from "react-icons/bi"; import { IoEyeOutline } from "react-icons/io5"; import { LuEyeClosed } from "react-icons/lu"; +import { VscError } from "react-icons/vsc"; interface InputProps { name: Path; @@ -13,8 +15,15 @@ interface InputProps { placeholderText: string; isOptional?: boolean; mask?: "cpf" | "phone"; + rules?: PasswordRule[]; } +interface PasswordRule { + label: string; + valid: boolean; +} + + export function Input({ name, control, @@ -22,12 +31,20 @@ export function Input({ typeInput = 'text', placeholderText, isOptional = false, - mask + mask, + rules = [] }: InputProps) { const [showPassword, setShowPassword] = useState(false); const isPassword = typeInput === 'password'; const formattedType = isPassword ? (showPassword ? 'text' : 'password') : typeInput; + const hasInvalidRule = rules.some((rule) => !rule.valid); + + const isPasswordValid = + isPassword && + rules.length > 0 && + !hasInvalidRule; + type MaskType = "cpf" | "phone" | "none"; function applyMask(value: string, mask?: MaskType) { @@ -58,40 +75,76 @@ export function Input({ render={({ field }) => (
- handleInputChange(e.target.value, field.onChange, mask)} - className={`w-full p-5 bg-primary-gray-100 text-primary-gray-base font-normal placeholder:text-[27px] text-[27px] rounded-[20px] outline-none border-2 h-20 - placeholder:text-primary-gray-base - focus:border-primary-blue-300 - ${errors?.[name] ? 'border-[#CF1A0F]' : 'border-transparent'} - `} - /> - - {isPassword && ( - - )} + +
+ + handleInputChange(e.target.value, field.onChange, mask) + } + className={`w-full p-5 font-normal rounded-[10px] outline-none h-[52px] + placeholder:text-[#99A1AF] + + ${errors?.[name] + ? "border border-[#C10007] bg-[#FEF2F2] text-[#C10007]" + : isPasswordValid + ? "border border-[#008235] bg-[#F0FDF4]" + : "border border-[#E5E7EB] bg-[#F3F4F6] focus:border-[#0069A8]" + } + `} + /> + + {isPassword && ( + + )} +
- {errors?.[name] && ( - + {errors?.[name] && (!isPassword || rules.length === 0) && ( + {errors[name]?.message as string} )} + + {isPassword && hasInvalidRule && ( +
+ Sua senha deve conter: + {rules.map((rule) => ( +
+ {rule.valid + ? + : + } + + {rule.label} + +
+ ))} +
+ )} + + {isPasswordValid && ( + + Senha forte + + )}
)} /> From 76561a204759cdebe122203283f19691fbcca623 Mon Sep 17 00:00:00 2001 From: CaioMiranda12 Date: Tue, 25 Aug 2026 15:38:50 -0300 Subject: [PATCH 5/7] refactor: add new style on student form --- src/components/StudentForm.tsx | 90 +++++++++++++--------------------- 1 file changed, 34 insertions(+), 56 deletions(-) diff --git a/src/components/StudentForm.tsx b/src/components/StudentForm.tsx index 4aa3801..a24f4f3 100644 --- a/src/components/StudentForm.tsx +++ b/src/components/StudentForm.tsx @@ -7,10 +7,9 @@ import { toast } from "react-toastify"; import { TOAST_STYLES } from "@/pages/ToastStyleContainer"; import { SignUpStudentSchema, type SignUpStudentSchemaType } from "@/schemas/SignUp"; import { PrimaryButton } from "./ButtonPrimary"; -import { BiCheck } from "react-icons/bi"; -import { IoClose } from "react-icons/io5"; import { ButtonLoader } from "./ButtonLoader"; import { toStudentPayload } from "@/adapters/auth/toStudentPayload"; +import { getPasswordRules } from "@/utils/passwordRules"; export function StudentForm() { const { errors, handleSubmit, reset, control, watch } = useFormValidation(SignUpStudentSchema, { @@ -50,17 +49,8 @@ export function StudentForm() { } }, [isError, isSuccess, navigate, reset]); - function usePasswordRules(password: string) { - return [ - { label: "Mais de 10 caracteres", valid: password.length > 10 }, - { label: "Pelo menos 1 número", valid: /\d/.test(password) }, - { label: "Letras maiúsculas e minúsculas", valid: /[a-z]/.test(password) && /[A-Z]/.test(password) }, - { label: "Pelo menos 1 caractere especial", valid: /[!@#$%^&*(),.?":{}|<>]/.test(password) }, - ]; - } - const passwordValue = watch("password", ""); - const rules = usePasswordRules(passwordValue); + const rules = getPasswordRules(passwordValue); const onSubmit = (formData: SignUpStudentSchemaType) => { console.log("Formulário submetido", formData); @@ -86,66 +76,54 @@ export function StudentForm() { placeholderText="E-mail" /> - - name="cpf" - control={control} - errors={errors} - placeholderText="CPF" - mask="cpf" - /> - - - name="phone" - control={control} - errors={errors} - placeholderText="Celular" - mask="phone" - isOptional - /> +
+ + name="cpf" + control={control} + errors={errors} + placeholderText="CPF" + mask="cpf" + /> + + + name="phone" + control={control} + errors={errors} + placeholderText="Telefone" + mask="phone" + isOptional + /> +
name="password" control={control} errors={errors} - placeholderText="Crie sua senha" + placeholderText="Senha" typeInput="password" + rules={rules} /> name="confirmPassword" control={control} errors={errors} - placeholderText="Confirme sua senha" + placeholderText="Confirmar senha" typeInput="password" /> -
- Sua senha deve conter: - {rules.map((rule) => ( -
- {rule.valid - ? - : - } - - {rule.label} - -
- ))} - - *campos obrigatórios +
+ rule.valid) || watch("password") !== watch("confirmPassword")}> + {isPending ? ( + <> + Carregando + + + ) : ( + "Criar conta" + )} +
- - - {isPending ? ( - <> - Carregando - - - ) : ( - "Criar conta" - )} -
From d657bd3436e2391512acbf25ce67c95c4ca6c37b Mon Sep 17 00:00:00 2001 From: CaioMiranda12 Date: Tue, 25 Aug 2026 15:40:58 -0300 Subject: [PATCH 6/7] refactor: add new style on signup page --- src/pages/SignUp.tsx | 91 +++++++++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 35 deletions(-) diff --git a/src/pages/SignUp.tsx b/src/pages/SignUp.tsx index 67d8eea..0e26107 100644 --- a/src/pages/SignUp.tsx +++ b/src/pages/SignUp.tsx @@ -6,54 +6,75 @@ import { CompanyForm } from '@/components/CompanyForm'; import { StudentForm } from "@/components/StudentForm"; import { useState } from 'react'; import { Link } from 'react-router-dom'; - +import { LuShieldAlert } from "react-icons/lu"; +import { PrimaryButton } from '@/components/ButtonPrimary'; export const SignUpForm = () => { const [isStudent, setIsStudent] = useState(true); return ( -
-
-
- {/* Logo */} -
- Logo Certify -
+
+
+
+ + Já tem conta? Login + +
-

Criar conta

-

Selecione se você é empresa ou aluno

- -
-
- setIsStudent(true)} isActive={isStudent}> - Aluno - -
- -
- setIsStudent(false)} isActive={!isStudent}> - Empresa - -
-
+

+ Criar conta +

- {isStudent ? ( - - ) : ( - - )} +
+ Aluno + Empresa +
-
- Já tem conta? - Faça o login aqui! -
+
+ +
+
+ + +
+

+ Precisa de ajuda? +

+ +

+ Fale com nosso suporte:{" "} + + suporte@certify.com.br + +

+
+ +
-
- Garota com certificado ou empresa + {/* Div da imagem */} +
+ Garota com certificado ou empresa + + Certify
+ ); }; From 2331bf60babf4dba9c96b3a4ee5d3cc886e7034a Mon Sep 17 00:00:00 2001 From: CaioMiranda12 Date: Tue, 25 Aug 2026 15:41:17 -0300 Subject: [PATCH 7/7] feat: add more validations on password of signup schema --- src/schemas/SignUp.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/schemas/SignUp.ts b/src/schemas/SignUp.ts index cab86e6..a519873 100644 --- a/src/schemas/SignUp.ts +++ b/src/schemas/SignUp.ts @@ -27,8 +27,24 @@ export const SignUpStudentSchema = z.object({ }), password: z .string() - .min(8, { message: "A senha deve ter pelo menos 8 caracteres" }) - .max(100, { message: "A senha deve ter no máximo 100 caracteres" }), + .min(8, { + message: "A senha deve ter pelo menos 8 caracteres", + }) + .max(100, { + message: "A senha deve ter no máximo 100 caracteres", + }) + .regex(/\d/, { + message: "A senha deve conter pelo menos 1 número", + }) + .regex(/[A-Z]/, { + message: "A senha deve conter pelo menos 1 letra maiúscula", + }) + .regex(/[a-z]/, { + message: "A senha deve conter pelo menos 1 letra minúscula", + }) + .regex(/[!@#$%^&*(),.?":{}|<>]/, { + message: "A senha deve conter pelo menos 1 caractere especial", + }), confirmPassword: z .string() .min(8, { message: "Confirme sua senha" }),