UNPKG

@fto-consult/expo-ui

Version:

Bibliothèque de composants UI Expo,react-native

393 lines (389 loc) 15.7 kB
import {getAppBarActionsProps} from "./utils"; import React, {ObservableComponent as AppComponent} from "$react"; import {isNonNullString,defaultStr,defaultNumber,defaultObj,extendObj,isObj,isFunction,defaultFunc,uniqid} from "$cutils"; import {getForm,getFormField} from "../utils"; import Surface from "$ecomponents/Surface"; import Form from "../Form"; import theme,{flattenStyle} from "$theme"; import PropTypes from "prop-types"; import {renderActions} from "$ecomponents/Dialog/utils"; import {handleBeforeSaveCallback} from "./utils"; import isDbDocEditing,{checkPrimaryKey} from "../utils/isDocEditing"; import keyboardShortcuts from "../utils/keyboardShortcuts"; import FieldsContent from "./FieldsContent"; import { isPermAllowed } from "$eauth/utils"; export default class FormDataComponent extends AppComponent{ constructor(props){ super(props); const formName = defaultStr(this.props.formName,uniqid("form-id")) Object.defineProperties(this,{ formName : { value : formName, }, getFormName : { value : x=> formName, }, isAllowed : { value : isPermAllowed(this.props.perm,props), }, }); } isFormList(){ return false; } getForm (){ return getForm(this.getFormName()); } getFormField (fieldName){ return getFormField(formName,fieldName); } getFields(){ return this.getForm()?.getFields() || {}; } getField(fieldName){ return getFormField(this.getFormName(),fieldName) } getData(...args){ return this.getFormData(...args); } getFormData(){ const form = this.getForm(); if(form){ return form.getData(); } return {}; } actionMutator(args){ const a2 = typeof this.props.actionMutator =='function'? this.props.actionMutator(args) :args.action; if(!isObj(a2)) return null; return a2; } getAppBarProps(){ return defaultObj(this.props.appBarProps); } beforeSave(){ return true; } canCallOnSuccess(){ return true; } onSave(args){ return true; } reset(args){ return null; } isValid(...args){ return this.isFormValid(...args); } isFormValid(...args){ return this.getForm()?.isValid(...args); } getErrorText(){ return this.getForm()?.getErrorText(); } getAppBarActionsProps(props){ let {data,onCancel,perm,beforeSaveArgumentsMutator,beforeSave,actions,saveDataMutator,...rest} = (defaultObj(props,this.props)); const onSave = typeof props.onSave ==='function'? props.onSave : this.props.onSave ; beforeSave = typeof beforeSave =='function'? beforeSave : x=>true; return getAppBarActionsProps({ ...defaultObj(rest), ...this.getAppBarProps(), actions, actionMutator : this.actionMutator.bind(this), formName : this.getFormName(), data:Object.assign({},data), save :(args)=>{ setTimeout(()=>{ const form = this.getForm(); if(!form || !form.isValid) return false; if(!form.isValid()){ const errorText = form.getErrorText(); if(errorText){ return "Impossible d'enregister les données à cause l'erreur suivante : "+errorText; } } const isUpdated = this.isDocEditing(args.data); const currentIndex = this.getCurrentIndex(); const action = typeof this.clickedAction =='string' ? this.clickedAction.toLowerCase() : ''; const savedArgs = {...args,isUpdated,context:this,action,currentIndex,index:currentIndex,isUpdate:isUpdated,isUpdated,props:this.props,context:this}; if(beforeSaveArgumentsMutator){ savedArgs = beforeSaveArgumentsMutator(savedArgs); if(!isObj(savedArgs)){ savedArgs = {...savedArgs,data} } } if(typeof saveDataMutator =='function'){ saveDataMutator(savedArgs); } return handleBeforeSaveCallback(this.beforeSave.bind(this),()=>{ return handleBeforeSaveCallback(beforeSave,()=>{ return handleBeforeSaveCallback(this.onSave.bind(this),()=>{ return handleBeforeSaveCallback(onSave,()=>{ if(action == 'save2close'){ ///on appelle la fonction qui enregistre et ferme this.doSave2Close(savedArgs) } else if(action == 'save2new' || action ==='new'){ ///on appelle la fonction qui enregistre et crèe un nouveau this.doSave2New({...savedArgs,index:undefined,data:{}}); } else { ///on appelle la fonction qui enregistre et reste sur la page this.doSave(savedArgs); } if(this.canCallOnSuccess()){ if(typeof this.props.onSuccess =="function"){ this.props.onSuccess(savedArgs); } else if(onSave !== this.props.onSave && typeof this.props.onSave =="function"){ this.props.onSave(savedArgs); } } },savedArgs); },savedArgs); },savedArgs); },savedArgs); },0); }, cancel:(args)=>{ this.onCancel(args); } }); } onCancel(args){ if(isFunction(this.props.onCancel)){ onCancel({...defaultObj(args),context:this,editingData:this.getData(),data:this.getDataProp(),props:this.props}); } } /*** cette fonction est appelée pour enregistrer les données */ doSave(args){} ///cette fonction est appelée pour enregistrer et fermer la page doSave2Close(args){} ////cette fonction est appelée pour enregister et créer un noveau doSave2New(args){} createNew(args){} getCurrentIndex(){ return undefined; } isDocEditing (data){ data = defaultObj(data); if(typeof this.props.isDocEditing =='function'){ return this.props.isDocEditing(data,{context:this}) ? true : false; } else if(typeof this.props.isDocUpdate =='function'){ return this.props.isDocUpdate(data,{context:this}) ? true : false; } return isObj(this.formDataPrimaryKeyFields) && Object.size(this.formDataPrimaryKeyFields,true) ? isDbDocEditing(data,this.formDataPrimaryKeyFields,({index:field,data})=>{ return checkPrimaryKey(data,field); }) : false; } canBindResizeEvents(){ return false; } componentDidMount(){ super.componentDidMount(); } componentWillUnmount(){ super.componentWillUnmount(); this.clearEvents(); } close(){ } onBackActionPress(){ return true; } getDataProp (){ return Object.assign({},this.props.data); } getFormName (){ return this.formName; } isArchivable (){ return false; } getActions (){ return renderActions(this.getAppBarActionsProps()); } _render (content){ return React.isValidElement(content)? content : null; } /*** les props à utiliser pour le rendu du composant, dans la méthode render */ getComponentProps (props){ return props; } /*** les props qui seront passé au composant Wrapper au moment du rendu du composant FormData * appélé dans la méthode _render */ getRenderingProps (){ return this.props; } handleCustomRender(){ return false; } onKeyEvent(event){ event = defaultObj(event); event.targetContext = this; const {onKeyEvent} = this.props; if(isFunction(onKeyEvent) && onKeyEvent({...event,context:this,data:this.getDataProp()}) === false){ return false; } let key = defaultStr(event.key).toLowerCase(); if(key === 'esc'){ this.onBackActionPress({close:this.close.bind(this)}); return false; } if(keyboardShortcuts[key]){ event.formKeyEventAction = keyboardShortcuts[key]; return event; } return false; } render (){ const props = defaultObj(this.getComponentProps(this.props)); this.componentWillRender(props); let { data, actions, fields, saveButton, saveButtonIcon, formProps, closeAfterSave, readOnly, component, disabled, onValidate, onNoValidate, onValidateField, responsive, responsiveProps, header, children, ignoreFields, //la liste des champs à ignorer lors du parcours des champs toolbarProps, text, getFieldProps, ///pour ajouter des champs supplémentaires aux props de la field title, onMount, windowWidth, onUnmount, isRenderedByFormPage, archivable, onKeyEvent, isFormDataDialog, archived, withBottomSheet, isAllowed, isDocEditing, beforeSave, onSave, saveDataMutator, beforeSaveArgumentsMutator, ...containerProps } = props; if(typeof isAllowed ==='function'){ isAllowed = isAllowed({...props,data:defaultObj(data),context:this}) } else isAllowed = true; if(isAllowed === false || !this.isAllowed){ Auth.showError(); return null; } formProps = Object.assign({},formProps); formProps.onNoValidate = onNoValidate; formProps.onValidate = onValidate; formProps.onNoValidate = onNoValidate; formProps.onValidateField = function(){ if(isFunction(onValidateField)){ onValidateField.apply(this,Array.prototype.slice.call(arguments,0)) } }; containerProps = Object.assign({},containerProps); const cStyle = flattenStyle([styles.container,{backgroundColor:theme.surfaceBackgroundColor},containerProps.style]); formProps.style = flattenStyle([{backgroundColor:cStyle.backgroundColor},formProps.style]); data = isObj(formProps.data) ? formProps.data : isObj(data) ? data : {}; ///getting fields content this.formDataPrimaryKeyFields = defaultObj(this.primaryKeyFields); const content = <Form {...formProps} windowWidth = {defaultNumber(formProps.windowWidth,windowWidth) || undefined} name={this.getFormName()} onKeyEvent = {this.onKeyEvent.bind(this)} data = {data} key = {this.getFormName()} > <FieldsContent {...formProps} fields = {defaultObj(formProps.fields,fields)} fieldProps = {defaultObj(formProps.fieldProps,this.props.fieldProps)} style = {flattenStyle(formProps.style)} data = {data} responsive = {typeof formProps.responsive =='boolean' ? formProps.responsive : this.props.responsive !== false ? true : false} responsiveProps = {extendObj({},this.props.responsiveProps,formProps.responsiveProps)} windowWidth = {defaultNumber(formProps.windowWidth,this.props.windowWidth) || undefined} primaryKeyFields = {this.formDataPrimaryKeyFields} formName = {this.getFormName()} disabled = {this.props.disabled} archived = {this.props.archived || data?.archived && true || false} archivable = {this.props.archivable || this.isArchivable()} onLoopField={(opts)=>{ this.formDataPrimaryKeyFields = defaultObj(this.formDataPrimaryKeyFields); if(opts.primaryKey){ this.formDataPrimaryKeyFields[opts.name] = true; } else { delete this.formDataPrimaryKeyFields[opts.name]; } if(typeof this.props.onLoopField ==='function'){ this.props.onLoopField(opts) } }} /> </Form> if(this.handleCustomRender()){ return this._render({ header, context : this, content, }); } if(typeof children ==='function'){ return this._render(children({ header, context : this, content, })); } return this._render(<Surface primary testID={'RN_FormDataComponent'} {...containerProps} style={cStyle}> {React.isValidElement(header,true)?header : null} {content} {React.isValidElement(children)? children : null} </Surface>); } } FormDataComponent.propTypes = { fieldProps : PropTypes.object,//les props à passer à chacun des fields onKeyEvent : PropTypes.func, isDocEditing : PropTypes.func,///permet de spécifier si le document en cours est en modification windowWidth : PropTypes.number,///la taille de la fenêtre à considérer pour le responsive isFormDataDialog : PropTypes.bool, //si la form data est rendu dans une boîte de dialogue onMount : PropTypes.func, onUnmount : PropTypes.func, withBottomSheet : PropTypes.bool,//si les éléments de formFields sera rendu en utilisant le bottomSheet, surtout les éléments de type select children : PropTypes.oneOfType([ PropTypes.func, PropTypes.node, PropTypes.element ]), beforeSaveArgumentsMutator : PropTypes.func, header : PropTypes.oneOfType([ PropTypes.string, PropTypes.number, PropTypes.node, ]), onLoopField : PropTypes.func,//la fonction appelée lorsqu'on boucle sur un champ du form data } const styles = { container : { height : '100%', flexDirection : 'column', justifyContent : 'flex-start', alignItems : 'flex-start', paddingBottom : 30, }, }