Commit 75729ccf authored by Rafael's avatar Rafael

Adiciona telas nos formulários de dados de proposta e conexão com o serviço

parent b069d199
......@@ -80,7 +80,7 @@
},
"dependencies": {
"@curio/client": "1.3.3",
"@curio/components": "^0.1.5",
"@curio/components": "^0.1.6",
"@curio/ui": "^0.1.0",
"@date-io/date-fns": "^1.0.0",
"@dynamo/components": "0.70.1",
......
......@@ -8,9 +8,19 @@ export interface Gender extends Entity {
description: string
}
export interface Schooling extends Entity {
description: string
}
export interface MaritalStatus extends Entity {
description: string
}
export interface ProposalDataContext {
frameworks: Framework[]
genders: Gender[]
schoolings: Schooling[]
maritalStatus: MaritalStatus[]
}
export interface FetchContext {
......
import { Address } from '../'
export interface InvolvedPersonAddress extends Omit<IPAddress, 'id'> {
proof: string
}
export interface IPAddress {
id: string
export interface IPAddress extends Address {
proof: string
street: string
number: string
cep: string
complement: string
city: string
district: string
state: string
}
interface InputUpdateCDAddress {
projectId: string
personId: string
address: IPAddress
}
export interface UpdateCDAddress {
Input: InputUpdateCDAddress
Output: IPAddress
}
......@@ -35,3 +35,13 @@ export interface DataType {
}
export type InvolvedPersonType = 'CUSTOMER' | 'PARTNER' | 'GUARANTOR'
interface InputAddCDIdentification {
identification: Identification
projectId: string
}
export interface AddCDIdentification {
Input: InputAddCDIdentification
Output: Identification
}
......@@ -22,3 +22,14 @@ export interface UpdatePersonalDataArgs {
personId: string
personalData: InvolvedPerson['personalData']
}
interface InputUpdateCDPersonalData {
personalData: PersonalData
projectId: string
personId: string
}
export interface UpdateCDPersonalData {
Input: InputUpdateCDPersonalData
Output: PersonalData
}
......@@ -10,3 +10,14 @@ export interface SourceIncome {
position: string
address: BaseAddress
}
interface InputUpdateCDSourceIncome {
sourceIncome: SourceIncome
projectId: string
personId: string
}
export interface UpdateCDSourceIncome {
Input: InputUpdateCDSourceIncome
Output: SourceIncome
}
......@@ -42,3 +42,14 @@ export interface UpdateSpouseDataArgs {
personId: string
spouseData: SpousePersonalData
}
interface InputUpdateCDSpouseData {
spouseData: SpousePersonalData
projectId: string
personId: string
}
export interface UpdateCDSpouseData {
Input: InputUpdateCDSpouseData
Output: SpousePersonalData
}
......@@ -37,11 +37,7 @@ interface InputCreateProposal {
subproductId: string
}
interface OutputCreateProposal {
proposalId: string
}
export interface CreateProposal {
Input: InputCreateProposal
Output: OutputCreateProposal
Output: string
}
import {
AddCDIdentification,
Address,
InvolvedPerson,
RG,
SourceIncome,
SpousePersonalData,
UpdateCDAddress,
UpdateCDPersonalData,
UpdateCDSourceIncome,
UpdateCDSpouseData
} from '@agiliza/api/domain'
import { extractNumbers } from '@agiliza/utils/method'
import {
EnderecoApiModel,
ProjetoPessoaEnvolvidaConjugeApiModel,
ProjetoPessoaEnvolvidaDadosPessoaisApiModel,
ProjetoPessoaEnvolvidaFonteRendaApiModel,
ProjetoPessoaEnvolvidaIdentificacaoApiModel,
ProjetoPessoaEnvolvidaRGApiModel
} from '@microcredito/client'
import {
AtualizarConjugePessoaEnvolvidaRequest,
AtualizarDadosPessoaisPessoaEnvolvidaRequest,
AtualizarEnderecoPessoaEnvolvidaRequest,
AtualizarFonteRendaPessoaEnvolvidaRequest,
IncluirPessoaEnvolvidaRequest
} from '@microcredito/client/dist/apis/AgenteApi'
import { ApiAdapter } from '../shared'
export class AddInvolvedPersonIdentification implements ApiAdapter<InvolvedPerson['identification'], ProjetoPessoaEnvolvidaIdentificacaoApiModel> {
public mapBanestesAccountToApi = (
acc: InvolvedPerson['identification']['account']
): ProjetoPessoaEnvolvidaIdentificacaoApiModel['contaBanestes'] => ({
numeroConta: acc?.number,
fotoCartao: acc?.cardPicture?.split(',')[1],
numeroAgencia: acc?.agencyNumber,
})
public mapDateTypeToApi = (dType: InvolvedPerson['identification']['dataType']): ProjetoPessoaEnvolvidaIdentificacaoApiModel['dadosTipo'] => ({
enquadramento: dType?.framework,
fazRetirada: dType?.doesWithdrawal,
porcentagemParticipacao: dType?.participationPercentage ? Number(dType?.participationPercentage) : undefined,
})
public mapDomainToApiModel = (domain: InvolvedPerson['identification']): ProjetoPessoaEnvolvidaIdentificacaoApiModel => ({
id: domain.id,
nome: domain.name,
cpfcnpj: extractNumbers(domain.cpfcnpj),
sexo: domain.gender,
tipo: domain.type,
contaBanestes: domain.account ? this.mapBanestesAccountToApi(domain.account) : undefined,
dadosTipo: domain.dataType ? this.mapDateTypeToApi(domain.dataType) : undefined,
})
}
export class CDAddIdentificationMapper implements ApiAdapter<AddCDIdentification['Input'], IncluirPessoaEnvolvidaRequest> {
private identificationApiMapper: AddInvolvedPersonIdentification
constructor() {
this.identificationApiMapper = new AddInvolvedPersonIdentification()
}
public mapDomainToApiModel = (input: AddCDIdentification['Input']): IncluirPessoaEnvolvidaRequest => ({
projetoId: input.projectId,
pessoaEnvolvidaIdentificacaoRequestApiModel: {
identificacao: this.identificationApiMapper.mapDomainToApiModel(input.identification),
},
})
}
export class RGApiAdapter implements ApiAdapter<RG, ProjetoPessoaEnvolvidaRGApiModel> {
public mapDomainToApiModel = (rg: RG): ProjetoPessoaEnvolvidaRGApiModel => ({
frente: rg.front.split(',')[1] || '',
verso: rg.back.split(',')[1] || '',
orgaoExpedidor: rg.dispatcherAgency,
numero: rg.number,
})
}
export class CDPersonalDataMapper implements ApiAdapter<InvolvedPerson['personalData'], ProjetoPessoaEnvolvidaDadosPessoaisApiModel> {
private rgApiAdapter: RGApiAdapter
constructor() {
this.rgApiAdapter = new RGApiAdapter()
}
public mapDomainToApiModel = (dP: InvolvedPerson['personalData']): ProjetoPessoaEnvolvidaDadosPessoaisApiModel => ({
dataNascimento: dP?.birthday || undefined,
emailPrimario: dP?.primaryEmail,
emailSecundario: dP?.secundaryEmail,
nomePai: dP?.fathersName,
nomeMae: dP?.mothersName,
dependentes: dP?.dependents,
escolaridade: dP?.schooling,
rg: dP?.rg ? this.rgApiAdapter.mapDomainToApiModel(dP?.rg) : undefined,
estadoCivil: dP?.maritalStatus,
profissao: dP?.occupation,
telefone: extractNumbers(dP?.mobile),
telefoneFixo: extractNumbers(dP?.landline),
usuarioCRAS: dP?.userCRAS,
})
}
export class CDUpdatePersonalDataMapper implements ApiAdapter<UpdateCDPersonalData['Input'], AtualizarDadosPessoaisPessoaEnvolvidaRequest> {
private cDPersonalDataMapper: CDPersonalDataMapper
constructor() {
this.cDPersonalDataMapper = new CDPersonalDataMapper()
}
public mapDomainToApiModel = (input: UpdateCDPersonalData['Input']): AtualizarDadosPessoaisPessoaEnvolvidaRequest => ({
pessoaId: input.personId,
projetoId: input.projectId,
pessoaEnvolvidaDadosPessoaisRequestApiModel: {
dadosPessoais: this.cDPersonalDataMapper.mapDomainToApiModel(input.personalData),
},
})
}
export class CDUpdateAddressApiMapper implements ApiAdapter<UpdateCDAddress['Input'], AtualizarEnderecoPessoaEnvolvidaRequest> {
private addressApiMapper: AddressApiMapper
constructor() {
this.addressApiMapper = new AddressApiMapper()
}
public mapDomainToApiModel = (input: UpdateCDAddress['Input']): AtualizarEnderecoPessoaEnvolvidaRequest => ({
projetoId: input.projectId,
pessoaId: input.personId,
projetoPessoaEnvolvidaEnderecoApiModel: {
comprovante: input.address.proof.split(',')[1],
endereco: this.addressApiMapper.mapDomainToApiModel(input.address),
},
})
}
export class AddressApiMapper implements ApiAdapter<Address, EnderecoApiModel> {
public mapDomainToApiModel = (address: Address): EnderecoApiModel => ({
bairro: address.district,
cep: extractNumbers(address.cep),
estado: address.state,
logradouro: address.street,
municipio: address.city,
numero: address.number,
complemento: address.complement,
})
}
export class CDUpdateSourceIncomeApiMapper implements ApiAdapter<UpdateCDSourceIncome['Input'], AtualizarFonteRendaPessoaEnvolvidaRequest> {
private addressApiMapper: AddressApiMapper
constructor() {
this.addressApiMapper = new AddressApiMapper()
}
private mapSourceIncomeToApi = (sI: SourceIncome): ProjetoPessoaEnvolvidaFonteRendaApiModel => ({
cnpj: extractNumbers(sI.cnpj),
cargoFuncao: sI.position,
fotoComprovante: sI.proofAddress.split(',')[1],
telefone: extractNumbers(sI.mobile),
razaoSocial: sI.companyName,
dataAdmissao: sI.admissionDate || undefined,
endereco: sI.address ? this.addressApiMapper.mapDomainToApiModel(sI.address) : undefined,
rendaLiquida: Number(sI.netIncome) / 100,
})
public mapDomainToApiModel = (input: UpdateCDSourceIncome['Input']): AtualizarFonteRendaPessoaEnvolvidaRequest => ({
projetoId: input.projectId,
pessoaId: input.personId,
pessoaEnvolvidaFonteRendaRequestApiModel: { fonteRenda: this.mapSourceIncomeToApi(input.sourceIncome) },
})
}
export class CDUpdateSpouseDataApiMapper implements ApiAdapter<UpdateCDSpouseData['Input'], AtualizarConjugePessoaEnvolvidaRequest> {
private rgApiAdapter: RGApiAdapter
constructor() {
this.rgApiAdapter = new RGApiAdapter()
}
private mapSpouseDataToApi = (spouse: SpousePersonalData): ProjetoPessoaEnvolvidaConjugeApiModel => ({
cpf: extractNumbers(spouse.cpf),
dataNascimento: spouse.birthday || undefined,
dependentes: spouse.dependents ? Number(spouse.dependents) : undefined,
escolaridade: spouse.schooling ? Number(spouse.schooling) : undefined,
estadoCivil: spouse.maritalStatus ? Number(spouse.maritalStatus) : undefined,
nome: spouse.name,
nomeMae: spouse.mothersName,
nomePai: spouse.fathersName,
porcentagemParticipacao: spouse.participationPercentage ? Number(spouse.participationPercentage) : undefined,
profissao: spouse.occupation,
rg: spouse.rg ? this.rgApiAdapter.mapDomainToApiModel(spouse.rg) : undefined,
usuarioCRAS: spouse.userCRAS,
certidaoCasamento: spouse.marriageCertificate,
})
public mapDomainToApiModel = (input: UpdateCDSpouseData['Input']): AtualizarConjugePessoaEnvolvidaRequest => ({
projetoId: input.projectId,
pessoaId: input.personId,
projetoPessoaEnvolvidaConjugeApiModel: this.mapSpouseDataToApi(input.spouseData),
})
}
export * from './businessData'
export * from './customerData'
import { ProposalDataContext } from '@agiliza/api/domain'
import { EnquadramentoApiModel, GeneroApiModel } from '@microcredito/client'
import {
EnquadramentoApiModel,
EscolaridadeApiModel,
EstadoCivilApiModel,
GeneroApiModel
} from '@microcredito/client'
import { DomainAdapter, IdDescriptionMapper } from '../shared'
export interface DadosPropostaContexto {
enquadramentos: EnquadramentoApiModel[]
generos: GeneroApiModel[]
escolaridades: EscolaridadeApiModel[]
estadosCivis: EstadoCivilApiModel[]
}
export class ContextMapper implements DomainAdapter<DadosPropostaContexto, ProposalDataContext> {
......@@ -17,5 +24,7 @@ export class ContextMapper implements DomainAdapter<DadosPropostaContexto, Propo
public mapApiModelToDomain = (dP: DadosPropostaContexto): ProposalDataContext => ({
frameworks: dP.enquadramentos.map(this.idDescriptionMapper.mapApiModelToDomain),
genders: dP.generos.map(this.idDescriptionMapper.mapApiModelToDomain),
schoolings: dP.escolaridades.map(this.idDescriptionMapper.mapApiModelToDomain),
maritalStatus: dP.estadosCivis.map(this.idDescriptionMapper.mapApiModelToDomain),
})
}
import {
Address,
InvolvedPerson,
IPAddress,
PersonalData,
RG,
SourceIncome,
UpdateCDSpouseData,
Workplace
} from '@agiliza/api/domain'
import {
EnderecoApiModel,
ProjetoPessoaEnvolvidaConjugeApiModel,
ProjetoPessoaEnvolvidaConjugeDadosAdicionaisApiModel,
ProjetoPessoaEnvolvidaConjugeDadosAdicionaisLocalTrabalhoApiModel,
ProjetoPessoaEnvolvidaDadosPessoaisApiModel,
ProjetoPessoaEnvolvidaEnderecoApiModel,
ProjetoPessoaEnvolvidaFonteRendaApiModel,
ProjetoPessoaEnvolvidaIdentificacaoApiModel,
ProjetoPessoaEnvolvidaRGApiModel
} from '@microcredito/client'
import { DomainAdapter } from '../shared'
export class AddressMapper implements DomainAdapter<EnderecoApiModel, Address> {
public mapApiModelToDomain = (endereco: EnderecoApiModel): Address => ({
id: endereco.id || '',
cep: endereco.cep,
city: endereco.municipio,
state: endereco.estado,
complement: endereco.complemento || '',
district: endereco.bairro,
street: endereco.logradouro,
number: endereco.numero,
})
}
export class CDIdentificationAdapter implements DomainAdapter<ProjetoPessoaEnvolvidaIdentificacaoApiModel, InvolvedPerson['identification']> {
public mapContaBanestesToDomain = (
conta: ProjetoPessoaEnvolvidaIdentificacaoApiModel['contaBanestes']
): InvolvedPerson['identification']['account'] => ({
number: conta?.numeroConta,
agencyNumber: conta?.numeroAgencia,
cardPicture: conta?.fotoCartao,
})
public mapDadosTipoToDomain = (dados: ProjetoPessoaEnvolvidaIdentificacaoApiModel['dadosTipo']): InvolvedPerson['identification']['dataType'] => ({
doesWithdrawal: dados?.fazRetirada,
framework: dados?.enquadramento,
participationPercentage: dados?.porcentagemParticipacao?.toString() ?? '',
})
public mapApiModelToDomain = (pessoa: ProjetoPessoaEnvolvidaIdentificacaoApiModel): InvolvedPerson['identification'] => ({
id: pessoa.id || '',
name: pessoa.nome,
cpfcnpj: pessoa.cpfcnpj,
gender: pessoa.sexo,
type: pessoa.tipo,
account: pessoa.contaBanestes ? this.mapContaBanestesToDomain(pessoa.contaBanestes) : undefined,
dataType: pessoa.dadosTipo ? this.mapDadosTipoToDomain(pessoa.dadosTipo) : undefined,
})
}
export class RGMapper implements DomainAdapter<ProjetoPessoaEnvolvidaRGApiModel, RG> {
public mapApiModelToDomain = (rg: ProjetoPessoaEnvolvidaRGApiModel): RG => ({
back: rg.verso ?? '',
front: rg.frente ?? '',
number: rg.numero ?? '',
dispatcherAgency: rg.orgaoExpedidor ?? '',
})
}
export class CDPersonalDataMapper implements DomainAdapter<ProjetoPessoaEnvolvidaDadosPessoaisApiModel, PersonalData> {
private rgAdapter: RGMapper
constructor() {
this.rgAdapter = new RGMapper()
}
public mapApiModelToDomain = (pessoa: ProjetoPessoaEnvolvidaDadosPessoaisApiModel): PersonalData => ({
rg: pessoa.rg ? this.rgAdapter.mapApiModelToDomain(pessoa.rg) : undefined,
birthday: pessoa.dataNascimento || null,
userCRAS: pessoa.usuarioCRAS ?? false,
mothersName: pessoa.nomeMae ?? '',
fathersName: pessoa.nomePai ?? '',
occupation: pessoa.profissao ?? '',
schooling: pessoa.escolaridade ?? '',
maritalStatus: pessoa.estadoCivil ?? '',
dependents: pessoa.dependentes ?? '',
primaryEmail: pessoa.emailPrimario ?? '',
secundaryEmail: pessoa.emailSecundario ?? '',
mobile: pessoa.telefone ?? '',
landline: pessoa.telefoneFixo ?? '',
})
}
export class CDUpdateAddressMapper implements DomainAdapter<ProjetoPessoaEnvolvidaEnderecoApiModel, IPAddress> {
public mapApiModelToDomain = ({ endereco, comprovante }: ProjetoPessoaEnvolvidaEnderecoApiModel): IPAddress => ({
id: endereco?.id || '',
proof: comprovante || '',
cep: endereco?.cep || '',
number: endereco?.numero || '',
state: endereco?.estado || '',
city: endereco?.municipio || '',
district: endereco?.bairro || '',
complement: endereco?.complemento || '',
street: endereco?.logradouro || '',
})
}
export class CDSourceIncomeAdapter implements DomainAdapter<ProjetoPessoaEnvolvidaFonteRendaApiModel, SourceIncome> {
private addressAdapter: AddressMapper
constructor() {
this.addressAdapter = new AddressMapper()
}
public mapApiModelToDomain = (fonteRenda: ProjetoPessoaEnvolvidaFonteRendaApiModel): SourceIncome => ({
cnpj: fonteRenda.cnpj || '',
admissionDate: fonteRenda.dataAdmissao || null,
companyName: fonteRenda.razaoSocial || '',
position: fonteRenda.cargoFuncao || '',
mobile: fonteRenda.telefone || '',
netIncome: fonteRenda.rendaLiquida ? fonteRenda.rendaLiquida.toFixed(2) : '',
proofAddress: fonteRenda.fotoComprovante || '',
address: fonteRenda.endereco ? this.addressAdapter.mapApiModelToDomain(fonteRenda.endereco) : undefined,
})
}
export class WorkplaceAdapter implements DomainAdapter<ProjetoPessoaEnvolvidaConjugeDadosAdicionaisLocalTrabalhoApiModel, Workplace> {
public mapApiModelToDomain = (localTrabalho: ProjetoPessoaEnvolvidaConjugeDadosAdicionaisLocalTrabalhoApiModel): Workplace => ({
// address: localTrabalho.endereco ? this.addressAdapter.mapApiModelToDomain(localTrabalho.endereco) : undefined,
admissionDate: localTrabalho.dataAdmissao,
netIncome: localTrabalho.rendaLiquida?.toFixed(2),
phone: localTrabalho.telefone,
proof: localTrabalho.comprovanteRenda,
role: localTrabalho.cargo,
workplaceName: localTrabalho.razaoSocial,
cnpj: localTrabalho.cnpj,
})
}
export class CDUpdateSpouseDataMapper implements DomainAdapter<ProjetoPessoaEnvolvidaConjugeApiModel, UpdateCDSpouseData['Output']> {
private rgMapper: RGMapper
private workspaceMapper: WorkplaceAdapter
constructor() {
this.rgMapper = new RGMapper()
this.workspaceMapper = new WorkplaceAdapter()
}
public mapApiModelToDomain = (
pessoa: ProjetoPessoaEnvolvidaConjugeApiModel & ProjetoPessoaEnvolvidaConjugeDadosAdicionaisApiModel
): UpdateCDSpouseData['Output'] => ({
rg: pessoa.rg ? this.rgMapper.mapApiModelToDomain(pessoa.rg) : undefined,
birthday: pessoa.dataNascimento,
userCRAS: pessoa.usuarioCRAS ?? false,
mothersName: pessoa.nomeMae ?? '',
fathersName: pessoa.nomePai ?? '',
occupation: pessoa.profissao ?? '',
schooling: pessoa.escolaridade?.toString() ?? '',
maritalStatus: pessoa.estadoCivil?.toString() ?? '',
dependents: pessoa.dependentes?.toString() ?? '',
participationPercentage: pessoa.porcentagemParticipacao?.toString() ?? undefined,
name: pessoa.nome ?? '',
cpf: pessoa.cpf ?? '',
marriageCertificate: pessoa.certidaoCasamento ?? '',
landline: pessoa.telefoneFixo ?? '',
mobile: pessoa.telefoneCelular ?? '',
primaryEmail: pessoa.emailPrimario ?? '',
secundaryEmail: pessoa.emailSecundario ?? '',
workplace: pessoa.localTrabalho ? this.workspaceMapper.mapApiModelToDomain(pessoa.localTrabalho) : undefined,
})
}
export * from './businessData'
export * from './context'
export * from './customerData'
......@@ -31,7 +31,12 @@ export class ProposalDataContextRepositoryImpl implements ProposalDataContextRep
public fetchContext = async (): Promise<FetchContext['Output']> => {
try {
const contexto: DadosPropostaContexto = { enquadramentos: await this.api.obterEnquadramentos(), generos: await this.api.obterGeneros() }
const contexto: DadosPropostaContexto = {
enquadramentos: await this.api.obterEnquadramentos(),
generos: await this.api.obterGeneros(),
escolaridades: await this.api.obterEscolaridades(),
estadosCivis: await this.api.obterEstadosCivis(),
}
return this.contextMapper.mapApiModelToDomain(contexto)
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
......
import { CreateProposal, UpdateBDIdentification } from '@agiliza/api/domain'
import {
AddCDIdentification,
CreateProposal,
UpdateCDAddress,
UpdateCDPersonalData,
UpdateCDSourceIncome,
UpdateCDSpouseData
} from '@agiliza/api/domain'
import { ClienteApi, Configuration } from '@microcredito/client'
import { ErrorMappers, ProposalDataApiMappers, ProposalDataMappers } from '../../mappers'
......@@ -6,21 +13,41 @@ import { API_URL, mapUserAgentToString, SESSION_KEY, UserAgent } from '../shared
export interface PDCustomerDataDataRepository {
createProposal(input: CreateProposal['Input']): Promise<CreateProposal['Output']>
updateIdentification(input: UpdateBDIdentification['Input']): Promise<UpdateBDIdentification['Output']>
addIdentification(input: AddCDIdentification['Input']): Promise<AddCDIdentification['Output']>
updatePersonalData(input: UpdateCDPersonalData['Input']): Promise<UpdateCDPersonalData['Output']>
updateAddress(input: UpdateCDAddress['Input']): Promise<UpdateCDAddress['Output']>
updateSourceIncome(input: UpdateCDSourceIncome['Input']): Promise<UpdateCDSourceIncome['Output']>
updateSpouseData(input: UpdateCDSpouseData['Input']): Promise<UpdateCDSpouseData['Output']>
}
export class PDCustomerDataRepositoryImpl implements PDCustomerDataDataRepository {
private api: ClienteApi
private errorAdapter: ErrorMappers.ResponseErrorAdapter
private updateIdentificationApiMapper: ProposalDataApiMappers.BDUpdateIdentificationApiMapper
private identificationMapper: ProposalDataMappers.BDIdentificationMapper
private createProposalApiMapper: ProposalDataApiMappers.CreateProposalApiMapper
private cdUpdateIdentificationApiMapper: ProposalDataApiMappers.CDAddIdentificationMapper
private cdUpdatePersonalDataApiMapper: ProposalDataApiMappers.CDUpdatePersonalDataMapper
private cdIdentificationMapper: ProposalDataMappers.CDIdentificationAdapter
private cdPersonalDataMapper: ProposalDataMappers.CDPersonalDataMapper
private cdUpdateAddressApiMapper: ProposalDataApiMappers.CDUpdateAddressApiMapper
private cdUpdateAddressMapper: ProposalDataMappers.CDUpdateAddressMapper
private cdUpdateSourceIncomeApiMapper: ProposalDataApiMappers.CDUpdateSourceIncomeApiMapper
private cdUpdateSourceIncomeMapper: ProposalDataMappers.CDSourceIncomeAdapter
private cdUpdateSpouseDataApiMapper: ProposalDataApiMappers.CDUpdateSpouseDataApiMapper
private cdUpdateSpouseDataMapper: ProposalDataMappers.CDUpdateSpouseDataMapper
constructor(userAgent: string, accessToken: string) {
this.errorAdapter = new ErrorMappers.ResponseErrorAdapter()
this.updateIdentificationApiMapper = new ProposalDataApiMappers.BDUpdateIdentificationApiMapper()
this.identificationMapper = new ProposalDataMappers.BDIdentificationMapper()
this.createProposalApiMapper = new ProposalDataApiMappers.CreateProposalApiMapper()
this.cdIdentificationMapper = new ProposalDataMappers.CDIdentificationAdapter()
this.cdUpdateIdentificationApiMapper = new ProposalDataApiMappers.CDAddIdentificationMapper()
this.cdUpdatePersonalDataApiMapper = new ProposalDataApiMappers.CDUpdatePersonalDataMapper()
this.cdPersonalDataMapper = new ProposalDataMappers.CDPersonalDataMapper()
this.cdUpdateAddressApiMapper = new ProposalDataApiMappers.CDUpdateAddressApiMapper()
this.cdUpdateAddressMapper = new ProposalDataMappers.CDUpdateAddressMapper()
this.cdUpdateSourceIncomeApiMapper = new ProposalDataApiMappers.CDUpdateSourceIncomeApiMapper()
this.cdUpdateSourceIncomeMapper = new ProposalDataMappers.CDSourceIncomeAdapter()
this.cdUpdateSpouseDataApiMapper = new ProposalDataApiMappers.CDUpdateSpouseDataApiMapper()
this.cdUpdateSpouseDataMapper = new ProposalDataMappers.CDUpdateSpouseDataMapper()
this.api = new ClienteApi(
new Configuration({
......@@ -33,10 +60,10 @@ export class PDCustomerDataRepositoryImpl implements PDCustomerDataDataRepositor
)
}
public updateIdentification = async (input: UpdateBDIdentification['Input']): Promise<UpdateBDIdentification['Output']> => {
public addIdentification = async (input: AddCDIdentification['Input']): Promise<AddCDIdentification['Output']> => {
try {
const response = await this.api.atualizarIdentificacaoDadosNegocio(this.updateIdentificationApiMapper.mapDomainToApiModel(input))
return this.identificationMapper.mapApiModelToDomain(response)
const response = await this.api.incluirPessoaEnvolvida(this.cdUpdateIdentificationApiMapper.mapDomainToApiModel(input))
return this.cdIdentificationMapper.mapApiModelToDomain(response)
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
......@@ -46,7 +73,47 @@ export class PDCustomerDataRepositoryImpl implements PDCustomerDataDataRepositor
public createProposal = async (input: CreateProposal['Input']): Promise<CreateProposal['Output']> => {
try {
const response = await this.api.criarProposta(this.createProposalApiMapper.mapDomainToApiModel(input))
return { proposalId: response.propostaId || '' }
return response.propostaId || ''
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
public updatePersonalData = async (input: UpdateCDPersonalData['Input']): Promise<UpdateCDPersonalData['Output']> => {
try {
const response = await this.api.atualizarDadosPessoaisPessoaEnvolvida(this.cdUpdatePersonalDataApiMapper.mapDomainToApiModel(input))
return this.cdPersonalDataMapper.mapApiModelToDomain(response)
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
public updateAddress = async (input: UpdateCDAddress['Input']): Promise<UpdateCDAddress['Output']> => {
try {
const response = await this.api.atualizarEnderecoPessoaEnvolvida(this.cdUpdateAddressApiMapper.mapDomainToApiModel(input))
return this.cdUpdateAddressMapper.mapApiModelToDomain(response)
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
public updateSourceIncome = async (input: UpdateCDSourceIncome['Input']): Promise<UpdateCDSourceIncome['Output']> => {
try {
const response = await this.api.atualizarFonteRendaPessoaEnvolvida(this.cdUpdateSourceIncomeApiMapper.mapDomainToApiModel(input))
return this.cdUpdateSourceIncomeMapper.mapApiModelToDomain(response)
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
public updateSpouseData = async (input: UpdateCDSpouseData['Input']): Promise<UpdateCDSpouseData['Output']> => {
try {
const response = await this.api.atualizarConjugePessoaEnvolvida(this.cdUpdateSpouseDataApiMapper.mapDomainToApiModel(input))
return this.cdUpdateSpouseDataMapper.mapApiModelToDomain(response)
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
......
export * from './context'
export * from './businessData'
export * from './customerData'
import cn from 'classnames'
import React from 'react'
import { Button } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles'
import { PhotoCamera as PhotoCameraIcon } from '@material-ui/icons'
import styles from './styles'
type ExtendedProps = WithStyles<typeof styles>
interface Props extends ExtendedProps {
image?: string
onChangeImage: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>['onChange']
label: string
imageStyle?: React.HTMLAttributes<HTMLDivElement>['style']
className?: string
buttonClassName?: string
}
const ImageUpload = (props: Props) => {
const { classes, className, buttonClassName, image, onChangeImage, label, imageStyle } = props
return (
<div className={className}>
<Button variant="text" component="label" className={cn(classes.photoBtn, buttonClassName)} classes={{ label: classes.photoLabelBtn }}>
{image ? (
<div className={classes.card} style={imageStyle}>
<img src={image} className={classes.media} />
</div>
) : (
<PhotoCameraIcon />
)}
{label}
<input
type="file"
// value={image}
accept="image/jpg, image/jpeg, image/png"
hidden
onChange={onChangeImage}
/>
</Button>
</div>
)
}
export default withStyles(styles)(ImageUpload)
export { default } from './ImageUpload'
export * from './ImageUpload'
import { Theme } from '@material-ui/core/styles'
import { createStyles } from '@material-ui/styles'
// eslint-disable-next-line
export default (theme: Theme) => {
return createStyles({
photoBtn: { width: '100%' },
photoLabelBtn: { display: 'flex', flexDirection: 'column', height: '280px', alignItems: 'center', flexGrow: 1 },
card: { width: '100%', maxWidth: '100%', height: '100%', textAlign: 'center' },
media: {
height: '230px',
maxWidth: '100%',
width: 'auto',
// paddingTop: '56.25%', // 16:9
},
})
}
export * from './DashboardCard'
export * from './ImageUpload'
import React from 'react'
import { BanestesAccount } from '@agiliza/api/domain'
import { Button, TextField, TextFieldProps } from '@material-ui/core'
import ImageUpload from '@agiliza/components/organisms/ImageUpload'
import { extractNumbers } from '@agiliza/utils/method'
import { TextField, TextFieldProps } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles'
import { PhotoCamera as PhotoCameraIcon } from '@material-ui/icons'
import styles from './styles'
......@@ -24,34 +25,31 @@ const AccountInputsPhoto = (props: Props) => {
const handleChangeField = (type: keyof BanestesAccount): TextFieldProps['onChange'] => onChanges.account(type)
const handleChangePhoto: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>['onChange'] = (evt) => {
const handleChangePhoto: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>['onChange'] = async (evt) => {
const file = evt.target.files && evt.target.files[0]
if (file) onChanges.photo(URL.createObjectURL(file))
if (file) {
const b64: string = await new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => resolve(reader.result as string)
reader.onerror = (error) => reject(error)
})
onChanges.photo(b64)
}
}
return (
<div className={classes.accountInputsPhotoContainer}>
<div className={classes.accountInputsContainer}>
<TextField label="Número da agência" value={agencyNumber || ''} onChange={handleChangeField('agencyNumber')} variant="outlined" />
<TextField label="Número da conta corrente" value={number || ''} onChange={handleChangeField('number')} variant="outlined" />
</div>
<Button variant="text" component="label" className={classes.photoBtn} classes={{ label: classes.photoLabelBtn }}>
{cardPicture ? (
<div className={classes.card}>
<img src={cardPicture} className={classes.media} />
</div>
) : (
<PhotoCameraIcon />
)}
Foto cartão
<input
type="file"
// value={cardPicture}
accept="image/jpg, image/jpeg, image/png"
hidden
onChange={handleChangePhoto}
<TextField
label="Número da agência"
value={extractNumbers(agencyNumber) || ''}
onChange={handleChangeField('agencyNumber')}
variant="outlined"
/>
</Button>
<TextField label="Número da conta corrente" value={extractNumbers(number) || ''} onChange={handleChangeField('number')} variant="outlined" />
</div>
<ImageUpload label="Foto cartão" image={cardPicture} onChangeImage={handleChangePhoto} />
</div>
)
}
......
......@@ -4,8 +4,8 @@ import { createStyles } from '@material-ui/styles'
// eslint-disable-next-line
export default (theme: Theme) => {
return createStyles({
accountInputsPhotoContainer: { display: 'flex', flexDirection: 'column', alignItems: 'center', height: '100%' },
accountInputsContainer: { marginRight: theme.spacing(1), height: '100%' },
accountInputsPhotoContainer: { width: '100%', height: '100%' },
accountInputsContainer: { height: '100%' },
photoBtn: { minWidth: '50%' },
photoLabelBtn: { display: 'flex', flexDirection: 'column', height: '280px', alignItems: 'center', flexGrow: 1 },
card: { width: 'auto', height: 'auto' },
......
import React, { useMemo } from 'react'
import { City, State } from '@agiliza/api/domain'
import { ActionType } from '@agiliza/utils/hooks/state'
import { maskCEP } from '@agiliza/utils/masks'
import { SelectField, SelectFieldProps } from '@curio/components'
import { TextField, TextFieldProps } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles'
import { AddressState as FormState } from './state'
import { AddressState } from './state'
import styles from './styles'
type ExtendedProps = WithStyles<typeof styles>
......@@ -15,25 +14,25 @@ type ExtendedProps = WithStyles<typeof styles>
interface Props extends ExtendedProps {
states: State[]
cities: City[]
state: FormState
actions: ActionType<FormState>
state: AddressState
onChange: (address: Partial<AddressState>) => void
}
const Address = (props: Props) => {
const { classes, state: _state, actions, states, cities } = props
const { classes, state: _state, onChange, states, cities } = props
const { cep, street, number, complement, state, city, district } = _state
const handleChange =
(key: keyof FormState): TextFieldProps['onChange'] =>
(key: keyof AddressState): TextFieldProps['onChange'] =>
(evt) => {
actions.update({ [key]: evt.target.value })
onChange({ [key]: evt.target.value })
}
const handleChangeSelect =
(key: keyof FormState): SelectFieldProps['onChange'] =>
(key: keyof AddressState): SelectFieldProps['onChange'] =>
(value) => {
actions.update({ [key]: value })
onChange({ [key]: value })
}
const availableCities = useMemo(() => {
......
......@@ -7,7 +7,7 @@ import { maskCPFCNPJ, maskPhone } from '@agiliza/utils/masks'
import { TextField, TextFieldProps } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles'
import AddressForm from '../Address'
import AddressForm, { AddressState } from '../Address'
import { initState, State as FirstAccessState } from './state'
import styles from './styles'
......@@ -33,6 +33,9 @@ const FirstAccess = (props: Props) => {
actions.update({ [key]: evt.target.value })
errorActions.validate({ [key]: evt.target.value })
}
const handleChangeAddress = (value: Partial<AddressState>) => {
actions.update(value)
}
return (
<form className={classes.form}>
......@@ -48,7 +51,7 @@ const FirstAccess = (props: Props) => {
<TextField variant="outlined" label="Nome" value={name} onChange={handleChange('name')} />
<TextField variant="outlined" label="Email" value={email} onChange={handleChange('email')} />
<TextField variant="outlined" label="Telefone" value={maskPhone(phone)} onChange={handleChange('phone')} inputProps={{ maxLength: 15 }} />
<AddressForm state={addressState} actions={actions} states={states} cities={cities} />
<AddressForm state={addressState} onChange={handleChangeAddress} states={states} cities={cities} />
</form>
)
}
......
import React from 'react'
import { RG } from '@agiliza/api/domain'
import ImageUpload from '@agiliza/components/organisms/ImageUpload'
import { maskRG } from '@agiliza/utils/masks'
import { TextField, TextFieldProps } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles'
import styles from './styles'
type ExtendedProps = WithStyles<typeof styles>
interface Props extends ExtendedProps {
rg?: RG
onChange: (rg: Partial<RG>) => void
}
const RGTemplate = (props: Props) => {
const { classes, rg, onChange } = props
const handleChangePhoto =
(key: keyof Pick<RG, 'front' | 'back'>): React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>['onChange'] =>
async (evt) => {
const file = evt.target.files && evt.target.files[0]
if (file) {
const b64 = await new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => resolve(reader.result)
reader.onerror = (error) => reject(error)
})
onChange({ [key]: b64 })
}
}
const handleChangeField =
(key: keyof RG): TextFieldProps['onChange'] =>
(evt) => {
onChange({ [key]: evt.target.value })
}
return (
<div className={classes.container}>
<div className={classes.imagesContainer}>
<ImageUpload label="Frente" image={rg?.front} onChangeImage={handleChangePhoto('front')} className={classes.imageUpload} />
<ImageUpload label="Verso" image={rg?.back} onChangeImage={handleChangePhoto('back')} className={classes.imageUpload} />
</div>
<TextField
variant="outlined"
label="Número do RG"
value={maskRG(rg?.number || '')}
onChange={handleChangeField('number')}
inputProps={{ maxLength: 9 }}
/>
<TextField variant="outlined" label="Órgão Exp." value={rg?.dispatcherAgency || ''} onChange={handleChangeField('dispatcherAgency')} />
</div>
)
}
export default withStyles(styles)(RGTemplate)
export { default } from './RGTemplate'
export * from './RGTemplate'
import { Theme } from '@material-ui/core/styles'
import { createStyles } from '@material-ui/styles'
// eslint-disable-next-line
export default (theme: Theme) => {
return createStyles({
container: { display: 'flex', flexDirection: 'column', alignItems: 'center' },
imagesContainer: { display: 'flex', width: '100%', padding: theme.spacing(1) },
imageUpload: { width: '50%', textAlign: 'center' },
})
}
......@@ -3,3 +3,4 @@ export * from './AccountInputsPhoto'
export * from './Login'
export * from './Address'
export * from './FirstAccess'
export * from './RGTemplate'
......@@ -12,6 +12,8 @@ export interface Store extends WithEntityStore<ProposalDataContext> {
export const initialState: Store = {
frameworks: { byId: {}, allIds: [] },
genders: { byId: {}, allIds: [] },
schoolings: { byId: {}, allIds: [] },
maritalStatus: { byId: {}, allIds: [] },
}
export default createSlice({
......
import { combineReducers } from 'redux'
import context, { initialState as contextInitState, Store as ContextStore } from './context'
import proposal, { initialState as proposalInitState, Store as ProposalStore } from './proposal'
export interface State {
context: ContextStore
proposal: ProposalStore
}
export const initialState: State = {
context: contextInitState,
proposal: proposalInitState,
}
export default combineReducers({
context,
proposal,
})
import { getActionTypes } from '@agiliza/utils/method'
import * as selectors from './selectors'
import slice from './slice'
export * from './slice'
const actions = slice.actions
const reducer = slice.reducer
const types = getActionTypes(slice.actions)
export { actions, types, selectors }
export default reducer
import { Store } from './slice'
export const getProposalId = (state: Store) => state.proposalId
export const getPersonlId = (state: Store) => state.personId
import { Identification } from '@agiliza/api/domain'
import { types as fetchTypes } from '@agiliza/redux/useCases/proposalData/customerData'
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import { PROPOSAL_DATA_PREFIX } from '../shared'
export interface Store {
proposalId: string
personId: string
}
export const initialState: Store = {
proposalId: '',
personId: '',
}
export default createSlice({
name: `${PROPOSAL_DATA_PREFIX}/proposal`,
initialState,
reducers: {},
extraReducers: {
[fetchTypes.createProposal.fulfilled]: (state, action: PayloadAction<string>) => {
state.proposalId = action.payload
},
[fetchTypes.addIndentification.fulfilled]: (state, action: PayloadAction<Identification>) => {
state.personId = action.payload.id
},
},
})
......@@ -10,6 +10,8 @@ export type NormalizedContext = WithNormalizedEntity<ProposalDataContext>
const contextSchemas = new schema.Object({
frameworks: new schema.Array(new schema.Entity('frameworks')),
genders: new schema.Array(new schema.Entity('genders')),
schoolings: new schema.Array(new schema.Entity('schoolings')),
maritalStatus: new schema.Array(new schema.Entity('maritalStatus')),
})
export const normalizeContext = (context: ProposalDataContext) => {
......
import { CreateProposal } from '@agiliza/api/domain'
import {
AddCDIdentification,
CreateProposal,
UpdateCDAddress,
UpdateCDPersonalData,
UpdateCDSourceIncome,
UpdateCDSpouseData
} from '@agiliza/api/domain'
import {
PDCustomerDataRepositoryImplFactory
} from '@agiliza/api/useCases/proposalData/customerData'
......@@ -32,10 +39,50 @@ export const actions = {
return thunkApi.rejectWithValue(e)
}
}),
updateIndentification: createAsyncThunk(`${prefix}/updateIndentification`, async (input: WithSuccess<CreateProposal['Input']>, thunkApi) => {
addIndentification: createAsyncThunk(`${prefix}/addIndentification`, async (input: WithSuccess<AddCDIdentification['Input']>, thunkApi) => {
const useCase = PDCustomerDataRepositoryImplFactory.create(appPlatform)
try {
const proposalId = await useCase.createProposal(input)
const proposal = await useCase.addIdentification(input)
input.onSuccess && input.onSuccess()
return proposal
} catch (e) {
return thunkApi.rejectWithValue(e)
}
}),
updatePersonalData: createAsyncThunk(`${prefix}/updatePersonalData`, async (input: WithSuccess<UpdateCDPersonalData['Input']>, thunkApi) => {
const useCase = PDCustomerDataRepositoryImplFactory.create(appPlatform)
try {
const proposalId = await useCase.updatePersonalData(input)
input.onSuccess && input.onSuccess()
return proposalId
} catch (e) {
return thunkApi.rejectWithValue(e)
}
}),
updateAddress: createAsyncThunk(`${prefix}/updateAddress`, async (input: WithSuccess<UpdateCDAddress['Input']>, thunkApi) => {
const useCase = PDCustomerDataRepositoryImplFactory.create(appPlatform)
try {
const proposalId = await useCase.updateAddress(input)
input.onSuccess && input.onSuccess()
return proposalId
} catch (e) {
return thunkApi.rejectWithValue(e)
}
}),
updateSourceIncome: createAsyncThunk(`${prefix}/updateSourceIncome`, async (input: WithSuccess<UpdateCDSourceIncome['Input']>, thunkApi) => {
const useCase = PDCustomerDataRepositoryImplFactory.create(appPlatform)
try {
const proposalId = await useCase.updateSourceIncome(input)
input.onSuccess && input.onSuccess()
return proposalId
} catch (e) {
return thunkApi.rejectWithValue(e)
}
}),
updateSpouseData: createAsyncThunk(`${prefix}/updateSourceIncome`, async (input: WithSuccess<UpdateCDSpouseData['Input']>, thunkApi) => {
const useCase = PDCustomerDataRepositoryImplFactory.create(appPlatform)
try {
const proposalId = await useCase.updateSpouseData(input)
input.onSuccess && input.onSuccess()
return proposalId
} catch (e) {
......
......@@ -62,6 +62,29 @@ export const maskPhone = (str?: string) => {
// return filteredString
}
export const maskLandline = (str?: string) => {
if (!str) return ''
const filteredString = extractNumbers(str)
const length = filteredString.length
if (length < 3) return filteredString
if (length < 8) return filteredString.replace(/(\d\d)/, '($1) ')
// if (length < 12) return filteredString.replace(/(\d\d)(\d\d\d\d\d)/, '($1) $2-')
return filteredString.replace(/(\d{2})(\d{4})/, '($1) $2-')
// return filteredString
}
export const maskRG = (txt?: string) => {
if (!txt) return ''
const filteredTxt = extractNumbers(txt)
if (filteredTxt.length < 2) return filteredTxt
if (filteredTxt.length < 5) return filteredTxt.replace(/^(\d)/g, '$1.')
if (filteredTxt.length < 8) return filteredTxt.replace(/^(\d)(\d{3})/g, '$1.$2.')
return txt
}
export const maskLicensePlate = (str?: string) => {
if (!str) return ''
const filteredString = str.toUpperCase().replace(/([^A-Z0-9]*)/g, '')
......
......@@ -193,3 +193,22 @@ export const getActionTypes = <Actions>(actions: Actions) => {
}
export type WithSuccess<T, A = void> = T & { onSuccess?: (args?: A) => void }
export const b64toBlob = (b64Data: string, contentType = '', sliceSize = 512) => {
const byteCharacters = atob(b64Data.replace(/(\s)/g, ''))
const byteArrays: Uint8Array[] = []
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize)
const byteNumbers = new Array(slice.length)
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i)
}
const byteArray = new Uint8Array(byteNumbers)
byteArrays.push(byteArray)
}
const blob = new Blob(byteArrays, { type: contentType })
return blob
}
......@@ -3,7 +3,6 @@ import { Redirect, Route, RouteComponentProps, Switch, useHistory } from 'react-
import AppBar from '@agiliza/components/molecules/AppBar'
import CircularProgress from '@agiliza/components/molecules/CircularProgress'
import NotFound from '@agiliza/components/templates/NotFound'
import { actions as drawerActions } from '@agiliza/redux/ui/drawer'
import { actions as loginActions } from '@agiliza/redux/ui/login'
import { ProposalDataRouteState } from '@agiliza/views/ProposalData/pages/ProposalData'
......@@ -52,8 +51,9 @@ const Main = (props: Props) => {
path={PATHS.proposalData}
render={(rProps) => {
const { location } = rProps as RouteComponentProps<any, any, ProposalDataRouteState>
if (!location.state) location.state = { subproductId: '0' }
if (location.state?.subproductId) return <ProposalData {...rProps} />
else return <NotFound {...rProps} />
else return <Redirect from={PATHS.proposalData} to="/" />
}}
/>
<Redirect from="/" to={PATHS.creditLines} />
......
......@@ -2,6 +2,7 @@ import React from 'react'
import { IPAddress } from '@agiliza/api/domain'
import { maskCEP } from '@agiliza/utils/masks'
import { extractNumbers } from '@agiliza/utils/method'
import { TextField, TextFieldProps } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles'
......@@ -30,7 +31,7 @@ const Address = (props: Props) => {
<>
<TextField variant="outlined" label="CEP" value={maskCEP(cep)} onChange={handleChangeText('cep')} inputProps={{ maxLength: 9 }} />
<TextField variant="outlined" label="Rua / Avenida" value={street} onChange={handleChangeText('street')} />
<TextField variant="outlined" label="Number" value={number} onChange={handleChangeText('number')} type="tel" />
<TextField variant="outlined" label="Number" value={extractNumbers(number)} onChange={handleChangeText('number')} type="tel" />
</>
)
}
......
import React from 'react'
import { useFormState } from '@agiliza/utils/hooks/state'
import { ActionType } from '@agiliza/utils/hooks/state'
import { withStyles, WithStyles } from '@material-ui/core/styles'
import { connected, ConnectedProps } from './connect'
import Form from './Form'
import { initialState } from './state'
import { CDAddressState } from './state'
import styles from './styles'
type ExtendedProps = WithStyles<typeof styles>
type ExtendedProps = WithStyles<typeof styles> & ConnectedProps
interface Props extends ExtendedProps {}
interface Props extends ExtendedProps {
state: CDAddressState
actions: ActionType<CDAddressState>
}
const Address = (props: Props) => {
const { classes } = props
const formState = useFormState('addressData', initialState)
const { classes, context, state, actions } = props
return (
<div className={classes.contentContainer}>
<div className={classes.content}>
<Form {...formState} />
<Form states={context.states} cities={context.cities} state={state} actions={actions} />
</div>
</div>
)
}
export default withStyles(styles)(Address)
export default connected(withStyles(styles)(Address))
import React from 'react'
import { City, State } from '@agiliza/api/domain'
import ImageUpload from '@agiliza/components/organisms/ImageUpload'
import Address, { AddressState } from '@agiliza/components/templates/Address'
import { ActionType } from '@agiliza/utils/hooks/state'
import Address from '@agiliza/views/ProposalData/components/templates/Address'
import { withStyles, WithStyles } from '@material-ui/core/styles'
import { CustomerAddressState } from '../state'
import { CDAddressState } from '../state'
import styles from './styles'
type ExtendedProps = WithStyles<typeof styles>
interface Props extends ExtendedProps {
state: CustomerAddressState
actions: ActionType<CustomerAddressState>
states: State[]
cities: City[]
state: CDAddressState
actions: ActionType<CDAddressState>
}
const Form = (props: Props) => {
const { classes, state, actions } = props
const { classes, state, actions, states, cities } = props
const { proof } = state
const handleChangeProof: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>['onChange'] = async (evt) => {
const file = evt.target.files && evt.target.files[0]
if (file) {
const b64: string = await new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => resolve(reader.result as string)
reader.onerror = (error) => reject(error)
})
actions.update({ proof: b64 })
}
}
const handleChangeAddress = (value: Partial<AddressState>) => {
actions.update(value)
}
return (
<form className={classes.form}>
<Address state={state} onChange={(addrs) => actions.update(addrs)} />
<ImageUpload label="Comprovante de residência" image={proof} onChangeImage={handleChangeProof} className={classes.imageUpload} />
<Address state={state} onChange={handleChangeAddress} states={states} cities={cities} />
</form>
)
}
......
......@@ -7,16 +7,6 @@ import sharedStyles from '../styles'
export default (theme: Theme) => {
return createStyles({
...sharedStyles(theme),
form: {
'& .MuiTextField-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
'& .MuiFormControl-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
},
switchCardPhotoContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly' },
datePicker: { marginBottom: '0px !important' },
})
......
import { connect } from 'react-redux'
import { AuthenticationContext } from '@agiliza/api/domain'
import { StoreState } from '@agiliza/redux'
import * as entAuthentication from '@agiliza/redux/entities/authentication'
import * as ucAuthentication from '@agiliza/redux/useCases/authentication'
export interface ConnectedProps {
fetching: boolean
context: AuthenticationContext
}
type StateProps = Pick<ConnectedProps, 'fetching' | 'context'>
// type DispatchProps = Pick<ConnectedProps, 'getContext'>
const mapStateToProps = (state: StoreState): StateProps => ({
fetching: ucAuthentication.selectors.isFetching(state.useCases.authentication),
context: entAuthentication.selectors.getContextEntities(state.entities.authentication),
})
// const mapDispatchToProps = (dispatch: Dispatch): DispatchProps =>
// bindActionCreators(
// {
// },
// dispatch
// )
export const connected = connect(mapStateToProps)
export { default } from './Address'
export * from './Address'
export * from './state'
......@@ -2,9 +2,9 @@ import { IPAddress } from '@agiliza/api/domain'
type ExtendedState = IPAddress
export interface CustomerAddressState extends ExtendedState {}
export interface CDAddressState extends ExtendedState {}
export const initialState: CustomerAddressState = {
export const initialState: CDAddressState = {
id: '',
proof: '',
cep: '',
......
......@@ -7,16 +7,7 @@ import sharedStyles from '../styles'
export default (theme: Theme) => {
return createStyles({
...sharedStyles(theme),
form: {
'& .MuiTextField-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
'& .MuiFormControl-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
},
switchCardPhotoContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly' },
})
}
......@@ -64,13 +64,7 @@ const Form = (props: Props) => {
variant="outlined"
shrink={false}
/>
<TextField
variant="outlined"
label="CPF / CNPJ"
value={maskCPFCNPJ(cpfcnpj)}
onChange={handleChangeText('cpfcnpj')}
inputProps={{ maxLength: 18 }}
/>
<TextField variant="outlined" label="CPF" value={maskCPFCNPJ(cpfcnpj)} onChange={handleChangeText('cpfcnpj')} inputProps={{ maxLength: 14 }} />
<TextField variant="outlined" label="Nome / Razão social" value={name || ''} onChange={handleChangeText('name')} />
<SelectField
id="gender-select-field"
......
......@@ -7,16 +7,6 @@ import sharedStyles from '../styles'
export default (theme: Theme) => {
return createStyles({
...sharedStyles(theme),
form: {
'& .MuiTextField-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
'& .MuiFormControl-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
},
switchCardPhotoContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly' },
})
}
import React, { useEffect } from 'react'
import React from 'react'
import { ActionType } from '@agiliza/utils/hooks/state'
import { withStyles, WithStyles } from '@material-ui/core/styles'
......@@ -18,10 +18,6 @@ interface Props extends ExtendedProps {
const Identification = (props: Props) => {
const { classes, context, state, actions } = props
useEffect(() => {
props.fetchContext()
}, [])
return (
<div className={classes.contentContainer}>
<div className={classes.content}>
......
import { connect } from 'react-redux'
import { bindActionCreators, Dispatch } from 'redux'
import { ProposalDataContext } from '@agiliza/api/domain'
import { StoreState } from '@agiliza/redux'
import * as entProposalDataContext from '@agiliza/redux/entities/proposalData/context'
import * as ucProposalDataContext from '@agiliza/redux/useCases/proposalData/context'
import * as ucProposalDataCD from '@agiliza/redux/useCases/proposalData/customerData'
export interface ConnectedProps {
fetching: boolean
context: ProposalDataContext
fetchContext: typeof ucProposalDataContext.actions.fetchContext
updateIndentification: typeof ucProposalDataCD.actions.updateIndentification
}
type StateProps = Pick<ConnectedProps, 'fetching' | 'context'>
type DispatchProps = Pick<ConnectedProps, 'fetchContext' | 'updateIndentification'>
// type DispatchProps = Pick<ConnectedProps, 'addIndentification'>
const mapStateToProps = (state: StoreState): StateProps => ({
fetching: ucProposalDataContext.selectors.isFetching(state.ui.login),
context: entProposalDataContext.selectors.getContext(state.entities.proposalData.context),
})
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps =>
bindActionCreators(
{
fetchContext: ucProposalDataContext.actions.fetchContext,
updateIndentification: ucProposalDataCD.actions.updateIndentification,
},
dispatch
)
// const mapDispatchToProps = (dispatch: Dispatch): DispatchProps =>
// bindActionCreators(
// {
// },
// dispatch
// )
export const connected = connect(mapStateToProps, mapDispatchToProps)
export const connected = connect(mapStateToProps)
import { InvolvedPerson } from '@agiliza/api/domain'
import { INVOLVED_PERSON_TYPES } from '@agiliza/constants/involvedPeople'
type ExtendedState = Omit<InvolvedPerson['identification'], 'type'>
type ExtendedState = InvolvedPerson['identification']
export interface CDIdentificationState extends ExtendedState {
hasAccount: boolean
......@@ -11,6 +12,7 @@ export const initialState: CDIdentificationState = {
name: '',
cpfcnpj: '',
gender: '',
type: INVOLVED_PERSON_TYPES['CUSTOMER'],
hasAccount: false,
account: { agencyNumber: '', number: '', cardPicture: '' },
dataType: { doesWithdrawal: false, framework: '' },
......
import React from 'react'
import { ProposalDataContext } from '@agiliza/api/domain'
import RGTemplate from '@agiliza/components/templates/RGTemplate'
import { ActionType } from '@agiliza/utils/hooks/state'
import { DatePicker } from '@curio/components'
import { maskLandline, maskPhone } from '@agiliza/utils/masks'
import { DatePicker, SelectField, SelectFieldProps, Switch } from '@curio/components'
import { TextField, TextFieldProps } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles'
import { CustomerPersonalDataState } from '../state'
import { CDPersonalDataState } from '../state'
import styles from './styles'
type ExtendedProps = WithStyles<typeof styles>
interface Props extends ExtendedProps {
state: CustomerPersonalDataState
actions: ActionType<CustomerPersonalDataState>
state: CDPersonalDataState
actions: ActionType<CDPersonalDataState>
context: ProposalDataContext
}
const Form = (props: Props) => {
const { classes, state, actions } = props
const { classes, state, actions, context } = props
const { birthday, primaryEmail } = state
const {
birthday,
primaryEmail,
rg,
userCRAS,
mothersName,
fathersName,
occupation,
schooling,
maritalStatus,
dependents,
secundaryEmail,
mobile,
landline,
} = state
const handleChangeDate = (type: keyof Pick<CustomerPersonalDataState, 'birthday'>) => (date: Date | null) => {
const handleChangeDate = (type: keyof Pick<CDPersonalDataState, 'birthday'>) => (date: Date | null) => {
actions.update({ [type]: date })
}
const handleChangeText =
(key: keyof CustomerPersonalDataState): TextFieldProps['onChange'] =>
(key: keyof CDPersonalDataState): TextFieldProps['onChange'] =>
(evt) => {
actions.update({ [key]: evt.target.value })
}
const handleChangeRG = (rg: Partial<CDPersonalDataState['rg']>) => {
actions.update({ rg: rg as CDPersonalDataState['rg'] })
}
const handleChangeSelect =
(key: keyof CDPersonalDataState): SelectFieldProps['onChange'] =>
(value) => {
actions.update({ [key]: value })
}
return (
<form className={classes.form}>
<DatePicker
......@@ -40,7 +68,46 @@ const Form = (props: Props) => {
format="dd/MM/yyyy"
className={classes.datePicker}
/>
<RGTemplate rg={rg} onChange={handleChangeRG} />
<Switch label="Usuário CRAS?" required value={userCRAS} onChange={(value) => actions.update({ userCRAS: value })} />
<TextField variant="outlined" label="Nome da mãe" value={mothersName} onChange={handleChangeText('mothersName')} />
<TextField variant="outlined" label="Nome do pai" value={fathersName} onChange={handleChangeText('fathersName')} />
<TextField variant="outlined" label="Profissão" value={occupation} onChange={handleChangeText('occupation')} />
<SelectField
id="schooling-select-field"
shrink={false}
label="Escolaridade"
value={schooling}
items={context.schoolings.map((sch) => ({ label: sch.description, value: sch.id }))}
onChange={handleChangeSelect('schooling')}
variant="outlined"
/>
<SelectField
id="schooling-select-field"
shrink={false}
label="Estado Civil"
value={maritalStatus}
items={context.maritalStatus.map((sch) => ({ label: sch.description, value: sch.id }))}
onChange={handleChangeSelect('maritalStatus')}
variant="outlined"
/>
<TextField variant="outlined" label="Dependentes" type="number" value={dependents} onChange={handleChangeText('dependents')} />
<TextField variant="outlined" label="Email primário" value={primaryEmail} onChange={handleChangeText('primaryEmail')} />
<TextField variant="outlined" label="Email secondário" value={secundaryEmail} onChange={handleChangeText('secundaryEmail')} />
<TextField
variant="outlined"
label="Telefone celular"
value={maskPhone(mobile)}
onChange={handleChangeText('mobile')}
inputProps={{ maxLength: 15 }}
/>
<TextField
variant="outlined"
label="Telefone fixo"
value={maskLandline(landline)}
onChange={handleChangeText('landline')}
inputProps={{ maxLength: 14 }}
/>
</form>
)
}
......
......@@ -7,16 +7,7 @@ import sharedStyles from '../styles'
export default (theme: Theme) => {
return createStyles({
...sharedStyles(theme),
form: {
'& .MuiTextField-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
'& .MuiFormControl-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
},
switchCardPhotoContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly' },
datePicker: { marginBottom: '0px !important' },
})
......
import React from 'react'
import { useFormState } from '@agiliza/utils/hooks/state'
import { ActionType } from '@agiliza/utils/hooks/state'
import { withStyles, WithStyles } from '@material-ui/core/styles'
import { connected, ConnectedProps } from './connect'
import Form from './Form'
import { initialState } from './state'
import { CDPersonalDataState } from './state'
import styles from './styles'
type ExtendedProps = WithStyles<typeof styles>
type ExtendedProps = WithStyles<typeof styles> & ConnectedProps
interface Props extends ExtendedProps {}
interface Props extends ExtendedProps {
state: CDPersonalDataState
actions: ActionType<CDPersonalDataState>
}
const PersonalData = (props: Props) => {
const { classes } = props
const formState = useFormState('personalData', initialState)
const { classes, context, state, actions } = props
return (
<div className={classes.contentContainer}>
<div className={classes.content}>
<Form {...formState} />
<Form context={context} state={state} actions={actions} />
</div>
</div>
)
}
export default withStyles(styles)(PersonalData)
export default connected(withStyles(styles)(PersonalData))
import { connect } from 'react-redux'
import { ProposalDataContext } from '@agiliza/api/domain'
import { StoreState } from '@agiliza/redux'
import * as entProposalDataContext from '@agiliza/redux/entities/proposalData/context'
import * as ucProposalDataContext from '@agiliza/redux/useCases/proposalData/context'
export interface ConnectedProps {
fetching: boolean
context: ProposalDataContext
}
type StateProps = Pick<ConnectedProps, 'fetching' | 'context'>
// type DispatchProps = Pick<ConnectedProps, 'updateIndentification'>
const mapStateToProps = (state: StoreState): StateProps => ({
fetching: ucProposalDataContext.selectors.isFetching(state.ui.login),
context: entProposalDataContext.selectors.getContext(state.entities.proposalData.context),
})
// const mapDispatchToProps = (dispatch: Dispatch): DispatchProps =>
// bindActionCreators(
// {
// },
// dispatch
// )
export const connected = connect(mapStateToProps)
export { default } from './PersonalData'
export * from './PersonalData'
export * from './state'
......@@ -2,9 +2,9 @@ import { PersonalData } from '@agiliza/api/domain'
type ExtendedState = PersonalData
export interface CustomerPersonalDataState extends ExtendedState {}
export interface CDPersonalDataState extends ExtendedState {}
export const initialState: CustomerPersonalDataState = {
export const initialState: CDPersonalDataState = {
rg: { number: '', dispatcherAgency: '', front: '', back: '' },
birthday: null,
userCRAS: false,
......
......@@ -7,16 +7,7 @@ import sharedStyles from '../styles'
export default (theme: Theme) => {
return createStyles({
...sharedStyles(theme),
form: {
'& .MuiTextField-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
'& .MuiFormControl-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
},
switchCardPhotoContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly' },
datePicker: { marginBottom: '0px !important' },
})
......
import React from 'react'
import { AuthenticationContext } from '@agiliza/api/domain'
import ImageUpload from '@agiliza/components/organisms/ImageUpload'
import Address, { AddressState } from '@agiliza/components/templates/Address'
import { formatCurrency } from '@agiliza/utils/formatters'
import { ActionType } from '@agiliza/utils/hooks/state'
import { maskCPFCNPJ } from '@agiliza/utils/masks'
import { maskCPFCNPJ, maskPhone } from '@agiliza/utils/masks'
import { DatePicker } from '@curio/components'
import { TextField, TextFieldProps } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles'
......@@ -14,12 +18,13 @@ type ExtendedProps = WithStyles<typeof styles>
interface Props extends ExtendedProps {
state: CustomerSourceIncomeState
actions: ActionType<CustomerSourceIncomeState>
context: AuthenticationContext
}
const Form = (props: Props) => {
const { classes, state, actions } = props
const { classes, state, actions, context } = props
const { cnpj, admissionDate } = state
const { cnpj, admissionDate, companyName, proofAddress, mobile, netIncome, address } = state
const handleChangeDate = (type: keyof Pick<CustomerSourceIncomeState, 'admissionDate'>) => (date: Date | null) => {
actions.update({ [type]: date })
......@@ -31,8 +36,26 @@ const Form = (props: Props) => {
actions.update({ [key]: evt.target.value })
}
const handleChangeProof: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>['onChange'] = async (evt) => {
const file = evt.target.files && evt.target.files[0]
if (file) {
const b64: string = await new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => resolve(reader.result as string)
reader.onerror = (error) => reject(error)
})
actions.update({ proofAddress: b64 })
}
}
const handleChangeAddress = (value: Partial<AddressState>) => {
actions.update({ address: value })
}
return (
<form className={classes.form}>
<TextField variant="outlined" label="Razão social" value={companyName} onChange={handleChangeText('companyName')} />
<TextField variant="outlined" label="CNPJ" value={maskCPFCNPJ(cnpj)} onChange={handleChangeText('cnpj')} />
<DatePicker
id="admission-date"
......@@ -42,6 +65,10 @@ const Form = (props: Props) => {
format="dd/MM/yyyy"
className={classes.datePicker}
/>
<ImageUpload className={classes.imageUpload} label="Comprovante" image={proofAddress} onChangeImage={handleChangeProof} />
<TextField variant="outlined" label="Telefone" value={maskPhone(mobile)} onChange={handleChangeText('mobile')} />
<TextField variant="outlined" label="Renda líquida" value={formatCurrency(netIncome)} onChange={handleChangeText('netIncome')} />
<Address state={address} onChange={handleChangeAddress} states={context.states} cities={context.cities} />
</form>
)
}
......
......@@ -7,16 +7,7 @@ import sharedStyles from '../styles'
export default (theme: Theme) => {
return createStyles({
...sharedStyles(theme),
form: {
'& .MuiTextField-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
'& .MuiFormControl-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
},
switchCardPhotoContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly' },
datePicker: { marginBottom: '0px !important' },
})
......
import React from 'react'
import { useFormState } from '@agiliza/utils/hooks/state'
import { ActionType } from '@agiliza/utils/hooks/state'
import { withStyles, WithStyles } from '@material-ui/core/styles'
import { connected, ConnectedProps } from './connect'
import Form from './Form'
import { initialState } from './state'
import { CustomerSourceIncomeState } from './state'
import styles from './styles'
type ExtendedProps = WithStyles<typeof styles>
type ExtendedProps = WithStyles<typeof styles> & ConnectedProps
interface Props extends ExtendedProps {}
interface Props extends ExtendedProps {
state: CustomerSourceIncomeState
actions: ActionType<CustomerSourceIncomeState>
}
const SourceIncome = (props: Props) => {
const { classes } = props
const { classes, context, state, actions } = props
const formState = useFormState('sourceIncome', initialState)
return (
<div className={classes.contentContainer}>
<div className={classes.content}>
<Form {...formState} />
<Form state={state} actions={actions} context={context} />
</div>
</div>
)
}
export default withStyles(styles)(SourceIncome)
export default connected(withStyles(styles)(SourceIncome))
import { connect } from 'react-redux'
import { AuthenticationContext } from '@agiliza/api/domain'
import { StoreState } from '@agiliza/redux'
import * as entAuthentication from '@agiliza/redux/entities/authentication'
import * as ucAuthentication from '@agiliza/redux/useCases/authentication'
export interface ConnectedProps {
fetching: boolean
context: AuthenticationContext
}
type StateProps = Pick<ConnectedProps, 'fetching' | 'context'>
// type DispatchProps = Pick<ConnectedProps, 'getContext'>
const mapStateToProps = (state: StoreState): StateProps => ({
fetching: ucAuthentication.selectors.isFetching(state.useCases.authentication),
context: entAuthentication.selectors.getContextEntities(state.entities.authentication),
})
// const mapDispatchToProps = (dispatch: Dispatch): DispatchProps =>
// bindActionCreators(
// {
// },
// dispatch
// )
export const connected = connect(mapStateToProps)
export { default } from './SourceIncome'
export * from './SourceIncome'
export * from './state'
......@@ -7,16 +7,7 @@ import sharedStyles from '../styles'
export default (theme: Theme) => {
return createStyles({
...sharedStyles(theme),
form: {
'& .MuiTextField-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
'& .MuiFormControl-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
},
switchCardPhotoContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly' },
datePicker: { marginBottom: '0px !important' },
})
......
import React from 'react'
import { ProposalDataContext } from '@agiliza/api/domain'
import ImageUpload from '@agiliza/components/organisms/ImageUpload'
import RGTemplate from '@agiliza/components/templates/RGTemplate'
import { ActionType } from '@agiliza/utils/hooks/state'
import { DatePicker } from '@curio/components'
import { maskCPFCNPJ } from '@agiliza/utils/masks'
import { extractNumbers } from '@agiliza/utils/method'
import { DatePicker, SelectField, SelectFieldProps, Switch } from '@curio/components'
import { TextField, TextFieldProps } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles'
import { CustomerSpousePersonalDataState } from '../state'
import { CDSpousePersonalDataState } from '../state'
import styles from './styles'
type ExtendedProps = WithStyles<typeof styles>
interface Props extends ExtendedProps {
state: CustomerSpousePersonalDataState
actions: ActionType<CustomerSpousePersonalDataState>
state: CDSpousePersonalDataState
actions: ActionType<CDSpousePersonalDataState>
context: ProposalDataContext
}
const Form = (props: Props) => {
const { classes, state, actions } = props
const { classes, state, actions, context } = props
const { name, birthday } = state
const {
cpf,
name,
birthday,
marriageCertificate,
rg,
userCRAS,
mothersName,
fathersName,
occupation,
schooling,
maritalStatus,
participationPercentage,
dependents,
} = state
const handleChangeDate = (type: keyof Pick<CustomerSpousePersonalDataState, 'birthday'>) => (date: Date | null) => {
const handleChangeDate = (type: keyof Pick<CDSpousePersonalDataState, 'birthday'>) => (date: Date | null) => {
actions.update({ [type]: date })
}
const handleChangeText =
(key: keyof CustomerSpousePersonalDataState): TextFieldProps['onChange'] =>
(key: keyof CDSpousePersonalDataState): TextFieldProps['onChange'] =>
(evt) => {
actions.update({ [key]: evt.target.value })
}
const handleChangeProof: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>['onChange'] = async (evt) => {
const file = evt.target.files && evt.target.files[0]
if (file) {
const b64: string = await new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => resolve(reader.result as string)
reader.onerror = (error) => reject(error)
})
actions.update({ marriageCertificate: b64 })
}
}
const handleChangeRG = (rg: Partial<CDSpousePersonalDataState['rg']>) => {
actions.update({ rg: rg as CDSpousePersonalDataState['rg'] })
}
const handleChangeSelect =
(key: keyof CDSpousePersonalDataState): SelectFieldProps['onChange'] =>
(value) => {
actions.update({ [key]: value })
}
return (
<form className={classes.form}>
<TextField variant="outlined" label="CPF" value={maskCPFCNPJ(cpf)} onChange={handleChangeText('cpf')} inputProps={{ maxLength: 14 }} />
<ImageUpload label="Certidão de casamento" image={marriageCertificate} onChangeImage={handleChangeProof} className={classes.imageUpload} />
<TextField variant="outlined" label="Nome" value={name} onChange={handleChangeText('name')} />
<RGTemplate rg={rg} onChange={handleChangeRG} />
<DatePicker
id="admission-date"
label="Data de nascimento"
......@@ -41,6 +87,35 @@ const Form = (props: Props) => {
format="dd/MM/yyyy"
className={classes.datePicker}
/>
<Switch label="Usuário CRAS?" required value={userCRAS} onChange={(value) => actions.update({ userCRAS: value })} />
<TextField variant="outlined" label="Nome mãe" value={mothersName} onChange={handleChangeText('mothersName')} />
<TextField variant="outlined" label="Nome pai" value={fathersName} onChange={handleChangeText('fathersName')} />
<TextField variant="outlined" label="Profissão" value={occupation} onChange={handleChangeText('occupation')} />
<SelectField
id="schooling-select-field"
shrink={false}
label="Escolaridade"
value={schooling}
items={context.schoolings.map((sch) => ({ label: sch.description, value: sch.id }))}
onChange={handleChangeSelect('schooling')}
variant="outlined"
/>
<SelectField
id="schooling-select-field"
shrink={false}
label="Estado Civil"
value={maritalStatus}
items={context.maritalStatus.map((sch) => ({ label: sch.description, value: sch.id }))}
onChange={handleChangeSelect('maritalStatus')}
variant="outlined"
/>
<TextField
variant="outlined"
label="Participação (%)"
value={extractNumbers(participationPercentage)}
onChange={handleChangeText('participationPercentage')}
/>
<TextField variant="outlined" label="Dependentes" value={extractNumbers(dependents)} onChange={handleChangeText('dependents')} />
</form>
)
}
......
......@@ -7,16 +7,7 @@ import sharedStyles from '../styles'
export default (theme: Theme) => {
return createStyles({
...sharedStyles(theme),
form: {
'& .MuiTextField-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
'& .MuiFormControl-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
},
switchCardPhotoContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly' },
datePicker: { marginBottom: '0px !important' },
})
......
import React from 'react'
import { useFormState } from '@agiliza/utils/hooks/state'
import { ActionType } from '@agiliza/utils/hooks/state'
import { withStyles, WithStyles } from '@material-ui/core/styles'
import { connected, ConnectedProps } from './connect'
import Form from './Form'
import { initialState } from './state'
import { CDSpousePersonalDataState } from './state'
import styles from './styles'
type ExtendedProps = WithStyles<typeof styles>
type ExtendedProps = WithStyles<typeof styles> & ConnectedProps
interface Props extends ExtendedProps {}
interface Props extends ExtendedProps {
state: CDSpousePersonalDataState
actions: ActionType<CDSpousePersonalDataState>
}
const SpouseData = (props: Props) => {
const { classes } = props
const { classes, context, state, actions } = props
const formState = useFormState('spouseDataForm', initialState)
return (
<div className={classes.contentContainer}>
<div className={classes.content}>
<Form {...formState} />
<Form state={state} actions={actions} context={context} />
</div>
</div>
)
}
export default withStyles(styles)(SpouseData)
export default connected(withStyles(styles)(SpouseData))
import { connect } from 'react-redux'
import { ProposalDataContext } from '@agiliza/api/domain'
import { StoreState } from '@agiliza/redux'
import * as entProposalDataContext from '@agiliza/redux/entities/proposalData/context'
import * as ucProposalDataContext from '@agiliza/redux/useCases/proposalData/context'
export interface ConnectedProps {
fetching: boolean
context: ProposalDataContext
}
type StateProps = Pick<ConnectedProps, 'fetching' | 'context'>
// type DispatchProps = Pick<ConnectedProps, 'updateIndentification'>
const mapStateToProps = (state: StoreState): StateProps => ({
fetching: ucProposalDataContext.selectors.isFetching(state.ui.login),
context: entProposalDataContext.selectors.getContext(state.entities.proposalData.context),
})
// const mapDispatchToProps = (dispatch: Dispatch): DispatchProps =>
// bindActionCreators(
// {
// },
// dispatch
// )
export const connected = connect(mapStateToProps)
export { default } from './SpouseData'
export * from './SpouseData'
export * from './state'
......@@ -2,9 +2,9 @@ import { SpousePersonalData } from '@agiliza/api/domain'
type ExtendedState = SpousePersonalData
export interface CustomerSpousePersonalDataState extends ExtendedState {}
export interface CDSpousePersonalDataState extends ExtendedState {}
export const initialState: CustomerSpousePersonalDataState = {
export const initialState: CDSpousePersonalDataState = {
cpf: '',
name: '',
rg: { number: '', dispatcherAgency: '', front: '', back: '' },
......
......@@ -7,16 +7,7 @@ import sharedStyles from '../styles'
export default (theme: Theme) => {
return createStyles({
...sharedStyles(theme),
form: {
'& .MuiTextField-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
'& .MuiFormControl-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
},
switchCardPhotoContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly' },
datePicker: { marginBottom: '0px !important' },
})
......
......@@ -7,4 +7,18 @@ import sharedStyles from '../shared-styles'
export default (theme: Theme) =>
createStyles({
...sharedStyles(theme),
form: {
'& .MuiTextField-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
'& .MuiFormControl-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
'& .MuiFormControlLabel-root': {
marginBottom: theme.spacing(2),
width: '100%',
},
},
})
import React, { useMemo, useState } from 'react'
import React, { useEffect, useMemo, useState } from 'react'
import { RouteComponentProps } from 'react-router'
import ButtonWithProgress from '@agiliza/components/atoms/ButtonWithProgress'
import { useFormState } from '@agiliza/utils/hooks/state'
import { Button, MobileStepper, Typography } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles'
......@@ -20,14 +21,14 @@ import {
import { businessDataItems } from './BusinessData'
import { connected, ConnectedProps } from './connect'
import Address from './CustomerData/Address'
import Address, { initialState as cdAddressInitState } from './CustomerData/Address'
import Home from './CustomerData/Home'
import Identification, { initialState as cdIdentInitState } from './CustomerData/Identification'
import PersonalData from './CustomerData/PersonalData'
import PersonalData, { initialState as cdPersonalDataInitState } from './CustomerData/PersonalData'
import References from './CustomerData/References'
import SourceIncome from './CustomerData/SourceIncome'
import SourceIncome, { initialState as cdSourceIncomeInitState } from './CustomerData/SourceIncome'
import SpouseAdditionalData from './CustomerData/SpouseAdditionalData'
import SpouseData from './CustomerData/SpouseData'
import SpouseData, { initialState as cdSpouseDataInitState } from './CustomerData/SpouseData'
import Vehicles from './CustomerData/Vehicles'
import styles from './shared-styles'
......@@ -46,10 +47,19 @@ type ExtendedProps = WithStyles<typeof styles> & RouteComponentProps & Connected
interface Props extends ExtendedProps {}
const ProposalData = (props: Props) => {
const { classes } = props
const [activeStep, setActiveStep] = useState(0)
const { classes, fetching, proposalId, personId } = props
const [activeStep, setActiveStep] = useState(4)
const cdIdentification = useFormState('proposalDataState', cdIdentInitState)
useEffect(() => {
props.fetchContext()
props.getContextAddress()
}, [])
const cdIdentification = useFormState('cdIdentificationState', cdIdentInitState)
const cdPersonalData = useFormState('cdPersonalDataState', cdPersonalDataInitState)
const cdAddress = useFormState('cdAddressState', cdAddressInitState)
const cdSourceIncome = useFormState('cdAddressState', cdSourceIncomeInitState)
const cdSpouseData = useFormState('cdAddressState', cdSpouseDataInitState)
const customerDataItems = useMemo(
() => [
......@@ -58,16 +68,16 @@ const ProposalData = (props: Props) => {
icon: <AccountBoxIcon />,
component: <Identification state={cdIdentification.state} actions={cdIdentification.actions} />,
},
{ label: 'Dados Pessoais', icon: <ListIcon />, component: <PersonalData /> },
{ label: 'Endereço', icon: <ContactMailIcon />, component: <Address /> },
{ label: 'Fonte de renda', icon: <LocalAtmIcon />, component: <SourceIncome /> },
{ label: 'Cônjuge - Ident.', icon: <ForumIcon />, component: <SpouseData /> },
{ label: 'Dados Pessoais', icon: <ListIcon />, component: <PersonalData state={cdPersonalData.state} actions={cdPersonalData.actions} /> },
{ label: 'Endereço', icon: <ContactMailIcon />, component: <Address state={cdAddress.state} actions={cdAddress.actions} /> },
{ label: 'Fonte de renda', icon: <LocalAtmIcon />, component: <SourceIncome state={cdSourceIncome.state} actions={cdSourceIncome.actions} /> },
{ label: 'Cônjuge - Ident.', icon: <ForumIcon />, component: <SpouseData state={cdSpouseData.state} actions={cdSpouseData.actions} /> },
{ label: 'Cônjuge +', icon: <ZoomOutMapIcon />, component: <SpouseAdditionalData /> },
{ label: 'Referências', icon: <CheckBoxIcon />, component: <References /> },
{ label: 'Moradia', icon: <HomeIcon />, component: <Home /> },
{ label: 'Veículos', icon: <DriveEtaIcon />, component: <Vehicles /> },
],
[cdIdentification]
[cdIdentification, cdPersonalData, cdAddress, cdSpouseData]
)
const proposalDataItems = useMemo(() => [...customerDataItems, ...businessDataItems], [customerDataItems, businessDataItems])
......@@ -77,7 +87,46 @@ const ProposalData = (props: Props) => {
const handleNext = () => {
// if (activeStep === steps - 1) history.push({ pathname: PATHS.creditLines })
setActiveStep((prevActiveStep) => prevActiveStep + 1)
const projectPersonIds = { projectId: proposalId, personId }
switch (activeStep) {
case 0:
props.addIndentification({
identification: { ...cdIdentification.state, account: cdIdentification.state.hasAccount ? cdIdentification.state.account : undefined },
projectId: proposalId,
onSuccess: () => setActiveStep((prevActiveStep) => prevActiveStep + 1),
})
break
case 1:
props.updatePersonalData({
...projectPersonIds,
personalData: cdPersonalData.state,
onSuccess: () => setActiveStep((prevActiveStep) => prevActiveStep + 1),
})
break
case 2:
props.updateAddress({
...projectPersonIds,
address: cdAddress.state,
onSuccess: () => setActiveStep((prevActiveStep) => prevActiveStep + 1),
})
break
case 3:
props.updateSourceIncome({
...projectPersonIds,
sourceIncome: cdSourceIncome.state,
onSuccess: () => setActiveStep((prevActiveStep) => prevActiveStep + 1),
})
break
case 4:
props.updateSpouseData({
...projectPersonIds,
spouseData: cdSpouseData.state,
onSuccess: () => setActiveStep((prevActiveStep) => prevActiveStep + 1),
})
break
default:
setActiveStep((prevActiveStep) => prevActiveStep + 1)
}
}
const handleBack = () => {
......@@ -122,10 +171,17 @@ const ProposalData = (props: Props) => {
</Button>
}
backButton={
<Button size="large" onClick={handleBack} disabled={activeStep === 0} className={classes.stepperBtn}>
<ButtonWithProgress
fetching={fetching}
size="large"
variant="text"
onClick={handleBack}
disabled={activeStep === 0}
className={classes.stepperBtn}
>
<KeyboardArrowLeftIcon />
Anterior
</Button>
</ButtonWithProgress>
}
/>
{/* </Stepper> */}
......
import { connect } from 'react-redux'
import { bindActionCreators, Dispatch } from 'redux'
import { StoreState } from '@agiliza/redux'
import * as entProposal from '@agiliza/redux/entities/proposalData/proposal'
import * as ucAuthentication from '@agiliza/redux/useCases/authentication'
import * as ucProposalDataContext from '@agiliza/redux/useCases/proposalData/context'
import * as ucProposalDataCD from '@agiliza/redux/useCases/proposalData/customerData'
export interface ConnectedProps {
fetching: boolean
proposalId: string
personId: string
fetchContext: typeof ucProposalDataContext.actions.fetchContext
getContextAddress: typeof ucAuthentication.actions.getContext
addIndentification: typeof ucProposalDataCD.actions.addIndentification
updatePersonalData: typeof ucProposalDataCD.actions.updatePersonalData
updateAddress: typeof ucProposalDataCD.actions.updateAddress
updateSourceIncome: typeof ucProposalDataCD.actions.updateSourceIncome
updateSpouseData: typeof ucProposalDataCD.actions.updateSpouseData
}
type StateProps = Pick<ConnectedProps, 'fetching'>
// type DispatchProps = Record<string, any>
type StateProps = Pick<ConnectedProps, 'fetching' | 'proposalId' | 'personId'>
type DispatchProps = Pick<
ConnectedProps,
'addIndentification' | 'fetchContext' | 'updatePersonalData' | 'updateAddress' | 'getContextAddress' | 'updateSourceIncome' | 'updateSpouseData'
>
const mapStateToProps = (state: StoreState): StateProps => ({
fetching: ucProposalDataContext.selectors.isFetching(state.ui.login),
proposalId: entProposal.selectors.getProposalId(state.entities.proposalData.proposal),
personId: entProposal.selectors.getPersonlId(state.entities.proposalData.proposal),
})
// const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => bindActionCreators({}, dispatch)
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps =>
bindActionCreators(
{
addIndentification: ucProposalDataCD.actions.addIndentification,
fetchContext: ucProposalDataContext.actions.fetchContext,
updatePersonalData: ucProposalDataCD.actions.updatePersonalData,
updateAddress: ucProposalDataCD.actions.updateAddress,
getContextAddress: ucAuthentication.actions.getContext,
updateSourceIncome: ucProposalDataCD.actions.updateSourceIncome,
updateSpouseData: ucProposalDataCD.actions.updateSpouseData,
},
dispatch
)
export const connected = connect(mapStateToProps)
export const connected = connect(mapStateToProps, mapDispatchToProps)
......@@ -27,7 +27,8 @@ export default (theme: Theme) =>
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
width: '25%',
width: '30%',
height: '100%',
},
imageUpload: { width: '100%', textAlign: 'center', marginTop: theme.spacing(1), marginBottom: theme.spacing(1) },
})
......@@ -937,10 +937,10 @@
isomorphic-fetch "^2.2.1"
symbol-observable "^1.2.0"
"@curio/components@^0.1.5":
version "0.1.5"
resolved "https://nexus.dev.evologica.com.br/repository/npm/@curio/components/-/components-0.1.5.tgz#098d89ed0d06a0178af71a6e7c73f588aeccb241"
integrity sha512-g9WKPReGIzDioaXBMlycUO4ghWY2WPCoAE7U/YC88+s8tDylgrqSIDpE8SQJGZ0p8R0odqszhXehmec2Amfv7A==
"@curio/components@^0.1.6":
version "0.1.6"
resolved "https://nexus.dev.evologica.com.br/repository/npm/@curio/components/-/components-0.1.6.tgz#a6b69b17af2ab2966c97016372cddbc35f0eef87"
integrity sha512-AVblcKODqCqforRww+1buMRMDMNyDN75N6TqYsRwM34onRlstcT4wQXLv0gZA1qZrCMu9E9TAcKjVy3RKgQ1Dw==
dependencies:
"@curio/client" "1.3.3"
"@date-io/date-fns" "^1.0.0"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment