chore: UI elements for Accounts screen

- Typography
- TextInput, Select
- AddPaymentMethod
- supported currencies and payment methods
- theme updates
This commit is contained in:
Subir 2022-05-06 01:49:37 +05:30
parent b029419e7f
commit 5460d3afae
No known key found for this signature in database
GPG Key ID: 2D633D8047FD3FF0
61 changed files with 2427 additions and 70 deletions

View File

@ -46,6 +46,7 @@
"@storybook/react": "^6.4.22",
"@storybook/testing-library": "^0.0.10",
"@testing-library/react": "^12",
"@types/lodash": "^4.14.182",
"@types/react": "<18.0.0",
"@types/react-dom": "<18.0.0",
"@typescript-eslint/eslint-plugin": "5.12.1",
@ -74,12 +75,15 @@
"dependencies": {
"@mantine/core": "^4.1.2",
"@mantine/dates": "^4.1.2",
"@mantine/form": "^4.2.2",
"@mantine/hooks": "^4.1.2",
"@mantine/modals": "^4.1.2",
"@mantine/notifications": "^4.1.2",
"dayjs": "^1.11.0",
"electron-store": "^8.0.1",
"electron-updater": "4.6.5",
"joi": "^17.6.0",
"lodash": "^4.17.21",
"react": "<18.0.0",
"react-dom": "<18.0.0",
"react-intl": "^5.24.8",

View File

@ -0,0 +1,4 @@
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M27.578 17.3866C25.7081 24.8866 18.1118 29.4511 10.6109 27.5808C3.11301 25.7109 -1.45142 18.1141 0.419327 10.6145C2.28833 3.11358 9.88464 -1.45129 17.3834 0.418582C24.8839 2.28846 29.4479 9.88608 27.578 17.3866Z" fill="#F7931A"/>
<path d="M20.173 12.0055C20.4516 10.1426 19.0333 9.14117 17.0938 8.47311L17.723 5.94961L16.1869 5.5668L15.5744 8.0238C15.1706 7.92317 14.7558 7.82824 14.3437 7.73417L14.9606 5.26099L13.4254 4.87817L12.7958 7.4008C12.4616 7.32467 12.1335 7.24942 11.815 7.17024L11.8167 7.16236L9.69833 6.63342L9.28971 8.27405C9.28971 8.27405 10.4294 8.53524 10.4053 8.55142C11.0275 8.70674 11.1399 9.11842 11.1211 9.4448L10.4045 12.3196C10.4473 12.3305 10.5029 12.3463 10.5641 12.3708C10.513 12.3581 10.4583 12.3441 10.4018 12.3305L9.39733 16.3577C9.32121 16.5467 9.12827 16.8302 8.69339 16.7226C8.70871 16.7449 7.57689 16.4439 7.57689 16.4439L6.81433 18.2022L8.81327 18.7005C9.18514 18.7937 9.54958 18.8913 9.90833 18.9832L9.27264 21.5355L10.807 21.9184L11.4365 19.3931C11.8556 19.5069 12.2625 19.6119 12.6606 19.7107L12.0333 22.2242L13.5693 22.607L14.205 20.0594C16.8243 20.5551 18.794 20.3552 19.623 17.9861C20.2911 16.0786 19.5898 14.9783 18.2116 14.2608C19.2153 14.0294 19.9713 13.3692 20.173 12.0055ZM16.6633 16.9269C16.1886 18.8344 12.977 17.8032 11.9357 17.5447L12.7792 14.1632C13.8205 14.4231 17.1595 14.9376 16.6633 16.9269ZM17.1385 11.9779C16.7053 13.713 14.0322 12.8315 13.1651 12.6154L13.9298 9.54849C14.797 9.76461 17.5895 10.168 17.1385 11.9779Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,3 @@
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 0C6.3 0 0 6.3 0 14C0 21.7 6.3 28 14 28C21.7 28 28 21.7 28 14C28 6.3 21.7 0 14 0ZM21 15H15V21C15 21.55 14.55 22 14 22C13.45 22 13 21.55 13 21V15H7C6.45 15 6 14.55 6 14C6 13.45 6.45 13 7 13C7 13 10.05 13 13 13V7C13 6.45 13.45 6 14 6C14.55 6 15 6.45 15 7V13C17.95 13 21 13 21 13C21.55 13 22 13.45 22 14C22 14.55 21.55 15 21 15Z" fill="#0B65DA" fill-opacity="0.25"/>
</svg>

After

Width:  |  Height:  |  Size: 479 B

View File

@ -0,0 +1,3 @@
<svg width="15" height="4" viewBox="0 0 15 4" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.375 1.875C9.375 2.925 8.5125 3.75 7.5 3.75C6.4875 3.75 5.625 2.8875 5.625 1.875C5.625 0.8625 6.4875 0 7.5 0C8.5125 0 9.375 0.8625 9.375 1.875ZM13.125 0C12.075 0 11.25 0.8625 11.25 1.875C11.25 2.8875 12.075 3.75 13.125 3.75C14.175 3.75 15 2.8875 15 1.875C15 0.8625 14.175 0 13.125 0ZM1.875 0C0.825 0 0 0.8625 0 1.875C0 2.8875 0.8625 3.75 1.875 3.75C2.8875 3.75 3.75 2.8875 3.75 1.875C3.75 0.8625 2.925 0 1.875 0Z" fill="#111111"/>
</svg>

After

Width:  |  Height:  |  Size: 543 B

View File

@ -0,0 +1,18 @@
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M27.5805 17.3866C25.7106 24.8866 18.1143 29.4511 10.6133 27.5808C3.11545 25.7109 -1.44898 18.1141 0.421768 10.6145C2.29077 3.11358 9.88708 -1.45129 17.3858 0.418582C24.8863 2.28846 29.4503 9.88608 27.5805 17.3866Z" fill="#DBDBDB"/>
<g opacity="0.6">
<path opacity="0.6" d="M14.1963 11.708L8.79468 14.1646L14.1963 17.3559L19.5958 14.1646L14.1963 11.708Z" fill="#010101"/>
</g>
<g opacity="0.45">
<path opacity="0.45" d="M8.79468 14.1647L14.1963 17.356V5.20239L8.79468 14.1647Z" fill="#010101"/>
</g>
<g opacity="0.8">
<path opacity="0.8" d="M14.1963 5.20239V17.356L19.5958 14.1647L14.1963 5.20239Z" fill="#010101"/>
</g>
<g opacity="0.45">
<path opacity="0.45" d="M8.79468 15.1881L14.1963 22.7979V18.3794L8.79468 15.1881Z" fill="#010101"/>
</g>
<g opacity="0.8">
<path opacity="0.8" d="M14.1963 18.3794V22.7979L19.6 15.1881L14.1963 18.3794Z" fill="#010101"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 975 B

View File

@ -0,0 +1,4 @@
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="14" cy="14" r="14" fill="#111111"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.3125 13.5653C10.2938 13.7446 10.2842 13.9266 10.2842 14.1108C10.2842 14.2923 10.2935 14.4715 10.3116 14.6481H16.7626V16.5591H10.8955C11.771 18.1966 13.4975 19.3107 15.4841 19.3107C16.8432 19.3107 18.0785 18.7906 19.0054 17.9369L20.3 19.3425C19.0342 20.5085 17.3414 21.2217 15.4841 21.2217C12.4172 21.2217 9.80382 19.2801 8.80596 16.5591H6.30005V14.6481H8.39325C8.38 14.4708 8.37326 14.2916 8.37326 14.1108C8.37326 13.9273 8.38021 13.7453 8.39388 13.5653H6.30005V11.6543H8.80901C9.80913 8.93763 12.4204 7 15.4841 7C17.3413 7 19.0342 7.71318 20.3 8.87918L19.0054 10.2847C18.0785 9.43103 16.8432 8.91097 15.4841 8.91097C13.5008 8.91097 11.7769 10.0213 10.8999 11.6543H16.7626V13.5653H10.3125Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 910 B

View File

@ -17,6 +17,7 @@
import { Routes, Route } from "react-router-dom";
import { Home, Welcome } from "@pages/Onboarding";
import { Wallet } from "@pages/Wallet";
import { PaymentMethods, AddPaymentMethod } from "@pages/Account";
export const ROUTES = {
Home: "/",
@ -24,6 +25,8 @@ export const ROUTES = {
RestoreBackup: "/onboarding/restore-backup",
SetupAccount: "/onboarding/setup",
Wallet: "/wallet",
AccountPaymentMethods: "/account/payment-methods",
AccountAddPaymentMethod: "/account/payment-methods/add",
};
export function AppRoutes() {
@ -32,6 +35,11 @@ export function AppRoutes() {
<Route path={ROUTES.Home} element={<Home />} />
<Route path={ROUTES.Welcome} element={<Welcome />} />
<Route path={ROUTES.Wallet} element={<Wallet />} />
<Route path={ROUTES.AccountPaymentMethods} element={<PaymentMethods />} />
<Route
path={ROUTES.AccountAddPaymentMethod}
element={<AddPaymentMethod />}
/>
</Routes>
);
}

View File

@ -14,20 +14,17 @@
// limitations under the License.
// =============================================================================
import { Box, createStyles, keyframes, Stack, Text } from "@mantine/core";
import { FormattedMessage } from "react-intl";
import { Box, createStyles, keyframes, Stack } from "@mantine/core";
import { LangKeys } from "@constants/lang/LangKeys";
import { BodyText } from "@atoms/Typography";
export function ConnectionProgress() {
const { classes } = useStyles();
return (
<Stack align="center" justify="center">
<Text size="sm">
<FormattedMessage
id={LangKeys.ConnectingToNetwork}
defaultMessage="Connecting to Monero Network"
/>
</Text>
<BodyText size="lg" stringId={LangKeys.ConnectingToNetwork}>
Connecting to Monero Network
</BodyText>
<Box className={classes.container}>
<Box className={classes.bar} />
</Box>

View File

@ -6,7 +6,7 @@ exports[`atoms::ConnectionProgress > renders without exploding 1`] = `
class="mantine-Stack-root mantine-njf2rt"
>
<div
class="mantine-Text-root mantine-102fqds"
class="mantine-Text-root mantine-1ourfup"
>
Connecting to Monero Network
</div>

View File

@ -0,0 +1,68 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import { Stack } from "@mantine/core";
import type { ComponentStory, ComponentMeta } from "@storybook/react";
import { Select } from ".";
export default {
title: "atoms/Select",
component: Select,
} as ComponentMeta<typeof Select>;
const Template: ComponentStory<typeof Select> = (args) => {
return (
<Stack>
<Select {...args} />
</Stack>
);
};
export const Default = Template.bind({});
Default.args = {
data: [
{ value: "react", label: "React" },
{ value: "ng", label: "Angular" },
{ value: "svelte", label: "Svelte" },
{ value: "vue", label: "Vue" },
],
placeholder: "Pick one",
};
export const Clearable = Template.bind({});
Clearable.args = {
clearable: true,
data: [
{ value: "react", label: "React" },
{ value: "ng", label: "Angular" },
{ value: "svelte", label: "Svelte" },
{ value: "vue", label: "Vue" },
],
placeholder: "Pick one",
searchable: false,
};
export const Searchable = Template.bind({});
Searchable.args = {
data: [
{ value: "react", label: "React" },
{ value: "ng", label: "Angular" },
{ value: "svelte", label: "Svelte" },
{ value: "vue", label: "Vue" },
],
placeholder: "Pick one",
searchable: true,
};

View File

@ -0,0 +1,38 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import { describe, expect, it } from "vitest";
import { render } from "@testing-library/react";
import { Select } from ".";
describe("atoms::Select", () => {
it("renders without exploding", () => {
const { asFragment } = render(
<Select
id="select"
label="Select your favorite framework"
placeholder="Pick one"
data={[
{ value: "react", label: "React" },
{ value: "ng", label: "Angular" },
{ value: "svelte", label: "Svelte" },
{ value: "vue", label: "Vue" },
]}
/>
);
expect(asFragment()).toMatchSnapshot();
});
});

View File

@ -0,0 +1,84 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import { useState, useMemo } from "react";
import type { SelectProps as MSelectProps } from "@mantine/core";
import { createStyles, Select as MSelect } from "@mantine/core";
import { ReactComponent as ArrowIcon } from "@assets/arrow-down.svg";
interface SelectProps extends MSelectProps {
id: string;
}
export function Select(props: SelectProps) {
const { clearable, value, onChange } = props;
const [isEmpty, setEmpty] = useState(!value);
const showClearButton = useMemo(
() => clearable === true && !isEmpty,
[clearable, isEmpty]
);
const { classes } = useStyles({ showClearButton });
const handleChange = (value: string) => {
setEmpty(!value);
if (onChange) {
onChange(value);
}
};
return (
<MSelect
{...props}
classNames={classes}
onChange={handleChange}
rightSection={
showClearButton ? undefined : (
<ArrowIcon className={classes.arrowIcon} />
)
}
withinPortal={false}
/>
);
}
const useStyles = createStyles<string, { showClearButton: boolean }>(
(theme, params) => ({
label: {
fontSize: "0.875rem",
fontWeight: 600,
marginBottom: theme.spacing.sm,
},
input: {
fontSize: "0.875rem",
fontWeight: 700,
height: "3rem",
padding: "1rem",
},
item: {
fontSize: "0.875rem",
fontWeight: 500,
padding: "1rem",
},
...(params.showClearButton
? null
: {
rightSection: { pointerEvents: "none" },
}),
arrowIcon: {
width: "0.5rem",
},
})
);

View File

@ -0,0 +1,65 @@
// Vitest Snapshot v1
exports[`atoms::Select > renders without exploding 1`] = `
<DocumentFragment>
<div
class="mantine-Select-root mantine-18udhi"
>
<label
class="mantine-Select-label mantine-7802ha"
for="select"
id="select-label"
>
Select your favorite framework
</label>
<div
aria-controls="select"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="select-items"
role="combobox"
tabindex="-1"
>
<input
defaultvalue=""
type="hidden"
/>
<div
class="mantine-Select-wrapper mantine-12sbrde"
>
<input
aria-autocomplete="list"
aria-invalid="false"
autocomplete="nope"
class="mantine-Select-defaultVariant mantine-Select-input mantine-93d3e4"
data-mantine-stop-propagation="false"
defaultvalue=""
id="select"
placeholder="Pick one"
readonly=""
type="text"
/>
<div
class="mantine-Select-rightSection mantine-14dm59e"
>
<svg
class="mantine-18du5gu"
fill="none"
height="1em"
viewBox="0 0 7 4"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
clip-rule="evenodd"
d="M2.91916 3.69319C3.23963 4.04927 3.76166 4.04657 4.07971 3.69319L6.82329 0.644746C7.14377 0.288661 7.01636 0 6.53811 0H0.460749C-0.0172283 0 -0.14248 0.291357 0.17557 0.644746L2.91916 3.69319Z"
fill="#111111"
fill-rule="evenodd"
/>
</svg>
</div>
</div>
</div>
</div>
</DocumentFragment>
`;

View File

@ -0,0 +1,17 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
export * from "./Select";

View File

@ -0,0 +1,39 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import { Stack } from "@mantine/core";
import type { ComponentStory, ComponentMeta } from "@storybook/react";
import { TextInput } from ".";
export default {
title: "atoms/TextInput",
component: TextInput,
} as ComponentMeta<typeof TextInput>;
const Template: ComponentStory<typeof TextInput> = (args) => {
return (
<Stack>
<TextInput {...args} />
</Stack>
);
};
export const Default = Template.bind({});
Default.args = {
id: "email",
label: "Your email",
placeholder: "johndoe@gmail.com",
};

View File

@ -0,0 +1,33 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import { describe, expect, it } from "vitest";
import { render } from "@testing-library/react";
import { TextInput } from ".";
describe("atoms::TextInput", () => {
it("renders without exploding", () => {
const { asFragment } = render(
<TextInput
id="textfield"
label="Email"
placeholder="johndoe@gmail.com"
type="email"
/>
);
expect(asFragment()).toMatchSnapshot();
});
});

View File

@ -0,0 +1,42 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import type { TextInputProps as MTextInputProps } from "@mantine/core";
import { createStyles, TextInput as MTextInput } from "@mantine/core";
interface TextInputProps extends MTextInputProps {
id: string;
}
export function TextInput(props: TextInputProps) {
const { id, ...rest } = props;
const { classes } = useStyles();
return <MTextInput classNames={classes} id={id} {...rest} />;
}
const useStyles = createStyles((theme) => ({
label: {
fontSize: "0.875rem",
fontWeight: 600,
marginBottom: theme.spacing.sm,
},
input: {
fontSize: "0.875rem",
fontWeight: 700,
height: "3rem",
padding: "1rem",
},
}));

View File

@ -0,0 +1,28 @@
// Vitest Snapshot v1
exports[`atoms::TextInput > renders without exploding 1`] = `
<DocumentFragment>
<div
class="mantine-TextInput-root mantine-18udhi"
>
<label
class="mantine-TextInput-label mantine-7802ha"
for="textfield"
id="textfield-label"
>
Email
</label>
<div
class="mantine-TextInput-wrapper mantine-12sbrde"
>
<input
aria-invalid="false"
class="mantine-TextInput-defaultVariant mantine-TextInput-input mantine-dagq8e"
id="textfield"
placeholder="johndoe@gmail.com"
type="email"
/>
</div>
</div>
</DocumentFragment>
`;

View File

@ -0,0 +1,17 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
export * from "./TextInput";

View File

@ -0,0 +1,37 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import { Stack } from "@mantine/core";
import type { ComponentStory, ComponentMeta } from "@storybook/react";
import { BodyText } from ".";
export default {
title: "atoms/Typography/ BodyText",
component: BodyText,
} as ComponentMeta<typeof BodyText>;
const Template: ComponentStory<typeof BodyText> = (args) => {
return (
<Stack>
<BodyText {...args}>Body Text</BodyText>
</Stack>
);
};
export const Default = Template.bind({});
Default.args = {
heavy: false,
};

View File

@ -0,0 +1,46 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import { Stack } from "@mantine/core";
import type { ComponentStory, ComponentMeta } from "@storybook/react";
import { Heading } from ".";
export default {
title: "atoms/Typography/Heading",
component: Heading,
argTypes: {
order: {
options: [1, 2, 3, 4, 5],
control: {
type: "radio",
},
},
},
} as ComponentMeta<typeof Heading>;
const Template: ComponentStory<typeof Heading> = (args) => {
return (
<Stack>
<Heading {...args} />
</Stack>
);
};
export const Default = Template.bind({});
Default.args = {
order: 1,
children: "This is a heading",
};

View File

@ -0,0 +1,40 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import type { ReactText } from "react";
import { FormattedMessage } from "react-intl";
import type { TitleProps } from "@mantine/core";
import { Title } from "@mantine/core";
import type { LangKeys } from "@constants/lang";
interface HeadingProps extends TitleProps {
children: ReactText;
stringId?: LangKeys;
}
export function Heading(props: HeadingProps) {
const { children, stringId, ...rest } = props;
return (
<Title {...rest}>
{stringId ? (
<FormattedMessage id={stringId} defaultMessage={children.toString()} />
) : (
children
)}
</Title>
);
}

View File

@ -0,0 +1,35 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import { Stack } from "@mantine/core";
import type { ComponentStory, ComponentMeta } from "@storybook/react";
import { InfoText } from ".";
export default {
title: "atoms/Typography/InfoText",
component: InfoText,
} as ComponentMeta<typeof InfoText>;
const Template: ComponentStory<typeof InfoText> = (args) => {
return (
<Stack>
<InfoText {...args}>Info Text</InfoText>
</Stack>
);
};
export const Default = Template.bind({});
Default.args = {};

View File

@ -0,0 +1,35 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import { Stack } from "@mantine/core";
import type { ComponentStory, ComponentMeta } from "@storybook/react";
import { LabelText } from ".";
export default {
title: "atoms/Typography/LabelText",
component: LabelText,
} as ComponentMeta<typeof LabelText>;
const Template: ComponentStory<typeof LabelText> = (args) => {
return (
<Stack>
<LabelText {...args}>Label Text</LabelText>
</Stack>
);
};
export const Default = Template.bind({});
Default.args = {};

View File

@ -0,0 +1,101 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import type { ReactText } from "react";
import { FormattedMessage } from "react-intl";
import type { TextProps as MTextProps } from "@mantine/core";
import { Text as MText, createStyles } from "@mantine/core";
import type { LangKeys } from "@constants/lang";
type TextProps<TComponent> = MTextProps<TComponent> & {
children: ReactText;
stringId?: LangKeys;
};
type BodyTextProps<TComponent> = TextProps<TComponent> & {
heavy?: boolean;
};
export function BodyText<TComponent = "p">(props: BodyTextProps<TComponent>) {
const { children, className, heavy, size, stringId, ...rest } = props;
const { classes, cx } = useStyles();
return (
<MText
{...rest}
className={cx(className, {
[classes.body]: !size || size === "md",
[classes.bodyLg]: size === "lg",
[classes.bodyHeavy]: Boolean(heavy),
})}
size={size}
>
{stringId ? (
<FormattedMessage id={stringId} defaultMessage={children.toString()} />
) : (
children
)}
</MText>
);
}
export function InfoText<TComponent = "p">(props: TextProps<TComponent>) {
const { children, className, stringId, ...rest } = props;
const { classes, cx } = useStyles();
return (
<MText {...rest} className={cx(className, classes.info)}>
{stringId ? (
<FormattedMessage id={stringId} defaultMessage={children.toString()} />
) : (
children
)}
</MText>
);
}
export function LabelText(props: TextProps<"label">) {
const { children, className, stringId, ...rest } = props;
const { classes, cx } = useStyles();
return (
<MText component="label" {...rest} className={cx(className, classes.label)}>
{stringId ? (
<FormattedMessage id={stringId} defaultMessage={children.toString()} />
) : (
children
)}
</MText>
);
}
const useStyles = createStyles((theme) => ({
info: {
color: theme.colors.gray[6],
fontSize: "0.875rem",
},
body: {
fontSize: "0.8125rem",
},
bodyHeavy: {
fontWeight: 500,
},
bodyLg: {
fontSize: "1rem",
fontWeight: 500,
},
label: {},
}));

View File

@ -0,0 +1,57 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import { describe, expect, it } from "vitest";
import { render } from "@testing-library/react";
import { BodyText, Heading, InfoText, LabelText } from ".";
describe("atoms::Typography", () => {
describe("::BodyText", () => {
it("renders without exploding", () => {
const { asFragment } = render(<BodyText>body text</BodyText>);
expect(asFragment()).toMatchSnapshot();
});
it("renders heavy variant exploding", () => {
const { asFragment } = render(<BodyText heavy>body text</BodyText>);
expect(asFragment()).toMatchSnapshot();
});
});
describe("::Heading", () => {
it("renders h1 by default", () => {
const { asFragment } = render(<Heading>heading text</Heading>);
expect(asFragment()).toMatchSnapshot();
});
it("renders h2", () => {
const { asFragment } = render(<Heading order={2}>heading text</Heading>);
expect(asFragment()).toMatchSnapshot();
});
});
describe("::InfoText", () => {
it("renders without exploding", () => {
const { asFragment } = render(<InfoText>Info text</InfoText>);
expect(asFragment()).toMatchSnapshot();
});
});
describe("::LabelText", () => {
it("renders without exploding", () => {
const { asFragment } = render(<LabelText>Label text</LabelText>);
expect(asFragment()).toMatchSnapshot();
});
});
});

View File

@ -0,0 +1,71 @@
// Vitest Snapshot v1
exports[`atoms::Typography > ::BodyText > renders heavy variant exploding 1`] = `
<DocumentFragment>
<div
class="mantine-Text-root mantine-119fjqf"
>
body text
</div>
</DocumentFragment>
`;
exports[`atoms::Typography > ::BodyText > renders without exploding 1`] = `
<DocumentFragment>
<div
class="mantine-Text-root mantine-1q69ff6"
>
body text
</div>
</DocumentFragment>
`;
exports[`atoms::Typography > ::Heading > renders h1 1`] = `
<DocumentFragment>
<h1
class="mantine-Title-root mantine-xz2ygd"
>
heading text
</h1>
</DocumentFragment>
`;
exports[`atoms::Typography > ::Heading > renders h1 by default 1`] = `
<DocumentFragment>
<h1
class="mantine-Title-root mantine-xz2ygd"
>
heading text
</h1>
</DocumentFragment>
`;
exports[`atoms::Typography > ::Heading > renders h2 1`] = `
<DocumentFragment>
<h2
class="mantine-Title-root mantine-1dbhwd4"
>
heading text
</h2>
</DocumentFragment>
`;
exports[`atoms::Typography > ::InfoText > renders without exploding 1`] = `
<DocumentFragment>
<div
class="mantine-Text-root mantine-5q0bln"
>
Info text
</div>
</DocumentFragment>
`;
exports[`atoms::Typography > ::LabelText > renders without exploding 1`] = `
<DocumentFragment>
<label
class="mantine-Text-root mantine-12ze1td"
>
Label text
</label>
</DocumentFragment>
`;

View File

@ -0,0 +1,18 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
export * from "./Heading";
export * from "./Text";

View File

@ -0,0 +1,55 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import { createStyles, UnstyledButton } from "@mantine/core";
import { ReactComponent as AddIcon } from "@assets/circle-plus.svg";
import { HEIGHT, WIDTH } from "./_constants";
interface AddCardProps {
onClick: () => void;
}
export function AddPaymentMethodButton({ onClick }: AddCardProps) {
const { classes } = useStyles();
return (
<UnstyledButton className={classes.card} onClick={onClick}>
<AddIcon />
</UnstyledButton>
);
}
const useStyles = createStyles((theme) => ({
card: {
background: theme.colors.gray[2],
borderRadius: "0.625rem",
display: "grid",
height: HEIGHT,
opacity: 0.75,
placeContent: "center",
transition: "opacity 0.2s",
width: WIDTH,
"&:hover": {
opacity: 1,
},
"& svg": {
height: "1.75rem",
width: "1.75rem",
},
},
}));

View File

@ -0,0 +1,81 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import {
Box,
createStyles,
Group,
Stack,
Text,
UnstyledButton,
} from "@mantine/core";
import { ReactComponent as MenuIcon } from "@assets/ellipsis.svg";
import { HEIGHT, WIDTH, CurrencyLogos } from "./_constants";
import type { SupportedCurrencies } from "./_types";
import { BodyText } from "@atoms/Typography";
import { useMemo } from "react";
interface PaymentMethodCardProps {
currency: SupportedCurrencies;
accountId: string;
}
export function PaymentMethodCard(props: PaymentMethodCardProps) {
const { accountId, currency } = props;
const { classes } = useStyles();
const Logo = useMemo(() => CurrencyLogos[currency].Logo, [currency]);
return (
<Box className={classes.card}>
<Stack>
<Group position="apart">
<Group>
<Logo className={classes.logo} />
<Text className={classes.name}>{CurrencyLogos[currency].name}</Text>
</Group>
<UnstyledButton>
<MenuIcon className={classes.menuIcon} />
</UnstyledButton>
</Group>
<BodyText heavy sx={{ wordBreak: "break-word" }}>
{accountId}
</BodyText>
</Stack>
</Box>
);
}
const useStyles = createStyles((theme) => ({
card: {
background: theme.colors.white[0],
border: `solid 1px ${theme.colors.gray[2]}`,
borderRadius: "0.625rem",
height: HEIGHT,
padding: "1.25rem",
width: WIDTH,
},
logo: {
height: "1.75rem",
width: "1.75rem",
},
name: {
color: theme.colors.gray[6],
},
menuIcon: {
width: "1rem",
},
}));

View File

@ -0,0 +1,44 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import type { FC } from "react";
import { ReactComponent as BtcLogo } from "@assets/btc.svg";
import { ReactComponent as EthLogo } from "@assets/eth.svg";
import { ReactComponent as EurLogo } from "@assets/eur.svg";
import type { SupportedCurrencies } from "./_types";
export const WIDTH = "17rem";
export const HEIGHT = "7.25rem";
interface CurrencyDetails {
Logo: FC<any>; // eslint-disable-line @typescript-eslint/no-explicit-any
name: string;
}
export const CurrencyLogos: Record<SupportedCurrencies, CurrencyDetails> = {
BTC: {
Logo: BtcLogo,
name: "Bitcoin",
},
ETH: {
Logo: EthLogo,
name: "Ethereum",
},
EUR: {
Logo: EurLogo,
name: "Euro",
},
};

View File

@ -0,0 +1,17 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
export type SupportedCurrencies = "BTC" | "ETH" | "EUR";

View File

@ -0,0 +1,18 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
export * from "./AddPaymentMethodButton";
export * from "./PaymentMethodCard";

View File

@ -3,7 +3,7 @@
exports[`molecules::WalletBalance > renders without exploding 1`] = `
<DocumentFragment>
<button
class="mantine-UnstyledButton-root mantine-1v0qbt7"
class="mantine-UnstyledButton-root mantine-3om9so"
type="button"
>
<div
@ -45,7 +45,7 @@ exports[`molecules::WalletBalance > renders without exploding 1`] = `
</defs>
</svg>
<div
class="mantine-Text-root mantine-Group-child mantine-15e7vnj"
class="mantine-Text-root mantine-Group-child mantine-1iw7oli"
>
Available Balance
</div>
@ -57,7 +57,7 @@ exports[`molecules::WalletBalance > renders without exploding 1`] = `
class="mantine-Group-root mantine-6y1794"
>
<div
class="mantine-Text-root mantine-Group-child mantine-3vx9ct"
class="mantine-Text-root mantine-Group-child mantine-q5labh"
>
10.647382650365
</div>
@ -78,7 +78,7 @@ exports[`molecules::WalletBalance > renders without exploding 1`] = `
</svg>
</div>
<div
class="mantine-Text-root mantine-14xctlx"
class="mantine-Text-root mantine-1pfxwhx"
>
(EUR 2441,02)
</div>
@ -98,12 +98,12 @@ exports[`molecules::WalletBalance > renders without exploding 1`] = `
class="mantine-Stack-root mantine-1kb6t4k"
>
<div
class="mantine-Text-root mantine-xtp7ze"
class="mantine-Text-root mantine-kaqdcf"
>
Total
</div>
<div
class="mantine-Text-root mantine-pxv98s"
class="mantine-Text-root mantine-14d5cdm"
>
14.048212174412
</div>
@ -112,12 +112,12 @@ exports[`molecules::WalletBalance > renders without exploding 1`] = `
class="mantine-Stack-root mantine-1kb6t4k"
>
<div
class="mantine-Text-root mantine-xtp7ze"
class="mantine-Text-root mantine-kaqdcf"
>
Reserved
</div>
<div
class="mantine-Text-root mantine-pxv98s"
class="mantine-Text-root mantine-14d5cdm"
>
2.874598526325
</div>
@ -126,12 +126,12 @@ exports[`molecules::WalletBalance > renders without exploding 1`] = `
class="mantine-Stack-root mantine-1kb6t4k"
>
<div
class="mantine-Text-root mantine-xtp7ze"
class="mantine-Text-root mantine-kaqdcf"
>
Locked
</div>
<div
class="mantine-Text-root mantine-pxv98s"
class="mantine-Text-root mantine-14d5cdm"
>
0.854975624859
</div>

View File

@ -0,0 +1,30 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import type { ComponentStory, ComponentMeta } from "@storybook/react";
import { AddPaymentMethod } from ".";
export default {
title: "organisms/Add Payment Method",
component: AddPaymentMethod,
} as ComponentMeta<typeof AddPaymentMethod>;
const Template: ComponentStory<typeof AddPaymentMethod> = () => {
return <AddPaymentMethod />;
};
export const Default = Template.bind({});
Default.args = {};

View File

@ -0,0 +1,26 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import { describe, expect, it } from "vitest";
import { render } from "@testing-library/react";
import { AddPaymentMethod } from ".";
describe("organisms::AddPaymentMethod", () => {
it("renders without exploding", () => {
const { asFragment } = render(<AddPaymentMethod />);
expect(asFragment()).toMatchSnapshot();
});
});

View File

@ -0,0 +1,126 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import { useEffect, useMemo } from "react";
import { Collapse, Group, Space, Stack } from "@mantine/core";
import { useForm, joiResolver } from "@mantine/form";
import Joi from "joi";
import { Button } from "@atoms/Buttons";
import { Select } from "@atoms/Select";
import { SupportedCurrencies } from "@constants/currencies";
import { PaymentMethods as _PaymentMethods } from "@constants/payment-methods";
import { TextInput } from "@atoms/TextInput";
interface FormValues {
currency: string;
paymentMethod: string;
accountNumber: string;
}
export function AddPaymentMethod() {
const { getInputProps, onSubmit, setFieldValue, values } =
useForm<FormValues>({
schema: joiResolver(schema),
initialValues: {
currency: "",
paymentMethod: "",
accountNumber: "",
},
});
const PaymentMethods = useMemo(() => {
if (!values.currency) {
return [];
}
const currency = SupportedCurrencies.find(
(curr) => curr.id === values.currency
);
if (!currency) {
return [];
}
return Object.entries(_PaymentMethods)
.filter(([, method]) => currency.paymentMethods.includes(method.id))
.map(([, method]) => ({
value: method.id,
label: method.name,
}))
.sort((a, b) => (a.label > b.label ? 1 : -1));
}, [values?.currency]);
const handleSubmit = (values: FormValues) => console.log(values);
useEffect(() => {
setFieldValue("paymentMethod", "");
}, [values.currency]);
useEffect(() => {
setFieldValue("accountNumber", "");
}, [values.paymentMethod]);
return (
<Stack spacing="lg">
<form onSubmit={onSubmit(handleSubmit)}>
<Stack sx={{ maxWidth: "32rem" }}>
<Select
data={Currencies}
id="currency"
label="Select the currency for your new payment account"
placeholder="Pick one"
{...getInputProps("currency")}
/>
<Collapse in={Boolean(values.currency)}>
<Select
creatable
data={PaymentMethods}
id="paymentMethod"
label="Select your preferred payment method"
placeholder="Pick one"
searchable
{...getInputProps("paymentMethod")}
/>
</Collapse>
<Collapse in={Boolean(values.paymentMethod)}>
<TextInput
id="accountNumber"
label="Account Number"
{...getInputProps("accountNumber")}
/>
</Collapse>
<Group position="right" mt="md">
<Button type="submit">Save</Button>
</Group>
</Stack>
</form>
<Space h="xl" />
<Stack></Stack>
</Stack>
);
}
const schema = Joi.object({
currency: Joi.string().required(),
paymentMethod: Joi.string().required(),
accountNumber: Joi.string().required(),
});
const Currencies = SupportedCurrencies.map((curr) => ({
value: curr.id,
label: curr.name,
}));

View File

@ -0,0 +1,199 @@
// Vitest Snapshot v1
exports[`organisms::AddPaymentMethod > renders without exploding 1`] = `
<DocumentFragment>
<div
class="mantine-Stack-root mantine-1kgx180"
>
<form>
<div
class="mantine-Stack-root mantine-1i7neaa"
>
<div
class="mantine-Select-root mantine-18udhi"
>
<label
class="mantine-Select-label mantine-7802ha"
for="currency"
id="currency-label"
>
Select the currency for your new payment account
</label>
<div
aria-controls="currency"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="currency-items"
role="combobox"
tabindex="-1"
>
<input
defaultvalue=""
type="hidden"
/>
<div
class="mantine-Select-wrapper mantine-12sbrde"
>
<input
aria-autocomplete="list"
aria-invalid="false"
autocomplete="nope"
class="mantine-Select-defaultVariant mantine-Select-input mantine-93d3e4"
data-mantine-stop-propagation="false"
defaultvalue=""
id="currency"
placeholder="Pick one"
readonly=""
type="text"
/>
<div
class="mantine-Select-rightSection mantine-14dm59e"
>
<svg
class="mantine-18du5gu"
fill="none"
height="1em"
viewBox="0 0 7 4"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
clip-rule="evenodd"
d="M2.91916 3.69319C3.23963 4.04927 3.76166 4.04657 4.07971 3.69319L6.82329 0.644746C7.14377 0.288661 7.01636 0 6.53811 0H0.460749C-0.0172283 0 -0.14248 0.291357 0.17557 0.644746L2.91916 3.69319Z"
fill="#111111"
fill-rule="evenodd"
/>
</svg>
</div>
</div>
</div>
</div>
<div
aria-hidden="true"
class="mantine-1avyp1d"
style="box-sizing: border-box; display: none; height: 0px; overflow: hidden;"
>
<div
style="opacity: 0; transition: opacity 200ms ease;"
>
<div
class="mantine-Select-root mantine-18udhi"
>
<label
class="mantine-Select-label mantine-7802ha"
for="paymentMethod"
id="paymentMethod-label"
>
Select your preferred payment method
</label>
<div
aria-controls="paymentMethod"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="paymentMethod-items"
role="combobox"
tabindex="-1"
>
<input
defaultvalue=""
type="hidden"
/>
<div
class="mantine-Select-wrapper mantine-12sbrde"
>
<input
aria-autocomplete="list"
aria-invalid="false"
autocomplete="nope"
class="mantine-Select-defaultVariant mantine-Select-input mantine-16ko5f2"
data-mantine-stop-propagation="false"
defaultvalue=""
id="paymentMethod"
placeholder="Pick one"
type="text"
/>
<div
class="mantine-Select-rightSection mantine-14dm59e"
>
<svg
class="mantine-18du5gu"
fill="none"
height="1em"
viewBox="0 0 7 4"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
clip-rule="evenodd"
d="M2.91916 3.69319C3.23963 4.04927 3.76166 4.04657 4.07971 3.69319L6.82329 0.644746C7.14377 0.288661 7.01636 0 6.53811 0H0.460749C-0.0172283 0 -0.14248 0.291357 0.17557 0.644746L2.91916 3.69319Z"
fill="#111111"
fill-rule="evenodd"
/>
</svg>
</div>
</div>
</div>
</div>
</div>
</div>
<div
aria-hidden="true"
class="mantine-1avyp1d"
style="box-sizing: border-box; display: none; height: 0px; overflow: hidden;"
>
<div
style="opacity: 0; transition: opacity 200ms ease;"
>
<div
class="mantine-TextInput-root mantine-18udhi"
>
<label
class="mantine-TextInput-label mantine-7802ha"
for="accountNumber"
id="accountNumber-label"
>
Account Number
</label>
<div
class="mantine-TextInput-wrapper mantine-12sbrde"
>
<input
aria-invalid="false"
class="mantine-TextInput-defaultVariant mantine-TextInput-input mantine-dagq8e"
defaultvalue=""
id="accountNumber"
type="text"
/>
</div>
</div>
</div>
</div>
<div
class="mantine-Group-root mantine-mk7hdv"
>
<button
class="mantine-Button-filled mantine-Button-root mantine-Group-child mantine-1i7r9hr"
type="submit"
>
<div
class="mantine-3xbgk5 mantine-Button-inner"
>
<span
class="mantine-qo1k2 mantine-Button-label"
>
Save
</span>
</div>
</button>
</div>
</div>
</form>
<div
class="mantine-1eabysl"
/>
<div
class="mantine-Stack-root mantine-lfk3cq"
/>
</div>
</DocumentFragment>
`;

View File

@ -0,0 +1,17 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
export * from "./AddPaymentMethod";

View File

@ -0,0 +1,32 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import type { ComponentStory, ComponentMeta } from "@storybook/react";
import { PaymentMethodList } from ".";
export default {
title: "organisms/Payment Method List",
component: PaymentMethodList,
} as ComponentMeta<typeof PaymentMethodList>;
const Template: ComponentStory<typeof PaymentMethodList> = (args) => {
return <PaymentMethodList {...args} />;
};
export const Default = Template.bind({});
Default.args = {
onAdd: () => console.log("onAdd called"),
};

View File

@ -0,0 +1,51 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import { Group, Space, Stack } from "@mantine/core";
import { Heading, BodyText } from "@atoms/Typography";
import {
AddPaymentMethodButton,
PaymentMethodCard,
} from "@molecules/PaymentMethodCard";
interface PaymentMethodsProps {
onAdd: () => void;
}
export function PaymentMethodList({ onAdd }: PaymentMethodsProps) {
return (
<Stack spacing="lg">
<Stack sx={{ maxWidth: "32rem" }}>
<Heading order={2}>Your available payment accounts</Heading>
<BodyText heavy>
To engage in trades you need payment methods to support these trades.
The payment methods are stored locally on your device and details are
only shown to counter parties in trades when needed.
</BodyText>
</Stack>
<Space h="xl" />
<Group spacing="xl">
<PaymentMethodCard
accountId="1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2"
currency="BTC"
/>
<PaymentMethodCard accountId="tqTFn5Au4m4GFg7x" currency="ETH" />
<PaymentMethodCard accountId="112233" currency="EUR" />
<AddPaymentMethodButton onClick={onAdd} />
</Group>
</Stack>
);
}

View File

@ -0,0 +1,17 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
export * from "./PaymentMethodList";

View File

@ -19,7 +19,7 @@ import type { ComponentStory, ComponentMeta } from "@storybook/react";
import { Sidebar } from ".";
export default {
title: "molecules/Sidebar",
title: "organisms/Sidebar",
component: Sidebar,
} as ComponentMeta<typeof Sidebar>;

View File

@ -24,7 +24,7 @@ export function Sidebar() {
const { classes } = useStyles();
return (
<Stack className={classes.container}>
<Navbar height="100%" p={0} width={{ base: WIDTH }}>
<Navbar height="100%" p={0} pl="sm" width={{ base: WIDTH }}>
<Navbar.Section>
<Box component={Logo} className={classes.logo} />
</Navbar.Section>

View File

@ -34,7 +34,6 @@ export function NavLink({ icon, isActive = false, label }: NavLinkProps) {
color="gray"
size="xs"
transform="uppercase"
weight={700}
>
{label}
</Text>
@ -81,7 +80,8 @@ const useStyles = createStyles<string, { isActive: boolean }>(
theme.colorScheme === "dark"
? theme.colors.dark[6]
: theme.colors.dark[8],
fontSize: "0.6875rem",
fontWeight: 700,
transition: "opacity 0.2s",
},
})

View File

@ -6,7 +6,7 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
class="mantine-Stack-root mantine-dczm8e"
>
<nav
class="mantine-Navbar-root mantine-11l21uw"
class="mantine-Navbar-root mantine-pjloqa"
>
<div
class="mantine-khtkeg"
@ -33,7 +33,7 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
class="mantine-khtkeg"
>
<button
class="mantine-UnstyledButton-root mantine-1wgvoyu"
class="mantine-UnstyledButton-root mantine-1fq8ags"
type="button"
>
<div
@ -53,7 +53,7 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
/>
</svg>
<div
class="mantine-Text-root mantine-Group-child __mantine-ref-text mantine-1omu9y9"
class="mantine-Text-root mantine-Group-child __mantine-ref-text mantine-1b3ywxa"
>
Markets
</div>
@ -64,7 +64,7 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
class="mantine-khtkeg"
>
<button
class="mantine-UnstyledButton-root mantine-1wgvoyu"
class="mantine-UnstyledButton-root mantine-1fq8ags"
type="button"
>
<div
@ -88,7 +88,7 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
/>
</svg>
<div
class="mantine-Text-root mantine-Group-child __mantine-ref-text mantine-1omu9y9"
class="mantine-Text-root mantine-Group-child __mantine-ref-text mantine-1b3ywxa"
>
My Offers
</div>
@ -99,7 +99,7 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
class="mantine-khtkeg"
>
<button
class="mantine-UnstyledButton-root mantine-1wgvoyu"
class="mantine-UnstyledButton-root mantine-1fq8ags"
type="button"
>
<div
@ -127,7 +127,7 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
/>
</svg>
<div
class="mantine-Text-root mantine-Group-child __mantine-ref-text mantine-1omu9y9"
class="mantine-Text-root mantine-Group-child __mantine-ref-text mantine-1b3ywxa"
>
My Trades
</div>
@ -138,7 +138,7 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
class="mantine-khtkeg"
>
<button
class="mantine-UnstyledButton-root mantine-1wgvoyu"
class="mantine-UnstyledButton-root mantine-1fq8ags"
type="button"
>
<div
@ -158,7 +158,7 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
/>
</svg>
<div
class="mantine-Text-root mantine-Group-child __mantine-ref-text mantine-1omu9y9"
class="mantine-Text-root mantine-Group-child __mantine-ref-text mantine-1b3ywxa"
>
Notifications
</div>
@ -169,7 +169,7 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
class="mantine-khtkeg"
>
<button
class="mantine-UnstyledButton-root mantine-1wgvoyu"
class="mantine-UnstyledButton-root mantine-1fq8ags"
type="button"
>
<div
@ -188,7 +188,7 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
/>
</svg>
<div
class="mantine-Text-root mantine-Group-child __mantine-ref-text mantine-1omu9y9"
class="mantine-Text-root mantine-Group-child __mantine-ref-text mantine-1b3ywxa"
>
Account
</div>
@ -202,7 +202,7 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
class="mantine-b98ato"
>
<button
class="mantine-UnstyledButton-root mantine-1v0qbt7"
class="mantine-UnstyledButton-root mantine-3om9so"
type="button"
>
<div
@ -244,7 +244,7 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
</defs>
</svg>
<div
class="mantine-Text-root mantine-Group-child mantine-15e7vnj"
class="mantine-Text-root mantine-Group-child mantine-1iw7oli"
>
Available Balance
</div>
@ -256,7 +256,7 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
class="mantine-Group-root mantine-6y1794"
>
<div
class="mantine-Text-root mantine-Group-child mantine-3vx9ct"
class="mantine-Text-root mantine-Group-child mantine-q5labh"
>
10.647382650365
</div>
@ -277,7 +277,7 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
</svg>
</div>
<div
class="mantine-Text-root mantine-14xctlx"
class="mantine-Text-root mantine-1pfxwhx"
>
(EUR 2441,02)
</div>
@ -297,12 +297,12 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
class="mantine-Stack-root mantine-1kb6t4k"
>
<div
class="mantine-Text-root mantine-xtp7ze"
class="mantine-Text-root mantine-kaqdcf"
>
Total
</div>
<div
class="mantine-Text-root mantine-pxv98s"
class="mantine-Text-root mantine-14d5cdm"
>
14.048212174412
</div>
@ -311,12 +311,12 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
class="mantine-Stack-root mantine-1kb6t4k"
>
<div
class="mantine-Text-root mantine-xtp7ze"
class="mantine-Text-root mantine-kaqdcf"
>
Reserved
</div>
<div
class="mantine-Text-root mantine-pxv98s"
class="mantine-Text-root mantine-14d5cdm"
>
2.874598526325
</div>
@ -325,12 +325,12 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
class="mantine-Stack-root mantine-1kb6t4k"
>
<div
class="mantine-Text-root mantine-xtp7ze"
class="mantine-Text-root mantine-kaqdcf"
>
Locked
</div>
<div
class="mantine-Text-root mantine-pxv98s"
class="mantine-Text-root mantine-14d5cdm"
>
0.854975624859
</div>

View File

@ -16,7 +16,7 @@
import type { FC } from "react";
import { Box, createStyles, Group } from "@mantine/core";
import { Sidebar } from "@molecules/Sidebar";
import { Sidebar } from "@organisms/Sidebar";
export const NavbarLayout: FC = (props) => {
const { children } = props;
@ -28,7 +28,6 @@ export const NavbarLayout: FC = (props) => {
</Group>
);
};
// fcfcfc
const useStyles = createStyles((theme) => ({
container: {

View File

@ -0,0 +1,129 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import { ReactComponent as BtcLogo } from "@assets/btc.svg";
import { ReactComponent as EthLogo } from "@assets/eth.svg";
import { ReactComponent as EurLogo } from "@assets/eur.svg";
import { PaymentMethodIds } from "./payment-methods";
export const SupportedCurrencies = [
{
id: "BTC",
name: "Bitcoin",
logo: BtcLogo,
paymentMethods: [PaymentMethodIds.BLOCK_CHAINS_ID],
},
{
id: "ETH",
name: "Ethereum",
logo: EthLogo,
paymentMethods: [PaymentMethodIds.BLOCK_CHAINS_ID],
},
{
id: "EUR",
name: "Euro",
logo: EurLogo,
paymentMethods: [
// EUR
PaymentMethodIds.SEPA_ID,
PaymentMethodIds.SEPA_INSTANT_ID,
PaymentMethodIds.MONEY_BEAM_ID,
// UK
PaymentMethodIds.FASTER_PAYMENTS_ID,
// Sweden
PaymentMethodIds.SWISH_ID,
// Global
PaymentMethodIds.CASH_DEPOSIT_ID,
PaymentMethodIds.CASH_BY_MAIL_ID,
PaymentMethodIds.MONEY_GRAM_ID,
PaymentMethodIds.WESTERN_UNION_ID,
PaymentMethodIds.NATIONAL_BANK_ID,
PaymentMethodIds.SAME_BANK_ID,
PaymentMethodIds.SPECIFIC_BANKS_ID,
PaymentMethodIds.HAL_CASH_ID,
PaymentMethodIds.F2F_ID,
PaymentMethodIds.AMAZON_GIFT_CARD_ID,
// Trans national
PaymentMethodIds.UPHOLD_ID,
PaymentMethodIds.REVOLUT_ID,
PaymentMethodIds.PERFECT_MONEY_ID,
PaymentMethodIds.ADVANCED_CASH_ID,
PaymentMethodIds.TRANSFERWISE_ID,
PaymentMethodIds.TRANSFERWISE_USD_ID,
PaymentMethodIds.PAYSERA_ID,
PaymentMethodIds.PAXUM_ID,
PaymentMethodIds.NEQUI_ID,
PaymentMethodIds.BIZUM_ID,
PaymentMethodIds.PIX_ID,
PaymentMethodIds.CAPITUAL_ID,
PaymentMethodIds.CELPAY_ID,
PaymentMethodIds.MONESE_ID,
PaymentMethodIds.SATISPAY_ID,
PaymentMethodIds.TIKKIE_ID,
PaymentMethodIds.VERSE_ID,
PaymentMethodIds.STRIKE_ID,
PaymentMethodIds.SWIFT_ID,
PaymentMethodIds.ACH_TRANSFER_ID,
PaymentMethodIds.DOMESTIC_WIRE_TRANSFER_ID,
],
},
{
id: "USD",
name: "US Dollar",
logo: EurLogo,
paymentMethods: [
// US
PaymentMethodIds.CLEAR_X_CHANGE_ID,
PaymentMethodIds.POPMONEY_ID,
PaymentMethodIds.US_POSTAL_MONEY_ORDER_ID,
// Global
PaymentMethodIds.CASH_DEPOSIT_ID,
PaymentMethodIds.CASH_BY_MAIL_ID,
PaymentMethodIds.MONEY_GRAM_ID,
PaymentMethodIds.WESTERN_UNION_ID,
PaymentMethodIds.NATIONAL_BANK_ID,
PaymentMethodIds.SAME_BANK_ID,
PaymentMethodIds.SPECIFIC_BANKS_ID,
PaymentMethodIds.HAL_CASH_ID,
PaymentMethodIds.F2F_ID,
PaymentMethodIds.AMAZON_GIFT_CARD_ID,
// Trans national
PaymentMethodIds.UPHOLD_ID,
PaymentMethodIds.REVOLUT_ID,
PaymentMethodIds.PERFECT_MONEY_ID,
PaymentMethodIds.ADVANCED_CASH_ID,
PaymentMethodIds.TRANSFERWISE_ID,
PaymentMethodIds.TRANSFERWISE_USD_ID,
PaymentMethodIds.PAYSERA_ID,
PaymentMethodIds.PAXUM_ID,
PaymentMethodIds.NEQUI_ID,
PaymentMethodIds.BIZUM_ID,
PaymentMethodIds.PIX_ID,
PaymentMethodIds.CAPITUAL_ID,
PaymentMethodIds.CELPAY_ID,
PaymentMethodIds.MONESE_ID,
PaymentMethodIds.SATISPAY_ID,
PaymentMethodIds.TIKKIE_ID,
PaymentMethodIds.VERSE_ID,
PaymentMethodIds.STRIKE_ID,
PaymentMethodIds.SWIFT_ID,
PaymentMethodIds.ACH_TRANSFER_ID,
PaymentMethodIds.DOMESTIC_WIRE_TRANSFER_ID,
],
},
];

View File

@ -0,0 +1,433 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import startCase from "lodash/startCase";
import camelCase from "lodash/camelCase";
// Ref: https://github.com/bisq-network/bisq/blob/master/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java
const DEFAULT_TRADE_LIMIT_VERY_LOW_RISK = 1;
const DEFAULT_TRADE_LIMIT_LOW_RISK = 0.5;
const DEFAULT_TRADE_LIMIT_MID_RISK = 0.25;
const DEFAULT_TRADE_LIMIT_HIGH_RISK = 0.125;
export enum PaymentMethodIds {
UPHOLD_ID = "UPHOLD",
MONEY_BEAM_ID = "MONEY_BEAM",
POPMONEY_ID = "POPMONEY",
REVOLUT_ID = "REVOLUT",
PERFECT_MONEY_ID = "PERFECT_MONEY",
SEPA_ID = "SEPA",
SEPA_INSTANT_ID = "SEPA_INSTANT",
FASTER_PAYMENTS_ID = "FASTER_PAYMENTS",
NATIONAL_BANK_ID = "NATIONAL_BANK",
JAPAN_BANK_ID = "JAPAN_BANK",
AUSTRALIA_PAYID_ID = "AUSTRALIA_PAYID",
SAME_BANK_ID = "SAME_BANK",
SPECIFIC_BANKS_ID = "SPECIFIC_BANKS",
SWISH_ID = "SWISH",
ALI_PAY_ID = "ALI_PAY",
WECHAT_PAY_ID = "WECHAT_PAY",
CLEAR_X_CHANGE_ID = "CLEAR_X_CHANGE",
INTERAC_E_TRANSFER_ID = "INTERAC_E_TRANSFER",
US_POSTAL_MONEY_ORDER_ID = "US_POSTAL_MONEY_ORDER",
CASH_DEPOSIT_ID = "CASH_DEPOSIT",
MONEY_GRAM_ID = "MONEY_GRAM",
WESTERN_UNION_ID = "WESTERN_UNION",
HAL_CASH_ID = "HAL_CASH",
F2F_ID = "F2F",
BLOCK_CHAINS_ID = "BLOCK_CHAINS",
PROMPT_PAY_ID = "PROMPT_PAY",
ADVANCED_CASH_ID = "ADVANCED_CASH",
TRANSFERWISE_ID = "TRANSFERWISE",
TRANSFERWISE_USD_ID = "TRANSFERWISE_USD",
PAYSERA_ID = "PAYSERA",
PAXUM_ID = "PAXUM",
NEFT_ID = "NEFT",
RTGS_ID = "RTGS",
IMPS_ID = "IMPS",
UPI_ID = "UPI",
PAYTM_ID = "PAYTM",
NEQUI_ID = "NEQUI",
BIZUM_ID = "BIZUM",
PIX_ID = "PIX",
AMAZON_GIFT_CARD_ID = "AMAZON_GIFT_CARD",
BLOCK_CHAINS_INSTANT_ID = "BLOCK_CHAINS_INSTANT",
CASH_BY_MAIL_ID = "CASH_BY_MAIL",
CAPITUAL_ID = "CAPITUAL",
CELPAY_ID = "CELPAY",
MONESE_ID = "MONESE",
SATISPAY_ID = "SATISPAY",
TIKKIE_ID = "TIKKIE",
VERSE_ID = "VERSE",
STRIKE_ID = "STRIKE",
SWIFT_ID = "SWIFT",
ACH_TRANSFER_ID = "ACH_TRANSFER",
DOMESTIC_WIRE_TRANSFER_ID = "DOMESTIC_WIRE_TRANSFER",
}
const HOUR = 3_600_000; // ms in 1 hour
const DAY = 86_400_000; // ms in 1 day
export const PaymentMethods: Record<
PaymentMethodIds,
{
id: PaymentMethodIds;
name: string;
maxTradePeriod: number;
maxTradeLimit: number;
}
> = {
// EUR
[PaymentMethodIds.SEPA_ID]: {
id: PaymentMethodIds.SEPA_ID,
name: startCase(camelCase(PaymentMethodIds.SEPA_ID)),
maxTradePeriod: 6 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.SEPA_INSTANT_ID]: {
id: PaymentMethodIds.SEPA_INSTANT_ID,
name: startCase(camelCase(PaymentMethodIds.SEPA_INSTANT_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.MONEY_BEAM_ID]: {
id: PaymentMethodIds.MONEY_BEAM_ID,
name: startCase(camelCase(PaymentMethodIds.MONEY_BEAM_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
// UK
[PaymentMethodIds.FASTER_PAYMENTS_ID]: {
id: PaymentMethodIds.FASTER_PAYMENTS_ID,
name: startCase(camelCase(PaymentMethodIds.FASTER_PAYMENTS_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
// Sweden
[PaymentMethodIds.SWISH_ID]: {
id: PaymentMethodIds.SWISH_ID,
name: startCase(camelCase(PaymentMethodIds.SWISH_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_LOW_RISK,
},
// US
[PaymentMethodIds.CLEAR_X_CHANGE_ID]: {
id: PaymentMethodIds.CLEAR_X_CHANGE_ID,
name: startCase(camelCase(PaymentMethodIds.CLEAR_X_CHANGE_ID)),
maxTradePeriod: 4 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.POPMONEY_ID]: {
id: PaymentMethodIds.POPMONEY_ID,
name: startCase(camelCase(PaymentMethodIds.POPMONEY_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.US_POSTAL_MONEY_ORDER_ID]: {
id: PaymentMethodIds.US_POSTAL_MONEY_ORDER_ID,
name: startCase(camelCase(PaymentMethodIds.US_POSTAL_MONEY_ORDER_ID)),
maxTradePeriod: 8 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
// Canada
[PaymentMethodIds.INTERAC_E_TRANSFER_ID]: {
id: PaymentMethodIds.INTERAC_E_TRANSFER_ID,
name: startCase(camelCase(PaymentMethodIds.INTERAC_E_TRANSFER_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
// Global
[PaymentMethodIds.CASH_DEPOSIT_ID]: {
id: PaymentMethodIds.CASH_DEPOSIT_ID,
name: startCase(camelCase(PaymentMethodIds.CASH_DEPOSIT_ID)),
maxTradePeriod: 4 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.CASH_BY_MAIL_ID]: {
id: PaymentMethodIds.CASH_BY_MAIL_ID,
name: startCase(camelCase(PaymentMethodIds.CASH_BY_MAIL_ID)),
maxTradePeriod: 8 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.MONEY_GRAM_ID]: {
id: PaymentMethodIds.MONEY_GRAM_ID,
name: startCase(camelCase(PaymentMethodIds.MONEY_GRAM_ID)),
maxTradePeriod: 4 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_MID_RISK,
},
[PaymentMethodIds.WESTERN_UNION_ID]: {
id: PaymentMethodIds.WESTERN_UNION_ID,
name: startCase(camelCase(PaymentMethodIds.WESTERN_UNION_ID)),
maxTradePeriod: 4 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_MID_RISK,
},
[PaymentMethodIds.NATIONAL_BANK_ID]: {
id: PaymentMethodIds.NATIONAL_BANK_ID,
name: startCase(camelCase(PaymentMethodIds.NATIONAL_BANK_ID)),
maxTradePeriod: 4 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.SAME_BANK_ID]: {
id: PaymentMethodIds.SAME_BANK_ID,
name: startCase(camelCase(PaymentMethodIds.SAME_BANK_ID)),
maxTradePeriod: 2 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.SPECIFIC_BANKS_ID]: {
id: PaymentMethodIds.SPECIFIC_BANKS_ID,
name: startCase(camelCase(PaymentMethodIds.SPECIFIC_BANKS_ID)),
maxTradePeriod: 4 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.HAL_CASH_ID]: {
id: PaymentMethodIds.HAL_CASH_ID,
name: startCase(camelCase(PaymentMethodIds.HAL_CASH_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_LOW_RISK,
},
[PaymentMethodIds.F2F_ID]: {
id: PaymentMethodIds.F2F_ID,
name: startCase(camelCase(PaymentMethodIds.F2F_ID)),
maxTradePeriod: 4 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_LOW_RISK,
},
[PaymentMethodIds.AMAZON_GIFT_CARD_ID]: {
id: PaymentMethodIds.AMAZON_GIFT_CARD_ID,
name: startCase(camelCase(PaymentMethodIds.AMAZON_GIFT_CARD_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
// Trans national
[PaymentMethodIds.UPHOLD_ID]: {
id: PaymentMethodIds.UPHOLD_ID,
name: startCase(camelCase(PaymentMethodIds.UPHOLD_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.REVOLUT_ID]: {
id: PaymentMethodIds.REVOLUT_ID,
name: startCase(camelCase(PaymentMethodIds.REVOLUT_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.PERFECT_MONEY_ID]: {
id: PaymentMethodIds.PERFECT_MONEY_ID,
name: startCase(camelCase(PaymentMethodIds.PERFECT_MONEY_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_LOW_RISK,
},
[PaymentMethodIds.ADVANCED_CASH_ID]: {
id: PaymentMethodIds.ADVANCED_CASH_ID,
name: startCase(camelCase(PaymentMethodIds.ADVANCED_CASH_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_VERY_LOW_RISK,
},
[PaymentMethodIds.TRANSFERWISE_ID]: {
id: PaymentMethodIds.TRANSFERWISE_ID,
name: startCase(camelCase(PaymentMethodIds.TRANSFERWISE_ID)),
maxTradePeriod: 4 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.TRANSFERWISE_USD_ID]: {
id: PaymentMethodIds.TRANSFERWISE_USD_ID,
name: startCase(camelCase(PaymentMethodIds.TRANSFERWISE_USD_ID)),
maxTradePeriod: 4 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.PAYSERA_ID]: {
id: PaymentMethodIds.PAYSERA_ID,
name: startCase(camelCase(PaymentMethodIds.PAYSERA_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.PAXUM_ID]: {
id: PaymentMethodIds.PAXUM_ID,
name: startCase(camelCase(PaymentMethodIds.PAXUM_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.NEFT_ID]: {
id: PaymentMethodIds.NEFT_ID,
name: startCase(camelCase(PaymentMethodIds.NEFT_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: 0.02,
},
[PaymentMethodIds.RTGS_ID]: {
id: PaymentMethodIds.RTGS_ID,
name: startCase(camelCase(PaymentMethodIds.RTGS_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.IMPS_ID]: {
id: PaymentMethodIds.IMPS_ID,
name: startCase(camelCase(PaymentMethodIds.IMPS_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.UPI_ID]: {
id: PaymentMethodIds.UPI_ID,
name: startCase(camelCase(PaymentMethodIds.UPI_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: 0.05,
},
[PaymentMethodIds.PAYTM_ID]: {
id: PaymentMethodIds.PAYTM_ID,
name: startCase(camelCase(PaymentMethodIds.PAYTM_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: 0.05,
},
[PaymentMethodIds.NEQUI_ID]: {
id: PaymentMethodIds.NEQUI_ID,
name: startCase(camelCase(PaymentMethodIds.NEQUI_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.BIZUM_ID]: {
id: PaymentMethodIds.BIZUM_ID,
name: startCase(camelCase(PaymentMethodIds.BIZUM_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: 0.04,
},
[PaymentMethodIds.PIX_ID]: {
id: PaymentMethodIds.PIX_ID,
name: startCase(camelCase(PaymentMethodIds.PIX_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.CAPITUAL_ID]: {
id: PaymentMethodIds.CAPITUAL_ID,
name: startCase(camelCase(PaymentMethodIds.CAPITUAL_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.CELPAY_ID]: {
id: PaymentMethodIds.CELPAY_ID,
name: startCase(camelCase(PaymentMethodIds.CELPAY_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.MONESE_ID]: {
id: PaymentMethodIds.MONESE_ID,
name: startCase(camelCase(PaymentMethodIds.MONESE_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.SATISPAY_ID]: {
id: PaymentMethodIds.SATISPAY_ID,
name: startCase(camelCase(PaymentMethodIds.SATISPAY_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.TIKKIE_ID]: {
id: PaymentMethodIds.TIKKIE_ID,
name: startCase(camelCase(PaymentMethodIds.TIKKIE_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: 0.05,
},
[PaymentMethodIds.VERSE_ID]: {
id: PaymentMethodIds.VERSE_ID,
name: startCase(camelCase(PaymentMethodIds.VERSE_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.STRIKE_ID]: {
id: PaymentMethodIds.STRIKE_ID,
name: startCase(camelCase(PaymentMethodIds.STRIKE_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.SWIFT_ID]: {
id: PaymentMethodIds.SWIFT_ID,
name: startCase(camelCase(PaymentMethodIds.SWIFT_ID)),
maxTradePeriod: 7 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_MID_RISK,
},
[PaymentMethodIds.ACH_TRANSFER_ID]: {
id: PaymentMethodIds.ACH_TRANSFER_ID,
name: startCase(camelCase(PaymentMethodIds.ACH_TRANSFER_ID)),
maxTradePeriod: 5 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
[PaymentMethodIds.DOMESTIC_WIRE_TRANSFER_ID]: {
id: PaymentMethodIds.DOMESTIC_WIRE_TRANSFER_ID,
name: startCase(camelCase(PaymentMethodIds.DOMESTIC_WIRE_TRANSFER_ID)),
maxTradePeriod: 3 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_HIGH_RISK,
},
// Japan
[PaymentMethodIds.JAPAN_BANK_ID]: {
id: PaymentMethodIds.JAPAN_BANK_ID,
name: startCase(camelCase(PaymentMethodIds.JAPAN_BANK_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_LOW_RISK,
},
// Australia
[PaymentMethodIds.AUSTRALIA_PAYID_ID]: {
id: PaymentMethodIds.AUSTRALIA_PAYID_ID,
name: startCase(camelCase(PaymentMethodIds.AUSTRALIA_PAYID_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_LOW_RISK,
},
// China
[PaymentMethodIds.ALI_PAY_ID]: {
id: PaymentMethodIds.ALI_PAY_ID,
name: startCase(camelCase(PaymentMethodIds.ALI_PAY_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_LOW_RISK,
},
[PaymentMethodIds.WECHAT_PAY_ID]: {
id: PaymentMethodIds.WECHAT_PAY_ID,
name: startCase(camelCase(PaymentMethodIds.WECHAT_PAY_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_LOW_RISK,
},
// Thailand
[PaymentMethodIds.PROMPT_PAY_ID]: {
id: PaymentMethodIds.PROMPT_PAY_ID,
name: startCase(camelCase(PaymentMethodIds.PROMPT_PAY_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_LOW_RISK,
},
// Altcoins
[PaymentMethodIds.BLOCK_CHAINS_ID]: {
id: PaymentMethodIds.BLOCK_CHAINS_ID,
name: startCase(camelCase(PaymentMethodIds.BLOCK_CHAINS_ID)),
maxTradePeriod: 1 * DAY,
maxTradeLimit: DEFAULT_TRADE_LIMIT_VERY_LOW_RISK,
},
// Altcoins with 1 hour trade period
[PaymentMethodIds.BLOCK_CHAINS_INSTANT_ID]: {
id: PaymentMethodIds.BLOCK_CHAINS_INSTANT_ID,
name: startCase(camelCase(PaymentMethodIds.BLOCK_CHAINS_INSTANT_ID)),
maxTradePeriod: HOUR,
maxTradeLimit: DEFAULT_TRADE_LIMIT_VERY_LOW_RISK,
},
};

View File

@ -0,0 +1,26 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import { AddPaymentMethod as AddPaymentMethodOrganism } from "@organisms/AddPaymentMethod";
import { NavbarLayout } from "@templates/NavbarLayout";
export function AddPaymentMethod() {
return (
<NavbarLayout>
<AddPaymentMethodOrganism />
</NavbarLayout>
);
}

View File

@ -0,0 +1,32 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
import { useNavigate } from "react-router-dom";
import { PaymentMethodList } from "@organisms/PaymentMethodList";
import { NavbarLayout } from "@templates/NavbarLayout";
import { ROUTES } from "@src/Routes";
export function PaymentMethods() {
const navigate = useNavigate();
return (
<NavbarLayout>
<PaymentMethodList
onAdd={() => navigate(ROUTES.AccountAddPaymentMethod)}
/>
</NavbarLayout>
);
}

View File

@ -0,0 +1,18 @@
// =============================================================================
// Copyright 2022 Haveno
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
export * from "./AddPaymentMethod";
export * from "./PaymentMethods";

View File

@ -14,11 +14,11 @@
// limitations under the License.
// =============================================================================
import { FormattedMessage } from "react-intl";
import { Box, Space, Stack, Text } from "@mantine/core";
import { Box, Space, Stack } from "@mantine/core";
import { LangKeys } from "@constants/lang/LangKeys";
import { CenteredLayout } from "@templates/CenteredLayout";
import { ConnectionProgress } from "@atoms/ConnectionProgress";
import { Heading } from "@atoms/Typography";
import Logo from "@assets/logo.svg";
export function Home() {
@ -27,12 +27,13 @@ export function Home() {
<Stack align="center" justify="center" sx={{ flex: 1 }}>
<Stack>
<Box component="img" src={Logo} alt="Haveno" />
<Text size="lg">
<FormattedMessage
id={LangKeys.AppHeading2}
defaultMessage="Monero based decentralized exchange"
/>
</Text>
<Heading
order={2}
stringId={LangKeys.AppHeading2}
sx={{ fontWeight: 500 }}
>
Monero based decentralized exchange
</Heading>
</Stack>
<Space h="lg" />
<ConnectionProgress />

View File

@ -14,11 +14,11 @@
// limitations under the License.
// =============================================================================
import { Stack, Space, Text, Title, Container, Group } from "@mantine/core";
import { FormattedMessage } from "react-intl";
import { Stack, Space, Container, Group } from "@mantine/core";
import { LangKeys } from "@constants/lang/LangKeys";
import { CenteredLayout } from "@src/components/templates/CenteredLayout";
import { CenteredLayout } from "@templates/CenteredLayout";
import { Button } from "@atoms/Buttons";
import { BodyText, Heading } from "@atoms/Typography";
import { CONTENT_MAX_WIDTH } from "./_constants";
export function Welcome() {
@ -27,17 +27,15 @@ export function Welcome() {
<Stack align="center" justify="center" sx={{ flex: 1 }}>
<Stack>
<Container size={CONTENT_MAX_WIDTH}>
<Title order={1}>
<FormattedMessage
id={LangKeys.WelcomeToHaveno}
defaultMessage="Welcome to Haveno. The worlds first Monero based decentralised exchange."
/>
</Title>
<Heading order={1} stringId={LangKeys.WelcomeToHaveno}>
Welcome to Haveno. The world&apos;s first Monero based
decentralised exchange.
</Heading>
</Container>
<Container size={CONTENT_MAX_WIDTH}>
<Text size="md">
Before you can use Haveno, were going to set up your account.{" "}
</Text>
<BodyText size="lg">
Before you can use Haveno, we&apos;re going to set up your account
</BodyText>
</Container>
</Stack>
<Space h="lg" />

View File

@ -14,15 +14,19 @@
// limitations under the License.
// =============================================================================
import type { CSSObject } from "@mantine/core";
import InterFont from "@assets/fonts/Inter-Variable.ttf";
export const globalStyles = {
export const globalStyles: CSSObject = {
"@font-face": {
fontFamily: "Inter",
src: `url('${InterFont}')`,
fontWeight: "100 800",
fontStyle: "normal italic",
},
"*, *::before, *::after": {
boxSizing: "border-box",
},
body: {
margin: 0,
padding: 0,

View File

@ -17,9 +17,39 @@
import type { MantineThemeOverride } from "@mantine/core";
export const themeOverride: MantineThemeOverride = {
fontFamily: "Inter",
fontFamily: "Inter, sans-serif",
fontSizes: {
xl: 18,
lg: 16,
md: 14,
sm: 12,
xs: 10,
},
headings: {
fontFamily: "Inter",
fontFamily: "Inter, sans-serif",
fontWeight: 600,
sizes: {
h1: {
fontSize: "2.25rem",
lineHeight: 1.25,
},
h2: {
fontSize: "1.25rem",
lineHeight: 1.25,
},
h3: {
fontSize: "1.125rem",
lineHeight: 1.25,
},
h4: {
fontSize: "0.875rem",
lineHeight: 1.25,
},
h5: {
fontSize: "0.75rem",
lineHeight: 1.25,
},
},
},
other: {
buttonHeight: 48,
@ -40,7 +70,7 @@ export const themeOverride: MantineThemeOverride = {
gray: [
"#fcfcfc",
"#f1f3f5",
"#ececec",
"#E8E7EC",
"#dee2e6",
"#ced4da",
"#adb5bd",
@ -73,5 +103,17 @@ export const themeOverride: MantineThemeOverride = {
"#58190E",
"#2C0C07",
],
white: [
"#fff",
"#fff",
"#fff",
"#fff",
"#fff",
"#fff",
"#fff",
"#fff",
"#fff",
"#fff",
],
},
};

View File

@ -1601,6 +1601,18 @@
resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
"@hapi/hoek@^9.0.0":
version "9.3.0"
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb"
integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==
"@hapi/topo@^5.0.0":
version "5.1.0"
resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012"
integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==
dependencies:
"@hapi/hoek" "^9.0.0"
"@humanwhocodes/config-array@^0.9.2":
version "0.9.5"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7"
@ -1743,6 +1755,11 @@
resolved "https://registry.yarnpkg.com/@mantine/dates/-/dates-4.1.2.tgz#21290c24513622df3f701d3bee1a548a3ae7e4b9"
integrity sha512-Eb47531xlgZlhlkPsesyWGnfH+0mSYtKP5AylXdJAdi9rqC/9bxsEyIJHTUiJmVs+Cr5LvnVblubKBemapGWGg==
"@mantine/form@^4.2.2":
version "4.2.2"
resolved "https://registry.yarnpkg.com/@mantine/form/-/form-4.2.2.tgz#083cbd3d8554f3efa3c12421b8c6ebb0154d056d"
integrity sha512-wrC1m3TV4icaaUwfd4sUV8xyjx6MHsVNSdaP7hqALCVC3iNWLOHLxkDCZZbOn0lg1X7UX62JUqcJm6E+41PNog==
"@mantine/hooks@^4.1.2":
version "4.1.2"
resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-4.1.2.tgz#7d9af7e505bdfb017a37181ed4061fa66e37cbae"
@ -1984,6 +2001,23 @@
estree-walker "^2.0.1"
picomatch "^2.2.2"
"@sideway/address@^4.1.3":
version "4.1.4"
resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0"
integrity sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==
dependencies:
"@hapi/hoek" "^9.0.0"
"@sideway/formula@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.0.tgz#fe158aee32e6bd5de85044be615bc08478a0a13c"
integrity sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==
"@sideway/pinpoint@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df"
integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==
"@sindresorhus/is@^0.14.0":
version "0.14.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
@ -3144,6 +3178,11 @@
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
"@types/lodash@^4.14.182":
version "4.14.182"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.182.tgz#05301a4d5e62963227eaafe0ce04dd77c54ea5c2"
integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==
"@types/mdast@^3.0.0":
version "3.0.10"
resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af"
@ -8835,6 +8874,17 @@ jest-worker@^26.5.0, jest-worker@^26.6.2:
merge-stream "^2.0.0"
supports-color "^7.0.0"
joi@^17.6.0:
version "17.6.0"
resolved "https://registry.yarnpkg.com/joi/-/joi-17.6.0.tgz#0bb54f2f006c09a96e75ce687957bd04290054b2"
integrity sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==
dependencies:
"@hapi/hoek" "^9.0.0"
"@hapi/topo" "^5.0.0"
"@sideway/address" "^4.1.3"
"@sideway/formula" "^3.0.0"
"@sideway/pinpoint" "^2.0.0"
jpeg-js@0.4.3:
version "0.4.3"
resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.3.tgz#6158e09f1983ad773813704be80680550eff977b"