Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Signup Form #266

Open
wants to merge 90 commits into
base: dev
Choose a base branch
from

Conversation

vitormarkis
Copy link
Contributor

Overview

Não excluí codigo da implementação passada, todo o código que eu criei para o formulário está dentro do diretório src/SIGNUP para facilitar o review, quando a PR for aprovada, eu posso mover os arquivos para seus devidos lugares, e dar merge.

Feat: Agora a escolha de ser mentor ou mentorado e o formulário de signup ficam na mesma página /register.

Feat: Criei um contexto provendo qual step o usuário está (0-1-2) no momento, poderia ter usado o próprio contexto do React Hook Form mas não me pareceu semântico.

No component/page RegisterPage, eu renderizei o grupo de inputs de cada etapa do formulario com base no formCurrentStep que vem do contexto que citei acima.

<div className="mb-3">
  {formCurrentStep === 0 && <Personal />}
  {formCurrentStep === 1 && (
    <Location
      cityFactory={City}
      countryFactory={Country}
      skillsFactory={Skills}
      stateFactory={State}
    />
  )}
  {formCurrentStep === 2 && <Professional />}
</div>

Por conta dos elementos estarem sendos montados e remontados, eu tive que instanciar as factories de cada input fora do componente do step, e passar ele como props (Componente <Location /> por exemplo) caso contrário seus states e dependências ficariam sendo resetadas ao navegar pelos steps, por estarem sendo remontados.

Validação

Para fazer a validação de cada step, eu fiz eles de forma manual através da função trigger() do useForm.

Eu criei um objeto armazenando arrays com os campos que estão sendos validados em cada step.
Para validar os campos do step atual, eu iterei sobre o array do step atual, dando trigger em cada campo.

export const validationPerStep: Record<number, (keyof IFormValues)[]> = {
  0: [
    "firstName",
    "lastName",
    "email",
    "password",
    "repeatPassword",
    "isTermsAccepted",
  ],
  1: ["country", "state", "city", "birthDate", "skills"],
  2: ["linkedin", "github", "description"],
};

// ...

const handleActionButton = async () => {
  const allStepValidations = validationPerStep[formCurrentStep].map(field =>
    trigger(field)
  );
  const allStepValidationsResult = await Promise.all(allStepValidations);
  const allValidationsPassed = allStepValidationsResult.every(Boolean);
  if (allValidationsPassed)
    return setFormCurrentStep(currentStep => currentStep + 1);
};

Quando usuário não está no último step, renderiza botão Próximo que chama essa função handleActionButton
Quando usuário está no último step, renderiza botão Enviar que é do type "submit" e ativa o submit do form.

Checar

O resultado desse submit está sendo logado no console atualmente, para facilitar o review, ao aprovar a PR, vou integrar ele com a API.

Checar validações, se aprovado, vou passar para o time de UX, criar os textos de validação e placeholder de forma mais trabalhada.

Na página RegisterPage, eu coloquei um elemento a mais, de escolher entre mentor e mentorado, que permanece durante todo fluxo de signup, você pode encontrar buscando pelo elemento TextToggle.

Em alguns elementos precisei colocar cores no style em vez da classe por causa da sobreposição do CSS.

Todas as validações dos campos estão em: src/SIGNUP_SRC/forms/signup/validations.

Notas

Como eu custumo criar meus componentes, as classes, estilos e atributos mecânicos do componente, ficam dentro do componente, e as classes, estilos e atributos de estilização são passados na hora de usar o elemento, fica mais fácil de dar manutenção, todo a estilização fica no mesmo arquivo.

Feat: Eu abstraí a lógica de cada input mais complexo, e joguei dentro do seu factory, onde você passa as dependências necessárias, e ele retorna os métodos e propriedades que serão úteis para compor o formulário.

Você pode checar isso que eu falei na página RegisterPage onde eu instancio as factories do input Country, State, City e Skills.

// src/components/_Layout/RegisterPage.tsx
const Country = useCountriesFactory(methods);
const State = useStatesFactory(methods, geoStatesOptions);
const City = useCitiesFactory(methods, geoCitiesOptions);
const Skills = useSkillsFactory(methods);

Dessa forma consigo abstrair blocos de códigos repetidos e que deixariam o corpo do componente muito verboso, e crio uma interface mais fácil de se trabalhar, debugar, e extender.

// src/SIGNUP_SRC/steps/Location.tsx
<Controller
  name="country"
  control={control}
  render={({ field }) => (
    <Input.Select
      id={Country.inputId}
      field={field}
      isLoading={Country.isLoading}
      options={Country.options ?? null}
      noOptionsMessage="Nenhum país encontrado."
      placeholder="Selecione um país"
      defaultValue="Brasil"
      tabIndex={20}
    />
  )}
/>
// ...

No arquivo SIGNUP_SRC/types/units/useGeo.ts ta a tipagem de todos os métodos genéricos, e podem ser importados para compor o retorno de uma factory.

// SIGNUP_SRC/steps/factories/useStatesFactory/types.ts
import {
  InputId,
  Errors,
  SelectOptions,
  GetFieldController,
} from "SIGNUP_SRC/types/units/useGeo";

export type StatesFactoryMethods = Pretify<
  InputId & Errors & SelectOptions & GetFieldController & CustomMethods
>;

type CustomMethods = {
  userAlreadyChooseState: boolean;
};

Propostas

  • Diretório para providers personalizados a nível rota em vez de toda aplicação. Ex: src/providers/signup/register/index.tsx.

  • Diretório para forms, toda vez que tiver um form, colocar todos os arquivos relacionados apenas desse form, nesse diretório src/forms/NOME_DO_FORMULARIO/*.
    Ex: SIGNUP_SRC/forms/signup/*

@vitormarkis vitormarkis self-assigned this Jul 3, 2023
@vitormarkis vitormarkis added the Sprint 2 - Signup Refatorar o signup e adicionar RHF e zod label Jul 3, 2023
@vitormarkis vitormarkis changed the title Raw refactor signup form Refactor Signup Form Jul 3, 2023
Copy link
Contributor

@oliveirabalsa oliveirabalsa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fala @vitormarkis código ta espetacular, somente alguns pontos de UI que percebi aqui ao clonar.

Posição do Eye-Icon
image

image

Termos de serviço e politica de privacidade sem link de redirecionamento e cursor pointer
image

Texto de descrição dividindo em duas linhas
image

Botões de navegação sem efeitos de hover
Os botões da primeira tela (escolha o modelo de usuário que deseja seguir) ele sim tem uma leve alteração na saturação ao passar o mouse sobre, porém os de navegação não

image

src/SIGNUP_SRC/steps/Personal.tsx Outdated Show resolved Hide resolved
Copy link
Member

@salviotonon salviotonon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Precisamos resolver alguns problemas de conflitos entre o light mode e nossa palleta de cores no global.css

@vitormarkis vitormarkis linked an issue Jul 25, 2023 that may be closed by this pull request
@sonarcloud
Copy link

sonarcloud bot commented Jul 25, 2023

SonarCloud Quality Gate failed.    Quality Gate failed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 12 Code Smells

No Coverage information No Coverage information
5.2% 5.2% Duplication

idea Catch issues before they fail your Quality Gate with our IDE extension sonarlint SonarLint

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Sprint 2 - Signup Refatorar o signup e adicionar RHF e zod
Projects
None yet
3 participants