refactor: split Lume Provider into LumeStatusProvider, NetworksProvider, and AuthProvider

This commit is contained in:
Derrick Hammer 2023-10-16 14:55:01 -04:00
parent 40f6699064
commit dc3fe6adb6
Signed by: pcfreak30
GPG Key ID: C997C339BE476FF2
9 changed files with 137 additions and 69 deletions

View File

@ -0,0 +1,38 @@
import { createContext, useState, useContext, ReactNode } from "react";
// AuthContextType
export interface AuthContextType {
isLoggedIn: boolean;
setIsLoggedIn: (value: boolean) => void;
}
// AuthContext
const AuthContext = createContext<AuthContextType | undefined>(undefined);
// AuthProvider
interface AuthProviderProps {
children: ReactNode;
}
export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
return (
<AuthContext.Provider value={{ isLoggedIn, setIsLoggedIn }}>
{children}
</AuthContext.Provider>
);
};
// useAuth hook
export function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error("useAuth must be used within an AuthProvider");
}
return context;
}
export default AuthProvider;

View File

@ -0,0 +1,45 @@
import { createContext, useState, useContext, ReactNode } from "react";
// LumeStatusContextType
interface LumeStatusContextType {
inited: boolean;
setInited: (value: boolean) => void;
ready: boolean;
setReady: (value: boolean) => void;
}
// LumeStatusContext
export const LumeStatusContext = createContext<
LumeStatusContextType | undefined
>(undefined);
// LumeStatusProvider
interface LumeStatusProviderProps {
children: ReactNode;
}
export const LumeStatusProvider: React.FC<LumeStatusProviderProps> = ({
children,
}) => {
const [inited, setInited] = useState(false);
const [ready, setReady] = useState(false);
return (
<LumeStatusContext.Provider value={{ inited, setInited, ready, setReady }}>
{children}
</LumeStatusContext.Provider>
);
};
// useLumeStatus hook
export function useLumeStatus() {
const context = useContext(LumeStatusContext);
if (!context) {
throw new Error("useLumeStatus must be used within a LumeStatusProvider");
}
return context;
}
export default LumeStatusProvider;

View File

