aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Joe Banks <[email protected]>2024-08-25 04:10:49 +0100
committerGravatar Joe Banks <[email protected]>2024-08-25 04:10:49 +0100
commit923de5c2a264fec92ac28775030957ecc68350a2 (patch)
treec63411ad385639f6b8a5a41e14b690000be1114f
parentAdd store front page (diff)
Gracefully handle missing token errors
-rw-r--r--thallium-frontend/src/api/client.ts6
-rw-r--r--thallium-frontend/src/api/templates.ts4
-rw-r--r--thallium-frontend/src/pages/StorePage.tsx14
3 files changed, 20 insertions, 4 deletions
diff --git a/thallium-frontend/src/api/client.ts b/thallium-frontend/src/api/client.ts
index 9e64af5..bbba0d5 100644
--- a/thallium-frontend/src/api/client.ts
+++ b/thallium-frontend/src/api/client.ts
@@ -4,6 +4,12 @@ TODO: Someday these methods should try pick out authentication from the Redux st
const BASE_URL = THALLIUM_BASE_URL;
+export class APIMissingTokenError extends Error {
+ constructor() {
+ super("No token available");
+ }
+}
+
interface APIErrorResponse {
detail?: string;
}
diff --git a/thallium-frontend/src/api/templates.ts b/thallium-frontend/src/api/templates.ts
index d60260d..0c8dffd 100644
--- a/thallium-frontend/src/api/templates.ts
+++ b/thallium-frontend/src/api/templates.ts
@@ -1,4 +1,4 @@
-import { get } from "./client";
+import { get, APIMissingTokenError } from "./client";
import store from "../store";
export interface Variant {
@@ -27,7 +27,7 @@ export const getTemplates = async (withVariants: boolean): Promise<Template[]> =
const token = store.getState().authorization.voucherToken;
if (!token) {
- throw new Error("No token available");
+ throw new APIMissingTokenError();
};
return await get(`/templates/?with_variants=${withVariants.toString()}`, {
diff --git a/thallium-frontend/src/pages/StorePage.tsx b/thallium-frontend/src/pages/StorePage.tsx
index 6899bd8..a3143d3 100644
--- a/thallium-frontend/src/pages/StorePage.tsx
+++ b/thallium-frontend/src/pages/StorePage.tsx
@@ -3,8 +3,10 @@ import { RootState } from "../store";
import { useEffect, useState } from "react";
import { Template, getTemplates } from "../api/templates";
+import { APIMissingTokenError } from "../api/client";
import StoreItem from "../components/StoreItem";
import styled from "styled-components";
+import { Link } from "react-router-dom";
const StoreGrid = styled.div`
display: grid;
@@ -17,11 +19,14 @@ const StoreGrid = styled.div`
const StorePage = () => {
const voucherToken = useSelector((state: RootState) => state.authorization.voucherToken);
const [storeItems, setStoreItems] = useState<Template[] | null>(null);
+ const [permissionDenied, setPermissionDenied] = useState<boolean>(false);
useEffect(() => {
getTemplates(true).then(setStoreItems).catch((err: unknown) => {
setStoreItems([]);
- console.error(err);
+ if (err instanceof APIMissingTokenError) {
+ setPermissionDenied(true);
+ }
});
}, [voucherToken]);
@@ -33,7 +38,12 @@ const StorePage = () => {
<StoreItem key={item.template_id} template={item} />
))}
</StoreGrid>
-
+ {permissionDenied && (
+ <>
+ <p>You need to have a valid voucher code to access the store.</p>
+ <Link to="/">Redeem a voucher</Link>
+ </>
+ )}
</>
);
};