Skip to content

Commit

Permalink
Merge branch 'main' into pv-dependabot-fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
vecchp authored Dec 18, 2024
2 parents c52d7db + 9e1ea0d commit 22a65fd
Show file tree
Hide file tree
Showing 84 changed files with 1,662 additions and 600 deletions.
1 change: 1 addition & 0 deletions apps/shelter-web/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.env
.env.production
12 changes: 12 additions & 0 deletions apps/shelter-web/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@
"options": {
"jestConfig": "apps/shelter-web/jest.config.ts"
}
},
"build": {
"executor": "@nx/vite:build",
"options": {
"outputPath": "dist/apps/shelter-web",
"configFile": "apps/shelter-web/vite.config.mts"
},
"configurations": {
"production": {
"mode": "production"
}
}
}
}
}
1 change: 1 addition & 0 deletions apps/shelter-web/src/app/app.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const SHELTERS_MAP_ID = 'shelters-map';
23 changes: 16 additions & 7 deletions apps/shelter-web/src/app/app.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
import { APIProvider as MapsApiProvider } from '@vis.gl/react-google-maps';
import { Route, Routes } from 'react-router-dom';
import { MainLayout } from './layout/mainLayout';
import { routeChildren } from './routes/appRoutes';

const googleMapsApiKey = import.meta.env.VITE_GOOGLE_MAPS_API_KEY;

export function App() {
function onMapsProviderError(error: unknown) {
console.error(`MapsApiProvider error ${error}`);
}

return (
<Routes>
<Route path="/" element={<MainLayout />}>
{routeChildren.map((route) => (
<Route key={route.path} path={route.path} element={route.element} />
))}
</Route>
</Routes>
<MapsApiProvider apiKey={googleMapsApiKey} onError={onMapsProviderError}>
<Routes>
<Route path="/" element={<MainLayout />}>
{routeChildren.map((route) => (
<Route key={route.path} path={route.path} element={route.element} />
))}
</Route>
</Routes>
</MapsApiProvider>
);
}

Expand Down
1 change: 1 addition & 0 deletions apps/shelter-web/src/app/constants.app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const SHELTERS_MAP_ID = 'ba-shelters-map';
53 changes: 37 additions & 16 deletions apps/shelter-web/src/app/pages/home/home.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,50 @@
import { APIProvider as MapsApiProvider } from '@vis.gl/react-google-maps';
import { useState } from 'react';
import { useAtom } from 'jotai';
import { useEffect, useState } from 'react';
import { SHELTERS_MAP_ID } from '../../constants.app';
import { MaxWLayout } from '../../layout/maxWLayout';
import { Map } from '../../shared/components/maps/map';
import { TLatLng } from '../../shared/components/maps/types.maps';
import { locationAtom } from '../../shared/atoms/locationAtom';
import { sheltersAtom } from '../../shared/atoms/sheltersAtom';
import { Map } from '../../shared/components/map/map';
import { TLatLng, TMarker } from '../../shared/components/map/types.maps';
import { ShelterSearch } from '../../shared/components/shelters/shelterSearch';

const googleMapsApiKey = import.meta.env.VITE_GOOGLE_MAPS_API_KEY;

