Files
Website/resources/js/helpers/form.ts
2023-02-27 14:52:01 +10:00

198 lines
5.5 KiB
TypeScript

import { ApiResponse } from "./api";
import {
createValidationResult,
defaultValidationResult,
ValidationObject,
ValidationResult,
} from "./validate";
type FormObjectValidateFunction = (item: string | null) => boolean;
type FormObjectLoadingFunction = (state: boolean) => void;
type FormObjectMessageFunction = (
message: string,
type: string,
icon: string
) => void;
type FormObjectErrorFunction = (message: string) => void;
type FormObjectApiErrorsFunction = (apiErrors: ApiResponse) => void;
export interface FormObject {
validate: FormObjectValidateFunction;
loading: FormObjectLoadingFunction;
message: FormObjectMessageFunction;
error: FormObjectErrorFunction;
apiErrors: FormObjectApiErrorsFunction;
_loading: boolean;
_message: string;
_messageType: string;
_messageIcon: string;
controls: { [key: string]: FormControlObject };
}
const defaultFormObject: FormObject = {
validate: function (item = null) {
const keys = item ? [item] : Object.keys(this.controls);
let valid = true;
keys.every(async (key) => {
if (
typeof this[key] == "object" &&
Object.keys(this[key]).includes("validation")
) {
this[key].validation.result = await this[
key
].validation.validator.validate(this[key].value);
if (!this[key].validation.result.valid) {
valid = false;
}
}
return true;
});
return valid;
},
loading: function (state = true) {
this._loading = state;
},
message: function (message = "", type = "", icon = "") {
this._message = message;
if (type.length > 0) {
this._messageType = type;
}
if (icon.length > 0) {
this._messageIcon = icon;
}
},
error: function (message = "") {
if (message == "") {
this.message("");
} else {
this.message(message, "error", "alert-circle-outline");
}
},
apiErrors: function (apiResponse: ApiResponse) {
let foundKeys = false;
if (
apiResponse.json &&
typeof apiResponse.json === "object" &&
apiResponse.json.errors
) {
const errors = apiResponse.json.errors as Record<string, string>;
Object.keys(errors).forEach((key) => {
if (
typeof this[key] === "object" &&
Object.keys(this[key]).includes("validation")
) {
foundKeys = true;
this[key].validation.result = createValidationResult(
false,
errors[key]
);
}
});
}
if (foundKeys == false) {
this.error(
apiResponse?.json?.message ||
"An unknown server error occurred.\nPlease try again later."
);
}
},
controls: {},
_loading: false,
_message: "",
_messageType: "primary",
_messageIcon: "",
};
/**
* Create a new Form object.
*
* @param {Record<string, FormControlObject>} controls The controls included in the form.
* @returns {FormObject} Returns a form object.
*/
export const Form = (
controls: Record<string, FormControlObject>
): FormObject => {
const form = defaultFormObject;
form.controls = controls;
return form;
};
interface FormControlValidation {
validator: ValidationObject;
result: ValidationResult;
}
const defaultFormControlValidation: FormControlValidation = {
validator: {
validate: (): ValidationResult => {
return defaultValidationResult;
},
},
result: defaultValidationResult,
};
type FormControlClearValidations = () => void;
type FormControlSetValidation = (
valid: boolean,
message?: string | Array<string>
) => ValidationResult;
type FormControlIsValid = () => boolean;
export interface FormControlObject {
value: string;
validate: () => ValidationResult;
validation: FormControlValidation;
clearValidations: FormControlClearValidations;
setValidationResult: FormControlSetValidation;
isValid: FormControlIsValid;
}
/**
* Create a new form control object.
*
* @param {string} value The control name.
* @param {ValidationObject | null} validator The control validation rules.
* @returns {FormControlObject} The form control object.
*/
export const FormControl = (
value: string = "",
validator: ValidationObject | null = null
): FormControlObject => {
return {
value: value,
validation:
validator == null
? defaultFormControlValidation
: {
validator: validator,
result: defaultValidationResult,
},
clearValidations: function () {
this.validation.result = defaultValidationResult;
},
setValidationResult: createValidationResult,
validate: function () {
if (this.validation.validator) {
this.validation.result = this.validation.validator.validate(
this.value
);
return this.validation.result;
}
return defaultValidationResult;
},
isValid: function () {
return this.validation.result.valid;
},
};
};