You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ctk/services/frontend/src/utils/forms.ts

243 lines
4.8 KiB
TypeScript

import lodash from "lodash";
import { toaster } from ".";
export const checkArray = <T>(array: any, name: string): T => {
if (!Array.isArray(array)) {
throw new Error(
`Looks like we encountered a bug. The current implementation expects "${name}" to be an array.`
);
}
return array as unknown as T;
};
export const pruneArray = <T>(array: (T | undefined)[]): T[] | undefined => {
const result = array.filter(Boolean);
if (array.length === 0) {
return undefined;
}
return result as T[];
};
export const pruneObject = <T, R = T>(object: T): R | undefined => {
const result = lodash.pickBy(object ?? {}, (value) => value !== undefined);
if (Object.keys(result).length === 0) {
return undefined;
}
return result as unknown as R;
};
export const pruneString = (value?: string): string | undefined => {
if (!value) {
return undefined;
}
return value;
};
export const pruneNumber = (value?: number): number | undefined => {
if (
value === undefined ||
value === null ||
isNaN(value) ||
(value as unknown as string) === ""
) {
return undefined;
}
return value;
};
export const splitKVPairs = (
text: string,
seperator: string,
optional = true
): [string, string] => {
const firstIndex = text.indexOf(seperator);
if (firstIndex < 0) {
if (optional) {
return [text, ""];
} else {
throw new Error("Malformed document!");
}
}
const key = text.substring(0, firstIndex);
const value = text.substring(firstIndex + 1);
return [key, value];
};
export type TTransformFunction = (
item: string,
index: number
) => Record<string, any>;
export const extractObjectOrArray = (
seperator: string,
keyName: string,
valueName: string,
object: any
): any => {
if (!object) {
return undefined;
}
if (Array.isArray(object)) {
return object.map((item: string) => {
const [key, value] = splitKVPairs(item, seperator);
return {
[keyName]: key,
[valueName]: value
};
});
}
return Object.entries(object).map(([key, value]) => {
return {
[keyName]: key,
[valueName]: value
};
});
};
export const extractArray = (
seperator: string,
keyName: string,
valueName: string,
array: any
): any => {
if (!array) {
return undefined;
}
if (!Array.isArray(array)) {
throw new Error("Malformed document. Expected an array at this point.");
}
return array.map((item: string) => {
const [key, value] = splitKVPairs(item, seperator);
return {
[keyName]: key,
[valueName]: value
};
});
};
/**
* Converts an array of the form `[{ [K]: string, [V]: string}]` to `{K: V}`.
* For example,
* ```
* [
* {
* key: "NODE_ENV",
* value: "production"
* }
* ]
*
* becomes
*
* {
* NODE_ENV: "production"
* }
* ```
*/
export const packArrayAsObject = (
array: any[],
keyName: string,
valueName: string
) => {
return pruneObject(
Object.fromEntries(array.map((item) => [item[keyName], item[valueName]]))
);
};
/**
* Converts an array objects of the form
* ```
* [
* {
* [K]: string,
* [V]: string
* }
* ...
* ]`
*
* to
*
* [
* `${item[i][K]]}${seperator}${item[i][V]}`,
* ...
* ]
* ```
*
* For example,
* ```
* [
* {
* key: "NODE_ENV",
* value: "production"
* }
* ]
*
* becomes
*
* {
* "NODE_ENV=production"
* }
* ```
*/
export const packArrayAsStrings = (
objects: any[],
keyName: string,
valueName: string,
seperator: string
) => {
return pruneArray(
objects.map((object) =>
[object[keyName], object[valueName]].join(seperator)
)
);
};
const isObject = (value: any) => {
return !!(value && typeof value === "object" && !Array.isArray(value));
};
const digForString = (error: any[] | string) => {
if (lodash.isString(error) && /\s/.test(error)) {
toaster(error as string, "error");
return;
}
if (Array.isArray(error)) {
for (const message of error) {
digForString(message);
}
}
if (isObject(error)) {
for (const [_, value] of Object.entries(error)) {
if (Array.isArray(value)) {
digForString(value);
}
if (lodash.isString(value)) {
toaster(value as string, "error");
}
}
}
};
/**
* Formik is configured to validate fields automatically using Yup.
* The problem is Formik does not call `onSubmit` function when errors
* are present. Therefore, a work around was to call `formik.submitForm`
* after showing errors to the user. The `reportErrorsAndSubmit` utility
* function basically implements this.
*/
export const reportErrorsAndSubmit = (formik: any) => () => {
const errors: [string, any][] = Object.entries(formik.errors);
if (errors.length > 0) {
digForString(errors);
} else {
formik.submitForm();
}
};