diff --git a/src/app/GlobalHeader.js b/src/app/GlobalHeader.js
index 4b6e66d..a67a81c 100644
--- a/src/app/GlobalHeader.js
+++ b/src/app/GlobalHeader.js
@@ -8,14 +8,17 @@ import {
MenuButton,
MenuList,
MenuItem,
+ useDisclosure,
} from "@chakra-ui/react";
import { HamburgerIcon } from "@chakra-ui/icons";
import { Link, useLocation } from "react-router-dom";
-import { useAuth0 } from "@auth0/auth0-react";
import { ChevronLeftIcon } from "@chakra-ui/icons";
import Image from "next/image";
-import useCurrentUser from "./components/useCurrentUser";
+import useCurrentUser, {
+ useAuthModeFeatureFlag,
+ useLoginActions,
+} from "./components/useCurrentUser";
import HomeLinkIcon from "./images/home-link-icon.png";
function GlobalHeader() {
@@ -109,8 +112,8 @@ function HomeLink(props) {
}
function UserNavBarSection() {
- const { loginWithRedirect, logout } = useAuth0();
const { isLoading, isLoggedIn, id, username } = useCurrentUser();
+ const { logout } = useLoginActions();
if (isLoading) {
return null;
@@ -150,12 +153,43 @@ function UserNavBarSection() {
Modeling
- loginWithRedirect()}>Log in
+
);
}
}
+function LoginButton() {
+ const authMode = useAuthModeFeatureFlag();
+ const { startLogin } = useLoginActions();
+ const { isOpen, onOpen, onClose } = useDisclosure();
+
+ const onClick = () => {
+ if (authMode === "auth0") {
+ startLogin();
+ } else if (authMode === "db") {
+ onOpen();
+ } else {
+ throw new Error(`unexpected auth mode: ${JSON.stringify(authMode)}`);
+ }
+ };
+
+ return (
+ <>
+ Log in
+ {authMode === "db" && (
+
+
+
+ )}
+ >
+ );
+}
+
+// I don't wanna load all these Chakra components as part of the bundle for
+// every single page. Split it out!
+const LoginModal = React.lazy(() => import("./components/LoginModal"));
+
/**
* Renders the given children as a dropdown menu or as a list
* of buttons, depending on the screen size.
diff --git a/src/app/components/LoginModal.js b/src/app/components/LoginModal.js
new file mode 100644
index 0000000..85d9c8c
--- /dev/null
+++ b/src/app/components/LoginModal.js
@@ -0,0 +1,135 @@
+import {
+ Box,
+ Button,
+ FormControl,
+ FormHelperText,
+ FormLabel,
+ Input,
+ Modal,
+ ModalBody,
+ ModalCloseButton,
+ ModalContent,
+ ModalHeader,
+ ModalOverlay,
+ Tab,
+ TabList,
+ TabPanel,
+ TabPanels,
+ Tabs,
+} from "@chakra-ui/react";
+import React from "react";
+
+export default function LoginModal({ isOpen, onClose }) {
+ return (
+
+
+
+ Welcome back to Dress to Impress! ✨
+
+
+
+ Log in
+ Create account
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+function LoginForm() {
+ const onSubmit = (e) => {
+ e.preventDefault();
+ alert("TODO: Log in!");
+ };
+
+ return (
+
+ );
+}
+
+function CreateAccountForm() {
+ const onSubmit = (e) => {
+ e.preventDefault();
+ alert("TODO: Create account!");
+ };
+
+ return (
+
+ );
+}
diff --git a/src/app/components/useCurrentUser.js b/src/app/components/useCurrentUser.js
index 9943c18..2ef3b07 100644
--- a/src/app/components/useCurrentUser.js
+++ b/src/app/components/useCurrentUser.js
@@ -1,4 +1,6 @@
import { useAuth0 } from "@auth0/auth0-react";
+import { useEffect } from "react";
+import { useLocalStorage } from "../util";
function useCurrentUser() {
const { isLoading, isAuthenticated, user } = useAuth0();
@@ -61,4 +63,88 @@ function getUserInfo(user) {
};
}
+/**
+ * useLoginActions returns a `startLogin` function to start login with Auth0,
+ * and a `logout` function to logout from whatever auth mode is in use.
+ *
+ * Note that `startLogin` is only supported with the Auth0 auto mode. In db
+ * mode, you should open a `LoginModal` instead!
+ */
+export function useLoginActions() {
+ const {
+ loginWithRedirect: auth0StartLogin,
+ logout: auth0Logout,
+ } = useAuth0();
+ const authMode = useAuthModeFeatureFlag();
+
+ if (authMode === "auth0") {
+ return { startLogin: auth0StartLogin, logout: auth0Logout };
+ } else if (authMode === "db") {
+ return {
+ startLogin: () => {
+ console.error(
+ `Error: Cannot call startLogin in db login mode. Open a ` +
+ ` instead.`
+ );
+ alert(
+ `Error: Cannot call startLogin in db login mode. Open a ` +
+ ` instead.`
+ );
+ },
+ logout: () => {
+ alert(`TODO: logout`);
+ },
+ };
+ } else {
+ console.error(`unexpected auth mode: ${JSON.stringify(authMode)}`);
+ return { startLogin: () => {}, logout: () => {} };
+ }
+}
+
+/**
+ * useAuthModeFeatureFlag returns "auth0" by default, but "db" if you're trying
+ * the new db-backed login mode.
+ *
+ * To set this manually, run `window.setAuthModeFeatureFlag("db")` in your
+ * browser console.
+ */
+export function useAuthModeFeatureFlag() {
+ // We'll probably add a like, experimental gradual rollout thing here too.
+ // But for now we just check your device's local storage! (This is why we
+ // default to `null` instead of "auth0", I want to be unambiguous that this
+ // is the *absence* of a localStorage value, and not risk accidentally
+ // setting this override value to auth0 on everyone's devices 😅)
+ const [savedValue] = useLocalStorage("DTIAuthModeFeatureFlag", null);
+
+ useEffect(() => {
+ window.setAuthModeFeatureFlag = setAuthModeFeatureFlag;
+ });
+
+ if (!["auth0", "db", null].includes(savedValue)) {
+ console.warn(
+ `Unexpected DTIAuthModeFeatureFlag value: %o. Treating as null.`,
+ savedValue
+ );
+ return null;
+ }
+
+ return savedValue || "auth0";
+}
+
+/**
+ * setAuthModeFeatureFlag is mounted on the window, so you can call it from the
+ * browser console to set this override manually.
+ */
+function setAuthModeFeatureFlag(newValue) {
+ if (!["auth0", "db", null].includes(newValue)) {
+ throw new Error(`Auth mode must be "auth0", "db", or null.`);
+ }
+
+ localStorage.setItem("DTIAuthModeFeatureFlag", JSON.stringify(newValue));
+
+ // The useLocalStorage hook isn't *quite* good enough to catch this change.
+ // Let's just reload the page lmao.
+ window.location.reload();
+}
+
export default useCurrentUser;