catarse/catarse.js

View on GitHub
legacy/src/c/projects/publish-by-steps/user-info-edit-settings.tsx

Summary

Maintainability
D
2 days
Test Coverage
import m from 'mithril';
import prop from 'mithril/stream';
import _ from 'underscore';
import { StreamType } from '../../../@types/reward-details-stream';
import { UserDetails } from '../../../@types/user-details';
import { State } from '../../../@types/state';
import h from '../../../h';
import addressVM from '../../../vms/address-vm';
import { InlineErrors } from '../../inline-errors';
import UserSettingsAddress from '../../user-settings-address';
import UserSettingsResponsible from '../../user-settings-responsible';
import { UserAddress } from '../../../@types/user-address';
import moment from 'moment';

export type UserInfoEditSettingsAttrs = {
    hasErrorOn(field : string): boolean
    getErrorsOn(field : string): string[]
    user: UserDetails
}

export type UserInfoEditSettingsState = {
    parsedErrors: {
        hasError(field : string) : void
        inlineError(field : string): JSX.Element
    },
    fields: StreamType<{
        account_type: StreamType<string>
        name: StreamType<string>
        owner_document: StreamType<string>
        birth_date: StreamType<string>
        state_inscription: StreamType<string>
    }>
    disableFields: boolean
    applyDocumentMask(newData : string): string
    applyBirthDateMask(newData : string): string
    addVM: StreamType<any>
}

export class UserInfoEditSettings implements m.Component {

    oninit({attrs, state} : m.Vnode<UserInfoEditSettingsAttrs, UserInfoEditSettingsState>) {
        const hasErrorOn = attrs.hasErrorOn
        const getErrorsOn = attrs.getErrorsOn
        const user = attrs.user
        user.address = user.address || {
            address_number: '',
            address_complement: '',
            address_neighbourhood: '',
            phone_number: '',
            country_id: 36,
            address_street: '',
            address_city: '',
            address_state: '',
            address_zip_code: '',
        } as UserAddress
        const errors = {
            addressStreet: prop(false),
            addressNeighbourhood: prop(false),
            addressCity: prop(false),
            stateID: prop(false),
            addressZipCode: prop(false),
            phoneNumber: prop(false),
            addressState: prop(false),
            countryID: prop(false),
            addressNumber: prop(false),
            addressComplement: prop(false),
        }

        const parsedErrors = {
            hasError: (field : string) => {
                switch(field) {
                    case 'address_zip_code': {
                        errors.addressZipCode(hasErrorOn(field))
                        break;
                    }
                    case 'phone_number': {
                        errors.phoneNumber(hasErrorOn(field))
                        break;
                    }
                    case 'address_state': {
                        errors.addressState(hasErrorOn(field))
                        break;
                    }
                    case 'address_street': {
                        errors.addressStreet(hasErrorOn(field))
                        break;
                    }
                    case 'address_neighbourhood': {
                        errors.addressNeighbourhood(hasErrorOn(field))
                        break;
                    }
                    case 'address_city': {
                        errors.addressCity(hasErrorOn(field))
                        break;
                    }
                    case 'state_id': {
                        errors.stateID(hasErrorOn(field))
                        break;
                    }
                    case 'country_id': {
                        errors.countryID(hasErrorOn(field))
                        break;
                    }
                    case 'address_number': {
                        errors.addressNumber(hasErrorOn(field))
                        break;
                    }
                    case 'address_complement': {
                        errors.addressComplement(hasErrorOn(field))
                        break;
                    }

                    case 'owner_document': {
                        return hasErrorOn('cpf')
                    }
                    case 'state': {
                        errors.addressState(hasErrorOn('address_state'))
                        return hasErrorOn('address_state')
                    }
                    case 'street': {
                        errors.addressStreet(hasErrorOn('address_street'))
                        return hasErrorOn('address_street')
                    }
                    case 'number': {
                        errors.addressNumber(hasErrorOn('address_number'))
                        return hasErrorOn('address_number')
                    }
                    case 'neighbourhood': {
                        errors.addressNeighbourhood(hasErrorOn('address_neighbourhood'))
                        return hasErrorOn('address_neighbourhood')
                    }
                    case 'city': {
                        errors.addressCity(hasErrorOn('address_city'))
                        return hasErrorOn('address_city')
                    }
                    case 'zipcode': {
                        errors.addressZipCode(hasErrorOn('address_zip_code'))
                        return hasErrorOn('address_zip_code')
                    }
                    case 'phonenumber': {
                        errors.phoneNumber(hasErrorOn('phone_number'))
                        return hasErrorOn('phone_number')
                    }
                }

                return hasErrorOn(field)
            },
            inlineError: (field : string) => {
                switch(field) {
                    case 'owner_document':
                        return <InlineErrors messages={getErrorsOn('cpf')} />        
                }
                return <InlineErrors messages={getErrorsOn(field)} />
            }
        }

        const userFieldsNames = [
            'account_type',
            'name',
            'owner_document',
            'birth_date',
            'state_inscription',
        ]

        const fields = prop(objectOfStreamsFromPOJO(user, userFieldsNames)) as any

        const hasContributedOrPublished = user.total_contributed_projects >= 1 || user.total_published_projects >= 1
        const disableFields = user.is_admin_role ? false : (hasContributedOrPublished && !_.isEmpty(user.name) && !_.isEmpty(user.owner_document))
        
        const birthDayMask = _.partial(h.mask, '99/99/9999') as (newData : string) => string
        const documentMask = _.partial(h.mask, '999.999.999-99') as (newData : string) => string
        const documentCompanyMask = _.partial(h.mask, '99.999.999/9999-99') as (newData : string) => string
        
        const hasBirthDate = !!fields().birth_date()
        if (hasBirthDate) {
            fields().birth_date(h.momentify(fields().birth_date() || moment()))
        }

        const applyBirthDateMask = _.compose(fields().birth_date, birthDayMask) as (newData : string) => string
        const applyDocumentMask = (value : string) => {
            if (fields().account_type() != 'pf') {
                fields().owner_document(documentCompanyMask(value));
            } else {
                fields().owner_document(documentMask(value));
            }
            
            h.redraw()

            return fields().owner_document()
        }
        
        state.parsedErrors = parsedErrors
        state.fields = fields
        state.disableFields = disableFields
        state.applyBirthDateMask = applyBirthDateMask
        state.applyDocumentMask = applyDocumentMask
        state.addVM = addViewModel()

        function addViewModel() {

            const statesProp = prop<State[]>([])

            const fieldsMap = {
                addressZipCode: 'address_zip_code',
                phoneNumber: 'phone_number',
                addressState: 'address_state',
                addressStreet: 'address_street',
                addressNeighbourhood: 'address_neighbourhood',
                addressCity: 'address_city',
                stateID: 'state_id',
                countryID: 'country_id',
                addressNumber: 'address_number',
                addressComplement: 'address_complement',
            }

            const newMappedFields = Object.keys(fieldsMap).reduce((mappedFields, fieldNameToMap) => {
                mappedFields[fieldNameToMap] = mapFieldToProp(fieldsMap[fieldNameToMap])
                return mappedFields;
            }, {})

            function mapFieldToProp(field : string) {
                return (data? : string) => {
                    if (typeof data !== 'undefined') {
                        user.address[field] = data
                        WhenChangeNationality(user, statesProp)
                    }
                    return user.address[field]
                }
            }

            newMappedFields['states'] = statesProp
            newMappedFields['errors'] = errors

            return (data? : any) => {
                return {
                    fields: newMappedFields,
                }
            }
        }
    }

