1
1
import Stack from "@mui/material/Stack" ;
2
- import { FastField } from "formik" ;
2
+ import { FastField , Field , getIn , useFormikContext } from "formik" ;
3
3
import { AutocompleteRenderInputParams } from "@mui/material/Autocomplete" ;
4
4
import Typography from "@mui/material/Typography" ;
5
- import { memo } from "react" ;
5
+ import { SyntheticEvent , useRef } from "react" ;
6
+ import * as Yup from "yup" ;
6
7
7
8
import { SelectField } from "@components/SelectField" ;
8
- import { CONDITION_OPERATORS , CONDITION_PROPERTIES_OPTIONS , OPERATOR_OPTIONS } from "../constants" ;
9
+ import { CONDITION_OPERATORS , OPERATOR_OPTIONS } from "../constants" ;
9
10
import { InputWithLabel } from "@components/TextField" ;
10
11
import { AutocompleteField } from "@components/AutocompleteField" ;
12
+ import { FieldPropertySelectOption } from "@hooks/useIntrospectSchema" ;
13
+ import { Promotion } from "types/promotions" ;
14
+ import { SelectOptionType } from "types/common" ;
15
+ import { Type } from "types/schema" ;
11
16
12
17
type ConditionFieldProps = {
13
18
name : string
14
19
index : number
15
20
operator : string
21
+ schemaProperties : FieldPropertySelectOption [ ]
22
+ isLoadingSchema : boolean
16
23
}
17
24
18
- export const ConditionField = memo ( ( { name, index, operator } : ConditionFieldProps ) =>
19
- (
25
+
26
+ export const ConditionField = ( { name, index, operator, isLoadingSchema, schemaProperties } : ConditionFieldProps ) => {
27
+ const { setFieldValue, values } = useFormikContext < Promotion > ( ) ;
28
+
29
+ const selectedProperty = useRef ( schemaProperties . find ( ( option ) => option . value === getIn ( values , `${ name } .path` ) ) || null ) ;
30
+ const availableValueOptions = useRef < string [ ] > ( [ ] ) ;
31
+
32
+ const onPathChange = ( _ : SyntheticEvent , selectedOption : FieldPropertySelectOption | null ) => {
33
+ setFieldValue ( `${ name } .path` , selectedOption ? selectedOption . value : null ) ;
34
+ selectedProperty . current = selectedOption ;
35
+
36
+ if ( selectedOption ?. type === Type . Boolean ) {
37
+ availableValueOptions . current = [ "true" , "false" ] ;
38
+ } else if ( selectedOption ?. enum ) {
39
+ availableValueOptions . current = selectedOption . enum ;
40
+ }
41
+ } ;
42
+
43
+ const getOptionLabel = ( optionValue : string | FieldPropertySelectOption ) => {
44
+ if ( typeof optionValue === "string" ) return schemaProperties . find ( ( option ) => option . value === optionValue ) ?. label || "" ;
45
+ return optionValue . label ;
46
+ } ;
47
+
48
+ const validateConditionValue = ( selectedValues : string [ ] ) => {
49
+ let error ;
50
+ if ( selectedProperty . current ?. type === Type . Number || selectedProperty . current ?. type === Type . Integer ) {
51
+ if ( selectedValues . some ( ( value ) => ! Yup . number ( ) . isValidSync ( value ) ) ) {
52
+ error = "Please enter number values" ;
53
+ }
54
+ if ( typeof selectedProperty . current ?. minimum !== "undefined"
55
+ && selectedValues . some ( ( value ) => ! Yup . number ( ) . min ( Number ( selectedProperty . current ?. minimum ) ) . isValidSync ( value ) ) ) {
56
+ error = `All values must be greater than or equal to ${ selectedProperty . current . minimum } ` ;
57
+ }
58
+ }
59
+ if ( selectedProperty . current ?. format === Type . DateTime && selectedValues . some ( ( value ) => ! Yup . date ( ) . isValidSync ( value ) ) ) {
60
+ error = "Please enter valid date time values" ;
61
+ }
62
+ return error ;
63
+ } ;
64
+
65
+ return (
20
66
< Stack direction = "row" gap = { 1 } alignItems = "center" pl = { 1 } >
21
67
< Stack flexBasis = "30px" >
22
68
{ index > 0 ? < Typography color = "grey.700" variant = "caption" >
23
69
{ CONDITION_OPERATORS [ operator ] ?. fieldPrefix ?. toUpperCase ( ) }
24
70
</ Typography > : null }
25
71
</ Stack >
26
72
< Stack sx = { { flexDirection : { sm : "column" , md : "row" } , gap : { sm : 0 , md : 3 } } } flexGrow = { 1 } >
27
- < FastField
28
- component = { SelectField }
73
+ < Field
29
74
name = { `${ name } .path` }
30
- placeholder = "Property"
31
- ariaLabel = "Property"
32
- hiddenLabel
33
- options = { CONDITION_PROPERTIES_OPTIONS }
34
- displayEmpty
75
+ component = { AutocompleteField }
76
+ options = { schemaProperties }
77
+ loading = { isLoadingSchema }
78
+ isOptionEqualToValue = { ( option : SelectOptionType , value : string ) => ( value ? option . value === value : false ) }
79
+ onChange = { onPathChange }
80
+ getOptionLabel = { getOptionLabel }
81
+ renderInput = { ( params : AutocompleteRenderInputParams ) => (
82
+ < InputWithLabel
83
+ { ...params }
84
+ name = { `${ name } .path` }
85
+ placeholder = "Property"
86
+ ariaLabel = "Property"
87
+ hiddenLabel
88
+ />
89
+ ) }
35
90
/>
36
91
< FastField
37
92
component = { SelectField }
@@ -42,23 +97,24 @@ export const ConditionField = memo(({ name, index, operator }: ConditionFieldPro
42
97
placeholder = "Operator"
43
98
displayEmpty
44
99
/>
45
- < FastField
100
+ < Field
46
101
component = { AutocompleteField }
102
+ validate = { validateConditionValue }
47
103
name = { `${ name } .value` }
48
- freeSolo
104
+ freeSolo = { ! availableValueOptions . current . length }
49
105
multiple
50
- options = { [ ] }
106
+ options = { availableValueOptions . current }
51
107
autoSelect
52
108
renderInput = { ( params : AutocompleteRenderInputParams ) => (
53
109
< InputWithLabel
54
110
{ ...params }
55
- name = " value"
111
+ name = { ` ${ name } . value` }
56
112
placeholder = "Enter Values"
57
113
hiddenLabel
58
114
/>
59
115
) }
60
116
/>
61
117
</ Stack >
62
118
</ Stack >
63
- ) ) ;
64
-
119
+ ) ;
120
+ } ;
0 commit comments