Compare commits

...

11 Commits

Author SHA1 Message Date
Hugo Falcão
e490f5eaf8 Merge pull request #18 from Hzin/revert-17-feature/VAN-16-view-create-itinerary
Revert "Feature/VAN-16-view-create-itinerary"
2022-09-18 19:26:13 -03:00
Hugo Falcão
1fbe031975 Revert "Feature/VAN-16-view-create-itinerary" 2022-09-18 19:25:57 -03:00
Hugo Falcão
d5b3f8afb8 Merge pull request #17 from Hzin/feature/VAN-16-view-create-itinerary
Feature/VAN-16-view-create-itinerary
2022-09-18 19:25:45 -03:00
Hugo Falcao
62847b012e feat(itineraries): Allows create an itinerary 2022-09-18 19:21:09 -03:00
Hugo Falcao
158c5e67c0 Merge branch 'develop' of https://github.com/CloudAlb/tcc-vamos-frontend into feature/VAN-16-view-create-itinerary 2022-09-14 21:11:08 -03:00
Hugo Falcao
327b1ee492 wip 2022-09-14 20:52:09 -03:00
CloudAlb
3a7ef9d039 Merge pull request #16 from Hzin/bugfix/hot-reload
Bugfix/hot reload
2022-09-13 22:09:11 -03:00
Matheus Albino Brunhara
a2ef184a12 Correção 2022-09-13 22:08:59 -03:00
Matheus Albino Brunhara
fd96166d56 Diversas alterações 2022-09-13 21:59:02 -03:00
Hugo Falcao
3d5aa1e144 fix: 🐛 Fix a bugs of merge with develop 2022-09-11 23:56:20 -03:00
Matheus Albino Brunhara
46768cb941 Refatora página de lista de itinerários da busca 2022-09-09 21:37:18 -03:00
18 changed files with 61871 additions and 1160 deletions

48515
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -9,15 +9,13 @@
"@capacitor/keyboard": "1.2.2", "@capacitor/keyboard": "1.2.2",
"@capacitor/status-bar": "1.0.8", "@capacitor/status-bar": "1.0.8",
"@craco/craco": "^6.4.5", "@craco/craco": "^6.4.5",
"@googlemaps/js-api-loader": "^1.14.3",
"@hookform/error-message": "^2.0.0", "@hookform/error-message": "^2.0.0",
"@ionic-selectable/core": "^5.0.0-alpha.13", "@ionic-selectable/core": "^5.0.0-alpha.13",
"@ionic/react": "^6.2.5", "@ionic/react": "^6.0.0",
"@ionic/react-router": "^6.2.5", "@ionic/react-router": "^6.0.0",
"@testing-library/jest-dom": "^5.11.9", "@testing-library/jest-dom": "^5.11.9",
"@testing-library/react": "^11.2.5", "@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^12.6.3", "@testing-library/user-event": "^12.6.3",
"@types/google.maps": "^3.50.0",
"@types/jest": "^26.0.20", "@types/jest": "^26.0.20",
"@types/node": "^12.19.15", "@types/node": "^12.19.15",
"@types/react": "^18.0.18", "@types/react": "^18.0.18",
@@ -32,6 +30,7 @@
"pullstate": "^1.24.0", "pullstate": "^1.24.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-google-places-autocomplete": "^3.4.0",
"react-hook-form": "^7.30.0", "react-hook-form": "^7.30.0",
"react-router": "^5.2.0", "react-router": "^5.2.0",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",

View File

