Skip to content
This repository has been archived by the owner on Jun 16, 2022. It is now read-only.

Regressions due to branching between JavaScript and TypeScript files #2389

Merged
merged 11 commits into from
Apr 5, 2022
Merged
123 changes: 123 additions & 0 deletions scripts/v3check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
const exec = require("child_process").exec;

/* eslint-disable no-console */

const LOG_COMMANDS = false;
const TEST_FILES = false;
const TS_TEST_FILES = [
// "src/screens/Settings/General/index.tsx",
"src/components/CurrencyRate.tsx",
];

async function executeAsync(command) {
return new Promise((resolve, reject) => {
exec(command, (error, stdout, stderr) => {
if (error) {
reject(error);
} else if (stderr) {
reject(stderr);
} else {
resolve(stdout);
}
});
});
}

async function listTsJsFilesPairs() {
const jsFilesPath = {};
const jsTsPairs = [];
await executeAsync('git ls-files | grep -e ".\\.js$"').then(res =>
res.split("\n").map(path => (jsFilesPath[path] = true)),
);
return executeAsync('git ls-files | grep -e ".\\.ts$" -e ".\\.tsx$"')
.then(res =>
res.split("\n").forEach(path => {
const beforeExtensionPath = path
.split(".")
.slice(0, -1)
.join(".");
const jsFilePath = `${beforeExtensionPath}.js`;
if (jsFilesPath[jsFilePath]) {
jsTsPairs.push({
tsFilePath: path,
jsFilePath,
});
}
}),
)
.then(() => jsTsPairs);
}

const branchRebrand = "LL-7742";
const branchRelease = "release/v3.0.x";
const mainBranchName = "develop";

async function getFileCreationDate(filePath, firstParent) {
const command = `git log --format=%aD --first-parent ${firstParent} --no-merges ${filePath} | tail -1`;
LOG_COMMANDS && console.log(`getFileCreationDate command:\n\t${command}`);
const rawDate = await executeAsync(command);
return { date: rawDate ? new Date(rawDate) : null, command };
}

async function listCommits(filePath, sinceDateIsoString) {
const command = `git log \
--first-parent \
${mainBranchName} \
${sinceDateIsoString ? `--since=${sinceDateIsoString}` : ""} \
--pretty=format:"%aI %H %s" \
${filePath}`;
LOG_COMMANDS && console.log(`listCommits command:\n\t${command}`);
const rawResult = await executeAsync(command);
const commitsRaw = rawResult.split("\n").filter(l => !!l);
return commitsRaw.map(commitRaw => {
const [dateStr, hashStr, ...rest] = commitRaw.split(" ");
const message = rest.join(" ");
return {
date: new Date(dateStr),
hashStr,
message,
command,
};
});
}

function pbcopy(data) {
const proc = require("child_process").spawn("pbcopy");
proc.stdin.write(data);
proc.stdin.end();
}

async function generateMarkdownTodoList() {
const pairs = await listTsJsFilesPairs();
let todoList = "";
const res = await Promise.all(
pairs
.filter(
({ tsFilePath }) => !TEST_FILES || TS_TEST_FILES.includes(tsFilePath),
)
.map(async ({ tsFilePath, jsFilePath }) => {
const { date: tsFileCreationDate } = await getFileCreationDate(
tsFilePath,
branchRebrand,
).then(res =>
res === null ? getFileCreationDate(tsFilePath, branchRelease) : res,
);
const commits = tsFileCreationDate
? await listCommits(jsFilePath, tsFileCreationDate.toISOString())
: [];
return { tsFilePath, jsFilePath, commits };
}),
);
res.forEach(({ jsFilePath, commits }) => {
if (commits.length === 0) return;
console.log("jsFilePath", jsFilePath);
todoList += `- [ ] **${jsFilePath}**\n`;
commits.forEach(({ message, date, hashStr }) => {
todoList += ` - [ ] ${date.toDateString()} ${hashStr} ${message}\n`;
});
todoList += "\n";
});
return todoList;
}

