Skip to content

Commit

Permalink
feat: abstracts select component
Browse files Browse the repository at this point in the history
  • Loading branch information
jacobsfletch committed Nov 29, 2021
1 parent 615e369 commit fa67137
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 83 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useCallback, useState } from 'react';
import SelectInput from '../../../../../../../src/admin/components/forms/field-types/Select';
import React, { useCallback } from 'react';
import SelectInput from '../../../../../../../src/admin/components/forms/field-types/Select/Input';
import { Props as SelectFieldType } from '../../../../../../../src/admin/components/forms/field-types/Select/types';
import useField from '../../../../../../../src/admin/components/forms/useField';

Expand All @@ -8,38 +8,43 @@ const Select: React.FC<SelectFieldType> = (props) => {
path,
name,
label,
options
options,
} = props;

const {
showError,
value,
setValue
setValue,
} = useField({
path
path,
});

const onChange = useCallback((incomingValue) => {
const onChange = useCallback((incomingOption) => {
const { value: incomingValue } = incomingOption;

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

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

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

return (
<SelectInput
Expand All @@ -48,8 +53,9 @@ const Select: React.FC<SelectFieldType> = (props) => {
options={options}
value={value as string}
onChange={onChange}
showError={showError}
/>
)
);
};

export default Select;
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const Text: React.FC<TextFieldType> = (props) => {
return (
<TextInput
name={name}
value={value as string}
value={value as string || ''}
label={label}
onChange={onChange}
showError={showError}
Expand Down
2 changes: 1 addition & 1 deletion demo/collections/CustomComponents/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const CustomComponents: CollectionConfig = {
},
{
name: 'select',
label: 'Custom select field (sends value to crm)',
label: 'Custom select field (syncs value with crm)',
type: 'select',
localized: true,
options: [
Expand Down
10 changes: 6 additions & 4 deletions src/admin/components/elements/ReactSelect/types.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import { OptionsType, GroupedOptionsType } from 'react-select';

export type Options = OptionsType<Value> | GroupedOptionsType<Value>;

export type Value = {
label: string
value: any
options?: Value[]
value: string
options?: Options
}

export type Props = {
className?: string
value?: Value | Value[],
onChange?: (value: any) => void,
onChange?: (value: Value) => void,
disabled?: boolean,
showError?: boolean,
options: OptionsType<Value> | GroupedOptionsType<Value>
options: Options
isMulti?: boolean,
isDisabled?: boolean
onInputChange?: (val: string) => void
Expand Down
87 changes: 87 additions & 0 deletions src/admin/components/forms/field-types/Select/Input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from 'react';
import Label from '../../Label';
import Error from '../../Error';
import FieldDescription from '../../FieldDescription';
import { SelectField } from '../../../../../fields/config/types';
import { Description } from '../../FieldDescription/types';
import ReactSelect from '../../../elements/ReactSelect';
import { Value as ReactSelectValue, Options as ReactSelectOptions } from '../../../elements/ReactSelect/types';
// import { FieldType } from '../../useField/types';

import './index.scss';

export type SelectInputProps = Omit<SelectField, 'type' | 'value'> & {
showError: boolean
errorMessage?: string
readOnly?: boolean
path?: string
required?: boolean
value?: string
description?: Description
onChange?: (value: ReactSelectValue) => void
style?: React.CSSProperties
width?: string
hasMany?: boolean
options?: ReactSelectOptions
}

const SelectInput: React.FC<SelectInputProps> = (props) => {
const {
showError,
errorMessage,
readOnly,
path,
label,
required,
value,
onChange,
description,
style,
width,
options,
hasMany,
} = props;

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

const selectedOption = options.find((option) => option.value === value);

return (
<div
className={classes}
style={{
...style,
width,
}}
>
<Error
showError={showError}
message={errorMessage}
/>
<Label
htmlFor={path}
label={label}
required={required}
/>
<ReactSelect
onChange={onChange}
value={selectedOption}
showError={showError}
isDisabled={readOnly}
options={options}
isMulti={hasMany}
/>
<FieldDescription
value={value}
description={description}
/>
</div>
);
};

export default SelectInput;
67 changes: 18 additions & 49 deletions src/admin/components/forms/field-types/Select/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
import React, { useCallback, useState, useEffect } from 'react';
import React, { useCallback, useState } from 'react';
import withCondition from '../../withCondition';
import ReactSelect from '../../../elements/ReactSelect';
import useField from '../../useField';
import Label from '../../Label';
import Error from '../../Error';
import FieldDescription from '../../FieldDescription';
import { select } from '../../../../../fields/validations';
import { Option } from '../../../../../fields/config/types';
import { Props, Option as ReactSelectOption } from './types';

import './index.scss';

const baseClass = 'select';
import { Props, ReactSelectOption } from './types';
import SelectInput from './Input';

const formatOptions = (options: Option[]): ReactSelectOption[] => options.map((option) => {
if (typeof option === 'object' && option.value) {
Expand Down Expand Up @@ -41,7 +34,7 @@ const Select: React.FC<Props> = (props) => {
condition,
} = {},
value: valueFromProps,
onChange: onChangeFromProps
onChange: onChangeFromProps,
} = props;

const path = pathFromProps || name;
Expand Down Expand Up @@ -87,15 +80,8 @@ const Select: React.FC<Props> = (props) => {
readOnly,
hasMany,
onChangeFromProps,
setValue
])

const classes = [
'field-type',
baseClass,
showError && 'error',
readOnly && `${baseClass}--read-only`,
].filter(Boolean).join(' ');
setValue,
]);

let valueToRender;

Expand All @@ -108,35 +94,18 @@ const Select: React.FC<Props> = (props) => {
}

return (
<div
className={classes}
style={{
...style,
width,
}}
>
<Error
showError={showError}
message={errorMessage}
/>
<Label
htmlFor={path}
label={label}
required={required}
/>
<ReactSelect
onChange={onChange}
value={valueToRender}
showError={showError}
isDisabled={readOnly}
options={options}
isMulti={hasMany}
/>
<FieldDescription
value={value}
description={description}
/>
</div>
<SelectInput
onChange={onChange}
value={valueToRender}
name={name}
options={options}
label={label}
showError={showError}
errorMessage={errorMessage}
description={description}
style={style}
width={width}
/>
);
};

Expand Down
5 changes: 0 additions & 5 deletions src/admin/components/forms/field-types/Select/types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { SelectField } from '../../../../../fields/config/types';

export type Option = {
label: string
value: any
}

export type Props = Omit<SelectField, 'type'> & {
path?: string
}
2 changes: 0 additions & 2 deletions src/admin/components/forms/field-types/Text/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import { text } from '../../../../../fields/validations';
import { Props } from './types';
import TextInput from './Input';

import './index.scss';

const Text: React.FC<Props> = (props) => {
const {
path: pathFromProps,
Expand Down
7 changes: 3 additions & 4 deletions src/admin/components/forms/useField/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ const useField = <T extends unknown>(options: Options): FieldType<T> => {
ignoreWhileFlattening,
initialValue,
stringify,
condition
condition,
]);

// Method to return from `useField`, used to
Expand All @@ -91,12 +91,11 @@ const useField = <T extends unknown>(options: Options): FieldType<T> => {
setModified(true);
}
}

setInternalValue(val);
}, [
setModified,
modified,
ignoreWhileFlattening
ignoreWhileFlattening,
]);

useEffect(() => {
Expand All @@ -116,7 +115,7 @@ const useField = <T extends unknown>(options: Options): FieldType<T> => {
}, [
valueToSend,
sendField,
field
field,
]);

return {
Expand Down
5 changes: 1 addition & 4 deletions src/fields/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,10 @@ export type Labels = {

export type Validate<T = any> = (value?: T, options?: any) => string | true | Promise<string | true>;

export type OptionObject = {
export type Option = {
label: string
value: string
}

export type Option = OptionObject | string

export interface FieldBase {
name: string;
label?: string | false;
Expand Down

0 comments on commit fa67137

Please sign in to comment.