@@ -1,3 +1,4 @@
import React, { useContext, useState } from "react";
import { import {
IonApp, IonApp,
IonIcon, IonIcon,
@@ -9,7 +10,6 @@ import {
setupIonicReact, setupIonicReact,
} from "@ionic/react"; } from "@ionic/react";
import { IonReactRouter } from "@ionic/react-router"; import { IonReactRouter } from "@ionic/react-router";
import React, { useContext, useState } from "react";
import { Redirect, Route } from "react-router-dom"; import { Redirect, Route } from "react-router-dom";
import { home, person, search } from "ionicons/icons"; import { home, person, search } from "ionicons/icons";
@@ -25,14 +25,14 @@ import Login from "./pages/Login";
import Perfil from "./pages/Perfil"; import Perfil from "./pages/Perfil";
import PerfilEditar from "./pages/PerfilEditar"; import PerfilEditar from "./pages/PerfilEditar";
import VeiculoCadastro from "./pages/VeiculoCadastro";
import MeusVeiculos from "./pages/MeusVeiculos";
import CadastrarItinerario from "./pages/CadastrarItinerario/CadastrarItinerario"; import CadastrarItinerario from "./pages/CadastrarItinerario/CadastrarItinerario";
import MeusItinerarios from "./pages/MeusItinerarios/MeusItinerarios"; import MeusItinerarios from "./pages/MeusItinerarios/MeusItinerarios";
import MeusVeiculos from "./pages/MeusVeiculos";
import VeiculoCadastro from "./pages/VeiculoCadastro";
import Buscas from "./pages/Buscas";
import BuscarItinerario from "./pages/BuscarItinerario"; import BuscarItinerario from "./pages/BuscarItinerario";
import BuscarPassageiro from "./pages/BuscarPassageiro/BuscarPassageiro"; import BuscarPassageiro from "./pages/BuscarPassageiro/BuscarPassageiro";
import Buscas from "./pages/Buscas";
import Transportes from "./pages/Transportes/Transportes"; import Transportes from "./pages/Transportes/Transportes";
/* Core CSS required for Ionic components to work properly */ /* Core CSS required for Ionic components to work properly */

View File

@@ -1,21 +1,24 @@
const tokenId = 'token';
const productDetails = '@productDetails';
const LocalStorage = { const LocalStorage = {
getToken: (): string => { getToken: (): string => {
const tokenId = localStorage.getItem("tokenId"); const tokenId = localStorage.getItem('tokenId')
if (!tokenId) { if (!tokenId) {
return ""; return ''
}
return tokenId
},
setToken: (token: string) => {
localStorage.setItem('tokenId', token)
},
clearToken: () => {
localStorage.removeItem('tokenId')
} }
}
return tokenId; export default LocalStorage
},
setToken: (token: string) => {
localStorage.setItem("tokenId", token);
},
clearToken: () => {
localStorage.removeItem("tokenId");
},
};
export default LocalStorage;

View File

@@ -1,102 +0,0 @@
import { Loader } from "@googlemaps/js-api-loader";
import { InputHTMLAttributes, useEffect, useRef } from "react";
const apiKey = process.env.REACT_APP_KEY_API
? process.env.REACT_APP_KEY_API
: "";
const extractAddress = (place: any) => {
const address = {
formatted_address: "",
lat: 0,
lng: 0,
};
if (place.formatted_address) {
address.formatted_address = place.formatted_address;
}
if (place.geometry && place.geometry.location) {
address.lat = place.geometry.location.lat();
address.lng = place.geometry.location.lng();
}
return address;
};
interface AddressSelected {
formatted_address: string;
lat: number;
lng: number;
}
interface AutoCompleteInputProps extends InputHTMLAttributes<HTMLInputElement> {
onAddressSelected: (address: AddressSelected) => void;
}
function AutoCompleteInput(props: AutoCompleteInputProps) {
const searchInput = useRef(null);
const { onAddressSelected, ...othersProps } = props;
// do something on address change
const onChangeAddress = (autocomplete: any) => {
const place = autocomplete.getPlace();
const extractedAddress = extractAddress(place);
props.onAddressSelected && props.onAddressSelected(extractedAddress);
};
// init autocomplete
const initAutocomplete = () => {
if (!searchInput.current) return;
const autocomplete = new window.google.maps.places.Autocomplete(
searchInput.current
);
autocomplete.setFields(["formatted_address", "geometry"]);
autocomplete.setComponentRestrictions({ country: "br" });
autocomplete.addListener("place_changed", () =>
onChangeAddress(autocomplete)
);
};
// load map script after mounted
useEffect(() => {
const init = async () => {
try {
if (
!window.google ||
!window.google.maps ||
!window.google.maps.places
) {
await new Loader({
apiKey,
version: "weekly",
libraries: ["places"],
language: "pt-BR",
}).load();
}
initAutocomplete();
} catch (error) {
console.log(error);
}
};
if (apiKey) init();
}, []);
return (
<input
ref={searchInput}
type="text"
{...othersProps}
style={{
textIndent: "0.5rem",
width: "100%",
height: "2.5rem",
borderRadius: "0.25rem",
}}
/>
);
}
export default AutoCompleteInput;

View File

@@ -4,9 +4,15 @@ import {
IonCardSubtitle, IonCardSubtitle,
IonCol, IonCol,
IonIcon, IonIcon,
IonNote,
IonRow, IonRow,
} from "@ionic/react"; } from "@ionic/react";
import { call, callOutline, navigateOutline } from "ionicons/icons"; import {
arrowForward,
call,
callOutline,
navigateOutline,
} from "ionicons/icons";
import "./UserSearchInfos.css"; import "./UserSearchInfos.css";
export const UserSearchInfos = (record: any) => { export const UserSearchInfos = (record: any) => {
@@ -22,7 +28,7 @@ export const UserSearchInfos = (record: any) => {
</IonBadge> </IonBadge>
<p> <p>
<IonIcon icon={navigateOutline} size="large" /> <IonIcon icon={navigateOutline} size='large' />
&nbsp;{record.record.address_to} &nbsp;{record.record.address_to}
</p> </p>

View File

@@ -1,16 +1,22 @@
import { import {
IonBackButton,
IonButton, IonButton,
IonButtons,
IonCard, IonCard,
IonCardContent, IonCardContent,
IonCardHeader, IonCardHeader,
IonCardSubtitle, IonCardSubtitle,
IonCardTitle, IonCardTitle,
IonContent, IonContent,
IonHeader,
IonIcon, IonIcon,
IonItem,
IonItemDivider, IonItemDivider,
IonPage, IonPage,
IonRow, IonRow,
IonTitle,
IonToast, IonToast,
IonToolbar,
} from "@ionic/react"; } from "@ionic/react";
import { import {
arrowForwardOutline, arrowForwardOutline,
@@ -29,9 +35,12 @@ import itinerariesService from "../services/functions/itinerariesService";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useHistory } from "react-router"; import { useHistory } from "react-router";
import { geocodeByAddress, getLatLng } from "react-google-places-autocomplete"; import GooglePlacesAutocomplete, {
import { PageHeader } from "../components/PageHeader"; geocodeByAddress,
getLatLng,
} from "react-google-places-autocomplete";
import { Itinerary } from "../models/itinerary.model"; import { Itinerary } from "../models/itinerary.model";
import { PageHeader } from "../components/PageHeader";
import { closeToast } from "../services/utils"; import { closeToast } from "../services/utils";
import { Color } from "@ionic/core"; import { Color } from "@ionic/core";
@@ -109,12 +118,10 @@ const BuscarItinerario: React.FC = () => {
return; return;
} }
const maxRecentSearchesLength = 0; const maxRecentSearchesLength = 0
if (recentSearches.length >= maxRecentSearchesLength) { if (recentSearches.length >= maxRecentSearchesLength) {
setRecentSearches( setRecentSearches(recentSearches.slice(recentSearches.length - maxRecentSearchesLength));
recentSearches.slice(recentSearches.length - maxRecentSearchesLength)
);
} }
setRecentSearches((arr) => [ setRecentSearches((arr) => [
@@ -172,7 +179,7 @@ const BuscarItinerario: React.FC = () => {
value={addressFrom} value={addressFrom}
placeholder="R. José Paulino, 1234 - Centro, Campinas - SP, 13013-001" placeholder="R. José Paulino, 1234 - Centro, Campinas - SP, 13013-001"
/> */} /> */}
{/* <GooglePlacesAutocomplete <GooglePlacesAutocomplete
apiKey={process.env.REACT_APP_KEY_API} apiKey={process.env.REACT_APP_KEY_API}
apiOptions={{ language: "pt-br", region: "br" }} apiOptions={{ language: "pt-br", region: "br" }}
selectProps={{ selectProps={{
@@ -181,7 +188,7 @@ const BuscarItinerario: React.FC = () => {
className: "input-autocomplete", className: "input-autocomplete",
placeholder: "R. José Paulino, 1234", placeholder: "R. José Paulino, 1234",
}} }}
/> */} />
</div> </div>
<div className="inputs-from-to"> <div className="inputs-from-to">
<IonIcon icon={locationOutline}></IonIcon> <IonIcon icon={locationOutline}></IonIcon>
@@ -191,7 +198,7 @@ const BuscarItinerario: React.FC = () => {
value={addressTo} value={addressTo}
placeholder="PUC Campinas" placeholder="PUC Campinas"
/> */} /> */}
{/* <GooglePlacesAutocomplete <GooglePlacesAutocomplete
apiKey={process.env.REACT_APP_KEY_API} apiKey={process.env.REACT_APP_KEY_API}
apiOptions={{ language: "pt-br", region: "br" }} apiOptions={{ language: "pt-br", region: "br" }}
selectProps={{ selectProps={{
@@ -200,7 +207,7 @@ const BuscarItinerario: React.FC = () => {
className: "input-autocomplete", className: "input-autocomplete",
placeholder: "PUC Campinas", placeholder: "PUC Campinas",
}} }}
/> */} />
</div> </div>
<div className="button-search"> <div className="button-search">
<IonButton color="primary" onClick={() => buscarItinerarios()}> <IonButton color="primary" onClick={() => buscarItinerarios()}>
@@ -218,8 +225,7 @@ const BuscarItinerario: React.FC = () => {
return ( return (
<> <>
<div> <div>
<IonRow <IonRow key={index}
key={index}
class="latest-searches" class="latest-searches"
onClick={() => { onClick={() => {
fillSearchBars(search.addressFrom, search.addressTo); fillSearchBars(search.addressFrom, search.addressTo);

View File

@@ -1,9 +1,9 @@
import { import {
IonContent, IonContent,
IonPage,
IonFab, IonFab,
IonFabButton, IonFabButton,
IonIcon, IonIcon,
IonPage,
} from "@ionic/react"; } from "@ionic/react";
import { search } from "ionicons/icons"; import { search } from "ionicons/icons";
import "./BuscarPassageiro.css"; import "./BuscarPassageiro.css";
@@ -12,11 +12,11 @@ import { Map, Marker, Overlay } from "pigeon-maps";
import { maptiler } from "pigeon-maps/providers"; import { maptiler } from "pigeon-maps/providers";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { PageHeader } from "../../components/PageHeader";
import { UserSearchInfos } from "../../components/UserSearchInfos/UserSearchInfos";
import { getUsersSearching } from "../../services/api/users";
import RecordsStore from "../../store/RecordsStore"; import RecordsStore from "../../store/RecordsStore";
import { fetchRecords } from "../../store/Selectors"; import { fetchRecords } from "../../store/Selectors";
import { getUsersSearching } from "../../services/api/users";
import { UserSearchInfos } from "../../components/UserSearchInfos/UserSearchInfos";
import { PageHeader } from "../../components/PageHeader";
const maptilerProvider = maptiler("d5JQJPLLuap8TkJJlTdJ", "streets"); const maptilerProvider = maptiler("d5JQJPLLuap8TkJJlTdJ", "streets");
@@ -52,7 +52,7 @@ const BuscarPassageiro: React.FC = () => {
const [results, setResults] = useState([]); const [results, setResults] = useState([]);
const [zoom, setZoom] = useState(14); const [zoom, setZoom] = useState(14);
// const [ moveMode, setMoveMode ] = useState(false); const [moveMode, setMoveMode] = useState(false);
// useEffect(() => { // useEffect(() => {

View File

@@ -1,181 +1,19 @@
import { Color } from "@ionic/core";
import { import {
IonBackButton,
IonButton, IonButton,
IonCheckbox, IonButtons,
IonContent, IonContent,
IonDatetime, IonHeader,
IonIcon, IonIcon,
IonInput,
IonItem,
IonLabel,
IonList,
IonPage, IonPage,
IonRange, IonTitle,
IonSelect, IonToolbar,
IonSelectOption,
IonSlide,
IonSlides,
IonToast,
} from "@ionic/react"; } from "@ionic/react";
import { import { close, locateOutline, locationOutline } from "ionicons/icons";
add, import GooglePlacesAutocomplete from "react-google-places-autocomplete";
addCircleOutline, import { PageHeader } from "../../components/PageHeader";
arrowBack,
arrowForward,
checkmark,
informationCircle,
locateOutline,
locationOutline,
removeCircleOutline,
} from "ionicons/icons";
import { useEffect, useRef, useState } from "react";
import { useHistory } from "react-router";
import AutoCompleteInput from "../../components/AutoCompleteInput";
import * as vansRoutes from "../../services/api/vans";
import sessionsService from "../../services/functions/sessionsService";
const slideOpts = {
initialSlide: 0,
allowTouchMove: false,
};
interface VanInfo {
plate: string;
brand: string;
model: string;
seats_number: string;
document_status: boolean;
locator_name: string;
locator_address: string;
locator_complement: string;
locator_city: string;
locator_state: string;
}
interface Coords {
lat: number;
lng: number;
}
interface Address {
formatted_address: string;
lat: number;
lng: number;
}
export default function CadastrarItinerario() { export default function CadastrarItinerario() {
const minDate = new Date();
const history = useHistory();
const mySlides = useRef<any>(null);
const nextButton1 = useRef<HTMLIonButtonElement>(null);
const nextButton2 = useRef<HTMLIonButtonElement>(null);
const [specificDate, setSpecificDate] = useState<boolean>(false);
const [singleVacancy, setSingleVacancy] = useState<boolean>(false);
const [vans, setVans] = useState<VanInfo[]>();
const [showToast, setShowToast] = useState<boolean>(false);
const [toastMessage, setToastMessage] = useState<string>("");
const [toastColor, setToastColor] = useState<Color>("primary");
//Infos
const [initialAddress, setInitialAddress] = useState<Address>();
const [initialCoords, setInitialCoords] = useState<Coords>();
const [neighborhoods, setNeighborhoods] = useState<Array<string>>([]);
const [finalAddress, setFinalAddress] = useState<string>("");
const [destinations, setDestinations] = useState<Array<string>>([]);
const [daysOfWeek, setDaysOfWeek] = useState<number>();
const [specificDay, setSpecificDay] = useState<Date>();
const [departureTime, setDepartureTime] = useState<Date>();
const [arrivalTime, setArrivalTime] = useState<Date>();
const [monthlyPrice, setMonthlyPrice] = useState<number>(0);
const [dailyPrice, setDailyPrice] = useState<number>(0);
const [van, setVan] = useState<string>("");
const [nickname, setNickname] = useState<string>("");
const redirectUserToLogin = () => {
history.push({ pathname: "/login" });
};
const onBtnClicked = async (direction: string) => {
const swiper = await mySlides.current.getSwiper();
if (direction === "next") {
swiper.slideNext();
} else if (direction === "prev") {
swiper.slidePrev();
}
};
function formatRange(rangeValue: number) {
switch (rangeValue) {
case 1:
return "Segunda";
case 2:
return "Terça";
case 3:
return "Quarta";
case 4:
return "Quinta";
case 5:
return "Sexta";
case 6:
return "Sabádo";
case 7:
return "Domingo";
default:
return "";
}
}
useEffect(() => {
const getUserVans = async () => {
let userId = "";
const refreshSessionRes = await sessionsService.refreshSession();
if (refreshSessionRes.error) {
redirectUserToLogin();
return;
}
if (refreshSessionRes.userId) {
userId = refreshSessionRes.userId;
}
vansRoutes
.getByUserId(userId)
.then((response) => {
if (response.status === "error") {
setToastColor("danger");
setToastMessage(response.message);
setShowToast(true);
return;
}
setVans(response.data);
})
.catch((err) => {
setToastColor("danger");
setToastMessage(err);
setShowToast(true);
});
};
getUserVans();
}, []);
useEffect(() => {
if (initialAddress) {
nextButton1.current!.disabled = false;
} else {
nextButton1.current!.disabled = true;
}
}, [initialAddress]);
function addNeighborhoodToList() {}
return ( return (
<IonPage> <IonPage>
<PageHeader <PageHeader
@@ -184,461 +22,34 @@ export default function CadastrarItinerario() {
></PageHeader> ></PageHeader>
<IonContent fullscreen> <IonContent fullscreen>
<IonSlides ref={mySlides} options={slideOpts}> <div className="m-3">
<IonSlide> <h1>Digite o endereço de onde você iniciará a rota do itinerário</h1>
<div className="m-3"> <div className="inputs-from-to">
<h1 className="mb-3 text-xl"> <IonIcon icon={locateOutline}></IonIcon>
Digite o endereço de onde você iniciará a rota do itinerário <GooglePlacesAutocomplete
</h1> apiKey={process.env.REACT_APP_KEY_API}
<div className="flex items-center mb-3"> apiOptions={{ language: "pt-br", region: "br" }}
<IonIcon icon={locateOutline}></IonIcon> selectProps={{
<AutoCompleteInput className: "input-autocomplete",
placeholder="R. José Paulino, 1234" placeholder: "R. José Paulino, 1234",
className="ml-2" }}
onAddressSelected={(address: Address) => />
setInitialAddress(address) </div>
} <div className="inputs-from-to">
onChange={(e: any) => { <IonIcon icon={locationOutline}></IonIcon>
nextButton1.current!.disabled = true; <GooglePlacesAutocomplete
}} apiKey={process.env.REACT_APP_KEY_API}
/> apiOptions={{ language: "pt-br", region: "br" }}
</div> selectProps={{
<div className="flex justify-end mb-3"> className: "input-autocomplete",
<IonButton placeholder: "PUC Campinas",
ref={nextButton1} }}
disabled />
onClick={() => onBtnClicked("next")} </div>
color="primary" <div className="button-search">
> <IonButton color="primary">Cadastrar</IonButton>
<IonIcon icon={arrowForward} /> </div>
</IonButton> </div>
</div>
<div className="flex items-center">
<IonIcon
icon={informationCircle}
size="large"
className="mr-4"
/>
<small className="text-gray-500">
Essa informação é importante para que possamos informar aos
passageiros um horário aproximado que você passará para
pegá-lo.
</small>
</div>
</div>
</IonSlide>
<IonSlide>
<div className="m-3">
<h1 className="mb-3 text-xl">
Adicione os bairros que você atenderá
</h1>
<div className="flex items-center mb-3">
<IonIcon icon={locationOutline}></IonIcon>
<AutoCompleteInput
placeholder="R. José Paulino, 1234"
className="ml-2"
onAddressSelected={(address: Address) => console.log(address)}
/>
</div>
<div className="flex justify-end mb-3">
<IonButton>
<IonIcon icon={add} />
</IonButton>
</div>
<div className="mb-3">
<IonList>
<IonItem>
<IonCheckbox slot="end"></IonCheckbox>
<IonLabel>Taquaral</IonLabel>
</IonItem>
<IonItem>
<IonCheckbox slot="end"></IonCheckbox>
<IonLabel>Barão Geraldo</IonLabel>
</IonItem>
</IonList>
</div>
<div className="flex justify-between mb-3">
<IonButton onClick={() => onBtnClicked("prev")} color="primary">
<IonIcon icon={arrowBack} />
</IonButton>
<IonButton onClick={() => onBtnClicked("next")} color="primary">
<IonIcon icon={arrowForward} />
</IonButton>
</div>
<div className="flex items-center">
<IonIcon
icon={informationCircle}
size="large"
className="mr-4"
/>
<small className="text-gray-500">
Não se preocupe, você poderá adicionar ou remover bairros
posteriormente caso precise editando o itinerário.
</small>
</div>
</div>
</IonSlide>
<IonSlide>
<div className="m-3">
<h1 className="mb-3 text-xl">
Digite o endereço de destino final do itinerário
</h1>
<div className="flex items-center mb-3">
<IonIcon icon={locationOutline}></IonIcon>
<AutoCompleteInput
placeholder="R. José Paulino, 1234"
className="ml-2"
onAddressSelected={(address: Address) => console.log(address)}
/>
</div>
<div className="flex justify-between mb-3">
<IonButton onClick={() => onBtnClicked("prev")} color="primary">
<IonIcon icon={arrowBack} />
</IonButton>
<IonButton
ref={nextButton2}
// disabled
onClick={() => onBtnClicked("next")}
color="primary"
>
<IonIcon icon={arrowForward} />
</IonButton>
</div>
<div className="flex items-center">
<IonIcon
icon={informationCircle}
size="large"
className="mr-4"
/>
<small className="text-gray-500">
Não se preocupe, você poderá adicionar paradas.
</small>
</div>
</div>
</IonSlide>
<IonSlide>
<div className="m-3">
<h1 className="mb-3 text-xl">
Adicione paradas durante o trajeto do itinerário para encontrar
mais passageiros
</h1>
<div className="flex items-center mb-3">
<IonIcon icon={locationOutline}></IonIcon>
<AutoCompleteInput
placeholder="R. José Paulino, 1234"
className="ml-2"
onAddressSelected={(address: Address) => console.log(address)}
/>
</div>
<div className="flex justify-end mb-3">
<IonButton>
<IonIcon icon={add} />
</IonButton>
</div>
<div className="mb-3">
<IonList>
<IonItem>
<IonCheckbox slot="end"></IonCheckbox>
<IonLabel>Unicamp</IonLabel>
</IonItem>
<IonItem>
<IonCheckbox slot="end"></IonCheckbox>
<IonLabel>CPFL</IonLabel>
</IonItem>
</IonList>
</div>
<div className="flex justify-between mb-3">
<IonButton onClick={() => onBtnClicked("prev")} color="primary">
<IonIcon icon={arrowBack} />
</IonButton>
<IonButton onClick={() => onBtnClicked("next")} color="primary">
<IonIcon icon={arrowForward} />
</IonButton>
</div>
<div className="flex items-center">
<IonIcon
icon={informationCircle}
size="large"
className="mr-4"
/>
<small className="text-gray-500">
Não se preocupe, você poderá adicionar ou remover paradas
posteriormente caso precise editando o itinerário.
</small>
</div>
</div>
</IonSlide>
<IonSlide>
<div className="m-3">
<h1 className="mb-3 text-xl">
Escolha o(s) dia(s) da semana ou um dia específico que o
itinerário será realizado
</h1>
<div hidden={specificDate} className="flex items-center mb-3">
<IonRange
dualKnobs
pin
pinFormatter={(value: number) => formatRange(value)}
ticks
snaps
min={1}
max={7}
>
<IonLabel slot="start">Seg</IonLabel>
<IonLabel slot="end">Dom</IonLabel>
</IonRange>
</div>
<div className="mb-3">
<IonItem className="mb-3">
<IonLabel>Dia Específico ?</IonLabel>
<IonCheckbox
onIonChange={(event) =>
event.detail.checked
? setSpecificDate(true)
: setSpecificDate(false)
}
></IonCheckbox>
</IonItem>
<IonDatetime
min={minDate.toISOString()}
presentation="date"
hidden={!specificDate}
></IonDatetime>
</div>
<div className="flex justify-between mb-3">
<IonButton onClick={() => onBtnClicked("prev")} color="primary">
<IonIcon icon={arrowBack} />
</IonButton>
<IonButton onClick={() => onBtnClicked("next")} color="primary">
<IonIcon icon={arrowForward} />
</IonButton>
</div>
</div>
</IonSlide>
<IonSlide>
<div className="m-3">
<h1 className="mb-3 text-xl">
Qual o horário estimado de ínicio do itinerário ?
</h1>
<div className="mb-3">
<IonDatetime presentation="time"></IonDatetime>
</div>
<div className="flex justify-between mb-3">
<IonButton onClick={() => onBtnClicked("prev")} color="primary">
<IonIcon icon={arrowBack} />
</IonButton>
<IonButton
ref={nextButton2}
// disabled
onClick={() => onBtnClicked("next")}
color="primary"
>
<IonIcon icon={arrowForward} />
</IonButton>
</div>
<div className="flex items-center">
<IonIcon
icon={informationCircle}
size="large"
className="mr-4"
/>
<small className="text-gray-500">
Não se preocupe, é apenas um horário estimado.
</small>
</div>
</div>
</IonSlide>
<IonSlide>
<div className="m-3">
<h1 className="mb-3 text-xl">
Qual o horário estimado de chegado no último destino do
itinerário ?
</h1>
<div className="mb-3">
<IonDatetime presentation="time"></IonDatetime>
</div>
<div className="flex justify-between mb-3">
<IonButton onClick={() => onBtnClicked("prev")} color="primary">
<IonIcon icon={arrowBack} />
</IonButton>
<IonButton
ref={nextButton2}
// disabled
onClick={() => onBtnClicked("next")}
color="primary"
>
<IonIcon icon={arrowForward} />
</IonButton>
</div>
<div className="flex items-center">
<IonIcon
icon={informationCircle}
size="large"
className="mr-4"
/>
<small className="text-gray-500">
Não se preocupe, é apenas um horário estimado.
</small>
</div>
</div>
</IonSlide>
<IonSlide>
<div className="m-3">
<h1 className="mb-3 text-xl">
Preencha as informações de pagamento
</h1>
<IonLabel>Valor cobrado mensalmente</IonLabel>
<div className="flex justify-between items-center mb-3">
<IonIcon
size="large"
onClick={() => setMonthlyPrice(monthlyPrice - 1)}
icon={removeCircleOutline}
/>
<h1 className="text-xl">R$ {monthlyPrice}</h1>
<IonIcon
className="text-4xl"
size="large"
onClick={() => setMonthlyPrice(monthlyPrice + 1)}
icon={addCircleOutline}
/>
</div>
<div className="mb-3">
<IonItem className="mb-3">
<IonLabel>Aceitar pedidos para vagas avulsa ?</IonLabel>
<IonCheckbox
onIonChange={(event) =>
setSingleVacancy(event.detail.checked)
}
></IonCheckbox>
</IonItem>
<div hidden={!singleVacancy}>
<IonLabel>Valor cobrado por dia (vaga avulsa)</IonLabel>
<div className="flex justify-between items-center">
<IonIcon
size="large"
onClick={() => setDailyPrice(dailyPrice - 1)}
icon={removeCircleOutline}
/>
<h1 className="text-xl">R$ {dailyPrice}</h1>
<IonIcon
className="text-4xl"
size="large"
onClick={() => setDailyPrice(dailyPrice + 1)}
icon={addCircleOutline}
/>
</div>
</div>
</div>
<div className="flex justify-between mb-3">
<IonButton onClick={() => onBtnClicked("prev")} color="primary">
<IonIcon icon={arrowBack} />
</IonButton>
<IonButton
ref={nextButton2}
// disabled
onClick={() => onBtnClicked("next")}
color="primary"
>
<IonIcon icon={arrowForward} />
</IonButton>
</div>
<div className="flex items-center">
<IonIcon
icon={informationCircle}
size="large"
className="mr-4"
/>
<small className="text-gray-500">
Lembre-se esse valor será cobrado independente do destino do
passageiro.
<br />
<b>
Em breve será possível cobrar valores diferentes para cada
destino.
</b>
</small>
</div>
</div>
</IonSlide>
<IonSlide>
<div className="m-3">
<h1 className="mb-3 text-xl">
Escolha o veículo que será utilizado no itinerário
</h1>
<div className="mb-3">
<IonSelect
interface="action-sheet"
placeholder="Selecione o veículo"
>
{vans ? (
vans.map((van, index) => {
return (
<IonSelectOption key={index} value={van.plate}>
{van.brand +
" - " +
van.model +
" | Placa: " +
van.plate}
</IonSelectOption>
);
})
) : (
<></>
)}
</IonSelect>
</div>
<div className="flex justify-between mb-3">
<IonButton onClick={() => onBtnClicked("prev")} color="primary">
<IonIcon icon={arrowBack} />
</IonButton>
<IonButton
ref={nextButton2}
// disabled
onClick={() => onBtnClicked("next")}
color="primary"
>
<IonIcon icon={arrowForward} />
</IonButton>
</div>
</div>
</IonSlide>
<IonSlide>
<div className="m-3">
<h1 className="mb-3 text-xl">
Escolha um apelido para o itinerário
</h1>
<div className="mb-3">
<IonInput
value={nickname}
onIonChange={(event) => setNickname(event.detail.value!)}
placeholder="Manhã - Centro"
></IonInput>
</div>
<div className="flex justify-between mb-3">
<IonButton onClick={() => onBtnClicked("prev")} color="primary">
<IonIcon icon={arrowBack} />
</IonButton>
<IonButton
ref={nextButton2}
// disabled
onClick={() => onBtnClicked("next")}
color="primary"
>
<IonIcon icon={checkmark} />
Cadastrar
</IonButton>
</div>
</div>
</IonSlide>
</IonSlides>
<IonToast
position="top"
color={toastColor}
isOpen={showToast}
onDidDismiss={() => setShowToast(false)}
message={toastMessage}
duration={2500}
/>
</IonContent> </IonContent>
</IonPage> </IonPage>
); );

View File

@@ -1,26 +1,16 @@
import { Color } from "@ionic/core"; import { IonToast, IonProgressBar, IonItem, IonLabel, IonInput, IonBackButton, IonButton, IonButtons, IonCardTitle, IonCol, IonContent, IonGrid, IonHeader, IonPage, IonRow, IonToolbar } from '@ionic/react';
import { import { arrowBack, logoFacebook, mail } from 'ionicons/icons';
IonButton, import { Action } from '../../components/Action';
IonCardTitle, import { useContext, useEffect, useState } from 'react';
IonCol, import { useHistory, useParams } from 'react-router';
IonContent, import './Cadastro.css';
IonGrid, import ModalExample from '../../components/Email';
IonInput, import * as UsersService from '../../services/api/users'
IonItem, import LocalStorage from '../../LocalStorage';
IonLabel, import { UserContext } from '../../App';
IonPage, import { Color } from '@ionic/core';
IonRow, import { closeToast } from '../../services/utils';
IonToast, import { PageHeader } from '../../components/PageHeader';
} from "@ionic/react";
import { useContext, useState } from "react";
import { useHistory, useParams } from "react-router";
import { UserContext } from "../../App";
import { Action } from "../../components/Action";
import { PageHeader } from "../../components/PageHeader";
import LocalStorage from "../../LocalStorage";
import * as UsersService from "../../services/api/users";
import { closeToast } from "../../services/utils";
import "./Cadastro.css";
const Cadastro: React.FC = () => { const Cadastro: React.FC = () => {
const history = useHistory(); const history = useHistory();
@@ -28,82 +18,74 @@ const Cadastro: React.FC = () => {
const user = useContext(UserContext); const user = useContext(UserContext);
const [showToast, setShowToast] = useState(false); const [showToast, setShowToast] = useState(false);
const [messageToast, setMessageToast] = useState(""); const [messageToast, setMessageToast] = useState('');
const [toastColor, setToastColor] = useState<Color>("primary"); const [toastColor, setToastColor] = useState<Color>("primary");
const [email, setEmail] = useState<string>(""); const [email, setEmail] = useState<string>('');
const [password, setPassword] = useState<string>(""); const [password, setPassword] = useState<string>('');
const [confirmPassword, setConfirmPassword] = useState<string>(""); const [confirmPassword, setConfirmPassword] = useState<string>('');
const [firstName, setFirstName] = useState<string>(""); const [firstName, setFirstName] = useState<string>('');
const [lastName, setLastName] = useState<string>(""); const [lastName, setLastName] = useState<string>('');
const [birthDate, setBirthDate] = useState<string>(""); const [birthDate, setBirthDate] = useState<string>('');
const [lResult, setlResult] = useState({ const [lResult, setlResult] = useState({
error: "", error: '',
success: true, success: true
}); });
const emailValidate = () => { const emailValidate = () => {
var usuario = email.substring(0, email.indexOf("@")); var usuario = email.substring(0, email.indexOf("@"));
var dominio = email.substring(email.indexOf("@") + 1, email.length); var dominio = email.substring(email.indexOf("@") + 1, email.length);
if ( if ((usuario.length >= 1) &&
usuario.length >= 1 && (dominio.length >= 3) &&
dominio.length >= 3 && (usuario.search("@") == -1) &&
usuario.search("@") === -1 && (dominio.search("@") == -1) &&
dominio.search("@") === -1 && (usuario.search(" ") == -1) &&
usuario.search(" ") === -1 && (dominio.search(" ") == -1) &&
dominio.search(" ") === -1 && (dominio.search(".") != -1) &&
dominio.search(".") !== -1 && (dominio.indexOf(".") >= 1) &&
dominio.indexOf(".") >= 1 && (dominio.lastIndexOf(".") < dominio.length - 1))
dominio.lastIndexOf(".") < dominio.length - 1 {
) { return true;
return true;
} else { } else {
return false; return false;
} }
}; };
const clearResult = () => { const clearResult = () => {
lResult.error = ""; lResult.error = '';
lResult.success = true; lResult.success = true;
}; }
const fieldValidate = async () => { const fieldValidate = async () => {
clearResult(); clearResult();
if (!emailValidate()) { if(!emailValidate()) {
lResult.error = "E-mail inválido!"; lResult.error = 'E-mail inválido!';
lResult.success = false; lResult.success = false;
return lResult; return lResult;
} else if (password.length < 7 || password.length > 12) { } else if(password.length < 7 || password.length > 12) { //TODO: validar de acordo com a documentação
//TODO: validar de acordo com a documentação lResult.error = 'A senha deve ter de 7 a 12 caracteres!';
lResult.error = "A senha deve ter de 7 a 12 caracteres!"; lResult.success = false;
lResult.success = false; return lResult;
return lResult; }
}
return lResult; return lResult;
}; };
const handleSubmit = async () => { const handleSubmit = async () => {
if ( if(name === '' || email === '' || birthDate === '' || password === '' || confirmPassword === '') {
name === "" || setToastColor("warning")
email === "" || setMessageToast('Nenhum campo pode estar vazio!');
birthDate === "" ||
password === "" ||
confirmPassword === ""
) {
setToastColor("warning");
setMessageToast("Nenhum campo pode estar vazio!");
setShowToast(true); setShowToast(true);
return; return
} }
if (password !== confirmPassword) { if(password !== confirmPassword) {
setToastColor("warning"); setToastColor("warning")
setMessageToast("As senhas devem ser iguais!"); setMessageToast('As senhas devem ser iguais!');
setShowToast(true); setShowToast(true);
return; return
} }
const signUpForm = { const signUpForm = {
@@ -111,127 +93,123 @@ const Cadastro: React.FC = () => {
lastname: lastName, lastname: lastName,
email: email, email: email,
birth_date: birthDate, birth_date: birthDate,
password: password, password: password
}; }
let result = fieldValidate(); let result = fieldValidate();
if (!(await result).success) { if(!(await result).success) {
setToastColor("warning"); setToastColor("warning")
setMessageToast(lResult.error); setMessageToast(lResult.error);
setShowToast(true); setShowToast(true);
return; return
} }
let retorno = await UsersService.create(signUpForm); let retorno = await UsersService.create(signUpForm);
if (!retorno.token) { if(!retorno.token) {
setToastColor("danger"); setToastColor('danger')
setMessageToast(retorno.message); setMessageToast(retorno.message);
setShowToast(true); setShowToast(true);
return; return
} }
LocalStorage.setToken(retorno.token.token); LocalStorage.setToken(retorno.token.token);
user.setIsLoggedIn(true); user.setIsLoggedIn(true);
history.push({ history.push({ pathname: '/home', state: {
pathname: "/home", redirectData: {
state: { showToastMessage: true,
redirectData: { toastColor: "success",
showToastMessage: true, toastMessage: "Usuário cadastrado com sucesso!",
toastColor: "success", }
toastMessage: "Usuário cadastrado com sucesso!", }})
},
},
});
}; };
const { name } = useParams<{ name: string }>(); const { name } = useParams<{ name: string; }>();
return ( return (
<IonPage> <IonPage>
<PageHeader pageName="Cadastro" backButtonPageUrl="/login"></PageHeader> <PageHeader
pageName="Cadastro"
backButtonPageUrl="/login"
></PageHeader>
<IonContent fullscreen> <IonContent fullscreen>
<IonGrid className="ion-padding"> <IonGrid className="ion-padding">
<IonRow> <IonRow>
<IonCol size="12"> <IonCol size="12">
{/* <IonCardTitle>Como você deseja se cadastrar?</IonCardTitle> */} {/* <IonCardTitle>Como você deseja se cadastrar?</IonCardTitle> */}
<IonCardTitle>Cadastro</IonCardTitle> <IonCardTitle>Cadastro</IonCardTitle>
</IonCol> </IonCol>
</IonRow> </IonRow>
<IonRow> <IonRow>
<IonCol size="12"> <IonCol size="12">
<div id="nome-sobrenome"> <div id='nome-sobrenome'>
<IonItem> <IonItem>
<IonLabel position="floating">Nome</IonLabel> <IonLabel position='floating'>Nome</IonLabel>
<IonInput <IonInput
type="text" type='text'
clearInput clearInput
onIonInput={(e: any) => setFirstName(e.target.value)} onIonInput={(e: any) => setFirstName(e.target.value)}
// error={isError} // error={isError}
// onIonChange={(e: any) => setFirstName(e.detail.value)} // onIonChange={(e: any) => setFirstName(e.detail.value)}
></IonInput> >
</IonItem> </IonInput>
<IonItem> </IonItem>
<IonLabel position="floating">Sobrenome</IonLabel> <IonItem>
<IonInput <IonLabel position='floating'>Sobrenome</IonLabel>
clearInput <IonInput
onIonChange={(e: any) => setLastName(e.target.value)} clearInput
></IonInput> onIonChange={(e: any) => setLastName(e.target.value)}
</IonItem> >
</div> </IonInput>
</IonItem>
</div>
<IonItem> <IonItem>
<IonLabel position="floating">E-mail</IonLabel> <IonLabel position='floating'>E-mail</IonLabel>
<IonInput <IonInput
clearInput clearInput
type="email" type='email'
onIonChange={(e: any) => setEmail(e.target.value)} onIonChange={(e: any) => setEmail(e.target.value)}
></IonInput> >
</IonItem> </IonInput>
</IonItem>
<IonItem> <IonItem>
<IonLabel position="stacked">Data de nascimento</IonLabel> <IonLabel position='stacked'>Data de nascimento</IonLabel>
<IonInput <IonInput
type="date" type='date'
onIonChange={(e: any) => setBirthDate(e.target.value)} onIonChange={(e: any) => setBirthDate(e.target.value)}
></IonInput> >
</IonItem> </IonInput>
</IonItem>
<IonItem> <IonItem>
<IonLabel position="floating">Senha</IonLabel> <IonLabel position='floating'>Senha</IonLabel>
<IonInput <IonInput
clearInput clearInput
type="password" type='password'
onIonChange={(e: any) => setPassword(e.target.value)} onIonChange={(e: any) => setPassword(e.target.value)}
></IonInput> ></IonInput>
</IonItem> </IonItem>
<IonItem> <IonItem>
<IonLabel position="floating">Confirme a senha</IonLabel> <IonLabel position='floating'>Confirme a senha</IonLabel>
<IonInput <IonInput
clearInput clearInput
type="password" type='password'
onIonChange={(e: any) => setConfirmPassword(e.target.value)} onIonChange={(e: any) => setConfirmPassword(e.target.value)}
></IonInput> ></IonInput>
</IonItem> </IonItem>
<IonButton <IonButton className="ion-margin-top" expand="block" onClick={ handleSubmit }>Cadastrar-se</IonButton>
className="ion-margin-top" </IonCol>
expand="block" </IonRow>
onClick={handleSubmit} <small className='ion-margin-top'>
> Ao se cadastrar, você aceita nossos <a href="">Termos e Condições</a> e nossa <a href=""> Política de Privacidade</a>.
Cadastrar-se </small>
</IonButton> <Action message="Já tem conta?" text="Login" link="/login" />
</IonCol>
</IonRow>
<small className="ion-margin-top">
Ao se cadastrar, você aceita nossos{" "}
<a href="">Termos e Condições</a> e nossa{" "}
<a href=""> Política de Privacidade</a>.
</small>
<Action message="Já tem conta?" text="Login" link="/login" />
</IonGrid> </IonGrid>
{/* <IonProgressBar type="indeterminate"></IonProgressBar><br /> */} {/* <IonProgressBar type="indeterminate"></IonProgressBar><br /> */}
@@ -242,8 +220,8 @@ const Cadastro: React.FC = () => {
message={messageToast} message={messageToast}
duration={2500} duration={2500}
/> />
</IonContent> </IonContent>
</IonPage> </IonPage>
); );
}; };

View File

@@ -1,22 +1,28 @@
import { import {
IonCard, IonBackButton,
IonCardContent, IonButtons,
IonContent, IonCard,
IonIcon, IonCardContent,
IonItem, IonContent,
IonLabel, IonHeader,
IonPage, IonIcon,
IonToast, IonItem,
IonLabel,
IonPage,
IonTitle,
IonToast,
IonToolbar
} from "@ionic/react"; } from "@ionic/react";
import React, { useEffect, useState } from "react"; import React, { useEffect, useReducer, useState } from "react";
import { callOutline, documentTextOutline } from "ionicons/icons"; import '../Perfil.css'
import { useHistory, useLocation } from "react-router"; import { useHistory, useLocation } from "react-router";
import "../Perfil.css"; import { callOutline, documentTextOutline } from "ionicons/icons";
import '../Cadastro/Cadastro.css'
import { Color } from "@ionic/core"; import { Color } from "@ionic/core";
import { PageHeader } from "../../components/PageHeader";
import { closeToast } from "../../services/utils"; import { closeToast } from "../../services/utils";
import { PageHeader } from "../../components/PageHeader";
interface cardItem { interface cardItem {
icon: string; icon: string;
@@ -44,62 +50,57 @@ interface LocationState {
showToastMessage: boolean; showToastMessage: boolean;
toastColor: Color; toastColor: Color;
toastMessage: string; toastMessage: string;
}; }
} }
let items: cardItem[] = [ let items: cardItem[] = [
{ {
icon: documentTextOutline, icon: documentTextOutline,
label: "Documento", label: 'Documento',
description: description: 'Cadastre seu documento para que seu perfil possa ser verificado',
"Cadastre seu documento para que seu perfil possa ser verificado", url: '/perfil/completar/documento',
url: "/perfil/completar/documento", required: false
required: false,
}, },
{ {
icon: callOutline, icon: callOutline,
label: "Informações de contato", label: 'Informações de contato',
description: description: 'Cadastre seu número de telefone celular que para possam contatar você',
"Cadastre seu número de telefone celular que para possam contatar você", url: '/perfil/completar/telefone',
url: "/perfil/completar/telefone", required: false
required: false, }
}, ]
];
const CadastroCompletar: React.FC = () => { const CadastroCompletar: React.FC = () => {
const history = useHistory(); const history = useHistory();
const location = useLocation<LocationState>(); const location = useLocation<LocationState>();
const [showToast, setShowToast] = useState(false); const [showToast, setShowToast] = useState(false);
const [toastMessage, setToastMessage] = useState(""); const [toastMessage, setToastMessage] = useState('');
const [toastColor, setToastColor] = useState<Color>("primary"); const [toastColor, setToastColor] = useState<Color>("primary");
const handleCardClick = (item: cardItem) => { const handleCardClick = (item: cardItem) => {
if (!item.required) return; if (!item.required) return
history.push({ history.push({ pathname: item.url, state: { userData: location.state.userData } });
pathname: item.url, }
state: { userData: location.state.userData },
});
};
useEffect(() => { useEffect(() => {
if (!location.state || !location.state.userData) { if (!location.state || !location.state.userData) {
history.push({ pathname: "/perfil" }); history.push({ pathname: '/perfil' })
} }
if (location.state && location.state.redirectData) { if (location.state && location.state.redirectData) {
const redirectData = location.state.redirectData; const redirectData = location.state.redirectData
if (redirectData.showToastMessage) { if (redirectData.showToastMessage) {
setToastColor(redirectData.toastColor); setToastColor(redirectData.toastColor)
setToastMessage(redirectData.toastMessage); setToastMessage(redirectData.toastMessage)
setShowToast(true); setShowToast(true)
} }
} }
if (!location.state.userData.document) items[0].required = true; if (!location.state.userData.document) items[0].required = true
if (!location.state.userData.phone_number) items[1].required = true; if (!location.state.userData.phone_number) items[1].required = true
}, []); }, []);
return ( return (
@@ -110,15 +111,9 @@ const CadastroCompletar: React.FC = () => {
></PageHeader> ></PageHeader>
<IonContent> <IonContent>
{items.map((item, index) => { { items.map((item, index) => {
return ( return (
<IonCard <IonCard button={item.required} key={index} onClick={() => { handleCardClick(item) }}>
button={item.required}
key={index}
onClick={() => {
handleCardClick(item);
}}
>
<IonItem> <IonItem>
<IonIcon icon={item.icon} slot="start" /> <IonIcon icon={item.icon} slot="start" />
<IonLabel>{item.label}</IonLabel> <IonLabel>{item.label}</IonLabel>
@@ -126,7 +121,7 @@ const CadastroCompletar: React.FC = () => {
<IonCardContent>{item.description}</IonCardContent> <IonCardContent>{item.description}</IonCardContent>
</IonCard> </IonCard>
); )
})} })}
<IonToast <IonToast

View File

@@ -1,19 +1,26 @@
import { import {
IonBackButton,
IonBadge, IonBadge,
IonButtons,
IonCard, IonCard,
IonCardContent, IonCardContent,
IonCardHeader, IonCardHeader,
IonCardTitle, IonCardTitle,
IonChip, IonChip,
IonContent, IonContent,
IonHeader,
IonIcon, IonIcon,
IonItem, IonItem,
IonLabel, IonLabel,
IonList, IonList,
IonListHeader, IonListHeader,
IonPage, IonPage,
IonTitle,
IonToast, IonToast,
IonToolbar,
} from "@ionic/react"; } from "@ionic/react";
import { useHistory, useLocation } from "react-router-dom";
import React, { useState, useEffect, useReducer, useContext } from "react";
import { import {
callOutline, callOutline,
cardOutline, cardOutline,
@@ -25,21 +32,16 @@ import {
shieldCheckmarkOutline, shieldCheckmarkOutline,
starOutline, starOutline,
} from "ionicons/icons"; } from "ionicons/icons";
import React, { useContext, useEffect, useReducer, useState } from "react";
import { useHistory, useLocation } from "react-router-dom";
import LocalStorage from "../LocalStorage";
import "./Perfil.css"; import "./Perfil.css";
import LocalStorage from "../LocalStorage";
import { Color } from "@ionic/core";
import { UserContext } from "../App";
import { PageHeader } from "../components/PageHeader";
import sessionsService from "../services/functions/sessionsService"; import sessionsService from "../services/functions/sessionsService";
import { import usersService from "../services/functions/usersService";
checkIfUserIsDriver, import { UserContext } from "../App";
getById, import { Color } from "@ionic/core";
} from "../services/functions/usersService";
import { closeToast } from "../services/utils"; import { closeToast } from "../services/utils";
import { PageHeader } from "../components/PageHeader";
interface ScanNewProps { interface ScanNewProps {
match: { match: {
@@ -131,7 +133,7 @@ const Perfil: React.FC<ScanNewProps> = (props) => {
} }
// get user info by ID // get user info by ID
const getByIdRes = await getById(userId); const getByIdRes = await usersService.getById(userId);
if (getByIdRes.error) { if (getByIdRes.error) {
if (isVisitor && props.match.params.id) { if (isVisitor && props.match.params.id) {
@@ -146,8 +148,8 @@ const Perfil: React.FC<ScanNewProps> = (props) => {
return; return;
} }
// check if user is driver (if they have vans) // check if user is driver (if they have vehicles)
const userIsDriverRes = await checkIfUserIsDriver(userId); const userIsDriverRes = await usersService.checkIfUserIsDriver(userId);
// if (userIsDriverRes.error) { // if (userIsDriverRes.error) {
// setToastColor('warning') // setToastColor('warning')
@@ -345,15 +347,6 @@ const Perfil: React.FC<ScanNewProps> = (props) => {
<IonIcon icon={personOutline} slot="start" /> <IonIcon icon={personOutline} slot="start" />
<IonLabel>Buscar passageiros</IonLabel> <IonLabel>Buscar passageiros</IonLabel>
</IonItem> </IonItem>
<IonItem
button
onClick={() =>
history.push({ pathname: "/cadastrar-itinerario" })
}
>
<IonIcon icon={mapOutline} slot="start" />
<IonLabel>Cadastrar itinerário</IonLabel>
</IonItem>
<IonItem <IonItem
button button
onClick={() => onClick={() =>

View File

@@ -1,36 +1,54 @@
import { import {
IonButton,
IonCard,
IonCardContent,
IonCheckbox,
IonContent, IonContent,
IonPage,
IonFab, IonFab,
IonFabButton, IonFabButton,
IonFooter,
IonHeader,
IonIcon, IonIcon,
IonItem, IonCard,
IonLabel, IonInput,
IonModal, IonRow,
IonPage, IonCol,
IonRadio, IonCardContent,
IonRadioGroup, IonButton,
IonSlide, IonHeader,
IonSlides,
IonToast,
IonToolbar, IonToolbar,
IonButtons,
IonBackButton,
IonTabs,
IonTabBar,
IonTabButton,
IonLabel,
IonBadge,
IonRouterOutlet,
IonSlides,
IonSlide,
IonModal,
IonList,
IonRadioGroup,
IonListHeader,
IonItem,
IonRadio,
IonCheckbox,
IonFooter,
IonToast,
} from "@ionic/react"; } from "@ionic/react";
import { import {
arrowBack,
arrowBackOutline,
arrowForwardOutline, arrowForwardOutline,
chevronBackOutline, chevronBackOutline,
chevronForwardOutline,
closeOutline, closeOutline,
locateOutline,
locationOutline,
timeOutline,
} from "ionicons/icons"; } from "ionicons/icons";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useHistory, useLocation } from "react-router"; import { useHistory, useLocation } from "react-router";
import { createUserSearch } from "../../services/api/users";
import itinerariesService from "../../services/functions/itinerariesService"; import itinerariesService from "../../services/functions/itinerariesService";
import { closeToast } from "../../services/utils"; import { createUserSearch } from "../../services/api/users";
import "./Transportes.css"; import "./Transportes.css";
import { closeToast } from "../../services/utils";
interface InfoBusca { interface InfoBusca {
addressFrom: any; addressFrom: any;
@@ -46,8 +64,8 @@ const Transportes: React.FC = () => {
const [itinerarios, setItinerarios] = useState([]); const [itinerarios, setItinerarios] = useState([]);
const [showModalFilters, setShowModalFilters] = useState(false); const [showModalFilters, setShowModalFilters] = useState(false);
const [showToast, setShowToast] = useState(false); const [showToast, setShowToast] = useState(false);
const [messageToast, setMessageToast] = useState(""); const [messageToast, setMessageToast ] = useState('');
const [toastColor, setToastColor] = useState("success"); const [toastColor, setToastColor] = useState('success');
useEffect(() => { useEffect(() => {
if (props) { if (props) {
@@ -60,21 +78,15 @@ const Transportes: React.FC = () => {
setItinerarios(data); setItinerarios(data);
} }
function criaAlerta() { function criaAlerta(){
createUserSearch( createUserSearch(props.coordinatesFrom.lat, props.coordinatesFrom.lng, props.addressTo.label).then(() => {
props.coordinatesFrom.lat, setMessageToast('Alerta criado com sucesso!');
props.coordinatesFrom.lng, setShowToast(true);
props.addressTo.label }).catch((err:any) => {
) setMessageToast('Não foi possível criar o alerta!');
.then(() => { setToastColor('danger');
setMessageToast("Alerta criado com sucesso!"); setShowToast(true);
setShowToast(true); })
})
.catch((err: any) => {
setMessageToast("Não foi possível criar o alerta!");
setToastColor("danger");
setShowToast(true);
});
} }
return ( return (
@@ -97,7 +109,7 @@ const Transportes: React.FC = () => {
</div> </div>
</IonHeader> </IonHeader>
<IonContent fullscreen> <IonContent fullscreen>
{itinerarios && itinerarios.length > 0 ? ( {itinerarios && itinerarios.length > 0? (
<div className="header-tabs"> <div className="header-tabs">
<IonSlides> <IonSlides>
<IonSlide> <IonSlide>
@@ -114,11 +126,9 @@ const Transportes: React.FC = () => {
</IonSlide> </IonSlide>
</IonSlides> </IonSlides>
</div> </div>
) : ( )
<h1 className="msg-not-found"> :
Não foi encontrado nenhum transporte que atenda essa rota. (<h1 className="msg-not-found">Não foi encontrado nenhum transporte que atenda essa rota.</h1>)}
</h1>
)}
{itinerarios && {itinerarios &&
itinerarios.map((record: any, index: any) => { itinerarios.map((record: any, index: any) => {
return ( return (
@@ -131,7 +141,7 @@ const Transportes: React.FC = () => {
</IonCardContent> </IonCardContent>
</IonCard> </IonCard>
); );
})} })}
<div className="button-criar-alerta"> <div className="button-criar-alerta">
<IonButton onClick={() => criaAlerta()}>Criar Alerta</IonButton> <IonButton onClick={() => criaAlerta()}>Criar Alerta</IonButton>

View File

@@ -1,10 +1,10 @@
import instance from "./api"; import instance from './api';
// import LocalStorage from '../LocalStorage'; // import LocalStorage from '../LocalStorage';
import { AxiosRequestHeaders } from "axios"; import userRoutes from '../../constants/routes/usersRoutes';
import userRoutes from "../../constants/routes/usersRoutes"; import { AxiosRequestHeaders } from 'axios';
import LocalStorage from "../../LocalStorage"; import LocalStorage from '../../LocalStorage';
import { setStore } from "../../store/RecordsStore"; import { setStore } from '../../store/RecordsStore';
let token: string; let token: string;
let header: AxiosRequestHeaders; let header: AxiosRequestHeaders;
@@ -13,20 +13,20 @@ function updateHeader() {
token = LocalStorage.getToken(); token = LocalStorage.getToken();
header = { header = {
Accept: "application/json", "Accept": 'application/json',
"Content-Type": "application/json", "Content-Type": 'application/json',
Authorization: "Bearer " + token, "Authorization": 'Bearer ' + token
}; }
} }
export interface CadastroResponse { export interface CadastroResponse {
message?: string; message?: string;
token?: { token?: {
token: string; token: string;
}; };
error?: string; error?: string;
} }
export interface CadastroRequest { export interface CadastroRequest {
@@ -63,28 +63,21 @@ export async function create(CadastroRequest: any) {
export async function getById(userId: string) { export async function getById(userId: string) {
updateHeader(); updateHeader();
const response = await instance.get(userRoutes.get.url + `/${userId}`, { const response = await instance.get(userRoutes.get.url + `/${userId}`, { headers: header });
headers: header,
});
return response.data; return response.data;
} }
export async function update(userData: UpdateUserRequest) { export async function update(userData: UpdateUserRequest) {
updateHeader(); updateHeader();
const response = await instance.patch(userRoutes.update.url, userData, { const response = await instance.patch(userRoutes.update.url, userData, { headers: header });
headers: header,
});
return response.data; return response.data;
} }
export async function checkIfUserIsDriver(id_user: string) { export async function checkIfUserIsDriver(id_user: string) {
updateHeader(); updateHeader();
const response = await instance.get( const response = await instance.get(userRoutes.checkIfUserIsDriver.url + `/${id_user}`, { headers: header });
userRoutes.checkIfUserIsDriver.url + `/${id_user}`,
{ headers: header }
);
return response.data; return response.data;
} }
@@ -92,39 +85,25 @@ export async function checkIfUserIsDriver(id_user: string) {
export async function getSocialInfo(userId: string) { export async function getSocialInfo(userId: string) {
updateHeader(); updateHeader();
const response = await instance.get( const response = await instance.get(userRoutes.getSocialInfo.url + `/${userId}`, { headers: header });
userRoutes.getSocialInfo.url + `/${userId}`,
{ headers: header }
);
return response.data; return response.data;
} }
export async function getUsersSearching(currentPoint: any) { export async function getUsersSearching(currentPoint: any) {
// Replace lat/long with values from get current location. // Replace lat/long with values from get current location.
// Allow choosing of radius? // Allow choosing of radius?
// Offset could = amount loaded in an infinite scroll? // Offset could = amount loaded in an infinite scroll?
// var latitude = currentPoint.latitude, longitude = currentPoint.longitude, radius = 3000, offset = 0; var latitude = currentPoint.latitude, longitude = currentPoint.longitude, radius = 3000, offset = 0;
// const response = await fetch(`http://localhost:4000/get-records?latitude=${ latitude }&longitude=${ longitude }&radius=${ radius }&offset=${ offset }`); // const response = await fetch(`http://localhost:4000/get-records?latitude=${ latitude }&longitude=${ longitude }&radius=${ radius }&offset=${ offset }`);
const response = await instance.post( const response = await instance.post(`${userRoutes.getUsersSearching.url}`, currentPoint)
`${userRoutes.getUsersSearching.url}`, // const data = await response.json();
currentPoint console.log(response.data)
); setStore(response.data);
// const data = await response.json();
console.log(response.data);
setStore(response.data);
} }
export async function createUserSearch( export async function createUserSearch(latitude_from: any, longitude_from: any, addres_to: any) {
latitude_from: any, const response = await instance.post(`${userRoutes.createUserSearch.url}`, { latitude_from, longitude_from, addres_to });
longitude_from: any,
addres_to: any
) {
const response = await instance.post(`${userRoutes.createUserSearch.url}`, {
latitude_from,
longitude_from,
addres_to,
});
console.log(response); console.log(response)
setStore(response); setStore(response);
} }

View File

@@ -10,13 +10,13 @@ interface getAllCarBrandsReturn {
error?: { error?: {
errorMessage: string; errorMessage: string;
}; }
} }
interface getAllCarBrandsRes { interface getAllCarBrandsRes {
status?: string; status?: string;
message: string; message: string
data?: CarObject[]; data?: CarObject[];
} }
@@ -45,9 +45,7 @@ const getAllCarBrands = async (): Promise<getAllCarBrandsReturn> => {
} }
}; };
const getCarModels = async ( const getCarModels = async (carBrandId: string): Promise<getAllCarBrandsReturn> => {
carBrandId: string
): Promise<getAllCarBrandsReturn> => {
try { try {
let res: getAllCarBrandsRes = await carsRoutes.listCarModels(carBrandId); let res: getAllCarBrandsRes = await carsRoutes.listCarModels(carBrandId);

View File

@@ -14,7 +14,7 @@ interface refreshSessionResponse {
const refreshSession = async (): Promise<refreshSessionReturn> => { const refreshSession = async (): Promise<refreshSessionReturn> => {
try { try {
let res: refreshSessionResponse = await sessionRoutes.refresh(); let res: refreshSessionResponse = await sessionRoutes.refresh()
if (res.status === "error") { if (res.status === "error") {
return { return {
@@ -26,7 +26,7 @@ const refreshSession = async (): Promise<refreshSessionReturn> => {
return { return {
userId: res.userId, userId: res.userId,
}; };
} catch (err) { } catch(err) {
return { return {
error: true, error: true,
errorMessage: "Por favor, autentique-se.", errorMessage: "Por favor, autentique-se.",
@@ -40,11 +40,7 @@ const refreshSession = async (): Promise<refreshSessionReturn> => {
// } else { // } else {
// // Anything else // // Anything else
// } // }
// } // }
}; };
const method = { export default { refreshSession }
refreshSession,
};
export default method;

View File

@@ -10,10 +10,10 @@ interface getByIdReturn {
bio: string; bio: string;
document_type: string; document_type: string;
document: string; document: string;
}; },
error?: { error?: {
errorMessage: string; errorMessage: string;
}; }
} }
interface getByIdRes { interface getByIdRes {
@@ -29,67 +29,65 @@ interface getByIdRes {
bio: string; bio: string;
document_type: string; document_type: string;
document: string; document: string;
}; },
} }
export const getById = async (userId: string): Promise<getByIdReturn> => { const getById = async (userId: string): Promise<getByIdReturn> => {
try { try {
let res: getByIdRes = await usersRoutes.getById(userId); let res: getByIdRes = await usersRoutes.getById(userId)
if (res.status === "error") { if (res.status === "error") {
return { return {
error: { error: {
errorMessage: res.message, errorMessage: res.message,
}, }
}; };
} }
return { return {
userData: res.data, userData: res.data,
}; };
} catch (err) { } catch(err) {
return { return {
error: { error: {
errorMessage: "Por favor, autentique-se.", errorMessage: "Por favor, autentique-se.",
}, }
}; };
} }
}; };
interface getByIdReturn { interface getByIdReturn {
data?: { data?: {
phone: ""; phone: '',
whatsapp: ""; whatsapp: '',
facebook: ""; facebook: '',
telegram: ""; telegram: '',
}; },
error?: { error?: {
errorMessage: string; errorMessage: string;
}; }
} }
export const getUserSocialInfo = async ( const getUserSocialInfo = async (userId: string): Promise<getByIdReturn> => {
userId: string
): Promise<getByIdReturn> => {
try { try {
let res: getByIdRes = await usersRoutes.getSocialInfo(userId); let res: getByIdRes = await usersRoutes.getSocialInfo(userId)
if (res.status === "error") { if (res.status === "error") {
return { return {
error: { error: {
errorMessage: res.message, errorMessage: res.message,
}, }
}; };
} }
return { return {
userData: res.data, userData: res.data,
}; };
} catch (err) { } catch(err) {
return { return {
error: { error: {
errorMessage: "Por favor, autentique-se.", errorMessage: "Por favor, autentique-se.",
}, }
}; };
} }
}; };
@@ -98,7 +96,7 @@ interface checkIfUserIsDriverReturn {
result?: boolean; result?: boolean;
error?: { error?: {
errorMessage: string; errorMessage: string;
}; }
} }
interface checkIfUserIsDriverResponse { interface checkIfUserIsDriverResponse {
@@ -107,32 +105,31 @@ interface checkIfUserIsDriverResponse {
result?: boolean; result?: boolean;
error?: { error?: {
errorMessage: string; errorMessage: string;
}; }
} }
export const checkIfUserIsDriver = async ( const checkIfUserIsDriver = async (id_user: string): Promise<checkIfUserIsDriverReturn> => {
id_user: string
): Promise<checkIfUserIsDriverReturn> => {
try { try {
let res: checkIfUserIsDriverResponse = let res: checkIfUserIsDriverResponse = await usersRoutes.checkIfUserIsDriver(id_user)
await usersRoutes.checkIfUserIsDriver(id_user);
if (res.status === "error") { if (res.status === "error") {
return { return {
error: { error: {
errorMessage: res.message, errorMessage: res.message,
}, }
}; };
} }
return { return {
result: res.result, result: res.result,
}; };
} catch (err) { } catch(err) {
return { return {
error: { error: {
errorMessage: "Por favor, autentique-se.", errorMessage: "Por favor, autentique-se.",
}, }
}; };
} }
}; };
export default { getById, getUserSocialInfo, checkIfUserIsDriver }

12927
yarn.lock Normal file

File diff suppressed because it is too large Load Diff