diff --git a/src/App.tsx b/src/App.tsx index 7b60766..ee3dfae 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -19,7 +19,8 @@ import Perfil from './pages/Perfil'; import PerfilEditar from './pages/PerfilEditar'; import CadastroVan from './pages/CadastroVan'; import CadastroCompletar from './pages/CadastroCompletar/CadastroCompletar'; -import CompletarDocumentos from './pages/CadastroCompletar/CompletarDocumentos'; +import CompletarDocumento from './pages/CadastroCompletar/CompletarDocumento'; +import CompletarTelefone from './pages/CadastroCompletar/CompletarTelefone'; /* Core CSS required for Ionic components to work properly */ import '@ionic/react/css/core.css'; @@ -55,7 +56,8 @@ const routes = ( - + + diff --git a/src/pages/CadastroCompletar/CadastroCompletar.tsx b/src/pages/CadastroCompletar/CadastroCompletar.tsx index 234aa19..09e4c73 100644 --- a/src/pages/CadastroCompletar/CadastroCompletar.tsx +++ b/src/pages/CadastroCompletar/CadastroCompletar.tsx @@ -12,13 +12,11 @@ IonPage, IonTitle, IonToolbar } from "@ionic/react"; -import React, { useEffect, useReducer, useState } from "react"; +import React, { useEffect, useReducer } from "react"; import '../Perfil.css' import { useHistory, useLocation } from "react-router"; -import { bookOutline, callOutline, documentTextOutline, homeOutline } from "ionicons/icons"; - -import * as usersRoutes from '../../services/api/users'; +import { callOutline, documentTextOutline } from "ionicons/icons"; import '../Cadastro/Cadastro.css' @@ -26,93 +24,60 @@ interface userData { name: string; lastname: string; email: string; + phone_number: string; birth_date: string; bio: string; + document_type: string; + document: string; } interface LocationState { userData: userData } -const items = [ - // TODO, CPF e CNH +interface cardItem { + icon: string; + label: string; + description: string; + url: string; + required: boolean; +} + +let items: cardItem[] = [ { icon: documentTextOutline, - label: 'Documentos', - description: 'Cadastre seus documentos para que seu perfil possa ser verificado.' + label: 'Documento', + description: 'Cadastre seu documento para que seu perfil possa ser verificado', + url: '/perfil/completar/documento', + required: false }, - // TODO, telefone e WhatsApp { icon: callOutline, label: 'Informações de contato', - description: 'Cadastre seu número de telefone celular que para possam contatar você.' - }, - { - icon: homeOutline, - label: 'Endereço de residência', - description: 'Diga-nos seu endereço para que possa começar a solicitar vagas.' - }, - { - icon: bookOutline, - label: 'Instituição de ensino', - description: 'Diga-nos sua IES para que possa começar a solicitar vagas.' - }, + description: 'Cadastre seu número de telefone celular que para possam contatar você', + url: '/perfil/completar/telefone', + required: false + } ] const CadastroCompletar: React.FC = () => { const history = useHistory(); const location = useLocation(); - const [showToast, setShowToast] = useState(false); - const [messageToast, setMessageToast] = useState(''); + const handleCardClick = (item: cardItem) => { + if (!item.required) return - const [userData, setUserData] = useState({ - name: '', - lastname: '', - email: '', - birth_date: '', - bio: '', - }); - - const [inputValues, setInputValues] = useReducer( - (state: any, newState: any) => ({ ...state, ...newState }), - { - name: '', - lastname: '', - email: '', - birth_date: '', - bio: '', - } - ); + history.push({ pathname: item.url }); + } useEffect(() => { - let userData = location.state.userData + if (!location.state) { + history.push({ pathname: '/perfil' }) + } - setUserData(location.state.userData) - setInputValues({ - 'name': userData.name, - 'lastname': userData.lastname, - 'email': userData.email, - 'birth_date': userData.birth_date, - 'bio': userData.bio - }); - }, [userData]); - - const handleUpdateUserData = () => { - usersRoutes.update(inputValues).then(response => { - if (response.status === 'error') { - setMessageToast(response.message); - setShowToast(true); - - return - } - - console.log(response) - }).catch((err) => { - setMessageToast(err); - setShowToast(true); - }) - } + if (!location.state.userData.document) items[0].required = true + if (!location.state.userData.phone_number) items[1].required = true + }, []); return ( @@ -128,7 +93,7 @@ const CadastroCompletar: React.FC = () => { { items.map((item, index) => { return ( - + { handleCardClick(item) }}> {item.label} diff --git a/src/pages/CadastroCompletar/CompletarDocumento.tsx b/src/pages/CadastroCompletar/CompletarDocumento.tsx new file mode 100644 index 0000000..d1c7147 --- /dev/null +++ b/src/pages/CadastroCompletar/CompletarDocumento.tsx @@ -0,0 +1,193 @@ +import { + IonBackButton, + IonButtons, + IonContent, + IonFab, + IonFabButton, + IonHeader, + IonIcon, + IonList, + IonPage, + IonSelect, + IonSelectOption, + IonTitle, + IonToast, + IonToolbar +} from "@ionic/react"; +import React, { useEffect, useState } from "react"; +import { IonGrid, IonRow, IonCol } from "@ionic/react"; +import { useHistory, useLocation } from "react-router-dom"; +import { + IonItem, + IonLabel, + IonInput, +} from "@ionic/react"; + +import { saveOutline } from "ionicons/icons"; + +import * as usersRoutes from '../../services/api/users'; + +import validateCpf from '../../services/validateCpf' + +interface documentTypesInterface { + label: string; + name: string; +} + +const CompletarDocumento: React.FC = () => { + const [hasChangedSinceInitialState, setHasChangedSinceInitialState] = useState(false); + + const [documentTypes, setDocumentTypes] = useState([]); + + const [document, setDocument] = useState(''); + const [documentType, setDocumentType] = useState(''); + + const [documentMaxLength, setDocumentMaxLength] = useState(0); + + const [showToast, setShowToast] = useState(false); + const [messageToast, setMessageToast] = useState(''); + + const history = useHistory(); + const location = useLocation(); + + useEffect(() => { + if (!location.state) { + history.push({ pathname: '/perfil/completar' }) + } + }, []) + + const validateform = () => { + console.log(document) + if (isNaN((Number)(document))) { + setMessageToast('Documento pode conter apenas números!') + setShowToast(true) + return false + } + + if (documentType === 'cpf' && !validateCpf(document)) { + setMessageToast('CPF inválido!') + setShowToast(true) + return false + } + + return true + } + + const handleUpdateUserDocuments = async () => { + if (!validateform()) { + return + } + + usersRoutes.update({ document_type: documentType, document: document }).then(response => { + if (response.status === 'error') { + setMessageToast(response.message); + setShowToast(true); + + return + } + + console.log(response) + }).catch((err) => { + setMessageToast(err); + setShowToast(true); + }) + }; + + const handleChangeDocumentType = (document_type: string) => { + switch(document_type) { + case 'cpf': + setDocumentType('cpf') // workaround para o problema de setState para valores vindos de um evento sendo triggerado por um ion-select + setDocumentMaxLength(11) + break; + case 'cnh': + setDocumentType('cnh') // workaround para o problema de setState para valores vindos de um evento sendo triggerado por um ion-select + setDocumentMaxLength(11) + break; + case 'rg': + setDocumentType('rg') // workaround para o problema de setState para valores vindos de um evento sendo triggerado por um ion-select + setDocumentMaxLength(9) + break; + } + } + + useEffect(() => { + setDocumentTypes([ + { + name: 'cpf', + label: 'CPF', + }, + { + name: 'rg', + label: 'RG', + }, + { + name: 'cnh', + label: 'CNH', + }, + ]) + }, []) + + return ( + + + + Completar cadastro + + + + + + + + + + Completar cadastro + + + + + + + + + Tipo de documento + { handleChangeDocumentType(e.detail.value) } }> + { documentTypes ? documentTypes.map((document, index) => { + return ({document.label}) + }) : <> } + + + + Documento + { setDocument(e.target.value); setHasChangedSinceInitialState(true) }} + > + + + + + + + + + + + + + setShowToast(false)} + message={messageToast} + duration={2500} + /> + + + ); +}; + +export default CompletarDocumento; + \ No newline at end of file diff --git a/src/pages/CadastroCompletar/CompletarTelefone.tsx b/src/pages/CadastroCompletar/CompletarTelefone.tsx new file mode 100644 index 0000000..6bccd65 --- /dev/null +++ b/src/pages/CadastroCompletar/CompletarTelefone.tsx @@ -0,0 +1,137 @@ +import { + IonBackButton, + IonButtons, + IonContent, + IonFab, + IonFabButton, + IonHeader, + IonIcon, + IonList, + IonPage, + IonSelect, + IonSelectOption, + IonTitle, + IonToast, + IonToolbar +} from "@ionic/react"; +import React, { useEffect, useState } from "react"; +import { IonGrid, IonRow, IonCol } from "@ionic/react"; +import { useHistory, useLocation } from "react-router-dom"; +import { + IonItem, + IonLabel, + IonInput, +} from "@ionic/react"; + +import { saveOutline } from "ionicons/icons"; + +import * as usersRoutes from '../../services/api/users'; + +interface documentTypesInterface { + label: string; + name: string; +} + +const CompletarTelefone: React.FC = () => { + const [hasChangedSinceInitialState, setHasChangedSinceInitialState] = useState(false); + + const [phone, setPhone] = useState(''); + + const [showToast, setShowToast] = useState(false); + const [messageToast, setMessageToast] = useState(''); + + const history = useHistory(); + const location = useLocation(); + + useEffect(() => { + if (!location.state) { + history.push({ pathname: '/perfil/completar' }) + } + }, []) + + const validateform = () => { + if (isNaN((Number)(phone))) { + setMessageToast('O telefone pode conter apenas números!') + setShowToast(true) + return false + } + + return true + } + + const handleUpdateUserDocuments = async () => { + if (!validateform()) { + return + } + + usersRoutes.update({ phone_number: phone }).then(response => { + if (response.status === 'error') { + setMessageToast(response.message); + setShowToast(true); + + return + } + + console.log(response) + }).catch((err) => { + setMessageToast(err); + setShowToast(true); + }) + }; + + return ( + + + + Completar cadastro + + + + + + + + + + Completar cadastro + + + + + + + + + Telefone + { setPhone(e.target.value); setHasChangedSinceInitialState(true) }} + > + + + + + + + + + + + + + setShowToast(false)} + message={messageToast} + duration={2500} + /> + + + ); +}; + +export default CompletarTelefone; + \ No newline at end of file diff --git a/src/pages/CadastroVan.tsx b/src/pages/CadastroVan.tsx index 5218d7c..7b592d3 100644 --- a/src/pages/CadastroVan.tsx +++ b/src/pages/CadastroVan.tsx @@ -231,9 +231,10 @@ const CadastroVan: React.FC = () => { /> + {/* TODO, problema de setState para valores vindos de um evento sendo triggerado por um ion-select */} Marca - setInputValues({ carBrand: e.target.value })}> + { setInputValues({ carBrand: e.detail.value }) }}> { carModels ? carModels.map((carModel, index) => { return ({carModel.name}) }) : <> } diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index b8b835c..c3d74d6 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -38,7 +38,7 @@ const Home: React.FC = () => { return ( - { history.push({ pathname: '/usuario/56520ae7-faf8-4444-a82b-7f3990ab02d8' }); }}>Ir para o perfil de outra pessoa + {/* { history.push({ pathname: '/usuario/56520ae7-faf8-4444-a82b-7f3990ab02d8' }); }}>Ir para o perfil de outra pessoa */} ); diff --git a/src/pages/Perfil.tsx b/src/pages/Perfil.tsx index ea2dcfd..cb4d126 100644 --- a/src/pages/Perfil.tsx +++ b/src/pages/Perfil.tsx @@ -42,27 +42,23 @@ const Perfil: React.FC = (props) => { const [isVisitor, setIsVisitor] = useState(true) + const [incompleteProfile, setIncompleteProfile] = useState(false) + const [showToast, setShowToast] = useState(false); const [messageToast, setMessageToast] = useState(''); const [inputValues, setInputValues] = useReducer( (state: any, newState: any) => ({ ...state, ...newState }), { + id: '', name: '', lastname: '', email: '', + phone_number: '', birth_date: '', bio: '', - } - ); - - const [inputSocialInformationValues, setInputSocialInformationValues] = useReducer( - (state: any, newState: any) => ({ ...state, ...newState }), - { - phone: '', - whatsapp: '', - facebook: '', - telegram: '', + document_type: '', + document: '', } ); @@ -122,44 +118,24 @@ const Perfil: React.FC = (props) => { if (isMounted) { setInputValues({ + 'id': userId, 'name': userData.name, 'lastname': userData.lastname, 'email': userData.email, + 'phone_number': userData.phone_number, 'birth_date': userData.birth_date, - 'bio': userData.bio + 'bio': userData.bio, + 'document_type': userData.document_type, + 'document': userData.document }); if (!props.match.params.id) { setIsVisitor(false) } - } - } - // get user social info - const getUserSocialInfoRes = await usersService.getUserSocialInfo(userId) - - if (getUserSocialInfoRes.error) { - if (isVisitor && props.match.params.id) { - setMessageToast('Usuário não existe!') - setShowToast(true) - history.push({ pathname: '/home' }) - } else { - setMessageToast(getUserSocialInfoRes.error.errorMessage) - setShowToast(true) - } - - return - } - - if (getUserSocialInfoRes.data) { - const userSocialData = getUserSocialInfoRes.data - - if (isMounted) { - setInputSocialInformationValues({ - 'phone': userSocialData.phone, - 'whatsapp': userSocialData.whatsapp, - 'facebook': userSocialData.facebook, - 'telegram': userSocialData.telegram, - }); + + if (!userData.document || !userData.phone_number) { + setIncompleteProfile(true) + } } } } @@ -226,42 +202,15 @@ const Perfil: React.FC = (props) => { Informações de contato - { !inputSocialInformationValues.phone && !inputSocialInformationValues.whatsapp && !inputSocialInformationValues.facebook && !inputSocialInformationValues.telegram ? + { !inputValues.phone_number ? <>Sem informações de contato. : <> { - inputSocialInformationValues.phone ? + inputValues.phone_number ? <> - {inputSocialInformationValues.phone} - - : <> - } - - { inputSocialInformationValues.whatsapp ? - <> - - - {inputSocialInformationValues.whatsapp} - - : <> - } - - { inputSocialInformationValues.facebook ? - <> - - - {inputSocialInformationValues.facebook} - - : <> - } - - { inputSocialInformationValues.telegram ? - <> - - - {inputSocialInformationValues.telegram} + {inputValues.phone_number} : <> } @@ -277,10 +226,16 @@ const Perfil: React.FC = (props) => { Editar perfil - history.push({ pathname: '/perfil/completar', state: { userData: inputValues } })}> - - Completar cadastro - + + { incompleteProfile ? + <> + history.push({ pathname: '/perfil/completar', state: { userData: inputValues } })}> + + Completar cadastro + + + : <> } + history.push({ pathname: '/cadastro-van'})}> Cadastrar Van diff --git a/src/pages/PerfilEditar.tsx b/src/pages/PerfilEditar.tsx index e7c8d1f..47271f0 100644 --- a/src/pages/PerfilEditar.tsx +++ b/src/pages/PerfilEditar.tsx @@ -68,6 +68,10 @@ const PerfilEditar: React.FC = () => { ); useEffect(() => { + if (!location.state) { + history.push({ pathname: '/perfil' }) + } + let userData = location.state.userData setUserData(location.state.userData) diff --git a/src/services/api/users.ts b/src/services/api/users.ts index be989af..d2d16e4 100644 --- a/src/services/api/users.ts +++ b/src/services/api/users.ts @@ -40,8 +40,9 @@ export interface UpdateUserRequest { name?: string; email?: string; bio?: string; - cpf?: string; - cnpj?: string; + document_type?: string; + document?: string; + phone_number?: string; } // export async function get(cpf) { diff --git a/src/services/functions/usersService.ts b/src/services/functions/usersService.ts index b0d6ae1..34b25be 100644 --- a/src/services/functions/usersService.ts +++ b/src/services/functions/usersService.ts @@ -5,10 +5,11 @@ interface getByIdReturn { name: string; lastname: string; email: string; + phone_number: string; birth_date: string; bio: string; - cpf: string; - cnpj: string; + document_type: string; + document: string; }, error?: { errorMessage: string; @@ -23,10 +24,11 @@ interface getByIdRes { name: string; lastname: string; email: string; + phone_number: string; birth_date: string; bio: string; - cpf: string; - cnpj: string; + document_type: string; + document: string; }, }