@ -8,7 +8,6 @@ import {
} from "react";
import { createClient as createNetworkRegistryClient } from "@lumeweb/kernel-network-registry-client";
import { createNetworkClient } from "@lumeweb/libkernel/module";
import { init, loginComplete } from "@lumeweb/libkernel/kernel";
type SyncState = "done" | "syncing" | "error";
@ -26,45 +25,35 @@ interface NetworkStatus {
error?: string;
}
type LumeObject = {
export interface NetworksContextType {
networks: Network[];
};
export type LumeContextType = {
isLoggedIn: boolean;
setIsLoggedIn: (value: boolean) => void;
lume: LumeObject;
inited: boolean;
setInited: React.Dispatch<React.SetStateAction<boolean>>;
ready: boolean;
setReady: React.Dispatch<React.SetStateAction<boolean>>;
};
setNetworks: React.Dispatch<React.SetStateAction<Network[]>>;
}
const networkRegistry = createNetworkRegistryClient();
const LumeContext = createContext<LumeContextType | undefined>(undefined);
// Networks Context
const NetworksContext = createContext<NetworksContextType | undefined>(
undefined,
);
const LumeProvider = ({ children }) => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [ready, setReady] = useState<boolean>(false);
const [inited, setInited] = useState<boolean>(false);
const [lume, setLume] = useState<LumeObject>({ networks: [] });
const NetworksProvider = ({ children }) => {
const [networks, setNetworks] = useState<Network[]>([]);
const statusUnsubs = useRef(new Map());
const isMounted = useRef(true); // Use a ref to track mounting
const handleStatusUpdate = useCallback((id, newNetwork) => {
setLume((prevLume) => {
const updatedNetworks = prevLume.networks.map((network) =>
setNetworks((prevNetworks) => {
return prevNetworks.map((network) =>
network.id === id ? { ...network, ...newNetwork } : network,
);
return { ...prevLume, networks: updatedNetworks };
});
}, []);
const fetchAndUpdateNetworks = useCallback(async () => {
const unsub = () => {
statusUnsubs.current.forEach((unsub) => unsub());
statusUnsubs.current = new Map<any, any>();
statusUnsubs.current.clear();
};
try {
@ -110,10 +99,7 @@ const LumeProvider = ({ children }) => {
statusUnsubs.current = newStatusUnsubs;
if (isMounted.current) {
setLume((prevLume) => ({
...prevLume,
networks: Array.from(newNetworksMap.values()),
}));
setNetworks(Array.from(newNetworksMap.values()));
} else {
unsub();
}
@ -139,29 +125,18 @@ const LumeProvider = ({ children }) => {
}, [fetchAndUpdateNetworks]);
return (
<LumeContext.Provider
value={{
lume,
ready,
setReady,
isLoggedIn,
setIsLoggedIn,
inited,
setInited,
}}>
<NetworksContext.Provider value={{ networks, setNetworks }}>
{children}
</LumeContext.Provider>
</NetworksContext.Provider>
);
};
export default LumeProvider;
export function useLume() {
const ctx = useContext(LumeContext);
if (!ctx) {
throw new Error("useLume must be used within a LumeProvider");
export function useNetworks() {
const context = useContext(NetworksContext);
if (!context) {
throw new Error("useNetworks must be used within a NetworksProvider");
}
return ctx;
return context;
}
export default NetworksProvider;

View File

@ -1,11 +1,11 @@
import * as Dialog from "@radix-ui/react-dialog";
import { Network, useLume } from "../LumeProvider";
import Logo from "../../../assets/lume-logo.png";
import { cva } from "class-variance-authority";
import { cn } from "../../utils";
import { useState, useEffect } from "react";
import React from "react";
import camelCase from "camelcase";
import { useNetworks, type Network } from "../../NetworksProvider";
const SYNCSTATE_TO_TEXT: Record<Network["syncState"], string> = {
done: "Synced",
@ -18,9 +18,7 @@ LumeDashboardTrigger.displayName = "LumeDashboardTrigger";
const LumeDashboard = (props: any) => {
const { children }: { children: React.PropsWithChildren } = props;
const {
lume: { networks },
} = useLume();
const { networks } = useNetworks();
const [uniqueNetworkTypes, setUniqueNetworkTypes] = useState<string[]>([]);

View File

@ -3,15 +3,15 @@ import {
// loginComplete,
// logoutComplete,
} from "@lumeweb/libkernel/kernel";
import { useLume } from "../LumeProvider";
import React, { useContext } from "react";
import { useAuth } from "../../AuthProvider.js";
export const LumeIdentityContext = React.createContext<
{ open: boolean; setOpen: (open: boolean) => void } | undefined
>(undefined);
export function useLumeIndentity() {
const { isLoggedIn, setIsLoggedIn } = useLume();
export function useLumeIdentity() {
const { isLoggedIn, setIsLoggedIn } = useAuth();
const ctx = useContext(LumeIdentityContext);
if (!ctx) {

View File

@ -10,7 +10,7 @@ import {
ExclamationTriangleIcon,
} from "@radix-ui/react-icons";
import { AnimatePresence, m } from "framer-motion";
import { useLumeIndentity } from "./LumeIdentityContext";
import { useLumeIdentity } from "./LumeIdentityContext";
import { useMemo, useState } from "react";
import * as bip39 from "@scure/bip39";
@ -54,7 +54,7 @@ const SubmitButtonComponent = () => {
};
const SeedPhraseInputComponent = () => {
const { signIn } = useLumeIndentity();
const { signIn } = useLumeIdentity();
return (
<m.form
className="flex-col flex gap-y-4"
@ -118,7 +118,7 @@ const SeedPhraseGenerationComponent = ({ phraseLength = 12 }) => {
"idle" | "clicked"
>("idle");
const [step, setStep] = useState<number>(0);
const { signIn } = useLumeIndentity();
const { signIn } = useLumeIdentity();
const phrases = useMemo(() => {
return bip39
@ -158,10 +158,12 @@ const SeedPhraseGenerationComponent = ({ phraseLength = 12 }) => {
<div
key={`SeedPhrase_${index}`}
className={`${TW_PREFIX} relative justify-center items-center gap-2 flex h-10 rounded border border-current ring-current text-neutral-700 w-[calc(33%-8px)]`}>
<span className={`${TW_PREFIX} text-white text-md font-normal leading-normal w-full h-fit px-2 bg-transparent text-center`}>
<span
className={`${TW_PREFIX} text-white text-md font-normal leading-normal w-full h-fit px-2 bg-transparent text-center`}>
{phrase}
</span>
<span className={`${TW_PREFIX} left-[6px] top-0 absolute text-current text-xs font-normal leading-normal`}>
<span
className={`${TW_PREFIX} left-[6px] top-0 absolute text-current text-xs font-normal leading-normal`}>
{index + 1}
</span>
</div>

View File

@ -1,8 +1,18 @@
export {
default as LumeProvider,
useLume,
type LumeContextType,
} from "./components/lume/LumeProvider";
default as AuthProvider,
useAuth,
type AuthContextType,
} from "./components/AuthProvider";
export {
default as NetworksProvider,
useNetworks,
type NetworksContextType,
} from "./components/NetworksProvider";
export {
default as LumeStatusProvider,
useLumeStatus,
type LumeStatusContext,
} from "src/components/LumeStatusProvider.js";
export {
default as LumeDashboard,
LumeDashboardTrigger,

View File

@ -1,7 +1,7 @@
import React from "react";
import { StoryFn, Meta } from "@storybook/react";
import LumeDashboard from "../src/components/lume/LumeDashboard/LumeDashboard.js";
import LumeProvider from "../src/components/lume/LumeProvider.js";
import NetworksProvider from "src/components/NetworksProvider.js";
export default {
title: "LumeDashboard",
@ -9,9 +9,9 @@ export default {
} as Meta<typeof LumeDashboard>;
const Template: StoryFn<typeof LumeDashboard> = (args) => (
<LumeProvider>
<NetworksProvider>
<LumeDashboard {...args} />
</LumeProvider>
</NetworksProvider>
);
export const Primary = Template.bind({});

View File

@ -1,7 +1,7 @@
import React from "react";
import { StoryFn, Meta } from "@storybook/react";
import LumeIdentity from "../src/components/lume/LumeIdentity/LumeIdentity.js";
import LumeProvider from "../src/components/lume/LumeProvider.js";
import AuthProvider from "src/components/AuthProvider.js";
export default {
title: "LumeIdentity",
@ -9,9 +9,9 @@ export default {
} as Meta<typeof LumeIdentity>;
const Template: StoryFn<typeof LumeIdentity> = (args) => (
<LumeProvider>
<AuthProvider>
<LumeIdentity {...args} />
</LumeProvider>
</AuthProvider>
);
export const Primary = Template.bind({});