diff --git a/public/hyperswitch/icons/solid.svg b/public/hyperswitch/icons/solid.svg index 1b856231f..f91f820a1 100644 --- a/public/hyperswitch/icons/solid.svg +++ b/public/hyperswitch/icons/solid.svg @@ -8938,4 +8938,4 @@ License) fill="#333333" /> - + \ No newline at end of file diff --git a/src/components/Filter.res b/src/components/Filter.res index 6156faf10..36c950196 100644 --- a/src/components/Filter.res +++ b/src/components/Filter.res @@ -365,7 +365,11 @@ let make = ( } -
+ + values->OrderUIUtils.validateForm(~fieldsToValidate=[StartAmount, EndAmount])}> { {<> diff --git a/src/components/FilterSelectBox.res b/src/components/FilterSelectBox.res index 0e0eb03c2..70db4341c 100644 --- a/src/components/FilterSelectBox.res +++ b/src/components/FilterSelectBox.res @@ -1882,7 +1882,7 @@ module BaseDropdown = { onClick className={`${textStyle->Option.getOr( "", - )} flex justify-center items-center whitespace-pre leading-5 text-sm font-medium hover:bg-opacity-80 cursor-pointer mr-2 border-r-2 pr-1`}> + )} flex justify-center items-center whitespace-pre leading-5 text-sm font-medium hover:bg-opacity-80 cursor-pointer mr-2 pr-1`}>
{selectButtonText->React.string}
@@ -1898,7 +1898,7 @@ module BaseDropdown = {
+ : ""} transition duration-[250ms] ease-out-[cubic-bezier(0.33, 1, 0.68, 1)] justify-between border`}> {if ( showToolTip && newInputSelect.value !== ""->JSON.Encode.string && @@ -1919,7 +1919,7 @@ module BaseDropdown = { selectButton }}
newInputSelect.name->onDeleteClick}>
diff --git a/src/components/RemoteFiltersUtils.res b/src/components/RemoteFiltersUtils.res index 71b020c39..d2acfa5d6 100644 --- a/src/components/RemoteFiltersUtils.res +++ b/src/components/RemoteFiltersUtils.res @@ -154,7 +154,7 @@ let getStrFromJson = (key, val) => { switch val->JSON.Classify.classify { | String(str) => str | Array(array) => array->Array.length > 0 ? `[${array->Array.joinWithUnsafe(",")}]` : "" - | Number(num) => key === "offset" ? "0" : num->Float.toInt->Int.toString + | Number(num) => key === "offset" ? "0" : num->Float.toString | _ => "" } } @@ -188,16 +188,24 @@ let getInitialValuesFromUrl = ( }) entriesList->Array.forEach(entry => { let (key, value) = entry - initialFilters->Array.forEach((filter: FormRenderer.fieldInfoType) => { - filter.inputNames->Array.forEach( - name => { - if name === key { - Dict.set(dict, key, value->UrlFetchUtils.getFilterValue) - } - }, - ) - }) - + let isAmountKey = switch key { + | "start_amount" + | "end_amount" => true + | _ => false + } + if isAmountKey { + Dict.set(dict, key, value->UrlFetchUtils.getFilterValue) + } else { + initialFilters->Array.forEach((filter: FormRenderer.fieldInfoType) => { + filter.inputNames->Array.forEach( + name => { + if name === key { + Dict.set(dict, key, value->UrlFetchUtils.getFilterValue) + } + }, + ) + }) + } options->Array.forEach(option => { let fieldName = option.urlKey if fieldName === key { diff --git a/src/components/form/FormRenderer.res b/src/components/form/FormRenderer.res index 840355f1f..f04b3e4ee 100644 --- a/src/components/form/FormRenderer.res +++ b/src/components/form/FormRenderer.res @@ -571,7 +571,7 @@ module SubmitButton = { ~tooltipPositioning: ToolTip.tooltipPositioning=#fixed, ~withDialog=false, ~modalObj: option=?, - ~tooltipWidthClass="w-64", + ~tooltipWidthClass="w-auto", ~tooltipForWidthClass="", ~tooltipForHeight="h-full", ~userInteractionRequired=false, diff --git a/src/context/FilterContext.res b/src/context/FilterContext.res index 74af77545..69fb4f1d6 100644 --- a/src/context/FilterContext.res +++ b/src/context/FilterContext.res @@ -89,6 +89,11 @@ let make = (~index: string, ~children) => { setfilterDict(prev => { let updatedDict = prev->Dict.toArray->Array.copy->Dict.fromArray->DictionaryUtils.deleteKeys(arr) + let updatedDict = if arr == ["amount"] { + updatedDict->DictionaryUtils.deleteKeys(["start_amount", "end_amount"]) + } else { + updatedDict + } let dict = if DictionaryUtils.equalDicts(updatedDict, prev) { prev } else { diff --git a/src/entryPoints/AuthModule/Common/CommonInputFields.res b/src/entryPoints/AuthModule/Common/CommonInputFields.res index a66abafeb..214e791ad 100644 --- a/src/entryPoints/AuthModule/Common/CommonInputFields.res +++ b/src/entryPoints/AuthModule/Common/CommonInputFields.res @@ -100,3 +100,79 @@ let passwordField = FormRenderer.makeFieldInfo( ), ~isRequired=false, ) + +let startamountField = FormRenderer.makeFieldInfo( + ~label="", + ~name="start_amount", + ~placeholder="0", + ~customInput=InputFields.numericTextInput(), + ~type_="number", +) + +let endAmountField = FormRenderer.makeFieldInfo( + ~label="", + ~name="end_amount", + ~placeholder="0", + ~customInput=InputFields.numericTextInput(), + ~type_="number", +) + +module CustomAmountEqualField = { + @react.component + let make = () => { + let form = ReactFinalForm.useForm() +
+ + InputFields.numericTextInput()( + ~input={ + ...input, + onChange: { + ev => { + form.change("end_amount", ev->Identity.genericTypeToJson) + input.onChange(ev) + } + }, + }, + ~placeholder="0", + ) + )} + /> +
+ } +} + +module CustomAmountBetweenField = { + @react.component + let make = () => { + let form = ReactFinalForm.useForm() +
+ + InputFields.numericTextInput()( + ~input={ + ...input, + onChange: { + ev => { + form.change("end_amount", 0->Identity.genericTypeToJson) + input.onChange(ev) + } + }, + }, + ~placeholder="0", + ) + )} + /> +

{"and"->React.string}

+ +
+ } +} diff --git a/src/screens/Order/OrderTypes.res b/src/screens/Order/OrderTypes.res index 1db8cd841..cffd4bfb0 100644 --- a/src/screens/Order/OrderTypes.res +++ b/src/screens/Order/OrderTypes.res @@ -282,8 +282,47 @@ type optionObj = { type frmStatus = [#APPROVE | #REJECT] +type amountFilter = + | GreaterThanEqualTo + | LessThanEqualTo + | EqualTo + | InBetween + | UnknownRange(string) + +type amountFields = + | StartAmount + | EndAmount + | UnknownValidateFields(string) + +let validationFieldsMapper = key => { + switch key { + | StartAmount => "start_amount" + | EndAmount => "end_amount" + | UnknownValidateFields(key) => key + } +} + let getSortString = (value: LoadedTable.sortOb) => switch value.sortType { | ASC => "asc" | DSC => "desc" } + +let mapStringToRange = val => + switch val { + | "Greater than Equal to" => GreaterThanEqualTo + | "Less than Equal to" => LessThanEqualTo + | "Equal to" => EqualTo + | "In Between" => InBetween + | _ => UnknownRange(val) + } + +let mapRangeTypetoString = amountFilter => { + switch amountFilter { + | GreaterThanEqualTo => "Greater than Equal to" + | LessThanEqualTo => "Less than Equal to" + | EqualTo => "Equal to" + | InBetween => "In Between" + | UnknownRange(string) => string + } +} diff --git a/src/screens/Order/OrderUIUtils.res b/src/screens/Order/OrderUIUtils.res index 1a3634e65..c3df27292 100644 --- a/src/screens/Order/OrderUIUtils.res +++ b/src/screens/Order/OrderUIUtils.res @@ -1,3 +1,4 @@ +open OrderTypes type filterTypes = { connector: array, currency: array, @@ -8,6 +9,7 @@ type filterTypes = { connector_label: array, card_network: array, customer_id: array, + amount: array, } type filter = [ @@ -20,6 +22,7 @@ type filter = [ | #connector_label | #card_network | #customer_id + | #amount | #unknown ] @@ -34,6 +37,7 @@ let getFilterTypeFromString = filterType => { | "connector_label" => #connector_label | "card_network" => #card_network | "customer_id" => #customer_id + | "amount" => #amount | _ => #unknown } } @@ -270,6 +274,7 @@ let itemToObjMapper = dict => { connector_label: [], card_network: dict->getArrayFromDict("card_network", [])->getStrArrayFromJsonArray, customer_id: [], + amount: [], } } @@ -290,6 +295,7 @@ let initialFilters = (json, filtervalues, removeKeys, filterKeys, setfilterKeys) } arr->Array.push("payment_method_type") arr->Array.push("customer_id") + arr->Array.push("amount") arr->Array.map((key): EntityType.initialFilters<'t> => { let values = switch key->getFilterTypeFromString { | #connector => filterArr.connector @@ -316,6 +322,19 @@ let initialFilters = (json, filtervalues, removeKeys, filterKeys, setfilterKeys) }) } + let amountFilterOptions: array = [ + GreaterThanEqualTo, + LessThanEqualTo, + EqualTo, + InBetween, + ]->Array.map(option => { + let label = option->mapRangeTypetoString + { + FilterSelectBox.label, + value: label, + } + }) + let options = switch key->getFilterTypeFromString { | #connector_label => getOptionsForOrderFilters(filterDict, filtervalues) | _ => values->makeOptions @@ -335,6 +354,10 @@ let initialFilters = (json, filtervalues, removeKeys, filterKeys, setfilterKeys)
, )(~input, ~placeholder=`Enter ${input.name->snakeToTitle}...`) + | #amount => + (~input as _, ~placeholder as _) => { + + } | _ => InputFields.filterMultiSelectInput( @@ -512,3 +535,26 @@ let orderViewList: OMPSwitchTypes.ompViews = [ entity: #Profile, }, ] + +let deleteNestedKeys = (dict: Dict.t<'a>, keys: array) => { + keys->Array.forEach(key => dict->Dict.delete(key)) +} + +let validateForm = (values, ~fieldsToValidate: array) => { + let errors = Dict.make() + open LogicUtils + let valuesDict = values->JsonFlattenUtils.flattenObject(false) + let amountValues = fieldsToValidate->Array.map(key => { + valuesDict->getJsonObjectFromDict(key->validationFieldsMapper) + }) + let start_amount = amountValues->getValueFromArray(0, JSON.Encode.null) + let end_amount = amountValues->getValueFromArray(1, JSON.Encode.null) + if start_amount->isNullJson && end_amount->isNullJson { + errors->Dict.set("Invalid", "Please enter value."->JSON.Encode.string) + } else if !isNullJson(start_amount) && !isNullJson(end_amount) { + if end_amount < start_amount { + errors->Dict.set("Invalid", "Please enter valid range."->JSON.Encode.string) + } + } + errors->JSON.Encode.object +} diff --git a/src/screens/Order/Orders.res b/src/screens/Order/Orders.res index 882e50d5a..0cb33150d 100644 --- a/src/screens/Order/Orders.res +++ b/src/screens/Order/Orders.res @@ -53,13 +53,34 @@ let make = (~previewOnly=false) => { ]->getJsonFromArrayOfJson, ) } - + let encodeFloatOrDefault = val => (val->getFloatFromJson(0.0) *. 100.0)->JSON.Encode.float + filters->Dict.set( + "amount_filter", + [ + ( + "start_amount", + getvalFromDict(dict, "start_amount")->mapOptionOrDefault( + JSON.Encode.null, + encodeFloatOrDefault, + ), + ), + ( + "end_amount", + getvalFromDict(dict, "end_amount")->mapOptionOrDefault( + JSON.Encode.null, + encodeFloatOrDefault, + ), + ), + ]->getJsonFromArrayOfJson, + ) dict ->Dict.toArray ->Array.forEach(item => { let (key, value) = item filters->Dict.set(key, value) }) + filters->OrderUIUtils.deleteNestedKeys(["start_amount", "end_amount"]) + filters ->getOrdersList( ~updateDetails, diff --git a/src/screens/Order/OrdersHelper.res b/src/screens/Order/OrdersHelper.res new file mode 100644 index 000000000..366fd57c6 --- /dev/null +++ b/src/screens/Order/OrdersHelper.res @@ -0,0 +1,66 @@ +open CommonAuthForm +open CommonInputFields +open OrderTypes +@react.component +let make = (~options) => { + let (selectedOption, setSelectedOption) = React.useState(_ => UnknownRange("Select Amount")) + let form = ReactFinalForm.useForm() + let input: ReactFinalForm.fieldRenderPropsInput = { + name: "amount", + onBlur: _ => (), + onChange: ev => { + let newValue = ev->Identity.formReactEventToString + if newValue != selectedOption->mapRangeTypetoString && newValue->LogicUtils.isNonEmptyString { + setSelectedOption(_ => newValue->mapStringToRange) + form.change("start_amount", JSON.Encode.null) + form.change("end_amount", JSON.Encode.null) + } + }, + onFocus: _ => (), + value: { + selectedOption->mapRangeTypetoString->JSON.Encode.string + }, + checked: true, + } + + let renderCommonFields = field => +
+ +
+ + let renderFields = () => + switch selectedOption { + | GreaterThanEqualTo => renderCommonFields(startamountField) + | LessThanEqualTo => renderCommonFields(endAmountField) + | EqualTo => + | InBetween => + | _ => React.null + } + + <> + mapRangeTypetoString} + buttonType=Button.SecondaryFilled + input + options + hideMultiSelectButtons=true + showSelectionAsChips={false} + fullLength=true + customButtonStyle="bg-white rounded-md !px-4 !py-2 !h-10" + /> + { +
+ {renderFields()} + +
+
} + +} diff --git a/src/utils/LogicUtils.res b/src/utils/LogicUtils.res index 89b12d803..197d85877 100644 --- a/src/utils/LogicUtils.res +++ b/src/utils/LogicUtils.res @@ -210,6 +210,10 @@ let getJsonObjectFromDict = (dict, key) => { dict->Dict.get(key)->Option.getOr(JSON.Encode.object(Dict.make())) } +let getvalFromDict = (dict, key) => { + dict->Dict.get(key) +} + let getBoolFromString = (boolString, default: bool) => { switch boolString->String.toLowerCase { | "true" => true @@ -338,6 +342,8 @@ let setOptionDict = (dict, key, optionDictValue) => let setOptionInt = (dict, key, optionInt) => optionInt->Option.mapOr((), int => dict->Dict.set(key, int->JSON.Encode.int)) +let mapOptionOrDefault = (t, defaultVal, func) => t->Option.mapOr(defaultVal, value => value->func) + let capitalizeString = str => { String.toUpperCase(String.charAt(str, 0)) ++ Js.String2.substringToEnd(str, ~from=1) } @@ -500,6 +506,10 @@ let isEmptyDict = dict => { dict->Dict.keysToArray->Array.length === 0 } +let isNullJson = val => { + val == JSON.Encode.null || checkEmptyJson(val) +} + let stringReplaceAll = (str, old, new) => { str->String.split(old)->Array.joinWith(new) } diff --git a/tailwind.config.js b/tailwind.config.js index d901773fb..280a9a106 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -64,6 +64,7 @@ module.exports = { "1.1-rem": "1.125rem", "77-rem": "77rem", "30-rem": "30rem", + "10.25-rem": "10.25rem", pageWidth11: "75rem", fixedPageWidth: "75.5rem",