Commit b069d199 authored by Rafael's avatar Rafael

Adiciona mais conexões com o serviço.

parent 06b6c363
{
"API_URL": "http://172.16.17.3:8080",
"APP_NAME_BROKER": "@microcredito-dev/agente",
"APP_NAME_CUSTOMER": "@microcredito-dev/cliente",
"SESSION_KEY_BROKER": "@microcredito-dev/agente",
"SESSION_KEY_CUSTOMER": "@microcredito-dev/cliente"
"APP_NAME_BROKER": "@agiliza-dev/agente",
"APP_NAME_CUSTOMER": "@agiliza-dev/cliente",
"SESSION_KEY_BROKER": "@agiliza-dev/agente",
"SESSION_KEY_CUSTOMER": "@agiliza-dev/cliente"
}
{
"API_URL": "http://192.168.0.34:8080",
"APP_NAME_BROKER": "@microcredito-dev/agente",
"APP_NAME_CUSTOMER": "@microcredito-dev/cliente",
"SESSION_KEY_BROKER": "@microcredito-dev/agente",
"SESSION_KEY_CUSTOMER": "@microcredito-dev/cliente"
"API_URL": "http://172.16.17.3:8080",
"APP_NAME_BROKER": "@agiliza-dev/agente",
"APP_NAME_CUSTOMER": "@agiliza-dev/cliente",
"SESSION_KEY_BROKER": "@agiliza-dev/agente",
"SESSION_KEY_CUSTOMER": "@agiliza-dev/cliente"
}
{
"API_URL": "https://microcredito.dev.evologica.com.br",
"APP_NAME_BROKER": "@microcredito/agente",
"APP_NAME_CUSTOMER": "@microcredito/cliente",
"SESSION_KEY_BROKER": "@microcredito/agente",
"SESSION_KEY_CUSTOMER": "@microcredito/cliente"
"API_URL": "http://172.16.17.3:8080",
"APP_NAME_BROKER": "@agiliza-dev/agente",
"APP_NAME_CUSTOMER": "@agiliza-dev/cliente",
"SESSION_KEY_BROKER": "@agiliza-dev/agente",
"SESSION_KEY_CUSTOMER": "@agiliza-dev/cliente"
}
{
"API_URL": "https://microcredito.test.evologica.com.br",
"APP_NAME_BROKER": "@microcredito-staging/agente",
"APP_NAME_CUSTOMER": "@microcredito-staging/cliente",
"SESSION_KEY_BROKER": "@microcredito-staging/agente",
"SESSION_KEY_CUSTOMER": "@microcredito-staging/cliente"
"API_URL": "http://172.16.17.3:8080",
"APP_NAME_BROKER": "@agiliza-dev/agente",
"APP_NAME_CUSTOMER": "@agiliza-dev/cliente",
"SESSION_KEY_BROKER": "@agiliza-dev/agente",
"SESSION_KEY_CUSTOMER": "@agiliza-dev/cliente"
}
......@@ -90,7 +90,7 @@
"@material-ui/icons": "^4.11.2",
"@material-ui/lab": "4.0.0-alpha.58",
"@material-ui/pickers": "^3.3.10",
"@microcredito/client": "^0.7.11",
"@microcredito/client": "^0.7.13",
"@reduxjs/toolkit": "^1.2.5",
"@types/react-swipeable-views": "^0.13.1",
"@types/react-swipeable-views-utils": "^0.13.3",
......
{
"API_URL": "http://172.16.17.3:8080",
"APP_NAME_BROKER": "@microcredito-dev/agente",
"APP_NAME_CUSTOMER": "@microcredito-dev/cliente",
"SESSION_KEY_BROKER": "@microcredito-dev/agente",
"SESSION_KEY_CUSTOMER": "@microcredito-dev/cliente"
"APP_NAME_BROKER": "@agiliza-dev/agente",
"APP_NAME_CUSTOMER": "@agiliza-dev/cliente",
"SESSION_KEY_BROKER": "@agiliza-dev/agente",
"SESSION_KEY_CUSTOMER": "@agiliza-dev/cliente"
}
\ No newline at end of file
import { Entity } from '@agiliza/utils/method'
export * from './proposalData'
export * from './context'
export * from './error'
......@@ -15,3 +17,19 @@ export interface Customer {
address?: Partial<Address>
profilePicture?: string
}
export interface IdDescricao {
id: string
descricao: string
}
export interface DocumentType extends Entity {
description: string
}
export interface Document {
id: string
type: DocumentType
extraInformations: string
url: string
}
......@@ -19,3 +19,13 @@ export interface UpdateBDIdentificationArgs {
projectId: string
identification: BDIdentification
}
interface InputUpdateBDIdentification {
projectId: string
identification: BDIdentification
}
export interface UpdateBDIdentification {
Input: InputUpdateBDIdentification
Output: BDIdentification
}
import { Entity } from '@agiliza/utils/method'
export interface Framework extends Entity {
description: string
}
export interface Gender extends Entity {
description: string
}
export interface ProposalDataContext {
frameworks: Framework[]
genders: Gender[]
}
export interface FetchContext {
Input: void
Output: ProposalDataContext
}
export * from './involvedPeople'
export * from './businessData'
export * from './context'
export interface Address {
id: string
......
......@@ -16,8 +16,8 @@ export interface GetSubProducts {
interface InputGetSubProducts {
creditValue: number
idModality: string
idGracePeriod: string
categoryId: string
gracePeriodId: string
installmentsNumber: number
}
......@@ -28,3 +28,20 @@ export interface InstallmentOption extends Entity {
installmentValue?: number
netValue?: number
}
interface InputCreateProposal {
creditValue: number
gracePeriodId: number
categoryId: string
installmentsNumber: number
subproductId: string
}
interface OutputCreateProposal {
proposalId: string
}
export interface CreateProposal {
Input: InputCreateProposal
Output: OutputCreateProposal
}
import * as AuthenticationApiMappers from './authentication'
import * as ProposalDataApiMappers from './proposalData'
import * as SessionApiAdapters from './session'
import * as SimulationApiMappers from './simulation'
export { SessionApiAdapters, SimulationApiMappers, AuthenticationApiMappers }
export { SessionApiAdapters, SimulationApiMappers, AuthenticationApiMappers, ProposalDataApiMappers }
import { BusinessData, CreateProposal, Document, UpdateBDIdentification } from '@agiliza/api/domain'
import { extractNumbers } from '@agiliza/utils/extractors'
import { DadosNegocioIdentificacaoApiModel, DocumentoApiModel } from '@microcredito/client'
import { AtualizarIdentificacaoDadosNegocioRequest } from '@microcredito/client/dist/apis/AgenteApi'
import { CriarPropostaRequest } from '@microcredito/client/dist/apis/ClienteApi'
import { ApiAdapter } from '../shared'
export class DocumentApiMapper implements ApiAdapter<Document, DocumentoApiModel> {
private mapDocumentTypeToApi = (docType: Document['type']): DocumentoApiModel['tipoDocumento'] => ({
codigo: docType.id,
descricao: docType.description,
})
public mapDomainToApiModel = (doc: Document): DocumentoApiModel => ({
id: doc.id,
imagem: doc.url,
tipoDocumento: this.mapDocumentTypeToApi(doc.type),
informacoesComplementares: doc.extraInformations,
})
}
export class BDIdentificationApiMapper implements ApiAdapter<BusinessData['identification'], DadosNegocioIdentificacaoApiModel> {
private documentAdapter: DocumentApiMapper
constructor() {
this.documentAdapter = new DocumentApiMapper()
}
public mapDomainToApiModel = (ident: BusinessData['identification']): DadosNegocioIdentificacaoApiModel => ({
cnpj: extractNumbers(ident?.cnpj),
codigoCNAE: ident?.codeCNAE,
dataAbertura: ident?.openingDate !== null ? ident?.openingDate : undefined,
documento: ident?.document ? this.documentAdapter.mapDomainToApiModel(ident?.document) : undefined,
inscricaoComercial: ident?.commercialRegistration,
inscricaoEstadual: ident?.stateRegistration,
inscricaoMunicipal: ident?.cityRegistration,
local: ident?.local,
nomeFantasia: ident?.fantasyName,
opLiquidada: ident?.settledOP,
razaoSocial: ident?.companyName,
setorAtividade: ident?.activitySector,
})
}
export class BDUpdateIdentificationApiMapper implements ApiAdapter<UpdateBDIdentification['Input'], AtualizarIdentificacaoDadosNegocioRequest> {
private identificationApiMapper: BDIdentificationApiMapper
constructor() {
this.identificationApiMapper = new BDIdentificationApiMapper()
}
public mapDomainToApiModel = (input: UpdateBDIdentification['Input']): AtualizarIdentificacaoDadosNegocioRequest => ({
projetoId: input.projectId,
dadosNegocioIdentificacaoApiModel: this.identificationApiMapper.mapDomainToApiModel(input.identification),
})
}
export class CreateProposalApiMapper implements ApiAdapter<CreateProposal['Input'], CriarPropostaRequest> {
public mapDomainToApiModel = (input: CreateProposal['Input']): CriarPropostaRequest => ({
criarPropostaRequestApiModel: {
carencia: input.gracePeriodId,
categoriaSimulacao: input.categoryId,
quantidadeParcelas: input.installmentsNumber,
valorInteresse: input.creditValue,
subprodutoId: input.subproductId,
},
})
}
......@@ -6,8 +6,8 @@ import { ApiAdapter } from '../shared'
export class GetSubProductsApiMapper implements ApiAdapter<GetSubProducts['Input'], SimularCreditoRequestApiModel> {
public mapDomainToApiModel = (input: GetSubProducts['Input']): SimularCreditoRequestApiModel => ({
valorCredito: input.creditValue,
codigoCarencia: input.idGracePeriod,
codigoModalidade: input.idModality,
codigoCarencia: input.gracePeriodId,
codigoModalidade: input.categoryId,
numeroParcelas: input.installmentsNumber,
})
}
......@@ -2,7 +2,10 @@ import * as AuthenticationMappers from './authentication'
import * as ContextMappers from './context'
import * as CustomerMappers from './customer'
import * as ErrorMappers from './error'
import * as ProposalDataMappers from './proposalData'
import * as SessionAdapters from './session'
import * as SimulationMappers from './simulation'
export { ContextMappers, ErrorMappers, SessionAdapters, SimulationMappers, AuthenticationMappers, CustomerMappers }
export { ContextMappers, ErrorMappers, SessionAdapters, SimulationMappers, AuthenticationMappers, CustomerMappers, ProposalDataMappers }
export * from './shared'
import { BDIdentification, Document } from '@agiliza/api/domain'
import { DadosNegocioIdentificacaoApiModel, DocumentoApiModel } from '@microcredito/client'
import { DomainAdapter } from '../shared'
export class ProjectDocumentMapper implements DomainAdapter<DocumentoApiModel, Document> {
public mapTipoDocumentoApiToDomain = (tipo: DocumentoApiModel['tipoDocumento']): Document['type'] => ({
id: tipo.codigo,
description: tipo.descricao,
})
public mapApiModelToDomain = (apimodel: DocumentoApiModel): Document => ({
id: apimodel.id,
url: apimodel.imagem,
type: this.mapTipoDocumentoApiToDomain(apimodel.tipoDocumento),
extraInformations: apimodel.informacoesComplementares || '',
})
}
export class BDIdentificationMapper implements DomainAdapter<DadosNegocioIdentificacaoApiModel, BDIdentification> {
private documentAdapter: ProjectDocumentMapper
constructor() {
this.documentAdapter = new ProjectDocumentMapper()
}
public mapApiModelToDomain = (dnIdent: DadosNegocioIdentificacaoApiModel): BDIdentification => ({
activitySector: dnIdent.setorAtividade || '',
cityRegistration: dnIdent.inscricaoMunicipal || '',
cnpj: dnIdent.cnpj || '',
codeCNAE: dnIdent.codigoCNAE || '',
commercialRegistration: dnIdent.inscricaoComercial || '',
companyName: dnIdent.razaoSocial || '',
fantasyName: dnIdent.nomeFantasia || '',
local: dnIdent.local || '',
openingDate: dnIdent.dataAbertura || null,
settledOP: dnIdent.opLiquidada || '',
stateRegistration: dnIdent.inscricaoEstadual || '',
document: dnIdent.documento ? this.documentAdapter.mapApiModelToDomain(dnIdent.documento) : undefined,
})
}
import { ProposalDataContext } from '@agiliza/api/domain'
import { EnquadramentoApiModel, GeneroApiModel } from '@microcredito/client'
import { DomainAdapter, IdDescriptionMapper } from '../shared'
export interface DadosPropostaContexto {
enquadramentos: EnquadramentoApiModel[]
generos: GeneroApiModel[]
}
export class ContextMapper implements DomainAdapter<DadosPropostaContexto, ProposalDataContext> {
private idDescriptionMapper: IdDescriptionMapper
constructor() {
this.idDescriptionMapper = new IdDescriptionMapper()
}
public mapApiModelToDomain = (dP: DadosPropostaContexto): ProposalDataContext => ({
frameworks: dP.enquadramentos.map(this.idDescriptionMapper.mapApiModelToDomain),
genders: dP.generos.map(this.idDescriptionMapper.mapApiModelToDomain),
})
}
export * from './businessData'
export * from './context'
import { IdDescricao } from '@agiliza/api/domain'
import { Entity } from '@agiliza/utils/method'
export interface DomainAdapter<A, B> {
mapApiModelToDomain(apiModel: A): B
}
interface IdDescription extends Entity {
description: string
}
export class IdDescriptionMapper implements DomainAdapter<IdDescricao, IdDescription> {
public mapApiModelToDomain = (iD: IdDescricao): IdDescription => ({
id: iD.id,
description: iD.descricao,
})
}
export * from './session'
export * from './simulation'
export * from './authentication'
export * from './proposalData'
import { mapUserAgentToString, SESSION_KEY, UserAgent } from '../shared'
export interface PDBusinessDataRepository {}
export class PDBusinessDataRepositoryImpl implements PDBusinessDataRepository {
// private api: ClienteApi
// private errorAdapter: ErrorMappers.ResponseErrorAdapter
constructor(userAgent: string, accessToken: string) {
// this.errorAdapter = new ErrorMappers.ResponseErrorAdapter()
// this.api = new ClienteApi(
// new Configuration({
// basePath: API_URL,
// accessToken,
// headers: {
// 'User-Agent': userAgent,
// },
// })
// )
}
}
export class PDBusinessDataRepositoryImplFactory {
static create(userAgent: UserAgent) {
const accessToken = localStorage.getItem(SESSION_KEY) || ''
const repository = new PDBusinessDataRepositoryImpl(mapUserAgentToString(userAgent), accessToken)
return repository
}
}
import { FetchContext } from '@agiliza/api/domain'
import { Configuration, DominioApi } from '@microcredito/client'
import { ErrorMappers, ProposalDataMappers } from '../../mappers'
import { DadosPropostaContexto } from '../../mappers/domain/proposalData/context'
import { API_URL, mapUserAgentToString, SESSION_KEY, UserAgent } from '../shared'
export interface ProposalDataContextRepository {
fetchContext(): Promise<FetchContext['Output']>
}
export class ProposalDataContextRepositoryImpl implements ProposalDataContextRepository {
private api: DominioApi
private errorAdapter: ErrorMappers.ResponseErrorAdapter
private contextMapper: ProposalDataMappers.ContextMapper
constructor(userAgent: string, accessToken: string) {
this.errorAdapter = new ErrorMappers.ResponseErrorAdapter()
this.contextMapper = new ProposalDataMappers.ContextMapper()
this.api = new DominioApi(
new Configuration({
basePath: API_URL,
accessToken,
headers: {
'User-Agent': userAgent,
},
})
)
}
public fetchContext = async (): Promise<FetchContext['Output']> => {
try {
const contexto: DadosPropostaContexto = { enquadramentos: await this.api.obterEnquadramentos(), generos: await this.api.obterGeneros() }
return this.contextMapper.mapApiModelToDomain(contexto)
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
}
export class ProposalDataContextRepositoryImplFactory {
static create(userAgent: UserAgent) {
const accessToken = localStorage.getItem(SESSION_KEY) || ''
const repository = new ProposalDataContextRepositoryImpl(mapUserAgentToString(userAgent), accessToken)
return repository
}
}
import { CreateProposal, UpdateBDIdentification } from '@agiliza/api/domain'
import { ClienteApi, Configuration } from '@microcredito/client'
import { ErrorMappers, ProposalDataApiMappers, ProposalDataMappers } from '../../mappers'
import { API_URL, mapUserAgentToString, SESSION_KEY, UserAgent } from '../shared'
export interface PDCustomerDataDataRepository {
createProposal(input: CreateProposal['Input']): Promise<CreateProposal['Output']>
updateIdentification(input: UpdateBDIdentification['Input']): Promise<UpdateBDIdentification['Output']>
}
export class PDCustomerDataRepositoryImpl implements PDCustomerDataDataRepository {
private api: ClienteApi
private errorAdapter: ErrorMappers.ResponseErrorAdapter
private updateIdentificationApiMapper: ProposalDataApiMappers.BDUpdateIdentificationApiMapper
private identificationMapper: ProposalDataMappers.BDIdentificationMapper
private createProposalApiMapper: ProposalDataApiMappers.CreateProposalApiMapper
constructor(userAgent: string, accessToken: string) {
this.errorAdapter = new ErrorMappers.ResponseErrorAdapter()
this.updateIdentificationApiMapper = new ProposalDataApiMappers.BDUpdateIdentificationApiMapper()
this.identificationMapper = new ProposalDataMappers.BDIdentificationMapper()
this.createProposalApiMapper = new ProposalDataApiMappers.CreateProposalApiMapper()
this.api = new ClienteApi(
new Configuration({
basePath: API_URL,
accessToken,
headers: {
'User-Agent': userAgent,
},
})
)
}
public updateIdentification = async (input: UpdateBDIdentification['Input']): Promise<UpdateBDIdentification['Output']> => {
try {
const response = await this.api.atualizarIdentificacaoDadosNegocio(this.updateIdentificationApiMapper.mapDomainToApiModel(input))
return this.identificationMapper.mapApiModelToDomain(response)
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
public createProposal = async (input: CreateProposal['Input']): Promise<CreateProposal['Output']> => {
try {
const response = await this.api.criarProposta(this.createProposalApiMapper.mapDomainToApiModel(input))
return { proposalId: response.propostaId || '' }
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
}
export class PDCustomerDataRepositoryImplFactory {
static create(userAgent: UserAgent) {
const accessToken = localStorage.getItem(SESSION_KEY) || ''
const repository = new PDCustomerDataRepositoryImpl(mapUserAgentToString(userAgent), accessToken)
return repository
}
}
export * from './context'
export * from './businessData'
......@@ -5,80 +5,6 @@ import { Customer } from '../domain'
import { CustomerMappers, SessionAdapters, SessionApiAdapters as Adapters } from '../mappers'
import { API_URL, mapUserAgentToString, SESSION_KEY, UserAgent } from './shared'
// import { getSessionManager } from '@agiliza/curio'
// import { createMenuAPI } from '../dynamo'
// // import { createMenuAPI } from '../dynamo'
// // import { SolicitarRedefinicao, VerificarCodigo, RedefinirSenha } from '../interfaces/Login'
// // const ucRecuperarSenha = {
// // id: '3522',
// // SOLICITAR_REDEFINICAO: 'RM_SOLICITAR_REDEFINICAO',
// // VERIFICAR_CODIGO: 'RM_VERIFICAR_CODIGO',
// // DEFIINIR_SENHA: 'RM_DEFINIR_SENHA'
// // }
// interface LoginParams {
// username: string
// password: string
// }
// export const initialize = async () => {
// await getSessionManager()
// }
// export const login = async ({ username, password }: LoginParams) => {
// const sessionManager = await getSessionManager()
// return sessionManager.openMainUseCase(username, password)
// }
// export const logout = async () => {
// const sessionManager = await getSessionManager()
// sessionManager?.session?.abort()
// }
// export const { fetchMenu } = createMenuAPI()
// export const solicitarRedefinicao = async (funcionario: SolicitarRedefinicao) => {
// const mainUseCase = await sessionManager.anonymousConnection()
// const uc = await mainUseCase.openUseCase(ucRecuperarSenha.id)
// const response = await uc.sendRequest(ucRecuperarSenha.SOLICITAR_REDEFINICAO, {
// Funcionario: funcionario
// })
// await uc.abort()
// return response.Funcionario as Funcionario
// }
// const enviarCodigoSenha = async (envCodigo: VerificarCodigo) => {
// const { _codigoAcesso, _OID } = envCodigo
// const mainUseCase = await sessionManager.anonymousConnection()
// const uc = await mainUseCase.openUseCase(ucRecuperarSenha.id)
// const response = await uc.sendRequest(ucRecuperarSenha.VERIFICAR_CODIGO, {
// Funcionario: { _codigoAcesso, _OID }
// })
// await uc.abort()
// return response.Funcionario as Funcionario
// }
// const redefinirSenha = async (redefSenha: RedefinirSenha) => {
// const { _OID, _senha, _codigoAcesso } = redefSenha
// const mainUseCase = await sessionManager.anonymousConnection()
// const uc = await mainUseCase.openUseCase(ucRecuperarSenha.id)
// const response = await uc.sendRequest(ucRecuperarSenha.DEFIINIR_SENHA, {
// Funcionario: { _senha, _OID, _codigoAcesso }
// })
// await uc.abort()
// return response.Funcionario as Funcionario
// }
// export const useCaseRecuperarSenha = {
// solicitarRedefinicao,
// enviarCodigoSenha,
// redefinirSenha
// }
export interface SessionRepository {
login(username: string, password: string): Promise<Customer>
logout(): void
......@@ -110,6 +36,7 @@ export class SessionRepositoryImpl implements SessionRepository {
try {
const params = this.loginApiAdapter.mapDomainToApiModel({ username: extractNumbers(username), password })
const accessToken = await this.api.login(params)
localStorage.setItem(SESSION_KEY, accessToken.token)
const clienteApi = new ClienteApi(
new Configuration({
basePath: API_URL,
......@@ -131,7 +58,7 @@ export class SessionRepositoryImpl implements SessionRepository {
localStorage.removeItem(SESSION_KEY)
}
public connect = () => {
const sessionKey = localStorage.getItem(SESSION_KEY)
const sessionKey = localStorage.getItem(SESSION_KEY) || 'a'
if (sessionKey) return
else throw new Error()
// return await new Promise<void>((res, rej) => {
......
......@@ -3,9 +3,7 @@ import React, { useState } from 'react'
import { Collapse, CollapseProps, Fade } from '@material-ui/core'
import MuiAppBar, { AppBarProps as MuiAppBarProps } from '@material-ui/core/AppBar'
import IconButton from '@material-ui/core/IconButton'
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
import { Menu as DrawerIcon } from '@material-ui/icons'
import { Toolbar, ToolbarProps } from './Toolbar'
......@@ -43,15 +41,15 @@ const AppBar = ({ className, position = 'static', actions, title, children, onNa
setFadeIn(isAppearing)
}
const nav = onNavClick ? (
<IconButton color="inherit" onClick={onNavClick}>
<DrawerIcon />
</IconButton>
) : null
// const nav = onNavClick ? (
// <IconButton color="inherit" onClick={onNavClick}>
// <DrawerIcon />
// </IconButton>
// ) : null
return (
<>
<MuiAppBar className={cn(classes.appBar, className)} position={position} style={style}>
<Toolbar title={title} actions={actions} nav={nav} />
<Toolbar title={title} actions={actions} /*nav={nav}*/ />
{children && (
<Collapse appear enter in onEntered={onCollapse} timeout={400}>
<div>
......
......@@ -12,6 +12,7 @@ import DateFnsUtils from '@date-io/date-fns'
import { MuiThemeProvider } from '@material-ui/core/styles'
import { MuiPickersUtilsProvider } from '@material-ui/pickers'
import { SESSION_KEY } from './api/useCases/shared'
import ErrorDialog from './components/molecules/ErrorDialog'
import { store } from './redux'
import { theme } from './theme'
......@@ -37,6 +38,8 @@ const Adm = (props: Props) => {
)
}
localStorage.removeItem(SESSION_KEY) // Don't store any access token
if (isValidBrowser) {
render(<Adm />, root)
} else {
......
......@@ -2,6 +2,10 @@ import authentication, {
initialState as authenticationInitState,
Store as AuthenticationState
} from './authentication'
import proposalData, {
initialState as proposalDataInitState,
State as ProposalDataState
} from './proposalData'
import simulation, {
initialState as simulationInitState,
State as SimulationState
......@@ -12,18 +16,21 @@ export interface EntitiesState {
system: System
simulation: SimulationState
authentication: AuthenticationState
proposalData: ProposalDataState
}
export const initialState: EntitiesState = {
simulation: simulationInitState,
system: systemInitState,
authentication: authenticationInitState,
proposalData: proposalDataInitState,
}
const reducers = {
simulation,
system,
authentication,
proposalData,
}
export default reducers
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 { ProposalDataContext } from '@agiliza/api/domain'
import { entries, values } from '@agiliza/utils/method'
import { createSelector } from '@reduxjs/toolkit'
import { Store } from './slice'
export const getAllIds = (key: keyof Store) => (state: Store) => {
return state[key].allIds
}
export const getById = (key: keyof Store) => (state: Store) => {
return state[key].byId
}
export const getFrameworks = createSelector(getById('frameworks'), getAllIds('frameworks'), (byId, allIds) => allIds.map((id) => byId[id]))
export const getContext = (state: Store) =>
entries(state).reduce((entities, [k, v]) => {
return { ...entities, [k]: values(v.byId) }
}, {} as ProposalDataContext)
import { ProposalDataContext } from '@agiliza/api/domain'
import { types as fetchTypes } from '@agiliza/redux/useCases/proposalData/context'
import { entries, keys, WithEntityStore } from '@agiliza/utils/method'
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import { normalizeContext, PROPOSAL_DATA_PREFIX } from '../shared'
export interface Store extends WithEntityStore<ProposalDataContext> {
// frameworks: EntityStore<Framework>
}
export const initialState: Store = {
frameworks: { byId: {}, allIds: [] },
genders: { byId: {}, allIds: [] },
}
export default createSlice({
name: `${PROPOSAL_DATA_PREFIX}/context`,
initialState,
reducers: {},
extraReducers: {
[fetchTypes.fetchContext.fulfilled]: (state, action: PayloadAction<ProposalDataContext>) => {
const normalized = normalizeContext(action.payload)
entries(normalized).forEach(([k, v]) => {
state[k].byId = v
state[k].allIds = keys(v)
})
},
},
})
import { combineReducers } from 'redux'
import context, { initialState as contextInitState, Store as ContextStore } from './context'
export interface State {
context: ContextStore
}
export const initialState: State = {
context: contextInitState,
}
export default combineReducers({
context,
})
import { normalize, schema } from 'normalizr'
import { ProposalDataContext } from '@agiliza/api/domain'
import { WithNormalizedEntity } from '@agiliza/utils/method'
export const PROPOSAL_DATA_PREFIX = 'entities/proposalData'
export type NormalizedContext = WithNormalizedEntity<ProposalDataContext>
const contextSchemas = new schema.Object({
frameworks: new schema.Array(new schema.Entity('frameworks')),
genders: new schema.Array(new schema.Entity('genders')),
})
export const normalizeContext = (context: ProposalDataContext) => {
const { entities } = normalize(context, contextSchemas)
const normalizedEntities = entities as unknown as NormalizedContext
return normalizedEntities
}
......@@ -5,27 +5,21 @@ import {
} from './drawer'
import { initialState as errorInitialState, reducer as error, State as ErrorState } from './error'
import login, { initialState as loginInitialState, State as LoginState } from './login'
// import {
// initialState as profileInitialState,
// reducer as profile,
// State as ProfileState
// } from './profile'
import simulation, {
initialState as simulationInitialState,
State as SimulationState
} from './simulation'
import {
initialState as systemInitialState,
reducer as system,
State as SystemState
} from './system'
// import { initialState as userInitialState, reducer as user, State as UserState } from './user'
// export * from './login'
export interface UIState {
login: LoginState
error: ErrorState
drawer: DrawerState
// user: UserState
// profile: ProfileState
simulation: SimulationState
system: SystemState
}
......@@ -33,18 +27,16 @@ const reducers = {
login,
error,
drawer,
// user,
// profile,
system,
simulation,
}
export const initialState: UIState = {
login: loginInitialState,
error: errorInitialState,
drawer: drawerInitialState,
// user: userInitialState,
// profile: profileInitialState,
system: systemInitialState,
simulation: simulationInitialState,
}
export default reducers
import * as selectors from './selectors'
import slice from './slice'
export * from './slice'
const actions = slice.actions
export { selectors, actions }
export default slice.reducer
import { State } from './slice'
export const getData = (state: State) => state.data
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
const prefix = 'ui/simulation'
export interface State {
data?: { simulationCategoryId: string; amount: string; paymentMonths: number; graceMonths: number }
}
export const initialState: State = {}
const simulation = createSlice({
name: prefix,
initialState,
reducers: {
setData: (state, action: PayloadAction<State['data']>) => {
state.data = action.payload
},
},
})
export default simulation
......@@ -2,6 +2,10 @@ import authentication, {
initialState as authenticationInitialState,
State as AuthenticationState
} from './authentication'
import proposalData, {
initialState as proposalDataInitialState,
State as ProposalDataState
} from './proposalData'
import simulation, {
initialState as simulationInitialState,
State as SimulationState
......@@ -10,16 +14,19 @@ import simulation, {
export interface UseCasesState {
simulation: SimulationState
authentication: AuthenticationState
proposalData: ProposalDataState
}
const reducers = {
simulation,
authentication,
proposalData,
}
export const initialState: UseCasesState = {
simulation: simulationInitialState,
authentication: authenticationInitialState,
proposalData: proposalDataInitialState,
}
export default reducers
import * as selectors from './selectors'
import slice from './slice'
export * from './slice'
export { selectors }
export default slice.reducer
import { State } from './slice'
export const isFetching = (state: State) => state.fetching
import { createAsyncReducers, getTypesThunkActions, values } from '@agiliza/utils/method'
import { createSlice } from '@reduxjs/toolkit'
const prefix = 'useCases/businessData'
export interface State {
fetching: boolean
}
export const initialState: State = {
fetching: false,
}
export const actions = {} as const
export const types = getTypesThunkActions(actions)
const login = createSlice({
name: prefix,
initialState,
reducers: {},
extraReducers: {
...values(types).reduce((reducers, type) => ({ ...reducers, ...createAsyncReducers(type) }), {}),
},
})
export default login
import * as selectors from './selectors'
import slice from './slice'
export * from './slice'
export { selectors }
export default slice.reducer
import { State } from './slice'
export const isFetching = (state: State) => state.fetching
import { ProposalDataContextRepositoryImplFactory } from '@agiliza/api/useCases'
import { appPlatform } from '@agiliza/constants/platform'
import { createAsyncReducers, getTypesThunkActions, values } from '@agiliza/utils/method'
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
const prefix = 'useCases/proposalData'
export interface State {
fetching: boolean
}
export const initialState: State = {
fetching: false,
}
export const actions = {
fetchContext: createAsyncThunk(`${prefix}/fetchContext`, async (_, thunkApi) => {
const useCase = ProposalDataContextRepositoryImplFactory.create(appPlatform)
try {
return await useCase.fetchContext()
} catch (e) {
return thunkApi.rejectWithValue(e)
}
}),
} as const
export const types = getTypesThunkActions(actions)
const login = createSlice({
name: prefix,
initialState,
reducers: {},
extraReducers: {
...values(types).reduce((reducers, type) => ({ ...reducers, ...createAsyncReducers(type) }), {}),
},
})
export default login
import * as selectors from './selectors'
import slice from './slice'
export * from './slice'
export { selectors }
export default slice.reducer
import { State } from './slice'
export const isFetching = (state: State) => state.fetching
import { CreateProposal } from '@agiliza/api/domain'
import {
PDCustomerDataRepositoryImplFactory
} from '@agiliza/api/useCases/proposalData/customerData'
import { appPlatform } from '@agiliza/constants/platform'
import {
createAsyncReducers,
getTypesThunkActions,
values,
WithSuccess
} from '@agiliza/utils/method'
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
const prefix = 'useCases/customerData'
export interface State {
fetching: boolean
}
export const initialState: State = {
fetching: false,
}
export const actions = {
createProposal: createAsyncThunk(`${prefix}/createProposal`, async (input: WithSuccess<CreateProposal['Input']>, thunkApi) => {
const useCase = PDCustomerDataRepositoryImplFactory.create(appPlatform)
try {
const proposalId = await useCase.createProposal(input)
input.onSuccess && input.onSuccess()
return proposalId
} catch (e) {
return thunkApi.rejectWithValue(e)
}
}),
updateIndentification: createAsyncThunk(`${prefix}/updateIndentification`, async (input: WithSuccess<CreateProposal['Input']>, thunkApi) => {
const useCase = PDCustomerDataRepositoryImplFactory.create(appPlatform)
try {
const proposalId = await useCase.createProposal(input)
input.onSuccess && input.onSuccess()
return proposalId
} catch (e) {
return thunkApi.rejectWithValue(e)
}
}),
} as const
export const types = getTypesThunkActions(actions)
const login = createSlice({
name: prefix,
initialState,
reducers: {},
extraReducers: {
...values(types).reduce((reducers, type) => ({ ...reducers, ...createAsyncReducers(type) }), {}),
},
})
export default login
import { combineReducers } from 'redux'
import businessData, {
initialState as businessDataInitialState,
State as BusinessDataState
} from './businessData'
import context, { initialState as contextInitialState, State as ContextState } from './context'
import customerData, {
initialState as customerDataInitialState,
State as CustomerDataState
} from './customerData'
export interface State {
context: ContextState
businessData: BusinessDataState
customerData: CustomerDataState
}
export const initialState: State = {
context: contextInitialState,
businessData: businessDataInitialState,
customerData: customerDataInitialState,
}
export default combineReducers({ context, businessData, customerData })
......@@ -109,6 +109,14 @@ export interface EntityStore<T> {
allIds: string[]
}
export type WithNormalizedEntity<T extends Record<string, any>> = {
[k in keyof T]: T[k] extends Array<any> ? NormalizedEntity<T[k][0]> : unknown
}
export type WithEntityStore<T> = {
[K in keyof T]: T[K] extends Array<any> ? EntityStore<T[K][0]> : unknown
}
export function syncById<T extends Entity, State extends EntityStore<T>>(state: State, entities: NormalizedEntity<T> = {}): NormalizedEntity<T> {
return deepmerge<NormalizedEntity<T>>(state.byId, entities, {
arrayMerge: <Type>(dest: Type[], src: Type[]) => src,
......
......@@ -3,11 +3,7 @@ import React from 'react'
import ItemWithIcon from '@agiliza/components/atoms/ItemWithIcon'
import List from '@material-ui/core/List'
import {
AttachMoney as AttachMoneyIcon,
Description as DescriptionIcon,
ExitToApp
} from '@material-ui/icons'
import { AttachMoney as AttachMoneyIcon, ExitToApp } from '@material-ui/icons'
import withStyles from '@material-ui/styles/withStyles'
import { styles } from './styles'
......@@ -28,7 +24,7 @@ export const PATHS = {
export const drawerListItems: ListItem[] = [
{ label: 'Linhas de Crédito', path: PATHS.creditLines, Icon: AttachMoneyIcon },
{ label: 'Dados da Proposta', path: PATHS.proposalData, Icon: DescriptionIcon },
// { label: 'Dados da Proposta', path: PATHS.proposalData, Icon: DescriptionIcon },
]
export const mapPathToTitle = (path: string) => {
......
import React, { lazy, Suspense, useEffect } from 'react'
import { Redirect, Route, RouteComponentProps, Switch, useLocation } from 'react-router'
import { Redirect, Route, RouteComponentProps, Switch, useHistory } from 'react-router'
import AppBar from '@agiliza/components/molecules/AppBar'
import CircularProgress from '@agiliza/components/molecules/CircularProgress'
import Drawer from '@agiliza/components/molecules/Drawer'
import NotFound from '@agiliza/components/templates/NotFound'
import { actions as drawerActions } from '@agiliza/redux/ui/drawer'
import { actions as loginActions } from '@agiliza/redux/ui/login'
import { ProposalDataRouteState } from '@agiliza/views/ProposalData/pages/ProposalData'
import { Typography } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles'
import connect, { ConnectedProps } from './connect'
import DrawerItems, { mapPathToTitle, PATHS } from './DrawerItems'
import { PATHS } from './DrawerItems'
import styles from './styles'
const SimulationCreditLines = lazy(() => import('@agiliza/views/SimulationCreditLines/pages/router'))
......@@ -24,9 +26,9 @@ interface Props extends BaseProps {
}
const Main = (props: Props) => {
const { classes, drawerOpen, toggleDrawer, logout, fetchMenu, ...routeProps } = props
const { classes, toggleDrawer, fetchMenu } = props
const { pathname } = useLocation()
const history = useHistory()
useEffect(() => {
fetchMenu()
......@@ -34,12 +36,26 @@ const Main = (props: Props) => {
return (
<div className={classes.pageContainer}>
<AppBar onNavClick={toggleDrawer} title={<div className={classes.title}>{mapPathToTitle(pathname)}</div>} />
<Drawer drawerOpen={drawerOpen} toggleDrawer={toggleDrawer} logout={logout} Items={DrawerItems} {...routeProps} />
<AppBar
onNavClick={toggleDrawer}
title={
<a onClick={() => history.push('/')} className={classes.titleAnchor}>
<Typography className={classes.appTitle}>Agiliza</Typography>
</a>
}
/>
{/* <Drawer drawerOpen={drawerOpen} toggleDrawer={toggleDrawer} logout={logout} Items={DrawerItems} {...routeProps} /> */}
<Suspense fallback={<CircularProgress />}>
<Switch>
<Route path={PATHS.creditLines} render={(rProps) => <SimulationCreditLines {...rProps} />} />
<Route path={PATHS.proposalData} render={(rProps) => <ProposalData {...rProps} />} />
<Route
path={PATHS.proposalData}
render={(rProps) => {
const { location } = rProps as RouteComponentProps<any, any, ProposalDataRouteState>
if (location.state?.subproductId) return <ProposalData {...rProps} />
else return <NotFound {...rProps} />
}}
/>
<Redirect from="/" to={PATHS.creditLines} />
</Switch>
</Suspense>
......
......@@ -14,5 +14,7 @@ export default (theme: Theme) => {
paddingBottom: 0,
justifyContent: 'flex-start',
},
appTitle: { flexGrow: 1, fontSize: '100%', textTransform: 'uppercase' },
titleAnchor: { cursor: 'pointer' },
})
}
import React from 'react'
import { withStyles, WithStyles } from '@material-ui/core/styles'
import {
AccountBox as AccountBoxIcon,
CheckBox as CheckBoxIcon,
ContactMail as ContactMailIcon,
DriveEta as DriveEtaIcon,
Forum as ForumIcon,
Home as HomeIcon,
List as ListIcon,
LocalAtm as LocalAtmIcon,
ZoomOutMap as ZoomOutMapIcon
} from '@material-ui/icons'
import Address from './Address'
import Home from './Home'
import Identification from './Identification'
import PersonalData from './PersonalData'
import References from './References'
import SourceIncome from './SourceIncome'
import SpouseAdditionalData from './SpouseAdditionalData'
import SpouseData from './SpouseData'
import styles from './styles'
import Vehicles from './Vehicles'
export const personalDataItems = [
{ label: 'Identificação', icon: <AccountBoxIcon />, component: <Identification /> },
{ label: 'Dados Pessoais', icon: <ListIcon />, component: <PersonalData /> },
{ label: 'Endereço', icon: <ContactMailIcon />, component: <Address /> },
{ label: 'Fonte de renda', icon: <LocalAtmIcon />, component: <SourceIncome /> },
{ label: 'Cônjuge - Ident.', icon: <ForumIcon />, component: <SpouseData /> },
{ label: 'Cônjuge +', icon: <ZoomOutMapIcon />, component: <SpouseAdditionalData /> },
{ label: 'Referências', icon: <CheckBoxIcon />, component: <References /> },
{ label: 'Moradia', icon: <HomeIcon />, component: <Home /> },
{ label: 'Veículos', icon: <DriveEtaIcon />, component: <Vehicles /> },
]
type ExtendedProps = WithStyles<typeof styles>
......@@ -43,8 +11,8 @@ interface Props extends ExtendedProps {
}
const CustomerData = (props: Props) => {
const { classes, activeStep } = props
return <div className={classes.stepContentContainer}>{personalDataItems[activeStep].component}</div>
const { classes } = props
return <div className={classes.stepContentContainer}>{}</div>
}
export default withStyles(styles)(CustomerData)
import React from 'react'
import { frameworks, genders } from '@agiliza/__mocks__/proposalData'
import { BanestesAccount, DataType } from '@agiliza/api/domain'
import { BanestesAccount, DataType, ProposalDataContext } from '@agiliza/api/domain'
import AccountInputsPhoto from '@agiliza/components/templates/AccountInputsPhoto'
import { ActionType } from '@agiliza/utils/hooks/state'
import { maskCPFCNPJ } from '@agiliza/utils/masks'
......@@ -9,28 +8,29 @@ import { SelectField, SelectFieldProps } from '@curio/components'
import { FormControlLabel, Switch, TextField, TextFieldProps } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles'
import { IPIdentificationState } from '../state'
import { CDIdentificationState } from '../state'
import styles from './styles'
type ExtendedProps = WithStyles<typeof styles>
interface Props extends ExtendedProps {
state: IPIdentificationState
actions: ActionType<IPIdentificationState>
state: CDIdentificationState
actions: ActionType<CDIdentificationState>
context: ProposalDataContext
}
const Form = (props: Props) => {
const { classes, state, actions } = props
const { classes, state, actions, context } = props
const { cpfcnpj, dataType, name, gender, hasAccount, account } = state
const handleChangeText =
(key: keyof IPIdentificationState): TextFieldProps['onChange'] =>
(key: keyof CDIdentificationState): TextFieldProps['onChange'] =>
(evt) => {
actions.update({ [key]: evt.target.value })
}
const handleChangeSelect =
(key: keyof IPIdentificationState): SelectFieldProps['onChange'] =>
(key: keyof CDIdentificationState): SelectFieldProps['onChange'] =>
(vl) => {
actions.update({ [key]: vl })
}
......@@ -60,7 +60,7 @@ const Form = (props: Props) => {
label="Enquadramento"
value={dataType?.framework}
onChange={handleChangeDataType('framework')}
items={frameworks.map((fw) => ({ label: fw.name, value: fw.id }))}
items={context.frameworks.map((fw) => ({ label: fw.description, value: fw.id }))}
variant="outlined"
shrink={false}
/>
......@@ -77,7 +77,7 @@ const Form = (props: Props) => {
label="Sexo"
value={gender}
onChange={handleChangeSelect('gender')}
items={genders.map((fw) => ({ label: fw.name, value: fw.id }))}
items={context.genders.map((fw) => ({ label: fw.description, value: fw.id }))}
variant="outlined"
shrink={false}
/>
......
import React from 'react'
import React, { useEffect } from 'react'
import { useFormState } from '@agiliza/utils/hooks/state'
import { ActionType } from '@agiliza/utils/hooks/state'
import { withStyles, WithStyles } from '@material-ui/core/styles'
import { connected, ConnectedProps } from './connect'
import Form from './Form'
import { initialState } from './state'
import { CDIdentificationState } from './state'
import styles from './styles'
type ExtendedProps = WithStyles<typeof styles>
type ExtendedProps = WithStyles<typeof styles> & ConnectedProps
interface Props extends ExtendedProps {}
interface Props extends ExtendedProps {
state: CDIdentificationState
actions: ActionType<any>
}
const Identification = (props: Props) => {
const { classes } = props
const { classes, context, state, actions } = props
const formState = useFormState('identificationForm', initialState)
useEffect(() => {
props.fetchContext()
}, [])
return (
<div className={classes.contentContainer}>
<div className={classes.content}>
<Form {...formState} />
<Form context={context} state={state} actions={actions} />
</div>
</div>
)
}
export default withStyles(styles)(Identification)
export default connected(withStyles(styles)(Identification))
import { connect } from 'react-redux'
import { bindActionCreators, Dispatch } from 'redux'
import { ProposalDataContext } from '@agiliza/api/domain'
import { StoreState } from '@agiliza/redux'
import * as entProposalDataContext from '@agiliza/redux/entities/proposalData/context'
import * as ucProposalDataContext from '@agiliza/redux/useCases/proposalData/context'
import * as ucProposalDataCD from '@agiliza/redux/useCases/proposalData/customerData'
export interface ConnectedProps {
fetching: boolean
context: ProposalDataContext
fetchContext: typeof ucProposalDataContext.actions.fetchContext
updateIndentification: typeof ucProposalDataCD.actions.updateIndentification
}
type StateProps = Pick<ConnectedProps, 'fetching' | 'context'>
type DispatchProps = Pick<ConnectedProps, 'fetchContext' | 'updateIndentification'>
const mapStateToProps = (state: StoreState): StateProps => ({
fetching: ucProposalDataContext.selectors.isFetching(state.ui.login),
context: entProposalDataContext.selectors.getContext(state.entities.proposalData.context),
})
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps =>
bindActionCreators(
{
fetchContext: ucProposalDataContext.actions.fetchContext,
updateIndentification: ucProposalDataCD.actions.updateIndentification,
},
dispatch
)
export const connected = connect(mapStateToProps, mapDispatchToProps)
export { default } from './Identification'
export * from './Identification'
export * from './state'
......@@ -2,11 +2,11 @@ import { InvolvedPerson } from '@agiliza/api/domain'
type ExtendedState = Omit<InvolvedPerson['identification'], 'type'>
export interface IPIdentificationState extends ExtendedState {
export interface CDIdentificationState extends ExtendedState {
hasAccount: boolean
}
export const initialState: IPIdentificationState = {
export const initialState: CDIdentificationState = {
id: '',
name: '',
cpfcnpj: '',
......
import React, { useMemo, useState } from 'react'
import { RouteComponentProps } from 'react-router'
import { PATHS } from '@agiliza/views/Main/DrawerItems'
import { useFormState } from '@agiliza/utils/hooks/state'
import { Button, MobileStepper, Typography } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles'
import {
AccountBox as AccountBoxIcon,
CheckBox as CheckBoxIcon,
ContactMail as ContactMailIcon,
DriveEta as DriveEtaIcon,
Forum as ForumIcon,
Home as HomeIcon,
KeyboardArrowLeft as KeyboardArrowLeftIcon,
KeyboardArrowRight as KeyboardArrowRightIcon
KeyboardArrowRight as KeyboardArrowRightIcon,
List as ListIcon,
LocalAtm as LocalAtmIcon,
ZoomOutMap as ZoomOutMapIcon
} from '@material-ui/icons'
import { businessDataItems } from './BusinessData'
import { personalDataItems } from './CustomerData'
import { connected, ConnectedProps } from './connect'
import Address from './CustomerData/Address'
import Home from './CustomerData/Home'
import Identification, { initialState as cdIdentInitState } from './CustomerData/Identification'
import PersonalData from './CustomerData/PersonalData'
import References from './CustomerData/References'
import SourceIncome from './CustomerData/SourceIncome'
import SpouseAdditionalData from './CustomerData/SpouseAdditionalData'
import SpouseData from './CustomerData/SpouseData'
import Vehicles from './CustomerData/Vehicles'
import styles from './shared-styles'
export const PROPOSAL_DATA_PATHS = {
selectOption: PATHS.proposalData + '/selecionarOpcao',
involvedPeople: PATHS.proposalData + '/pessoasEnvolvidas',
businessData: PATHS.proposalData + '/dadosNegocio',
selectOption: '/selecionarOpcao',
involvedPeople: '/pessoasEnvolvidas',
businessData: '/dadosNegocio',
}
const proposalDataItems = [...personalDataItems, ...businessDataItems]
export interface ProposalDataRouteState {
subproductId: string
}
type ExtendedProps = WithStyles<typeof styles> & RouteComponentProps
type ExtendedProps = WithStyles<typeof styles> & RouteComponentProps & ConnectedProps
interface Props extends ExtendedProps {}
......@@ -29,7 +49,31 @@ const ProposalData = (props: Props) => {
const { classes } = props
const [activeStep, setActiveStep] = useState(0)
const cdIdentification = useFormState('proposalDataState', cdIdentInitState)
const customerDataItems = useMemo(
() => [
{
label: 'Identificação',
icon: <AccountBoxIcon />,
component: <Identification state={cdIdentification.state} actions={cdIdentification.actions} />,
},
{ label: 'Dados Pessoais', icon: <ListIcon />, component: <PersonalData /> },
{ label: 'Endereço', icon: <ContactMailIcon />, component: <Address /> },
{ label: 'Fonte de renda', icon: <LocalAtmIcon />, component: <SourceIncome /> },
{ label: 'Cônjuge - Ident.', icon: <ForumIcon />, component: <SpouseData /> },
{ label: 'Cônjuge +', icon: <ZoomOutMapIcon />, component: <SpouseAdditionalData /> },
{ label: 'Referências', icon: <CheckBoxIcon />, component: <References /> },
{ label: 'Moradia', icon: <HomeIcon />, component: <Home /> },
{ label: 'Veículos', icon: <DriveEtaIcon />, component: <Vehicles /> },
],
[cdIdentification]
)
const proposalDataItems = useMemo(() => [...customerDataItems, ...businessDataItems], [customerDataItems, businessDataItems])
const steps = useMemo(() => proposalDataItems.length, [proposalDataItems])
// const location = useLocation<ProposalDataRouteState>()
const handleNext = () => {
// if (activeStep === steps - 1) history.push({ pathname: PATHS.creditLines })
......@@ -41,7 +85,7 @@ const ProposalData = (props: Props) => {
}
const mapActiveStepToTitle = () => {
if (activeStep < personalDataItems.length) return 'Dados do cliente'
if (activeStep < customerDataItems.length) return 'Dados do cliente'
if (activeStep < proposalDataItems.length) return 'Dados de negócio'
}
......@@ -90,4 +134,4 @@ const ProposalData = (props: Props) => {
)
}
export default withStyles(styles)(ProposalData)
export default connected(withStyles(styles)(ProposalData))
import { connect } from 'react-redux'
import { StoreState } from '@agiliza/redux'
import * as ucProposalDataContext from '@agiliza/redux/useCases/proposalData/context'
export interface ConnectedProps {
fetching: boolean
}
type StateProps = Pick<ConnectedProps, 'fetching'>
// type DispatchProps = Record<string, any>
const mapStateToProps = (state: StoreState): StateProps => ({
fetching: ucProposalDataContext.selectors.isFetching(state.ui.login),
})
// const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => bindActionCreators({}, dispatch)
export const connected = connect(mapStateToProps)
import React, { useEffect, useState } from 'react'
import { RouteComponentProps } from 'react-router'
import { RouteComponentProps, useHistory } from 'react-router'
import { SimulationCategory } from '@agiliza/api/domain'
import { extractCurrency, extractNumbers } from '@agiliza/utils/extractors'
......@@ -17,7 +17,7 @@ import { withStyles, WithStyles } from '@material-ui/core/styles'
import { Refresh as RefreshIcon } from '@material-ui/icons'
import { Autocomplete } from '@material-ui/lab'
import { CREDIT_LINES_PATHS } from '../router'
import { CREDIT_LINES_PATHS, SimulationRouteState } from '../router'
import { connected, ConnectedProps } from './connect'
import SliderField from './SliderField'
import styles from './styles'
......@@ -29,12 +29,14 @@ interface Props extends ExtendedProps {
}
const CreditLinesList = (props: Props) => {
const { classes, fetching, history, match, simulationCategories } = props
const { classes, fetching, match, simulationCategories } = props
useEffect(() => {
props.fetchSimulationCategories()
}, [])
const history = useHistory<SimulationRouteState>()
const [selectedSimulCategory, setSelectedSimulCategory] = useState<SimulationCategory | null>(null)
const [amount, setAmount] = useState('0')
const [paymentMonths, setPaymentMonths] = useState(0)
......@@ -44,13 +46,15 @@ const CreditLinesList = (props: Props) => {
const handleSimulate = () => {
if (selectedSimulCategory)
props.getSubproducts({
idModality: selectedSimulCategory.id,
categoryId: selectedSimulCategory.id,
creditValue: Number(amount),
idGracePeriod: graceMonths.toString(),
gracePeriodId: graceMonths.toString(),
installmentsNumber: paymentMonths,
onSuccess: (subPdcs) => {
if (subPdcs && subPdcs.length > 0) history.push({ pathname: parentPath + CREDIT_LINES_PATHS.simulation })
else props.setErrorMessage('Nenhum subproduto encontrado. Tente novamente com outros valores...')
if (subPdcs && subPdcs.length > 0) {
props.setData({ simulationCategoryId: selectedSimulCategory.id, amount, paymentMonths, graceMonths })
history.push({ pathname: parentPath + CREDIT_LINES_PATHS.simulation, state: { hasSubproducts: true } })
} else props.setErrorMessage('Nenhum subproduto encontrado. Tente novamente com outros valores...')
},
})
}
......@@ -81,7 +85,9 @@ const CreditLinesList = (props: Props) => {
const isValid = React.isValidElement(params.InputProps.endAdornment)
const fetchingEndAdornment = (
<InputAdornment position="end" style={{ flex: '1', display: 'flex', justifyContent: 'flex-end' }}>
<IconButton>
<CircularProgress size={20} />
</IconButton>
</InputAdornment>
)
const validEndAdornment = React.cloneElement(params.InputProps.endAdornment as React.ReactElement, {
......@@ -190,24 +196,24 @@ const CreditLinesList = (props: Props) => {
/>
<SliderField
className={classes.sliderField}
title="Quantos dias de carência?"
title="Quantos meses de carência?"
sliderProps={{
min: 0,
max: selectedSimulCategory?.maxGraceMonths || 12,
marks: selectedSimulCategory
? [
{ value: 0, label: `${0} dias` },
{ value: selectedSimulCategory?.maxGraceMonths, label: `${selectedSimulCategory?.maxGraceMonths} dias` },
{ value: 0, label: `${0} meses` },
{ value: selectedSimulCategory?.maxGraceMonths, label: `${selectedSimulCategory?.maxGraceMonths} meses` },
]
: [
{ value: 0, label: '0 dias' },
{ value: 0, label: '0 meses' },
{ value: 12, label: '' },
],
value: Number(graceMonths),
onChange: (_, value) => setGraceMonths(value as number),
}}
valueField={graceMonths.toString()}
suffix={`dia${graceMonths > 1 ? 's' : ''}`}
suffix={`m${paymentMonths > 1 ? 'e' : 'ê'}s${paymentMonths > 1 ? 'es' : ''}`}
disabled={!selectedSimulCategory}
onChangeField={(evt) => setGraceMonths(Number(extractNumbers(evt.target.value)))}
onBlurField={(evt) => {
......
......@@ -4,6 +4,7 @@ import { SimulationCategory } from '@agiliza/api/domain'
import { StoreState } from '@agiliza/redux'
import * as entSimulationContext from '@agiliza/redux/entities/simulation/context'
import { actions as errorActions } from '@agiliza/redux/ui/error'
import * as uiSimulation from '@agiliza/redux/ui/simulation'
import * as ucSimulation from '@agiliza/redux/useCases/simulation'
import { bindActionCreators, Dispatch } from '@reduxjs/toolkit'
......@@ -13,10 +14,11 @@ export interface ConnectedProps {
fetchSimulationCategories: typeof ucSimulation.actions.fetchSimulationCategories
getSubproducts: typeof ucSimulation.actions.getSubproducts
setErrorMessage: typeof errorActions.setErrorMessage
setData: typeof uiSimulation.actions.setData
}
type StateProps = Pick<ConnectedProps, 'fetching' | 'simulationCategories'>
type DispatchProps = Pick<ConnectedProps, 'fetchSimulationCategories' | 'getSubproducts' | 'setErrorMessage'>
type DispatchProps = Pick<ConnectedProps, 'fetchSimulationCategories' | 'getSubproducts' | 'setErrorMessage' | 'setData'>
const mapStateToProps = (state: StoreState): StateProps => ({
fetching: ucSimulation.selectors.isFetching(state.useCases.simulation),
......@@ -29,6 +31,7 @@ const mapDispatchToProps = (dispatch: Dispatch): DispatchProps =>
fetchSimulationCategories: ucSimulation.actions.fetchSimulationCategories,
getSubproducts: ucSimulation.actions.getSubproducts,
setErrorMessage: errorActions.setErrorMessage,
setData: uiSimulation.actions.setData,
},
dispatch
)
......
import React, { useEffect, useState } from 'react'
import React, { useState } from 'react'
import { SubProduct } from '@agiliza/api/domain'
import { formatCurrency } from '@agiliza/utils/formatters'
......@@ -14,19 +14,16 @@ import styles from './styles'
type ExtendedProps = WithStyles<typeof styles> & ConnectedProps
interface Props extends ExtendedProps {
onChangeCanGoForward: (vl: boolean) => void
subproduct?: SubProduct
onChangeSubproduct: (subprd?: SubProduct) => void
}
const CreditLinesInfo = (props: Props) => {
const { classes, onChangeCanGoForward, subproducts } = props
const { classes, subproducts, subproduct, onChangeSubproduct } = props
const [selectedSP, setSelectedSP] = useState<SubProduct | undefined>()
// const [selectedSP, setSelectedSP] = useState<SubProduct | undefined>()
const [open, setOpen] = useState(false)
useEffect(() => {
onChangeCanGoForward(!!selectedSP)
}, [selectedSP])
return (
<div className={classes.contentContainer}>
<div className={classes.content}>
......@@ -35,24 +32,24 @@ const CreditLinesInfo = (props: Props) => {
className={classes.selectField}
label="Opções de Subproduto"
items={subproducts.map((sp) => ({ label: sp.description || '', value: sp.id }))}
value={selectedSP?.id || ''}
value={subproduct?.id || ''}
onChange={(value) => {
const subprd = subproducts.find((sp) => sp.id === value)
setSelectedSP(subprd)
onChangeSubproduct(subprd)
}}
shrink={false}
/>
<Grid container className={classes.gridContainer}>
<GridLine label="Número de parcelas" value={selectedSP?.maxAmountInstallment || ''} />
{/* <GridLine label="Valor das parcelas" value={formatCurrency(selectedSP?.amount.toFixed(2))} /> */}
<GridLine label="Taxa de juros" value={selectedSP?.fee ? `${selectedSP?.fee} %` : ''} />
<GridLine label="Custo efetivo total (CET)" value={selectedSP?.IOF !== undefined ? `${selectedSP?.IOF} %` : ''} />
<GridLine label="Taxa abertura crédito (TAC)" value={formatCurrency(selectedSP?.TAC?.toFixed(2))} />
<GridLine label="Número de parcelas" value={subproduct?.maxAmountInstallment || ''} />
{/* <GridLine label="Valor das parcelas" value={formatCurrency(subproduct?.amount.toFixed(2))} /> */}
<GridLine label="Taxa de juros" value={subproduct?.fee ? `${subproduct?.fee} %` : ''} />
<GridLine label="Custo efetivo total (CET)" value={subproduct?.IOF !== undefined ? `${subproduct?.IOF} %` : ''} />
<GridLine label="Taxa abertura crédito (TAC)" value={formatCurrency(subproduct?.TAC?.toFixed(2))} />
</Grid>
<Button variant="text" onClick={() => setOpen(true)} disabled={!selectedSP}>
<Button variant="text" onClick={() => setOpen(true)} disabled={!subproduct}>
Exibir opções de parcelamento
</Button>
<InstallmentsDialog open={open} onClose={() => setOpen(false)} installmentOptions={selectedSP?.installementOptions} />
<InstallmentsDialog open={open} onClose={() => setOpen(false)} installmentOptions={subproduct?.installementOptions} />
</div>
</div>
)
......
import React, { useMemo, useState } from 'react'
import { RouteComponentProps } from 'react-router'
import { SubProduct } from '@agiliza/api/domain'
import { extractNumbers } from '@agiliza/utils/method'
import { PATHS } from '@agiliza/views/Main/DrawerItems'
import { Button, Step, StepLabel, Stepper } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles'
......@@ -9,37 +11,51 @@ import {
KeyboardArrowRight as KeyboardArrowRightIcon
} from '@material-ui/icons'
import { connected, ConnectedProps } from './connect'
import CreditLinesInfo from './CreditLinesInfo'
import styles from './styles'
import UserForm from './UserForm'
type ExtendedProps = WithStyles<typeof styles> & RouteComponentProps
type ExtendedProps = WithStyles<typeof styles> & RouteComponentProps & ConnectedProps
interface Props extends ExtendedProps {}
const Simulation = (props: Props) => {
const { classes, ...routerProps } = props
const { classes, customer, simulationData, ...routerProps } = props
const { history } = routerProps
// const theme = useTheme()
const [activeStep, setActiveStep] = useState(0)
const [canGoForward, setCanGoForward] = useState(true)
// const [canGoForward, setCanGoForward] = useState(true)
const handleChangeCanGoForward = (value: boolean) => {
setCanGoForward(value)
const [subproduct, setSubproduct] = useState<SubProduct | undefined>()
const handleChangeSubproduct = (sp?: SubProduct) => {
setSubproduct(sp)
}
const renderStep = (step: number) => {
switch (step) {
case 0:
return <CreditLinesInfo onChangeCanGoForward={handleChangeCanGoForward} />
return <CreditLinesInfo subproduct={subproduct} onChangeSubproduct={handleChangeSubproduct} />
case 1:
return <UserForm onChangeCanGoForward={handleChangeCanGoForward} />
return <UserForm />
}
}
const handleNext = () => {
if (activeStep === steps - 1) history.push({ pathname: PATHS.creditLines })
else setActiveStep((prevActiveStep) => prevActiveStep + 1)
if (activeStep === steps - 1) {
if (simulationData && subproduct) {
const { simulationCategoryId, amount, graceMonths, paymentMonths } = simulationData
props.createProposal({
categoryId: simulationCategoryId,
creditValue: Number(extractNumbers(amount)),
gracePeriodId: graceMonths,
installmentsNumber: paymentMonths,
subproductId: subproduct.id,
onSuccess: () => history.push({ pathname: PATHS.proposalData, state: { subproductId: subproduct?.id } }),
})
}
} else setActiveStep((prevActiveStep) => prevActiveStep + 1)
}
const handleBack = () => {
......@@ -48,6 +64,15 @@ const Simulation = (props: Props) => {
const steps = useMemo(() => 2, [])
const canGoForward = useMemo(() => {
switch (activeStep) {
case 0:
return !!subproduct
case 1:
return !!customer
}
}, [activeStep, subproduct, customer])
return (
<div className={classes.pageContent}>
<div className={classes.stepContentContainer}>{renderStep(activeStep)}</div>
......@@ -98,4 +123,4 @@ const Simulation = (props: Props) => {
)
}
export default withStyles(styles)(Simulation)
export default connected(withStyles(styles)(Simulation))
import React, { useEffect, useState } from 'react'
import React, { useState } from 'react'
import ButtonWithProgress from '@agiliza/components/atoms/ButtonWithProgress'
import LoginTemplate from '@agiliza/components/templates/Login'
......@@ -27,22 +27,16 @@ interface State {
type ExtendedProps = WithStyles<typeof styles> & ConnectedProps
interface Props extends ExtendedProps {
onChangeCanGoForward: (vl: boolean) => void
}
interface Props extends ExtendedProps {}
const UserForm = (props: Props) => {
const { classes, fetching, onChangeCanGoForward, customer } = props
const { classes, fetching, customer } = props
const [state, setState] = useState<State>({ username: '', password: '' })
const { username, password } = state
const [open, setOpen] = useState(false)
// const { errorState, validState: isValidState, actions } = useErrorValidator({ username: '', password: '' })
useEffect(() => {
onChangeCanGoForward(false)
}, [])
// useEffect(() => {
// onChangeCanGoForward(isValidState)
// }, [isValidState])
......@@ -68,9 +62,6 @@ const UserForm = (props: Props) => {
props.login({
username: extractNumbers(username),
password,
onSuccess: () => {
onChangeCanGoForward(true)
},
})
}
>
......
import { connect } from 'react-redux'
import { bindActionCreators, Dispatch } from 'redux'
import { Customer } from '@agiliza/api/domain'
import { StoreState } from '@agiliza/redux'
import * as session from '@agiliza/redux/session'
import * as uiSimulation from '@agiliza/redux/ui/simulation'
import * as ucProposalDataCD from '@agiliza/redux/useCases/proposalData/customerData'
export interface ConnectedProps {
customer?: Customer
simulationData: uiSimulation.State['data']
createProposal: typeof ucProposalDataCD.actions.createProposal
}
type StateProps = Pick<ConnectedProps, 'customer' | 'simulationData'>
type DispatchProps = Pick<ConnectedProps, 'createProposal'>
const mapStateToProps = (state: StoreState): StateProps => ({
customer: session.selectors.getCustomer(state.session),
simulationData: uiSimulation.selectors.getData(state.ui.simulation),
})
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps =>
bindActionCreators(
{
createProposal: ucProposalDataCD.actions.createProposal,
},
dispatch
)
export const connected = connect(mapStateToProps, mapDispatchToProps)
......@@ -14,6 +14,10 @@ export const CREDIT_LINES_PATHS = {
simulation: '/simulador',
}
export interface SimulationRouteState {
hasSubproducts: boolean
}
type ExtendedProps = WithStyles<typeof styles> & RouteComponentProps
interface Props extends ExtendedProps {}
......@@ -29,10 +33,9 @@ const CreditLinesRouter = (props: Props) => {
exact
path={match.path + CREDIT_LINES_PATHS.simulation}
render={(rProps) => {
return <Simulation {...rProps} />
// const { location } = rProps as RouteComponentProps<any, any, { id: string }>
// if (location.state?.id) return <Simulation {...rProps} />
// else return <NotFound {...rProps} />
const { location } = rProps as RouteComponentProps<any, any, SimulationRouteState>
if (location.state?.hasSubproducts) return <Simulation {...rProps} />
else return <Redirect from={match.path + CREDIT_LINES_PATHS.simulation} to="/" />
}}
/>
<Redirect from={match.path} to={match.path + CREDIT_LINES_PATHS.creditLinesList} />
......
......@@ -4,7 +4,6 @@ import { connect } from 'react-redux'
import { Route, Router, Switch } from 'react-router'
import { bindActionCreators, Dispatch } from 'redux'
import AuthRoute from '@agiliza/components/atoms/AuthRoute'
import CircularProgress from '@agiliza/components/molecules/CircularProgress'
import { StoreState } from '@agiliza/redux'
import { isAuthenticated, isAuthenticating, isInitializing } from '@agiliza/redux/session/selectors'
......@@ -13,7 +12,6 @@ import { isDrawerOpen } from '@agiliza/redux/ui/drawer/selectors'
import { getError } from '@agiliza/redux/ui/error/selectors'
import { actions as loginActions } from '@agiliza/redux/ui/login'
const Login = lazy(() => import('./Login'))
const Main = lazy(() => import('./Main'))
const history = createHashHistory()
......@@ -38,8 +36,9 @@ const Views = (props: Props) => {
<Router history={history}>
<Suspense fallback={<CircularProgress />}>
<Switch>
<Route path="/login" render={(renderProps) => <Login {...renderProps} />} />
<AuthRoute path="/" component={Main} />
{/* <Route path="/login" render={(renderProps) => <Login {...renderProps} />} /> */}
<Route path="/" component={Main} />
{/* <AuthRoute path="/" component={Main} /> */}
</Switch>
</Suspense>
</Router>
......
......@@ -1264,10 +1264,10 @@
prop-types "^15.7.2"
react-is "^16.8.0 || ^17.0.0"
"@microcredito/client@^0.7.11":
version "0.7.11"
resolved "https://nexus.dev.evologica.com.br/repository/npm/@microcredito/client/-/client-0.7.11.tgz#6601c681c6452c71d18e82f9ddca8bddeedf44a7"
integrity sha1-ZgHGgcZFLHHRjoL53cqL3e7fRKc=
"@microcredito/client@^0.7.13":
version "0.7.13"
resolved "https://nexus.dev.evologica.com.br/repository/npm/@microcredito/client/-/client-0.7.13.tgz#ab47d224d9e5a373df69375afd086d6db7dee77b"
integrity sha1-q0fSJNnlo3PfaTda/Qhtbbfe53s=
"@nodelib/fs.scandir@2.1.4":
version "2.1.4"
......
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