Enhanced Firestore sync in form fields

This commit is contained in:
francesco
2020-06-24 01:03:50 +02:00
parent b0613d3aae
commit beba796268
4 changed files with 44 additions and 22 deletions

View File

@@ -51,12 +51,11 @@ export default function EntityForm<S extends EntitySchema>({
const [customId, setCustomId] = React.useState<string | undefined>(undefined);
const [customIdError, setCustomIdError] = React.useState<boolean>(false);
const [savingError, setSavingError] = React.useState<any>();
/**
* Base values are the ones this view is initialized from, we use them to
* compare them with underlying changes in Firestore
*/
// const [baseValues, setBaseValues] = React.useState<EntityValues<S>>();
let baseValues: EntityValues<S>;
if (status === EntityStatus.new) {
baseValues = (initEntityValues(schema));
@@ -70,6 +69,8 @@ export default function EntityForm<S extends EntitySchema>({
function saveValues(values: EntityValues<S>, actions: FormikHelpers<EntityValues<S>>) {
console.log("Saving values", values);
if (mustSetCustomId && !customId) {
console.error("Missing custom Id");
setCustomIdError(true);
@@ -93,6 +94,7 @@ export default function EntityForm<S extends EntitySchema>({
}
onEntitySave(collectionPath, id, values)
.then(_ => actions.setTouched({}))
.catch(e => {
console.error(e);
setSavingError(e);
@@ -103,24 +105,33 @@ export default function EntityForm<S extends EntitySchema>({
}
return (
<Formik
initialValues={baseValues as EntityValues<S>}
onSubmit={saveValues}
validationSchema={getYupObjectSchema(schema.properties)}
>
{({ values, setFieldValue, errors, touched, handleChange, handleBlur, handleSubmit, isSubmitting }) => {
{({ values, touched, setFieldValue, setFieldTouched, handleSubmit, isSubmitting }) => {
let underlyingValuesChanged: [string, unknown][] = [];
if (baseValues && entity) {
underlyingValuesChanged = Object.entries(entity.values).filter(([key, value]) => !deepEqual(baseValues[key], value));
underlyingValuesChanged = Object.entries(entity.values)
.filter(([key, value]) => !deepEqual(baseValues[key], value));
// we update the form fields from the Firestore data
// if they were not touched
Object.entries(entity.values).forEach(([key, value]) => {
if (!deepEqual(values[key], value) && !touched[key])
setFieldValue(key, value);
const objectKeys = Object.entries(schema.properties)
.map(([key, property]) => key);
objectKeys.forEach((key) => {
const firestoreValue = entity.values[key];
const formValue = values[key];
if (!deepEqual(firestoreValue, formValue) && !touched[key]) {
setFieldValue(key, !!firestoreValue ? firestoreValue : null);
setFieldTouched(key, false);
}
});
}
function createFormFields(schema: EntitySchema) {

View File

@@ -23,12 +23,14 @@ export default function DisabledField<S extends EntitySchema>({ field, property,
</FormHelperText>
<Paper elevation={0} className={classes.paper} variant={"outlined"}>
{hasValue &&
<PreviewComponent value={value}
property={property}
small={false}/>}
{!hasValue && <Box m={1}>No value set</Box>}
{!hasValue && <Box>No value set</Box>}
</Paper>
{includeDescription && property.description &&

View File

@@ -29,6 +29,7 @@ import { CMSFieldProps } from "../form_props";
import { useDropzone } from "react-dropzone";
import ClearIcon from "@material-ui/icons/Clear";
import PreviewComponent from "../../preview/PreviewComponent";
import deepEqual from "deep-equal";
type StorageUploadFieldProps = CMSFieldProps<string | string[]> ;
@@ -58,6 +59,8 @@ export default function StorageUploadField({
const value = multipleFilesSupported ?
(Array.isArray(field.value) ? field.value : []) :
field.value;
console.log("StorageUploadField", value);
return (
@@ -117,7 +120,7 @@ export function StorageUpload({
const classes = formStyles();
const initialValue: StorageFieldItem[] = multipleFilesSupported ?
const internalInitialValue: StorageFieldItem[] = multipleFilesSupported ?
(value as string[]).map(v => (
{
storagePath: v
@@ -126,7 +129,12 @@ export function StorageUpload({
storagePath: value as string
}];
const [internalValue, setInternalValue] = React.useState<StorageFieldItem[]>(initialValue);
const [initialValue, setInitialValue] = React.useState<string| string[]>(value);
const [internalValue, setInternalValue] = React.useState<StorageFieldItem[]>(internalInitialValue);
if (!deepEqual(initialValue, value)) {
setInitialValue(value)
setInternalValue(internalInitialValue);
}
function removeDuplicates(items: StorageFieldItem[]) {
return items.filter(
@@ -222,7 +230,7 @@ export function StorageUpload({
flexDirection="row"
flexWrap="wrap"
alignItems="center"
minHeight={220}>
minHeight={250}>
{internalValue.map(entry => {
if (entry.storagePath) {
@@ -378,8 +386,8 @@ export function StorageItemPreview({
variant={"outlined"}>
<Box position={"absolute"}
top={4}
right={4}
top={-8}
right={-8}
style={{ zIndex: 100 }}>
<IconButton
style={{ backgroundColor: "white" }}

View File

@@ -23,7 +23,6 @@ import ArrayDefaultField from "./fields/ArrayDefaultField";
import ArrayMapField from "./fields/ArrayMapField";
import DisabledField from "./fields/DisabledField";
import { CMSFieldProps } from "./form_props";
import { Alert } from "@material-ui/lab";
function buildField<P extends Property<T>, T = any>(name: string,
@@ -49,11 +48,9 @@ function buildField<P extends Property<T>, T = any>(name: string,
</Field>
{underlyingValueHasChanged &&
<Alert>
<FormHelperText>
This value has been updated in Firestore
</FormHelperText>
</Alert>}
<FormHelperText>
This value has been updated in Firestore
</FormHelperText>}
</React.Fragment>;
}
@@ -129,7 +126,8 @@ export function createCustomIdField(schema: EntitySchema, formType: EntityStatus
};
return (
<FormControl fullWidth error={error} {...fieldProps}>
<FormControl fullWidth error={error} {...fieldProps}
key={"custom-id-field"}>
{hasEnumValues && schema.customId &&
<React.Fragment>
@@ -141,7 +139,10 @@ export function createCustomIdField(schema: EntitySchema, formType: EntityStatus
onChange={(event: any) => onChange(event.target.value)}>
{Object.entries(schema.customId).map(([key, label]) =>
<MenuItem
value={key}>{`${key} - ${label}`}</MenuItem>)}
key={`custom-id-item-${key}`}
value={key}>
{`${key} - ${label}`}
</MenuItem>)}
</MuiSelect>
</React.Fragment>}