@@ -84,7 +84,11 @@
|
||||
"@types/lodash.isequal": "^4.5.6",
|
||||
"autoprefixer": "^9.8.8",
|
||||
"postcss": "^7.0.39",
|
||||
"react-error-overlay": "6.0.9",
|
||||
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.17"
|
||||
},
|
||||
"description": "Projeto de conclusão de curso a fim de resolver a dificuldade de alunos universitários ao buscar vans para suas universidades"
|
||||
"description": "Projeto de conclusão de curso a fim de resolver a dificuldade de alunos universitários ao buscar vans para suas universidades",
|
||||
"resolutions": {
|
||||
"react-error-overlay": "6.0.9"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import MeusItinerarios from "./pages/MeusItinerarios/MeusItinerarios";
|
||||
import Buscas from "./pages/Buscas";
|
||||
import BuscarItinerario from "./pages/BuscarItinerario";
|
||||
import BuscarPassageiro from "./pages/BuscarPassageiro/BuscarPassageiro";
|
||||
import Transportes from "./pages/Transportes/Transportes";
|
||||
import ListaItinerarios from "./pages/ListaItinerarios";
|
||||
|
||||
/* Core CSS required for Ionic components to work properly */
|
||||
import "@ionic/react/css/core.css";
|
||||
@@ -93,7 +93,7 @@ const routes = (
|
||||
<Route exact path="/buscas" component={Buscas}></Route>
|
||||
<Route exact path="/buscar/itinerario" component={BuscarItinerario}></Route>
|
||||
<Route exact path="/buscar/passageiro" component={BuscarPassageiro}></Route>
|
||||
<Route exact path="/transportes" component={Transportes}></Route>
|
||||
<Route exact path="/buscar/itinerario/lista" component={ListaItinerarios}></Route>
|
||||
|
||||
<Route exact path="/">
|
||||
<Redirect to="/home" />
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { IonBackButton, IonButtons, IonHeader, IonTitle, IonToolbar } from "@ionic/react";
|
||||
import {
|
||||
IonBackButton,
|
||||
IonButtons,
|
||||
IonHeader,
|
||||
IonTitle,
|
||||
IonToolbar,
|
||||
} from "@ionic/react";
|
||||
|
||||
interface ComponentProps {
|
||||
pageName: string;
|
||||
@@ -10,7 +16,12 @@ export const PageHeader = (props: ComponentProps) => (
|
||||
<IonToolbar>
|
||||
<IonTitle>{props.pageName}</IonTitle>
|
||||
<IonButtons slot="start">
|
||||
<IonBackButton text="" defaultHref={ props.backButtonPageUrl ? props.backButtonPageUrl : undefined } />
|
||||
<IonBackButton
|
||||
text=""
|
||||
defaultHref={
|
||||
props.backButtonPageUrl ? props.backButtonPageUrl : undefined
|
||||
}
|
||||
/>
|
||||
</IonButtons>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
.button-search{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
margin-top: 50%;
|
||||
}
|
||||
|
||||
.latest-searches{
|
||||
|
||||
@@ -1,31 +1,19 @@
|
||||
import {
|
||||
IonBackButton,
|
||||
IonButton,
|
||||
IonButtons,
|
||||
IonCard,
|
||||
IonCardContent,
|
||||
IonCardHeader,
|
||||
IonCardSubtitle,
|
||||
IonCardTitle,
|
||||
IonContent,
|
||||
IonHeader,
|
||||
IonIcon,
|
||||
IonItem,
|
||||
IonItemDivider,
|
||||
IonPage,
|
||||
IonRow,
|
||||
IonTitle,
|
||||
IonToast,
|
||||
IonToolbar,
|
||||
} from "@ionic/react";
|
||||
import {
|
||||
arrowForwardOutline,
|
||||
cashOutline,
|
||||
chevronForwardOutline,
|
||||
locateOutline,
|
||||
locationOutline,
|
||||
personOutline,
|
||||
starOutline,
|
||||
timeOutline,
|
||||
} from "ionicons/icons";
|
||||
import "./BuscarItinerario.css";
|
||||
@@ -39,7 +27,6 @@ import GooglePlacesAutocomplete, {
|
||||
geocodeByAddress,
|
||||
getLatLng,
|
||||
} from "react-google-places-autocomplete";
|
||||
import { Itinerary } from "../models/itinerary.model";
|
||||
import { PageHeader } from "../components/PageHeader";
|
||||
import { closeToast } from "../services/utils";
|
||||
|
||||
@@ -56,47 +43,9 @@ const BuscarItinerario: React.FC = () => {
|
||||
const [coordinatesFrom, setCoordinatesFrom] = useState<any>("");
|
||||
const [addressTo, setAddressTo] = useState<any>("");
|
||||
const [coordinatesTo, setCoordinatesTo] = useState<any>("");
|
||||
const [showModalEnd, setShowModalEnd] = useState(false);
|
||||
const [addressResults, setAddressResults] = useState<any[]>([]);
|
||||
const [inputActive, setInputActive] = useState("");
|
||||
|
||||
const [recentSearches, setRecentSearches] = useState<any[]>([]);
|
||||
|
||||
const [itinerariesList, setItinerariesList] = useState<Itinerary[]>();
|
||||
|
||||
// const optionsAddress = async (inputValue: any) => {
|
||||
// let results = await autoCompleteAddress(inputValue)
|
||||
// .then((res) => {
|
||||
// return res.map((item: any) => {
|
||||
// return {
|
||||
// value:
|
||||
// item.geometry.coordinates[0] + "," + item.geometry.coordinates[1],
|
||||
// label: item.properties.formatted,
|
||||
// };
|
||||
// });
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// console.log("Erro ao buscar endereço:", err);
|
||||
// });
|
||||
// setAddressResults(results);
|
||||
// };
|
||||
|
||||
// function setInputActiveOpenModal(input: string) {
|
||||
// setInputActive(input);
|
||||
// setShowModalEnd(true);
|
||||
// }
|
||||
|
||||
// function setAddress(div: any) {
|
||||
// if (inputActive === "from") {
|
||||
// setAddressFrom(div.target.attributes[2].value);
|
||||
// setCoordinatesFrom(div.target.attributes[1].value);
|
||||
// } else {
|
||||
// setAddressTo(div.target.attributes[2].value);
|
||||
// setCoordinatesTo(div.target.attributes[1].value);
|
||||
// }
|
||||
// setShowModalEnd(false);
|
||||
// }
|
||||
|
||||
useEffect(() => {
|
||||
if (addressFrom.label && addressFrom.label.length > 0) {
|
||||
geocodeByAddress(addressFrom.label)
|
||||
@@ -118,10 +67,12 @@ const BuscarItinerario: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const maxRecentSearchesLength = 0
|
||||
const maxRecentSearchesLength = 0;
|
||||
|
||||
if (recentSearches.length >= maxRecentSearchesLength) {
|
||||
setRecentSearches(recentSearches.slice(recentSearches.length - maxRecentSearchesLength));
|
||||
setRecentSearches(
|
||||
recentSearches.slice(recentSearches.length - maxRecentSearchesLength)
|
||||
);
|
||||
}
|
||||
|
||||
setRecentSearches((arr) => [
|
||||
@@ -134,10 +85,12 @@ const BuscarItinerario: React.FC = () => {
|
||||
]);
|
||||
|
||||
await itinerariesService
|
||||
.searchItineraries({
|
||||
coordinatesFrom,
|
||||
coordinatesTo,
|
||||
})
|
||||
// TODO, desfazer
|
||||
// .searchItineraries({
|
||||
// coordinatesFrom,
|
||||
// coordinatesTo,
|
||||
// })
|
||||
.getAllItineraries()
|
||||
.then((response) => {
|
||||
// if (response.status === "error") {
|
||||
// setToastColor("danger");
|
||||
@@ -147,7 +100,18 @@ const BuscarItinerario: React.FC = () => {
|
||||
// return;
|
||||
// }
|
||||
|
||||
setItinerariesList(response);
|
||||
history.push({
|
||||
pathname: "/buscar/itinerario/lista",
|
||||
state: {
|
||||
coordinatesFrom,
|
||||
coordinatesTo,
|
||||
addressFrom,
|
||||
addressTo,
|
||||
itineraries: response,
|
||||
},
|
||||
});
|
||||
|
||||
// setItinerariesList(response);
|
||||
})
|
||||
.catch((err) => {
|
||||
setToastColor("danger");
|
||||
@@ -225,7 +189,8 @@ const BuscarItinerario: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<IonRow key={index}
|
||||
<IonRow
|
||||
key={index}
|
||||
class="latest-searches"
|
||||
onClick={() => {
|
||||
fillSearchBars(search.addressFrom, search.addressTo);
|
||||
@@ -258,102 +223,6 @@ const BuscarItinerario: React.FC = () => {
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{/* <IonRow class="latest-searches">
|
||||
<IonIcon
|
||||
className="icon-align-vcenter"
|
||||
size="large"
|
||||
icon={timeOutline}
|
||||
/>
|
||||
<div className="div_from_to">
|
||||
<span>Taquaral</span>
|
||||
<IonIcon icon={arrowForwardOutline}></IonIcon>
|
||||
<span>PUC-Campinas</span>
|
||||
<br />
|
||||
<small>Há 2 hora</small>
|
||||
</div>
|
||||
<IonIcon
|
||||
className="icon-forward icon-align-vcenter"
|
||||
size="large"
|
||||
icon={chevronForwardOutline}
|
||||
/>
|
||||
</IonRow> */}
|
||||
{/* <IonModal isOpen={showModalEnd}>
|
||||
<IonContent>
|
||||
<div className="header-search-modal">
|
||||
<IonIcon
|
||||
className="icon-return-modal"
|
||||
icon={arrowBack}
|
||||
onClick={() => setShowModalEnd(false)}
|
||||
/>
|
||||
<IonInput
|
||||
onIonChange={(e) => optionsAddress(e.detail.value)}
|
||||
placeholder="R. José Paulino, 1234 - Centro, Campinas - SP, 13013-001"
|
||||
className="search-modal"
|
||||
/>
|
||||
</div>
|
||||
{addressResults.length > 0 ? (
|
||||
addressResults.map((item: any) => {
|
||||
return (
|
||||
<div
|
||||
key={item.value}
|
||||
className="modal-search-results"
|
||||
data-value={item.value}
|
||||
data-label={item.label}
|
||||
onClick={(e) => setAddress(e)}
|
||||
>
|
||||
{item.label}
|
||||
<IonIcon
|
||||
className="icon-results-modal"
|
||||
icon={chevronForwardOutline}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<>
|
||||
<IonProgressBar type="indeterminate" />
|
||||
<br />
|
||||
</>
|
||||
)}
|
||||
</IonContent>
|
||||
</IonModal> */}
|
||||
|
||||
{itinerariesList && itinerariesList.length !== 0 ? (
|
||||
<>
|
||||
<IonItemDivider color="secondary">Resultados</IonItemDivider>
|
||||
{itinerariesList.map((itinerary, index) => {
|
||||
return (
|
||||
<IonCard
|
||||
button
|
||||
key={index}
|
||||
onClick={() => {
|
||||
history.push(`/itinerary/${itinerary.id_itinerary}`);
|
||||
}}
|
||||
>
|
||||
<IonCardHeader>
|
||||
<IonCardTitle>{itinerary.itinerary_nickname}</IonCardTitle>
|
||||
<IonCardSubtitle>
|
||||
<p>
|
||||
<IonIcon icon={personOutline} /> Vagas disponíveis:{" "}
|
||||
{itinerary.available_seats}
|
||||
</p>
|
||||
<p>
|
||||
<IonIcon icon={starOutline} /> Motorista:{" "}
|
||||
{itinerary.price}
|
||||
</p>
|
||||
<p>
|
||||
<IonIcon icon={cashOutline} /> Valor:{" "}
|
||||
{itinerary.vehicle_plate}
|
||||
</p>
|
||||
</IonCardSubtitle>
|
||||
</IonCardHeader>
|
||||
</IonCard>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
|
||||
<IonToast
|
||||
color={toastColor}
|
||||
|
||||
@@ -70,9 +70,14 @@
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 1rem 0 5.5rem 0;
|
||||
/* margin: 1rem 0 5.5rem 0; */
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.msg-not-found{
|
||||
margin: 1.5rem;
|
||||
}
|
||||
|
||||
.msg-not-found span {
|
||||
font-size: 120%;
|
||||
}
|
||||
259
src/pages/ListaItinerarios.tsx
Normal file
259
src/pages/ListaItinerarios.tsx
Normal file
@@ -0,0 +1,259 @@
|
||||
import {
|
||||
IonContent,
|
||||
IonPage,
|
||||
IonFab,
|
||||
IonFabButton,
|
||||
IonIcon,
|
||||
IonCard,
|
||||
IonButton,
|
||||
IonHeader,
|
||||
IonToolbar,
|
||||
IonLabel,
|
||||
IonModal,
|
||||
IonRadioGroup,
|
||||
IonItem,
|
||||
IonRadio,
|
||||
IonCheckbox,
|
||||
IonFooter,
|
||||
IonToast,
|
||||
IonCardHeader,
|
||||
IonCardSubtitle,
|
||||
IonCardTitle,
|
||||
IonItemDivider,
|
||||
IonCardContent,
|
||||
IonChip,
|
||||
IonGrid,
|
||||
IonRow,
|
||||
IonCol,
|
||||
IonList,
|
||||
IonListHeader,
|
||||
IonTitle,
|
||||
IonBackButton,
|
||||
IonButtons,
|
||||
} from "@ionic/react";
|
||||
import {
|
||||
arrowForwardOutline,
|
||||
cashOutline,
|
||||
closeOutline,
|
||||
personOutline,
|
||||
starOutline,
|
||||
} from "ionicons/icons";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useHistory, useLocation } from "react-router";
|
||||
import { createUserSearch } from "../services/api/users";
|
||||
import "./ListaItinerarios.css";
|
||||
import { closeToast, convertNumberToPrice } from "../services/utils";
|
||||
import { Itinerary } from "../models/itinerary.model";
|
||||
import { PageHeader } from "../components/PageHeader";
|
||||
|
||||
interface InfoBusca {
|
||||
addressFrom: any;
|
||||
addressTo: any;
|
||||
coordinatesFrom: any;
|
||||
coordinatesTo: any;
|
||||
|
||||
itineraries: Itinerary[];
|
||||
}
|
||||
|
||||
const ListaItinerarios: React.FC = () => {
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
const props = location.state as InfoBusca;
|
||||
const [itinerariesList, setItinerariesList] = useState<Itinerary[]>([]);
|
||||
const [showModalFilters, setShowModalFilters] = useState(true);
|
||||
const [showToast, setShowToast] = useState(false);
|
||||
const [messageToast, setMessageToast] = useState("");
|
||||
const [toastColor, setToastColor] = useState("success");
|
||||
|
||||
useEffect(() => {
|
||||
if (props.itineraries) {
|
||||
setItinerariesList(props.itineraries);
|
||||
}
|
||||
}, [props]);
|
||||
|
||||
function criaAlerta() {
|
||||
createUserSearch(
|
||||
props.coordinatesFrom.lat,
|
||||
props.coordinatesFrom.lng,
|
||||
props.addressTo.label
|
||||
)
|
||||
.then(() => {
|
||||
setMessageToast("Alerta criado com sucesso!");
|
||||
setShowToast(true);
|
||||
})
|
||||
.catch((err: any) => {
|
||||
setMessageToast("Não foi possível criar o alerta!");
|
||||
setToastColor("danger");
|
||||
setShowToast(true);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<IonPage>
|
||||
<PageHeader
|
||||
pageName="Resultados da busca"
|
||||
backButtonPageUrl="/buscar/itinerario"
|
||||
/>
|
||||
<IonContent fullscreen>
|
||||
<IonCard color="light">
|
||||
<IonCardHeader>
|
||||
<IonCardSubtitle>Origem: {props.addressFrom.label}</IonCardSubtitle>
|
||||
</IonCardHeader>
|
||||
</IonCard>
|
||||
<IonCard color="light">
|
||||
<IonCardHeader>
|
||||
<IonCardSubtitle>Destino: {props.addressTo.label}</IonCardSubtitle>
|
||||
</IonCardHeader>
|
||||
</IonCard>
|
||||
|
||||
{itinerariesList && itinerariesList.length !== 0 ? (
|
||||
<>
|
||||
<IonItemDivider color="secondary">Resultados</IonItemDivider>
|
||||
{itinerariesList.map((itinerary, index) => {
|
||||
return (
|
||||
<IonCard
|
||||
button
|
||||
key={index}
|
||||
onClick={() => {
|
||||
history.push(`/itinerary/${itinerary.id_itinerary}`);
|
||||
}}
|
||||
>
|
||||
<IonCardHeader>
|
||||
<IonCardTitle>{itinerary.itinerary_nickname}</IonCardTitle>
|
||||
<IonCardContent>
|
||||
<p>
|
||||
<IonIcon icon={personOutline} /> Vagas disponíveis:{" "}
|
||||
{itinerary.available_seats}
|
||||
</p>
|
||||
<p>
|
||||
<IonIcon icon={starOutline} /> Motorista:{" "}
|
||||
{itinerary.price}
|
||||
</p>
|
||||
<p>
|
||||
<IonIcon icon={cashOutline} /> Valor:{" "}
|
||||
{convertNumberToPrice(itinerary.price)}
|
||||
</p>
|
||||
</IonCardContent>
|
||||
</IonCardHeader>
|
||||
</IonCard>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="msg-not-found">
|
||||
<IonCard>
|
||||
<IonCardContent>
|
||||
<span>
|
||||
Não foi encontrado nenhum itinerário que atenda essa rota.
|
||||
</span>
|
||||
</IonCardContent>
|
||||
</IonCard>
|
||||
<IonCard>
|
||||
<IonCardContent>
|
||||
<span>
|
||||
Deseja criar um alerta para ser notificado caso haja
|
||||
itinerário para essa origem e destino?
|
||||
</span>
|
||||
<div className="button-criar-alerta">
|
||||
<IonButton onClick={() => criaAlerta()}>
|
||||
Criar Alerta
|
||||
</IonButton>
|
||||
</div>
|
||||
</IonCardContent>
|
||||
</IonCard>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<IonFab
|
||||
onClick={() => setShowModalFilters(true)}
|
||||
vertical="bottom"
|
||||
horizontal="center"
|
||||
slot="fixed"
|
||||
>
|
||||
<IonFabButton>Filtros</IonFabButton>
|
||||
</IonFab>
|
||||
<IonModal isOpen={showModalFilters}>
|
||||
<IonHeader translucent>
|
||||
<IonToolbar>
|
||||
<IonTitle>Filtros</IonTitle>
|
||||
<IonButtons slot="start">
|
||||
<IonIcon
|
||||
size="large"
|
||||
icon={closeOutline}
|
||||
onClick={() => setShowModalFilters(false)}
|
||||
/>
|
||||
</IonButtons>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
|
||||
<IonContent>
|
||||
<IonList>
|
||||
<IonListHeader>Ordenar por</IonListHeader>
|
||||
<IonRadioGroup>
|
||||
<IonItem>
|
||||
<IonLabel>Sem filtro</IonLabel>
|
||||
<IonRadio value="sem_filtro" />
|
||||
</IonItem>
|
||||
|
||||
<IonItem>
|
||||
<IonLabel>Menor preço</IonLabel>
|
||||
<IonRadio value="menor_preco" />
|
||||
</IonItem>
|
||||
|
||||
<IonItem>
|
||||
<IonLabel>Avaliação</IonLabel>
|
||||
<IonRadio value="avaliacao" />
|
||||
</IonItem>
|
||||
|
||||
<IonItem>
|
||||
<IonLabel>Lugares disponíveis</IonLabel>
|
||||
<IonRadio value="lugares_disponiveis" />
|
||||
</IonItem>
|
||||
</IonRadioGroup>
|
||||
</IonList>
|
||||
|
||||
<IonItemDivider />
|
||||
|
||||
<IonList>
|
||||
<IonListHeader>Preferências</IonListHeader>
|
||||
<IonItem>
|
||||
<IonLabel>Vaga avulsa</IonLabel>
|
||||
<IonCheckbox value="vaga_avulsa" />
|
||||
</IonItem>
|
||||
<IonItem>
|
||||
<IonLabel>Ar condicionado</IonLabel>
|
||||
<IonCheckbox value="ar_condicionado" />
|
||||
</IonItem>
|
||||
<IonItem>
|
||||
<IonLabel>Assento preferencial</IonLabel>
|
||||
<IonCheckbox value="assento_preferencial" />
|
||||
</IonItem>
|
||||
</IonList>
|
||||
</IonContent>
|
||||
|
||||
<IonFooter>
|
||||
<IonButton
|
||||
expand="block"
|
||||
onClick={() => setShowModalFilters(false)}
|
||||
>
|
||||
Aplicar Filtros
|
||||
</IonButton>
|
||||
</IonFooter>
|
||||
</IonModal>
|
||||
|
||||
<IonToast
|
||||
// cssClass={"toast-notification"}
|
||||
color={toastColor}
|
||||
isOpen={showToast}
|
||||
onDidDismiss={() => closeToast(setShowToast)}
|
||||
message={messageToast}
|
||||
duration={2500}
|
||||
/>
|
||||
</IonContent>
|
||||
</IonPage>
|
||||
);
|
||||
};
|
||||
|
||||
export default ListaItinerarios;
|
||||
@@ -1,224 +0,0 @@
|
||||
import {
|
||||
IonContent,
|
||||
IonPage,
|
||||
IonFab,
|
||||
IonFabButton,
|
||||
IonIcon,
|
||||
IonCard,
|
||||
IonInput,
|
||||
IonRow,
|
||||
IonCol,
|
||||
IonCardContent,
|
||||
IonButton,
|
||||
IonHeader,
|
||||
IonToolbar,
|
||||
IonButtons,
|
||||
IonBackButton,
|
||||
IonTabs,
|
||||
IonTabBar,
|
||||
IonTabButton,
|
||||
IonLabel,
|
||||
IonBadge,
|
||||
IonRouterOutlet,
|
||||
IonSlides,
|
||||
IonSlide,
|
||||
IonModal,
|
||||
IonList,
|
||||
IonRadioGroup,
|
||||
IonListHeader,
|
||||
IonItem,
|
||||
IonRadio,
|
||||
IonCheckbox,
|
||||
IonFooter,
|
||||
IonToast,
|
||||
} from "@ionic/react";
|
||||
import {
|
||||
arrowBack,
|
||||
arrowBackOutline,
|
||||
arrowForwardOutline,
|
||||
chevronBackOutline,
|
||||
chevronForwardOutline,
|
||||
closeOutline,
|
||||
locateOutline,
|
||||
locationOutline,
|
||||
timeOutline,
|
||||
} from "ionicons/icons";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useHistory, useLocation } from "react-router";
|
||||
import itinerariesService from "../../services/functions/itinerariesService";
|
||||
import { createUserSearch } from "../../services/api/users";
|
||||
import "./Transportes.css";
|
||||
import { closeToast } from "../../services/utils";
|
||||
|
||||
interface InfoBusca {
|
||||
addressFrom: any;
|
||||
addressTo: any;
|
||||
coordinatesFrom: any;
|
||||
coordinatesTo: any;
|
||||
}
|
||||
|
||||
const Transportes: React.FC = () => {
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
const props = location.state as InfoBusca;
|
||||
const [itinerarios, setItinerarios] = useState([]);
|
||||
const [showModalFilters, setShowModalFilters] = useState(false);
|
||||
const [showToast, setShowToast] = useState(false);
|
||||
const [messageToast, setMessageToast ] = useState('');
|
||||
const [toastColor, setToastColor] = useState('success');
|
||||
|
||||
useEffect(() => {
|
||||
if (props) {
|
||||
buscaItinerarios();
|
||||
}
|
||||
}, [props]);
|
||||
|
||||
async function buscaItinerarios() {
|
||||
let data = (await itinerariesService.searchItineraries(props)) as any;
|
||||
setItinerarios(data);
|
||||
}
|
||||
|
||||
function criaAlerta(){
|
||||
createUserSearch(props.coordinatesFrom.lat, props.coordinatesFrom.lng, props.addressTo.label).then(() => {
|
||||
setMessageToast('Alerta criado com sucesso!');
|
||||
setShowToast(true);
|
||||
}).catch((err:any) => {
|
||||
setMessageToast('Não foi possível criar o alerta!');
|
||||
setToastColor('danger');
|
||||
setShowToast(true);
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<IonPage>
|
||||
{/* TODO, componentizar Header */}
|
||||
<IonHeader>
|
||||
<div className="header-page">
|
||||
{/* <IonButtons slot="start">
|
||||
<IonBackButton text={'aaaa'} icon={arrowBack} defaultHref='buscar-transporte' />
|
||||
</IonButtons> */}
|
||||
<span className="span-info-back" onClick={history.goBack}>
|
||||
<IonIcon className="icon-return" icon={chevronBackOutline} />
|
||||
<div className="address-from-to">
|
||||
<span>{props.addressFrom.label}</span>
|
||||
<IonIcon icon={arrowForwardOutline} />
|
||||
<span>{props.addressTo.label}</span>
|
||||
<small>Hoje</small>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</IonHeader>
|
||||
<IonContent fullscreen>
|
||||
{itinerarios && itinerarios.length > 0? (
|
||||
<div className="header-tabs">
|
||||
<IonSlides>
|
||||
<IonSlide>
|
||||
<h5>Mais barata</h5>
|
||||
<IonCard className="card-transporte">
|
||||
<IonCardContent>Seu João</IonCardContent>
|
||||
</IonCard>
|
||||
</IonSlide>
|
||||
<IonSlide>
|
||||
<h5>Melhor avaliação</h5>
|
||||
<IonCard className="card-transporte">
|
||||
<IonCardContent>Seu Zé</IonCardContent>
|
||||
</IonCard>
|
||||
</IonSlide>
|
||||
</IonSlides>
|
||||
</div>
|
||||
)
|
||||
:
|
||||
(<h1 className="msg-not-found">Não foi encontrado nenhum transporte que atenda essa rota.</h1>)}
|
||||
{itinerarios &&
|
||||
itinerarios.map((record: any, index: any) => {
|
||||
return (
|
||||
<IonCard className="card-transporte" key={index}>
|
||||
<IonCardContent>
|
||||
<h1>Motorista: {record.motorista}</h1>
|
||||
<div>Avaliação: {record.avaliacao}</div>
|
||||
<div>Valor: {record.valor}</div>
|
||||
<div>Lugares disponíveis: {record.lugares}</div>
|
||||
</IonCardContent>
|
||||
</IonCard>
|
||||
);
|
||||
})}
|
||||
|
||||
<div className="button-criar-alerta">
|
||||
<IonButton onClick={() => criaAlerta()}>Criar Alerta</IonButton>
|
||||
</div>
|
||||
|
||||
<IonFab
|
||||
onClick={() => setShowModalFilters(true)}
|
||||
vertical="bottom"
|
||||
horizontal="center"
|
||||
slot="fixed"
|
||||
>
|
||||
<IonFabButton>Filtros</IonFabButton>
|
||||
</IonFab>
|
||||
<IonModal isOpen={showModalFilters}>
|
||||
<IonToolbar>
|
||||
<div className="header-filter-modal">
|
||||
<IonIcon
|
||||
size="large"
|
||||
icon={closeOutline}
|
||||
onClick={() => setShowModalFilters(false)}
|
||||
/>
|
||||
<h4>
|
||||
<b>Limpar</b>
|
||||
</h4>
|
||||
</div>
|
||||
</IonToolbar>
|
||||
<IonContent>
|
||||
<div className="content-filter-modal">
|
||||
<h1>Filtrar</h1>
|
||||
<h3>Ordernar por</h3>
|
||||
<IonRadioGroup>
|
||||
<IonItem>
|
||||
<IonLabel>Menor preço</IonLabel>
|
||||
<IonRadio value="menor_preco" />
|
||||
</IonItem>
|
||||
|
||||
<IonItem>
|
||||
<IonLabel>Avaliação</IonLabel>
|
||||
<IonRadio value="avaliacao" />
|
||||
</IonItem>
|
||||
|
||||
<IonItem>
|
||||
<IonLabel>Lugares disponíveis</IonLabel>
|
||||
<IonRadio value="lugares_disponiveis" />
|
||||
</IonItem>
|
||||
</IonRadioGroup>
|
||||
<h3>Preferências</h3>
|
||||
<IonItem>
|
||||
<IonLabel>Vaga avulsa</IonLabel>
|
||||
<IonCheckbox value="vaga_avulsa" />
|
||||
</IonItem>
|
||||
<IonItem>
|
||||
<IonLabel>Ar condicionado</IonLabel>
|
||||
<IonCheckbox value="ar_condicionado" />
|
||||
</IonItem>
|
||||
</div>
|
||||
</IonContent>
|
||||
<IonFooter>
|
||||
<IonButton
|
||||
expand="block"
|
||||
onClick={() => setShowModalFilters(false)}
|
||||
>
|
||||
Aplicar Filtros
|
||||
</IonButton>
|
||||
</IonFooter>
|
||||
</IonModal>
|
||||
<IonToast
|
||||
// cssClass={"toast-notification"}
|
||||
color={toastColor}
|
||||
isOpen={showToast}
|
||||
onDidDismiss={() => closeToast(setShowToast)}
|
||||
message={messageToast}
|
||||
duration={2500}
|
||||
/>
|
||||
</IonContent>
|
||||
</IonPage>
|
||||
);
|
||||
};
|
||||
|
||||
export default Transportes;
|
||||
@@ -10,3 +10,13 @@ export async function closeToast(setShowToast: React.Dispatch<React.SetStateActi
|
||||
setShowToast(false)
|
||||
window.history.replaceState({}, document.title)
|
||||
}
|
||||
|
||||
export function convertNumberToPrice(price: number) {
|
||||
// Create our number formatter.
|
||||
var formatter = new Intl.NumberFormat('pt-BR', {
|
||||
style: 'currency',
|
||||
currency: 'BRL',
|
||||
});
|
||||
|
||||
return formatter.format(price);
|
||||
}
|
||||
Reference in New Issue
Block a user