Skip to content

Commit

Permalink
feat: supports custom onChange handling in text, select, and upload f…
Browse files Browse the repository at this point in the history
…ields
  • Loading branch information
jacobsfletch committed Nov 24, 2021
1 parent 3540a18 commit 4affdc3
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 49 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useState } from 'react';
import React, { useCallback, useState } from 'react';
import SelectInput from '../../../../../../../src/admin/components/forms/field-types/Select';
import { Props as SelectFieldType } from '../../../../../../../src/admin/components/forms/field-types/Select/types';
import useFieldType from '../../../../../../../src/admin/components/forms/useFieldType';

const Select: React.FC<SelectFieldType> = (props) => {
const {
Expand All @@ -10,16 +11,43 @@ const Select: React.FC<SelectFieldType> = (props) => {
options
} = props;

const [internalValue, setInternalValue] = useState('');
const {
value,
setValue
} = useFieldType({
path
});

const onChange = useCallback((incomingValue) => {
const sendToCRM = async () => {
try {
const req = await fetch('https://fake-crm.com', {
method: 'post',
body: JSON.stringify({
someKey: incomingValue
})
});

const res = await req.json();
if (res.ok) {
console.log('Successfully synced to CRM.')
}
} catch (e) {
console.error(e);
}
}

sendToCRM();
setValue(incomingValue)
}, [])

return (
<SelectInput
path={path}
name={name}
label={label}
options={options}
value={internalValue}
onChange={setInternalValue}
value={value as string}
onChange={onChange}
/>
)
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useCallback, useState } from 'react';
import TextInput from '../../../../../../../src/admin/components/forms/field-types/Text';
import { Props as TextFieldType } from '../../../../../../../src/admin/components/forms/field-types/Text/types';
import useFieldType from '../../../../../../../src/admin/components/forms/useFieldType';

const Text: React.FC<TextFieldType> = (props) => {
const {
Expand All @@ -9,19 +10,24 @@ const Text: React.FC<TextFieldType> = (props) => {
label
} = props;

const [internalValue, setInternalValue] = useState('');
const {
value,
setValue
} = useFieldType({
path
});

const middleware = useCallback((incomingValue) => {
setInternalValue(`Hello, world: ${incomingValue}`)
const onChange = useCallback((incomingValue) => {
const valueWithoutSpaces = incomingValue.replace(/\s/g, '');
setValue(valueWithoutSpaces)
}, [])

return (
<TextInput
path={path}
name={name}
label={label}
value={internalValue}
onChange={middleware}
value={value as string}
onChange={onChange}
/>
)
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React, { useCallback } from 'react';
import TextInput from '../../../../../../../src/admin/components/forms/field-types/Text';
import { UIField as UIFieldType } from '../../../../../../../src/fields/config/types';
import SelectInput from '../../../../../../../src/admin/components/forms/field-types/Select';

const UIField: React.FC<UIFieldType> = () => {
const [textValue, setTextValue] = React.useState('');
const [selectValue, setSelectValue] = React.useState('');

const onTextChange = useCallback((incomingValue) => {
setTextValue(incomingValue);
}, [])

const onSelectChange = useCallback((incomingValue) => {
setSelectValue(incomingValue);
}, [])

return (
<div>
<TextInput
name="ui-text"
label="Presentation-only text field (does not submit)"
value={textValue as string}
onChange={onTextChange}
/>
<SelectInput
name="ui-select"
label="Presentation-only select field (does not submit)"
options={[
{
label: 'Option 1',
value: 'option-1'
},
{
label: 'Option 2',
value: 'option-2'
},
{
label: 'Option 3',
value: 'option-4'
}
]}
value={selectValue as string}
onChange={onSelectChange}
/>
</div>
)
};

export default UIField;
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useState } from 'react';
import React, { useCallback, useState } from 'react';
import Upload from '../../../../../../../src/admin/components/forms/field-types/Upload';
import { Props as UploadFieldType } from '../../../../../../../src/admin/components/forms/field-types/Upload/types';
import useFieldType from '../../../../../../../src/admin/components/forms/useFieldType';

const Text: React.FC<UploadFieldType> = (props) => {
const {
Expand All @@ -11,17 +12,25 @@ const Text: React.FC<UploadFieldType> = (props) => {
fieldTypes
} = props;

const [internalValue, setInternalValue] = useState('');
const {
value,
setValue
} = useFieldType({
path
});

const onChange = useCallback((incomingValue) => {
setValue(incomingValue)
}, [])

return (
<Upload
relationTo={relationTo}
fieldTypes={fieldTypes}
path={path}
name={name}
label={label}
value={internalValue}
onChange={setInternalValue}
value={value as string}
onChange={onChange}
/>
)
};
Expand Down
15 changes: 13 additions & 2 deletions demo/collections/CustomComponents/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import NestedArrayField from './components/fields/NestedArrayCustomField/Field';
import GroupField from './components/fields/Group/Field';
import NestedGroupField from './components/fields/NestedGroupCustomField/Field';
import NestedText1Field from './components/fields/NestedText1/Field';
import UIField from './components/fields/UI/Field';
import ListView from './components/views/List';
import CustomDescriptionComponent from '../../customComponents/Description';

Expand All @@ -30,7 +31,7 @@ const CustomComponents: CollectionConfig = {
},
{
name: 'text',
label: 'Text',
label: 'Custom text field (removes whitespace)',
type: 'text',
required: true,
localized: true,
Expand All @@ -42,7 +43,7 @@ const CustomComponents: CollectionConfig = {
},
{
name: 'select',
label: 'Select',
label: 'Custom select field (sends value to crm)',
type: 'select',
localized: true,
options: [
Expand All @@ -65,6 +66,16 @@ const CustomComponents: CollectionConfig = {
},
},
},
{
name: 'ui',
label: 'UI',
type: 'ui',
admin: {
components: {
Field: UIField,
},
},
},
{
name: 'upload',
label: 'Upload',
Expand Down
10 changes: 3 additions & 7 deletions src/admin/components/forms/field-types/Select/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const Select: React.FC<Props> = (props) => {
}, [validate, required, options]);

const {
value,
value: valueFromContext,
showError,
setValue,
errorMessage,
Expand Down Expand Up @@ -90,12 +90,6 @@ const Select: React.FC<Props> = (props) => {
setValue
])

useEffect(() => {
if (typeof valueFromProps === 'string') {
setValue(valueFromProps);
}
}, [valueFromProps])

const classes = [
'field-type',
baseClass,
Expand All @@ -105,6 +99,8 @@ const Select: React.FC<Props> = (props) => {

let valueToRender;

const value = valueFromProps || valueFromContext || '';

if (hasMany && Array.isArray(value)) {
valueToRender = value.map((val) => options.find((option) => option.value === val));
} else {
Expand Down
15 changes: 6 additions & 9 deletions src/admin/components/forms/field-types/Text/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,36 +38,33 @@ const Text: React.FC<Props> = (props) => {
});

const {
value,
value: valueFromContext,
showError,
setValue,
errorMessage,
} = fieldType;

const onChange = useCallback((e) => {
const { value: incomingValue } = e.target;
setValue(e);
if (typeof onChangeFromProps === 'function') {
onChangeFromProps(incomingValue);
} else {
setValue(e);
}
}, [
onChangeFromProps,
setValue,
]);

useEffect(() => {
if (typeof valueFromProps === 'string') {
setValue(valueFromProps);
}
}, [valueFromProps])

const classes = [
'field-type',
'text',
showError && 'error',
readOnly && 'read-only',
].filter(Boolean).join(' ');

const value = valueFromProps || valueFromContext || '';

return (
<div
className={classes}
Expand All @@ -86,7 +83,7 @@ const Text: React.FC<Props> = (props) => {
required={required}
/>
<input
value={value || ''}
value={value}
onChange={onChange}
disabled={readOnly}
placeholder={placeholder}
Expand Down
12 changes: 5 additions & 7 deletions src/admin/components/forms/field-types/Upload/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,14 @@ const Upload: React.FC<Props> = (props) => {
});

const {
value,
value: valueFromContext,
showError,
setValue,
errorMessage,
} = fieldType;

const value = valueFromProps || valueFromContext || '';

const classes = [
'field-type',
baseClass,
Expand All @@ -83,7 +85,6 @@ const Upload: React.FC<Props> = (props) => {
setInternalValue(json);
} else {
setInternalValue(undefined);
setValue(null);
setMissingFile(true);
}
};
Expand All @@ -92,7 +93,6 @@ const Upload: React.FC<Props> = (props) => {
}
}, [
value,
setInternalValue,
relationTo,
api,
serverURL,
Expand All @@ -108,8 +108,6 @@ const Upload: React.FC<Props> = (props) => {
}
}, [internalValue]);

const valueToUse = valueFromProps || value || '';

return (
<div
className={classes}
Expand Down Expand Up @@ -139,7 +137,7 @@ const Upload: React.FC<Props> = (props) => {
}}
/>
)}
{(!valueToUse || missingFile) && (
{(!value || missingFile) && (
<div className={`${baseClass}__wrap`}>
<Button
buttonStyle="secondary"
Expand Down Expand Up @@ -182,7 +180,7 @@ const Upload: React.FC<Props> = (props) => {
}}
/>
<FieldDescription
value={valueToUse}
value={value}
description={description}
/>
</React.Fragment>
Expand Down
Loading

0 comments on commit 4affdc3

Please sign in to comment.