Skip to content

Commit

Permalink
✨ (smpl) [DSDK-205]: Implement Send APDU UI (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdabbech-ledger authored Mar 29, 2024
2 parents 9d5b825 + e2a0a71 commit d1adf36
Show file tree
Hide file tree
Showing 9 changed files with 321 additions and 90 deletions.
10 changes: 10 additions & 0 deletions apps/sample/src/app/apdu/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"use client";
import React from "react";

import { ApduView } from "@/components/ApduView";

const Apdu: React.FC = () => {
return <ApduView />;
};

export default Apdu;
30 changes: 28 additions & 2 deletions apps/sample/src/app/client-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,48 @@
*/
"use client";

import { StyleProvider } from "@ledgerhq/react-ui";
import React from "react";
import { Flex, Icons, StyleProvider } from "@ledgerhq/react-ui";
import styled, { DefaultTheme } from "styled-components";

import { Header } from "@/components/Header";
import { Sidebar } from "@/components/Sidebar";
import { SdkProvider } from "@/providers/DeviceSdkProvider";
import { GlobalStyle } from "@/styles/globalstyles";

type ClientRootLayoutProps = {
children: React.ReactNode;
};

const Root = styled(Flex)`
flex-direction: row;
color: ${({ theme }: { theme: DefaultTheme }) => theme.colors.neutral.c90};
height: 100%;
flex: 1;
`;

const PageContainer = styled(Flex)`
flex-direction: column;
background-color: ${({ theme }: { theme: DefaultTheme }) =>
theme.colors.background.main};
flex: 1;
`;

const ClientRootLayout: React.FC<ClientRootLayoutProps> = ({ children }) => {
return (
<html lang="en">
<SdkProvider>
<StyleProvider selectedPalette="dark" fontsPath="/fonts">
<GlobalStyle />
<body>{children}</body>
<body>
<Root>
<Sidebar />
<PageContainer>
<Header />
{children}
</PageContainer>
</Root>
</body>
</StyleProvider>
</SdkProvider>
</html>
Expand Down
16 changes: 1 addition & 15 deletions apps/sample/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,10 @@
"use client";
import React from "react";
import { Flex } from "@ledgerhq/react-ui";
import styled, { DefaultTheme } from "styled-components";

import { MainView } from "@/components/MainView";
import { Sidebar } from "@/components/Sidebar";

const Root = styled(Flex)`
color: ${({ theme }: { theme: DefaultTheme }) => theme.colors.neutral.c90};
flex-direction: row;
height: 100%;
`;

const Home: React.FC = () => {
return (
<Root>
<Sidebar />
<MainView />
</Root>
);
return <MainView />;
};

// eslint-disable-next-line no-restricted-syntax
Expand Down
148 changes: 148 additions & 0 deletions apps/sample/src/components/ApduView/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { Button, Divider, Flex, Grid, Input, Text } from "@ledgerhq/react-ui";
import styled, { DefaultTheme } from "styled-components";

import { useApduForm } from "@/hooks/useApduForm";

const Root = styled(Flex).attrs({ mx: 15, mt: 10, mb: 5 })`
flex-direction: column;
flex: 1;
justify-content: center;
align-items: center;
`;

const Title = styled(Text).attrs({
variant: "large",
fontSize: 18,
mt: 8,
})``;

const FormContainer = styled(Flex)`
background-color: ${({ theme }: { theme: DefaultTheme }) =>
theme.colors.neutral.c30};
height: 100%;
width: 100%;
flex-direction: column;
border-radius: 12px;
`;

const FormHeader = styled(Flex).attrs({ px: 8, py: 6 })``;

const Form = styled(Flex).attrs({ my: 6, px: 10 })`
flex: 1;
flex-direction: column;
justify-content: center;
`;

const FormFooter = styled(Flex).attrs({ my: 8, px: 8 })`
flex-direction: row;
justify-content: flex-end;
align-self: flex-end;
align-items: flex-end;
`;

const FormFooterButton = styled(Button).attrs({
variant: "main",
size: "large",
color: "neutral.c00",
})``;

const InputContainer = styled(Flex).attrs({ mx: 8, mb: 4 })`
flex-direction: column;
min-width: 150px;
`;

const inputContainerProps = { style: { borderRadius: 4 } };

export const ApduView: React.FC = () => {
const { apduFormValues, setApduFormValue, apdu } = useApduForm();
return (
<Root>
<FormContainer>
<FormHeader>
<Title>APDU</Title>
</FormHeader>
<Divider my={4} />
<Form>
<Grid columns={2}>
<InputContainer>
<Text variant="body" mb={4}>
Class instruction
</Text>
<Input
name="instruction"
containerProps={inputContainerProps}
value={apduFormValues.classInstruction}
onChange={(value) =>
setApduFormValue("classInstruction", value)
}
/>
</InputContainer>
<InputContainer>
<Text variant="body" mb={4}>
Instruction method
</Text>
<Input
name="instructionMethod"
containerProps={inputContainerProps}
value={apduFormValues.instructionMethod}
onChange={(value) =>
setApduFormValue("instructionMethod", value)
}
/>
</InputContainer>
<InputContainer>
<Text variant="body" mb={4}>
Parameter 1
</Text>
<Input
name="firstParameter"
containerProps={inputContainerProps}
value={apduFormValues.firstParameter}
onChange={(value) => setApduFormValue("firstParameter", value)}
/>
</InputContainer>
<InputContainer>
<Text variant="body" mb={4}>
Parameter 2
</Text>
<Input
name="secondParameter"
containerProps={inputContainerProps}
value={apduFormValues.secondParameter}
onChange={(value) => setApduFormValue("secondParameter", value)}
/>
</InputContainer>
<InputContainer>
<Text variant="body" mb={4}>
Data
</Text>
<Input
name="data"
containerProps={inputContainerProps}
value={apduFormValues.data}
onChange={(value) => setApduFormValue("data", value)}
/>
</InputContainer>
<InputContainer>
<Text variant="body" mb={4}>
Data length
</Text>
<Input
name="dataLength"
containerProps={inputContainerProps}
value={apduFormValues.dataLength}
onChange={(value) => setApduFormValue("dataLength", value)}
/>
</InputContainer>
</Grid>
</Form>
<Divider my={4} />
<FormFooter my={8}>
<FormFooterButton onClick={() => console.log(apdu)}>
<Text color="neutral.c00">Send APDU</Text>
</FormFooterButton>
</FormFooter>
</FormContainer>
</Root>
);
};
33 changes: 33 additions & 0 deletions apps/sample/src/components/Header/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from "react";
import { Flex, Icons } from "@ledgerhq/react-ui";
import styled, { DefaultTheme } from "styled-components";

const Root = styled(Flex).attrs({ py: 3, px: 10, gridGap: 8 })`
color: ${({ theme }: { theme: DefaultTheme }) => theme.colors.neutral.c90};
justify-content: flex-end;
align-items: center;
`;

const Actions = styled(Flex)`
justify-content: flex-end;
align-items: center;
flex: 1 0 0;
`;
const IconBox = styled(Flex).attrs({ p: 3 })`
cursor: pointer;
align-items: center;
opacity: 0.7;
`;

export const Header = () => (
<Root>
<Actions>
<IconBox>
<Icons.Question size={"M"} />
</IconBox>
<IconBox>
<Icons.Settings size={"M"} />
</IconBox>
</Actions>
</Root>
);
81 changes: 21 additions & 60 deletions apps/sample/src/components/MainView/index.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,12 @@
import React, { useCallback, useEffect, useState } from "react";
import type { DiscoveredDevice } from "@ledgerhq/device-sdk-core";
import { Button, Flex, Icons, Text } from "@ledgerhq/react-ui";
import { Button, Flex, Text } from "@ledgerhq/react-ui";
import Image from "next/image";
import styled, { DefaultTheme } from "styled-components";

import { useSdk } from "@/providers/DeviceSdkProvider";

const Root = styled(Flex)`
flex-direction: column;
flex: 1;
`;

const Header = styled(Flex).attrs({ py: 3, px: 10, gridGap: 8 })`
justify-content: flex-end;
align-items: center;
`;

const Actions = styled(Flex)`
justify-content: flex-end;
align-items: center;
flex: 1 0 0;
`;

const IconBox = styled(Flex).attrs({ p: 3 })`
cursor: pointer;
align-items: center;
opacity: 0.7;
`;

const Container = styled(Flex)`
flex: 1;
justify-content: center;
align-items: center;
Expand Down Expand Up @@ -85,44 +63,27 @@ export const MainView: React.FC = () => {

return (
<Root>
<Header>
<Actions>
<IconBox>
<Icons.Question size={"M"} />
</IconBox>
<IconBox>
<Icons.Settings size={"M"} />
</IconBox>
</Actions>
</Header>

<Container>
<NanoLogo
src={"/nano-x.png"}
alt={"nano-x-logo"}
width={155}
height={250}
/>
<Text
variant={"h2Inter"}
fontWeight={"semiBold"}
textTransform={"none"}
>
Ledger Device SDK
</Text>
<Description variant={"body"}>
Use this application to test Ledger hardware device features.
</Description>
<NanoLogo
src={"/nano-x.png"}
alt={"nano-x-logo"}
width={155}
height={250}
/>
<Text variant={"h2Inter"} fontWeight={"semiBold"} textTransform={"none"}>
Ledger Device SDK
</Text>
<Description variant={"body"}>
Use this application to test Ledger hardware device features.
</Description>

<Button
onClick={onSelectDeviceClicked}
variant="main"
backgroundColor="main"
size="large"
>
Select a device
</Button>
</Container>
<Button
onClick={onSelectDeviceClicked}
variant="main"
backgroundColor="main"
size="large"
>
Select a device
</Button>
</Root>
);
};
Loading

0 comments on commit d1adf36

Please sign in to comment.