From 5c5c74724f2e796b8dc2b700215980251e907ae8 Mon Sep 17 00:00:00 2001 From: Steven Date: Wed, 27 Nov 2024 08:36:07 +0100 Subject: [PATCH] feat(rwa): add firebase (#2689) --- .changeset/afraid-parents-sparkle.md | 5 + .changeset/tame-horses-heal.md | 2 + packages/apps/rwa-demo/package.json | 1 + .../apps/rwa-demo/src/app/(app)/layout.tsx | 94 ++++++++++-- packages/apps/rwa-demo/src/app/(app)/page.tsx | 3 +- .../ActiveTransactionsList.tsx | 24 +++ .../components/AddAgentForm/AddAgentForm.tsx | 5 +- .../AddInvestorForm/AddInvestorForm.tsx | 3 +- .../src/components/AgentsList/AgentsList.tsx | 20 ++- .../DistributionForm/DistributionForm.tsx | 39 ++++- .../FreezeInvestor/FreezeInvestor.tsx | 19 ++- .../components/HomePage/InvestorRootPage.tsx | 2 - .../components/InvestorList/InvestorList.tsx | 67 ++++---- .../src/components/PauseForm/PauseForm.tsx | 27 +++- .../SendTransactionAnimation.tsx | 70 +++++++++ .../SendTransactionAnimation/styles.css.ts | 26 ++++ .../TransactionsProvider.tsx | 145 +++++++++++++----- .../rwa-demo/src/hooks/distributeTokens.ts | 7 +- packages/apps/rwa-demo/src/hooks/getAgents.ts | 1 - .../apps/rwa-demo/src/hooks/getInvestors.ts | 17 +- .../apps/rwa-demo/src/hooks/setCompliance.ts | 3 +- .../apps/rwa-demo/src/hooks/transferTokens.ts | 3 +- .../apps/rwa-demo/src/utils/store/firebase.ts | 35 +++++ .../apps/rwa-demo/src/utils/store/index.ts | 55 +++++++ .../SideBarLayout/SideBarLayout.stories.tsx | 5 + .../src/patterns/SideBarLayout/aside.css.ts | 7 +- .../LayoutProvider/SideBarLayoutProvider.tsx | 9 ++ .../components/SideBarHeader.tsx | 15 +- .../SideBarHeaderContext.tsx | 13 ++ .../src/patterns/SideBarLayout/index.ts | 1 + .../src/patterns/SideBarLayout/sidebar.css.ts | 15 +- packages/libs/kode-ui/src/patterns/index.ts | 1 + pnpm-lock.yaml | 121 ++++++++------- 33 files changed, 643 insertions(+), 217 deletions(-) create mode 100644 .changeset/afraid-parents-sparkle.md create mode 100644 .changeset/tame-horses-heal.md create mode 100644 packages/apps/rwa-demo/src/components/ActiveTransactionsList/ActiveTransactionsList.tsx create mode 100644 packages/apps/rwa-demo/src/components/SendTransactionAnimation/SendTransactionAnimation.tsx create mode 100644 packages/apps/rwa-demo/src/components/SendTransactionAnimation/styles.css.ts create mode 100644 packages/apps/rwa-demo/src/utils/store/firebase.ts create mode 100644 packages/apps/rwa-demo/src/utils/store/index.ts create mode 100644 packages/libs/kode-ui/src/patterns/SideBarLayout/components/SideBarHeaderContext/SideBarHeaderContext.tsx diff --git a/.changeset/afraid-parents-sparkle.md b/.changeset/afraid-parents-sparkle.md new file mode 100644 index 0000000000..a62914ab65 --- /dev/null +++ b/.changeset/afraid-parents-sparkle.md @@ -0,0 +1,5 @@ +--- +'@kadena/kode-ui': minor +--- + +add context section in the sidebar layout header diff --git a/.changeset/tame-horses-heal.md b/.changeset/tame-horses-heal.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/tame-horses-heal.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/packages/apps/rwa-demo/package.json b/packages/apps/rwa-demo/package.json index 1868b1a9a1..5ead245a13 100644 --- a/packages/apps/rwa-demo/package.json +++ b/packages/apps/rwa-demo/package.json @@ -32,6 +32,7 @@ "@vanilla-extract/recipes": "0.5.1", "@vanilla-extract/sprinkles": "1.6.1", "cache-sh": "^1.2.1", + "firebase": "^10.8.0", "graphql": "~16.8.1", "graphql-ws": "^5.16.0", "next": "14.2.2", diff --git a/packages/apps/rwa-demo/src/app/(app)/layout.tsx b/packages/apps/rwa-demo/src/app/(app)/layout.tsx index f68cb42d52..0b4c6fb377 100644 --- a/packages/apps/rwa-demo/src/app/(app)/layout.tsx +++ b/packages/apps/rwa-demo/src/app/(app)/layout.tsx @@ -1,11 +1,22 @@ 'use client'; -import { SideBarLayout } from '@kadena/kode-ui/patterns'; +import { + RightAside, + RightAsideContent, + RightAsideHeader, + SideBarHeaderContext, + SideBarLayout, + useLayout, +} from '@kadena/kode-ui/patterns'; +import { ActiveTransactionsList } from '@/components/ActiveTransactionsList/ActiveTransactionsList'; import { AssetInfo } from '@/components/AssetInfo/AssetInfo'; import { AssetForm } from '@/components/AssetSwitch/AssetForm'; +import { TransactionPendingIcon } from '@/components/TransactionPendingIcon/TransactionPendingIcon'; +import { useTransactions } from '@/hooks/transactions'; import { getAsset } from '@/utils/getAsset'; -import { Heading, Link, Stack } from '@kadena/kode-ui'; -import React from 'react'; +import { MonoAccountBalanceWallet } from '@kadena/kode-icons'; +import { Button, Heading, Link, Stack } from '@kadena/kode-ui'; +import React, { useEffect, useRef, useState } from 'react'; import { KLogo } from './KLogo'; import { SideBar } from './SideBar'; @@ -14,6 +25,19 @@ const RootLayout = ({ }: Readonly<{ children: React.ReactNode; }>) => { + const [openTransactionsSide, setOpenTransactionsSide] = useState(false); + const { setIsRightAsideExpanded, isRightAsideExpanded } = useLayout(); + const { transactions, setTxsButtonRef, setTxsAnimationRef } = + useTransactions(); + const txsButtonRef = useRef(null); + const transactionAnimationRef = useRef(null); + + useEffect(() => { + if (!txsButtonRef.current || !transactionAnimationRef.current) return; + setTxsButtonRef(txsButtonRef.current); + setTxsAnimationRef(transactionAnimationRef.current); + }, [txsButtonRef.current, transactionAnimationRef.current]); + if (!getAsset()) { return ( - - - } - sidebar={} - > - - - - {children} - - + <> + + - + + Distribute + + } + /> diff --git a/packages/apps/rwa-demo/src/components/FreezeInvestor/FreezeInvestor.tsx b/packages/apps/rwa-demo/src/components/FreezeInvestor/FreezeInvestor.tsx index a5ba65e59f..f86e21c65d 100644 --- a/packages/apps/rwa-demo/src/components/FreezeInvestor/FreezeInvestor.tsx +++ b/packages/apps/rwa-demo/src/components/FreezeInvestor/FreezeInvestor.tsx @@ -7,6 +7,7 @@ import { MonoPause, MonoPlayArrow } from '@kadena/kode-icons'; import { Button } from '@kadena/kode-ui'; import type { FC } from 'react'; import React, { useEffect, useState } from 'react'; +import { SendTransactionAnimation } from '../SendTransactionAnimation/SendTransactionAnimation'; import { TransactionPendingIcon } from '../TransactionPendingIcon/TransactionPendingIcon'; interface IProps { @@ -43,14 +44,11 @@ export const FreezeInvestor: FC = ({ investorAccount }) => { const client = getClient(); const res = await client.submit(signedTransaction); - addTransaction({ + const transaction = await addTransaction({ ...res, type: 'FREEZE-ADDRESS', - data: { - ...res, - ...data, - }, }); + return transaction; } catch (e: any) { setIsLoading(false); } @@ -61,8 +59,13 @@ export const FreezeInvestor: FC = ({ investorAccount }) => { }, [frozen]); return ( - + + {frozen ? 'Unfreeze account' : 'Freeze account'} + + } + > ); }; diff --git a/packages/apps/rwa-demo/src/components/HomePage/InvestorRootPage.tsx b/packages/apps/rwa-demo/src/components/HomePage/InvestorRootPage.tsx index 7157e4e598..64345ab112 100644 --- a/packages/apps/rwa-demo/src/components/HomePage/InvestorRootPage.tsx +++ b/packages/apps/rwa-demo/src/components/HomePage/InvestorRootPage.tsx @@ -1,4 +1,3 @@ -import { SideBarBreadcrumbs } from '@/components/SideBarBreadcrumbs/SideBarBreadcrumbs'; import { useAccount } from '@/hooks/account'; import { MonoCompareArrows } from '@kadena/kode-icons'; import { Button, Stack } from '@kadena/kode-ui'; @@ -34,7 +33,6 @@ export const InvestorRootPage: FC = () => { - + {paused ? 'paused' : 'active'} + } + > ); }; diff --git a/packages/apps/rwa-demo/src/components/SendTransactionAnimation/SendTransactionAnimation.tsx b/packages/apps/rwa-demo/src/components/SendTransactionAnimation/SendTransactionAnimation.tsx new file mode 100644 index 0000000000..9e07ff6845 --- /dev/null +++ b/packages/apps/rwa-demo/src/components/SendTransactionAnimation/SendTransactionAnimation.tsx @@ -0,0 +1,70 @@ +import { useTransactions } from '@/hooks/transactions'; +import { MonoWallet } from '@kadena/kode-icons'; +import type { PressEvent } from '@kadena/kode-ui'; +import type { FC, ReactElement } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; +import { createPortal } from 'react-dom'; +import { animationIconClass } from './styles.css'; +interface IProps { + onPress: (e: PressEvent) => any; + trigger: ReactElement; +} + +export const SendTransactionAnimation: FC = ({ trigger, onPress }) => { + const { txsButtonRef, txsAnimationRef } = useTransactions(); + const [showAnimation, setShowAnimation] = useState(false); + const [triggerPos, setTriggerPos] = useState(); + const [txButtonPos, setTxButtonPos] = useState(); + const ref = useRef(null); + const handlePress = async (e: PressEvent) => { + const tx = await onPress(e); + if (tx) { + setShowAnimation(true); + + setTimeout(() => { + setShowAnimation(false); + }, 2500); + } + }; + + useEffect(() => { + if (ref.current) { + const rect = ref.current.getBoundingClientRect(); + setTriggerPos(rect); + } + + if (txsButtonRef) { + const rect = txsButtonRef.getBoundingClientRect(); + setTxButtonPos(rect); + } + }, [ref.current, txsButtonRef, showAnimation]); + + const style = { + left: `${triggerPos?.x}px`, + top: `${triggerPos?.y}px`, + transition: 'left 2s ease-out, top 2s ease-in', + }; + if (showAnimation) { + style.left = `${txButtonPos?.x}px`; + style.top = `${txButtonPos?.y}px`; + } + + return ( + <> + {txsAnimationRef && + createPortal( +
+ +
, + txsAnimationRef, + )} + +
+ {React.cloneElement(trigger, { + ...trigger.props, + onPress: handlePress, + })} +
+ + ); +}; diff --git a/packages/apps/rwa-demo/src/components/SendTransactionAnimation/styles.css.ts b/packages/apps/rwa-demo/src/components/SendTransactionAnimation/styles.css.ts new file mode 100644 index 0000000000..119d76dcfe --- /dev/null +++ b/packages/apps/rwa-demo/src/components/SendTransactionAnimation/styles.css.ts @@ -0,0 +1,26 @@ +import { recipe } from '@kadena/kode-ui'; +import { keyframes } from '@vanilla-extract/css'; + +const scale = keyframes({ + '0%': { transform: 'scale(1, 1); opacity:0' }, + '20%': { transform: 'scale(1, 1); opacity:.8' }, + '80%': { transform: 'scale(2.5, 2.5); opacity: .8' }, + '100%': { transform: 'scale(.5, .5); opacity:0' }, +}); + +export const animationIconClass = recipe({ + base: { + position: 'fixed', + zIndex: 99999, + opacity: 0, + pointerEvents: 'none', + }, + variants: { + showAnimation: { + true: { + animation: `${scale} 2s ease-in-out`, + }, + false: {}, + }, + }, +}); diff --git a/packages/apps/rwa-demo/src/components/TransactionsProvider/TransactionsProvider.tsx b/packages/apps/rwa-demo/src/components/TransactionsProvider/TransactionsProvider.tsx index 2d4a006425..e2845fe0b5 100644 --- a/packages/apps/rwa-demo/src/components/TransactionsProvider/TransactionsProvider.tsx +++ b/packages/apps/rwa-demo/src/components/TransactionsProvider/TransactionsProvider.tsx @@ -1,31 +1,41 @@ 'use client'; +import { useAccount } from '@/hooks/account'; import { useNetwork } from '@/hooks/networks'; import { getClient } from '@/utils/client'; +import { store } from '@/utils/store'; import type { ICommandResult } from '@kadena/client'; import { useNotifications } from '@kadena/kode-ui/patterns'; import type { FC, PropsWithChildren } from 'react'; -import { createContext, useCallback, useState } from 'react'; +import { createContext, useCallback, useEffect, useState } from 'react'; +import type { IWalletAccount } from './utils'; export interface ITransaction { + uuid: string; requestKey: string; type: string; - data: Record; listener?: Promise; - result?: boolean; } export interface ITransactionsContext { - transactions: Record; - addTransaction: (request: ITransaction) => ITransaction; + transactions: ITransaction[]; + addTransaction: ( + request: Omit, + ) => Promise; getTransactions: (type: string) => ITransaction[]; + txsButtonRef?: HTMLButtonElement | null; + setTxsButtonRef: (value: HTMLButtonElement) => void; + txsAnimationRef?: HTMLDivElement | null; + setTxsAnimationRef: (value: HTMLDivElement) => void; } export const TransactionsContext = createContext({ - transactions: {}, - addTransaction: (request) => { + transactions: [], + addTransaction: async (request) => { return {} as ITransaction; }, getTransactions: () => [], + setTxsButtonRef: () => {}, + setTxsAnimationRef: () => {}, }); const interpretMessage = (str: string, data?: ITransaction): string => { @@ -52,38 +62,48 @@ export const interpretErrorMessage = ( export const TransactionsProvider: FC = ({ children }) => { const { addNotification } = useNotifications(); - const [transactions, setTransactions] = useState< - Record - >({}); + const { account } = useAccount(); + const [transactions, setTransactions] = useState([]); + const [txsAnimationRef, setTxsAnimationRefData] = + useState(null); + const [txsButtonRef, setTxsButtonRefData] = + useState(null); const { activeNetwork } = useNetwork(); - const addListener = useCallback((data: ITransaction) => { - return getClient() - .listen({ - requestKey: data.requestKey, - chainId: activeNetwork.chainId, - networkId: activeNetwork.networkId, - }) - .then((result) => { - if (result.result.status === 'failure') { + const addListener = useCallback( + (data: ITransaction, account: IWalletAccount) => { + return getClient() + .listen({ + requestKey: data.requestKey, + chainId: activeNetwork.chainId, + networkId: activeNetwork.networkId, + }) + .then((result) => { + if (result.result.status === 'failure') { + addNotification({ + intent: 'negative', + label: 'there was an error', + message: interpretErrorMessage(result, data), + url: `https://explorer.kadena.io/${activeNetwork.networkId}/transaction/${data.requestKey}`, + }); + } + }) + .catch((e) => { addNotification({ intent: 'negative', label: 'there was an error', - message: interpretErrorMessage(result, data), + message: JSON.stringify(e), url: `https://explorer.kadena.io/${activeNetwork.networkId}/transaction/${data.requestKey}`, }); - } - }) - .catch((e) => { - addNotification({ - intent: 'negative', - label: 'there was an error', - message: JSON.stringify(e), - url: `https://explorer.kadena.io/${activeNetwork.networkId}/transaction/${data.requestKey}`, + }) + .finally(() => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + store.removeTransaction(account!, data); }); - }); - }, []); + }, + [], + ); const getTransactions = (type: string) => { return Object.entries(transactions) @@ -91,24 +111,75 @@ export const TransactionsProvider: FC = ({ children }) => { .filter((val) => val.type === type); }; - const addTransaction = (request: ITransaction) => { - if (transactions[request.requestKey]) { + const addTransaction = async ( + request: Omit, + ): Promise => { + const foundExistingTransaction = transactions.find( + (v) => v.requestKey === request.requestKey, + ); + if (foundExistingTransaction) { console.error('requestKey already exists', request.requestKey); - return transactions[request.requestKey]; + return foundExistingTransaction; } - const data = { ...request }; - data.listener = addListener(data); + const data = { ...request, uuid: crypto.randomUUID() }; + data.listener = addListener(data, account!); setTransactions((v) => { - return { ...v, [request.requestKey]: { ...data } }; + return [...v, data]; }); + await store.addTransaction(account!, data); + return data; }; + const listenToTransactions = (transactions: ITransaction[]) => { + setTransactions(transactions); + }; + + const init = async () => { + store.listenToAllTransactions(account!, listenToTransactions); + }; + useEffect(() => { + if (!account) return; + // eslint-disable-next-line @typescript-eslint/no-floating-promises + init(); + }, [account]); + + useEffect(() => { + if (!account && !transactions.find((v) => !v.listener)) return; + + setTransactions((v) => { + const transactionsWithListeners = v.map((transaction) => { + const newTx = { ...transaction }; + if (newTx.listener) return newTx; + newTx.listener = addListener(newTx, account!); + + return newTx; + }); + + return transactionsWithListeners; + }); + }, [transactions.length, account]); + + const setTxsButtonRef = (ref: HTMLButtonElement) => { + setTxsButtonRefData(ref); + }; + const setTxsAnimationRef = (ref: HTMLDivElement) => { + setTxsAnimationRefData(ref); + }; + return ( {children} diff --git a/packages/apps/rwa-demo/src/hooks/distributeTokens.ts b/packages/apps/rwa-demo/src/hooks/distributeTokens.ts index 574461900d..fd7a8a8ef2 100644 --- a/packages/apps/rwa-demo/src/hooks/distributeTokens.ts +++ b/packages/apps/rwa-demo/src/hooks/distributeTokens.ts @@ -12,21 +12,18 @@ export const useDistributeTokens = () => { try { const tx = await distributeTokens(data, account!); - console.log(tx); const signedTransaction = await sign(tx); if (!signedTransaction) return; const client = getClient(); const res = await client.submit(signedTransaction); - addTransaction({ + const transaction = await addTransaction({ ...res, type: 'DISTRIBUTETOKENS', - data: { ...res, ...data }, }); - console.log({ res }); - console.log('DONE'); + return transaction; } catch (e: any) {} }; diff --git a/packages/apps/rwa-demo/src/hooks/getAgents.ts b/packages/apps/rwa-demo/src/hooks/getAgents.ts index e719145328..82f369311f 100644 --- a/packages/apps/rwa-demo/src/hooks/getAgents.ts +++ b/packages/apps/rwa-demo/src/hooks/getAgents.ts @@ -123,7 +123,6 @@ export const useGetAgents = () => { }) .filter((v) => v !== undefined) ?? []) as IRecord[]; - console.log(); const filteredData = [ ...filterRemovedRecords([ ...agentsAdded, diff --git a/packages/apps/rwa-demo/src/hooks/getInvestors.ts b/packages/apps/rwa-demo/src/hooks/getInvestors.ts index ff78787c7b..b96f4481e8 100644 --- a/packages/apps/rwa-demo/src/hooks/getInvestors.ts +++ b/packages/apps/rwa-demo/src/hooks/getInvestors.ts @@ -44,18 +44,6 @@ export const useGetInvestors = () => { return; } - const promises = transactions.map(async (t): Promise => { - const result = await t.listener; - return { - blockHeight: result?.metaData?.blockHeight, - chainId: t.data.chainId, - requestKey: t.requestKey, - accountName: t.data.agent, - result: result?.result.status === 'success', - } as IRecord; - }); - const promiseResults = await Promise.all(promises); - const agentsAdded: IRecord[] = addedData?.events.edges.map((edge: any) => { return { @@ -84,10 +72,7 @@ export const useGetInvestors = () => { console.log({ agentsAdded, agentsRemoved }); - setInnerData([ - ...filterRemovedRecords([...agentsAdded, ...agentsRemoved]), - ...promiseResults, - ]); + setInnerData([...filterRemovedRecords([...agentsAdded, ...agentsRemoved])]); }; useEffect(() => { diff --git a/packages/apps/rwa-demo/src/hooks/setCompliance.ts b/packages/apps/rwa-demo/src/hooks/setCompliance.ts index 201acf00bd..de0693d41e 100644 --- a/packages/apps/rwa-demo/src/hooks/setCompliance.ts +++ b/packages/apps/rwa-demo/src/hooks/setCompliance.ts @@ -21,10 +21,9 @@ export const useSetCompliance = () => { const client = getClient(); const res = await client.submit(signedTransaction); - addTransaction({ + await addTransaction({ ...res, type: 'SETCOMPLIANCE', - data: { ...res, ...data }, }); console.log({ res }); diff --git a/packages/apps/rwa-demo/src/hooks/transferTokens.ts b/packages/apps/rwa-demo/src/hooks/transferTokens.ts index 77149376e8..fe63012dcd 100644 --- a/packages/apps/rwa-demo/src/hooks/transferTokens.ts +++ b/packages/apps/rwa-demo/src/hooks/transferTokens.ts @@ -20,10 +20,9 @@ export const useTransferTokens = () => { const client = getClient(); const res = await client.submit(signedTransaction); - addTransaction({ + await addTransaction({ ...res, type: 'TRANSFERTOKENS', - data: { ...res }, }); console.log({ res }); diff --git a/packages/apps/rwa-demo/src/utils/store/firebase.ts b/packages/apps/rwa-demo/src/utils/store/firebase.ts new file mode 100644 index 0000000000..961b9f9656 --- /dev/null +++ b/packages/apps/rwa-demo/src/utils/store/firebase.ts @@ -0,0 +1,35 @@ +// Import the functions you need from the SDKs you need +import { initializeApp } from 'firebase/app'; +import type { Database, DatabaseReference } from 'firebase/database'; +import { getDatabase, ref } from 'firebase/database'; +// TODO: Add SDKs for Firebase products that you want to use +// https://firebase.google.com/docs/web/setup#available-libraries + +// Your web app's Firebase configuration +// For Firebase JS SDK v7.20.0 and later, measurementId is optional + +let database: Database; +let dbRef: DatabaseReference; +if ( + process.env.NEXT_PUBLIC_FB_APIKEY && + process.env.NEXT_PUBLIC_FB_PROJECTID && + process.env.NEXT_PUBLIC_FB_APPID && + process.env.NEXT_PUBLIC_FB_DBURL +) { + const firebaseConfig = { + apiKey: process.env.NEXT_PUBLIC_FB_APIKEY, + projectId: process.env.NEXT_PUBLIC_FB_PROJECTID, + appId: process.env.NEXT_PUBLIC_FB_APPID, + databaseURL: process.env.NEXT_PUBLIC_FB_DBURL, + }; + + const app = initializeApp(firebaseConfig); + database = getDatabase(app); + dbRef = ref(getDatabase()); +} + +// Initialize Firebase + +export { database, dbRef }; + +//export const analytics = getAnalytics(app); diff --git a/packages/apps/rwa-demo/src/utils/store/index.ts b/packages/apps/rwa-demo/src/utils/store/index.ts new file mode 100644 index 0000000000..bf96f2744c --- /dev/null +++ b/packages/apps/rwa-demo/src/utils/store/index.ts @@ -0,0 +1,55 @@ +import type { IWalletAccount } from '@/components/AccountProvider/utils'; +import type { ITransaction } from '@/components/TransactionsProvider/TransactionsProvider'; +import { get, off, onValue, ref, set } from 'firebase/database'; +import { database } from './firebase'; + +const RWAStore = () => { + const addTransaction = async ( + account: IWalletAccount, + data: ITransaction, + ) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { listener, ...newTransaction } = data; + await set(ref(database, `accounts/${account.address}/${data.uuid}`), data); + }; + + const removeTransaction = async ( + account: IWalletAccount, + data: ITransaction, + ) => { + await set(ref(database, `accounts/${account.address}/${data.uuid}`), null); + }; + + const getAllTransactions = async ( + account: IWalletAccount, + ): Promise => { + if (!account) return []; + const snapshot = await get(ref(database, `accounts/${account.address}`)); + + const data = snapshot.toJSON(); + if (!data) return []; + return Object.entries(data).map(([key, value]) => value); + }; + + const listenToAllTransactions = ( + account: IWalletAccount, + setDataCallback: (transactions: ITransaction[]) => void, + ) => { + const accountRef = ref(database, `accounts/${account.address}`); + onValue(accountRef, async (snapshot) => { + const data = await getAllTransactions(account); + setDataCallback(data); + }); + + return () => off(accountRef); + }; + + return { + addTransaction, + removeTransaction, + getAllTransactions, + listenToAllTransactions, + }; +}; + +export const store = RWAStore(); diff --git a/packages/libs/kode-ui/src/patterns/SideBarLayout/SideBarLayout.stories.tsx b/packages/libs/kode-ui/src/patterns/SideBarLayout/SideBarLayout.stories.tsx index 8306bd41d4..b1770d39ae 100644 --- a/packages/libs/kode-ui/src/patterns/SideBarLayout/SideBarLayout.stories.tsx +++ b/packages/libs/kode-ui/src/patterns/SideBarLayout/SideBarLayout.stories.tsx @@ -1,6 +1,7 @@ import { MonoAccountTree, MonoControlPointDuplicate, + MonoInsertDriveFile, MonoLightMode, MonoWallet, MonoWifiTethering, @@ -26,6 +27,7 @@ import { } from './components/RightAside'; import { SideBarFooter } from './components/SideBarFooter'; import { SideBarFooterItem } from './components/SideBarFooterItem'; +import { SideBarHeaderContext } from './components/SideBarHeaderContext/SideBarHeaderContext'; import { SideBarItem } from './components/SideBarItem'; import { SideBarItemsInline } from './components/SideBarItemsInline'; import { SideBarTree } from './components/SideBarTree'; @@ -350,6 +352,9 @@ export const Primary: IStory = { render: () => { return ( + +