Skip to content

Commit

Permalink
Ensure maps API key is properly retrieved and retained
Browse files Browse the repository at this point in the history
  • Loading branch information
davewalker5 committed Nov 21, 2023
1 parent bae3ae1 commit 3782bfe
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 95 deletions.
26 changes: 5 additions & 21 deletions src/music-catalogue-ui/components/app.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React, { useCallback, useEffect, useState } from "react";
import React, { useCallback, useState } from "react";
import Login from "./login";
import pages from "@/helpers/navigation";
import ComponentPicker from "./componentPicker";
import { apiClearToken } from "@/helpers/apiToken";
import useIsLoggedIn from "@/hooks/useIsLoggedIn";
import MenuBar from "./menuBar";
import { apiFetchSecret } from "@/helpers/apiSecrets";
import { clearStorageValue } from "@/helpers/storage";
import secrets from "@/helpers/secrets";

/**
* Default application state:
Expand All @@ -32,9 +33,6 @@ const App = () => {
// Application state
const [context, setContext] = useState(defaultContext);

// Google Maps API key
const [mapsApiKey, setMapsApiKey] = useState(null);

// Callback to set the context
const navigate = ({
page = pages.artists,
Expand Down Expand Up @@ -65,37 +63,23 @@ const App = () => {
}, [setIsLoggedIn]);

const logout = useCallback(() => {
clearStorageValue(secrets.mapsApiKey);
apiClearToken();
setIsLoggedIn(false);
}, [setIsLoggedIn]);

// Get the Google Maps API key and store it in state
useEffect(() => {
const fetchMapsApiKey = async () => {
try {
var fetchedKey = await apiFetchSecret("Maps API Key", logout);
setMapsApiKey(fetchedKey);
} catch {}
};

if (mapsApiKey == null) {
fetchMapsApiKey();
}
}, [mapsApiKey, logout]);

// If the user's logged in, show the banner and current component. Otherwise,
// show the login page
return (
<>
{isLoggedIn && mapsApiKey != null ? (
{isLoggedIn ? (
<>
<div>
<MenuBar navigate={navigate} logout={logout} />
</div>
<div>
<ComponentPicker
context={context}
mapsApiKey={mapsApiKey}
navigate={navigate}
logout={logout}
/>
Expand Down
3 changes: 1 addition & 2 deletions src/music-catalogue-ui/components/componentPicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import RetailerEditor from "./retailerEditor";
* @param {*} logout
* @returns
*/
const ComponentPicker = ({ context, mapsApiKey, navigate, logout }) => {
const ComponentPicker = ({ context, navigate, logout }) => {
switch (context.page) {
case pages.artists:
return (
Expand Down Expand Up @@ -80,7 +80,6 @@ const ComponentPicker = ({ context, mapsApiKey, navigate, logout }) => {
case pages.retailerDetails:
return (
<RetailerDetails
mapsApiKey={mapsApiKey}
retailer={context.retailer}
navigate={navigate}
logout={logout}
Expand Down
10 changes: 6 additions & 4 deletions src/music-catalogue-ui/components/locationMap.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import GoogleMapReact from "google-map-react";
import { useState } from "react";
import styles from "./locationMap.module.css";
import secrets from "@/helpers/secrets";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faMapMarkerAlt } from "@fortawesome/free-solid-svg-icons";
import { getStorageValue } from "@/helpers/storage";

const LocationMap = ({ apiKey, latitude, longitude }) => {
const [location, setLocation] = useState({ lat: latitude, lng: longitude });
const LocationMap = ({ latitude, longitude }) => {
const location = { lat: latitude, lng: longitude };
const mapsApiKey = getStorageValue(secrets.mapsApiKey);

return (
<>
<div className={styles.locationMapContainer}>
<GoogleMapReact
bootstrapURLKeys={{ key: apiKey }}
bootstrapURLKeys={{ key: mapsApiKey }}
defaultCenter={location}
defaultZoom={15}
>
Expand Down
11 changes: 11 additions & 0 deletions src/music-catalogue-ui/components/login.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import styles from "./login.module.css";
import secrets from "@/helpers/secrets";
import { React, useState, useCallback } from "react";
import { apiAuthenticate } from "@/helpers/apiAuthenticate";
import { apiSetToken } from "@/helpers/apiToken";
import { apiFetchSecret } from "@/helpers/apiSecrets";
import { setStorageValue } from "@/helpers/storage";

/**
* Component to render the login page
Expand All @@ -24,6 +27,14 @@ const Login = ({ login }) => {
if (token != null) {
// Successful, so store the token
apiSetToken(token);

// Now attempt to get the Google Maps API key
const apiKey = await apiFetchSecret(secrets.mapsApiKey);
if (apiKey != null) {
// Successful, so store it
setStorageValue(secrets.mapsApiKey, apiKey);
}

login(true);
}
},
Expand Down
9 changes: 6 additions & 3 deletions src/music-catalogue-ui/components/retailerDetails.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { getStorageValue } from "@/helpers/storage";
import pages from "../helpers/navigation";
import LocationMap from "./locationMap";
import styles from "./retailerDetails.module.css";
import secrets from "@/helpers/secrets";

/**
* Component to show retailer addressing and web site details and map location
* @param {*} param0
* @param {*} retailer
* @param {*} navigate
* @param {*} logout
* @returns
*/
const RetailerDetails = ({ mapsApiKey, retailer, navigate, logout }) => {
const RetailerDetails = ({ retailer, navigate, logout }) => {
// Set a flag indicating if we have enough data to show the map
const canShowMap = retailer.latitude != null && retailer.longitude != null;

Expand All @@ -23,7 +27,6 @@ const RetailerDetails = ({ mapsApiKey, retailer, navigate, logout }) => {
</div>
{canShowMap == true ? (
<LocationMap
apiKey={mapsApiKey}
latitude={retailer.latitude}
longitude={retailer.longitude}
logout={logout}
Expand Down
10 changes: 2 additions & 8 deletions src/music-catalogue-ui/components/retailerList.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ import RetailerRow from "./retailerRow";

/**
* Component to render a table listing all the retailers in the catalogue
* @param {*} mapsApiKey
* @param {*} navigate
* @param {*} logout
* @returns
*/
const RetailerList = ({ mapsApiKey, navigate, logout }) => {
const RetailerList = ({ navigate, logout }) => {
const { retailers: retailers, setRetailers } = useRetailers(logout);

return (
Expand All @@ -30,12 +29,7 @@ const RetailerList = ({ mapsApiKey, navigate, logout }) => {
{retailers != null && (
<tbody>
{retailers.map((r) => (
<RetailerRow
key={r.id}
mapsApiKey={mapsApiKey}
retailer={r}
navigate={navigate}
/>
<RetailerRow key={r.id} retailer={r} navigate={navigate} />
))}
</tbody>
)}
Expand Down
7 changes: 1 addition & 6 deletions src/music-catalogue-ui/components/retailerRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,18 @@ import { faPenToSquare } from "@fortawesome/free-solid-svg-icons";

/**
* Component to render a row containing the details for a single retailer
* @param {*} mapsApiKey
* @param {*} artist
* @param {*} navigate
* @returns
*/
const RetailerRow = ({ mapsApiKey, retailer, navigate }) => {
const RetailerRow = ({ retailer, navigate }) => {
return (
<tr>
<td
onClick={() =>
navigate({
page: pages.retailerDetails,
retailer: retailer,
mapsApiKey: mapsApiKey,
})
}
>
Expand All @@ -28,7 +26,6 @@ const RetailerRow = ({ mapsApiKey, retailer, navigate }) => {
navigate({
page: pages.retailerDetails,
retailer: retailer,
mapsApiKey: mapsApiKey,
})
}
>
Expand All @@ -39,7 +36,6 @@ const RetailerRow = ({ mapsApiKey, retailer, navigate }) => {
navigate({
page: pages.retailerDetails,
retailer: retailer,
mapsApiKey: mapsApiKey,
})
}
>
Expand All @@ -50,7 +46,6 @@ const RetailerRow = ({ mapsApiKey, retailer, navigate }) => {
navigate({
page: pages.retailerDetails,
retailer: retailer,
mapsApiKey: mapsApiKey,
})
}
>
Expand Down
22 changes: 5 additions & 17 deletions src/music-catalogue-ui/helpers/apiToken.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,21 @@
import { setStorageValue, getStorageValue, clearStorageValue } from "./storage";

/**
* Store the JWT token
* @param {*} token
*/
const apiSetToken = (token) => {
// TODO: Move to HTTP Cookie
localStorage.setItem("token", token);
};
const apiSetToken = (token) => setStorageValue("token", token);

/**
* Retrieve the current JWT token
* @param {*} token
* @returns
*/
const apiGetToken = () => {
try {
// TODO: Move to HTTP Cookie
const token = localStorage.getItem("token");
return token;
} catch {
return null;
}
};
const apiGetToken = () => getStorageValue("token");

/**
* Clear the current JWT token
*/
const apiClearToken = () => {
// TODO: Move to HTTP Cookie
localStorage.removeItem("token");
};
const apiClearToken = () => clearStorageValue("token");

export { apiClearToken, apiSetToken, apiGetToken };
45 changes: 45 additions & 0 deletions src/music-catalogue-ui/helpers/storage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Convert a name that may be mixed case and with spaces to a local storage key
* @param {*} name
* @returns
*/
const getStorageKey = (name) => {
const key = name.toLowerCase().replace(/ /g, "-");
return key;
};

/**
* Store a named value
* @param {*} token
* @param {*} value
*/
const setStorageValue = (name, value) => {
const key = getStorageKey(name);
localStorage.setItem(key, value);
};

/**
* Retrieve a stored value
* @param {*} name
* @returns
*/
const getStorageValue = (name) => {
try {
const key = getStorageKey(name);
const token = localStorage.getItem(key);
return token;
} catch {
return null;
}
};

/**
* Clear a named storage value
* @param {*} name
*/
const clearStorageValue = (name) => {
const key = getStorageKey(name);
localStorage.removeItem(key);
};

export { setStorageValue, getStorageValue, clearStorageValue };
34 changes: 0 additions & 34 deletions src/music-catalogue-ui/hooks/useMapsApiKey.js

This file was deleted.

0 comments on commit 3782bfe

Please sign in to comment.