Skip to content

Commit

Permalink
fix: add provider for recommended route store
Browse files Browse the repository at this point in the history
  • Loading branch information
chybisov committed Feb 15, 2023
1 parent 3e0d3fd commit e31da8f
Show file tree
Hide file tree
Showing 17 changed files with 296 additions and 374 deletions.
5 changes: 2 additions & 3 deletions packages/widget/src/hooks/useTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
import type { ToolsResponse } from '@lifi/sdk';
import { useQuery } from '@tanstack/react-query';
import { isItemAllowed, useLiFi, useWidgetConfig } from '../providers';
import { useSettingsStoreContext } from '../stores';
import { useSettingsStore } from '../stores';

export const useTools = () => {
const lifi = useLiFi();
const { bridges, exchanges } = useWidgetConfig();
const settingsStoreContext = useSettingsStoreContext();
const { data } = useQuery(
['tools'],
async (): Promise<ToolsResponse> => {
Expand All @@ -23,7 +22,7 @@ export const useTools = () => {
},
{
onSuccess(data) {
const { initializeTools } = settingsStoreContext.getState();
const { initializeTools } = useSettingsStore.getState();
initializeTools(
'Bridges',
data.bridges.map((bridge) => bridge.key),
Expand Down
13 changes: 5 additions & 8 deletions packages/widget/src/providers/WidgetProvider/WidgetProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ChainKey } from '@lifi/sdk';
import { getChainByKey } from '@lifi/sdk';
import { createContext, useContext, useEffect, useId, useMemo } from 'react';
import { setDefaultSettings, useSettingsStoreContext } from '../../stores';
import { createContext, useContext, useId, useMemo } from 'react';
import { setDefaultSettings } from '../../stores';
import { formatAmount } from '../../utils';
import type { WidgetContextProps, WidgetProviderProps } from './types';

Expand All @@ -28,7 +28,6 @@ export const WidgetProvider: React.FC<
...config
} = {},
}) => {
const settingsStoreContext = useSettingsStoreContext();
const elementId = useId();
const value = useMemo((): WidgetContextProps => {
try {
Expand All @@ -41,7 +40,7 @@ export const WidgetProvider: React.FC<
delete searchParams[`${key}Token`];
}
});
return {
const value = {
...config,
fromChain:
(searchParams.fromChain &&
Expand Down Expand Up @@ -80,16 +79,14 @@ export const WidgetProvider: React.FC<
: fromAmount,
elementId,
} as WidgetContextProps;
setDefaultSettings(value);
return value;
} catch (e) {
console.warn(e);
return { ...config, elementId };
}
}, [config, elementId, fromAmount, fromChain, fromToken, toChain, toToken]);

useEffect(() => {
setDefaultSettings(settingsStoreContext, value);
}, [settingsStoreContext, value]);

return (
<WidgetContext.Provider value={value}>{children}</WidgetContext.Provider>
);
Expand Down
18 changes: 5 additions & 13 deletions packages/widget/src/stores/StoreProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
import type { PropsWithChildren } from 'react';
import { ChainOrderStoreProvider } from './chains';
import { RouteExecutionStoreProvider } from './routes';
import { SettingsStoreProvider } from './settings';
import {
RecommendedRouteStoreProvider,
RouteExecutionStoreProvider,
} from './routes';
import type { PersistStoreProviderProps } from './types';

export const StoreProvider: React.FC<
PropsWithChildren<PersistStoreProviderProps>
> = ({ children, namePrefix }) => {
return (
<RouteExecutionStoreProvider namePrefix={namePrefix}>
{/* We don't want separate settings in each widget instance for now. */}
<SettingsStoreProvider
// namePrefix={namePrefix}
>
<ChainOrderStoreProvider
// namePrefix={namePrefix}
>
{children}
</ChainOrderStoreProvider>
</SettingsStoreProvider>
<RecommendedRouteStoreProvider>{children}</RecommendedRouteStoreProvider>
</RouteExecutionStoreProvider>
);
};
50 changes: 0 additions & 50 deletions packages/widget/src/stores/chains/ChainOrderStore.tsx

This file was deleted.

67 changes: 0 additions & 67 deletions packages/widget/src/stores/chains/createChainOrderStore.ts

This file was deleted.

3 changes: 1 addition & 2 deletions packages/widget/src/stores/chains/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from './ChainOrderStore';
export * from './createChainOrderStore';
export * from './types';
export * from './useChainOrder';
export * from './useChainOrderStore';
2 changes: 1 addition & 1 deletion packages/widget/src/stores/chains/useChainOrder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { shallow } from 'zustand/shallow';
import { useChainOrderStore } from './ChainOrderStore';
import { useChainOrderStore } from '.';

export const useChainOrder = (): [number[], (chainId: number) => void] => {
return useChainOrderStore(
Expand Down
65 changes: 65 additions & 0 deletions packages/widget/src/stores/chains/useChainOrderStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/* eslint-disable no-underscore-dangle */
import type { StateCreator } from 'zustand';
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import type { ChainOrderState } from './types';

export const maxChainToOrder = 9;

export const useChainOrderStore = create<ChainOrderState>(
persist(
(set, get) => ({
chainOrder: [],
availableChains: [],
initializeChains: (chainIds: number[]) => {
set((state: ChainOrderState) => {
const chainOrder = state.chainOrder.filter((chainId) =>
chainIds.includes(chainId),
);
const chainsToAdd = chainIds.filter(
(chainId) => !chainOrder.includes(chainId),
);
if (chainOrder.length === maxChainToOrder || !chainsToAdd.length) {
return {
availableChains: chainIds,
chainOrder,
};
}
const chainsToAddLength = maxChainToOrder - chainOrder.length;
for (let index = 0; index < chainsToAddLength; index++) {
chainOrder.push(chainsToAdd[index]);
}
return {
availableChains: chainIds,
chainOrder,
};
});
return get().chainOrder;
},
setChain: (chainId: number) => {
const state = get();
if (
state.chainOrder.includes(chainId) ||
!state.availableChains.includes(chainId)
) {
return;
}
set((state: ChainOrderState) => {
const chainOrder = state.chainOrder.slice();
chainOrder.unshift(chainId);
if (chainOrder.length > maxChainToOrder) {
chainOrder.pop();
}
return {
chainOrder,
};
});
},
}),
{
name: `li.fi-widget-chains-order`,
version: 0,
partialize: (state) => ({ chainOrder: state.chainOrder }),
},
) as StateCreator<ChainOrderState, [], [], ChainOrderState>,
);
2 changes: 1 addition & 1 deletion packages/widget/src/stores/routes/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export enum RouteExecutionStatus {
Refunded = 1 << 4,
}

export interface RecommendedRouteStore {
export interface RecommendedRouteState {
recommendedRoute?: Route;
setRecommendedRoute: (route?: Route) => void;
}
13 changes: 0 additions & 13 deletions packages/widget/src/stores/routes/useRecommendedRouteStore.ts

This file was deleted.

60 changes: 60 additions & 0 deletions packages/widget/src/stores/routes/useRecommendedRouteStore.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import type { Route } from '@lifi/sdk';
import { createContext, useContext, useRef } from 'react';
import type { StoreApi, UseBoundStore } from 'zustand';
import { create } from 'zustand';
import type { PersistStoreProviderProps } from '../types';
import type { RecommendedRouteState } from './types';

export const createRecommendedRouteStore = () =>
create<RecommendedRouteState>((set) => ({
setRecommendedRoute: (recommendedRoute?: Route) => {
set(() => ({
recommendedRoute,
}));
},
}));

export type RecommendedRouteStore = UseBoundStore<
StoreApi<RecommendedRouteState>
>;

export const RecommendedRouteStoreContext =
createContext<RecommendedRouteStore | null>(null);

export function RecommendedRouteStoreProvider({
children,
...props
}: PersistStoreProviderProps) {
const storeRef = useRef<RecommendedRouteStore>();
if (!storeRef.current) {
storeRef.current = createRecommendedRouteStore();
}
return (
<RecommendedRouteStoreContext.Provider value={storeRef.current}>
{children}
</RecommendedRouteStoreContext.Provider>
);
}

export function useRecommendedRouteStore<T>(
selector: (state: RecommendedRouteState) => T,
equalityFn?: (left: T, right: T) => boolean,
): T {
const useStore = useContext(RecommendedRouteStoreContext);
if (!useStore) {
throw new Error(
`You forgot to wrap your component in <${RecommendedRouteStoreProvider.name}>.`,
);
}
return useStore(selector, equalityFn);
}

export function useRecommendedRouteStoreContext() {
const useStore = useContext(RecommendedRouteStoreContext);
if (!useStore) {
throw new Error(
`You forgot to wrap your component in <${RecommendedRouteStoreProvider.name}>.`,
);
}
return useStore;
}
Loading

0 comments on commit e31da8f

Please sign in to comment.