Skip to content

Commit

Permalink
feat: ✨ Redirect Users to Corresponding Market Page When Clicking on …
Browse files Browse the repository at this point in the history
…Asset in Market Widget (#8504)
  • Loading branch information
mcayuelas-ledger authored Nov 28, 2024
1 parent e341fa2 commit 03c26f4
Show file tree
Hide file tree
Showing 13 changed files with 118 additions and 39 deletions.
5 changes: 5 additions & 0 deletions .changeset/giant-geese-film.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ledger-live-desktop": minor
---

Redirect Users to Corresponding Market Page When Clicking on Asset in Market Widget
2 changes: 2 additions & 0 deletions apps/ledger-live-desktop/src/renderer/actions/constants.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
// Action types
export const TOGGLE_MEMOTAG_INFO = "settings/toggleShouldDisplayMemoTagInfo";
export const TOGGLE_MEV = "settings/toggleMEV";
export const TOGGLE_MARKET_WIDGET = "settings/toggleMarketWidget";
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@ import { useMemo } from "react";
import { useSelector } from "react-redux";
import { useMarketcapIds, useTrackingPairsForTopCoins } from "@ledgerhq/live-countervalues-react";
import { TrackingPair } from "@ledgerhq/live-countervalues/types";
import { selectedTimeRangeSelector } from "~/renderer/reducers/settings";
import {
marketPerformanceWidgetSelector,
selectedTimeRangeSelector,
} from "~/renderer/reducers/settings";
import { getPortfolioRangeConfig } from "@ledgerhq/live-countervalues/portfolio";
import { Currency } from "@ledgerhq/types-cryptoassets";
import useFeature from "@ledgerhq/live-common/featureFlags/useFeature";
import { ABTestingVariants } from "@ledgerhq/types-live";
import { BASIC_REFETCH } from "../screens/market/utils";

export function useMarketPerformanceFeatureFlag() {
const marketPerformanceValue = useSelector(marketPerformanceWidgetSelector);
const marketperformanceWidgetDesktop = useFeature("marketperformanceWidgetDesktop");
return {
enabled: marketperformanceWidgetDesktop?.enabled || false,
enabled: (marketperformanceWidgetDesktop?.enabled && marketPerformanceValue) || false,
variant: marketperformanceWidgetDesktop?.params?.variant || ABTestingVariants.variantA,
refreshRate: marketperformanceWidgetDesktop?.params?.refreshRate || BASIC_REFETCH,
top: marketperformanceWidgetDesktop?.params?.top || 50,
Expand All @@ -31,6 +35,7 @@ export function useMarketPerformanceReferenceDate() {
export function useMarketPerformanceTrackingPairs(countervalue: Currency): TrackingPair[] {
const size = 50;
const refDate = useMarketPerformanceReferenceDate();

const marketPerformanceEnabled = useMarketPerformanceFeatureFlag().enabled;
const marketcapIds = useMarketcapIds();
return useTrackingPairsForTopCoins(
Expand Down
9 changes: 7 additions & 2 deletions apps/ledger-live-desktop/src/renderer/actions/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
import { useRefreshAccountsOrdering } from "~/renderer/actions/general";
import { Language, Locale } from "~/config/languages";
import { Layout } from "LLD/features/Collectibles/types/Layouts";
import { TOGGLE_MEMOTAG_INFO } from "./constants";
import { TOGGLE_MARKET_WIDGET, TOGGLE_MEMOTAG_INFO, TOGGLE_MEV } from "./constants";
export type SaveSettings = (a: Partial<Settings>) => {
type: string;
payload: Partial<Settings>;
Expand Down Expand Up @@ -439,7 +439,12 @@ export const setLastOnboardedDevice = (payload: Device | null) => ({
payload,
});
export const setMevProtection = (payload: boolean) => ({
type: "SET_MEV_PROTECTION",
type: TOGGLE_MEV,
payload,
});

export const setMarketWidget = (payload: boolean) => ({
type: TOGGLE_MARKET_WIDGET,
payload,
});

Expand Down
20 changes: 13 additions & 7 deletions apps/ledger-live-desktop/src/renderer/analytics/segment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
languageSelector,
lastSeenDeviceSelector,
localeSelector,
marketPerformanceWidgetSelector,
mevProtectionSelector,
shareAnalyticsSelector,
sharePersonalizedRecommendationsSelector,
Expand Down Expand Up @@ -61,11 +62,15 @@ export function setAnalyticsFeatureFlagMethod(method: typeof analyticsFeatureFla
analyticsFeatureFlagMethod = method;
}

const getMarketWidgetAnalytics = () => {
const getMarketWidgetAnalytics = (state: State) => {
if (!analyticsFeatureFlagMethod) return false;
const marketWidget = analyticsFeatureFlagMethod("marketperformanceWidgetDesktop");

return !!marketWidget?.enabled;
const hasMarketWidgetActivated = marketPerformanceWidgetSelector(state);

return {
hasMarketWidget: !marketWidget?.enabled ? "Null" : hasMarketWidgetActivated ? "Yes" : "No",
};
};

const getLedgerSyncAttributes = (state: State) => {
Expand Down Expand Up @@ -159,8 +164,9 @@ const extraProperties = (store: ReduxStore) => {
const accounts = accountsSelector(state);
const ptxAttributes = getPtxAttributes();

const ledgerSyncAtributes = getLedgerSyncAttributes(state);
const mevProtectionAtributes = getMEVAttributes(state);
const ledgerSyncAttributes = getLedgerSyncAttributes(state);
const mevProtectionAttributes = getMEVAttributes(state);
const marketWidgetAttributes = getMarketWidgetAnalytics(state);

const deviceInfo = device
? {
Expand Down Expand Up @@ -211,12 +217,12 @@ const extraProperties = (store: ReduxStore) => {
blockchainsWithNftsOwned,
hasGenesisPass,
hasInfinityPass,
hasSeenMarketWidget: getMarketWidgetAnalytics(),
modelIdList: devices,
...ptxAttributes,
...deviceInfo,
...ledgerSyncAtributes,
...mevProtectionAtributes,
...ledgerSyncAttributes,
...mevProtectionAttributes,
...marketWidgetAttributes,
};
};

Expand Down
17 changes: 12 additions & 5 deletions apps/ledger-live-desktop/src/renderer/reducers/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { getAppLocale } from "~/helpers/systemLocale";
import { Handlers } from "./types";
import { Layout, LayoutKey } from "LLD/features/Collectibles/types/Layouts";
import { OnboardingUseCase } from "../components/Onboarding/OnboardingUseCase";
import { TOGGLE_MEMOTAG_INFO } from "../actions/constants";
import { TOGGLE_MEMOTAG_INFO, TOGGLE_MARKET_WIDGET, TOGGLE_MEV } from "../actions/constants";

/* Initial state */

Expand Down Expand Up @@ -78,6 +78,7 @@ export type SettingsState = {
collectiblesViewMode: LayoutKey;
showAccountsHelperBanner: boolean;
mevProtection: boolean;
marketPerformanceWidget: boolean;
hideEmptyTokenAccounts: boolean;
filterTokenOperationsZeroAmount: boolean;
sidebarCollapsed: boolean;
Expand Down Expand Up @@ -182,6 +183,7 @@ export const INITIAL_STATE: SettingsState = {
hasInstalledApps: true,
lastSeenDevice: null,
mevProtection: true,
marketPerformanceWidget: true,
hasSeenOrdinalsDiscoveryDrawer: false,
hasProtectedOrdinalsAssets: false,
devicesModelList: [],
Expand Down Expand Up @@ -296,8 +298,9 @@ type HandlersPayloads = {
SET_HAS_REDIRECTED_TO_POST_ONBOARDING: boolean;
SET_LAST_ONBOARDED_DEVICE: Device | null;

SET_MEV_PROTECTION: boolean;
[TOGGLE_MEV]: boolean;
[TOGGLE_MEMOTAG_INFO]: boolean;
[TOGGLE_MARKET_WIDGET]: boolean;
};
type SettingsHandlers<PreciseKey = true> = Handlers<SettingsState, HandlersPayloads, PreciseKey>;

Expand Down Expand Up @@ -548,11 +551,14 @@ const handlers: SettingsHandlers = {
...state,
lastOnboardedDevice: payload,
}),
SET_MEV_PROTECTION: (state: SettingsState, { payload }) => ({
[TOGGLE_MEV]: (state: SettingsState, { payload }) => ({
...state,
mevProtection: payload,
}),

[TOGGLE_MARKET_WIDGET]: (state: SettingsState, { payload }) => ({
...state,
marketPerformanceWidget: payload,
}),
[TOGGLE_MEMOTAG_INFO]: (state: SettingsState, { payload }) => ({
...state,
alwaysShowMemoTagInfo: payload,
Expand Down Expand Up @@ -911,5 +917,6 @@ export const hasBeenRedirectedToPostOnboardingSelector = (state: State) =>
export const lastOnboardedDeviceSelector = (state: State) => state.settings.lastOnboardedDevice;

export const mevProtectionSelector = (state: State) => state.settings.mevProtection;

export const marketPerformanceWidgetSelector = (state: State) =>
state.settings.marketPerformanceWidget;
export const alwaysShowMemoTagInfoSelector = (state: State) => state.settings.alwaysShowMemoTagInfo;
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const createElem = (change: number): MarketItemPerformer => ({
ticker: "BTC",
price: 70000,
ledgerIds: [],
id: "bitcoin",
});

const createElemWithMultipleChange = (range: {
Expand All @@ -36,6 +37,7 @@ const createElemWithMultipleChange = (range: {
ticker: "BTC",
price: 70000,
ledgerIds: [],
id: "bitcoin",
});

describe("useMarketPerformanceWidget", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function MarketPerformanceWidgetHeader({ onChangeOrder, order }: HeaderPr
const { width } = useResize(ref);

return (
<Flex justifyContent="space-between" alignItems="center" ref={ref} mb={5}>
<Flex justifyContent="space-between" alignItems="center" ref={ref} mb={3}>
<Text variant="h3Inter" fontWeight="semiBold">
{t("dashboard.marketPerformanceWidget.title", {
time: t(`time.range.${timeRange}`),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from "react";
import React, { useCallback } from "react";
import { PropsBody, PropsBodyElem } from "../types";
import { Flex, Text } from "@ledgerhq/react-ui";
import styled from "@ledgerhq/react-ui/components/styled";
Expand All @@ -9,6 +9,8 @@ import { counterValueCurrencySelector, localeSelector } from "~/renderer/reducer
import { useSelector } from "react-redux";
import counterValueFormatter from "@ledgerhq/live-common/market/utils/countervalueFormatter";
import { getChangePercentage } from "~/renderer/screens/dashboard/MarketPerformanceWidget/utils";
import { useHistory } from "react-router-dom";
import { track } from "~/renderer/analytics/segment";

export function WidgetList({ data, order, range, top }: PropsBody) {
const noData = data.length === 0;
Expand All @@ -26,12 +28,24 @@ export function WidgetList({ data, order, range, top }: PropsBody) {
);
}

function WidgetRow({ data, index, isFirst, range }: PropsBodyElem) {
function WidgetRow({ data, index, range }: PropsBodyElem) {
const counterValueCurrency = useSelector(counterValueCurrencySelector);
const locale = useSelector(localeSelector);
const history = useHistory();

const onCurrencyClick = useCallback(() => {
track("widget_asset_clicked", {
asset: data.name,
page: "Portfolio",
});

history.push({
pathname: `/market/${data.id}`,
});
}, [data, history]);

return (
<Flex alignItems="center" mt={isFirst ? 0 : 2} justifyContent="space-between">
<MainContainer justifyContent="space-between" py="6px" onClick={onCurrencyClick}>
<Flex alignItems="center" flex={1}>
<Text color="neutral.c80" variant="h5Inter" mr={2}>
{index}
Expand Down Expand Up @@ -98,10 +112,22 @@ function WidgetRow({ data, index, isFirst, range }: PropsBodyElem) {
})}
</EllipsisText>
</Flex>
</Flex>
</MainContainer>
);
}

const MainContainer = styled(Flex)`
&:hover {
background-color: ${p => p.theme.colors.opacityDefault.c05};
padding: 6px 12px;
border-radius: 12px;
transition:
background-color 0.35s ease,
padding 0.35s ease;
cursor: pointer;
}
`;

const CryptoCurrencyIconWrapper = styled(Flex)<{
hasImage?: boolean;
}>`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,44 @@
import React from "react";
import React, { useCallback } from "react";
import Switch from "~/renderer/components/Switch";
import { useFeatureFlags } from "@ledgerhq/live-common/featureFlags/index";
import Track from "~/renderer/analytics/Track";
import { useSelector, useDispatch } from "react-redux";
import { setMarketWidget } from "~/renderer/actions/settings";
import { track } from "~/renderer/analytics/segment";
import { marketPerformanceWidgetSelector } from "~/renderer/reducers/settings";

const MarketPerformanceWidgetRow = () => {
const featureFlagsProvider = useFeatureFlags();
const marketWidgetValue = useSelector(marketPerformanceWidgetSelector);

const currentValue = Boolean(
featureFlagsProvider.getFeature("marketperformanceWidgetDesktop")?.enabled,
);
const dispatch = useDispatch();

const update = (value: boolean) => {
featureFlagsProvider.overrideFeature("marketperformanceWidgetDesktop", { enabled: value });
};
const toggle = useCallback(
(value: boolean) => {
dispatch(setMarketWidget(value));

track(
"toggle_clicked",
{
toggleAction: value ? "ON" : "OFF",
toggle: "MarketPerformanceWidget",
page: "Page Settings General",
},
true,
);
},
[dispatch],
);

return (
<>
<Track
onUpdate
event={
currentValue ? "MarketPerformanceWidgetEnabled" : "MarketPerformanceWidgetRowDisabled"
marketWidgetValue
? "MarketPerformanceWidgetEnabled"
: "MarketPerformanceWidgetRowDisabled"
}
/>
<Switch isChecked={currentValue} onChange={() => update(!currentValue)} />
<Switch isChecked={marketWidgetValue} onChange={() => toggle(!marketWidgetValue)} />
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,15 @@ const SectionGeneral = () => {
</Row>
</FeatureToggle>

<Row
title={t("settings.display.marketPerformanceWidget")}
desc={t("settings.display.marketPerformanceWidgetDesc")}
dataTestId="setting-marketPerformanceWidget"
>
<MarketPerformanceWidgetRow />
</Row>
<FeatureToggle featureId="marketperformanceWidgetDesktop">
<Row
title={t("settings.display.marketPerformanceWidget")}
desc={t("settings.display.marketPerformanceWidgetDesc")}
dataTestId="setting-marketPerformanceWidget"
>
<MarketPerformanceWidgetRow />
</Row>
</FeatureToggle>

<Row title={t("settings.profile.password")} desc={t("settings.profile.passwordDesc")}>
<PasswordButton />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export const format = (
});

export const formatPerformer = (currency: MarketItemResponse): MarketItemPerformer => ({
id: currency.id,
ledgerIds: currency.ledgerIds,
name: currency.name,
image: currency.image,
Expand Down
1 change: 1 addition & 0 deletions libs/ledger-live-common/src/market/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ export type MarketItemResponse = {
updatedAt: string;
};
export type MarketItemPerformer = {
id: string;
name: string;
ticker: string;
priceChangePercentage1h: number;
Expand Down

0 comments on commit 03c26f4

Please sign in to comment.