export function Home() {
const [coordinates, setCoordinates] = useState<TLatLng | null>();
const [_location, setLocation] = useAtom(locationAtom);
const [shelters] = useAtom(sheltersAtom);
const [shelterMarkers, setShelterMarkers] = useState<TMarker[]>([]);

function onProviderError(error: unknown) {
console.error(`MapsApiProvider error ${error}`);
}
useEffect(() => {
const markers = shelters
.filter((shelter) => !!shelter.location)
.map((shelter) => {
return {
id: shelter.id,
position: shelter.location,
label: shelter.name,
} as TMarker;
});

setShelterMarkers(markers);
}, [shelters]);

function onLocationChange(coordinates: TLatLng | null) {
setCoordinates(coordinates);
function onCenterSelect(center: TLatLng) {
setLocation({
...center,
source: 'currentLocation',
});
}

return (
<MapsApiProvider apiKey={googleMapsApiKey} onError={onProviderError}>
<>
<MaxWLayout className="-mx-4">
<Map className="h-[480px] md:h-80" center={coordinates} />
<Map
className="h-[70vh] md:h-80"
mapId={SHELTERS_MAP_ID}
markers={shelterMarkers}
onCenterSelect={onCenterSelect}
/>
</MaxWLayout>
<ShelterSearch onLocationChange={onLocationChange} />
</MapsApiProvider>
<ShelterSearch />
</>
);
}
10 changes: 10 additions & 0 deletions apps/shelter-web/src/app/shared/atoms/locationAtom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { atom } from 'jotai';
import { TLatLng } from '../components/map/types.maps';

export type TLocationSource = 'currentLocation' | 'address';

export interface TLocation extends TLatLng {
source: TLocationSource;
}

export const locationAtom = atom<TLocation | null | undefined>(undefined);
4 changes: 4 additions & 0 deletions apps/shelter-web/src/app/shared/atoms/sheltersAtom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { atom } from 'jotai';
import { TShelter } from '../components/shelter/shelterCard';

export const sheltersAtom = atom<TShelter[]>([]);
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { SearchIcon } from '@monorepo/react/icons';
import { useApiIsLoaded, useMapsLibrary } from '@vis.gl/react-google-maps';
import { useMapsLibrary } from '@vis.gl/react-google-maps';
import { useCallback, useEffect, useState } from 'react';
import { ISO3166Alpha2 } from '../../../types/isoCodes';
import { Input } from '../form/input';
import { LA_COUNTY_CENTER, getPlacesBounds } from '../maps/getPlacesBounds';
import { LA_COUNTY_CENTER } from '../map/constants.maps';
import { getPlacesBounds } from '../map/utils/getPlacesBounds';
import { AddressSuggestion } from './addressSuggestion';

const boundsLA = getPlacesBounds({
Expand All @@ -20,8 +21,6 @@ type TPlaceAutocomplete = {
export const AddressAutocomplete = (props: TPlaceAutocomplete) => {
const { onPlaceSelect, countryRestrictions = 'us', className = '' } = props;

const apiIsLoaded = useApiIsLoaded();

const [inputValue, setInputValue] = useState<string>('');
const [sessionToken, setSessionToken] = useState<
google.maps.places.AutocompleteSessionToken | undefined
Expand All @@ -35,7 +34,7 @@ export const AddressAutocomplete = (props: TPlaceAutocomplete) => {
const places = useMapsLibrary('places');

useEffect(() => {
if (!apiIsLoaded) {
if (!places) {
return;
}

Expand Down
103 changes: 0 additions & 103 deletions apps/shelter-web/src/app/shared/components/currentLocation.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { PropsWithChildren } from 'react';
import { mergeCss } from '../../utils/styles/mergeCss';
import { TLatLng } from '../map/types.maps';
import {
GeolocationErrorKey,
TLocationError,
getGeolocationErrorName,
} from './currentLocationError';

const POSITION_TIMEOUT_MS = 20 * 1000;

interface ICurrentLocation extends PropsWithChildren {
onChange: (location: TLatLng) => void;
onError: (error: TLocationError) => void;
className?: string;
timeout?: number;
}

export function CurrentLocation(props: ICurrentLocation) {
const {
onChange,
onError,
timeout = POSITION_TIMEOUT_MS,
className,
children,
} = props;

if (!navigator.geolocation) {
onError && onError('FEATURE_UNAVAILABLE');

return null;
}

const onLocationSuccess = (position: GeolocationPosition): void => {
onChange &&
onChange({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
});
};

const onLocationError = (err: GeolocationPositionError): void => {
onError &&
onError(getGeolocationErrorName(err.code as GeolocationErrorKey));
};

const getLocation = (): void => {
const options: PositionOptions = {
enableHighAccuracy: true,
timeout, // error out if takes longer
maximumAge: 0,
};

navigator.geolocation.getCurrentPosition(
onLocationSuccess,
onLocationError,
options
);
};

if (!children) {
return null;
}

const btnCss = ['w-full', 'h-full', className];

return (
<button className={mergeCss(btnCss)} onClick={getLocation}>
{children}
</button>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export type TLocationError =
| 'PERMISSION_DENIED'
| 'POSITION_UNAVAILABLE'
| 'TIMEOUT'
| 'FEATURE_UNAVAILABLE'
| 'UNKNOWN';

const GeolocationErrorNameMap = {
1: 'PERMISSION_DENIED',
2: 'POSITION_UNAVAILABLE',
3: 'TIMEOUT',
} as const;

export type GeolocationErrorKey = keyof typeof GeolocationErrorNameMap;

export function getGeolocationErrorName(
errorCode: GeolocationErrorKey
): TLocationError {
return GeolocationErrorNameMap[errorCode];
}
10 changes: 10 additions & 0 deletions apps/shelter-web/src/app/shared/components/map/constants.maps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { TLatLng } from './types.maps';

export const MILES_TO_DEGREES_AT_EQUATOR = 69.172;
export const DEFAULT_BOUNDS_MILES = 2;
export const LA_COUNTY_CENTER: TLatLng = {
latitude: 34.04499,
longitude: -118.251601,
};
export const DEFAULT_MAP_ZOOM = 13;
export const DEFAULT_GESTURE_HANDLING = 'greedy';
Loading

0 comments on commit 22a65fd

Please sign in to comment.