Merge
This commit is contained in:
12
mock/db.json
Normal file
12
mock/db.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"cadastro-van": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"placa": "DBE2356",
|
||||||
|
"marca": "Fiat",
|
||||||
|
"modelo": "Ducatto",
|
||||||
|
"numPassageiros": 14,
|
||||||
|
"alugado": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
29
package-lock.json
generated
29
package-lock.json
generated
@@ -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",
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
8
src/models/van.model.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export type Van = {
|
||||||
|
id: number;
|
||||||
|
carPlate: string;
|
||||||
|
carBrand: string;
|
||||||
|
carModel: string;
|
||||||
|
maxPassengers: number;
|
||||||
|
isRent: string;
|
||||||
|
};
|
||||||
0
src/pages/CadastroVan.css
Normal file
0
src/pages/CadastroVan.css
Normal file
347
src/pages/CadastroVan.tsx
Normal file
347
src/pages/CadastroVan.tsx
Normal 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;
|
||||||
18
src/services/api-client.service.ts
Normal file
18
src/services/api-client.service.ts
Normal 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);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user