    view({attrs, state} : m.Vnode<UserInfoEditSettingsAttrs, UserInfoEditSettingsState>) {

        const user = attrs.user
        const parsedErrors = state.parsedErrors
        const fields = state.fields
        const disableFields = state.disableFields
        const applyBirthDateMask = state.applyBirthDateMask
        const applyDocumentMask = state.applyDocumentMask
        const addVM = state.addVM

        return (
            <>
                <UserSettingsResponsible 
                    parsedErrors={parsedErrors}
                    fields={fields}
                    user={user}
                    disableFields={disableFields}
                    applyDocumentMask={applyDocumentMask}
                    applyBirthDateMask={applyBirthDateMask}
                    />
                <UserSettingsAddress 
                    addVM={addVM}
                    parsedErrors={parsedErrors}
                    />
            </>
        )
    }
}

function objectOfStreamsFromPOJO(obj = {}, fields : string[]) {
    const objStreams = {}

    for (const field of fields) {
        // objStreams[field] = propFromField(obj, field)
        objStreams[field] = (newData? : any) => {
            if (typeof newData !== 'undefined') {
                objStreams[field]._value = newData
                obj[field] = newData
            }
    
            return objStreams[field]._value
        }

        objStreams[field]._value = obj[field]
    }

    return objStreams
}

function WhenChangeNationality(user : UserDetails, states: prop<State[]>) : UserAddress {
    const defaultCountryID = 36 // Brasil
    const isInternational = Number(user.address.country_id) !== defaultCountryID

    if (!_.isEmpty(states()) && !isInternational) {
        const countryState = _.first(_.filter(states(), countryState => {
            return user.address.state_id === countryState.id
        }))
        
        if (countryState) {
            user.address.address_state = countryState.acronym
        }
    }

    if (isInternational) {
        user.address = {
            country_id: user.address.country_id,
            address_street: user.address.address_street,
            address_city: user.address.address_city,
            address_state: user.address.address_state,            
            address_zip_code: user.address.address_zip_code,
        } as UserAddress
    } else {
        user.address = {
            country_id: user.address.country_id,
            address_street: user.address.address_street,
            address_city: user.address.address_city,
            address_state: user.address.address_state,            
            address_zip_code: user.address.address_zip_code,
            state_id: user.address.state_id,
            address_number: user.address.address_number,
            address_complement: user.address.address_complement,
            address_neighbourhood: user.address.address_neighbourhood,
            phone_number: user.address.phone_number,
        } as UserAddress
    }
}