From 9130d37a77a4bd8ec9a9cab09eb4a4ca7b5c9499 Mon Sep 17 00:00:00 2001 From: Juan Di Toro Date: Wed, 13 Sep 2023 21:31:28 +0200 Subject: [PATCH] feat: pretty much done. Just one warning left to add on `LumeIdentity.tsx` --- .../lume/LumeIdentity/LumeIdentity.tsx | 44 ++++--- .../lume/LumeIdentity/LumeIdentityContext.ts | 43 +++++++ .../lume/LumeIdentity/components.tsx | 115 +++++++++++++++--- 3 files changed, 166 insertions(+), 36 deletions(-) create mode 100644 src/components/lume/LumeIdentity/LumeIdentityContext.ts diff --git a/src/components/lume/LumeIdentity/LumeIdentity.tsx b/src/components/lume/LumeIdentity/LumeIdentity.tsx index 6f80213..b5687b1 100644 --- a/src/components/lume/LumeIdentity/LumeIdentity.tsx +++ b/src/components/lume/LumeIdentity/LumeIdentity.tsx @@ -5,41 +5,50 @@ import LumeLogoBg from '@/assets/lume-logo-bg.svg'; import { Button } from '@/components/ui/button'; import { SwitchableComponent, SwitchableComponentProvider, useSwitchableComponent } from '@/components/SwitchableComponent'; import ComponentList from "./components"; +import { LumeIdentityContext, Session } from './LumeIdentityContext'; type Props = {} const LumeIdentity: React.FC = ({ }) => { const { visibleComponent, setVisibleComponent } = useSwitchableComponent(ComponentList.SubmitButton) - console.log({ visibleComponent }) const isSubmitButtonInView = [ComponentList.SubmitButton.index].includes(visibleComponent.index) - const isCreatingAccount = [ComponentList.SetupAccountKey.index, ComponentList.SeedPhraseForm.index].includes(visibleComponent.index) + const isLoginWithAccountKey = [ComponentList.SeedPhraseInput.index].includes(visibleComponent.index) + const isCreatingAccount = [ComponentList.SetupAccountKey.index].includes(visibleComponent.index) + const isShowingSeedPhrase = [ComponentList.SeedPhraseGeneration.index].includes(visibleComponent.index) + const isFinalStep = [ComponentList.SeedPhraseGeneration.index].includes(visibleComponent.index) const shouldShowBackButton = isCreatingAccount - const headingElement = !isCreatingAccount ? (

Sign-in with Lume

) : (

Set up your account key

) const coloredOrLine = isSubmitButtonInView ? 'text-primary' : 'text-border' + return
- {headingElement} +

+ {isSubmitButtonInView || isLoginWithAccountKey ? 'Sign in with Lume' : null} + {isCreatingAccount && !isShowingSeedPhrase ? 'Set up your account key' : null} + {isShowingSeedPhrase ? "Here's your account key" : null} +

-
- - - - -
- + {!isFinalStep ? <> +
+ + + + +
+ + : null}
@@ -47,7 +56,10 @@ const LumeIdentity: React.FC = ({ }) => { }; export default () => { - return - - + const [session, setSession] = React.useState(); + return + + + + }; \ No newline at end of file diff --git a/src/components/lume/LumeIdentity/LumeIdentityContext.ts b/src/components/lume/LumeIdentity/LumeIdentityContext.ts new file mode 100644 index 0000000..d1ec73d --- /dev/null +++ b/src/components/lume/LumeIdentity/LumeIdentityContext.ts @@ -0,0 +1,43 @@ +import React from "react"; + +export type Session = string; +export const LumeIdentityContext = React.createContext<{ + session: Session | undefined; + setSession: React.Dispatch>; +} | undefined>(undefined); +export function useLumeIndentity() { + const contextValue = React.useContext(LumeIdentityContext); + + // When the `session` changes we want to update the `session` in the local storage? + React.useEffect(() => { + if (contextValue?.session) { + localStorage.setItem('lume-session', contextValue.session); + } else { + localStorage.removeItem('lume-session'); + } + }, [contextValue?.session]); + + // Get the session from the local storage + React.useEffect(() => { + const session = localStorage.getItem('lume-session'); + if (session) { + contextValue?.setSession(session); + } + }, []); + + if (contextValue === undefined) { + throw new Error('useLumeIndentity hook is being used outside of its context. Please ensure that it is wrapped within a .'); + } + + return { + isSignedIn: !!contextValue.session, + signIn: (key: string) => { + console.log('signing in with key', key); + // TODO: From the key generate a session, and store it + contextValue.setSession('session'); + }, + signOut: () => { + contextValue.setSession(undefined); + }, + }; +} \ No newline at end of file diff --git a/src/components/lume/LumeIdentity/components.tsx b/src/components/lume/LumeIdentity/components.tsx index 50f2533..ac96f01 100644 --- a/src/components/lume/LumeIdentity/components.tsx +++ b/src/components/lume/LumeIdentity/components.tsx @@ -1,8 +1,10 @@ import { makeSwitchable, useSwitchableComponent } from "@/components/SwitchableComponent"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; -import { motion } from "framer-motion"; +import { CheckIcon, ClipboardCopyIcon, ExclamationTriangleIcon } from "@radix-ui/react-icons"; +import { AnimatePresence, motion } from "framer-motion"; import React from "react"; +import { useLumeIndentity } from "./LumeIdentityContext"; // Extracted components const SubmitButtonComponent = ({ }) => { @@ -14,11 +16,20 @@ const SubmitButtonComponent = ({ }) => { ) }; -const SeedPhraseInputComponent = ({ signIn }: { signIn: (value: string) => void }) => { - const [value, setValue] = React.useState(""); +const SeedPhraseInputComponent = ({ }) => { + const { signIn } = useLumeIndentity(); return ( - - setValue(e.target?.value)} /> + { + e.preventDefault(); + const target = e.target as typeof e.target & { + elements: { + seedPhrase: { value: string }; + } + }; + const seedPhrase = target.elements.seedPhrase.value; + signIn(seedPhrase) + }}> + void transition={{ type: "just", delay: 0.1 }} className="h-12" > - @@ -45,33 +56,97 @@ const SetupAccountKeyComponent = () => { transition={{ type: "just", delay: 0.1 }} className="h-12" > - ) }; -const SeedPhraseFormComponent = ({ phraseLength = 12 }) => ( -
- {Array(phraseLength).fill("a phrase").map((phrase, index) => ( -
- {phrase} - {index + 1} +const SeedPhraseGenerationComponent = ({ phraseLength = 12 }) => { + const [buttonClickedState, setButtonClickedState] = React.useState<"idle" | "clicked">("idle"); + const [step, setStep] = React.useState(0); + const { signIn } = useLumeIndentity(); + + const phrases = React.useMemo(() => { + // TODO: Replace with actual BIP39 or whatever is used for phrase generation + return Array(phraseLength).fill("a phrase") + }, [phraseLength]); + + const key = React.useMemo(() => { + return phrases.join(" "); + }, [phrases]); + + const copyPhrasesToClipboard = () => { + navigator.clipboard.writeText(phrases.join(" ")); + setButtonClickedState("clicked"); + setTimeout(() => setButtonClickedState("idle"), 1000); + } + + return ( +
+ + {step === 1 ? { + // setTimeout(() => { + // setOpacity(1); + // }, 2000); + // }} + > : null} + +
+ {phrases.map((phrase, index) => ( +
+ {phrase} + {index + 1} +
+ ))} + + {step === 1 ? + + Make sure to write this down for safe keeping. + : null} + +
- ))} - -
-); + {step === 0 ? ( + + ) : null} + + {step === 1 ? + + : null} + +
+ ) +}; // Usage const components = { SubmitButton: makeSwitchable(SubmitButtonComponent, 'submit-button'), SeedPhraseInput: makeSwitchable(SeedPhraseInputComponent, 'seed-phrase-input'), SetupAccountKey: makeSwitchable(SetupAccountKeyComponent, 'setup-account-key'), - SeedPhraseForm: makeSwitchable(SeedPhraseFormComponent, 'seed-phrase-form'), + SeedPhraseGeneration: makeSwitchable(SeedPhraseGenerationComponent, 'seed-phrase-form'), }; export default components;