From a7c7f2e50daca61bedbc04a855dabb9da19c65b2 Mon Sep 17 00:00:00 2001 From: ryry79261 Date: Thu, 21 Oct 2021 14:44:13 +0200 Subject: [PATCH 01/22] Working on fetching plans --- packages/files-ui/package.json | 2 +- .../files-ui/src/Components/FilesRoutes.tsx | 8 -- .../Settings/Products/ChangeProductModal.tsx | 58 ++++++++++++ .../ChangeProductViews/SelectPlan.tsx | 88 +++++++++++++++++++ .../SubscriptionTab/CurrentProduct.tsx | 26 +++--- .../src/Components/Pages/PlansPage.tsx | 8 -- .../files-ui/src/Contexts/BillingContext.tsx | 20 ++++- yarn.lock | 9 ++ 8 files changed, 187 insertions(+), 32 deletions(-) create mode 100644 packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductModal.tsx create mode 100644 packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx delete mode 100644 packages/files-ui/src/Components/Pages/PlansPage.tsx diff --git a/packages/files-ui/package.json b/packages/files-ui/package.json index e36bc68b94..b7670d5ca9 100644 --- a/packages/files-ui/package.json +++ b/packages/files-ui/package.json @@ -6,7 +6,7 @@ "@babel/core": "^7.12.10", "@babel/runtime": "^7.0.0", "@chainsafe/browser-storage-hooks": "^1.0.1", - "@chainsafe/files-api-client": "^1.18.16", + "@chainsafe/files-api-client": "^1.18.18", "@chainsafe/web3-context": "1.1.4", "@lingui/core": "^3.7.2", "@lingui/react": "^3.7.2", diff --git a/packages/files-ui/src/Components/FilesRoutes.tsx b/packages/files-ui/src/Components/FilesRoutes.tsx index b90c6cd350..d00714fc40 100644 --- a/packages/files-ui/src/Components/FilesRoutes.tsx +++ b/packages/files-ui/src/Components/FilesRoutes.tsx @@ -9,7 +9,6 @@ import BinPage from "./Pages/BinPage" import { useThresholdKey } from "../Contexts/ThresholdKeyContext" import ShareFilesPage from "./Pages/SharedFilesPage" import SharedFoldersOverview from "./Modules/FileBrowsers/SharedFoldersOverview" -import PlansPage from "./Pages/PlansPage" export const SETTINGS_BASE = "/settings" export const ROUTE_LINKS = { @@ -94,13 +93,6 @@ const FilesRoutes = () => { component={SettingsPage} redirectPath={ROUTE_LINKS.Landing} /> - + createStyles({ + root: { + }, + slide: { + borderRadius: constants.generalUnit / 2, + padding: `0 ${constants.generalUnit * 3}px` + } + }) +) + +interface IChangeProductModal { + active: boolean + className?: string + close: () => void +} + +const ChangeProductModal = ({ active, className, close }: IChangeProductModal) => { + const classes = useStyles() + + const [newPlan, setNewPlan] = useState() + + const [slide, setSlide] = useState<"select" | "confirm">("select") + + useEffect(() => { + if (!active && slide !== "select") { + setSlide("select") + } + }, [active, slide]) + + return ( + + { + slide === "select" && { + setNewPlan(id) + setSlide("confirm") + }} + /> + } + + ) +} + +export default ChangeProductModal \ No newline at end of file diff --git a/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx b/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx new file mode 100644 index 0000000000..103254cc8c --- /dev/null +++ b/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx @@ -0,0 +1,88 @@ +import React, { useState } from "react" +import { makeStyles, createStyles } from "@chainsafe/common-theme" +import clsx from "clsx" +import { Button, Typography } from "@chainsafe/common-components" +import { Trans } from "@lingui/macro" +import { CSFTheme } from "../../../../../Themes/types" + +const useStyles = makeStyles(({ constants, palette, typography }: CSFTheme) => + createStyles({ + root: { + margin: `${constants.generalUnit * 3}px 0px` + }, + buttons: { + display: "flex", + flexDirection: "row", + alignItems: "center", + justifyContent: "flex-end", + "& > *": { + marginLeft: constants.generalUnit + } + }, + bottomSection: { + display: "flex", + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center" + } + }) +) + +interface ISelectPlan { + className?: string + close: () => void + next: (id: string) => void +} + +const SelectPlan = ({ close, className, next }: ISelectPlan) => { + const classes = useStyles() + + const [newPlan, setNewPlan] = useState(undefined) + + return ( + + ) +} + +export default SelectPlan \ No newline at end of file diff --git a/packages/files-ui/src/Components/Modules/Settings/SubscriptionTab/CurrentProduct.tsx b/packages/files-ui/src/Components/Modules/Settings/SubscriptionTab/CurrentProduct.tsx index ead2f3e880..1d00b9986c 100644 --- a/packages/files-ui/src/Components/Modules/Settings/SubscriptionTab/CurrentProduct.tsx +++ b/packages/files-ui/src/Components/Modules/Settings/SubscriptionTab/CurrentProduct.tsx @@ -1,18 +1,17 @@ -import React from "react" +import React, { useState } from "react" import { Button, formatBytes, - Link, Loading, ProgressBar, Typography } from "@chainsafe/common-components" import { makeStyles, ITheme, createStyles } from "@chainsafe/common-theme" -import { ROUTE_LINKS } from "../../../FilesRoutes" import { useFiles } from "../../../../Contexts/FilesContext" import { t, Trans } from "@lingui/macro" import clsx from "clsx" import { useBilling } from "../../../../Contexts/BillingContext" +import ChangeProductModal from "../Products/ChangeProductModal" const useStyles = makeStyles(({ breakpoints, constants }: ITheme) => createStyles({ @@ -62,6 +61,7 @@ const CurrentProduct = ({ className }: ICurrentProduct) => { const classes = useStyles() const { storageSummary } = useFiles() const { currentSubscription } = useBilling() + const [changeProductActive, setChangeProductActive] = useState(false) return (
{ />
- setChangeProductActive(true)} > - - + Change Plan +
+ setChangeProductActive(false)} + /> } diff --git a/packages/files-ui/src/Components/Pages/PlansPage.tsx b/packages/files-ui/src/Components/Pages/PlansPage.tsx deleted file mode 100644 index f24f740b83..0000000000 --- a/packages/files-ui/src/Components/Pages/PlansPage.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import React from "react" -import Products from "../Modules/Settings/Products/Products" - -const PlansPage = () => { - return -} - -export default PlansPage diff --git a/packages/files-ui/src/Contexts/BillingContext.tsx b/packages/files-ui/src/Contexts/BillingContext.tsx index 8e683680ae..3543102283 100644 --- a/packages/files-ui/src/Contexts/BillingContext.tsx +++ b/packages/files-ui/src/Contexts/BillingContext.tsx @@ -1,7 +1,7 @@ import * as React from "react" import { useFilesApi } from "./FilesApiContext" import { ReactNode, useEffect, useState } from "react" -import { Card, CurrentSubscription } from "@chainsafe/files-api-client" +import { Card, CurrentSubscription, Product } from "@chainsafe/files-api-client" import { useCallback } from "react" import { t } from "@lingui/macro" @@ -14,6 +14,7 @@ interface IBillingContext { refreshDefaultCard: () => void currentSubscription: CurrentSubscription | undefined fetchCurrentSubscription: () => void + getAvailablePlans: () => void } const ProductMapping: {[key: string]: { @@ -78,13 +79,28 @@ const BillingProvider = ({ children }: BillingContextProps) => { } }, [isLoggedIn, fetchCurrentSubscription, currentSubscription]) + const getAvailablePlans = useCallback(() => { + filesApiClient.getAllProducts() + .then((products) => { + return products.map(product => { + product.name = ProductMapping[product.id].name + product.description = ProductMapping[product.id].description + return product + }) + }) + .catch((error: any) => { + console.error(error) + }) + }, []) + return ( {children} diff --git a/yarn.lock b/yarn.lock index 39993e2a54..0a4e658b07 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1934,6 +1934,15 @@ "@redocly/openapi-core" "^1.0.0-beta.58" redoc-cli "^0.12.3" +"@chainsafe/files-api-client@^1.18.18": + version "1.18.18" + resolved "https://registry.yarnpkg.com/@chainsafe/files-api-client/-/files-api-client-1.18.18.tgz#1fc8e7fe2a657d95a8aec8e1e7d69b0c1e2a9a38" + integrity sha512-MkMsEUebgsY/7RtWQU3WMcVKa0xuj9nq/6V87P5YiQ3B7cxqOyFZsmsU3u2dVS15crBWXcEiey0LUUDrvbVNOg== + dependencies: + "@redocly/openapi-cli" "^1.0.0-beta.58" + "@redocly/openapi-core" "^1.0.0-beta.58" + redoc-cli "^0.12.3" + "@chainsafe/web3-context@1.1.4": version "1.1.4" resolved "https://registry.yarnpkg.com/@chainsafe/web3-context/-/web3-context-1.1.4.tgz#ce0f140af8ccf93af1a189fbdbd6f018b9bf5fb7" From 4cb1bd9e86d3f22a2b33feadeafdd965fe5478cb Mon Sep 17 00:00:00 2001 From: ryry79261 Date: Fri, 22 Oct 2021 11:47:55 +0200 Subject: [PATCH 02/22] Working on toggle switch --- .../src/ToggleSwitch/ToggleSwitch.tsx | 118 ++++++++++++++++++ .../src/ToggleSwitch/index.tsx | 6 + packages/common-components/src/index.ts | 1 + .../src/Overrides/ToggleSwitch.ts | 5 + packages/common-theme/src/Overrides/index.ts | 2 + .../ChangeProductViews/SelectPlan.tsx | 65 ++++++++-- .../files-ui/src/Contexts/BillingContext.tsx | 7 +- 7 files changed, 191 insertions(+), 13 deletions(-) create mode 100644 packages/common-components/src/ToggleSwitch/ToggleSwitch.tsx create mode 100644 packages/common-components/src/ToggleSwitch/index.tsx create mode 100644 packages/common-theme/src/Overrides/ToggleSwitch.ts diff --git a/packages/common-components/src/ToggleSwitch/ToggleSwitch.tsx b/packages/common-components/src/ToggleSwitch/ToggleSwitch.tsx new file mode 100644 index 0000000000..ce66f98346 --- /dev/null +++ b/packages/common-components/src/ToggleSwitch/ToggleSwitch.tsx @@ -0,0 +1,118 @@ +import { createStyles, ITheme, makeStyles } from "@chainsafe/common-theme" +import clsx from "clsx" +import React, { ReactNode, useCallback, useState } from "react" +import { Typography } from ".." + +interface IStyleProps { + size: "large" | "medium" | "small" | number | undefined +} + +const SIZES = { + small: 14, + medium: 16, + large: 20 +} + +const useStyles = makeStyles( + ({ breakpoints, overrides }: ITheme) => + createStyles({ + root : { + [breakpoints.down("md")]: { + marginBottom: 0 + }, + ...overrides?.Tabs?.root + }, + background: ({ size }: IStyleProps) => ({ + height: size && typeof size === "number" ? size : "initial", + width: size && typeof size === "number" ? size * 2 : "initial", + "&.large": { + height: SIZES.large, + width: SIZES.large * 2 + }, + "&.medium": { + height: SIZES.medium, + width: SIZES.medium * 2 + }, + "&.small": { + height: SIZES.small, + width: SIZES.small * 2 + } + }), + dot: { + + } + }) +) + +interface ToggleSwitchInjectedClasses { + root?: string + background?: string + dot?: string +} + +// Could allow for a slider to be made from this +interface IToggleOption { + value: string | number + label?: string | ReactNode | number +} + +interface IToggleSwitch { + injectedClasses?: ToggleSwitchInjectedClasses + left: IToggleOption + right: IToggleOption + onChange(value: string | number): void + size?: "large" | "medium" | "small" | number + error?: string + disabled?: boolean + value?: string | number + isClearable?: boolean + // name?: string +} + +const ToggleSwitch = ({ injectedClasses, left, right, onChange, value, size }: IToggleSwitch) => { + const classes = useStyles({ size }) + const [side, setSide] = useState<"left" | "right">(value && right.value === value ? "right" : "left") + + const onToggle = useCallback(() => { + if (side === "left") { + setSide("right") + onChange(right.value) + } else { + setSide("left") + onChange(left.value) + } + }, [left, right, side, onChange]) + + return
+ { + side === "left" && left.label && ( + + { left.label } + + ) + } + { + side === "right" && right.label && ( + + { right.label } + + ) + } +
+
+
+
+
+} + +export default ToggleSwitch +export { IToggleSwitch, IToggleOption, ToggleSwitchInjectedClasses } diff --git a/packages/common-components/src/ToggleSwitch/index.tsx b/packages/common-components/src/ToggleSwitch/index.tsx new file mode 100644 index 0000000000..0bd778f9e6 --- /dev/null +++ b/packages/common-components/src/ToggleSwitch/index.tsx @@ -0,0 +1,6 @@ +export { + default as ToggleSwitch, + IToggleOption, + IToggleSwitch, + ToggleSwitchInjectedClasses +} from "./ToggleSwitch" diff --git a/packages/common-components/src/index.ts b/packages/common-components/src/index.ts index a6d8a17044..561e07dde4 100644 --- a/packages/common-components/src/index.ts +++ b/packages/common-components/src/index.ts @@ -34,6 +34,7 @@ export * from "./Tabs" export * from "./TagsInput" export * from "./Toasts" export * from "./ToggleHiddenText" +export * from "./ToggleSwitch" export * from "./TextInput" export * from "./TreeView" export * from "./Typography" diff --git a/packages/common-theme/src/Overrides/ToggleSwitch.ts b/packages/common-theme/src/Overrides/ToggleSwitch.ts new file mode 100644 index 0000000000..ae39a6ac0f --- /dev/null +++ b/packages/common-theme/src/Overrides/ToggleSwitch.ts @@ -0,0 +1,5 @@ +export interface IToggleSwitch { + root?: Record + background?: Record + dot?: Record +} diff --git a/packages/common-theme/src/Overrides/index.ts b/packages/common-theme/src/Overrides/index.ts index e56d61266b..d661438a34 100644 --- a/packages/common-theme/src/Overrides/index.ts +++ b/packages/common-theme/src/Overrides/index.ts @@ -25,6 +25,7 @@ import { IToastsOverride } from "./Toasts" import { ITypographyOverride } from "./Typography" import { ITagsInputOverride } from "./TagsInput" import { IToggleHiddenText } from "./ToggleHiddenText" +import { IToggleSwitch } from "./ToggleSwitch" export interface IComponentOverrides { Avatar?: IAvatarOverride @@ -52,6 +53,7 @@ export interface IComponentOverrides { TextInput?: ITextInputOverride Toasts?: IToastsOverride ToggleHiddenText?: IToggleHiddenText + ToggleSwitch?: IToggleSwitch Typography?: ITypographyOverride TagsInput?: ITagsInputOverride } diff --git a/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx b/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx index 103254cc8c..ac1915e74b 100644 --- a/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx +++ b/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx @@ -1,14 +1,19 @@ -import React, { useState } from "react" +import React, { useEffect, useState } from "react" import { makeStyles, createStyles } from "@chainsafe/common-theme" import clsx from "clsx" import { Button, Typography } from "@chainsafe/common-components" import { Trans } from "@lingui/macro" import { CSFTheme } from "../../../../../Themes/types" +import { useBilling } from "../../../../../Contexts/BillingContext" +import { Product, ProductPriceRecurringInterval } from "@chainsafe/files-api-client" const useStyles = makeStyles(({ constants, palette, typography }: CSFTheme) => createStyles({ root: { margin: `${constants.generalUnit * 3}px 0px` + }, + panel: { + }, buttons: { display: "flex", @@ -36,21 +41,61 @@ interface ISelectPlan { const SelectPlan = ({ close, className, next }: ISelectPlan) => { const classes = useStyles() + const { getAvailablePlans } = useBilling() const [newPlan, setNewPlan] = useState(undefined) + const [plans, setPlans] = useState() + const [interval, setInterval] = useState("month") + + useEffect(() => { + if(!plans) { + getAvailablePlans() + .then((plans) => setPlans(plans)) + } + }) + console.log("Plans ", plans) return (
- - - Switch Plans - - +
+ + + Switch Plans + + +
+
- + { + plans && plans.map((plan) =>
+
+ + { + plan.name + } + + + { + plan.description + } + +
+
+ { + plan.prices.filter(plan => plan.recurring.interval === interval).map(price =>
+ { + price.currency + } +
) + } +
+
) + }
void currentSubscription: CurrentSubscription | undefined fetchCurrentSubscription: () => void - getAvailablePlans: () => void + getAvailablePlans: () => Promise } const ProductMapping: {[key: string]: { @@ -80,7 +80,7 @@ const BillingProvider = ({ children }: BillingContextProps) => { }, [isLoggedIn, fetchCurrentSubscription, currentSubscription]) const getAvailablePlans = useCallback(() => { - filesApiClient.getAllProducts() + return filesApiClient.getAllProducts() .then((products) => { return products.map(product => { product.name = ProductMapping[product.id].name @@ -90,8 +90,9 @@ const BillingProvider = ({ children }: BillingContextProps) => { }) .catch((error: any) => { console.error(error) + return [] }) - }, []) + }, [filesApiClient]) return ( Date: Mon, 25 Oct 2021 11:11:02 +0200 Subject: [PATCH 03/22] Toggle done --- .../src/ToggleSwitch/ToggleSwitch.tsx | 116 +++++++++++++----- .../src/stories/ToggleSwitch.stories.tsx | 39 ++++++ .../src/Overrides/ToggleSwitch.ts | 1 + 3 files changed, 126 insertions(+), 30 deletions(-) create mode 100644 packages/common-components/src/stories/ToggleSwitch.stories.tsx diff --git a/packages/common-components/src/ToggleSwitch/ToggleSwitch.tsx b/packages/common-components/src/ToggleSwitch/ToggleSwitch.tsx index ce66f98346..ae7641d31a 100644 --- a/packages/common-components/src/ToggleSwitch/ToggleSwitch.tsx +++ b/packages/common-components/src/ToggleSwitch/ToggleSwitch.tsx @@ -1,10 +1,10 @@ import { createStyles, ITheme, makeStyles } from "@chainsafe/common-theme" import clsx from "clsx" -import React, { ReactNode, useCallback, useState } from "react" +import React, { ReactNode, useCallback, useMemo, useState } from "react" import { Typography } from ".." interface IStyleProps { - size: "large" | "medium" | "small" | number | undefined + size: number } const SIZES = { @@ -13,67 +13,111 @@ const SIZES = { large: 20 } +const PADDING = 2 + const useStyles = makeStyles( - ({ breakpoints, overrides }: ITheme) => + ({ animation, breakpoints, constants, overrides, palette }: ITheme) => createStyles({ root : { + padding: `${constants.generalUnit}px`, + display: "flex", + flexDirection: "row", + justifyContent: "flex-start", + alignItems: "center", + cursor: "pointer", + "&.disabled": { + cursor: "initial" + }, [breakpoints.down("md")]: { marginBottom: 0 }, ...overrides?.Tabs?.root }, + label: { + marginRight: constants.generalUnit, + ...overrides?.ToggleSwitch?.label + }, background: ({ size }: IStyleProps) => ({ - height: size && typeof size === "number" ? size : "initial", - width: size && typeof size === "number" ? size * 2 : "initial", - "&.large": { - height: SIZES.large, - width: SIZES.large * 2 + boxSizing: "border-box", + display: "block", + position: "relative", + backgroundColor: palette.additional.gray[6], + borderRadius: size, + padding: PADDING, + height: size, + width: `calc(${size * 2}px - ${PADDING * 2}px)`, + transitionDuration: `${animation.transform}ms`, + ...overrides?.ToggleSwitch?.background + }), + dot: ({ size }: IStyleProps) => ({ + display: "block", + position: "absolute", + borderRadius: "100%", + height: `calc(${size}px - ${PADDING * 2}px)`, + width: `calc(${size}px - ${PADDING * 2}px)`, + backgroundColor: palette.additional.gray[1], + transitionDuration: `${animation.transform}ms`, + top: "50%", + transform: "translateY(-50%)", + "&.left": { + left: PADDING }, - "&.medium": { - height: SIZES.medium, - width: SIZES.medium * 2 + "&.right": { + left: "50%" }, - "&.small": { - height: SIZES.small, - width: SIZES.small * 2 - } - }), - dot: { - - } + "&.error": { + backgroundColor: palette.error.main + }, + ...overrides?.ToggleSwitch?.dot + }) }) ) interface ToggleSwitchInjectedClasses { root?: string + label?: string background?: string dot?: string } // Could allow for a slider to be made from this interface IToggleOption { - value: string | number + value: any label?: string | ReactNode | number } interface IToggleSwitch { - injectedClasses?: ToggleSwitchInjectedClasses left: IToggleOption right: IToggleOption - onChange(value: string | number): void + onChange(value: any): void + injectedClasses?: ToggleSwitchInjectedClasses size?: "large" | "medium" | "small" | number error?: string disabled?: boolean - value?: string | number - isClearable?: boolean + value?: any // name?: string } -const ToggleSwitch = ({ injectedClasses, left, right, onChange, value, size }: IToggleSwitch) => { - const classes = useStyles({ size }) +const ToggleSwitch = ({ injectedClasses, disabled, left, right, onChange, value, size, error }: IToggleSwitch) => { + const resolvedSize = useMemo(() => { + switch (size) { + case "large": + return SIZES.large + case "medium": + return SIZES.medium + case "small": + return SIZES.small + case undefined: + return SIZES.medium + default: + return size + } + }, [size]) + const classes = useStyles({ size: resolvedSize }) const [side, setSide] = useState<"left" | "right">(value && right.value === value ? "right" : "left") const onToggle = useCallback(() => { + if (disabled) return if (side === "left") { setSide("right") onChange(right.value) @@ -81,10 +125,12 @@ const ToggleSwitch = ({ injectedClasses, left, right, onChange, value, size }: I setSide("left") onChange(left.value) } - }, [left, right, side, onChange]) + }, [left, right, side, onChange, disabled]) return
{ @@ -92,6 +138,9 @@ const ToggleSwitch = ({ injectedClasses, left, right, onChange, value, size }: I { left.label } @@ -102,13 +151,20 @@ const ToggleSwitch = ({ injectedClasses, left, right, onChange, value, size }: I { right.label } ) } -
-
+
+
diff --git a/packages/common-components/src/stories/ToggleSwitch.stories.tsx b/packages/common-components/src/stories/ToggleSwitch.stories.tsx new file mode 100644 index 0000000000..9c270ec741 --- /dev/null +++ b/packages/common-components/src/stories/ToggleSwitch.stories.tsx @@ -0,0 +1,39 @@ +import { action } from "@storybook/addon-actions" +import { boolean, select } from "@storybook/addon-knobs" +import React, { useState } from "react" +import { ToggleSwitch } from ".." +import { SizeOption } from "./types" + +export default { + title: "ToggleSwitch", + component: ToggleSwitch +} + +const sizeOptions: SizeOption[] = ["large", "medium", "small"] + +const actionsData = { + onChange: action("onChange") +} + +export const ToggleSwitchDemo = (): React.ReactNode => { + const [state, setState] = useState(false) + return ( + { + setState(value) + actionsData.onChange(value) + }} + disabled={boolean("Disabled", false)} + size={select("Size", sizeOptions, "medium")} + /> + ) +} diff --git a/packages/common-theme/src/Overrides/ToggleSwitch.ts b/packages/common-theme/src/Overrides/ToggleSwitch.ts index ae39a6ac0f..7a76099eb8 100644 --- a/packages/common-theme/src/Overrides/ToggleSwitch.ts +++ b/packages/common-theme/src/Overrides/ToggleSwitch.ts @@ -1,5 +1,6 @@ export interface IToggleSwitch { root?: Record + label?: Record background?: Record dot?: Record } From 3ead3f1e02bc38c0479a368319cdcfcb5f1863f7 Mon Sep 17 00:00:00 2001 From: ryry79261 Date: Mon, 25 Oct 2021 12:46:07 +0200 Subject: [PATCH 04/22] View done --- .../src/ToggleSwitch/ToggleSwitch.tsx | 2 +- .../Settings/Products/ChangeProductModal.tsx | 19 +- .../ChangeProductViews/SelectPlan.tsx | 187 +++++++++++++++--- .../files-ui/src/Contexts/BillingContext.tsx | 12 ++ packages/files-ui/src/Themes/Constants.ts | 4 + packages/files-ui/src/Themes/DarkTheme.ts | 4 + packages/files-ui/src/Themes/LightTheme.ts | 4 + 7 files changed, 198 insertions(+), 34 deletions(-) diff --git a/packages/common-components/src/ToggleSwitch/ToggleSwitch.tsx b/packages/common-components/src/ToggleSwitch/ToggleSwitch.tsx index ae7641d31a..cde436933d 100644 --- a/packages/common-components/src/ToggleSwitch/ToggleSwitch.tsx +++ b/packages/common-components/src/ToggleSwitch/ToggleSwitch.tsx @@ -19,7 +19,7 @@ const useStyles = makeStyles( ({ animation, breakpoints, constants, overrides, palette }: ITheme) => createStyles({ root : { - padding: `${constants.generalUnit}px`, + padding: `${constants.generalUnit}px 0`, display: "flex", flexDirection: "row", justifyContent: "flex-start", diff --git a/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductModal.tsx b/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductModal.tsx index 54e6ddcd0a..88a216f663 100644 --- a/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductModal.tsx +++ b/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductModal.tsx @@ -4,11 +4,15 @@ import { CSFTheme } from "../../../../Themes/types" import clsx from "clsx" import { Modal } from "@chainsafe/common-components" import SelectPlan from "./ChangeProductViews/SelectPlan" +import { useBilling } from "../../../../Contexts/BillingContext" -const useStyles = makeStyles(({ constants, palette, typography }: CSFTheme) => +const useStyles = makeStyles(({ constants }: CSFTheme) => createStyles({ root: { }, + inner: { + borderRadius: `${constants.generalUnit / 2}px` + }, slide: { borderRadius: constants.generalUnit / 2, padding: `0 ${constants.generalUnit * 3}px` @@ -25,7 +29,7 @@ interface IChangeProductModal { const ChangeProductModal = ({ active, className, close }: IChangeProductModal) => { const classes = useStyles() - const [newPlan, setNewPlan] = useState() + const { changeSubscription } = useBilling() const [slide, setSlide] = useState<"select" | "confirm">("select") @@ -39,15 +43,20 @@ const ChangeProductModal = ({ active, className, close }: IChangeProductModal) = { slide === "select" && { - setNewPlan(id) - setSlide("confirm") + next={(productId: string, priceId: string) => { + // setSlide("confirm") + changeSubscription(productId, priceId) }} /> } diff --git a/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx b/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx index ac1915e74b..1757d0bd4e 100644 --- a/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx +++ b/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx @@ -1,19 +1,84 @@ -import React, { useEffect, useState } from "react" +import React, { useEffect, useMemo, useState } from "react" import { makeStyles, createStyles } from "@chainsafe/common-theme" import clsx from "clsx" -import { Button, Typography } from "@chainsafe/common-components" -import { Trans } from "@lingui/macro" +import { Button, Loading, ToggleSwitch, Typography } from "@chainsafe/common-components" +import { t, Trans } from "@lingui/macro" import { CSFTheme } from "../../../../../Themes/types" import { useBilling } from "../../../../../Contexts/BillingContext" import { Product, ProductPriceRecurringInterval } from "@chainsafe/files-api-client" -const useStyles = makeStyles(({ constants, palette, typography }: CSFTheme) => +const useStyles = makeStyles(({ breakpoints, constants, palette, typography }: CSFTheme) => createStyles({ root: { - margin: `${constants.generalUnit * 3}px 0px` + margin: `${constants.generalUnit * 2}px 0px` + }, + header: { + display: "flex", + flexDirection: "row", + alignItems: "center", + justifyContent: "space-between" + }, + label: { + ...typography.h5 + }, + panels: { + display: "flex", + flexDirection: "row", + flexWrap: "wrap", + justifyContent: "space-between", + margin: `${constants.generalUnit * 3.5}px 0` }, panel: { - + display: "flex", + flexDirection: "column", + padding: `${constants.generalUnit}px ${constants.generalUnit * 3}px`, + width: `calc(33.3333% - ${constants.generalUnit * 2}px)`, + minHeight: 200, + cursor: "pointer", + border: `3px solid ${palette.additional.gray[4]}`, + borderRadius: constants.generalUnit, + marginBottom: constants.generalUnit, + "&.disabled": { + cursor: "initial", + opacity: 0.4 + }, + "&.active": { + opacity: "1 !important", + backgroundColor: constants.changeProduct.currentBackground, + borderColor: constants.changeProduct.selectedColor + }, + [breakpoints.down("sm")]: { + width: `calc(50% - ${constants.generalUnit}px)` + } + }, + loader: { + margin: "0 auto" + }, + panelTop: { + height: "60%", + "& > header": { + display: "flex", + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + marginBottom: constants.generalUnit + } + }, + tag: { + display: "block", + padding: `0 ${constants.generalUnit}px`, + borderRadius: `${constants.generalUnit * 2}px`, + height: 20, + "&.current": { + backgroundColor: palette.primary.main, + color: palette.additional.gray[10] + }, + "&.popular": { + backgroundColor: palette.additional.gold[5] + } + }, + panelBottom: { + height: "40%" }, buttons: { display: "flex", @@ -36,14 +101,13 @@ const useStyles = makeStyles(({ constants, palette, typography }: CSFTheme) => interface ISelectPlan { className?: string close: () => void - next: (id: string) => void + next: (productId: string, priceId: string) => void } const SelectPlan = ({ close, className, next }: ISelectPlan) => { const classes = useStyles() - const { getAvailablePlans } = useBilling() - - const [newPlan, setNewPlan] = useState(undefined) + const { getAvailablePlans, currentSubscription } = useBilling() + const [selectedPlan, setSelectedPlan] = useState(currentSubscription?.product.id) const [plans, setPlans] = useState() const [interval, setInterval] = useState("month") @@ -53,11 +117,23 @@ const SelectPlan = ({ close, className, next }: ISelectPlan) => { .then((plans) => setPlans(plans)) } }) - console.log("Plans ", plans) + + const translatedPrice = useMemo(() => { + switch (interval) { + case "day": + return t`per day` + case "week": + return t`per week` + case "month": + return t`per month` + case "year": + return t`per year` + } + }, [interval]) return (
-
+
{ Switch Plans -
+
+ setInterval(value)} + size="medium" + /> +
-
+
+ { + !plans && + } { plans && plans.map((plan) =>
price.recurring.interval === interval) + .find(price => price.is_update_allowed)?.is_update_allowed) + })} + onClick={() => { + if(plan.prices + .filter(price => price.recurring.interval === interval) + .find(price => price.is_update_allowed)?.is_update_allowed) { + setSelectedPlan(plan.id) + } + } } key={`plan-${plan.id}`}> -
- +
+
+ + { + plan.name + } + { - plan.name + plan.id === currentSubscription?.product.id && + + Current + + } - - +
+ { plan.description }
-
+
{ - plan.prices.filter(plan => plan.recurring.interval === interval).map(price =>
- { - price.currency - } -
) + plan.prices + .filter(price => price.recurring.interval === interval) + .map(price => + { + price.unit_amount === 0 ? t`Free` : <>{ price.unit_amount } { price.currency } { translatedPrice } + } + ) }
) @@ -116,8 +245,10 @@ const SelectPlan = ({ close, className, next }: ISelectPlan) => {
- - Not sure what to pick? Learn more about our plans - + + + Not sure what to pick? Learn more about our plans + + +
setChangeProductActive(false)} + active={isChangeProductModalVisible} + close={() => setChangeProductModalVisible(false)} /> } diff --git a/packages/files-ui/src/Themes/Constants.ts b/packages/files-ui/src/Themes/Constants.ts index 7b787e785f..5ca6a1e648 100644 --- a/packages/files-ui/src/Themes/Constants.ts +++ b/packages/files-ui/src/Themes/Constants.ts @@ -179,5 +179,8 @@ export interface CsfColors extends IConstants { changeProduct: { currentBackground: string selectedColor: string + currentTag: { + text: string + } } } \ No newline at end of file diff --git a/packages/files-ui/src/Themes/DarkTheme.ts b/packages/files-ui/src/Themes/DarkTheme.ts index 10b58354da..e395bd835d 100644 --- a/packages/files-ui/src/Themes/DarkTheme.ts +++ b/packages/files-ui/src/Themes/DarkTheme.ts @@ -490,7 +490,10 @@ export const darkTheme = createTheme({ }, changeProduct: { currentBackground: "initial", - selectedColor: "var(--csf-primary)" + selectedColor: "var(--csf-primary)", + currentTag: { + text: "var(--gray10)" + } } } as CsfColors) }, diff --git a/packages/files-ui/src/Themes/LightTheme.ts b/packages/files-ui/src/Themes/LightTheme.ts index 4783d9d89e..24c30df245 100644 --- a/packages/files-ui/src/Themes/LightTheme.ts +++ b/packages/files-ui/src/Themes/LightTheme.ts @@ -177,7 +177,10 @@ export const lightTheme = createTheme({ }, changeProduct: { currentBackground: "#ECEFFF", - selectedColor: "var(--csf-primary)" + selectedColor: "var(--csf-primary)", + currentTag: { + text: "var(--gray1)" + } } } as CsfColors) }, From 35b43da0f5267aff5cc158eac3181fb5d897ae9a Mon Sep 17 00:00:00 2001 From: ryry79261 Date: Wed, 27 Oct 2021 13:23:31 +0200 Subject: [PATCH 13/22] Changed display logic --- .../Modules/Settings/Products/ChangeProductModal.tsx | 9 ++++----- .../Modules/Settings/SubscriptionTab/CurrentProduct.tsx | 9 +++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductModal.tsx b/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductModal.tsx index e2ba15698f..5aa0e19c10 100644 --- a/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductModal.tsx +++ b/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductModal.tsx @@ -21,12 +21,11 @@ const useStyles = makeStyles(({ constants }: CSFTheme) => ) interface IChangeProductModal { - active: boolean className?: string close: () => void } -const ChangeProductModal = ({ active, className, close }: IChangeProductModal) => { +const ChangeProductModal = ({ className, close }: IChangeProductModal) => { const classes = useStyles() const { changeSubscription } = useBilling() @@ -34,15 +33,15 @@ const ChangeProductModal = ({ active, className, close }: IChangeProductModal) = const [slide, setSlide] = useState<"select" | "confirm">("select") useEffect(() => { - if (!active && slide !== "select") { + if (slide !== "select") { setSlide("select") } - }, [active, slide]) + }, [slide]) return ( { Change Plan - setChangeProductModalVisible(false)} - /> + { + isChangeProductModalVisible && ( setChangeProductModalVisible(false)} + />) + } } From 09a6d179f24e2d0e937163c0bcac72a35f83bff7 Mon Sep 17 00:00:00 2001 From: Ryan Noble Date: Wed, 27 Oct 2021 13:24:41 +0200 Subject: [PATCH 14/22] Apply suggestions from code review Co-authored-by: Thibaut Sardan <33178835+Tbaut@users.noreply.github.com> --- .../Settings/Products/ChangeProductViews/SelectPlan.tsx | 8 ++++---- packages/files-ui/src/Contexts/BillingContext.tsx | 4 +--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx b/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx index a5b5ded0b0..cbd62c99ec 100644 --- a/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx +++ b/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx @@ -122,6 +122,7 @@ const SelectPlan = ({ close, className, next }: ISelectPlan) => { if(!plans) { getAvailablePlans() .then((plans) => setPlans(plans)) + .catch(console.error) } }) @@ -187,10 +188,9 @@ const SelectPlan = ({ close, className, next }: ISelectPlan) => {
- { - plan.name - } + variant="h5" + > + {plan.name} { plan.id === currentSubscription?.product.id && { price_id: priceId }) .then(() => true) - .catch((error: any) => { - console.error(error) - }) + .catch(console.error) }, [filesApiClient]) return ( From 5217224faa8f95ab1212bd8e24287c9252cc9ff3 Mon Sep 17 00:00:00 2001 From: ryry79261 Date: Wed, 27 Oct 2021 13:34:00 +0200 Subject: [PATCH 15/22] Fixed change subscription --- .../Modules/Settings/Products/ChangeProductModal.tsx | 4 ++-- .../Products/ChangeProductViews/SelectPlan.tsx | 3 +-- packages/files-ui/src/Contexts/BillingContext.tsx | 11 ++++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductModal.tsx b/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductModal.tsx index 5aa0e19c10..63ff757933 100644 --- a/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductModal.tsx +++ b/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductModal.tsx @@ -53,9 +53,9 @@ const ChangeProductModal = ({ className, close }: IChangeProductModal) => { slide === "select" && { + next={(newpriceId: string) => { // setSlide("confirm") - changeSubscription(productId, priceId) + changeSubscription(newpriceId) .then(() => close()) .catch(console.error) }} diff --git a/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx b/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx index a5b5ded0b0..0b781b1997 100644 --- a/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx +++ b/packages/files-ui/src/Components/Modules/Settings/Products/ChangeProductViews/SelectPlan.tsx @@ -108,7 +108,7 @@ const useStyles = makeStyles(({ breakpoints, constants, palette, typography }: C interface ISelectPlan { className?: string close: () => void - next: (productId: string, priceId: string) => void + next: (newPriceId: string) => void } const SelectPlan = ({ close, className, next }: ISelectPlan) => { @@ -256,7 +256,6 @@ const SelectPlan = ({ close, className, next }: ISelectPlan) => {
- { - !plans && - } - { - plans && plans.map((plan) =>
} + {plans && plans.map((plan) => ( +
setSelectedPlan(plan.id) } - key={`plan-${plan.id}`}> + key={`plan-${plan.id}`} + >
{ > {plan.name} - { - plan.id === currentSubscription?.product.id && + className={clsx(classes.tag, "current")} + > Current - } + )}
{
- { - plan.prices - .filter(price => price.recurring.interval === interval) - .map(price => price.recurring.interval === interval) + .map(price => ( + - { - price.unit_amount === 0 ? t`Free` : `${price.unit_amount} ${price.currency} ${translatedPrice}` - } - ) - } + key={`${plan.id}-${price.id}`} + > + {price.unit_amount === 0 ? t`Free` : `${price.unit_amount} ${price.currency} ${translatedPrice}`} + + ))}
-
) +
+ )) }
@@ -237,7 +235,8 @@ const SelectPlan = ({ close, className, next }: ISelectPlan) => { > + variant="h5" + > Not sure what to pick? Learn more about our plans @@ -255,8 +254,7 @@ const SelectPlan = ({ close, className, next }: ISelectPlan) => {