Skip to content

Commit

Permalink
Improved Traveltimes Data Display & Frontend Map Feature
Browse files Browse the repository at this point in the history
- Modified TravelTimes type (isolated from Apartments type)
- Implemented map recenter feature upon map modal closure
- Implemented mobile map modal
  • Loading branch information
CasperL1218 committed Nov 15, 2024
1 parent 76c933d commit 09b3fe0
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 115 deletions.
5 changes: 0 additions & 5 deletions backend/scripts/add_buildings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,6 @@ const formatBuilding = ({
area: getAreaType(area),
latitude,
longitude,
travelTimes: {
agQuad: { walk: 0, drive: 0 },
engQuad: { walk: 0, drive: 0 },
hoPlaza: { walk: 0, drive: 0 },
},
});

const makeBuilding = async (apartmentWithId: ApartmentWithId) => {
Expand Down
41 changes: 5 additions & 36 deletions backend/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,46 +212,14 @@ app.get('/api/apts/:ids', async (req, res) => {
try {
const { ids } = req.params;
const idsList = ids.split(',');
// Fetching each apartment and its travel times from the database
// Fetching each apartment from the database and returning an array of apartment objects
const aptsArr = await Promise.all(
idsList.map(async (id) => {
const [snapshot, travelTimeDoc] = await Promise.all([
buildingsCollection.doc(id).get(),
travelTimesCollection.doc(id).get(),
]);

const snapshot = await buildingsCollection.doc(id).get();
if (!snapshot.exists) {
throw new Error('Invalid id');
}

// Transform travel times to match LocationTravelTimes schema
const rawTravelTimes = travelTimeDoc.exists ? travelTimeDoc.data() : null;
const travelTimes: LocationTravelTimes = rawTravelTimes
? {
agQuad: {
walk: rawTravelTimes.agQuadWalking,
drive: rawTravelTimes.agQuadDriving,
},
engQuad: {
walk: rawTravelTimes.engQuadWalking,
drive: rawTravelTimes.engQuadDriving,
},
hoPlaza: {
walk: rawTravelTimes.hoPlazaWalking,
drive: rawTravelTimes.hoPlazaDriving,
},
}
: {
agQuad: { walk: 0, drive: 0 },
engQuad: { walk: 0, drive: 0 },
hoPlaza: { walk: 0, drive: 0 },
};

return {
id,
...snapshot.data(),
travelTimes,
} as ApartmentWithId;
return { id, ...snapshot.data() } as ApartmentWithId;
})
);
res.status(200).send(JSON.stringify(aptsArr));
Expand Down Expand Up @@ -1235,7 +1203,8 @@ app.get('/api/travel-times-by-id/:buildingId', async (req, res) => {
return res.status(404).json({ error: 'Travel times not found for this building' });
}

const travelTimes = travelTimeDoc.data() as TravelTimes;
const travelTimes = travelTimeDoc.data() as LocationTravelTimes;

return res.status(200).json(travelTimes);
} catch (error) {
console.error('Error retrieving travel times:', error);
Expand Down
15 changes: 6 additions & 9 deletions common/types/db-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,15 @@ export type Apartment = {
readonly area: 'COLLEGETOWN' | 'WEST' | 'NORTH' | 'DOWNTOWN' | 'OTHER';
readonly latitude: number;
readonly longitude: number;
readonly travelTimes: LocationTravelTimes;
};

type TravelTime = {
walk: number;
drive: number;
};

export type LocationTravelTimes = {
agQuad: TravelTime;
engQuad: TravelTime;
hoPlaza: TravelTime;
agQuadDriving: number;
agQuadWalking: number;
engQuadDriving: number;
engQuadWalking: number;
hoPlazaDriving: number;
hoPlazaWalking: number;
};

export type ApartmentWithId = Apartment & Id;
Expand Down
58 changes: 21 additions & 37 deletions frontend/src/components/Apartment/MapInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React, { ReactElement, useRef } from 'react';
import React, { ReactElement, useRef, useEffect } from 'react';
import { Box, Grid, IconButton, Typography, makeStyles } from '@material-ui/core';
import GoogleMapReact from 'google-map-react';
import aptIcon from '../../assets/location-pin.svg';
import schoolIcon from '../../assets/school-pin.svg';
import expandIcon from '../../assets/expand-button.svg';
import zoomInIcon from '../../assets/zoom-in-icon.png';
import zoomOutIcon from '../../assets/zoom-out-icon.png';
import recenterIcon from '../../assets/recenter-icon.svg';
import blackPinIcon from '../../assets/ph_map-pin-fill.svg';
import { config } from 'dotenv';
import { Marker } from './Marker';
Expand All @@ -19,11 +18,12 @@ export type BaseProps = {
readonly latitude?: number;
readonly longitude?: number;
readonly travelTimes?: LocationTravelTimes;
isMobile: boolean;
};

type MapInfoProps = BaseProps & {
handleClick: () => void;
isMobile: boolean;
mapToggle: boolean;
};

export type distanceProps = {
Expand Down Expand Up @@ -141,57 +141,39 @@ const useStyles = makeStyles((theme) => ({
* - `longitude`: The longitude of the apartment location.
* - `walkTime`: The walk time from the apartment to campus landmarks.
*/
export default function MapInfo({
function MapInfo({
address,
latitude = 0,
longitude = 0,
travelTimes,
handleClick,
mapToggle,
isMobile,
}: MapInfoProps): ReactElement {
const { outerMapDiv, innerMapDiv, mapExpandButton, recenterButton, zoomInButton, zoomOutButton } =
useStyles();
const { outerMapDiv, innerMapDiv, mapExpandButton, zoomInButton, zoomOutButton } = useStyles();
const mapRef = useRef<google.maps.Map | null>(null);

const handleApiLoaded = ({ map, maps }: { map: google.maps.Map; maps: typeof google.maps }) => {
mapRef.current = map;
};

const handleRecenter = () => {
useEffect(() => {
if (mapRef.current) {
mapRef.current.setCenter({ lat: latitude, lng: longitude });
mapRef.current.setZoom(16);
}
};
}, [mapToggle, latitude, longitude]);

// Function to handle zoom in/out of the map
const handleZoom = (zoomChange: number) => {
if (mapRef.current) {
const currentZoom = mapRef.current.getZoom() || 16; // Ensure there is a valid value for currentZoom
const currentZoom = mapRef.current.getZoom() || 16;
const newZoom = currentZoom + zoomChange;
if (newZoom > 11 && newZoom < 20) {
// Ensure the new zoom is within the allowed range
mapRef.current.setZoom(newZoom);
}
}
};

const expandOrRecenter = (isMobile: boolean) => {
return isMobile ? (
<IconButton disableRipple className={recenterButton} onClick={handleRecenter}>
<img
src={recenterIcon}
alt={'recenter-icon'}
style={{ width: '21.4px', height: '21.4px' }}
/>
</IconButton>
) : (
<IconButton onClick={handleClick} className={mapExpandButton} disableRipple>
<img src={expandIcon} alt={'expand-icon'} style={{ width: '21.4px', height: '21.4px' }} />
</IconButton>
);
};

return (
<Box border={1} borderColor="grey.300" borderRadius={10} mb={3}>
<Box mx={3} my={3}>
Expand All @@ -216,12 +198,6 @@ export default function MapInfo({
src={schoolIcon}
altText="Engineering Quad icon"
/>
<Marker
lat={42.449014547431425}
lng={-76.48413980587392}
src={schoolIcon}
altText="Arts Quad icon"
/>
<Marker
lat={42.446768276610875}
lng={-76.48505175766948}
Expand All @@ -236,7 +212,13 @@ export default function MapInfo({
/>
</GoogleMapReact>
</div>
{expandOrRecenter(isMobile)}
<IconButton onClick={handleClick} className={mapExpandButton} disableRipple>
<img
src={expandIcon}
alt={'expand-icon'}
style={{ width: '21.4px', height: '21.4px' }}
/>
</IconButton>
{
<div>
<IconButton disableRipple className={zoomInButton} onClick={() => handleZoom(1)}>
Expand Down Expand Up @@ -276,19 +258,21 @@ export default function MapInfo({
</Typography>
<WalkDistanceInfo
location={'Engineering Quad'}
walkDistance={Math.round(travelTimes?.engQuad.walk || 0)}
walkDistance={Math.round(travelTimes?.engQuadWalking || 0)}
/>
<WalkDistanceInfo
location={'Ho Plaza'}
walkDistance={Math.round(travelTimes?.hoPlaza.walk || 0)}
walkDistance={Math.round(travelTimes?.hoPlazaWalking || 0)}
/>
<WalkDistanceInfo
location={'Ag Quad'}
walkDistance={Math.round(travelTimes?.agQuad.walk || 0)}
walkDistance={Math.round(travelTimes?.agQuadWalking || 0)}
/>
</Box>
</Box>
</Box>
</Box>
);
}

export default MapInfo;
47 changes: 23 additions & 24 deletions frontend/src/components/Apartment/MapModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,26 @@ import { BaseProps, distanceProps } from './MapInfo';

const useStyles = makeStyles((theme) => ({
paper: {
borderRadius: '13.895px',
maxWidth: '70%',
maxHeight: '94%',
borderRadius: ({ isMobile }: { isMobile: boolean }) => (isMobile ? '0px' : '13.895px'),
maxWidth: ({ isMobile }: { isMobile: boolean }) => (isMobile ? '100%' : '70%'),
maxHeight: ({ isMobile }: { isMobile: boolean }) => (isMobile ? '100%' : '94%'),
height: ({ isMobile }: { isMobile: boolean }) => (isMobile ? '100%' : 'auto'),
margin: ({ isMobile }: { isMobile: boolean }) => (isMobile ? '0' : undefined),
overflow: 'hidden',
},
outerMapDiv: {
height: '50vh',
width: '94%',
borderRadius: '12.764px',
height: ({ isMobile }: { isMobile: boolean }) => (isMobile ? '65vh' : '50vh'),
width: ({ isMobile }: { isMobile: boolean }) => (isMobile ? '100%' : '94%'),
borderRadius: '0px',
overflow: 'hidden',
outline: 'none',
position: 'relative',
marginBottom: '30px',
marginBottom: ({ isMobile }: { isMobile: boolean }) => (isMobile ? '0' : '30px'),
},
innerMapDiv: {
height: '130%',
width: '100%',
borderRadius: '12.764px',
borderRadius: '0px',
overflow: 'hidden',
outline: 'none',
position: 'absolute',
Expand All @@ -68,7 +70,8 @@ const useStyles = makeStyles((theme) => ({
width: '100%',
overflow: 'auto',
alignItems: 'center',
marginBottom: '30px',
marginBottom: ({ isMobile }: { isMobile: boolean }) => (isMobile ? '0' : '30px'),
padding: ({ isMobile }: { isMobile: boolean }) => (isMobile ? '0' : undefined),
},
addressTypography: {
fontWeight: 600,
Expand Down Expand Up @@ -110,6 +113,7 @@ interface MapModalProps extends BaseProps {
* - `walkTime`: The walk time from the apartment to campus landmarks (default: 0).
* - `driveTime`: The drive time from the apartment to campus landmarks (default: 0).
*/

const MapModal = ({
aptName,
open,
Expand All @@ -119,11 +123,11 @@ const MapModal = ({
latitude = 0,
longitude = 0,
travelTimes,
isMobile,
}: MapModalProps) => {
const classes = useStyles();
const classes = useStyles({ isMobile });
const theme = useTheme();
const mapRef = useRef<google.maps.Map | null>(null);
const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
const isMediumScreen = useMediaQuery(theme.breakpoints.up('lg'));

const handleApiLoaded = ({ map, maps }: { map: google.maps.Map; maps: typeof google.maps }) => {
Expand Down Expand Up @@ -217,6 +221,7 @@ const MapModal = ({
}}
maxWidth="md"
fullWidth
fullScreen={isMobile}
>
<DialogTitle style={{ padding: '16px' }}>
<Grid container justifyContent="space-between" alignItems="center">
Expand All @@ -229,7 +234,7 @@ const MapModal = ({
</Typography>
</Grid>
<Grid item>
<IconButton onClick={() => setOpen(false)} style={{ padding: 0 }}>
<IconButton onClick={onClose} style={{ padding: 0 }}>
<img
src={closeMapIcon}
alt={'close-icon'}
Expand Down Expand Up @@ -264,12 +269,6 @@ const MapModal = ({
src={schoolIcon}
altText="Engineering Quad icon"
/>
<Marker
lat={42.449014547431425}
lng={-76.48413980587392}
src={schoolIcon}
altText="Arts Quad icon"
/>
<Marker
lat={42.446768276610875}
lng={-76.48505175766948}
Expand Down Expand Up @@ -335,18 +334,18 @@ const MapModal = ({
<Typography className={classes.distanceTypography}>Distance from Campus</Typography>
<DistanceInfo
location={'Engineering Quad'}
walkTime={Math.round(travelTimes?.engQuad?.walk || 0)}
driveTime={Math.round(travelTimes?.engQuad?.drive || 0)}
walkTime={Math.round(travelTimes?.engQuadWalking || 0)}
driveTime={Math.round(travelTimes?.engQuadDriving || 0)}
/>
<DistanceInfo
location={'Ho Plaza'}
walkTime={Math.round(travelTimes?.hoPlaza?.walk || 0)}
driveTime={Math.round(travelTimes?.hoPlaza?.drive || 0)}
walkTime={Math.round(travelTimes?.hoPlazaWalking || 0)}
driveTime={Math.round(travelTimes?.hoPlazaDriving || 0)}
/>
<DistanceInfo
location={'Ag Quad'}
walkTime={Math.round(travelTimes?.agQuad?.walk || 0)}
driveTime={Math.round(travelTimes?.agQuad?.drive || 0)}
walkTime={Math.round(travelTimes?.agQuadWalking || 0)}
driveTime={Math.round(travelTimes?.agQuadDriving || 0)}
/>
</Box>
</Box>
Expand Down
Loading

0 comments on commit 09b3fe0

Please sign in to comment.