This commit is contained in:
Matheus Albino Brunhara
2022-05-28 12:54:11 -05:00
8 changed files with 418 additions and 1 deletions

12
mock/db.json Normal file
View File

@@ -0,0 +1,12 @@
{
"cadastro-van": [
{
"id": 1,
"placa": "DBE2356",
"marca": "Fiat",
"modelo": "Ducatto",
"numPassageiros": 14,
"alugado": false
}
]
}

29
package-lock.json generated
View File

@@ -13336,6 +13336,21 @@
"react": "^16.8.0 || ^17 || ^18" "react": "^16.8.0 || ^17 || ^18"
} }
}, },
"node_modules/react-hook-form": {
"version": "7.30.0",
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.30.0.tgz",
"integrity": "sha512-DzjiM6o2vtDGNMB9I4yCqW8J21P314SboNG1O0obROkbg7KVS0I7bMtwSdKyapnCPjHgnxc3L7E5PEdISeEUcQ==",
"engines": {
"node": ">=12.22.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/react-hook-form"
},
"peerDependencies": {
"react": "^16.8.0 || ^17 || ^18"
}
},
"node_modules/react-is": { "node_modules/react-is": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -20219,6 +20234,14 @@
"follow-redirects": "^1.14.8" "follow-redirects": "^1.14.8"
} }
}, },
"axios": {
"version": "0.26.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
"requires": {
"follow-redirects": "^1.14.8"
}
},
"axobject-query": { "axobject-query": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
@@ -26462,6 +26485,12 @@
"integrity": "sha512-DzjiM6o2vtDGNMB9I4yCqW8J21P314SboNG1O0obROkbg7KVS0I7bMtwSdKyapnCPjHgnxc3L7E5PEdISeEUcQ==", "integrity": "sha512-DzjiM6o2vtDGNMB9I4yCqW8J21P314SboNG1O0obROkbg7KVS0I7bMtwSdKyapnCPjHgnxc3L7E5PEdISeEUcQ==",
"requires": {} "requires": {}
}, },
"react-hook-form": {
"version": "7.30.0",
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.30.0.tgz",
"integrity": "sha512-DzjiM6o2vtDGNMB9I4yCqW8J21P314SboNG1O0obROkbg7KVS0I7bMtwSdKyapnCPjHgnxc3L7E5PEdISeEUcQ==",
"requires": {}
},
"react-is": { "react-is": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",

View File

@@ -45,6 +45,7 @@
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",
"start:mock": "json-server --port 8080 --watch ./mock/db.json",
"build": "react-scripts build", "build": "react-scripts build",
"test": "react-scripts test --transformIgnorePatterns 'node_modules/(?!(@ionic/react|@ionic/react-router|@ionic/core|@stencil/core|ionicons)/)'", "test": "react-scripts test --transformIgnorePatterns 'node_modules/(?!(@ionic/react|@ionic/react-router|@ionic/core|@stencil/core|ionicons)/)'",
"eject": "react-scripts eject" "eject": "react-scripts eject"

View File

@@ -10,10 +10,11 @@ import {
setupIonicReact setupIonicReact
} from '@ionic/react'; } from '@ionic/react';
import { IonReactRouter } from '@ionic/react-router'; import { IonReactRouter } from '@ionic/react-router';
import Cadastro from './pages/Cadastro/Cadastro';
// importação das páginas // importação das páginas
import Login from './pages/Login'; import Login from './pages/Login';
import Cadastro from './pages/Cadastro/Cadastro';
import CadastroVan from './pages/CadastroVan';
/* Core CSS required for Ionic components to work properly */ /* Core CSS required for Ionic components to work properly */
import '@ionic/react/css/core.css'; import '@ionic/react/css/core.css';
@@ -49,6 +50,7 @@ const routes = (
<Route exact path="/login" component={Login}></Route> <Route exact path="/login" component={Login}></Route>
<Route exact path="/perfil" component={Perfil}></Route> <Route exact path="/perfil" component={Perfil}></Route>
<Route exact path="/perfil/editar" component={PerfilEditar}></Route> <Route exact path="/perfil/editar" component={PerfilEditar}></Route>
<Route exact path="/cadastro-van" component={CadastroVan}></Route>
<Route exact path="/"> <Route exact path="/">
<Redirect to="/cadastro" /> <Redirect to="/cadastro" />
</Route> </Route>

8
src/models/van.model.ts Normal file
View File

@@ -0,0 +1,8 @@
export type Van = {
id: number;
carPlate: string;
carBrand: string;
carModel: string;
maxPassengers: number;
isRent: string;
};

View File

347
src/pages/CadastroVan.tsx Normal file
View File

@@ -0,0 +1,347 @@
import {
IonToast,
IonItem,
IonLabel,
IonInput,
IonBackButton,
IonButton,
IonButtons,
IonCardTitle,
IonContent,
IonHeader,
IonPage,
IonToolbar,
IonTitle,
IonText,
IonRadioGroup,
IonRadio
} from "@ionic/react";
import React, { useState } from "react";
import { ApiClient } from "../services/api-client.service";
import { arrowBack } from "ionicons/icons";
import "./CadastroVan.css";
const CadastroVan: React.FC = () => {
const [showToast, setShowToast] = useState<boolean>(false);
const [toastMessage, setToastMessage] = useState<string>("");
const [carPlate, setCarPlate] = useState<string>("");
const [carBrand, setCarBrand] = useState<string>("");
const [carModel, setCarModel] = useState<string>("");
const [maxPassengers, setMaxPassengers] = useState<number>(1);
const [isRent, setIsRent] = useState<boolean>(false);
const [carRentalName, setCarRentalName] = useState<string>("");
const [postalCode, setPostalCode] = useState<string>("");
const [street, setStreet] = useState<string>("");
const [number, setNumber] = useState<string>("");
const [complement, setComplement] = useState<string>("");
const [city, setCity] = useState<string>("");
const [state, setState] = useState<string>("");
const vanForm = {
carPlate,
carBrand,
carModel,
maxPassengers,
isRent,
carRentalName,
carRentalAddress: {
postalCode,
street,
number,
complement,
city,
state
}
};
const clearRentalData = () => {
setCarRentalName("");
setPostalCode("");
setStreet("");
setNumber("");
setComplement("");
setCity("");
setState("");
};
const validateForm = (): boolean => {
if (
!vanForm.carPlate ||
vanForm.carPlate.length !== 7 ||
!vanForm.carPlate.match(/([A-z0-9]){7}/g)
) {
setToastMessage("Placa do veículo inválida!");
setShowToast(true);
return false;
}
if (!vanForm.carBrand) {
setToastMessage("Marca do veículo é obrigatório");
setShowToast(true);
return false;
}
if (!vanForm.carModel) {
setToastMessage("Modelo do veículo é obrigatório");
setShowToast(true);
return false;
}
if (!vanForm.maxPassengers || !parseInt(`${vanForm.maxPassengers}`)) {
setToastMessage("Número de passageiros inválido");
setShowToast(true);
return false;
}
if (vanForm.isRent) {
return validateRentalForm();
} else {
clearRentalData();
}
return true;
};
const validateRentalForm = (): boolean => {
if (!vanForm.carRentalName) {
setToastMessage("Nome do Locador é obrigatório");
setShowToast(true);
return false;
}
if (
!vanForm.carRentalAddress.postalCode ||
vanForm.carRentalAddress.postalCode.length !== 8 ||
!vanForm.carRentalAddress.postalCode.match(/([0-9]){8}/g)
) {
setToastMessage("Cep inválido");
setShowToast(true);
return false;
}
if (
!vanForm.carRentalAddress.number ||
!parseInt(`${vanForm.carRentalAddress.number}`)
) {
setToastMessage("Número inválido");
setShowToast(true);
return false;
}
if (
!vanForm.carRentalAddress.city ||
!vanForm.carRentalAddress.city.match(/([A-zà-úÀ-Ú])/g)
) {
setToastMessage("Cidade inválido");
setShowToast(true);
return false;
}
if (
!vanForm.carRentalAddress.state ||
!vanForm.carRentalAddress.state.match(/([A-zà-úÀ-Ú])/g)
) {
setToastMessage("Estado inválido");
setShowToast(true);
return false;
}
return true;
};
const handleSubmit = async () => {
if (validateForm()) {
await ApiClient.doPost("/cadastro-van", vanForm);
}
};
return (
<IonPage>
<IonHeader>
<IonToolbar color='primary'>
<IonTitle>VanMos App v1.0</IonTitle>
<IonButtons slot='start'>
<IonBackButton icon={arrowBack} defaultHref='cadastro-van'>
Return
</IonBackButton>
</IonButtons>
</IonToolbar>
</IonHeader>
<IonContent className='ion-padding'>
<form className='ion-padding'>
<IonCardTitle>Cadastro do Veículo</IonCardTitle>
<IonItem>
<IonLabel position='floating'>Placa *</IonLabel>
<IonInput
type='text'
clearInput
placeholder='Digite a Placa do Veículo'
onIonInput={(e: any) => setCarPlate(e.target.value)}
/>
</IonItem>
<IonItem>
<IonLabel position='floating'>Marca *</IonLabel>
<IonInput
type='text'
clearInput
placeholder='Digite a Marca do Veículo'
onIonInput={(e: any) => setCarBrand(e.target.value)}
/>
</IonItem>
<IonItem>
<IonLabel position='floating'>Modelo *</IonLabel>
<IonInput
type='text'
clearInput
placeholder='Digite o Modelo do Veículo'
onIonInput={(e: any) => setCarModel(e.target.value)}
/>
</IonItem>
<IonItem>
<IonLabel position='floating'>
Número Máximo de Passageiros *
</IonLabel>
<IonInput
type='text'
clearInput
placeholder='Digite o número máximo de passageiros'
onIonInput={(e: any) => setMaxPassengers(e.target.value)}
/>
</IonItem>
<IonItem>
<IonText>
<div style={{ padding: 8, paddingLeft: 0, fontWeight: "bold" }}>
Veículo alugado?
</div>
<div>
<IonRadioGroup
style={{ display: "flex", width: "100%" }}
onIonChange={(e: any) => setIsRent(e.target.value)}
>
<IonItem lines='none' style={{ flexGrow: 2 }}>
<IonLabel position='fixed'>Sim</IonLabel>
<IonRadio value={true} />
</IonItem>
<IonItem style={{ flexGrow: 2 }} lines='none'>
<IonLabel position='fixed'>Não</IonLabel>
<IonRadio value={false} />
</IonItem>
</IonRadioGroup>
</div>
</IonText>
</IonItem>
{isRent && (
<div>
<IonItem>
<IonLabel position='floating'>Nome do Locador *</IonLabel>
<IonInput
type='text'
clearInput
placeholder='Digite o nome do locador do veículo'
onIonInput={(e: any) => setCarRentalName(e.target.value)}
/>
</IonItem>
<IonText>
<div
style={{ padding: 8, paddingLeft: 16, fontWeight: "bold" }}
>
Endereço do Locador
</div>
<IonItem>
<IonLabel position='floating'>CEP*</IonLabel>
<IonInput
type='text'
clearInput
placeholder='Digite o endereço completo do locador do veículo'
onIonInput={(e: any) => setPostalCode(e.target.value)}
/>
</IonItem>
<IonItem>
<IonLabel position='floating'>Logradouro*</IonLabel>
<IonInput
type='text'
clearInput
placeholder='Digite o nome da rua'
onIonInput={(e: any) => setStreet(e.target.value)}
/>
</IonItem>
<IonItem>
<IonLabel position='floating'>Número*</IonLabel>
<IonInput
type='text'
clearInput
placeholder='Digite o número'
onIonInput={(e: any) => setNumber(e.target.value)}
/>
</IonItem>
<IonItem>
<IonLabel position='floating'>Complemento*</IonLabel>
<IonInput
type='text'
clearInput
placeholder='Digite o endereço completo'
onIonInput={(e: any) => setComplement(e.target.value)}
/>
</IonItem>
<IonItem>
<IonLabel position='floating'>Cidade*</IonLabel>
<IonInput
type='text'
clearInput
placeholder='Digite a cidade'
onIonInput={(e: any) => setCity(e.target.value)}
/>
</IonItem>
<IonItem>
<IonLabel position='floating'>Estado*</IonLabel>
<IonInput
type='text'
clearInput
placeholder='Digite o estado'
onIonInput={(e: any) => setState(e.target.value)}
/>
</IonItem>
</IonText>
</div>
)}
<div>
<IonButton
className='ion-margin-top'
expand='block'
onClick={handleSubmit}
>
Salvar
</IonButton>
</div>
</form>
<IonToast
color='danger'
isOpen={showToast}
onDidDismiss={() => setShowToast(false)}
message={toastMessage}
duration={2500}
/>
</IonContent>
</IonPage>
);
};
export default CadastroVan;

View File

@@ -0,0 +1,18 @@
import axios from "axios";
export class ApiClient{
private static api = axios.create({
baseURL: "http://localhost:8080"
});
public static async doPost (url: string, body: any): Promise<any> {
return await this.api
.post(url, body)
.then(res => {
console.log(res.data);
})
.catch(error => {
console.log(error);
});
};
}