diff --git a/packages/widget/src/pages-dashboard/common/components/tabs/index.tsx b/packages/widget/src/pages-dashboard/common/components/tabs/index.tsx index 8478e96c..e542b4c2 100644 --- a/packages/widget/src/pages-dashboard/common/components/tabs/index.tsx +++ b/packages/widget/src/pages-dashboard/common/components/tabs/index.tsx @@ -17,9 +17,10 @@ import { } from "./styles.css"; import { Tab } from "./tab"; -type RouteTab = "manage" | "activity"; +type RouteTab = "earn" | "manage" | "activity"; const TABS_MAP = { + earn: "/", manage: "/manage", activity: "/activity", }; @@ -63,7 +64,8 @@ export const Tabs = () => { Match.orElse(() => "earn") ); - const { variant } = useSettings(); + const { variant, yieldGrouping } = useSettings(); + const dashboardYieldCategoryGroupingEnabled = yieldGrouping === "category"; return ( @@ -71,19 +73,28 @@ export const Tabs = () => { data-rk="tabs-section" className={combineRecipeWithVariant({ rec: tabsContainer, variant })} > - {availableDashboardYieldCategories.map((category) => ( + {dashboardYieldCategoryGroupingEnabled ? ( + availableDashboardYieldCategories.map((category) => ( + onYieldCategoryPress(category)} + variant={category} + /> + )) + ) : ( onYieldCategoryPress(category)} - variant={category} + isSelected={selectedTab === "earn"} + onTabPress={() => onRouteTabPress("earn")} + variant="earn" /> - ))} + )} - {availableDashboardYieldCategories.length > 0 ? ( + {dashboardYieldCategoryGroupingEnabled && + availableDashboardYieldCategories.length > 0 ? ( ) : null} diff --git a/packages/widget/src/pages-dashboard/common/components/tabs/tab.tsx b/packages/widget/src/pages-dashboard/common/components/tabs/tab.tsx index 75f4a089..37063772 100644 --- a/packages/widget/src/pages-dashboard/common/components/tabs/tab.tsx +++ b/packages/widget/src/pages-dashboard/common/components/tabs/tab.tsx @@ -10,7 +10,7 @@ import { tab, tabBorder, tabContainer, tabText } from "./styles.css"; type Props = { isSelected: boolean; onTabPress: () => void; - variant: "stake" | "defi" | "rwa" | "manage" | "activity"; + variant: "earn" | "stake" | "defi" | "rwa" | "manage" | "activity"; }; export const Tab = ({ isSelected, variant, onTabPress }: Props) => { diff --git a/packages/widget/src/pages-dashboard/overview/positions/hooks/use-grouped-positions.ts b/packages/widget/src/pages-dashboard/overview/positions/hooks/use-grouped-positions.ts index 7429b95c..fead5589 100644 --- a/packages/widget/src/pages-dashboard/overview/positions/hooks/use-grouped-positions.ts +++ b/packages/widget/src/pages-dashboard/overview/positions/hooks/use-grouped-positions.ts @@ -8,6 +8,7 @@ import { queryFn } from "../../../../hooks/api/use-yield-opportunity/get-yield-o import type { usePositions } from "../../../../pages/details/positions-page/hooks/use-positions"; import { useApiClient } from "../../../../providers/api/api-client-provider"; import { useSKQueryClient } from "../../../../providers/query-client"; +import { useSettings } from "../../../../providers/settings"; import { useSKWallet } from "../../../../providers/sk-wallet"; type PositionItem = ReturnType< @@ -32,19 +33,30 @@ export const useGroupedPositions = ( const { isLedgerLive } = useSKWallet(); const apiClient = useApiClient(); const queryClient = useSKQueryClient(); + const { yieldGrouping } = useSettings(); + const dashboardYieldCategoryGroupingEnabled = yieldGrouping === "category"; - const integrationIds = [...new Set(positions.map((p) => p.integrationId))]; + const integrationIds = dashboardYieldCategoryGroupingEnabled + ? [...new Set(positions.map((p) => p.integrationId))] + : []; const categoryQueries = useQueries({ queries: integrationIds.map((yieldId) => ({ queryKey: ["yield-opportunity", yieldId, isLedgerLive], - enabled: !!yieldId, + enabled: dashboardYieldCategoryGroupingEnabled && !!yieldId, staleTime, queryFn: ({ signal }: { signal: AbortSignal }) => queryFn({ yieldId, isLedgerLive, apiClient, queryClient, signal }), })), }); + if (!dashboardYieldCategoryGroupingEnabled) { + return [ + { kind: "chain-modal" }, + ...positions.map((item) => ({ kind: "position" as const, item })), + ]; + } + const categoryByIntegrationId = new Map< string, DashboardYieldCategory | null diff --git a/packages/widget/src/pages/details/earn-page/state/earn-page-context.tsx b/packages/widget/src/pages/details/earn-page/state/earn-page-context.tsx index 3793dff1..b18218c0 100644 --- a/packages/widget/src/pages/details/earn-page/state/earn-page-context.tsx +++ b/packages/widget/src/pages/details/earn-page/state/earn-page-context.tsx @@ -113,7 +113,10 @@ export const EarnPageContextProvider = ({ const { t } = useTranslation(); const initParams = useInitParams(); - const { dashboardVariant, externalProviders, variant } = useSettings(); + const { dashboardVariant, externalProviders, variant, yieldGrouping } = + useSettings(); + const dashboardYieldCategoryGroupingEnabled = + dashboardVariant && yieldGrouping === "category"; const { isConnected, isConnecting, isLedgerLiveAccountPlaceholder, chain } = useSKWallet(); @@ -298,7 +301,8 @@ export const EarnPageContextProvider = ({ ) .map(({ all, filteredDtos }) => { const dashboardFilteredDtos = - dashboardVariant && selectedDashboardYieldCategory + dashboardYieldCategoryGroupingEnabled && + selectedDashboardYieldCategory ? filteredDtos.filter( (yieldDto) => getDashboardYieldCategory(yieldDto) === @@ -358,7 +362,7 @@ export const EarnPageContextProvider = ({ }; }), [ - dashboardVariant, + dashboardYieldCategoryGroupingEnabled, deferredStakeSearch, selectedStake, yieldSummaries, @@ -482,6 +486,8 @@ export const EarnPageContextProvider = ({ }; const onDashboardYieldCategorySelect = (category: DashboardYieldCategory) => { + if (!dashboardYieldCategoryGroupingEnabled) return; + if (selectedDashboardYieldCategory === category) return; dispatch({ diff --git a/packages/widget/src/pages/details/earn-page/state/earn-page-state-context.tsx b/packages/widget/src/pages/details/earn-page/state/earn-page-state-context.tsx index 5d9f5956..4dc353c9 100644 --- a/packages/widget/src/pages/details/earn-page/state/earn-page-state-context.tsx +++ b/packages/widget/src/pages/details/earn-page/state/earn-page-state-context.tsx @@ -66,13 +66,17 @@ const getInitialState = (): State => ({ export const EarnPageStateProvider = ({ children }: PropsWithChildren) => { const { network, isConnected } = useSKWallet(); - const { dashboardVariant } = useSettings(); + const { dashboardVariant, yieldGrouping } = useSettings(); + const dashboardYieldCategoryGroupingEnabled = + dashboardVariant && yieldGrouping === "category"; + const dashboardYieldCategorySelectionEnabled = + !dashboardVariant || dashboardYieldCategoryGroupingEnabled; const getInitYield = useGetInitYield(); const positionsData = usePositionsData(); const dashboardYieldCatalog = useDashboardYieldCatalog({ - enabled: dashboardVariant, + enabled: dashboardYieldCategoryGroupingEnabled, }); const reducer = (state: State, action: Actions): State => { @@ -86,7 +90,9 @@ export const EarnPageStateProvider = ({ children }: PropsWithChildren) => { .chain(() => getInitYield({ selectedDashboardYieldCategory: - state.selectedDashboardYieldCategory, + dashboardYieldCategorySelectionEnabled + ? state.selectedDashboardYieldCategory + : null, selectedToken: action.data, }) .map<{ @@ -94,7 +100,9 @@ export const EarnPageStateProvider = ({ children }: PropsWithChildren) => { yieldState: ReturnType | null; }>((yieldDto) => ({ selectedDashboardYieldCategory: - state.selectedDashboardYieldCategory, + dashboardYieldCategorySelectionEnabled + ? state.selectedDashboardYieldCategory + : null, yieldState: onYieldSelectState({ yieldDto, positionsData: positionsData.data, @@ -103,7 +111,9 @@ export const EarnPageStateProvider = ({ children }: PropsWithChildren) => { .alt( Maybe.of({ selectedDashboardYieldCategory: - state.selectedDashboardYieldCategory, + dashboardYieldCategorySelectionEnabled + ? state.selectedDashboardYieldCategory + : null, yieldState: null, }) ) @@ -118,6 +128,8 @@ export const EarnPageStateProvider = ({ children }: PropsWithChildren) => { } case "dashboard/yield-category/select": { + if (!dashboardYieldCategoryGroupingEnabled) return state; + const target = dashboardYieldCatalog.initialSelectionByCategory.get( action.data ); @@ -171,9 +183,10 @@ export const EarnPageStateProvider = ({ children }: PropsWithChildren) => { .map((val) => ({ ...getInitialState(), selectedToken: Maybe.of(action.data.token), - selectedDashboardYieldCategory: getDashboardYieldCategory( - action.data - ), + selectedDashboardYieldCategory: + dashboardYieldCategorySelectionEnabled + ? getDashboardYieldCategory(action.data) + : null, ...val, })) .orDefault(state); @@ -192,9 +205,10 @@ export const EarnPageStateProvider = ({ children }: PropsWithChildren) => { .map((val) => ({ ...getInitialState(), selectedToken: state.selectedToken, - selectedDashboardYieldCategory: getDashboardYieldCategory( - action.data - ), + selectedDashboardYieldCategory: + dashboardYieldCategorySelectionEnabled + ? getDashboardYieldCategory(action.data) + : null, ...val, })) .orDefault(state); @@ -291,7 +305,9 @@ export const EarnPageStateProvider = ({ children }: PropsWithChildren) => { ); const initYieldRes = useInitYield({ - selectedDashboardYieldCategory: selectedDashboardYieldCategoryFallback, + selectedDashboardYieldCategory: dashboardYieldCategorySelectionEnabled + ? selectedDashboardYieldCategoryFallback + : null, selectedToken, }); const initYield = useMemo( @@ -320,9 +336,10 @@ export const EarnPageStateProvider = ({ children }: PropsWithChildren) => { const selectedStakeDashboardYieldCategory = selectedStake .chainNullable(getDashboardYieldCategory) .extractNullable(); - const selectedDashboardYieldCategory = - selectedStakeDashboardYieldCategory ?? - selectedDashboardYieldCategoryFallback; + const selectedDashboardYieldCategory = dashboardYieldCategorySelectionEnabled + ? (selectedStakeDashboardYieldCategory ?? + selectedDashboardYieldCategoryFallback) + : null; /** * If stake amount is less then min, use min @@ -478,8 +495,9 @@ export const EarnPageStateProvider = ({ children }: PropsWithChildren) => { hasNotYieldsForToken, selectedProviderYieldId, selectedDashboardYieldCategory, - availableDashboardYieldCategories: - dashboardYieldCatalog.availableCategories, + availableDashboardYieldCategories: dashboardYieldCategoryGroupingEnabled + ? dashboardYieldCatalog.availableCategories + : [], }), [ selectedStakeId, @@ -500,6 +518,7 @@ export const EarnPageStateProvider = ({ children }: PropsWithChildren) => { hasNotYieldsForToken, selectedProviderYieldId, selectedDashboardYieldCategory, + dashboardYieldCategoryGroupingEnabled, dashboardYieldCatalog.availableCategories, ] ); diff --git a/packages/widget/src/providers/settings/types.ts b/packages/widget/src/providers/settings/types.ts index 10d1a0f9..8e425bf5 100644 --- a/packages/widget/src/providers/settings/types.ts +++ b/packages/widget/src/providers/settings/types.ts @@ -84,6 +84,7 @@ export type SettingsProps = { | Record | ((chain: SupportedSKChains) => string); dashboardVariant?: boolean; + yieldGrouping?: "flat" | "category"; institutionalWallets?: boolean; hideChainSelector?: boolean; hideAccountAndChainSelector?: boolean; diff --git a/packages/widget/tests/use-cases/renders-initial-page.test.tsx b/packages/widget/tests/use-cases/renders-initial-page.test.tsx index bc09f210..8a597954 100644 --- a/packages/widget/tests/use-cases/renders-initial-page.test.tsx +++ b/packages/widget/tests/use-cases/renders-initial-page.test.tsx @@ -154,4 +154,22 @@ describe("Renders initial page", () => { app.unmount(); }); + + it("uses flat dashboard yield grouping by default", async () => { + const app = await renderApp({ + skProps: { + apiKey: import.meta.env.VITE_API_KEY, + dashboardVariant: true, + }, + }); + + await expect.element(app.getByText("Earn")).toBeInTheDocument(); + await expect.element(app.getByText("Manage")).toBeInTheDocument(); + await expect.element(app.getByText("Activity")).toBeInTheDocument(); + await expect.element(app.getByText("Stake")).not.toBeInTheDocument(); + await expect.element(app.getByText("DeFi")).not.toBeInTheDocument(); + await expect.element(app.getByText("RWA")).not.toBeInTheDocument(); + + app.unmount(); + }); });