@autobusal/common 1.3.2 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,64 @@
1
+ import { TFunction } from 'i18next';
2
+ import { MapContainer, TileLayer, Marker, Popup, Polyline } from 'react-leaflet';
3
+ import { getCoordinates, getPosition, autobusMarker } from './utilities';
4
+ import { Container, Loading, Disclaimer } from './styles';
5
+ import { LocationData } from '@autobusal/providers/types/locations';
6
+ import { useGetDriveData } from './services';
7
+
8
+ interface Props {
9
+ locations: LocationData[]
10
+ t: TFunction<'common'>
11
+ }
12
+
13
+ const Drive = ({ locations, t }: Props): JSX.Element => {
14
+ const coordinates = getCoordinates(locations);
15
+
16
+ const { data: MapData, isLoading } = useGetDriveData(coordinates);
17
+
18
+ if (isLoading) {
19
+ return (
20
+ <Container>
21
+ <Loading className="leaflet-container">{ t('drive.loading', { ns: 'common' }) }</Loading>
22
+ </Container>
23
+ );
24
+ }
25
+
26
+ // we get the coordinates for the roads to paint
27
+ const geometryData = MapData?.features[0].geometry.coordinates;
28
+
29
+ // we paint the drive lines
30
+ const lines = geometryData?.map((item, index) => {
31
+ const nextLocation = geometryData[index + 1] ?? item;
32
+
33
+ const from = getPosition(item, 'coordinates');
34
+ const to = getPosition(nextLocation, 'coordinates');
35
+
36
+ return <Polyline key={ index } positions={ [from, to] } color="#3388FF" />;
37
+ });
38
+
39
+ // we add the stop markers
40
+ const markers = locations.map((item, index) => (
41
+ <Marker key={ index } position={ getPosition(item.stop?.location) } icon={ autobusMarker }>
42
+ <Popup>
43
+ <strong>{ item.city.name }</strong> <br />
44
+ { item.stop?.name }, { item.departure }
45
+ </Popup>
46
+ </Marker>
47
+ ));
48
+
49
+ return (
50
+ <Container>
51
+ <MapContainer center={ getPosition(locations[0].stop?.location) } minZoom={ 6 } maxZoom={ 13 } zoom={ 6 } scrollWheelZoom={ true }>
52
+ <TileLayer attribution="&copy; <a href='http://osm.org/copyright'>OpenStreetMap</a> contributors" url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
53
+
54
+ { markers }
55
+
56
+ { lines }
57
+ </MapContainer>
58
+
59
+ <Disclaimer>{ t('drive.disclaimer', { ns: 'common' }) }</Disclaimer>
60
+ </Container>
61
+ );
62
+ };
63
+
64
+ export default Drive;
Binary file
Binary file
@@ -0,0 +1,24 @@
1
+ import { useQuery, UseQueryResult } from '@tanstack/react-query';
2
+ import { apiClient } from '@autobusal/providers';
3
+ import { GeoJsonData } from './types';
4
+
5
+ export const useGetDriveData = (coordinates: number[][]): UseQueryResult<GeoJsonData> => (
6
+ useQuery({
7
+ queryKey: ['drive-data'],
8
+ queryFn: async () => (
9
+ await apiClient
10
+ .post('https://api.openrouteservice.org/v2/directions/driving-car/geojson', {
11
+ coordinates
12
+ }, {
13
+ headers: {
14
+ Authorization: import.meta.env.VITE_OPEN_ROUTE_SERVICE_KEY
15
+ },
16
+ withCredentials: false,
17
+ withXSRFToken: false
18
+ })
19
+ .then(response => (
20
+ response.data
21
+ ))
22
+ )
23
+ })
24
+ );
@@ -0,0 +1,34 @@
1
+ import styled from 'styled-components';
2
+ import 'leaflet/dist/leaflet.css';
3
+
4
+ export const Container = styled.div`
5
+ position: relative;
6
+
7
+ & > .leaflet-container {
8
+ width: 100%;
9
+ height: 100%;
10
+ }
11
+ `;
12
+
13
+ export const Loading = styled.div`
14
+ display: flex;
15
+ align-items: center;
16
+ justify-content: center;
17
+ `;
18
+
19
+ export const Disclaimer = styled.div`
20
+ position: absolute;
21
+ bottom: 20px;
22
+ left: 10px;
23
+ right: 10px;
24
+ z-index: 100000;
25
+ padding: 5px;
26
+ text-align: center;
27
+ font-size: ${ props => props.theme.size.xxs };
28
+ color: ${ props => props.theme.font.info };
29
+ background: ${ props => props.theme.menu.transparent };
30
+ border-radius: ${ props => props.theme.borderRadius };
31
+ box-shadow: ${ props => props.theme.boxShadow };
32
+ backdrop-filter: blur(15px);
33
+ -webkit-backdrop-filter: blur(15px);
34
+ `;
package/Drive/types.ts ADDED
@@ -0,0 +1,11 @@
1
+ export interface GeoJsonData {
2
+ features: FeaturesData[]
3
+ }
4
+
5
+ interface FeaturesData {
6
+ geometry: GeometryData
7
+ }
8
+
9
+ interface GeometryData {
10
+ coordinates: string[][]
11
+ }
@@ -0,0 +1,48 @@
1
+ import L, { LatLngExpression } from 'leaflet';
2
+ import markerIcon from './images/marker-icon.png';
3
+ import markerShadow from './images/marker-shadow.png';
4
+ import { LocationData } from '@autobusal/providers/types/locations';
5
+
6
+ const STOP_UNDEFINED = ['0', '0'];
7
+
8
+ export const getCoordinates = (locations: LocationData[]): number[][] => {
9
+ const coordinates: number[][] = [];
10
+
11
+ locations.forEach((item, index) => {
12
+ const nextLocation = locations[index + 1] ?? item;
13
+
14
+ const from = getPosition(item.stop?.location ?? STOP_UNDEFINED, 'coordinates') as number[];
15
+ const to = getPosition(nextLocation.stop?.location ?? STOP_UNDEFINED, 'coordinates') as number[];
16
+
17
+ // we push both coordinates
18
+ coordinates.push(from)
19
+ coordinates.push(to)
20
+ });
21
+
22
+ return coordinates;
23
+ };
24
+
25
+ export const getPosition = (position: string[] | undefined, type: string = 'normal'): LatLngExpression => {
26
+ if (position === undefined) {
27
+ return [0, 0];
28
+ }
29
+
30
+ // for the coordinates, we need to reverse the positions
31
+ if (type !== 'normal') {
32
+ position = position.slice().reverse();
33
+ }
34
+
35
+ return [
36
+ Number(position[0]),
37
+ Number(position[1])
38
+ ];
39
+ };
40
+
41
+ export const autobusMarker = new L.Icon({
42
+ iconUrl: markerIcon,
43
+ iconSize: [25, 41], // icon size
44
+ iconAnchor: [12, 41], // point of the icon which will correspond to marker's location
45
+ popupAnchor: [1, -34], // point from which the popup should open relative to the iconAnchor
46
+ shadowUrl: markerShadow,
47
+ shadowSize: [41, 41] // shadow size
48
+ });
@@ -1,6 +1,6 @@
1
1
  import { UseMutationResult, useMutation } from '@tanstack/react-query';
2
2
  import { apiClient } from '@autobusal/providers';
3
- import { UploadData } from '@autobusal/providers/types';
3
+ import { UploadData } from '@autobusal/providers/types/settings';
4
4
 
5
5
  export const useFileUpload = (): UseMutationResult<UploadData, Error, any, unknown> => (
6
6
  useMutation({
package/index.ts CHANGED
@@ -12,6 +12,7 @@ import ChooseSeat from './Seats/ChooseSeat';
12
12
  import CompanyItem from './CompanyItem/CompanyItem';
13
13
  import ContactInfo from './ContactInfo/ContactInfo';
14
14
  import CookieNotification from './CookieNotification/CookieNotification';
15
+ import Drive from './Drive/Drive';
15
16
  import File from './File/File';
16
17
  import Gender from './Gender';
17
18
  import { General, Inline, Box, BoxMiddle, GeneralFull } from './Loading/Loading';
@@ -48,6 +49,7 @@ export {
48
49
  CompanyItem,
49
50
  ContactInfo,
50
51
  CookieNotification,
52
+ Drive,
51
53
  File,
52
54
  Gender,
53
55
  General,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autobusal/common",
3
- "version": "1.3.2",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "main": "index.ts"
6
6
  }