Skip to content

Commit

Permalink
[FEAT] : Update market performers (#6517)
Browse files Browse the repository at this point in the history
* WIP

* Add peerDependency

* Fix coming back to page and don't refetch everything

* test(lld): update screenshots (ubuntu-latest)  lld, test, screenshot

* WIP

* Add peerDependency

* Add FF refreshTime rate for LLD

* WIP change Api for MarketPerformanceWidget

* Fix tests + improve Typing

* Add more test

* Add changeset

* Clean + add more parameters to FF for config

* Get cryptoasset from develop

* Improve errors message

* Move logic outside Fetch

* Fix Trend

* Revome old implem

* 🧹

* fix file

* fix file

* fix initial display

* chnage type

* enrich tests

* clean code

* Fix typo

---------

Co-authored-by: live-github-bot[bot] <105061298+live-github-bot[bot]@users.noreply.github.com>
  • Loading branch information
mcayuelas-ledger and live-github-bot[bot] committed Apr 10, 2024
1 parent bd5188b commit 33c4239
Show file tree
Hide file tree
Showing 24 changed files with 439 additions and 230 deletions.
7 changes: 7 additions & 0 deletions .changeset/hot-eagles-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@ledgerhq/types-live": patch
"ledger-live-desktop": patch
"@ledgerhq/live-common": patch
---

Update MarketPerformers Endpoint
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ 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 marketperformanceWidgetDesktop = useFeature("marketperformanceWidgetDesktop");
return {
enabled: marketperformanceWidgetDesktop?.enabled || false,
variant: marketperformanceWidgetDesktop?.params?.variant || ABTestingVariants.variantA,
refreshRate: marketperformanceWidgetDesktop?.params?.refreshRate || BASIC_REFETCH,
top: marketperformanceWidgetDesktop?.params?.top || 50,
supported: marketperformanceWidgetDesktop?.params?.supported || false,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,14 +138,6 @@ export function relativeTime(currentDate: Date, targetDate: Date): string {
const years = Math.round(months / 12);

const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
console.log({
years,
months,
days,
hours,
minutes,
seconds,
});
if (years) {
return rtf.format(years, Math.abs(years) > 1 ? "years" : "year");
} else if (months) {
Expand Down
9 changes: 6 additions & 3 deletions apps/ledger-live-desktop/src/renderer/hooks/useResize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,17 @@ export const useResize = (
}, [myRef]);

useEffect(() => {
window.addEventListener("load", handleResize);
if (width === 0 && height === 0 && myRef.current) {
setWidth(myRef.current.offsetWidth);
setHeight(myRef.current.offsetHeight);
}

window.addEventListener("resize", handleResize);

return () => {
window.removeEventListener("load", handleResize);
window.removeEventListener("resize", handleResize);
};
}, [myRef, handleResize]);
}, [myRef, handleResize, width, height]);

return { width, height };
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,45 @@
*/

import { describe, expect, it } from "@jest/globals";
import { getSlicedList } from "../useMarketPerformanceWidget";
import { Order } from "../types";
import { Currency } from "@ledgerhq/types-cryptoassets";
import { MarketItemPerformer } from "@ledgerhq/live-common/market/types";
import { getChangePercentage, getSlicedList } from "../utils";

const createElem = (change: number) => ({
currency: { id: "bitcoin" } as Currency,
change,
currentValue: 100,
referenceValue: 100,
const createElem = (change: number): MarketItemPerformer => ({
name: "Bitcoin",
image: "https://bitcoin.org/logo.png",
priceChangePercentage1h: change,
priceChangePercentage1y: change,
priceChangePercentage24h: change,
priceChangePercentage30d: change,
priceChangePercentage7d: change,
ticker: "BTC",
price: 70000,
ledgerIds: [],
});

const createElemWithMultipleChange = (range: {
priceChangePercentage1h: number;
priceChangePercentage24h: number;
priceChangePercentage7d: number;
priceChangePercentage30d: number;
priceChangePercentage1y: number;
}): MarketItemPerformer => ({
name: "Bitcoin",
image: "https://bitcoin.org/logo.png",
priceChangePercentage1h: range.priceChangePercentage1h,
priceChangePercentage1y: range.priceChangePercentage1y,
priceChangePercentage24h: range.priceChangePercentage24h,
priceChangePercentage30d: range.priceChangePercentage30d,
priceChangePercentage7d: range.priceChangePercentage7d,
ticker: "BTC",
price: 70000,
ledgerIds: [],
});

describe("useMarketPerformanceWidget", () => {
describe("getSlicedList", () => {
it("Should return a list of 4 positive elements sorted", () => {
it("Should return a list of 4 positive elements on day", () => {
const DATA = [
createElem(-50),
createElem(10),
Expand All @@ -25,14 +50,40 @@ describe("useMarketPerformanceWidget", () => {
createElem(30),
];

const list = getSlicedList(DATA, Order.asc);
const list = getSlicedList(DATA, Order.asc, "day");

expect(list).toHaveLength(4);
expect(list[0].change).toBe(50);
expect(list[1].change).toBe(30);
});

it("Should return a list of 2 negative elements sorted", () => {
it("Should return a list of 1 positive elements on month", () => {
const DATA = [
createElem(-50),
createElem(-10),
createElem(-50),
createElem(20),
createElem(-30),
];

const list = getSlicedList(DATA, Order.asc, "month");

expect(list).toHaveLength(1);
});

it("Should return a list of 2 positive elements on week", () => {
const DATA = [
createElem(-50),
createElem(-10),
createElem(50),
createElem(20),
createElem(-30),
];

const list = getSlicedList(DATA, Order.asc, "week");

expect(list).toHaveLength(2);
});

it("Should return a list of 2 negative elements on day", () => {
const DATA = [
createElem(-20),
createElem(50),
Expand All @@ -41,11 +92,70 @@ describe("useMarketPerformanceWidget", () => {
createElem(30),
];

const list = getSlicedList(DATA, Order.desc);
const list = getSlicedList(DATA, Order.desc, "day");

expect(list).toHaveLength(2);
expect(list[0].change).toBe(-50);
expect(list[1].change).toBe(-20);
});

it("Should return a list of 4 negative elements on month", () => {
const DATA = [
createElem(-50),
createElem(-10),
createElem(50),
createElem(-20),
createElem(-30),
];

const list = getSlicedList(DATA, Order.desc, "month");

expect(list).toHaveLength(4);
});

it("Should return a list of 3 negative elements on week", () => {
const DATA = [
createElem(-50),
createElem(-10),
createElem(50),
createElem(20),
createElem(-30),
];

const list = getSlicedList(DATA, Order.desc, "week");

expect(list).toHaveLength(3);
});
});

describe("getChangePercentage", () => {
const elem = createElemWithMultipleChange({
priceChangePercentage1h: 10,
priceChangePercentage24h: 20,
priceChangePercentage7d: 30,
priceChangePercentage30d: 40,
priceChangePercentage1y: 50,
});

it("Should return right percentageChange for day", () => {
const res = getChangePercentage(elem, "day");

expect(res).toEqual(elem.priceChangePercentage24h);
});

it("Should return right percentageChange for week", () => {
const res = getChangePercentage(elem, "week");

expect(res).toEqual(elem.priceChangePercentage7d);
});

it("Should return right percentageChange for month", () => {
const res = getChangePercentage(elem, "month");

expect(res).toEqual(elem.priceChangePercentage30d);
});
it("Should return right percentageChange for year", () => {
const res = getChangePercentage(elem, "year");

expect(res).toEqual(elem.priceChangePercentage1y);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,16 @@ const BodyByMode: Record<ABTestingVariants, React.ComponentType<PropsBody>> = {
[ABTestingVariants.variantB]: WidgetList,
};

export function MarketPerformanceWidgetContainer({ variant, list, setOrder, order, state }: Props) {
export function MarketPerformanceWidgetContainer({
variant,
list,
setOrder,
order,
range,
isLoading,
hasError,
top,
}: Props) {
const Body = BodyByMode[variant];

return (
Expand All @@ -30,15 +39,17 @@ export function MarketPerformanceWidgetContainer({ variant, list, setOrder, orde
<MarketPerformanceWidgetHeader order={order} onChangeOrder={setOrder} />

<Flex flex={1} alignItems="center" justifyContent="center">
{state.isLoading ? (
{isLoading ? (
<InfiniteLoader />
) : state.hasError ? (
) : hasError ? (
<Error
title={"dashboard.marketPerformanceWidget.error.title"}
description={"dashboard.marketPerformanceWidget.error.description"}
top={top}
range={range}
/>
) : (
<Body data={list} order={order} />
<Body data={list} order={order} range={range} top={top} />
)}
</Flex>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import React from "react";
import { Flex, Icons, Text } from "@ledgerhq/react-ui";
import { useTranslation } from "react-i18next";
import { PortfolioRange } from "@ledgerhq/types-live";

type Props = {
title: string;
description: string;
top: number;
range: PortfolioRange;
};

export function Error({ title, description }: Props) {
export function Error({ title, description, top, range }: Props) {
const { t } = useTranslation();

return (
<Flex flexDirection="column" alignItems="center" justifyContent="center" flex={1}>
<Flex
Expand All @@ -31,7 +33,10 @@ export function Error({ title, description }: Props) {
mt={4}
mb={4}
>
{t(title)}
{t(title, {
count: top,
trend: t(`dashboard.marketPerformanceWidget.trend.${range}`),
})}
</Text>

<Text variant="small" fontWeight="medium" color="neutral.c70" textAlign="center">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import React from "react";
import { Order } from "../types";
import { Error } from "./Error";
import { PortfolioRange } from "@ledgerhq/types-live";

type Props = {
order: Order;
range: PortfolioRange;
top: number;
};

export function MissingData({ order }: Props) {
export function MissingData({ order, top, range }: Props) {
const key = order === Order.asc ? "gainers" : "losers";
const title = `dashboard.marketPerformanceWidget.missingData.${key}.title`;
const description = `dashboard.marketPerformanceWidget.missingData.${key}.description`;
return <Error title={title} description={description} />;
return <Error title={title} description={description} top={top} range={range} />;
}

0 comments on commit 33c4239

Please sign in to comment.