implements readOnly on more fields, fixes bugs with relationship

This commit is contained in:
James
2020-07-28 19:32:41 -04:00
parent f4127e1820
commit 455f2ab183
8 changed files with 154 additions and 54 deletions

View File

@@ -50,7 +50,7 @@ const Checkbox = (props) => {
baseClass,
showError && 'error',
value && `${baseClass}--checked`,
readOnly && 'read-only',
readOnly && `${baseClass}--read-only`,
].filter(Boolean).join(' ');
return (
@@ -74,7 +74,7 @@ const Checkbox = (props) => {
/>
<button
type="button"
onClick={() => {
onClick={readOnly ? undefined : () => {
setValue(!value);
if (typeof onChange === 'function') onChange(!value);
}}

View File

@@ -55,4 +55,10 @@
}
}
}
&--read-only {
&__input {
background-color: lighten($color-gray, 5%);
}
}
}

View File

@@ -61,17 +61,27 @@
}
.radio-group--read-only {
.radio-input__label {
color: $color-gray;
}
.radio-input {
&__label {
color: $color-gray;
}
.radio-input--is-selected {
.radio-input {
&__styled-radio {
&--is-selected {
.radio-input__styled-radio {
&:before {
background-color: $color-gray;
}
}
}
&:not(&--is-selected) {
&:hover {
.radio-input__styled-radio {
&:before {
opacity: 0;
}
}
}
}
}
}

View File

@@ -34,6 +34,7 @@ class Relationship extends Component {
lastLoadedPage: 1,
options: [],
errorLoading: false,
loadedIDs: [],
};
}
@@ -41,11 +42,15 @@ class Relationship extends Component {
this.getNextOptions();
}
componentDidUpdate(prevProps, prevState) {
const { search } = this.state;
componentDidUpdate(_, prevState) {
const { search, options } = this.state;
if (search !== prevState.search) {
this.getNextOptions({ clear: true });
}
if (options !== prevState.options) {
this.ensureValueHasOption();
}
}
getNextOptions = (params = {}) => {
@@ -55,6 +60,8 @@ class Relationship extends Component {
if (clear) {
this.setState({
options: [],
loadedIDs: [],
lastFullyLoadedRelation: -1,
});
}
@@ -63,7 +70,7 @@ class Relationship extends Component {
relations, lastFullyLoadedRelation, lastLoadedPage, search,
} = this.state;
const relationsToSearch = relations.slice(lastFullyLoadedRelation + 1);
const relationsToSearch = lastFullyLoadedRelation === -1 ? relations : relations.slice(lastFullyLoadedRelation + 1);
if (relationsToSearch.length > 0) {
some(relationsToSearch, async (relation, callback) => {
@@ -97,6 +104,9 @@ class Relationship extends Component {
if (nextPage) {
const { data, relation } = nextPage;
this.addOptions(data, relation);
this.setState({
lastLoadedPage: lastLoadedPage + 1,
});
} else {
const { data, relation } = lastPage;
this.addOptions(data, relation);
@@ -154,61 +164,116 @@ class Relationship extends Component {
addOptions = (data, relation) => {
const { hasMultipleRelations } = this.props;
const { lastLoadedPage, options } = this.state;
const { options, loadedIDs } = this.state;
const collection = collections.find((coll) => coll.slug === relation);
if (!hasMultipleRelations) {
this.setState({
options: [
...options,
...data.docs.map((doc) => ({
label: doc[collection?.admin?.useAsTitle || 'id'],
value: doc.id,
})),
],
});
} else {
const allOptionGroups = [...options];
const optionsToAddTo = allOptionGroups.find((optionGroup) => optionGroup.label === collection.labels.plural);
const newlyLoadedIDs = [];
const newOptions = data.docs.map((doc) => ({
label: doc[collection?.admin?.useAsTitle || 'id'],
value: {
relationTo: collection.slug,
value: doc.id,
},
}));
let newOptions = [];
if (!hasMultipleRelations) {
newOptions = [
...options,
...data.docs.reduce((docs, doc) => {
if (loadedIDs.indexOf(doc.id) === -1) {
newlyLoadedIDs.push(doc.id);
return [
...docs,
{
label: doc[collection?.admin?.useAsTitle || 'id'],
value: doc.id,
},
];
}
return docs;
}, []),
];
} else {
newOptions = [...options];
const optionsToAddTo = newOptions.find((optionGroup) => optionGroup.label === collection.labels.plural);
const newSubOptions = data.docs.reduce((docs, doc) => {
if (loadedIDs.indexOf(doc.id) === -1) {
newlyLoadedIDs.push(doc.id);
return [
...docs,
{
label: doc[collection?.admin?.useAsTitle || 'id'],
value: {
relationTo: collection.slug,
value: doc.id,
},
},
];
}
return docs;
}, []);
if (optionsToAddTo) {
optionsToAddTo.options = [
...optionsToAddTo.options,
...newOptions,
...newSubOptions,
];
} else {
allOptionGroups.push({
newOptions.push({
label: collection.labels.plural,
options: newOptions,
options: newSubOptions,
});
}
this.setState({
options: [
...allOptionGroups,
],
});
}
this.setState({
lastLoadedPage: lastLoadedPage + 1,
options: newOptions,
loadedIDs: [
...loadedIDs,
...newlyLoadedIDs,
],
});
}
ensureValueHasOption = async () => {
const { relationTo, hasMany, value } = this.props;
const { options } = this.state;
const locatedValue = this.findValueInOptions(options, value);
const hasMultipleRelations = Array.isArray(relationTo);
if (!locatedValue && value) {
if (hasMany) {
value.forEach((val) => {
if (hasMultipleRelations) {
this.addOptionByID(val.value, val.relationTo);
} else {
this.addOptionByID(val, relationTo);
}
});
} else if (hasMultipleRelations) {
this.addOptionByID(value.value, value.relationTo);
} else {
this.addOptionByID(value, relationTo);
}
}
}
addOptionByID = async (id, relation) => {
const response = await fetch(`${serverURL}${api}/${relation}/${id}`);
const data = await response.json();
this.addOptions({ docs: [data] }, relation);
}
handleInputChange = (search) => {
this.setState({
search,
lastFullyLoadedRelation: -1,
lastLoadedPage: 1,
});
const { search: existingSearch } = this.state;
if (search !== existingSearch) {
this.setState({
search,
lastFullyLoadedRelation: -1,
lastLoadedPage: 1,
});
}
}
handleMenuScrollToBottom = () => {
@@ -240,10 +305,10 @@ class Relationship extends Component {
baseClass,
showError && 'error',
errorLoading && 'error-loading',
readOnly && 'read-only',
readOnly && `${baseClass}--read-only`,
].filter(Boolean).join(' ');
const valueToRender = this.findValueInOptions(options, value);
const valueToRender = this.findValueInOptions(options, value) || value;
return (
<div
@@ -264,6 +329,7 @@ class Relationship extends Component {
/>
{!errorLoading && (
<ReactSelect
isDisabled={readOnly}
onInputChange={this.handleInputChange}
onChange={!readOnly ? setValue : undefined}
formatValue={this.formatSelectedValue}

View File

@@ -11,3 +11,11 @@
background-color: $color-red;
color: white;
}
.relationship--read-only {
div.react-select {
div.rs__control {
background: lighten($color-light-gray, 5%);
}
}
}

View File

@@ -9,6 +9,8 @@ import { select } from '../../../../../fields/validations';
import './index.scss';
const baseClass = 'select';
const findFullOption = (value, options) => {
const matchedOption = options.find((option) => option?.value === value);
@@ -97,9 +99,9 @@ const Select = (props) => {
const classes = [
'field-type',
'select',
baseClass,
showError && 'error',
readOnly && 'read-only',
readOnly && `${baseClass}--read-only`,
].filter(Boolean).join(' ');
const valueToRender = formatRenderValue(value, options);
@@ -126,7 +128,7 @@ const Select = (props) => {
value={valueToRender}
formatValue={formatFormValue}
showError={showError}
disabled={readOnly}
isDisabled={readOnly}
options={options}
isMulti={hasMany}
/>

View File

@@ -3,3 +3,11 @@
.field-type.select {
position: relative;
}
.select--read-only {
div.react-select {
div.rs__control {
background: lighten($color-light-gray, 5%);
}
}
}

View File

@@ -37,8 +37,8 @@
}
&:disabled {
background: $color-light-gray;
color: $color-gray;
background: lighten($color-light-gray, 5%);
color: darken($color-gray, 5%);
&:hover {
border-color: $color-light-gray;