refactor: split Lume Provider into LumeStatusProvider, NetworksProvider, and AuthProvider
This commit is contained in:
parent
40f6699064
commit
dc3fe6adb6
|
@ -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;
|
|
@ -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;
|
|
@ -8,7 +8,6 @@ import {
|
||||||
} from "react";
|
} from "react";
|
||||||
import { createClient as createNetworkRegistryClient } from "@lumeweb/kernel-network-registry-client";
|
import { createClient as createNetworkRegistryClient } from "@lumeweb/kernel-network-registry-client";
|
||||||
import { createNetworkClient } from "@lumeweb/libkernel/module";
|
import { createNetworkClient } from "@lumeweb/libkernel/module";
|
||||||
import { init, loginComplete } from "@lumeweb/libkernel/kernel";
|
|
||||||
|
|
||||||
type SyncState = "done" | "syncing" | "error";
|
type SyncState = "done" | "syncing" | "error";
|
||||||
|
|
||||||
|
@ -26,45 +25,35 @@ interface NetworkStatus {
|
||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type LumeObject = {
|
export interface NetworksContextType {
|
||||||
networks: Network[];
|
networks: Network[];
|
||||||
};
|
setNetworks: React.Dispatch<React.SetStateAction<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>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const networkRegistry = createNetworkRegistryClient();
|
const networkRegistry = createNetworkRegistryClient();
|
||||||
|
|
||||||
const LumeContext = createContext<LumeContextType | undefined>(undefined);
|
// Networks Context
|
||||||
|
const NetworksContext = createContext<NetworksContextType | undefined>(
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
|
||||||
const LumeProvider = ({ children }) => {
|
const NetworksProvider = ({ children }) => {
|
||||||
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
const [networks, setNetworks] = useState<Network[]>([]);
|
||||||
const [ready, setReady] = useState<boolean>(false);
|
|
||||||
const [inited, setInited] = useState<boolean>(false);
|
|
||||||
const [lume, setLume] = useState<LumeObject>({ networks: [] });
|
|
||||||
const statusUnsubs = useRef(new Map());
|
const statusUnsubs = useRef(new Map());
|
||||||
const isMounted = useRef(true); // Use a ref to track mounting
|
const isMounted = useRef(true); // Use a ref to track mounting
|
||||||
|
|
||||||
const handleStatusUpdate = useCallback((id, newNetwork) => {
|
const handleStatusUpdate = useCallback((id, newNetwork) => {
|
||||||
setLume((prevLume) => {
|
setNetworks((prevNetworks) => {
|
||||||
const updatedNetworks = prevLume.networks.map((network) =>
|
return prevNetworks.map((network) =>
|
||||||
network.id === id ? { ...network, ...newNetwork } : network,
|
network.id === id ? { ...network, ...newNetwork } : network,
|
||||||
);
|
);
|
||||||
return { ...prevLume, networks: updatedNetworks };
|
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const fetchAndUpdateNetworks = useCallback(async () => {
|
const fetchAndUpdateNetworks = useCallback(async () => {
|
||||||
const unsub = () => {
|
const unsub = () => {
|
||||||
statusUnsubs.current.forEach((unsub) => unsub());
|
statusUnsubs.current.forEach((unsub) => unsub());
|
||||||
statusUnsubs.current = new Map<any, any>();
|
statusUnsubs.current.clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -110,10 +99,7 @@ const LumeProvider = ({ children }) => {
|
||||||
statusUnsubs.current = newStatusUnsubs;
|
statusUnsubs.current = newStatusUnsubs;
|
||||||
|
|
||||||
if (isMounted.current) {
|
if (isMounted.current) {
|
||||||
setLume((prevLume) => ({
|
setNetworks(Array.from(newNetworksMap.values()));
|
||||||
...prevLume,
|
|
||||||
networks: Array.from(newNetworksMap.values()),
|
|
||||||
}));
|
|
||||||
} else {
|
} else {
|
||||||
unsub();
|
unsub();
|
||||||
}
|
}
|
||||||
|
@ -139,29 +125,18 @@ const LumeProvider = ({ children }) => {
|
||||||
}, [fetchAndUpdateNetworks]);
|
}, [fetchAndUpdateNetworks]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LumeContext.Provider
|
<NetworksContext.Provider value={{ networks, setNetworks }}>
|
||||||
value={{
|
|
||||||
lume,
|
|
||||||
ready,
|
|
||||||
setReady,
|
|
||||||
isLoggedIn,
|
|
||||||
setIsLoggedIn,
|
|
||||||
inited,
|
|
||||||
setInited,
|
|
||||||
}}>
|
|
||||||
{children}
|
{children}
|
||||||
</LumeContext.Provider>
|
</NetworksContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LumeProvider;
|
export function useNetworks() {
|
||||||
|
const context = useContext(NetworksContext);
|
||||||
export function useLume() {
|
if (!context) {
|
||||||
const ctx = useContext(LumeContext);
|
throw new Error("useNetworks must be used within a NetworksProvider");
|
||||||
|
}
|
||||||
if (!ctx) {
|
return context;
|
||||||
throw new Error("useLume must be used within a LumeProvider");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx;
|
export default NetworksProvider;
|
||||||
}
|
|
|
@ -1,11 +1,11 @@
|
||||||
import * as Dialog from "@radix-ui/react-dialog";
|
import * as Dialog from "@radix-ui/react-dialog";
|
||||||
import { Network, useLume } from "../LumeProvider";
|
|
||||||
import Logo from "../../../assets/lume-logo.png";
|
import Logo from "../../../assets/lume-logo.png";
|
||||||
import { cva } from "class-variance-authority";
|
import { cva } from "class-variance-authority";
|
||||||
import { cn } from "../../utils";
|
import { cn } from "../../utils";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import camelCase from "camelcase";
|
import camelCase from "camelcase";
|
||||||
|
import { useNetworks, type Network } from "../../NetworksProvider";
|
||||||
|
|
||||||
const SYNCSTATE_TO_TEXT: Record<Network["syncState"], string> = {
|
const SYNCSTATE_TO_TEXT: Record<Network["syncState"], string> = {
|
||||||
done: "Synced",
|
done: "Synced",
|
||||||
|
@ -18,9 +18,7 @@ LumeDashboardTrigger.displayName = "LumeDashboardTrigger";
|
||||||
|
|
||||||
const LumeDashboard = (props: any) => {
|
const LumeDashboard = (props: any) => {
|
||||||
const { children }: { children: React.PropsWithChildren } = props;
|
const { children }: { children: React.PropsWithChildren } = props;
|
||||||
const {
|
const { networks } = useNetworks();
|
||||||
lume: { networks },
|
|
||||||
} = useLume();
|
|
||||||
|
|
||||||
const [uniqueNetworkTypes, setUniqueNetworkTypes] = useState<string[]>([]);
|
const [uniqueNetworkTypes, setUniqueNetworkTypes] = useState<string[]>([]);
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,15 @@ import {
|
||||||
// loginComplete,
|
// loginComplete,
|
||||||
// logoutComplete,
|
// logoutComplete,
|
||||||
} from "@lumeweb/libkernel/kernel";
|
} from "@lumeweb/libkernel/kernel";
|
||||||
import { useLume } from "../LumeProvider";
|
|
||||||
import React, { useContext } from "react";
|
import React, { useContext } from "react";
|
||||||
|
import { useAuth } from "../../AuthProvider.js";
|
||||||
|
|
||||||
export const LumeIdentityContext = React.createContext<
|
export const LumeIdentityContext = React.createContext<
|
||||||
{ open: boolean; setOpen: (open: boolean) => void } | undefined
|
{ open: boolean; setOpen: (open: boolean) => void } | undefined
|
||||||
>(undefined);
|
>(undefined);
|
||||||
|
|
||||||
export function useLumeIndentity() {
|
export function useLumeIdentity() {
|
||||||
const { isLoggedIn, setIsLoggedIn } = useLume();
|
const { isLoggedIn, setIsLoggedIn } = useAuth();
|
||||||
const ctx = useContext(LumeIdentityContext);
|
const ctx = useContext(LumeIdentityContext);
|
||||||
|
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
ExclamationTriangleIcon,
|
ExclamationTriangleIcon,
|
||||||
} from "@radix-ui/react-icons";
|
} from "@radix-ui/react-icons";
|
||||||
import { AnimatePresence, m } from "framer-motion";
|
import { AnimatePresence, m } from "framer-motion";
|
||||||
import { useLumeIndentity } from "./LumeIdentityContext";
|
import { useLumeIdentity } from "./LumeIdentityContext";
|
||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
|
|
||||||
import * as bip39 from "@scure/bip39";
|
import * as bip39 from "@scure/bip39";
|
||||||
|
@ -54,7 +54,7 @@ const SubmitButtonComponent = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const SeedPhraseInputComponent = () => {
|
const SeedPhraseInputComponent = () => {
|
||||||
const { signIn } = useLumeIndentity();
|
const { signIn } = useLumeIdentity();
|
||||||
return (
|
return (
|
||||||
<m.form
|
<m.form
|
||||||
className="flex-col flex gap-y-4"
|
className="flex-col flex gap-y-4"
|
||||||
|
@ -118,7 +118,7 @@ const SeedPhraseGenerationComponent = ({ phraseLength = 12 }) => {
|
||||||
"idle" | "clicked"
|
"idle" | "clicked"
|
||||||
>("idle");
|
>("idle");
|
||||||
const [step, setStep] = useState<number>(0);
|
const [step, setStep] = useState<number>(0);
|
||||||
const { signIn } = useLumeIndentity();
|
const { signIn } = useLumeIdentity();
|
||||||
|
|
||||||
const phrases = useMemo(() => {
|
const phrases = useMemo(() => {
|
||||||
return bip39
|
return bip39
|
||||||
|
@ -158,10 +158,12 @@ const SeedPhraseGenerationComponent = ({ phraseLength = 12 }) => {
|
||||||
<div
|
<div
|
||||||
key={`SeedPhrase_${index}`}
|
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)]`}>
|
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}
|
{phrase}
|
||||||
</span>
|
</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}
|
{index + 1}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
18
src/index.ts
18
src/index.ts
|
@ -1,8 +1,18 @@
|
||||||
export {
|
export {
|
||||||
default as LumeProvider,
|
default as AuthProvider,
|
||||||
useLume,
|
useAuth,
|
||||||
type LumeContextType,
|
type AuthContextType,
|
||||||
} from "./components/lume/LumeProvider";
|
} 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 {
|
export {
|
||||||
default as LumeDashboard,
|
default as LumeDashboard,
|
||||||
LumeDashboardTrigger,
|
LumeDashboardTrigger,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { StoryFn, Meta } from "@storybook/react";
|
import { StoryFn, Meta } from "@storybook/react";
|
||||||
import LumeDashboard from "../src/components/lume/LumeDashboard/LumeDashboard.js";
|
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 {
|
export default {
|
||||||
title: "LumeDashboard",
|
title: "LumeDashboard",
|
||||||
|
@ -9,9 +9,9 @@ export default {
|
||||||
} as Meta<typeof LumeDashboard>;
|
} as Meta<typeof LumeDashboard>;
|
||||||
|
|
||||||
const Template: StoryFn<typeof LumeDashboard> = (args) => (
|
const Template: StoryFn<typeof LumeDashboard> = (args) => (
|
||||||
<LumeProvider>
|
<NetworksProvider>
|
||||||
<LumeDashboard {...args} />
|
<LumeDashboard {...args} />
|
||||||
</LumeProvider>
|
</NetworksProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const Primary = Template.bind({});
|
export const Primary = Template.bind({});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { StoryFn, Meta } from "@storybook/react";
|
import { StoryFn, Meta } from "@storybook/react";
|
||||||
import LumeIdentity from "../src/components/lume/LumeIdentity/LumeIdentity.js";
|
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 {
|
export default {
|
||||||
title: "LumeIdentity",
|
title: "LumeIdentity",
|
||||||
|
@ -9,9 +9,9 @@ export default {
|
||||||
} as Meta<typeof LumeIdentity>;
|
} as Meta<typeof LumeIdentity>;
|
||||||
|
|
||||||
const Template: StoryFn<typeof LumeIdentity> = (args) => (
|
const Template: StoryFn<typeof LumeIdentity> = (args) => (
|
||||||
<LumeProvider>
|
<AuthProvider>
|
||||||
<LumeIdentity {...args} />
|
<LumeIdentity {...args} />
|
||||||
</LumeProvider>
|
</AuthProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const Primary = Template.bind({});
|
export const Primary = Template.bind({});
|
||||||
|
|
Loading…
Reference in New Issue