-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
34 changed files
with
1,386 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# .npmrc | ||
engine-strict=true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
node_modules | ||
# Ignore artifacts: | ||
build | ||
coverage | ||
.gitignore | ||
.npmrc | ||
.prettierignore | ||
yarn.lock | ||
package-lock.json | ||
pnpm-lock.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"editor.defaultFormatter": "esbenp.prettier-vscode", | ||
"editor.formatOnSave": true, | ||
"[json]": { | ||
"editor.defaultFormatter": "esbenp.prettier-vscode" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import path from "path"; | ||
|
||
const config = { | ||
webpack: { | ||
alias: { | ||
"@assets": path.resolve(__dirname, "src/assets"), | ||
"@styles": path.resolve(__dirname, "src/styles"), | ||
"@utils": path.resolve(__dirname, "src/utils"), | ||
"@components": path.resolve(__dirname, "src/components"), | ||
"@pages": path.resolve(__dirname, "src/pages"), | ||
"@constants": path.resolve(__dirname, "src/constants.ts"), | ||
"@types": path.resolve(__dirname, "src/types"), | ||
"@api": path.resolve(__dirname, "src/api"), | ||
"@hooks": path.resolve(__dirname, "src/hooks"), | ||
"@theme": path.resolve(__dirname, "src/theme.ts"), | ||
"@contexts": path.resolve(__dirname, "src/contexts"), | ||
}, | ||
}, | ||
}; | ||
|
||
export default config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"semi": true, | ||
"printWidth": 70, | ||
"tabWidth": 2, | ||
"singleQuote": true, | ||
"bracketSpacing": true, | ||
"jsxBracketSameLine": false, | ||
"useTabs": false, | ||
"arrowParens": "avoid", | ||
"jsxSingleQuote": true, | ||
"trailingComma": "all" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./usersAPI"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { BASE_USERS_API_URL } from "@constants"; | ||
import axios from "axios"; | ||
import { IRandomUserResponse } from "types/user"; | ||
import urlcat from "urlcat"; | ||
|
||
/** | ||
* It takes an object with a property called `results` that is a number (the number of random users to | ||
* get from the server), and returns a promise that | ||
* resolves to an object with a property called `results` that is an array of objects (IUser objects) | ||
* @param - results - the number of users to return | ||
* @returns An object with a property called data that is of type IRandomUserResponse | ||
*/ | ||
export function getRandomUsers({ results = 1 }: { results?: number }) { | ||
const queryURL = urlcat(BASE_USERS_API_URL, `/`, { results }); | ||
|
||
return axios.get(queryURL).then((res) => res.data as IRandomUserResponse); | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { | ||
Dialog, | ||
DialogContent, | ||
DialogContentText, | ||
DialogActions, | ||
Button, | ||
} from "@mui/material"; | ||
import { useMemo } from "react"; | ||
|
||
interface IAlertDialog { | ||
text: string; | ||
isOpen: boolean; | ||
onCancel?: () => void; | ||
onContinue?: () => void; | ||
btnCancelText?: string; | ||
btnContinueText?: string; | ||
} | ||
|
||
/** | ||
* AlertDialog is a function that returns a Material UI Dialog component that displays a message and | ||
* two buttons | ||
* @param {IAlertDialog} - IAlertDialog | ||
* @returns A React component. | ||
*/ | ||
export function AlertDialog({ | ||
text, | ||
isOpen, | ||
onCancel, | ||
onContinue, | ||
btnCancelText, | ||
btnContinueText, | ||
}: IAlertDialog) { | ||
/** | ||
* _handleOnClickCancel() is a function that calls the onCancel prop if onCancel is a function. | ||
*/ | ||
function _handleOnClickCancel() { | ||
if (typeof onCancel === "function") onCancel(); | ||
} | ||
|
||
/** | ||
* _handleOnClickContinue() is a function that calls the onContinue prop if it is a function. | ||
*/ | ||
function _handleOnClickContinue() { | ||
if (typeof onContinue === "function") onContinue(); | ||
} | ||
|
||
const _btnTextCancel = useMemo( | ||
() => btnCancelText ?? "Cancel", | ||
[btnCancelText] | ||
); | ||
const _btnTextContinue = useMemo( | ||
() => btnContinueText ?? "Continue", | ||
[btnContinueText] | ||
); | ||
|
||
return ( | ||
<Dialog open={isOpen} onClose={_handleOnClickCancel}> | ||
<DialogContent> | ||
<DialogContentText>{text}</DialogContentText> | ||
</DialogContent> | ||
<DialogActions> | ||
<Button onClick={_handleOnClickCancel}>{_btnTextCancel}</Button> | ||
<Button onClick={_handleOnClickContinue} autoFocus> | ||
{_btnTextContinue} | ||
</Button> | ||
</DialogActions> | ||
</Dialog> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./AlertDialog"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
import { useEffect, useMemo, useRef } from "react"; | ||
import Map from "ol/Map"; | ||
import View from "ol/View"; | ||
import "../../../node_modules/ol/ol.css"; | ||
import { Box } from "@mui/material"; | ||
import TileLayer from "ol/layer/Tile"; | ||
import OSM from "ol/source/OSM"; | ||
import VectorLayer from "ol/layer/Vector"; | ||
import VectorSource from "ol/source/Vector"; | ||
import { Feature } from "ol"; | ||
import { Point } from "ol/geom"; | ||
import { fromLonLat } from "ol/proj"; | ||
import Style from "ol/style/Style"; | ||
import Icon from "ol/style/Icon"; | ||
|
||
import markerImage from "@assets/marker.png"; | ||
import markerActiveImage from "@assets/marker_active.png"; | ||
|
||
import { IUserPoint } from "@types"; | ||
import { | ||
useMap, | ||
useMapCenter, | ||
useMapUserPoints, | ||
useMapZoom, | ||
} from "@hooks/mapContext"; | ||
|
||
/** | ||
* It creates a map, sets it in the context, and updates it when the context changes | ||
* @param - `children`: the (optional) children JSX Elements. | ||
* @returns A box with a map inside of it. | ||
*/ | ||
export const OLMap = ({ children }: { children?: JSX.Element }) => { | ||
const { map, setMap } = useMap(); | ||
const { userPoints: mapUserPoints } = useMapUserPoints(); | ||
const { zoom: mapZoom } = useMapZoom(); | ||
const { center: mapCenter } = useMapCenter(); | ||
|
||
const mapId = useRef(); | ||
|
||
/* A memoized version of the selected user points. */ | ||
const selectedUserPoints: Array<IUserPoint> = useMemo( | ||
() => mapUserPoints.filter((mapUserPoint) => mapUserPoint.isSelected), | ||
[mapUserPoints] | ||
); | ||
|
||
/* A memoized version of the non-selected user points. */ | ||
const nonSelectedUserPoints: Array<IUserPoint> = useMemo( | ||
() => mapUserPoints.filter((mapUserPoint) => !mapUserPoint.isSelected), | ||
[mapUserPoints] | ||
); | ||
|
||
/* An effect to animate zoom and center changes in the map. */ | ||
useEffect(() => { | ||
map.getView().animate({ | ||
zoom: mapZoom, | ||
center: fromLonLat(mapCenter), | ||
duration: 500, | ||
}); | ||
}, [mapZoom, mapCenter, map]); | ||
|
||
/** An effect somewhat tricky to update the map vector points based on the | ||
* updated user points in a performant way (avoiding full re-renders when possible | ||
* by updating only the modified points). */ | ||
useEffect(() => { | ||
if (map.getAllLayers().length < 3) return; | ||
|
||
const _layers = map.getAllLayers(); | ||
|
||
const selectedUsersLayerSource = ( | ||
_layers[1] as VectorLayer<VectorSource<Point>> | ||
).getSource(); | ||
|
||
selectedUsersLayerSource?.clear(); | ||
selectedUsersLayerSource?.addFeatures( | ||
selectedUserPoints.map( | ||
(point) => | ||
new Feature({ | ||
geometry: new Point(fromLonLat(point.position)), | ||
}) | ||
) | ||
); | ||
selectedUsersLayerSource?.changed(); | ||
|
||
const nonSelectedUsersLayerSource = ( | ||
_layers[2] as VectorLayer<VectorSource<Point>> | ||
).getSource(); | ||
nonSelectedUsersLayerSource?.clear(); | ||
nonSelectedUsersLayerSource?.addFeatures( | ||
nonSelectedUserPoints.map( | ||
(point) => | ||
new Feature({ | ||
geometry: new Point(fromLonLat(point.position)), | ||
}) | ||
) | ||
); | ||
nonSelectedUsersLayerSource?.changed(); | ||
}, [selectedUserPoints, nonSelectedUserPoints, map]); | ||
|
||
/** This is the effect that creates the map var and sets it in the context. | ||
* It will be triggered only if the context's map is null, to avoid re-renders | ||
* and other issues. | ||
*/ | ||
useEffect(() => { | ||
const theMap = new Map({ | ||
layers: [ | ||
new TileLayer({ | ||
source: new OSM(), | ||
}), | ||
new VectorLayer({ | ||
source: new VectorSource({ | ||
features: [], | ||
}), | ||
style: new Style({ | ||
image: new Icon({ | ||
scale: 0.3, | ||
anchor: [0.5, 0], | ||
anchorOrigin: "bottom-left", | ||
anchorXUnits: "fraction", | ||
anchorYUnits: "pixels", | ||
src: markerActiveImage, | ||
}), | ||
}), | ||
}), | ||
new VectorLayer({ | ||
source: new VectorSource({ | ||
features: [], | ||
}), | ||
style: new Style({ | ||
image: new Icon({ | ||
scale: 0.3, | ||
anchor: [0.5, 0], | ||
opacity: 1, | ||
anchorOrigin: "bottom-left", | ||
anchorXUnits: "fraction", | ||
anchorYUnits: "pixels", | ||
src: markerImage, | ||
}), | ||
}), | ||
}), | ||
], | ||
view: new View({ | ||
center: mapCenter, | ||
zoom: mapZoom, | ||
}), | ||
}); | ||
theMap.setTarget(mapId.current); | ||
setMap(theMap); | ||
|
||
return () => { | ||
if (!theMap) return; | ||
theMap.setTarget(undefined); | ||
setMap(new Map()); | ||
}; | ||
// We disable here the eslint rule for exhaustive-deps since we only want this effect to be triggered | ||
// when the component is mounted for the first time. So even if the linter recommends to add some | ||
// dependencies to the useEffect, we don't really want to do it. And since I don't like to have useless | ||
// warnings, we disable the rule for that line. | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, []); | ||
|
||
return ( | ||
<Box ref={mapId} width="100%" height="100vh"> | ||
{children} | ||
</Box> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./OLMap"; |
Oops, something went wrong.