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 @@ ...@@ -80,7 +80,7 @@
}, },
"dependencies": { "dependencies": {
"@curio/client": "1.3.3", "@curio/client": "1.3.3",
"@curio/components": "^0.1.5", "@curio/components": "^0.1.6",
"@curio/ui": "^0.1.0", "@curio/ui": "^0.1.0",
"@date-io/date-fns": "^1.0.0", "@date-io/date-fns": "^1.0.0",
"@dynamo/components": "0.70.1", "@dynamo/components": "0.70.1",
......
...@@ -8,9 +8,19 @@ export interface Gender extends Entity { ...@@ -8,9 +8,19 @@ export interface Gender extends Entity {
description: string description: string
} }
export interface Schooling extends Entity {
description: string
}
export interface MaritalStatus extends Entity {
description: string
}
export interface ProposalDataContext { export interface ProposalDataContext {
frameworks: Framework[] frameworks: Framework[]
genders: Gender[] genders: Gender[]
schoolings: Schooling[]
maritalStatus: MaritalStatus[]
} }
export interface FetchContext { export interface FetchContext {
......
import { Address } from '../'
export interface InvolvedPersonAddress extends Omit<IPAddress, 'id'> { export interface InvolvedPersonAddress extends Omit<IPAddress, 'id'> {
proof: string proof: string
} }
export interface IPAddress { export interface IPAddress extends Address {
id: string
proof: string proof: string
street: string }
number: string
cep: string interface InputUpdateCDAddress {
complement: string projectId: string
city: string personId: string
district: string address: IPAddress
state: string }
export interface UpdateCDAddress {
Input: InputUpdateCDAddress
Output: IPAddress
} }
...@@ -35,3 +35,13 @@ export interface DataType { ...@@ -35,3 +35,13 @@ export interface DataType {
} }
export type InvolvedPersonType = 'CUSTOMER' | 'PARTNER' | 'GUARANTOR' 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 { ...@@ -22,3 +22,14 @@ export interface UpdatePersonalDataArgs {
personId: string personId: string
personalData: InvolvedPerson['personalData'] 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 { ...@@ -10,3 +10,14 @@ export interface SourceIncome {
position: string position: string
address: BaseAddress address: BaseAddress
} }
interface InputUpdateCDSourceIncome {
sourceIncome: SourceIncome
projectId: string
personId: string
}
export interface UpdateCDSourceIncome {
Input: InputUpdateCDSourceIncome
Output: SourceIncome
}
...@@ -42,3 +42,14 @@ export interface UpdateSpouseDataArgs { ...@@ -42,3 +42,14 @@ export interface UpdateSpouseDataArgs {
personId: string personId: string
spouseData: SpousePersonalData spouseData: SpousePersonalData
} }
interface InputUpdateCDSpouseData {
spouseData: SpousePersonalData
projectId: string
personId: string
}
export interface UpdateCDSpouseData {
Input: InputUpdateCDSpouseData
Output: SpousePersonalData
}
...@@ -37,11 +37,7 @@ interface InputCreateProposal { ...@@ -37,11 +37,7 @@ interface InputCreateProposal {
subproductId: string subproductId: string
} }
interface OutputCreateProposal {
proposalId: string
}
export interface CreateProposal { export interface CreateProposal {
Input: InputCreateProposal 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 './businessData'
export * from './customerData'
import { ProposalDataContext } from '@agiliza/api/domain' 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' import { DomainAdapter, IdDescriptionMapper } from '../shared'
export interface DadosPropostaContexto { export interface DadosPropostaContexto {
enquadramentos: EnquadramentoApiModel[] enquadramentos: EnquadramentoApiModel[]
generos: GeneroApiModel[] generos: GeneroApiModel[]
escolaridades: EscolaridadeApiModel[]
estadosCivis: EstadoCivilApiModel[]
} }
export class ContextMapper implements DomainAdapter<DadosPropostaContexto, ProposalDataContext> { export class ContextMapper implements DomainAdapter<DadosPropostaContexto, ProposalDataContext> {
...@@ -17,5 +24,7 @@ export class ContextMapper implements DomainAdapter<DadosPropostaContexto, Propo ...@@ -17,5 +24,7 @@ export class ContextMapper implements DomainAdapter<DadosPropostaContexto, Propo
public mapApiModelToDomain = (dP: DadosPropostaContexto): ProposalDataContext => ({ public mapApiModelToDomain = (dP: DadosPropostaContexto): ProposalDataContext => ({
frameworks: dP.enquadramentos.map(this.idDescriptionMapper.mapApiModelToDomain), frameworks: dP.enquadramentos.map(this.idDescriptionMapper.mapApiModelToDomain),
genders: dP.generos.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 './businessData'
export * from './context' export * from './context'
export * from './customerData'
...@@ -31,7 +31,12 @@ export class ProposalDataContextRepositoryImpl implements ProposalDataContextRep ...@@ -31,7 +31,12 @@ export class ProposalDataContextRepositoryImpl implements ProposalDataContextRep
public fetchContext = async (): Promise<FetchContext['Output']> => { public fetchContext = async (): Promise<FetchContext['Output']> => {
try { 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) return this.contextMapper.mapApiModelToDomain(contexto)
} catch (e) { } catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(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 { ClienteApi, Configuration } from '@microcredito/client'
import { ErrorMappers, ProposalDataApiMappers, ProposalDataMappers } from '../../mappers' import { ErrorMappers, ProposalDataApiMappers, ProposalDataMappers } from '../../mappers'
...@@ -6,21 +13,41 @@ import { API_URL, mapUserAgentToString, SESSION_KEY, UserAgent } from '../shared ...@@ -6,21 +13,41 @@ import { API_URL, mapUserAgentToString, SESSION_KEY, UserAgent } from '../shared
export interface PDCustomerDataDataRepository { export interface PDCustomerDataDataRepository {
createProposal(input: CreateProposal['Input']): Promise<CreateProposal['Output']> 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 { export class PDCustomerDataRepositoryImpl implements PDCustomerDataDataRepository {
private api: ClienteApi private api: ClienteApi
private errorAdapter: ErrorMappers.ResponseErrorAdapter private errorAdapter: ErrorMappers.ResponseErrorAdapter
private updateIdentificationApiMapper: ProposalDataApiMappers.BDUpdateIdentificationApiMapper
private identificationMapper: ProposalDataMappers.BDIdentificationMapper
private createProposalApiMapper: ProposalDataApiMappers.CreateProposalApiMapper 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) { constructor(userAgent: string, accessToken: string) {
this.errorAdapter = new ErrorMappers.ResponseErrorAdapter() this.errorAdapter = new ErrorMappers.ResponseErrorAdapter()
this.updateIdentificationApiMapper = new ProposalDataApiMappers.BDUpdateIdentificationApiMapper()
this.identificationMapper = new ProposalDataMappers.BDIdentificationMapper()
this.createProposalApiMapper = new ProposalDataApiMappers.CreateProposalApiMapper() 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( this.api = new ClienteApi(
new Configuration({ new Configuration({
...@@ -33,10 +60,10 @@ export class PDCustomerDataRepositoryImpl implements PDCustomerDataDataRepositor ...@@ -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 { try {
const response = await this.api.atualizarIdentificacaoDadosNegocio(this.updateIdentificationApiMapper.mapDomainToApiModel(input)) const response = await this.api.incluirPessoaEnvolvida(this.cdUpdateIdentificationApiMapper.mapDomainToApiModel(input))
return this.identificationMapper.mapApiModelToDomain(response) return this.cdIdentificationMapper.mapApiModelToDomain(response)
} catch (e) { } catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e) const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result throw result
...@@ -46,7 +73,47 @@ export class PDCustomerDataRepositoryImpl implements PDCustomerDataDataRepositor ...@@ -46,7 +73,47 @@ export class PDCustomerDataRepositoryImpl implements PDCustomerDataDataRepositor
public createProposal = async (input: CreateProposal['Input']): Promise<CreateProposal['Output']> => { public createProposal = async (input: CreateProposal['Input']): Promise<CreateProposal['Output']> => {
try { try {
const response = await this.api.criarProposta(this.createProposalApiMapper.mapDomainToApiModel(input)) 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) { } catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e) const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result throw result
......
export * from './context' export * from './context'
export * from './businessData' 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 './DashboardCard'
export * from './ImageUpload'
import React from 'react' import React from 'react'
import { BanestesAccount } from '@agiliza/api/domain' 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 { withStyles, WithStyles } from '@material-ui/core/styles'
import { PhotoCamera as PhotoCameraIcon } from '@material-ui/icons'
import styles from './styles' import styles from './styles'
...@@ -24,34 +25,31 @@ const AccountInputsPhoto = (props: Props) => { ...@@ -24,34 +25,31 @@ const AccountInputsPhoto = (props: Props) => {
const handleChangeField = (type: keyof BanestesAccount): TextFieldProps['onChange'] => onChanges.account(type) 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] 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 ( return (
<div className={classes.accountInputsPhotoContainer}> <div className={classes.accountInputsPhotoContainer}>
<div className={classes.accountInputsContainer}> <div className={classes.accountInputsContainer}>
<TextField label="Número da agência" value={agencyNumber || ''} onChange={handleChangeField('agencyNumber')} variant="outlined" /> <TextField
<TextField label="Número da conta corrente" value={number || ''} onChange={handleChangeField('number')} variant="outlined" /> label="Número da agência"
</div> value={extractNumbers(agencyNumber) || ''}
<Button variant="text" component="label" className={classes.photoBtn} classes={{ label: classes.photoLabelBtn }}> onChange={handleChangeField('agencyNumber')}
{cardPicture ? ( variant="outlined"
<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}
/> />
</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> </div>
) )
} }
......
...@@ -4,8 +4,8 @@ import { createStyles } from '@material-ui/styles' ...@@ -4,8 +4,8 @@ import { createStyles } from '@material-ui/styles'
// eslint-disable-next-line // eslint-disable-next-line
export default (theme: Theme) => { export default (theme: Theme) => {
return createStyles({ return createStyles({
accountInputsPhotoContainer: { display: 'flex', flexDirection: 'column', alignItems: 'center', height: '100%' }, accountInputsPhotoContainer: { width: '100%', height: '100%' },
accountInputsContainer: { marginRight: theme.spacing(1), height: '100%' }, accountInputsContainer: { height: '100%' },
photoBtn: { minWidth: '50%' }, photoBtn: { minWidth: '50%' },
photoLabelBtn: { display: 'flex', flexDirection: 'column', height: '280px', alignItems: 'center', flexGrow: 1 }, photoLabelBtn: { display: 'flex', flexDirection: 'column', height: '280px', alignItems: 'center', flexGrow: 1 },
card: { width: 'auto', height: 'auto' }, card: { width: 'auto', height: 'auto' },
......
import React, { useMemo } from 'react' import React, { useMemo } from 'react'
import { City, State } from '@agiliza/api/domain' import { City, State } from '@agiliza/api/domain'
import { ActionType } from '@agiliza/utils/hooks/state'
import { maskCEP } from '@agiliza/utils/masks' import { maskCEP } from '@agiliza/utils/masks'
import { SelectField, SelectFieldProps } from '@curio/components' import { SelectField, SelectFieldProps } from '@curio/components'
import { TextField, TextFieldProps } from '@material-ui/core' import { TextField, TextFieldProps } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles' import { withStyles, WithStyles } from '@material-ui/core/styles'
import { AddressState as FormState } from './state' import { AddressState } from './state'
import styles from './styles' import styles from './styles'
type ExtendedProps = WithStyles<typeof styles> type ExtendedProps = WithStyles<typeof styles>
...@@ -15,25 +14,25 @@ type ExtendedProps = WithStyles<typeof styles> ...@@ -15,25 +14,25 @@ type ExtendedProps = WithStyles<typeof styles>
interface Props extends ExtendedProps { interface Props extends ExtendedProps {
states: State[] states: State[]
cities: City[] cities: City[]
state: FormState state: AddressState
actions: ActionType<FormState> onChange: (address: Partial<AddressState>) => void
} }
const Address = (props: Props) => { 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 { cep, street, number, complement, state, city, district } = _state
const handleChange = const handleChange =
(key: keyof FormState): TextFieldProps['onChange'] => (key: keyof AddressState): TextFieldProps['onChange'] =>
(evt) => { (evt) => {
actions.update({ [key]: evt.target.value }) onChange({ [key]: evt.target.value })
} }
const handleChangeSelect = const handleChangeSelect =
(key: keyof FormState): SelectFieldProps['onChange'] => (key: keyof AddressState): SelectFieldProps['onChange'] =>
(value) => { (value) => {
actions.update({ [key]: value }) onChange({ [key]: value })
} }
const availableCities = useMemo(() => { const availableCities = useMemo(() => {
......
...@@ -7,7 +7,7 @@ import { maskCPFCNPJ, maskPhone } from '@agiliza/utils/masks' ...@@ -7,7 +7,7 @@ import { maskCPFCNPJ, maskPhone } from '@agiliza/utils/masks'
import { TextField, TextFieldProps } from '@material-ui/core' import { TextField, TextFieldProps } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles' 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 { initState, State as FirstAccessState } from './state'
import styles from './styles' import styles from './styles'
...@@ -33,6 +33,9 @@ const FirstAccess = (props: Props) => { ...@@ -33,6 +33,9 @@ const FirstAccess = (props: Props) => {
actions.update({ [key]: evt.target.value }) actions.update({ [key]: evt.target.value })
errorActions.validate({ [key]: evt.target.value }) errorActions.validate({ [key]: evt.target.value })
} }
const handleChangeAddress = (value: Partial<AddressState>) => {
actions.update(value)
}
return ( return (
<form className={classes.form}> <form className={classes.form}>
...@@ -48,7 +51,7 @@ const FirstAccess = (props: Props) => { ...@@ -48,7 +51,7 @@ const FirstAccess = (props: Props) => {
<TextField variant="outlined" label="Nome" value={name} onChange={handleChange('name')} /> <TextField variant="outlined" label="Nome" value={name} onChange={handleChange('name')} />
<TextField variant="outlined" label="Email" value={email} onChange={handleChange('email')} /> <TextField variant="outlined" label="Email" value={email} onChange={handleChange('email')} />
<TextField variant="outlined" label="Telefone" value={maskPhone(phone)} onChange={handleChange('phone')} inputProps={{ maxLength: 15 }} /> <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> </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' ...@@ -3,3 +3,4 @@ export * from './AccountInputsPhoto'
export * from './Login' export * from './Login'
export * from './Address' export * from './Address'
export * from './FirstAccess' export * from './FirstAccess'
export * from './RGTemplate'
...@@ -12,6 +12,8 @@ export interface Store extends WithEntityStore<ProposalDataContext> { ...@@ -12,6 +12,8 @@ export interface Store extends WithEntityStore<ProposalDataContext> {
export const initialState: Store = { export const initialState: Store = {
frameworks: { byId: {}, allIds: [] }, frameworks: { byId: {}, allIds: [] },
genders: { byId: {}, allIds: [] }, genders: { byId: {}, allIds: [] },
schoolings: { byId: {}, allIds: [] },
maritalStatus: { byId: {}, allIds: [] },
} }
export default createSlice({ export default createSlice({
......
import { combineReducers } from 'redux' import { combineReducers } from 'redux'
import context, { initialState as contextInitState, Store as ContextStore } from './context' import context, { initialState as contextInitState, Store as ContextStore } from './context'
import proposal, { initialState as proposalInitState, Store as ProposalStore } from './proposal'
export interface State { export interface State {
context: ContextStore context: ContextStore
proposal: ProposalStore
} }
export const initialState: State = { export const initialState: State = {
context: contextInitState, context: contextInitState,
proposal: proposalInitState,
} }
export default combineReducers({ export default combineReducers({
context, 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> ...@@ -10,6 +10,8 @@ export type NormalizedContext = WithNormalizedEntity<ProposalDataContext>
const contextSchemas = new schema.Object({ const contextSchemas = new schema.Object({
frameworks: new schema.Array(new schema.Entity('frameworks')), frameworks: new schema.Array(new schema.Entity('frameworks')),
genders: new schema.Array(new schema.Entity('genders')), 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) => { export const normalizeContext = (context: ProposalDataContext) => {
......
import { CreateProposal } from '@agiliza/api/domain' import {
AddCDIdentification,
CreateProposal,
UpdateCDAddress,
UpdateCDPersonalData,
UpdateCDSourceIncome,
UpdateCDSpouseData
} from '@agiliza/api/domain'
import { import {
PDCustomerDataRepositoryImplFactory PDCustomerDataRepositoryImplFactory
} from '@agiliza/api/useCases/proposalData/customerData' } from '@agiliza/api/useCases/proposalData/customerData'
...@@ -32,10 +39,50 @@ export const actions = { ...@@ -32,10 +39,50 @@ export const actions = {
return thunkApi.rejectWithValue(e) 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) const useCase = PDCustomerDataRepositoryImplFactory.create(appPlatform)
try { 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() input.onSuccess && input.onSuccess()
return proposalId return proposalId
} catch (e) { } catch (e) {
......
...@@ -62,6 +62,29 @@ export const maskPhone = (str?: string) => { ...@@ -62,6 +62,29 @@ export const maskPhone = (str?: string) => {
// return filteredString // 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) => { export const maskLicensePlate = (str?: string) => {
if (!str) return '' if (!str) return ''
const filteredString = str.toUpperCase().replace(/([^A-Z0-9]*)/g, '') const filteredString = str.toUpperCase().replace(/([^A-Z0-9]*)/g, '')
......
...@@ -193,3 +193,22 @@ export const getActionTypes = <Actions>(actions: Actions) => { ...@@ -193,3 +193,22 @@ export const getActionTypes = <Actions>(actions: Actions) => {
} }
export type WithSuccess<T, A = void> = T & { onSuccess?: (args?: A) => void } 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- ...@@ -3,7 +3,6 @@ import { Redirect, Route, RouteComponentProps, Switch, useHistory } from 'react-
import AppBar from '@agiliza/components/molecules/AppBar' import AppBar from '@agiliza/components/molecules/AppBar'
import CircularProgress from '@agiliza/components/molecules/CircularProgress' 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 drawerActions } from '@agiliza/redux/ui/drawer'
import { actions as loginActions } from '@agiliza/redux/ui/login' import { actions as loginActions } from '@agiliza/redux/ui/login'
import { ProposalDataRouteState } from '@agiliza/views/ProposalData/pages/ProposalData' import { ProposalDataRouteState } from '@agiliza/views/ProposalData/pages/ProposalData'
...@@ -52,8 +51,9 @@ const Main = (props: Props) => { ...@@ -52,8 +51,9 @@ const Main = (props: Props) => {
path={PATHS.proposalData} path={PATHS.proposalData}
render={(rProps) => { render={(rProps) => {
const { location } = rProps as RouteComponentProps<any, any, ProposalDataRouteState> const { location } = rProps as RouteComponentProps<any, any, ProposalDataRouteState>
if (!location.state) location.state = { subproductId: '0' }
if (location.state?.subproductId) return <ProposalData {...rProps} /> if (location.state?.subproductId) return <ProposalData {...rProps} />
else return <NotFound {...rProps} /> else return <Redirect from={PATHS.proposalData} to="/" />
}} }}
/> />
<Redirect from="/" to={PATHS.creditLines} /> <Redirect from="/" to={PATHS.creditLines} />
......
...@@ -2,6 +2,7 @@ import React from 'react' ...@@ -2,6 +2,7 @@ import React from 'react'
import { IPAddress } from '@agiliza/api/domain' import { IPAddress } from '@agiliza/api/domain'
import { maskCEP } from '@agiliza/utils/masks' import { maskCEP } from '@agiliza/utils/masks'
import { extractNumbers } from '@agiliza/utils/method'
import { TextField, TextFieldProps } from '@material-ui/core' import { TextField, TextFieldProps } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles' import { withStyles, WithStyles } from '@material-ui/core/styles'
...@@ -30,7 +31,7 @@ const Address = (props: Props) => { ...@@ -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="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="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 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 { withStyles, WithStyles } from '@material-ui/core/styles'
import { connected, ConnectedProps } from './connect'
import Form from './Form' import Form from './Form'
import { initialState } from './state' import { CDAddressState } from './state'
import styles from './styles' 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 Address = (props: Props) => {
const { classes } = props const { classes, context, state, actions } = props
const formState = useFormState('addressData', initialState)
return ( return (
<div className={classes.contentContainer}> <div className={classes.contentContainer}>
<div className={classes.content}> <div className={classes.content}>
<Form {...formState} /> <Form states={context.states} cities={context.cities} state={state} actions={actions} />
</div> </div>
</div> </div>
) )
} }
export default withStyles(styles)(Address) export default connected(withStyles(styles)(Address))
import React from 'react' 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 { ActionType } from '@agiliza/utils/hooks/state'
import Address from '@agiliza/views/ProposalData/components/templates/Address'
import { withStyles, WithStyles } from '@material-ui/core/styles' import { withStyles, WithStyles } from '@material-ui/core/styles'
import { CustomerAddressState } from '../state' import { CDAddressState } from '../state'
import styles from './styles' import styles from './styles'
type ExtendedProps = WithStyles<typeof styles> type ExtendedProps = WithStyles<typeof styles>
interface Props extends ExtendedProps { interface Props extends ExtendedProps {
state: CustomerAddressState states: State[]
actions: ActionType<CustomerAddressState> cities: City[]
state: CDAddressState
actions: ActionType<CDAddressState>
} }
const Form = (props: Props) => { 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 ( return (
<form className={classes.form}> <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> </form>
) )
} }
......
...@@ -7,16 +7,6 @@ import sharedStyles from '../styles' ...@@ -7,16 +7,6 @@ import sharedStyles from '../styles'
export default (theme: Theme) => { export default (theme: Theme) => {
return createStyles({ return createStyles({
...sharedStyles(theme), ...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' }, switchCardPhotoContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly' },
datePicker: { marginBottom: '0px !important' }, 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 { default } from './Address'
export * from './Address' export * from './Address'
export * from './state'
...@@ -2,9 +2,9 @@ import { IPAddress } from '@agiliza/api/domain' ...@@ -2,9 +2,9 @@ import { IPAddress } from '@agiliza/api/domain'
type ExtendedState = IPAddress type ExtendedState = IPAddress
export interface CustomerAddressState extends ExtendedState {} export interface CDAddressState extends ExtendedState {}
export const initialState: CustomerAddressState = { export const initialState: CDAddressState = {
id: '', id: '',
proof: '', proof: '',
cep: '', cep: '',
......
...@@ -7,16 +7,7 @@ import sharedStyles from '../styles' ...@@ -7,16 +7,7 @@ import sharedStyles from '../styles'
export default (theme: Theme) => { export default (theme: Theme) => {
return createStyles({ return createStyles({
...sharedStyles(theme), ...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' }, switchCardPhotoContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly' },
}) })
} }
...@@ -64,13 +64,7 @@ const Form = (props: Props) => { ...@@ -64,13 +64,7 @@ const Form = (props: Props) => {
variant="outlined" variant="outlined"
shrink={false} shrink={false}
/> />
<TextField <TextField variant="outlined" label="CPF" value={maskCPFCNPJ(cpfcnpj)} onChange={handleChangeText('cpfcnpj')} inputProps={{ maxLength: 14 }} />
variant="outlined"
label="CPF / CNPJ"
value={maskCPFCNPJ(cpfcnpj)}
onChange={handleChangeText('cpfcnpj')}
inputProps={{ maxLength: 18 }}
/>
<TextField variant="outlined" label="Nome / Razão social" value={name || ''} onChange={handleChangeText('name')} /> <TextField variant="outlined" label="Nome / Razão social" value={name || ''} onChange={handleChangeText('name')} />
<SelectField <SelectField
id="gender-select-field" id="gender-select-field"
......
...@@ -7,16 +7,6 @@ import sharedStyles from '../styles' ...@@ -7,16 +7,6 @@ import sharedStyles from '../styles'
export default (theme: Theme) => { export default (theme: Theme) => {
return createStyles({ return createStyles({
...sharedStyles(theme), ...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' }, 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 { ActionType } from '@agiliza/utils/hooks/state'
import { withStyles, WithStyles } from '@material-ui/core/styles' import { withStyles, WithStyles } from '@material-ui/core/styles'
...@@ -18,10 +18,6 @@ interface Props extends ExtendedProps { ...@@ -18,10 +18,6 @@ interface Props extends ExtendedProps {
const Identification = (props: Props) => { const Identification = (props: Props) => {
const { classes, context, state, actions } = props const { classes, context, state, actions } = props
useEffect(() => {
props.fetchContext()
}, [])
return ( return (
<div className={classes.contentContainer}> <div className={classes.contentContainer}>
<div className={classes.content}> <div className={classes.content}>
......
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { bindActionCreators, Dispatch } from 'redux'
import { ProposalDataContext } from '@agiliza/api/domain' import { ProposalDataContext } from '@agiliza/api/domain'
import { StoreState } from '@agiliza/redux' import { StoreState } from '@agiliza/redux'
import * as entProposalDataContext from '@agiliza/redux/entities/proposalData/context' import * as entProposalDataContext from '@agiliza/redux/entities/proposalData/context'
import * as ucProposalDataContext from '@agiliza/redux/useCases/proposalData/context' import * as ucProposalDataContext from '@agiliza/redux/useCases/proposalData/context'
import * as ucProposalDataCD from '@agiliza/redux/useCases/proposalData/customerData'
export interface ConnectedProps { export interface ConnectedProps {
fetching: boolean fetching: boolean
context: ProposalDataContext context: ProposalDataContext
fetchContext: typeof ucProposalDataContext.actions.fetchContext
updateIndentification: typeof ucProposalDataCD.actions.updateIndentification
} }
type StateProps = Pick<ConnectedProps, 'fetching' | 'context'> type StateProps = Pick<ConnectedProps, 'fetching' | 'context'>
type DispatchProps = Pick<ConnectedProps, 'fetchContext' | 'updateIndentification'> // type DispatchProps = Pick<ConnectedProps, 'addIndentification'>
const mapStateToProps = (state: StoreState): StateProps => ({ const mapStateToProps = (state: StoreState): StateProps => ({
fetching: ucProposalDataContext.selectors.isFetching(state.ui.login), fetching: ucProposalDataContext.selectors.isFetching(state.ui.login),
context: entProposalDataContext.selectors.getContext(state.entities.proposalData.context), context: entProposalDataContext.selectors.getContext(state.entities.proposalData.context),
}) })
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => // const mapDispatchToProps = (dispatch: Dispatch): DispatchProps =>
bindActionCreators( // bindActionCreators(
{ // {
fetchContext: ucProposalDataContext.actions.fetchContext, // },
updateIndentification: ucProposalDataCD.actions.updateIndentification, // dispatch
}, // )
dispatch
)
export const connected = connect(mapStateToProps, mapDispatchToProps) export const connected = connect(mapStateToProps)
import { InvolvedPerson } from '@agiliza/api/domain' 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 { export interface CDIdentificationState extends ExtendedState {
hasAccount: boolean hasAccount: boolean
...@@ -11,6 +12,7 @@ export const initialState: CDIdentificationState = { ...@@ -11,6 +12,7 @@ export const initialState: CDIdentificationState = {
name: '', name: '',
cpfcnpj: '', cpfcnpj: '',
gender: '', gender: '',
type: INVOLVED_PERSON_TYPES['CUSTOMER'],
hasAccount: false, hasAccount: false,
account: { agencyNumber: '', number: '', cardPicture: '' }, account: { agencyNumber: '', number: '', cardPicture: '' },
dataType: { doesWithdrawal: false, framework: '' }, dataType: { doesWithdrawal: false, framework: '' },
......
import React from 'react' 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 { 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 { TextField, TextFieldProps } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles' import { withStyles, WithStyles } from '@material-ui/core/styles'
import { CustomerPersonalDataState } from '../state' import { CDPersonalDataState } from '../state'
import styles from './styles' import styles from './styles'
type ExtendedProps = WithStyles<typeof styles> type ExtendedProps = WithStyles<typeof styles>
interface Props extends ExtendedProps { interface Props extends ExtendedProps {
state: CustomerPersonalDataState state: CDPersonalDataState
actions: ActionType<CustomerPersonalDataState> actions: ActionType<CDPersonalDataState>
context: ProposalDataContext
} }
const Form = (props: Props) => { 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 }) actions.update({ [type]: date })
} }
const handleChangeText = const handleChangeText =
(key: keyof CustomerPersonalDataState): TextFieldProps['onChange'] => (key: keyof CDPersonalDataState): TextFieldProps['onChange'] =>
(evt) => { (evt) => {
actions.update({ [key]: evt.target.value }) 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 ( return (
<form className={classes.form}> <form className={classes.form}>
<DatePicker <DatePicker
...@@ -40,7 +68,46 @@ const Form = (props: Props) => { ...@@ -40,7 +68,46 @@ const Form = (props: Props) => {
format="dd/MM/yyyy" format="dd/MM/yyyy"
className={classes.datePicker} 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 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> </form>
) )
} }
......
...@@ -7,16 +7,7 @@ import sharedStyles from '../styles' ...@@ -7,16 +7,7 @@ import sharedStyles from '../styles'
export default (theme: Theme) => { export default (theme: Theme) => {
return createStyles({ return createStyles({
...sharedStyles(theme), ...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' }, switchCardPhotoContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly' },
datePicker: { marginBottom: '0px !important' }, datePicker: { marginBottom: '0px !important' },
}) })
......
import React from 'react' 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 { withStyles, WithStyles } from '@material-ui/core/styles'
import { connected, ConnectedProps } from './connect'
import Form from './Form' import Form from './Form'
import { initialState } from './state' import { CDPersonalDataState } from './state'
import styles from './styles' 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 PersonalData = (props: Props) => {
const { classes } = props const { classes, context, state, actions } = props
const formState = useFormState('personalData', initialState)
return ( return (
<div className={classes.contentContainer}> <div className={classes.contentContainer}>
<div className={classes.content}> <div className={classes.content}>
<Form {...formState} /> <Form context={context} state={state} actions={actions} />
</div> </div>
</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 { default } from './PersonalData'
export * from './PersonalData' export * from './PersonalData'
export * from './state'
...@@ -2,9 +2,9 @@ import { PersonalData } from '@agiliza/api/domain' ...@@ -2,9 +2,9 @@ import { PersonalData } from '@agiliza/api/domain'
type ExtendedState = PersonalData 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: '' }, rg: { number: '', dispatcherAgency: '', front: '', back: '' },
birthday: null, birthday: null,
userCRAS: false, userCRAS: false,
......
...@@ -7,16 +7,7 @@ import sharedStyles from '../styles' ...@@ -7,16 +7,7 @@ import sharedStyles from '../styles'
export default (theme: Theme) => { export default (theme: Theme) => {
return createStyles({ return createStyles({
...sharedStyles(theme), ...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' }, switchCardPhotoContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly' },
datePicker: { marginBottom: '0px !important' }, datePicker: { marginBottom: '0px !important' },
}) })
......
import React from 'react' 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 { 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 { DatePicker } from '@curio/components'
import { TextField, TextFieldProps } from '@material-ui/core' import { TextField, TextFieldProps } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles' import { withStyles, WithStyles } from '@material-ui/core/styles'
...@@ -14,12 +18,13 @@ type ExtendedProps = WithStyles<typeof styles> ...@@ -14,12 +18,13 @@ type ExtendedProps = WithStyles<typeof styles>
interface Props extends ExtendedProps { interface Props extends ExtendedProps {
state: CustomerSourceIncomeState state: CustomerSourceIncomeState
actions: ActionType<CustomerSourceIncomeState> actions: ActionType<CustomerSourceIncomeState>
context: AuthenticationContext
} }
const Form = (props: Props) => { 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) => { const handleChangeDate = (type: keyof Pick<CustomerSourceIncomeState, 'admissionDate'>) => (date: Date | null) => {
actions.update({ [type]: date }) actions.update({ [type]: date })
...@@ -31,8 +36,26 @@ const Form = (props: Props) => { ...@@ -31,8 +36,26 @@ const Form = (props: Props) => {
actions.update({ [key]: evt.target.value }) 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 ( return (
<form className={classes.form}> <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')} /> <TextField variant="outlined" label="CNPJ" value={maskCPFCNPJ(cnpj)} onChange={handleChangeText('cnpj')} />
<DatePicker <DatePicker
id="admission-date" id="admission-date"
...@@ -42,6 +65,10 @@ const Form = (props: Props) => { ...@@ -42,6 +65,10 @@ const Form = (props: Props) => {
format="dd/MM/yyyy" format="dd/MM/yyyy"
className={classes.datePicker} 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> </form>
) )
} }
......
...@@ -7,16 +7,7 @@ import sharedStyles from '../styles' ...@@ -7,16 +7,7 @@ import sharedStyles from '../styles'
export default (theme: Theme) => { export default (theme: Theme) => {
return createStyles({ return createStyles({
...sharedStyles(theme), ...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' }, switchCardPhotoContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly' },
datePicker: { marginBottom: '0px !important' }, datePicker: { marginBottom: '0px !important' },
}) })
......
import React from 'react' 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 { withStyles, WithStyles } from '@material-ui/core/styles'
import { connected, ConnectedProps } from './connect'
import Form from './Form' import Form from './Form'
import { initialState } from './state' import { CustomerSourceIncomeState } from './state'
import styles from './styles' 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 SourceIncome = (props: Props) => {
const { classes } = props const { classes, context, state, actions } = props
const formState = useFormState('sourceIncome', initialState)
return ( return (
<div className={classes.contentContainer}> <div className={classes.contentContainer}>
<div className={classes.content}> <div className={classes.content}>
<Form {...formState} /> <Form state={state} actions={actions} context={context} />
</div> </div>
</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 { default } from './SourceIncome'
export * from './SourceIncome' export * from './SourceIncome'
export * from './state'
...@@ -7,16 +7,7 @@ import sharedStyles from '../styles' ...@@ -7,16 +7,7 @@ import sharedStyles from '../styles'
export default (theme: Theme) => { export default (theme: Theme) => {
return createStyles({ return createStyles({
...sharedStyles(theme), ...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' }, switchCardPhotoContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly' },
datePicker: { marginBottom: '0px !important' }, datePicker: { marginBottom: '0px !important' },
}) })
......
import React from 'react' 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 { 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 { TextField, TextFieldProps } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles' import { withStyles, WithStyles } from '@material-ui/core/styles'
import { CustomerSpousePersonalDataState } from '../state' import { CDSpousePersonalDataState } from '../state'
import styles from './styles' import styles from './styles'
type ExtendedProps = WithStyles<typeof styles> type ExtendedProps = WithStyles<typeof styles>
interface Props extends ExtendedProps { interface Props extends ExtendedProps {
state: CustomerSpousePersonalDataState state: CDSpousePersonalDataState
actions: ActionType<CustomerSpousePersonalDataState> actions: ActionType<CDSpousePersonalDataState>
context: ProposalDataContext
} }
const Form = (props: Props) => { 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 }) actions.update({ [type]: date })
} }
const handleChangeText = const handleChangeText =
(key: keyof CustomerSpousePersonalDataState): TextFieldProps['onChange'] => (key: keyof CDSpousePersonalDataState): TextFieldProps['onChange'] =>
(evt) => { (evt) => {
actions.update({ [key]: evt.target.value }) 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 ( return (
<form className={classes.form}> <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')} /> <TextField variant="outlined" label="Nome" value={name} onChange={handleChangeText('name')} />
<RGTemplate rg={rg} onChange={handleChangeRG} />
<DatePicker <DatePicker
id="admission-date" id="admission-date"
label="Data de nascimento" label="Data de nascimento"
...@@ -41,6 +87,35 @@ const Form = (props: Props) => { ...@@ -41,6 +87,35 @@ const Form = (props: Props) => {
format="dd/MM/yyyy" format="dd/MM/yyyy"
className={classes.datePicker} 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> </form>
) )
} }
......
...@@ -7,16 +7,7 @@ import sharedStyles from '../styles' ...@@ -7,16 +7,7 @@ import sharedStyles from '../styles'
export default (theme: Theme) => { export default (theme: Theme) => {
return createStyles({ return createStyles({
...sharedStyles(theme), ...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' }, switchCardPhotoContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly' },
datePicker: { marginBottom: '0px !important' }, datePicker: { marginBottom: '0px !important' },
}) })
......
import React from 'react' 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 { withStyles, WithStyles } from '@material-ui/core/styles'
import { connected, ConnectedProps } from './connect'
import Form from './Form' import Form from './Form'
import { initialState } from './state' import { CDSpousePersonalDataState } from './state'
import styles from './styles' 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 SpouseData = (props: Props) => {
const { classes } = props const { classes, context, state, actions } = props
const formState = useFormState('spouseDataForm', initialState)
return ( return (
<div className={classes.contentContainer}> <div className={classes.contentContainer}>
<div className={classes.content}> <div className={classes.content}>
<Form {...formState} /> <Form state={state} actions={actions} context={context} />
</div> </div>
</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 { default } from './SpouseData'
export * from './SpouseData' export * from './SpouseData'
export * from './state'
...@@ -2,9 +2,9 @@ import { SpousePersonalData } from '@agiliza/api/domain' ...@@ -2,9 +2,9 @@ import { SpousePersonalData } from '@agiliza/api/domain'
type ExtendedState = SpousePersonalData type ExtendedState = SpousePersonalData
export interface CustomerSpousePersonalDataState extends ExtendedState {} export interface CDSpousePersonalDataState extends ExtendedState {}
export const initialState: CustomerSpousePersonalDataState = { export const initialState: CDSpousePersonalDataState = {
cpf: '', cpf: '',
name: '', name: '',
rg: { number: '', dispatcherAgency: '', front: '', back: '' }, rg: { number: '', dispatcherAgency: '', front: '', back: '' },
......
...@@ -7,16 +7,7 @@ import sharedStyles from '../styles' ...@@ -7,16 +7,7 @@ import sharedStyles from '../styles'
export default (theme: Theme) => { export default (theme: Theme) => {
return createStyles({ return createStyles({
...sharedStyles(theme), ...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' }, switchCardPhotoContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly' },
datePicker: { marginBottom: '0px !important' }, datePicker: { marginBottom: '0px !important' },
}) })
......
...@@ -7,4 +7,18 @@ import sharedStyles from '../shared-styles' ...@@ -7,4 +7,18 @@ import sharedStyles from '../shared-styles'
export default (theme: Theme) => export default (theme: Theme) =>
createStyles({ createStyles({
...sharedStyles(theme), ...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 { RouteComponentProps } from 'react-router'
import ButtonWithProgress from '@agiliza/components/atoms/ButtonWithProgress'
import { useFormState } from '@agiliza/utils/hooks/state' import { useFormState } from '@agiliza/utils/hooks/state'
import { Button, MobileStepper, Typography } from '@material-ui/core' import { Button, MobileStepper, Typography } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles' import { withStyles, WithStyles } from '@material-ui/core/styles'
...@@ -20,14 +21,14 @@ import { ...@@ -20,14 +21,14 @@ import {
import { businessDataItems } from './BusinessData' import { businessDataItems } from './BusinessData'
import { connected, ConnectedProps } from './connect' import { connected, ConnectedProps } from './connect'
import Address from './CustomerData/Address' import Address, { initialState as cdAddressInitState } from './CustomerData/Address'
import Home from './CustomerData/Home' import Home from './CustomerData/Home'
import Identification, { initialState as cdIdentInitState } from './CustomerData/Identification' 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 References from './CustomerData/References'
import SourceIncome from './CustomerData/SourceIncome' import SourceIncome, { initialState as cdSourceIncomeInitState } from './CustomerData/SourceIncome'
import SpouseAdditionalData from './CustomerData/SpouseAdditionalData' import SpouseAdditionalData from './CustomerData/SpouseAdditionalData'
import SpouseData from './CustomerData/SpouseData' import SpouseData, { initialState as cdSpouseDataInitState } from './CustomerData/SpouseData'
import Vehicles from './CustomerData/Vehicles' import Vehicles from './CustomerData/Vehicles'
import styles from './shared-styles' import styles from './shared-styles'
...@@ -46,10 +47,19 @@ type ExtendedProps = WithStyles<typeof styles> & RouteComponentProps & Connected ...@@ -46,10 +47,19 @@ type ExtendedProps = WithStyles<typeof styles> & RouteComponentProps & Connected
interface Props extends ExtendedProps {} interface Props extends ExtendedProps {}
const ProposalData = (props: Props) => { const ProposalData = (props: Props) => {
const { classes } = props const { classes, fetching, proposalId, personId } = props
const [activeStep, setActiveStep] = useState(0) 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( const customerDataItems = useMemo(
() => [ () => [
...@@ -58,16 +68,16 @@ const ProposalData = (props: Props) => { ...@@ -58,16 +68,16 @@ const ProposalData = (props: Props) => {
icon: <AccountBoxIcon />, icon: <AccountBoxIcon />,
component: <Identification state={cdIdentification.state} actions={cdIdentification.actions} />, component: <Identification state={cdIdentification.state} actions={cdIdentification.actions} />,
}, },
{ label: 'Dados Pessoais', icon: <ListIcon />, component: <PersonalData /> }, { label: 'Dados Pessoais', icon: <ListIcon />, component: <PersonalData state={cdPersonalData.state} actions={cdPersonalData.actions} /> },
{ label: 'Endereço', icon: <ContactMailIcon />, component: <Address /> }, { label: 'Endereço', icon: <ContactMailIcon />, component: <Address state={cdAddress.state} actions={cdAddress.actions} /> },
{ label: 'Fonte de renda', icon: <LocalAtmIcon />, component: <SourceIncome /> }, { label: 'Fonte de renda', icon: <LocalAtmIcon />, component: <SourceIncome state={cdSourceIncome.state} actions={cdSourceIncome.actions} /> },
{ label: 'Cônjuge - Ident.', icon: <ForumIcon />, component: <SpouseData /> }, { label: 'Cônjuge - Ident.', icon: <ForumIcon />, component: <SpouseData state={cdSpouseData.state} actions={cdSpouseData.actions} /> },
{ label: 'Cônjuge +', icon: <ZoomOutMapIcon />, component: <SpouseAdditionalData /> }, { label: 'Cônjuge +', icon: <ZoomOutMapIcon />, component: <SpouseAdditionalData /> },
{ label: 'Referências', icon: <CheckBoxIcon />, component: <References /> }, { label: 'Referências', icon: <CheckBoxIcon />, component: <References /> },
{ label: 'Moradia', icon: <HomeIcon />, component: <Home /> }, { label: 'Moradia', icon: <HomeIcon />, component: <Home /> },
{ label: 'Veículos', icon: <DriveEtaIcon />, component: <Vehicles /> }, { label: 'Veículos', icon: <DriveEtaIcon />, component: <Vehicles /> },
], ],
[cdIdentification] [cdIdentification, cdPersonalData, cdAddress, cdSpouseData]
) )
const proposalDataItems = useMemo(() => [...customerDataItems, ...businessDataItems], [customerDataItems, businessDataItems]) const proposalDataItems = useMemo(() => [...customerDataItems, ...businessDataItems], [customerDataItems, businessDataItems])
...@@ -77,7 +87,46 @@ const ProposalData = (props: Props) => { ...@@ -77,7 +87,46 @@ const ProposalData = (props: Props) => {
const handleNext = () => { const handleNext = () => {
// if (activeStep === steps - 1) history.push({ pathname: PATHS.creditLines }) // 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 = () => { const handleBack = () => {
...@@ -122,10 +171,17 @@ const ProposalData = (props: Props) => { ...@@ -122,10 +171,17 @@ const ProposalData = (props: Props) => {
</Button> </Button>
} }
backButton={ 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 /> <KeyboardArrowLeftIcon />
Anterior Anterior
</Button> </ButtonWithProgress>
} }
/> />
{/* </Stepper> */} {/* </Stepper> */}
......
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { bindActionCreators, Dispatch } from 'redux'
import { StoreState } from '@agiliza/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 ucProposalDataContext from '@agiliza/redux/useCases/proposalData/context'
import * as ucProposalDataCD from '@agiliza/redux/useCases/proposalData/customerData'
export interface ConnectedProps { export interface ConnectedProps {
fetching: boolean 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 StateProps = Pick<ConnectedProps, 'fetching' | 'proposalId' | 'personId'>
// type DispatchProps = Record<string, any> type DispatchProps = Pick<
ConnectedProps,
'addIndentification' | 'fetchContext' | 'updatePersonalData' | 'updateAddress' | 'getContextAddress' | 'updateSourceIncome' | 'updateSpouseData'
>
const mapStateToProps = (state: StoreState): StateProps => ({ const mapStateToProps = (state: StoreState): StateProps => ({
fetching: ucProposalDataContext.selectors.isFetching(state.ui.login), 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) => ...@@ -27,7 +27,8 @@ export default (theme: Theme) =>
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
alignItems: 'center', alignItems: 'center',
width: '25%', width: '30%',
height: '100%', height: '100%',
}, },
imageUpload: { width: '100%', textAlign: 'center', marginTop: theme.spacing(1), marginBottom: theme.spacing(1) },
}) })
...@@ -937,10 +937,10 @@ ...@@ -937,10 +937,10 @@
isomorphic-fetch "^2.2.1" isomorphic-fetch "^2.2.1"
symbol-observable "^1.2.0" symbol-observable "^1.2.0"
"@curio/components@^0.1.5": "@curio/components@^0.1.6":
version "0.1.5" version "0.1.6"
resolved "https://nexus.dev.evologica.com.br/repository/npm/@curio/components/-/components-0.1.5.tgz#098d89ed0d06a0178af71a6e7c73f588aeccb241" resolved "https://nexus.dev.evologica.com.br/repository/npm/@curio/components/-/components-0.1.6.tgz#a6b69b17af2ab2966c97016372cddbc35f0eef87"
integrity sha512-g9WKPReGIzDioaXBMlycUO4ghWY2WPCoAE7U/YC88+s8tDylgrqSIDpE8SQJGZ0p8R0odqszhXehmec2Amfv7A== integrity sha512-AVblcKODqCqforRww+1buMRMDMNyDN75N6TqYsRwM34onRlstcT4wQXLv0gZA1qZrCMu9E9TAcKjVy3RKgQ1Dw==
dependencies: dependencies:
"@curio/client" "1.3.3" "@curio/client" "1.3.3"
"@date-io/date-fns" "^1.0.0" "@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