Skip to content

Commit

Permalink
fix(app-headless-cms): update invalid form field tracking [skip ci]
Browse files Browse the repository at this point in the history
  • Loading branch information
Pavel910 committed May 7, 2024
1 parent 43123da commit bbdd960
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ export interface FileProps {
};
description?: string;
}
const File = (props: FileProps) => {

export const File = (props: FileProps) => {
const { url, onRemove, onEdit, placeholder, showFileManager, description } = props;

const styles = props.styles || defaultStyles;
Expand Down Expand Up @@ -104,5 +105,3 @@ const File = (props: FileProps) => {
</>
);
};

export default File;
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { CmsModelFieldRendererPlugin } from "@webiny/app-headless-cms/types";
import { i18n } from "@webiny/app/i18n";
import { FileManager } from "@webiny/app-admin/components";
import { Typography } from "@webiny/ui/Typography";
import File from "./File";
import { File } from "./File";
import { EditFileUsingUrl } from "~/components/EditFileUsingUrl";

const ImageFieldWrapper = styled("div")({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Cell, GridInner } from "@webiny/ui/Grid";
import { FileManager } from "@webiny/app-admin/components";
import styled from "@emotion/styled";
import { imageWrapperStyles } from "./utils";
import File from "./File";
import { File } from "./File";
import { EditFileUsingUrl } from "~/components/EditFileUsingUrl";

const t = i18n.ns("app-headless-cms/admin/fields/file");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"
import pick from "lodash/pick";
import debounce from "lodash/debounce";
import { Prompt } from "@webiny/react-router";
import { Form, FormAPI, FormOnSubmit } from "@webiny/form";
import { Form, FormAPI, FormOnSubmit, FormValidation } from "@webiny/form";
import { CmsContentEntry, CmsModel } from "@webiny/app-headless-cms-common/types";
import { useSnackbar } from "@webiny/app-admin";
import { prepareFormData } from "@webiny/app-headless-cms-common";
Expand Down Expand Up @@ -32,7 +32,7 @@ export interface ContentEntryFormContext {
entry: Partial<CmsContentEntry>;
isDirty: boolean;
saveEntry: (options?: SaveEntryOptions) => Promise<CmsContentEntry | null>;
invalidFields: Record<string, any>;
invalidFields: FormValidation;
}

export const ContentEntryFormContext = React.createContext<ContentEntryFormContext | undefined>(
Expand Down Expand Up @@ -62,6 +62,13 @@ interface ContentEntryFormProviderProps {
children: React.ReactNode;
}

const formValidationToMap = (invalidFields: FormValidation) => {
return Object.keys(invalidFields).reduce(
(acc, key) => ({ ...acc, [key]: invalidFields[key].message }),
{} as Record<string, string | undefined>
);
};

export const ContentEntryFormProvider = ({
model,
entry,
Expand Down Expand Up @@ -177,8 +184,9 @@ export const ContentEntryFormProvider = ({
data={entry}
ref={ref}
invalidFields={invalidFields}
onInvalid={() => {
onInvalid={invalidFields => {
setIsDirty(true);
setInvalidFields(formValidationToMap(invalidFields));
showSnackbar("Some fields did not pass the validation. Please check the form.");
}}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ const {
ContentEntry: { ContentEntryForm, useContentEntry }
} = ContentEntryEditorConfig;

type SaveEntry = ReturnType<typeof ContentEntryForm.useContentEntryForm>["saveEntry"];

export const UseSaveEntryDecorator = ContentEntryForm.useContentEntryForm.createDecorator(
originalHook => {
return function useRecordLockingUseSave() {
Expand All @@ -15,36 +17,39 @@ export const UseSaveEntryDecorator = ContentEntryForm.useContentEntryForm.create
const { fetchLockedEntryLockRecord, updateEntryLock } = useRecordLocking();
const { showSnackbar } = useSnackbar();

const saveEntry = useCallback(async () => {
if (!entry.id) {
return hook.saveEntry();
}

const result = await fetchLockedEntryLockRecord({
id: entry.id,
$lockingType: model.modelId
});

if (result?.lockedBy) {
const lockedBy = result.lockedBy;
showSnackbar(
`It seems that the entry is locked by ${
lockedBy.displayName || lockedBy.id
}. You can't save your changes.`
);
return null;
}

const saveResult = await hook.saveEntry();
if (saveResult) {
await updateEntryLock({
id: saveResult.id,
const saveEntry: SaveEntry = useCallback(
async (...params) => {
if (!entry.id) {
return hook.saveEntry();
}

const result = await fetchLockedEntryLockRecord({
id: entry.id,
$lockingType: model.modelId
});
}

return saveResult;
}, [entry?.id, model.modelId, updateEntryLock]);
if (result?.lockedBy) {
const lockedBy = result.lockedBy;
showSnackbar(
`It seems that the entry is locked by ${
lockedBy.displayName || lockedBy.id
}. You can't save your changes.`
);
return null;
}

const saveResult = await hook.saveEntry(...params);
if (saveResult) {
await updateEntryLock({
id: saveResult.id,
$lockingType: model.modelId
});
}

return saveResult;
},
[entry?.id, model.modelId, updateEntryLock]
);

return {
...hook,
Expand Down
28 changes: 16 additions & 12 deletions packages/form/src/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
FormAPI,
FormProps,
FormSubmitOptions,
FormValidation,
GenericFormData,
Validation
} from "~/types";
Expand All @@ -25,7 +26,7 @@ interface State<T extends GenericFormData = GenericFormData> {
data: T;
originalData: T;
wasSubmitted: boolean;
validation: Validation;
validation: FormValidation;
options?: FormSubmitOptions;
}

Expand Down Expand Up @@ -135,7 +136,7 @@ function FormInner<T extends GenericFormData = GenericFormData>(
{
isValid: undefined,
message: undefined,
results: false
results: undefined
},
state
);
Expand Down Expand Up @@ -170,7 +171,7 @@ function FormInner<T extends GenericFormData = GenericFormData>(
const stateRef = useRef<State<T>>({
data: {} as T,
originalData: {} as T,
validation: [],
validation: {},
wasSubmitted: false
});

Expand Down Expand Up @@ -250,7 +251,10 @@ function FormInner<T extends GenericFormData = GenericFormData>(

const onInvalid = () => {
if (typeof props.onInvalid === "function") {
props.onInvalid();
const { onInvalid } = props;
setTimeout(() => {
onInvalid(stateRef.current.validation);
});
}
};

Expand All @@ -266,7 +270,7 @@ function FormInner<T extends GenericFormData = GenericFormData>(
event.preventDefault();
}

setState(state => ({ ...state, wasSubmitted: true, options }));
setState(state => ({ ...state, wasSubmitted: true, validation: {}, options }));

const valid = await validate(options);

Expand Down Expand Up @@ -367,7 +371,7 @@ function FormInner<T extends GenericFormData = GenericFormData>(

return await Promise.resolve(executeValidators(value, validators))
.then(validationResults => {
const isValid = hasValidators ? (value === null ? null : true) : null;
const isValid = hasValidators ? (value === null ? undefined : true) : undefined;

if (isMounted.current) {
setState(state => ({
Expand All @@ -376,7 +380,7 @@ function FormInner<T extends GenericFormData = GenericFormData>(
...state.validation,
[name]: {
isValid,
message: null,
message: undefined,
results: validationResults
}
}
Expand All @@ -394,7 +398,7 @@ function FormInner<T extends GenericFormData = GenericFormData>(
[name]: {
isValid: false,
message: validationError.getMessage(),
results: false
results: undefined
}
}
}));
Expand Down Expand Up @@ -445,10 +449,10 @@ function FormInner<T extends GenericFormData = GenericFormData>(

const getValidationState = (name: string): Validation => {
return (
state.validation[name] || {
isValid: null,
message: null,
results: null
stateRef.current.validation[name] || {
isValid: undefined,
message: undefined,
results: undefined
}
);
};
Expand Down
10 changes: 8 additions & 2 deletions packages/form/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,16 @@ export type GenericFormData = {
[key: string]: any;
};

export interface FormValidation {
[name: string]: Validation;
}

export interface Validation {
isValid?: boolean;
message?: string;
[key: string]: any;
results?: {
[key: string]: any;
};
}

export interface FormOnSubmit<T = GenericFormData> {
Expand All @@ -92,7 +98,7 @@ export interface FormProps<T extends GenericFormData = GenericFormData> {
validateOnFirstSubmit?: boolean;
submitOnEnter?: boolean;
onSubmit?: FormOnSubmit<T>;
onInvalid?: () => void;
onInvalid?: (validation: FormValidation) => void;
onChange?: FormOnSubmit<T>;
children(params: FormRenderPropParams<T>): React.ReactElement;
ref?: React.MutableRefObject<any>;
Expand Down

0 comments on commit bbdd960

Please sign in to comment.