From e7f640c7bcfca899de3ba85c272ef0b019b6a536 Mon Sep 17 00:00:00 2001 From: Kaspar Kallas Date: Thu, 24 Aug 2023 12:50:35 +0000 Subject: [PATCH 01/20] separate product and payment tabs --- .../payment-editor/PaymentEditor.tsx | 92 +++++++++++++++++++ .../product-editor/ProductEditor.tsx | 78 +++------------- .../src/components/ui-editor/UiEditor.tsx | 13 --- apps/widget-builder/src/pages/builder.tsx | 84 +++++++++++------ 4 files changed, 161 insertions(+), 106 deletions(-) create mode 100644 apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx diff --git a/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx b/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx new file mode 100644 index 00000000..bda93d9b --- /dev/null +++ b/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx @@ -0,0 +1,92 @@ +import { Divider, Stack, Typography } from "@mui/material"; +import { FC } from "react"; +import { Controller, useFieldArray, useFormContext } from "react-hook-form"; + +import theme from "../../theme"; +import PaymentOptionView from "../payment-option-view/PaymentOptionView"; +import SelectPaymentOption from "../select-payment-option/SelectPaymentOption"; +import { WidgetProps } from "../widget-preview/WidgetPreview"; + +const ProductEditor: FC = () => { + const { control, watch } = useFormContext(); + + const { fields, append, remove } = useFieldArray({ + control, + name: "paymentDetails.paymentOptions", // unique name for your Field Array + }); + + const [paymentOptions] = watch(["paymentDetails.paymentOptions"]); + + return ( + + + Add Payment Options + } + /> + + + + + + Payment Details Summary + + Added: {paymentOptions.length} + + + + + {paymentOptions.length ? ( + paymentOptions.map( + ( + { + superToken, + chainId, + transferAmountEther, + flowRate, + receiverAddress, + }, + i, + ) => ( + + ), + ) + ) : ( + + - None + + )} + + + + + ); +}; + +export default ProductEditor; diff --git a/apps/widget-builder/src/components/product-editor/ProductEditor.tsx b/apps/widget-builder/src/components/product-editor/ProductEditor.tsx index b3d0b138..0451fa5a 100644 --- a/apps/widget-builder/src/components/product-editor/ProductEditor.tsx +++ b/apps/widget-builder/src/components/product-editor/ProductEditor.tsx @@ -1,11 +1,9 @@ -import { Divider, Stack, TextField, Typography } from "@mui/material"; +import { Stack, TextField, Typography } from "@mui/material"; import { FC } from "react"; import { Controller, useFieldArray, useFormContext } from "react-hook-form"; -import theme from "../../theme"; import InputWrapper from "../form/InputWrapper"; -import PaymentOptionView from "../payment-option-view/PaymentOptionView"; -import SelectPaymentOption from "../select-payment-option/SelectPaymentOption"; +import ImageSelect from "../image-select/ImageSelect"; import { WidgetProps } from "../widget-preview/WidgetPreview"; const ProductEditor: FC = () => { @@ -60,73 +58,19 @@ const ProductEditor: FC = () => { )} /> - - - Add Payment Options } + name="productDetails.imageURI" + render={({ field: { value, onChange } }) => ( + onChange(URL.createObjectURL(file))} + onRemove={() => onChange("")} + imageSrc={value} + /> + )} /> - - - - - - Payment Details Summary - - Added: {paymentOptions.length} - - - - - {paymentOptions.length ? ( - paymentOptions.map( - ( - { - superToken, - chainId, - transferAmountEther, - flowRate, - receiverAddress, - }, - i, - ) => ( - - ), - ) - ) : ( - - - None - - )} - - ); diff --git a/apps/widget-builder/src/components/ui-editor/UiEditor.tsx b/apps/widget-builder/src/components/ui-editor/UiEditor.tsx index d25311e3..2d32423f 100644 --- a/apps/widget-builder/src/components/ui-editor/UiEditor.tsx +++ b/apps/widget-builder/src/components/ui-editor/UiEditor.tsx @@ -15,7 +15,6 @@ import { Controller, useFormContext } from "react-hook-form"; import useFontOptions from "../../hooks/useFontOptions"; import InputWrapper from "../form/InputWrapper"; -import ImageSelect from "../image-select/ImageSelect"; import { WidgetProps } from "../widget-preview/WidgetPreview"; const UiEditor: FC = () => { @@ -27,18 +26,6 @@ const UiEditor: FC = () => { return ( - ( - onChange(URL.createObjectURL(file))} - onRemove={() => onChange("")} - imageSrc={value} - /> - )} - /> {/* - - - Widget Builder - - } - label={Demo} - /> - - - setActiveTab(value)} sx={{ px: 2 }}> - - - - + + + + Widget Builder + + + } + label="Demo Mode" + /> + + + setActiveTab(value)} + sx={{ px: 2 }} + > + + + + + + + @@ -104,6 +133,9 @@ export default function Builder() { + + + From fa41ce5f6d9c29977bbcdc77a4b2658b5ac67526 Mon Sep 17 00:00:00 2001 From: Kaspar Kallas Date: Thu, 24 Aug 2023 14:02:08 +0000 Subject: [PATCH 02/20] reduce tab font size --- .../src/components/payment-editor/PaymentEditor.tsx | 2 +- apps/widget-builder/src/pages/builder.tsx | 2 -- apps/widget-builder/src/theme.ts | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx b/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx index bda93d9b..46def4ed 100644 --- a/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx +++ b/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx @@ -27,7 +27,7 @@ const ProductEditor: FC = () => { render={() => } /> - + @@ -104,7 +103,6 @@ export default function Builder() { setActiveTab(value)} - sx={{ px: 2 }} > Date: Thu, 24 Aug 2023 14:04:05 +0000 Subject: [PATCH 03/20] make app bar sticky --- apps/widget-builder/src/pages/builder.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/widget-builder/src/pages/builder.tsx b/apps/widget-builder/src/pages/builder.tsx index be931303..3f8b4f8a 100644 --- a/apps/widget-builder/src/pages/builder.tsx +++ b/apps/widget-builder/src/pages/builder.tsx @@ -73,7 +73,7 @@ export default function Builder() { }} > - + Date: Sun, 27 Aug 2023 20:25:55 +0000 Subject: [PATCH 04/20] add bottom navigation --- apps/widget-builder/src/pages/builder.tsx | 107 ++++++++++++++-------- 1 file changed, 71 insertions(+), 36 deletions(-) diff --git a/apps/widget-builder/src/pages/builder.tsx b/apps/widget-builder/src/pages/builder.tsx index 3f8b4f8a..cae70b45 100644 --- a/apps/widget-builder/src/pages/builder.tsx +++ b/apps/widget-builder/src/pages/builder.tsx @@ -1,5 +1,7 @@ import CodeIcon from "@mui/icons-material/Code"; import FullscreenIcon from "@mui/icons-material/Fullscreen"; +import KeyboardArrowLeft from "@mui/icons-material/KeyboardArrowLeft"; +import KeyboardArrowRight from "@mui/icons-material/KeyboardArrowRight"; import ViewSidebarIcon from "@mui/icons-material/ViewSidebar"; import WebIcon from "@mui/icons-material/Web"; import WebAssetIcon from "@mui/icons-material/WebAsset"; @@ -10,6 +12,8 @@ import { Button, Drawer, FormControlLabel, + MobileStepper, + Paper, Stack, Switch, Tab, @@ -37,9 +41,15 @@ const drawerWidth = "480px"; export default function Builder() { const theme = useTheme(); - const [activeTab, setActiveTab] = useState<"ui" | "product" | "export">( - "product", - ); + + const [activeStep, setActiveStep] = useState(0); + const maxSteps = 4; + const handleNext = () => { + setActiveStep((prevActiveStep) => prevActiveStep + 1); + }; + const handleBack = () => { + setActiveStep((prevActiveStep) => prevActiveStep - 1); + }; const { widgetProps, demoMode, toggleDemoMode } = useDemoMode(); @@ -72,8 +82,8 @@ export default function Builder() { }, }} > - - + + setActiveTab(value)} + onChange={(_, value) => setActiveStep(Number(value))} > - - - - + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + Next + + + } + backButton={ + + } + /> + Date: Tue, 29 Aug 2023 07:31:43 +0000 Subject: [PATCH 05/20] make navigating with back & next more robust --- apps/widget-builder/src/pages/builder.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/widget-builder/src/pages/builder.tsx b/apps/widget-builder/src/pages/builder.tsx index cae70b45..80b83ad8 100644 --- a/apps/widget-builder/src/pages/builder.tsx +++ b/apps/widget-builder/src/pages/builder.tsx @@ -43,12 +43,14 @@ export default function Builder() { const theme = useTheme(); const [activeStep, setActiveStep] = useState(0); - const maxSteps = 4; + const stepCount = 4; const handleNext = () => { - setActiveStep((prevActiveStep) => prevActiveStep + 1); + setActiveStep((prevActiveStep) => + Math.min(prevActiveStep + 1, stepCount - 1), + ); }; const handleBack = () => { - setActiveStep((prevActiveStep) => prevActiveStep - 1); + setActiveStep((prevActiveStep) => Math.max(prevActiveStep - 1, 0)); }; const { widgetProps, demoMode, toggleDemoMode } = useDemoMode(); @@ -148,14 +150,14 @@ export default function Builder() { bgcolor: "background.paper", }} variant="text" - steps={4} + steps={stepCount} position="static" activeStep={activeStep} nextButton={ } backButton={ } From 2e3da79960770af52b8d108e9c9b2c6b0b3fe638 Mon Sep 17 00:00:00 2001 From: Kaspar Kallas Date: Tue, 29 Aug 2023 09:29:17 +0000 Subject: [PATCH 08/20] clean form when adding payment --- .../payment-editor/PaymentEditor.tsx | 84 +++++--- .../SelectPaymentOption.tsx | 204 +++++++++--------- 2 files changed, 161 insertions(+), 127 deletions(-) diff --git a/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx b/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx index e9747962..a608e7cb 100644 --- a/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx +++ b/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx @@ -1,5 +1,5 @@ -import { Divider, Stack, Typography } from "@mui/material"; -import { FC } from "react"; +import { Box,Divider, Stack, Typography, Zoom } from "@mui/material"; +import { FC, useState } from "react"; import { Controller, useFieldArray, useFormContext } from "react-hook-form"; import theme from "../../theme"; @@ -17,6 +17,8 @@ const ProductEditor: FC = () => { const [paymentOptions] = watch(["paymentDetails.paymentOptions"]); + const [addCount, setAddCount] = useState(0); + return ( @@ -24,9 +26,17 @@ const ProductEditor: FC = () => { Add Payment Option } + render={() => ( + { + setAddCount((x) => x + 1); + append(params); + }} + /> + )} /> @@ -53,34 +63,46 @@ const ProductEditor: FC = () => { {paymentOptions.length ? ( - paymentOptions.map( - ( - { - superToken, - chainId, - transferAmountEther, - flowRate, - receiverAddress, - }, - i, - ) => ( - - ), - ) + paymentOptions + .map( + ( + { + superToken, + chainId, + transferAmountEther, + flowRate, + receiverAddress, + }, + i, + ) => ( + + + { + remove(params); + setAddCount(0); + }} + /> + + + ), + ) + .reverse() ) : ( - None diff --git a/apps/widget-builder/src/components/select-payment-option/SelectPaymentOption.tsx b/apps/widget-builder/src/components/select-payment-option/SelectPaymentOption.tsx index 4fb859f6..815254b9 100644 --- a/apps/widget-builder/src/components/select-payment-option/SelectPaymentOption.tsx +++ b/apps/widget-builder/src/components/select-payment-option/SelectPaymentOption.tsx @@ -2,7 +2,6 @@ import { Autocomplete, Avatar, Button, - Chip, Collapse, FormControlLabel, FormGroup, @@ -10,6 +9,7 @@ import { ListItem, ListItemAvatar, ListItemText, + ListSubheader, MenuItem, Select, SelectChangeEvent, @@ -150,8 +150,15 @@ const SelectPaymentOption: FC = ({ onAdd }) => { const [upfrontPaymentAmount, setUpfrontPaymentAmount] = useState< `${number}` | "" >(""); - const onShowUpfrontPaymentChanged = (_e: ChangeEvent, checked: boolean) => - setShowUpfrontPayment(checked); + const onShowUpfrontPaymentChanged = (_e: ChangeEvent, checked: boolean) => { + if (checked) { + setShowUpfrontPayment(true); + setUpfrontPaymentAmount(flowRateAmount); + } else { + setShowUpfrontPayment(false); + setUpfrontPaymentAmount(""); + } + }; return ( @@ -179,24 +186,45 @@ const SelectPaymentOption: FC = ({ onAdd }) => { )} - - - {(id) => ( - + Mainnets + {filteredNetworks + .filter((x) => !x.testnet) + .map((network) => ( + + + + {network.name} + + + ))} + Testnets + {filteredNetworks + .filter((x) => x.testnet) + .map((network) => ( = ({ onAdd }) => { sx={{ alignItems: "center", width: "100%" }} > - - {network.name} - {network.testnet && ( - - )} - + {network.name} ))} - - )} - + + )} + - - {(id) => ( - setSelectedToken(value!)} - id={id} - options={autoCompleteTokenOptions} - getOptionLabel={(token) => token.symbol} - componentsProps={{ - popper: { - placement: "bottom-end", - }, - }} - renderOption={(props, option) => ( - - - {option.logoURI && ( - - )} - - - - )} - renderInput={(params) => ( - - ), - }} + + {(id) => ( + setSelectedToken(value!)} + id={id} + options={autoCompleteTokenOptions} + getOptionLabel={(token) => token.symbol} + componentsProps={{ + popper: { + placement: "bottom-end", + }, + }} + renderOption={(props, option) => ( + + + {option.logoURI && ( + + )} + + - )} - /> - )} - - + + )} + renderInput={(params) => ( + + ), + }} + /> + )} + /> + )} + From 24748169778beb9553ad72d47dc578b8755790cb Mon Sep 17 00:00:00 2001 From: Kaspar Kallas Date: Tue, 29 Aug 2023 21:54:18 +0000 Subject: [PATCH 09/20] move toggle buttons under UI tab & change demo mode behaviour --- .../config-editor/ConfigEditorDrawer.tsx | 1 + .../payment-editor/PaymentEditor.tsx | 30 ++++++- .../product-editor/ProductEditor.tsx | 28 +++++- .../SelectPaymentOption.tsx | 8 -- .../src/components/ui-editor/UiEditor.tsx | 56 +++++++++--- .../widget-preview/WidgetPreview.tsx | 13 ++- apps/widget-builder/src/hooks/useDemoMode.ts | 55 +++++------- apps/widget-builder/src/pages/builder.tsx | 90 +++---------------- 8 files changed, 137 insertions(+), 144 deletions(-) diff --git a/apps/widget-builder/src/components/config-editor/ConfigEditorDrawer.tsx b/apps/widget-builder/src/components/config-editor/ConfigEditorDrawer.tsx index 70cdccb0..1ed52760 100644 --- a/apps/widget-builder/src/components/config-editor/ConfigEditorDrawer.tsx +++ b/apps/widget-builder/src/components/config-editor/ConfigEditorDrawer.tsx @@ -19,6 +19,7 @@ export const ConfigEditorDrawer: FC = ({ setValue, }) => ( setIsOpen(false)} keepMounted={true} diff --git a/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx b/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx index a608e7cb..22bf6db8 100644 --- a/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx +++ b/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx @@ -1,7 +1,17 @@ -import { Box,Divider, Stack, Typography, Zoom } from "@mui/material"; +import AutoFixHighIcon from "@mui/icons-material/AutoFixHigh"; +import { + Box, + Divider, + IconButton, + Stack, + Tooltip, + Typography, + Zoom, +} from "@mui/material"; import { FC, useState } from "react"; import { Controller, useFieldArray, useFormContext } from "react-hook-form"; +import useDemoMode from "../../hooks/useDemoMode"; import theme from "../../theme"; import PaymentOptionView from "../payment-option-view/PaymentOptionView"; import SelectPaymentOption from "../select-payment-option/SelectPaymentOption"; @@ -18,13 +28,25 @@ const ProductEditor: FC = () => { const [paymentOptions] = watch(["paymentDetails.paymentOptions"]); const [addCount, setAddCount] = useState(0); + const { setDemoPaymentDetails } = useDemoMode(); return ( - - Add Payment Option - + + + Add Payment Option + + + + + + + { }); const [paymentOptions] = watch(["paymentDetails.paymentOptions"]); + const { setDemoProductDetails } = useDemoMode(); return ( - - Edit Product Details - + + + Edit Product Details + + + + + + + = ({ onAdd }) => { {(id) => ( + Mainnets + {filteredNetworks + .filter((x) => !x.testnet) + .map((network) => ( + + + + {network.name} + + + ))} + Testnets + {filteredNetworks + .filter((x) => x.testnet) + .map((network) => ( + + + + {network.name} + + + ))} + + )} + - - {(id) => ( - - )} - - - - {(id) => ( - setSelectedToken(value!)} - id={id} - options={autoCompleteTokenOptions} - getOptionLabel={(token) => token.symbol} - componentsProps={{ - popper: { - placement: "bottom-end", - }, - }} - renderOption={(props, option) => ( - - - {option.logoURI && ( - - )} - - - - )} - renderInput={(params) => ( + {(id) => ( - ), + id={id} + data-testid="receiver-input-field" + value={receiver} + onChange={({ target }) => + setReceiver(target.value as `0x${string}`) + } + /> + )} + + + + {(id) => ( + setSelectedToken(value!)} + id={id} + options={autoCompleteTokenOptions} + getOptionLabel={(token) => token.symbol} + componentsProps={{ + popper: { + placement: "bottom-end", + }, }} + renderOption={(props, option) => ( + + + {option.logoURI && ( + + )} + + + + )} + renderInput={(params) => ( + + ), + }} + /> + )} /> )} - /> - )} - + - - {(id) => ( - - - setFlowRateAmount(target.value as `${number}`) - } - InputProps={{ - sx: { - borderTopRightRadius: 0, - borderBottomRightRadius: 0, - }, - endAdornment: ( - - {selectedToken?.symbol} - - ), - }} - /> - - + User-defined rate + Fixed rate + )} - - - - } - label="Charge upfront payment amount" - /> - - - - - + + {(id) => ( - - setUpfrontPaymentAmount(target.value as `${number}`) - } - InputProps={{ - endAdornment: ( - - {selectedToken?.symbol} - - ), - }} - /> + + + setFlowRateAmount(target.value as `${number}`) + } + InputProps={{ + sx: { + borderTopRightRadius: 0, + borderBottomRightRadius: 0, + }, + endAdornment: ( + + {selectedToken?.symbol} + + ), + }} + /> + + )} - + + + + } + label="Charge upfront payment amount" + /> + + + + + + + + {(id) => ( + + setUpfrontPaymentAmount(target.value as `${number}`) + } + InputProps={{ + endAdornment: ( + + {selectedToken?.symbol} + + ), + }} + /> + )} + + + + - - - - {(id) => ( - - setReceiver(target.value as `0x${string}`) - } - /> - )} - - - - + + + + + + + + ); }; diff --git a/apps/widget-builder/src/components/widget-preview/WidgetPreview.tsx b/apps/widget-builder/src/components/widget-preview/WidgetPreview.tsx index 104e7a71..d39bb3a2 100644 --- a/apps/widget-builder/src/components/widget-preview/WidgetPreview.tsx +++ b/apps/widget-builder/src/components/widget-preview/WidgetPreview.tsx @@ -1,9 +1,4 @@ -import { - colors, - Fab, - SelectChangeEvent, - ThemeOptions, -} from "@mui/material"; +import { colors, Fab, SelectChangeEvent, ThemeOptions } from "@mui/material"; import SuperfluidWidget, { PaymentDetails, ProductDetails, From 363570af06de302dfa7257fc4a6d98b3305904ac Mon Sep 17 00:00:00 2001 From: Kaspar Kallas Date: Wed, 30 Aug 2023 10:38:33 +0000 Subject: [PATCH 11/20] mark optional input & rename UI tab --- .../src/components/form/InputWrapper.tsx | 13 +++++++++++++ .../src/components/product-editor/ProductEditor.tsx | 4 ++-- apps/widget-builder/src/pages/builder.tsx | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/widget-builder/src/components/form/InputWrapper.tsx b/apps/widget-builder/src/components/form/InputWrapper.tsx index 8a442066..61f8f772 100644 --- a/apps/widget-builder/src/components/form/InputWrapper.tsx +++ b/apps/widget-builder/src/components/form/InputWrapper.tsx @@ -6,6 +6,7 @@ import { Stack, SxProps, Tooltip, + Typography, useTheme, } from "@mui/material"; import { FC, PropsWithChildren, useId } from "react"; @@ -30,6 +31,7 @@ interface InputWrapperProps { tooltip?: string; sx?: SxProps; helperText?: string; + optional?: boolean; children: (inputId: string) => PropsWithChildren["children"]; } @@ -39,6 +41,7 @@ const InputWrapper: FC = ({ sx = {}, helperText, children, + optional, ...props }) => { const generatedId = useId(); @@ -50,6 +53,16 @@ const InputWrapper: FC = ({ {!!title && ( {title} + {!!optional && ( + + (optional) + + )} )} {!!tooltip && } diff --git a/apps/widget-builder/src/components/product-editor/ProductEditor.tsx b/apps/widget-builder/src/components/product-editor/ProductEditor.tsx index fa1c0841..f371be3f 100644 --- a/apps/widget-builder/src/components/product-editor/ProductEditor.tsx +++ b/apps/widget-builder/src/components/product-editor/ProductEditor.tsx @@ -46,7 +46,7 @@ const ProductEditor: FC = () => { control={control} name="productDetails.name" render={({ field: { value, onChange } }) => ( - + {(id) => ( { control={control} name="productDetails.description" render={({ field: { value, onChange } }) => ( - + {(id) => ( - + From e52c910cab135b3c14eb3781cd26086bb503626f Mon Sep 17 00:00:00 2001 From: Kaspar Kallas Date: Wed, 30 Aug 2023 11:31:17 +0000 Subject: [PATCH 12/20] change magic wand and add payment option btn positioning --- .../payment-editor/PaymentEditor.tsx | 213 ++++++++++-------- .../product-editor/ProductEditor.tsx | 147 ++++++------ 2 files changed, 195 insertions(+), 165 deletions(-) diff --git a/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx b/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx index 9ecf8657..90b72dc1 100644 --- a/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx +++ b/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx @@ -4,9 +4,12 @@ import CloseIcon from "@mui/icons-material/Close"; import { AppBar, Box, + Button, Dialog, Fab, IconButton, + Slide, + SlideProps, Stack, Toolbar, Tooltip, @@ -17,7 +20,6 @@ import { FC, useState } from "react"; import { Controller, useFieldArray, useFormContext } from "react-hook-form"; import useDemoMode from "../../hooks/useDemoMode"; -import theme from "../../theme"; import PaymentOptionView from "../payment-option-view/PaymentOptionView"; import SelectPaymentOption from "../select-payment-option/SelectPaymentOption"; import { WidgetProps } from "../widget-preview/WidgetPreview"; @@ -46,113 +48,104 @@ const ProductEditor: FC = () => { const { setDemoPaymentDetails } = useDemoMode(); return ( - - - - - - - - - + <> + + Edit Payment Details - - { - setAddCount((x) => x + 1); - setDemoPaymentDetails(); + + - - - - + + Payment Options + + ({paymentOptions.length}) + + + + + + - - - Payment Options - - Added: {paymentOptions.length} - - - - - {paymentOptions.length ? ( - paymentOptions - .map( - ( - { - superToken, - chainId, - transferAmountEther, - flowRate, - receiverAddress, - }, - i, - ) => ( - - - + {paymentOptions.length ? ( + paymentOptions + .map( + ( + { + superToken, + chainId, + transferAmountEther, + flowRate, + receiverAddress, + }, + i, + ) => ( + + + { - remove(params); - setAddCount(0); - }} - /> - - - ), - ) - .reverse() - ) : ( - - - None - - )} + receiverAddress={receiverAddress} + superToken={superToken} + chainId={chainId} + index={i} + remove={(params) => { + remove(params); + setAddCount(0); + }} + /> + + + ), + ) + .reverse() + ) : ( + + - None + + )} + - - + { name="paymentDetails.paymentOptions" render={() => ( { setAddCount((x) => x + 1); append(props); @@ -185,7 +179,28 @@ const ProductEditor: FC = () => { )} /> - + + { + setAddCount((x) => x + 1); + setDemoPaymentDetails(); + }} + > + + + + ); }; diff --git a/apps/widget-builder/src/components/product-editor/ProductEditor.tsx b/apps/widget-builder/src/components/product-editor/ProductEditor.tsx index f371be3f..94072a37 100644 --- a/apps/widget-builder/src/components/product-editor/ProductEditor.tsx +++ b/apps/widget-builder/src/components/product-editor/ProductEditor.tsx @@ -1,6 +1,6 @@ import AutoFixHighIcon from "@mui/icons-material/AutoFixHigh"; import { - IconButton, + Fab, Stack, TextField, Tooltip, @@ -26,73 +26,88 @@ const ProductEditor: FC = () => { const { setDemoProductDetails } = useDemoMode(); return ( - - - - - Edit Product Details - - - - - - - - ( - - {(id) => ( - - )} - - )} - /> + <> + + + + + Edit Product Details + + + ( + + {(id) => ( + + )} + + )} + /> - ( - - {(id) => ( - - )} - - )} - /> - ( - onChange(URL.createObjectURL(file))} - onRemove={() => onChange("")} - imageSrc={value} - /> - )} - /> + ( + + {(id) => ( + + )} + + )} + /> + ( + onChange(URL.createObjectURL(file))} + onRemove={() => onChange("")} + imageSrc={value} + /> + )} + /> + - + + + + + + ); }; From 8fc7cb398b44b62c9820febf8502fc1d6b1500c7 Mon Sep 17 00:00:00 2001 From: Kaspar Kallas Date: Wed, 30 Aug 2023 11:40:54 +0000 Subject: [PATCH 13/20] add random styling button --- .../src/components/ui-editor/UiEditor.tsx | 416 ++++++++++-------- apps/widget-builder/src/hooks/useDemoMode.ts | 19 +- 2 files changed, 240 insertions(+), 195 deletions(-) diff --git a/apps/widget-builder/src/components/ui-editor/UiEditor.tsx b/apps/widget-builder/src/components/ui-editor/UiEditor.tsx index 3280b697..ad07a2b8 100644 --- a/apps/widget-builder/src/components/ui-editor/UiEditor.tsx +++ b/apps/widget-builder/src/components/ui-editor/UiEditor.tsx @@ -1,5 +1,7 @@ +import AutoFixHighIcon from "@mui/icons-material/AutoFixHigh"; import { Autocomplete, + Fab, FormControlLabel, Slider, Stack, @@ -7,12 +9,14 @@ import { TextField, ToggleButton, ToggleButtonGroup, + Tooltip, Typography, } from "@mui/material"; import { MuiColorInput } from "mui-color-input"; import { FC } from "react"; import { Controller, useFormContext } from "react-hook-form"; +import useDemoMode from "../../hooks/useDemoMode"; import useFontOptions from "../../hooks/useFontOptions"; import InputWrapper from "../form/InputWrapper"; import { WidgetProps } from "../widget-preview/WidgetPreview"; @@ -23,142 +27,201 @@ const UiEditor: FC = () => { const [displaySettings] = watch(["displaySettings"]); const fontOptions = useFontOptions(); + const { setDemoStyling } = useDemoMode(); + return ( - - - {"Edit Widget's Styling"} - + <> + + + {"Edit Widget's Styling"} + - ( - } - label={ - {`Dark mode: ${value ? "on" : "off"}`} - } - /> - )} - /> + ( + } + label={ + {`Dark mode: ${value ? "on" : "off"}`} + } + /> + )} + /> - ( - - {(id) => ( - onChange(value)} - sx={{ - borderTopRightRadius: 0, - borderBottomRightRadius: 0, - }} - > - - Inline - - - Dialog - - - Drawer - - ( + + {(id) => ( + onChange(value)} + sx={{ + borderTopRightRadius: 0, + borderBottomRightRadius: 0, + }} > - Full-screen - - - )} - - )} - /> + + Inline + + + Dialog + + + Drawer + + + Full-screen + + + )} + + )} + /> - ( - - {(id) => ( - onChange(x as number)} - /> - )} - - )} - /> + ( + + {(id) => ( + onChange(x as number)} + /> + )} + + )} + /> + + ( + + {(id) => ( + onChange(x as number)} + /> + )} + + )} + /> + + ( + + {(id) => ( + onChange(x as number)} + /> + )} + + )} + /> - ( - - {(id) => ( - onChange(x as number)} - /> + + ( + + {(id) => ( + onChange(x as `#{string}`)} + /> + )} + )} - - )} - /> + /> - ( - - {(id) => ( - onChange(x as number)} - /> + ( + + {(id) => ( + onChange(x as `#{string}`)} + /> + )} + )} - - )} - /> + /> + - ( - + {(id) => ( - onChange(x as `#{string}`)} + loading={fontOptions.length === 0} + disablePortal + options={fontOptions} + isOptionEqualToValue={(option, value) => + option.family === value.family + } + onChange={(_, value) => onChange(value)} + getOptionLabel={(option) => + `${option.family}, ${option.category}` + } + fullWidth + renderInput={(params) => } /> )} @@ -167,88 +230,55 @@ const UiEditor: FC = () => { ( - + {(id) => ( - onChange(x as `#{string}`)} - /> + exclusive + onChange={(_, x: "vertical" | "horizontal") => onChange(x)} + sx={{ + borderTopRightRadius: 0, + borderBottomRightRadius: 0, + }} + > + + Vertical + + + Horizontal + + )} )} /> - - ( - - {(id) => ( - - option.family === value.family - } - onChange={(_, value) => onChange(value)} - getOptionLabel={(option) => - `${option.family}, ${option.category}` - } - fullWidth - renderInput={(params) => } - /> - )} - - )} - /> - - ( - - {(id) => ( - onChange(x)} - sx={{ - borderTopRightRadius: 0, - borderBottomRightRadius: 0, - }} - > - - Vertical - - - Horizontal - - - )} - - )} - /> - + + + + + + ); }; diff --git a/apps/widget-builder/src/hooks/useDemoMode.ts b/apps/widget-builder/src/hooks/useDemoMode.ts index c6b868cf..eb50332f 100644 --- a/apps/widget-builder/src/hooks/useDemoMode.ts +++ b/apps/widget-builder/src/hooks/useDemoMode.ts @@ -126,7 +126,7 @@ const defaultPaymentDetails: PaymentDetails = { const type: Layout = "page"; -const displaySettings: DisplaySettings = { +const defaultDisplaySettings: DisplaySettings = { darkMode: false, containerRadius: 20, buttonRadius: 10, @@ -144,7 +144,7 @@ export const defaultWidgetProps: WidgetProps = { productDetails: defaultProductDetails, paymentDetails: defaultPaymentDetails, type, - displaySettings, + displaySettings: defaultDisplaySettings, }; const useDemoMode = () => { @@ -154,6 +154,7 @@ const useDemoMode = () => { () => setValue("paymentDetails", demoPaymentDetails), [setValue], ); + const setDemoProductDetails = useCallback(() => { const demoProductDetails: ProductDetails = { name: `${faker.commerce.productName()}`, @@ -163,9 +164,23 @@ const useDemoMode = () => { setValue("productDetails", demoProductDetails); }, [setValue]); + const setDemoStyling = useCallback(() => { + const demoStyling: DisplaySettings = { + ...defaultDisplaySettings, + darkMode: faker.datatype.boolean(), + primaryColor: faker.color.rgb() as `#${string}`, + secondaryColor: faker.color.rgb() as `#${string}`, + containerRadius: faker.number.int({ min: 0, max: 50 }), + buttonRadius: faker.number.int({ min: 0, max: 25 }), + inputRadius: faker.number.int({ min: 0, max: 25 }), + }; + setValue("displaySettings", demoStyling); + }, [setValue]); + return { setDemoPaymentDetails, setDemoProductDetails, + setDemoStyling, }; }; From fa8e4d8a7b7211a8bb969828879db7208a7ee4ab Mon Sep 17 00:00:00 2001 From: Kaspar Kallas Date: Wed, 30 Aug 2023 11:42:25 +0000 Subject: [PATCH 14/20] missing formatting --- .../src/components/product-editor/ProductEditor.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/apps/widget-builder/src/components/product-editor/ProductEditor.tsx b/apps/widget-builder/src/components/product-editor/ProductEditor.tsx index 94072a37..86c6552c 100644 --- a/apps/widget-builder/src/components/product-editor/ProductEditor.tsx +++ b/apps/widget-builder/src/components/product-editor/ProductEditor.tsx @@ -1,11 +1,5 @@ import AutoFixHighIcon from "@mui/icons-material/AutoFixHigh"; -import { - Fab, - Stack, - TextField, - Tooltip, - Typography, -} from "@mui/material"; +import { Fab, Stack, TextField, Tooltip, Typography } from "@mui/material"; import { FC } from "react"; import { Controller, useFieldArray, useFormContext } from "react-hook-form"; From c65903c3255481a664cec2cdc3b1501d1320fd0a Mon Sep 17 00:00:00 2001 From: Kaspar Kallas Date: Wed, 30 Aug 2023 15:54:35 +0000 Subject: [PATCH 15/20] move payment tab first --- .../components/image-select/ImageSelect.tsx | 25 +-- .../payment-editor/PaymentEditor.tsx | 27 +-- .../payment-option-view/PaymentOptionView.tsx | 186 ++++++++---------- .../product-editor/ProductEditor.tsx | 20 +- .../src/components/ui-editor/UiEditor.tsx | 4 +- apps/widget-builder/src/pages/builder.tsx | 18 +- 6 files changed, 120 insertions(+), 160 deletions(-) diff --git a/apps/widget-builder/src/components/image-select/ImageSelect.tsx b/apps/widget-builder/src/components/image-select/ImageSelect.tsx index 1487c637..147fc133 100644 --- a/apps/widget-builder/src/components/image-select/ImageSelect.tsx +++ b/apps/widget-builder/src/components/image-select/ImageSelect.tsx @@ -5,20 +5,19 @@ import { Button, IconButton, Stack, - Typography, useTheme, } from "@mui/material"; import { ChangeEvent, FC, useRef } from "react"; type ImageSelectProps = { - label: string; + id: string; imageSrc?: string; onClick: (file: File) => void; onRemove: () => void; }; const ImageSelect: FC = ({ - label, + id, imageSrc, onClick, onRemove, @@ -39,13 +38,7 @@ const ImageSelect: FC = ({ return ( - - - {label} - + {imageSrc && ( @@ -74,7 +67,7 @@ const ImageSelect: FC = ({ data-testid="file-upload-field" hidden type="file" - name={label} + name={id} ref={inputRef} onChange={handleFileUpload} /> @@ -92,16 +85,6 @@ const ImageSelect: FC = ({ height: 90, }} > - - Optional - { <> - - Edit Payment Details + + Checkout Payment Details { mb: 2, }} > - - Payment Options - - ({paymentOptions.length}) - - + + + Payment Options + + ({paymentOptions.length}) + + + */} + + + } + /> + + + + - - + + ); }; diff --git a/apps/widget-builder/src/components/product-editor/ProductEditor.tsx b/apps/widget-builder/src/components/product-editor/ProductEditor.tsx index 86c6552c..a920a7d1 100644 --- a/apps/widget-builder/src/components/product-editor/ProductEditor.tsx +++ b/apps/widget-builder/src/components/product-editor/ProductEditor.tsx @@ -28,8 +28,8 @@ const ProductEditor: FC = () => { justifyContent="space-between" alignItems="center" > - - Edit Product Details + + Checkout Product Details { control={control} name="productDetails.imageURI" render={({ field: { value, onChange } }) => ( - onChange(URL.createObjectURL(file))} - onRemove={() => onChange("")} - imageSrc={value} - /> + + {(id) => ( + onChange(URL.createObjectURL(file))} + onRemove={() => onChange("")} + imageSrc={value} + /> + )} + )} /> diff --git a/apps/widget-builder/src/components/ui-editor/UiEditor.tsx b/apps/widget-builder/src/components/ui-editor/UiEditor.tsx index ad07a2b8..4fbd522a 100644 --- a/apps/widget-builder/src/components/ui-editor/UiEditor.tsx +++ b/apps/widget-builder/src/components/ui-editor/UiEditor.tsx @@ -32,8 +32,8 @@ const UiEditor: FC = () => { return ( <> - - {"Edit Widget's Styling"} + + {"Checkout Widget Styling"} - - + + Checkout Builder - + setActiveStep(Number(value))} > - - - - + + + + @@ -97,10 +97,10 @@ export default function Builder() { - + - + From 64a560f1aa9fcdac2af8d4c141aa101b4f2bb12f Mon Sep 17 00:00:00 2001 From: Kaspar Kallas Date: Wed, 30 Aug 2023 23:08:38 +0000 Subject: [PATCH 16/20] small clean-ups and unification --- .../src/components/buttons/BookDemoBtn.tsx | 1 + .../components/buttons/DownloadJsonBtn.tsx | 4 +- .../src/components/buttons/IPFSPublishBtn.tsx | 9 +- .../components/export-editor/ExportEditor.tsx | 30 ++- .../components/image-select/ImageSelect.tsx | 16 +- .../payment-editor/PaymentEditor.tsx | 192 ++++++++++-------- .../payment-option-view/PaymentOptionView.tsx | 56 +++-- .../product-editor/ProductEditor.tsx | 126 ++++++------ .../SelectPaymentOption.tsx | 29 +-- apps/widget-builder/src/pages/builder.tsx | 8 +- apps/widget-builder/src/theme.ts | 2 +- 11 files changed, 254 insertions(+), 219 deletions(-) diff --git a/apps/widget-builder/src/components/buttons/BookDemoBtn.tsx b/apps/widget-builder/src/components/buttons/BookDemoBtn.tsx index 24d17af1..4ec589c5 100644 --- a/apps/widget-builder/src/components/buttons/BookDemoBtn.tsx +++ b/apps/widget-builder/src/components/buttons/BookDemoBtn.tsx @@ -27,6 +27,7 @@ const BookDemoBtn: FC = ({ children, sx = {} }) => { variant="outlined" color="primary" sx={sx} + // startIcon={} > {children} diff --git a/apps/widget-builder/src/components/buttons/DownloadJsonBtn.tsx b/apps/widget-builder/src/components/buttons/DownloadJsonBtn.tsx index d5f8e51c..308a9f5f 100644 --- a/apps/widget-builder/src/components/buttons/DownloadJsonBtn.tsx +++ b/apps/widget-builder/src/components/buttons/DownloadJsonBtn.tsx @@ -1,3 +1,4 @@ +import DownloadIcon from "@mui/icons-material/Download"; import { Button } from "@mui/material"; import { FC } from "react"; @@ -12,12 +13,13 @@ const DownloadJsonBtn: FC = ({ json }) => ( data-testid="download-button" fullWidth size="large" + color="primary" variant="contained" href={URL.createObjectURL( new Blob([JSON.stringify(json, null, 2)], { type: "application/json" }), )} download={`widget.json`} - sx={{ color: "white" }} + startIcon={} > Download JSON diff --git a/apps/widget-builder/src/components/buttons/IPFSPublishBtn.tsx b/apps/widget-builder/src/components/buttons/IPFSPublishBtn.tsx index b8039385..678fc2e7 100644 --- a/apps/widget-builder/src/components/buttons/IPFSPublishBtn.tsx +++ b/apps/widget-builder/src/components/buttons/IPFSPublishBtn.tsx @@ -1,3 +1,4 @@ +import UploadIcon from "@mui/icons-material/Upload"; import { LoadingButton } from "@mui/lab"; import { Stack, Typography } from "@mui/material"; import { SuperfluidButton } from "@superfluid-finance/widget/components"; @@ -14,6 +15,7 @@ const IPFSPublishBtn: FC = ({ json }) => { const { publish, isLoading, ipfsHash } = usePinataIpfs({ pinataMetadata: { name: `${json.productDetails.name}-superfluid-widget` }, }); + const isPublished = !!ipfsHash; return ( @@ -21,13 +23,14 @@ const IPFSPublishBtn: FC = ({ json }) => { data-testid="publish-button" size="large" loading={isLoading} + disabled={isPublished} variant="contained" onClick={() => publish(json)} + startIcon={} > - Publish + {isPublished ? "Publish to IPFS" : "Published to IPFS"} - - {ipfsHash && ( + {isPublished && ( { useState("ipfs"); return ( - + + + Checkout Export + { )} - + How does it work? - + {selectedExportOption === "ipfs" ? "You’ll create a hosted link to your checkout which you can embed in your CTAs." : selectedExportOption === "json" @@ -118,17 +114,15 @@ const ExportEditor: FC = () => { {switchExportOption(selectedExportOption, json)} - - - - + + Do you have more questions? - + We’ll show you how your business can benefit from using our checkout. Book a Demo - + ); }; diff --git a/apps/widget-builder/src/components/image-select/ImageSelect.tsx b/apps/widget-builder/src/components/image-select/ImageSelect.tsx index 147fc133..6758fd49 100644 --- a/apps/widget-builder/src/components/image-select/ImageSelect.tsx +++ b/apps/widget-builder/src/components/image-select/ImageSelect.tsx @@ -1,12 +1,6 @@ import AddIcon from "@mui/icons-material/Add"; import CancelIcon from "@mui/icons-material/Cancel"; -import { - Box, - Button, - IconButton, - Stack, - useTheme, -} from "@mui/material"; +import { Box, Button, IconButton, Stack, useTheme } from "@mui/material"; import { ChangeEvent, FC, useRef } from "react"; type ImageSelectProps = { @@ -38,13 +32,13 @@ const ImageSelect: FC = ({ return ( - - {imageSrc && ( + {imageSrc && ( + - )} - + + )} {imageSrc ? ( { }; const { setDemoPaymentDetails } = useDemoMode(); + const handleDemo = useCallback(() => { + setAddCount((x) => x + 1); + setDemoPaymentDetails(); + }, []); return ( <> - - - - Checkout Payment Details - - - - - - Payment Options - - ({paymentOptions.length}) - - - - - + ({paymentOptions.length}) + + + + + - - {paymentOptions.length ? ( - paymentOptions - .map( - ( - { - superToken, - chainId, - transferAmountEther, - flowRate, - receiverAddress, - }, - i, - ) => ( - - - { - remove(params); - setAddCount(0); - }} - /> - - - ), - ) - .reverse() - ) : ( - - - None + + {paymentOptions.length ? ( + paymentOptions + .map( + ( + { + superToken, + chainId, + transferAmountEther, + flowRate, + receiverAddress, + }, + i, + ) => ( + + + { + remove(params); + setAddCount(0); + }} + /> + + + ), + ) + .reverse() + ) : ( + + {"You haven't added any payment options yet."} Add your first + one or{" "} + + replace with demo data - )} - + . + + )} @@ -145,11 +157,12 @@ const ProductEditor: FC = () => { TransitionProps={ { direction: "right", + exit: false, } as SlideProps } keepMounted > - + { + { append(props); handleClose(); }} - onDiscard={handleClose} + onDiscard={() => { + handleClose(); + setAddCount((x) => x + 1); + }} /> )} /> @@ -195,10 +212,7 @@ const ProductEditor: FC = () => { bottom: 72, left: 20, }} - onClick={() => { - setAddCount((x) => x + 1); - setDemoPaymentDetails(); - }} + onClick={handleDemo} > diff --git a/apps/widget-builder/src/components/payment-option-view/PaymentOptionView.tsx b/apps/widget-builder/src/components/payment-option-view/PaymentOptionView.tsx index 8d990604..a2555b11 100644 --- a/apps/widget-builder/src/components/payment-option-view/PaymentOptionView.tsx +++ b/apps/widget-builder/src/components/payment-option-view/PaymentOptionView.tsx @@ -1,4 +1,3 @@ -import ClearIcon from "@mui/icons-material/Clear"; import { Button, Card, @@ -6,7 +5,10 @@ import { CardContent, Divider, Stack, + styled, Tooltip, + tooltipClasses, + TooltipProps, Typography, useTheme, } from "@mui/material"; @@ -26,6 +28,14 @@ type PaymentOptionRowProps = { value: ReactNode; }; +const NoMaxWidthTooltip = styled(({ className, ...props }: TooltipProps) => ( + +))({ + [`& .${tooltipClasses.tooltip}`]: { + maxWidth: "none", + }, +}); + const PaymentOptionRow: FC = ({ label, value }) => { const theme = useTheme(); return ( @@ -36,11 +46,7 @@ const PaymentOptionRow: FC = ({ label, value }) => { direction="row" sx={{ width: "100%", justifyContent: "space-between" }} > - + {label} {value} @@ -51,7 +57,7 @@ const PaymentOptionRow: FC = ({ label, value }) => { type PaymentOptionViewProps = { superToken: { address: `0x${string}` }; upfrontPaymentAmountEther?: string; - flowRate: FlowRate; + flowRate: FlowRate | undefined; receiverAddress: `0x${string}`; chainId: ChainId; index: number; @@ -74,12 +80,12 @@ const PaymentOptionView: FC = ({ ); const flowRateValue = useMemo(() => { - if (!flowRate) return "Custom amount"; + if (!flowRate) return "User-defined"; return `${flowRate.amountEther} ${token?.symbol ?? "x"}/${flowRate.period}`; }, [flowRate, token]); return ( - + = ({ - + {`${receiverAddress.substring( 0, 6, @@ -142,24 +158,32 @@ const PaymentOptionView: FC = ({ )} `} - + } /> - + - + {/* + + + + */} + ); }; diff --git a/apps/widget-builder/src/components/product-editor/ProductEditor.tsx b/apps/widget-builder/src/components/product-editor/ProductEditor.tsx index a920a7d1..f04fbb6c 100644 --- a/apps/widget-builder/src/components/product-editor/ProductEditor.tsx +++ b/apps/widget-builder/src/components/product-editor/ProductEditor.tsx @@ -21,71 +21,69 @@ const ProductEditor: FC = () => { return ( <> - - - - - Checkout Product Details - - - ( - - {(id) => ( - - )} - - )} - /> - - ( - - {(id) => ( - - )} - - )} - /> - ( - - {(id) => ( - onChange(URL.createObjectURL(file))} - onRemove={() => onChange("")} - imageSrc={value} - /> - )} - - )} - /> + + + + Checkout Product Details + + ( + + {(id) => ( + + )} + + )} + /> + + ( + + {(id) => ( + + )} + + )} + /> + ( + + {(id) => ( + onChange(URL.createObjectURL(file))} + onRemove={() => onChange("")} + imageSrc={value} + /> + )} + + )} + /> = ({ null, ); - const [isCustomAmount, setIsCustomAmount] = useState(true); + const [isCustomAmount, setIsCustomAmount] = useState(false); const [flowRateAmount, setFlowRateAmount] = useState<`${number}` | "">(""); const [flowRateInterval, setFlowRateInterval] = useState("month"); @@ -314,8 +315,8 @@ const SelectPaymentOption: FC = ({ fullWidth color="primary" > - User-defined rate Fixed rate + User-defined rate )} @@ -423,28 +424,32 @@ const SelectPaymentOption: FC = ({ + - + diff --git a/apps/widget-builder/src/pages/builder.tsx b/apps/widget-builder/src/pages/builder.tsx index 1f372058..6ac90e86 100644 --- a/apps/widget-builder/src/pages/builder.tsx +++ b/apps/widget-builder/src/pages/builder.tsx @@ -96,16 +96,16 @@ export default function Builder() { - + - + - + - + diff --git a/apps/widget-builder/src/theme.ts b/apps/widget-builder/src/theme.ts index fc5cdb60..db0d8517 100644 --- a/apps/widget-builder/src/theme.ts +++ b/apps/widget-builder/src/theme.ts @@ -155,7 +155,7 @@ const theme = createTheme({ styleOverrides: { root: { textTransform: "uppercase", - fontSize: "0.875rem", + fontSize: "1rem", }, }, }, From a808718def53f7f79d70d3002bb930e101344917 Mon Sep 17 00:00:00 2001 From: Kaspar Kallas Date: Thu, 31 Aug 2023 07:40:42 +0000 Subject: [PATCH 17/20] fix ipfs button text and icon --- .../src/components/buttons/IPFSPublishBtn.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/widget-builder/src/components/buttons/IPFSPublishBtn.tsx b/apps/widget-builder/src/components/buttons/IPFSPublishBtn.tsx index 678fc2e7..952d5f6a 100644 --- a/apps/widget-builder/src/components/buttons/IPFSPublishBtn.tsx +++ b/apps/widget-builder/src/components/buttons/IPFSPublishBtn.tsx @@ -1,4 +1,5 @@ -import UploadIcon from "@mui/icons-material/Upload"; +import CloudDoneIcon from "@mui/icons-material/CloudDone"; +import CloudUploadIcon from "@mui/icons-material/CloudUpload"; import { LoadingButton } from "@mui/lab"; import { Stack, Typography } from "@mui/material"; import { SuperfluidButton } from "@superfluid-finance/widget/components"; @@ -26,9 +27,9 @@ const IPFSPublishBtn: FC = ({ json }) => { disabled={isPublished} variant="contained" onClick={() => publish(json)} - startIcon={} + startIcon={isPublished ? : } > - {isPublished ? "Publish to IPFS" : "Published to IPFS"} + {isPublished ? "Published to IPFS" : "Publish to IPFS"} {isPublished && ( From fae287257e323a840f548840d432734a8e68cf37 Mon Sep 17 00:00:00 2001 From: Kaspar Kallas Date: Thu, 31 Aug 2023 08:01:18 +0000 Subject: [PATCH 18/20] add descriptive subtitles under tab titles --- .../payment-editor/PaymentEditor.tsx | 12 ++++-- .../product-editor/ProductEditor.tsx | 14 +++---- .../src/components/ui-editor/UiEditor.tsx | 40 ++++++++++--------- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx b/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx index 586c6862..3c641598 100644 --- a/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx +++ b/apps/widget-builder/src/components/payment-editor/PaymentEditor.tsx @@ -55,9 +55,15 @@ const ProductEditor: FC = () => { return ( <> - - Checkout Payment Details - + + + Checkout Payment Details + + + Enter your preferred payment options to start receiving ongoing + real-time payments powered by the Superfluid Protocol. + + { return ( <> - + Checkout Product Details - + + Define the product you want to receive ongoing real-time payments + for. + + { return ( <> - - {"Checkout Widget Styling"} - - - ( - } - label={ - {`Dark mode: ${value ? "on" : "off"}`} - } - /> - )} - /> + + + Checkout Widget Styling + + + You are free to customize the look and feel of the checkout widget. + + { )} /> - + ( + } + label={ + {`Dark mode: ${value ? "on" : "off"}`} + } + /> + )} + /> Date: Thu, 31 Aug 2023 08:47:35 +0000 Subject: [PATCH 19/20] add form validation --- .../src/components/form/InputWrapper.tsx | 16 ++-- .../payment-option-view/PaymentOptionView.tsx | 11 ++- .../SelectPaymentOption.tsx | 86 +++++++++++-------- packages/widget/src/index.ts | 6 +- 4 files changed, 74 insertions(+), 45 deletions(-) diff --git a/apps/widget-builder/src/components/form/InputWrapper.tsx b/apps/widget-builder/src/components/form/InputWrapper.tsx index 61f8f772..744549fe 100644 --- a/apps/widget-builder/src/components/form/InputWrapper.tsx +++ b/apps/widget-builder/src/components/form/InputWrapper.tsx @@ -1,4 +1,4 @@ -import InfoIcon from "@mui/icons-material/Info"; +import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; import { FormControl, FormHelperText, @@ -20,7 +20,7 @@ export const InputInfo: FC = ({ tooltip }) => { return ( - + ); }; @@ -32,7 +32,8 @@ interface InputWrapperProps { sx?: SxProps; helperText?: string; optional?: boolean; - children: (inputId: string) => PropsWithChildren["children"]; + error?: boolean; + children: (inputId: string, error?: boolean) => PropsWithChildren["children"]; } const InputWrapper: FC = ({ @@ -42,13 +43,14 @@ const InputWrapper: FC = ({ helperText, children, optional, + error, ...props }) => { const generatedId = useId(); const inputId = props.id ?? generatedId; const labelId = `label-${inputId}`; return ( - + {!!title && ( @@ -67,8 +69,10 @@ const InputWrapper: FC = ({ )} {!!tooltip && } - {children(inputId)} - {!!helperText && {helperText}} + {children(inputId, error)} + {!!helperText && ( + {helperText} + )} ); }; diff --git a/apps/widget-builder/src/components/payment-option-view/PaymentOptionView.tsx b/apps/widget-builder/src/components/payment-option-view/PaymentOptionView.tsx index a2555b11..93b39dbf 100644 --- a/apps/widget-builder/src/components/payment-option-view/PaymentOptionView.tsx +++ b/apps/widget-builder/src/components/payment-option-view/PaymentOptionView.tsx @@ -73,10 +73,15 @@ const PaymentOptionView: FC = ({ index, remove, }) => { - const theme = useTheme(); const network = supportedNetworks.find((n) => n.id === chainId)!; - const token = Object.values(superTokenList.tokens).find( - (token) => token.address === superToken.address, + + const token = useMemo( + () => + Object.values(superTokenList.tokens).find( + (token) => + token.address.toLowerCase() === superToken.address.toLowerCase(), + ), + [superTokenList, superToken.address], ); const flowRateValue = useMemo(() => { diff --git a/apps/widget-builder/src/components/select-payment-option/SelectPaymentOption.tsx b/apps/widget-builder/src/components/select-payment-option/SelectPaymentOption.tsx index 8112f9c8..47d1e12e 100644 --- a/apps/widget-builder/src/components/select-payment-option/SelectPaymentOption.tsx +++ b/apps/widget-builder/src/components/select-payment-option/SelectPaymentOption.tsx @@ -25,6 +25,8 @@ import { import { ChainId, NetworkAssetInfo, + PaymentOption, + paymentOptionSchema, supportedNetworks, TimePeriod, timePeriods, @@ -35,12 +37,13 @@ import tokenList, { import { ChangeEvent, FC, useEffect, useMemo, useState } from "react"; import { UseFieldArrayAppend } from "react-hook-form"; import { Chain } from "wagmi"; +import { ZodError } from "zod"; import InputWrapper, { InputInfo } from "../form/InputWrapper"; import NetworkAvatar from "../NetworkAvatar"; import { WidgetProps } from "../widget-preview/WidgetPreview"; -export type PaymentOption = { +export type PaymentOptionWithSuperTokenAndNetwork = { network: NetworkAssetInfo; superToken: SuperTokenInfo; }; @@ -93,38 +96,41 @@ const SelectPaymentOption: FC = ({ } }; + const [errors, setErrors] = useState | null>(null); + const handleAdd = () => { - if (!selectedToken) { - return; - } + setErrors(null); - const network = supportedNetworks.find( - (n) => n.id === selectedToken.chainId, - ); + const thePaymentOption: Partial = { + receiverAddress: receiver as `0x${string}`, + superToken: selectedToken + ? { + address: selectedToken.address as `0x${string}`, + } + : undefined, + chainId: selectedToken ? (selectedToken.chainId as ChainId) : undefined, + ...(!isCustomAmount + ? { + ...(showUpfrontPayment + ? { + transferAmountEther: upfrontPaymentAmount + ? upfrontPaymentAmount + : "0", + } + : {}), + flowRate: { + amountEther: flowRateAmount ? flowRateAmount : "0", + period: flowRateInterval, + }, + } + : {}), + }; - if (network && receiver) { - onAdd({ - receiverAddress: receiver, - superToken: { - address: selectedToken.address as `0x${string}`, - }, - chainId: selectedToken.chainId as ChainId, - ...(!isCustomAmount - ? { - ...(showUpfrontPayment - ? { - transferAmountEther: upfrontPaymentAmount - ? upfrontPaymentAmount - : "0", - } - : {}), - flowRate: { - amountEther: flowRateAmount ? flowRateAmount : "0", - period: flowRateInterval, - }, - } - : {}), - }); + const validationResult = paymentOptionSchema.safeParse(thePaymentOption); + if (validationResult.success) { + onAdd(validationResult.data); + } else { + setErrors(validationResult.error); } }; @@ -174,6 +180,7 @@ const SelectPaymentOption: FC = ({ {(id) => (