/* eslint-disable no-underscore-dangle */ import { encodeGlobalId } from '@aztlan/react-relay' import type { Field, Display, FormField, } from '../types.js' class BaseMixin { id?:Field | string _name?:string _meta: { fields :Record; formFields:Field[]; fieldList:string[]; name :string; mutations:Record; } constructor( _: any, mutationMap: Record = {}, ) { const { name } = this.constructor this._meta = { fields :{}, formFields:[], fieldList :[], name, mutations :mutationMap?.[name] || {}, } console.log( 'Constructor', this._meta, mutationMap, name, ) } _constructMeta() { const fields: Record = {} const formFields: Field[] = [] const fieldList: string[] = [] Object.entries(this).forEach(([ key, value, ]) => { // fix hasOwnProperty if (!key.startsWith('_') && value.formField) { formFields.push({ ...value.formField, name:key, }) // Initialize instance property to null or any default value Object.defineProperty( this, key, { value :null, writable :true, enumerable :true, configurable:true, }, ) } if (!key.startsWith('_')) { fields[key] = value fieldList.push(key) } }) this._meta.fields = fields this._meta.formFields = formFields this._meta.fieldList = fieldList } _initialize(kwargs: Record = {}) { this._constructMeta() this._initialize_instance(kwargs) } _initialize_instance(kwargs: Record) { Object.entries(kwargs).forEach(([ key, value, ]) => { // FIX hasOwnproperty if (this._meta.fields[key]) { this[key] = value } }) } get _globalId() { return encodeGlobalId( this.constructor.name, this.id, ) } /** * Compares the provided keyword arguments with the current instance values * and returns the count of changes. * @param kwargs The new values to compare against the instance's current values. * @returns The number of fields that would change value. */ _compareChanges(kwargs: Record): number { let changeCount = 0 Object.entries(kwargs).forEach(([ key, newValue, ]) => { if (this[key] !== undefined && this[key] !== newValue) { changeCount += 1 } }) return changeCount } /** * Retrieves fields that are to be displayed based on the specified display value. * @param displayValue The display context (e.g., 'edit', 'create') to filter fields by. * @returns An array of fields that match the specified display context. */ _getFieldsForDisplay(displayValue: Display): Field[] { // Initialize an empty array to hold matching fields const matchingFields: Field[] = [] // Iterate over the _meta.fields object Object.values(this._meta.fields).forEach((field) => { if (field.display && field.display?.includes(displayValue)) { matchingFields.push(field) } }) return matchingFields } /** * Retrieves form fields that are to be displayed based on the specified display value. * This method is a wrapper around _getFieldsForDisplay, preparing fields for form display. * @param displayValue The display context (e.g., 'edit', 'create') to filter fields by. * @returns An array of form fields that match the specified display context. */ _getFormFields(displayValue: Display): FormField[] { const fields = this._getFieldsForDisplay(displayValue) const formFields = fields.map((field) => ({ ...field.formField, name :field.name, disabled:field.readOnly || field.formField.disabled, })) return formFields } /** * Retrieves active form fields based on the specified display value. * This method filters out fields that are disabled and matches the given display context. * * @param {Display} displayValue - The context (e.g., 'edit', 'create') to filter fields by. * @returns {Field[]} An array of active form fields that match the specified display context. */ _getActiveFormFields(displayValue: Display): FormField[] { const formFields = this._getFormFields(displayValue) console.log( 'formFields', formFields, formFields.filter((field) => !field.disabled), ) return formFields.filter((field) => !field.disabled) } /** * Applies transformations on the entire dictionary of variables. By default, does nothing * function but can be overridden in derived classes to implement specific transformation logic. * * @param {Record} payload - The entire dictionary of variables to transform. * @returns {Record} The transformed dictionary of variables. */ /* eslint-disable-next-line class-methods-use-this */ _transformPayload(payload: Record): Record { // By default, return payload as is. Override in subclass for specific behavior. return payload } /** * Prepares mutation variables by filtering out fields that are disabled and applying transformations * on the entire variables dictionary. * * @param {Record} variables - The input dictionary of variables. * @returns {Record} A cleaned and potentially transformed dictionary of variables. */ _prepareMutationVariables( variables: Record, displayValue: Display, ): Record { const activeFields = this._getActiveFormFields('edit') const activeFieldNames = activeFields.map((field) => field.name) const cleanVariables = Object.entries(variables) .filter(([key]) => activeFieldNames.includes(key)) .reduce( ( acc, [ key, value, ], ) => ({ ...acc, [key]:value, }), {}, ) return this._transformPayload(cleanVariables) } private _fields() { const fields: Record = {} Object.entries(this).forEach(([ key, value, ]) => { if (!key.startsWith('_')) { fields[key] = value } }) return fields } private _formFields() { const formFields: Record = {} const fields = this._fields() Object.entries(fields).forEach(([ key, field, ]) => { formFields[key] = { ...field.formField, name:field.name, } }) return formFields } } export default BaseMixin