From 9d2bb31ecd4919b42eb1de509b3536fdaeb0a3cf Mon Sep 17 00:00:00 2001 From: "vicky.bansal@primathon.in" Date: Mon, 7 Jun 2021 15:29:23 +0530 Subject: [PATCH 01/50] Added properties for currency type input in Input widget --- .../propertyControls/DropDownControl.tsx | 2 +- app/client/src/widgets/InputWidget.tsx | 57 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/app/client/src/components/propertyControls/DropDownControl.tsx b/app/client/src/components/propertyControls/DropDownControl.tsx index 8d906de06ef8..69e403d02e5d 100644 --- a/app/client/src/components/propertyControls/DropDownControl.tsx +++ b/app/client/src/components/propertyControls/DropDownControl.tsx @@ -9,7 +9,7 @@ class DropDownControl extends BaseControl { label: "No results.", value: undefined, }; - + console.log({ props: this.props }); const selected: DropdownOption = this.props.options.find( (option) => option.value === this.props.propertyValue, ); diff --git a/app/client/src/widgets/InputWidget.tsx b/app/client/src/widgets/InputWidget.tsx index 7517e7b5a6ab..2fd4b4962330 100644 --- a/app/client/src/widgets/InputWidget.tsx +++ b/app/client/src/widgets/InputWidget.tsx @@ -49,7 +49,61 @@ class InputWidget extends BaseWidget { label: "Email", value: "EMAIL", }, + { + label: "Currency", + value: "CURRENCY", + }, + ], + isBindProperty: false, + isTriggerProperty: false, + }, + { + propertyName: "allowCurrencyChange", + label: "Allow currency change", + helpText: "Allow currency type to be changed", + controlType: "SWITCH", + isJSConvertible: false, + isBindProperty: true, + isTriggerProperty: false, + validation: VALIDATION_TYPES.BOOLEAN, + hidden: (props: InputWidgetProps) => { + return props.inputType !== InputTypes.CURRENCY; + }, + }, + { + helpText: "Changes the type of currency", + propertyName: "currencyType", + label: "Currency", + controlType: "DROP_DOWN", + options: [], + hidden: (props: InputWidgetProps) => { + return props.inputType !== InputTypes.CURRENCY; + }, + isBindProperty: false, + isTriggerProperty: false, + }, + { + helpText: "No. of decimals in currency input", + propertyName: "decimalsInCurrency", + label: "Decimals", + controlType: "DROP_DOWN", + options: [ + { + label: "1", + value: "1", + }, + { + label: "2", + value: "2", + }, + { + label: "3", + value: "3", + }, ], + hidden: (props: InputWidgetProps) => { + return props.inputType !== InputTypes.CURRENCY; + }, isBindProperty: false, isTriggerProperty: false, }, @@ -357,6 +411,9 @@ export interface InputValidator { } export interface InputWidgetProps extends WidgetProps, WithMeta { inputType: InputType; + currencyType?: string; + noOfDecimals?: number; + allowCurrencyChange?: boolean; defaultText?: string; isDisabled?: boolean; text: string; From 796829c16d19b0597cbfe2dfe67293fcc5122428 Mon Sep 17 00:00:00 2001 From: "vicky.bansal@primathon.in" Date: Tue, 8 Jun 2021 12:28:08 +0530 Subject: [PATCH 02/50] Added search to dropdown Added currency type dropdown to input widget --- app/client/src/components/ads/Dropdown.tsx | 213 +- .../blueprint/InputComponent.tsx | 66 +- app/client/src/constants/Currency.tsx | 1998 +++++++++++++++++ app/client/src/widgets/InputWidget.tsx | 4 +- 4 files changed, 2216 insertions(+), 65 deletions(-) create mode 100644 app/client/src/constants/Currency.tsx diff --git a/app/client/src/components/ads/Dropdown.tsx b/app/client/src/components/ads/Dropdown.tsx index 77e7ce91911a..d8251eea55ef 100644 --- a/app/client/src/components/ads/Dropdown.tsx +++ b/app/client/src/components/ads/Dropdown.tsx @@ -1,9 +1,10 @@ -import React, { useState, useEffect, useCallback } from "react"; +import React, { useState, useEffect, useCallback, ReactNode } from "react"; import Icon, { IconName, IconSize } from "./Icon"; import { CommonComponentProps, Classes } from "./common"; import Text, { TextType } from "./Text"; import { Popover, Position } from "@blueprintjs/core"; import styled from "constants/DefaultTheme"; +import SearchComponent from "components/designSystems/appsmith/SearchComponent"; export type DropdownOption = { label?: string; @@ -15,18 +16,25 @@ export type DropdownOption = { iconColor?: string; onSelect?: (value?: string) => void; }; +export interface DropdownSearchProps { + enableSearch?: boolean; + searchPlaceholder?: string; + onSearch?: (value: any) => void; +} -export type DropdownProps = CommonComponentProps & { - options: DropdownOption[]; - selected: DropdownOption; - onSelect?: (value?: string) => void; - width?: string; - height?: string; - showLabelOnly?: boolean; - optionWidth?: string; - showDropIcon?: boolean; - SelectedValueNode?: typeof DefaultDropDownValueNode; -}; +export type DropdownProps = CommonComponentProps & + DropdownSearchProps & { + options: DropdownOption[]; + selected: DropdownOption; + onSelect?: (value?: string) => void; + width?: string; + height?: string; + showLabelOnly?: boolean; + optionWidth?: string; + showDropIcon?: boolean; + dropdownTriggerIcon?: ReactNode; + SelectedValueNode?: typeof DefaultDropDownValueNode; + }; export const DropdownContainer = styled.div<{ width: string; height: string }>` width: ${(props) => props.width}; @@ -34,6 +42,40 @@ export const DropdownContainer = styled.div<{ width: string; height: string }>` position: relative; `; +const DropdownTriggerWrapper = styled.div<{ + isOpen: boolean; + disabled?: boolean; + height: string; +}>` + height: ${(props) => props.height}; + ${(props) => + props.isOpen + ? `border: 1px solid ${props.theme.colors.info.main}` + : props.disabled + ? `border: 1px solid ${props.theme.colors.dropdown.header.disabledBg}` + : `border: 1px solid ${props.theme.colors.dropdown.header.bg}`}; + background: ${(props) => + props.disabled + ? props.theme.colors.dropdown.header.disabledBg + : props.theme.colors.dropdown.header.bg}; + display: flex; + align-items: center; + justify-content: space-between; + cursor: pointer; + ${(props) => + props.isOpen && !props.disabled ? "box-sizing: border-box" : null}; + ${(props) => + props.isOpen && !props.disabled + ? "box-shadow: 0px 0px 4px 4px rgba(203, 72, 16, 0.18)" + : null}; + .${Classes.TEXT} { + ${(props) => + props.disabled + ? `color: ${props.theme.colors.dropdown.header.disabledText}` + : `color: ${props.theme.colors.dropdown.header.text}`}; + } +`; + const Selected = styled.div<{ isOpen: boolean; disabled?: boolean; @@ -185,7 +227,7 @@ const SelectedIcon = styled(Icon)` } `; -function DefaultDropDownValueNode({ +export function DefaultDropDownValueNode({ selected, showLabelOnly, }: { @@ -204,6 +246,71 @@ function DefaultDropDownValueNode({ ); } +interface DropdownOptionsProps extends DropdownProps, DropdownSearchProps { + optionClickHandler: (option: DropdownOption) => void; + selected: DropdownOption; +} + +export function RenderDropdownOptions(props: DropdownOptionsProps) { + const { onSearch } = props; + const [options, setOptions] = useState>(props.options); + const [searchValue, setSearchValue] = useState(""); + const onOptionSearch = (searchStr: string) => { + const filteredOptions: Array = props.options.filter( + (option: DropdownOption) => { + return option.label?.includes(searchValue); + }, + ); + setSearchValue(searchStr); + setOptions(filteredOptions); + onSearch && onSearch(searchStr); + }; + return ( + + {props.enableSearch && ( + + )} + {options.map((option: DropdownOption, index: number) => { + return ( + props.optionClickHandler(option)} + selected={props.selected.value === option.value} + > + {option.icon ? ( + + ) : null} + + {props.showLabelOnly ? ( + {option.label} + ) : option.label && option.value ? ( + + {option.value} + {option.label} + + ) : ( + {option.value} + )} + + {option.subText ? ( + {option.subText} + ) : null} + + ); + })} + + ); +} + export default function Dropdown(props: DropdownProps) { const { onSelect, @@ -226,6 +333,31 @@ export default function Dropdown(props: DropdownProps) { }, [onSelect], ); + const dropdownTrigger = props.dropdownTriggerIcon ? ( + setIsOpen(!isOpen)} + > + {props.dropdownTriggerIcon} + + ) : ( + setIsOpen(!isOpen)} + > + + {showDropIcon && } + + ); return ( - setIsOpen(!isOpen)} - > - - {showDropIcon && } - - - {props.options.map((option: DropdownOption, index: number) => { - return ( - optionClickHandler(option)} - selected={selected.value === option.value} - > - {option.icon ? ( - - ) : null} - - {props.showLabelOnly ? ( - {option.label} - ) : option.label && option.value ? ( - - {option.value} - {option.label} - - ) : ( - {option.value} - )} - - {option.subText ? ( - - {option.subText} - - ) : null} - - ); - })} - + {dropdownTrigger} + ); diff --git a/app/client/src/components/designSystems/blueprint/InputComponent.tsx b/app/client/src/components/designSystems/blueprint/InputComponent.tsx index 24d684b7fcf3..b8664f2ea7b8 100644 --- a/app/client/src/components/designSystems/blueprint/InputComponent.tsx +++ b/app/client/src/components/designSystems/blueprint/InputComponent.tsx @@ -17,7 +17,7 @@ import { ControlGroup, TextArea, } from "@blueprintjs/core"; -import { InputType } from "widgets/InputWidget"; +import { InputType, InputTypes } from "widgets/InputWidget"; import { WIDGET_PADDING } from "constants/WidgetConstants"; import { Colors } from "constants/Colors"; import ErrorTooltip from "components/editorComponents/ErrorTooltip"; @@ -26,6 +26,8 @@ import { createMessage, INPUT_WIDGET_DEFAULT_VALIDATION_ERROR, } from "constants/messages"; +import Dropdown, { DropdownOption } from "components/ads/Dropdown"; +import { CurrencyTypeOptions, CurrencyOptionProps } from "constants/Currency"; /** * All design system component specific logic goes here. * Ex. Blueprint has a separate numeric input and text input so switching between them goes here @@ -93,6 +95,59 @@ const InputComponentWrapper = styled((props) => ( } `; +const DropdownWrapper = styled.div``; + +interface CurrencyDropdownProps { + onSelect?: (value?: string) => void; + options: Array; + selected: DropdownOption; +} + +function CurrencyTypeDropdown(props: CurrencyDropdownProps) { + return ( + + + + ); +} + +const getSelectedItem = (currencyType?: string): DropdownOption => { + const selectedCurrency: CurrencyOptionProps | undefined = currencyType + ? CurrencyTypeOptions.find((item: CurrencyOptionProps) => { + return item.currency === currencyType; + }) + : undefined; + if (selectedCurrency) { + return { + label: `${selectedCurrency.currency} - ${selectedCurrency.currency_name}`, + value: selectedCurrency.currency, + }; + } + return { + label: "USD - US Dollar", + value: "USD", + }; +}; + +export const getCurrencyOptions = (): Array => { + return CurrencyTypeOptions.map((item: CurrencyOptionProps) => { + return { + label: `${item.currency} - ${item.currency_name}`, + value: item.currency, + }; + }); +}; + class InputComponent extends React.Component< InputComponentProps, InputComponentState @@ -248,6 +303,12 @@ class InputComponent extends React.Component< multiline={this.props.multiline.toString()} numeric={this.isNumberInputType(this.props.inputType)} > + {this.props.inputType === InputTypes.CURRENCY && ( + + )} {this.props.label && (