generateMarkdownTodoList().then(pbcopy);
32 changes: 22 additions & 10 deletions src/components/GenericErrorView.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import React from "react";
import React, { memo, useEffect } from "react";
import { Trans } from "react-i18next";
import { NativeModules } from "react-native";
import { Box, Button, Flex, IconBox, Text } from "@ledgerhq/native-ui";
import { CloseMedium } from "@ledgerhq/native-ui/assets/icons";
import { BluetoothRequired } from "@ledgerhq/errors";
import useExportLogs from "./useExportLogs";
import TranslatedError from "./TranslatedError";
import SupportLinkError from "./SupportLinkError";
import DownloadFileIcon from "../icons/DownloadFile";

const GenericErrorView = ({
error,
outerError,
withDescription = true,
withIcon = true,
hasExportLogButton = true,
}: {
type Props = {
error: Error;
// sometimes we want to "hide" the technical error into a category
// for instance, for Genuine check we want to express "Genuine check failed" because "<actual error>"
Expand All @@ -22,7 +18,23 @@ const GenericErrorView = ({
withDescription?: boolean;
withIcon?: boolean;
hasExportLogButton?: boolean;
}) => {
};

const GenericErrorView = ({
error,
outerError,
withDescription = true,
withIcon = true,
hasExportLogButton = true,
}: Props) => {
useEffect(() => {
if (error instanceof BluetoothRequired) {
NativeModules.BluetoothHelperModule.prompt().catch(() => {
/* ignore */
});
}
}, [error]);

const onExport = useExportLogs();

const titleError = outerError || error;
Expand Down Expand Up @@ -78,4 +90,4 @@ const GenericErrorView = ({
);
};

export default GenericErrorView;
export default memo<Props>(GenericErrorView);
18 changes: 14 additions & 4 deletions src/components/OperationRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import CounterValue from "./CounterValue";
import OperationIcon from "./OperationIcon";
import { ScreenName } from "../const";
import OperationRowDate from "./OperationRowDate";
import OperationRowNftName from "./OperationRowNftName";

import perFamilyOperationDetails from "../generated/operationDetails";

Expand Down Expand Up @@ -60,13 +61,13 @@ const BodyLeftContainer = styled(Flex).attrs({
flex: 1,
})``;

const BodyRightContainer = styled(Flex).attrs({
const BodyRightContainer = styled(Flex).attrs(p => ({
flexDirection: "column",
justifyContent: "flex-start",
alignItems: "flex-end",
flexShrink: 0,
flexShrink: p.flexShrink ?? 0,
pl: 4,
})``;
}))``;

type Props = {
operation: Operation;
Expand Down Expand Up @@ -109,6 +110,11 @@ export default function OperationRow({
else navigation.navigate(...params);
}, 300);

const isNftOperation =
["NFT_IN", "NFT_OUT"].includes(operation.type) &&
operation.contract &&
operation.tokenId;

const renderAmountCellExtra = useCallback(() => {
const mainAccount = getMainAccount(account, parentAccount);
const currency = getAccountCurrency(account);
Expand Down Expand Up @@ -201,7 +207,11 @@ export default function OperationRow({

<BodyRightContainer>{renderAmountCellExtra()}</BodyRightContainer>

{amount.isZero() ? null : (
{isNftOperation ? (
<BodyRightContainer flexShrink={1} maxWidth="70%">
<OperationRowNftName operation={operation} />
</BodyRightContainer>
) : amount.isZero() ? null : (
<BodyRightContainer>
<Text
numberOfLines={1}
Expand Down
53 changes: 53 additions & 0 deletions src/components/OperationRowNftName.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from "react";

import { Operation } from "@ledgerhq/live-common/lib/types";
import { useNftMetadata } from "@ledgerhq/live-common/lib/nft";
import { StyleSheet } from "react-native";
import { Text } from "@ledgerhq/native-ui";
import Skeleton from "./Skeleton";

type Props = {
style?: Object;
operation: Operation;
};

const OperationRowNftName = ({ style, operation }: Props) => {
const { status, metadata } = useNftMetadata(
operation.contract,
operation.tokenId,
);

return (
<>
<Skeleton style={[styles.skeleton]} loading={status === "loading"}>
<Text
numberOfLines={1}
ellipsizeMode="tail"
variant="body"
fontWeight="semiBold"
>
{metadata?.nftName || "-"}
</Text>
</Skeleton>
<Text
variant="paragraph"
fontWeight="medium"
color="neutral.c70"
ellipsizeMode="middle"
numberOfLines={1}
>
ID {operation.tokenId}
</Text>
</>
);
};

const styles = StyleSheet.create({
skeleton: {
height: 8,
width: 120,
borderRadius: 4,
},
});

export default OperationRowNftName;
23 changes: 15 additions & 8 deletions src/components/SelectDevice/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import { StyleSheet, View, Platform, NativeModules } from "react-native";
import Config from "react-native-config";
import { useSelector, useDispatch } from "react-redux";
import { Trans } from "react-i18next";
import { useNavigation } from "@react-navigation/native";
import {
useNavigation,
useTheme as useNavTheme,
} from "@react-navigation/native";
import { discoverDevices, TransportModule } from "@ledgerhq/live-common/lib/hw";
import { Device } from "@ledgerhq/live-common/lib/hw/actions/types";
import { Button } from "@ledgerhq/native-ui";
Expand All @@ -16,10 +19,11 @@ import BluetoothEmpty from "./BluetoothEmpty";
import USBEmpty from "./USBEmpty";
import LText from "../LText";
import Animation from "../Animation";

import lottieUsb from "../../screens/Onboarding/assets/nanoS/plugDevice/dark.json";
import { track } from "../../analytics";

import PairLight from "../../screens/Onboarding/assets/nanoX/pairDevice/light.json";
import PairDark from "../../screens/Onboarding/assets/nanoX/pairDevice/dark.json";

type Props = {
onBluetoothDeviceAction?: (device: Device) => void;
onSelect: (device: Device) => void;
Expand Down Expand Up @@ -223,11 +227,14 @@ const WithoutDeviceHeader = () => (
);

// Fixme Use the illustration instead of the png
const UsbPlaceholder = () => (
<View style={styles.imageContainer}>
<Animation style={styles.image} source={lottieUsb} />
</View>
);
const UsbPlaceholder = () => {
const { dark } = useNavTheme();
return (
<View style={styles.imageContainer}>
<Animation style={styles.image} source={dark ? PairDark : PairLight} />
</View>
);
};

function getAll({ knownDevices }, { devices }): Device[] {
return [
Expand Down
24 changes: 1 addition & 23 deletions src/screens/Onboarding/steps/language.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,11 @@ import {
import { StackScreenProps } from "@react-navigation/stack";
import { useDispatch } from "react-redux";
import { useLocale } from "../../../context/Locale";
import { supportedLocales } from "../../../languages";
import { languages, supportedLocales } from "../../../languages";
import Button from "../../../components/Button";
import { ScreenName } from "../../../const";
import { setLanguage } from "../../../actions/settings";

const languages = {
de: "Deutsch",
el: "Ελληνικά",
en: "English",
es: "Español",
fi: "suomi",
fr: "Français",
hu: "magyar",
it: "italiano",
ja: "日本語",
ko: "한국어",
nl: "Nederlands",
no: "Norsk",
pl: "polski",
pt: "português",
ru: "Русский",
sr: "српски",
sv: "svenska",
tr: "Türkçe",
zh: "简体中文",
};

function OnboardingStepLanguage({ navigation }: StackScreenProps<{}>) {
const { locale: currentLocale } = useLocale();
const dispatch = useDispatch();
Expand Down
8 changes: 5 additions & 3 deletions src/screens/Onboarding/steps/welcome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { Linking } from "react-native";
import Svg, { Defs, LinearGradient, Rect, Stop } from "react-native-svg";
import { useDispatch } from "react-redux";
import Button from "../../../components/Button";
import { useLocale } from "../../../context/Locale";
import { ScreenName } from "../../../const";
import StyledStatusBar from "../../../components/StyledStatusBar";
import { urls } from "../../../config/urls";
Expand Down Expand Up @@ -41,7 +40,9 @@ function OnboardingStepWelcome({ navigation }: any) {
[navigation],
);

const { locale } = useLocale();
const {
i18n: { language: locale },
} = useTranslation();

const onTermsLink = useCallback(
() =>
Expand All @@ -52,7 +53,8 @@ function OnboardingStepWelcome({ navigation }: any) {
);

const onPrivacyLink = useCallback(
() => Linking.openURL(urls.privacyPolicy[locale]),
() =>
Linking.openURL((urls.privacyPolicy as Record<string, string>)[locale]),
[locale],
);

Expand Down
Loading