Commit 3085eedb authored by Rafael's avatar Rafael

Adiciona submissão de projetos no portal agente

parent ebdde345
--registry "https://nexus.dev.evologica.com.br/repository/npm"
--registry "https://nexus.dev.evologica.com.br/repository/npm-internal"
"@curio:registry" "https://nexus.dev.evologica.com.br/repository/npm"
"@dynamo:registry" "https://nexus.dev.evologica.com.br/repository/npm"
\ No newline at end of file
{
"service": {
"url": "https://mdk.dev.evologica.com.br/cxClient/cxIsapiClient.dll/gatewayJSON?version=4",
"server": "srvp4",
"system": 19,
"port": 7901,
"module": 1,
"version": 3
},
"accessToken": "ab4dfc4ab84517f900193f8a2530680c73ad3539f75e1f5661bee7065cfcdd32",
"resources": {
"get": "https://mdk.dev.evologica.com.br/cxClient/cxIsapiClient.dll/getpr",
"put": "https://mdk.dev.evologica.com.br/cxClient/cxIsapiClient.dll/putpr"
},
"logs": true
"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": "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"
}
{
"service": {
"url": "https://mdk.evologica.com.br/cxClient/cxIsapiClient.dll/gatewayJSONBalanced?version=4",
"server": "mdk.evologica.com.br",
"system": 94,
"port": 7902
},
"accessToken": "ed296c1d9dc3d3eb41a29077bd715278cc985849e0df51da0c2653996055d19f",
"resources": {
"get": "https://mdk.dev.evologica.com.br/cxClient/cxIsapiClient.dll/getpr",
"put": "https://mdk.dev.evologica.com.br/cxClient/cxIsapiClient.dll/putpr"
},
"logs": true
"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"
}
{
"service": {
"url": "https://mdk.dev.evologica.com.br/cxClient/cxIsapiClient.dll/gatewayJSON?version=4",
"server": "srvp4",
"system": 94,
"port": 7901
},
"accessToken": "ab4dfc4ab84517f900193f8a2530680c73ad3539f75e1f5661bee7065cfcdd32",
"resources": {
"get": "https://mdk.dev.evologica.com.br/cxClient/cxIsapiClient.dll/getpr",
"put": "https://mdk.dev.evologica.com.br/cxClient/cxIsapiClient.dll/putpr"
},
"logs": true
"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"
}
......@@ -81,6 +81,7 @@
"dependencies": {
"@curio/client": "1.3.3",
"@curio/ui": "^0.1.0",
"@curio/components": "^0.1.6",
"@date-io/date-fns": "^1.0.0",
"@dynamo/components": "0.70.1",
"@dynamo/curio": "0.70.1",
......@@ -89,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.18",
"@microcredito/client": "^0.7.22",
"@reduxjs/toolkit": "^1.2.5",
"@xstate/react": "^1.3.3",
"babel-plugin-import": "^1.13.0",
......
{
"service": {
"url": "https://mdk.dev.evologica.com.br/cxClient/cxIsapiClient.dll/gatewayJSON?version=4",
"server": "srvp4",
"system": 19,
"port": 7901,
"module": 1,
"version": 3
},
"accessToken": "ab4dfc4ab84517f900193f8a2530680c73ad3539f75e1f5661bee7065cfcdd32",
"resources": {
"get": "https://mdk.dev.evologica.com.br/cxClient/cxIsapiClient.dll/getpr",
"put": "https://mdk.dev.evologica.com.br/cxClient/cxIsapiClient.dll/putpr"
},
"logs": true
"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"
}
\ No newline at end of file
import { Entity } from '@agiliza/utils/method'
import { Customer } from '../'
import { User } from '../'
export interface City extends Entity {
name: string
......@@ -48,7 +48,7 @@ interface InputCreateCustomer {
}
interface OutputCreateCustomer {
customer: Customer
customer: User
}
export interface CreateCustomer {
......@@ -89,5 +89,5 @@ export interface CreatePassword {
export interface GetLoggedCustomer {
Input: void
Output: Customer
Output: User
}
......@@ -5,8 +5,10 @@ export * from './context'
export * from './error'
export * from './simulation'
export * from './authentication'
export * from './user'
export * from './project'
export interface Customer {
export interface User {
name: string
email: string
ownerName?: string
......@@ -31,10 +33,3 @@ export interface CodigoDescricao {
export interface DocumentType extends Entity {
description: string
}
export interface Document {
id: string
type: DocumentType
extraInformations: string
url: string
}
import { ProjectStatus } from './'
export interface ProjectContext {
statuses: ProjectStatus[]
}
export interface GetProjectContext {
Input: void
Output: ProjectContext
}
import { Entity } from '@agiliza/utils/method'
import type { InvolvedPerson, BusinessData } from './projectElaboration'
import type { Schedule } from './schedule'
import type { UserCustomer } from './user'
export * from './context'
export interface Project extends Entity {
status: ProjectStatus
events: string[]
documents?: Document[]
processNumber: string
permissions?: ProjectPermissions
schedules: Schedule[]
// customer: UserCustomer
// involvedPeople?: InvolvedPerson[]
// businessData?: BusinessData
}
export interface ProjectStatus extends Entity {
description: string
operations?: Operation[]
}
export interface Operation extends Entity {
description: string
descriptionTransition: string
permission: 'customer' | 'broker'
}
export interface ProjectPermissions {
requestCancel?: boolean
}
export interface Document {
id: string
type: DocumentType
extraInformations: string
url: string
}
export interface DocumentType extends Entity {
description: string
}
export interface FetchDocumentsArg {
projectId: string
visitId?: string
}
interface InputGetProjects {
beginDate: Date | null
endDate: Date | null
statuses?: number[]
}
export interface GetProjects {
Input: InputGetProjects
Output: Project[]
}
interface InputSubmitProjects {
ids: string[]
}
export interface SubmitProjects {
Input: InputSubmitProjects
Output: void
}
import { Document } from '../../../domain/project'
export interface StockSalesCosts {
document: Document
document?: Document
monthYearReference: string
salesCommission: string
monthRating: string
......
import { Entity } from '@agiliza/utils/method'
import { Document } from './project'
import { Address } from './user'
export interface Schedule extends Entity {
status: ScheduleStatus
events: string[]
documents?: Document[]
number: string
date: Date
permissions?: SchedulePermissions
requestReschedule?: RequestReschedule
requestCancel?: RequestCancel
}
interface RequestReschedule {
idReason: string
justification: string
date: Date | null
}
interface RequestCancel {
idReason: string
justification: string
}
export interface CreditInformation {
creditValue: string
creditObjective: string
creditInstallment: string
creditGracePeriod: string
}
export interface ScheduleTime {
dateTime: Date // must be converted to ISO string
documentFront: string //Base64 data
documentBack: string //Base 64 data
}
export interface ScheduleVisit {
address: Address
creditInformation: CreditInformation
scheduleTime: ScheduleTime
}
export interface SchedulePermissions {
requestCancel?: boolean
requestReschedule?: boolean
confirmReschedule?: boolean
}
export interface ScheduleStatus extends Entity {
description: string
operations: Operation[]
}
interface Operation {
id: string
description: string
descriptionTransition: string
permission: 'customer' | 'broker'
}
export interface RequestCancelSchedule {
idSchedule: string
idReason: string
explanationDescription: string
}
export interface RequestRescheduleInfo {
idSchedule: string
idReason: string
description?: string
date: Date
}
export interface FetchDocumentsArg {
projectId: string
visitId?: string
}
export interface PermissionResponse {
permission: boolean
projectId?: string
visitId?: string
}
export interface Broker {
name: string
cpf: string
email: string
phone: string
operatingCity: string
profilePicture: string
}
import * as AuthenticationApiMappers from './authentication'
import * as ProjectApiMappers from './project'
import * as ProposalDataApiMappers from './proposalData'
import * as SessionApiAdapters from './session'
import * as SimulationApiMappers from './simulation'
export { SessionApiAdapters, SimulationApiMappers, AuthenticationApiMappers, ProposalDataApiMappers }
export { SessionApiAdapters, SimulationApiMappers, AuthenticationApiMappers, ProposalDataApiMappers, ProjectApiMappers }
import { GetProjects } from '@agiliza/api/domain'
import { BuscarProjetosRequest } from '@microcredito/client/dist/apis/AgenteApi'
import { ApiAdapter } from '../shared'
export class GetProjectsApiMapper implements ApiAdapter<GetProjects['Input'], BuscarProjetosRequest> {
public mapDomainToApiModel = (input: GetProjects['Input']): BuscarProjetosRequest => ({
obterProjetosRequestApiModel: {
filtros: {
dataInicio: input.beginDate || undefined,
dataFim: input.endDate || undefined,
codigosFases: input.statuses?.length ? input.statuses : undefined,
},
},
})
}
......@@ -13,7 +13,7 @@ export class LoginApiAdapter implements ApiAdapter<LoginParams, ClienteApiModels
loginRequestApiModel: {
login: params.username,
senha: params.password,
agente: false,
agente: true,
},
}
return result
......
import { Broker } from '@agiliza/api/domain'
import { UsuarioApiModel } from '@microcredito/client'
import { DomainAdapter } from './shared'
export class BrokerMapper implements DomainAdapter<UsuarioApiModel, Broker> {
public mapApiModelToDomain = ({ usuarioAgente }: UsuarioApiModel): Broker => ({
cpf: usuarioAgente?.cpf || '',
operatingCity: usuarioAgente?.municipioDeAtuacao || '',
profilePicture: usuarioAgente?.fotoPerfil || '',
name: usuarioAgente?.nome || '',
phone: usuarioAgente?.celular || '',
email: usuarioAgente?.email || '',
})
}
import { Customer } from '@agiliza/api/domain'
import { UsuarioApiModel } from '@microcredito/client'
import { DomainAdapter } from './shared'
export class CustomerMapper implements DomainAdapter<UsuarioApiModel, Customer> {
public mapApiModelToDomain = ({ usuarioCliente }: UsuarioApiModel): Customer => ({
profilePicture: usuarioCliente?.fotoPerfil,
cpfcnpj: usuarioCliente?.cpfcnpj || '',
name: usuarioCliente?.nome || '',
phone: usuarioCliente?.celular || '',
ownerCPF: usuarioCliente?.cpfResponsavel,
ownerName: usuarioCliente?.nomeResponsavel,
address: usuarioCliente?.endereco
? {
additionalInfo: usuarioCliente?.endereco.complemento,
cep: usuarioCliente?.endereco.cep,
city: usuarioCliente?.endereco.municipio,
state: usuarioCliente?.endereco.estado,
district: usuarioCliente?.endereco.bairro,
number: usuarioCliente?.endereco.numero,
street: usuarioCliente?.endereco.logradouro,
id: usuarioCliente?.endereco.id,
}
: undefined,
email: usuarioCliente?.email || '',
})
}
import * as AuthenticationMappers from './authentication'
import * as BrokerMappers from './broker'
import * as ContextMappers from './context'
import * as CustomerMappers from './customer'
import * as ErrorMappers from './error'
import * as ProjectMappers from './project'
import * as ProposalDataMappers from './proposalData'
import * as SessionAdapters from './session'
import * as SimulationMappers from './simulation'
export { ContextMappers, ErrorMappers, SessionAdapters, SimulationMappers, AuthenticationMappers, CustomerMappers, ProposalDataMappers }
export {
ContextMappers,
ErrorMappers,
SessionAdapters,
SimulationMappers,
AuthenticationMappers,
BrokerMappers as UserMappers,
ProposalDataMappers,
ProjectMappers,
}
export * from './shared'
import { GetProjectContext, ProjectStatus } from '@agiliza/api/domain'
import { ProjetoSituacaoApiModel } from '@microcredito/client'
import { DomainAdapter } from '../shared'
export interface ContextoProjeto {
situacoes: ProjetoSituacaoApiModel[]
}
export class ProjectContextStatusMapper implements DomainAdapter<ProjetoSituacaoApiModel, ProjectStatus> {
public mapApiModelToDomain = (situacao: ProjetoSituacaoApiModel): ProjectStatus => ({
id: situacao.codigo,
description: situacao.descricao,
})
}
export class GetProjectContextMapper implements DomainAdapter<ContextoProjeto, GetProjectContext['Output']> {
private statusesMapper: ProjectContextStatusMapper
constructor() {
this.statusesMapper = new ProjectContextStatusMapper()
}
public mapApiModelToDomain = (input: ContextoProjeto): GetProjectContext['Output'] => ({
statuses: input.situacoes.map(this.statusesMapper.mapApiModelToDomain),
})
}
export * from './context'
export * from './projects'
import { Document, Project, ProjectStatus } from '@agiliza/api/domain'
import { Schedule } from '@agiliza/api/domain/schedule'
import {
DocumentoApiModel,
ProjetoAgenteApiModel,
ProjetoSituacaoApiModel
} from '@microcredito/client'
import { DomainAdapter } from '../'
import { ScheduleMapper } from '../schedule'
export class ProjectMapper implements DomainAdapter<ProjetoAgenteApiModel, Project> {
private statusAdapter: ProjectStatusMapper
private scheduleAdapter: ScheduleMapper
private documentAdapter: ProjectDocumentMapper
constructor() {
this.scheduleAdapter = new ScheduleMapper()
this.statusAdapter = new ProjectStatusMapper()
this.documentAdapter = new ProjectDocumentMapper()
}
public mapApiModelToDomain = (apimodel: ProjetoAgenteApiModel) => {
const result: Project = {
processNumber: apimodel.numeroProcesso,
events: apimodel.eventos ?? [],
id: apimodel.id,
status: this.statusAdapter.mapApiModelToDomain(apimodel.situacao),
schedules: apimodel.agendamentos?.map(this.scheduleAdapter.mapApiModelToDomain) || ([] as Schedule[]),
documents: apimodel.documentos.map(this.documentAdapter.mapApiModelToDomain),
}
return result
}
}
export class ProjectStatusMapper implements DomainAdapter<ProjetoSituacaoApiModel, ProjectStatus> {
public mapApiModelToDomain = (apimodel: ProjetoSituacaoApiModel) => {
const result: ProjectStatus = {
id: apimodel.codigo,
description: apimodel.descricao,
}
return result
}
}
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 || '',
})
}
import { Schedule, ScheduleStatus } from '@agiliza/api/domain/schedule'
import {
AgendamentoVisitaClienteApiModel,
AgendamentoVisitaClienteCompletoApiModel,
AgendamentoVisitaSituacaoApiModel,
AgendamentoVisitaSituacaoCompletoApiModel
} from '@microcredito/client'
import { DomainAdapter } from '../domain'
import { ProjectDocumentMapper } from './project/projects'
export class ScheduleMapper implements DomainAdapter<AgendamentoVisitaClienteApiModel, Schedule> {
private statusAdapter: ScheduleStatusMapper
private documentAdapter: ProjectDocumentMapper
constructor() {
this.statusAdapter = new ScheduleStatusMapper()
this.documentAdapter = new ProjectDocumentMapper()
}
private mapSolicitacaoReagendamentoToDomain = (
sR: AgendamentoVisitaClienteCompletoApiModel['solicitacaoReagendamento']
): Schedule['requestReschedule'] => ({
date: sR?.dataReagendamento || null,
idReason: sR?.codigoMotivo || '',
justification: sR?.justificativa || '',
})
private mapSolicitacaoCancelamentoToDomain = (
sC: AgendamentoVisitaClienteCompletoApiModel['solicitacaoCancelamento']
): Schedule['requestCancel'] => ({ idReason: sC?.codigoMotivo || '', justification: sC?.justificativa || '' })
public mapApiModelToDomain = (apimodel: AgendamentoVisitaClienteCompletoApiModel) => {
const result: Schedule = {
date: new Date(apimodel.data),
events: apimodel.eventos ?? [],
id: apimodel.id,
number: apimodel.numero,
status: this.statusAdapter.mapApiModelToDomain(apimodel.situacao),
documents: apimodel.documentos?.map(this.documentAdapter.mapApiModelToDomain),
requestReschedule: apimodel.solicitacaoReagendamento && this.mapSolicitacaoReagendamentoToDomain(apimodel.solicitacaoReagendamento),
requestCancel: apimodel.solicitacaoCancelamento && this.mapSolicitacaoCancelamentoToDomain(apimodel.solicitacaoCancelamento),
}
return result
}
}
export class ScheduleStatusMapper implements DomainAdapter<AgendamentoVisitaSituacaoApiModel, ScheduleStatus> {
public mapOperacaoToDomain = (operacao: AgendamentoVisitaSituacaoCompletoApiModel['operacoes'][0]): Schedule['status']['operations'][0] => ({
id: operacao.codigo,
description: operacao.descricao,
descriptionTransition: operacao.descricaoTransicao,
permission: operacao.permissao === 'cliente' ? 'customer' : 'broker',
})
public mapSituacaoToDomain = (situacao: AgendamentoVisitaSituacaoCompletoApiModel): Schedule['status'] => ({
id: situacao.codigo,
description: situacao.descricao,
operations: situacao.operacoes.map(this.mapOperacaoToDomain),
})
public mapApiModelToDomain = (apimodel: AgendamentoVisitaSituacaoCompletoApiModel) => {
const result: ScheduleStatus = {
id: apimodel.codigo,
description: apimodel.descricao,
operations: apimodel.operacoes.filter((op) => op.permissao === 'cliente').map(this.mapOperacaoToDomain),
}
return result
}
}
import {
CreateCustomer,
CreatePassword,
GetContext,
GetLoggedCustomer,
SendCode,
VerifyCode,
VerifyCPF
} from '@agiliza/api/domain'
import { extractNumbers } from '@agiliza/utils/extractors'
import { ClienteApi, Configuration, DominioApi } from '@microcredito/client'
import {
AuthenticationApiMappers,
AuthenticationMappers,
CustomerMappers,
ErrorMappers
} from '../mappers'
import { API_URL, mapUserAgentToString, UserAgent } from './shared'
export interface AuthenticationRepository {
getContext(): Promise<GetContext['Output']>
verifyCPF(input: VerifyCPF['Input']): Promise<VerifyCPF['Output']>
createCustomer(input: CreateCustomer['Input']): Promise<CreateCustomer['Output']>
sendCode(input: SendCode['Input']): Promise<SendCode['Output']>
verifyCode(input: VerifyCode['Input']): Promise<VerifyCode['Output']>
createPassword(input: CreatePassword['Input']): Promise<CreatePassword['Output']>
getLoggedCustomer(): Promise<GetLoggedCustomer['Output']>
}
export class AuthenticationRepositoryImpl implements AuthenticationRepository {
private api: DominioApi
private clienteApi: ClienteApi
private errorAdapter: ErrorMappers.ResponseErrorAdapter
private stateMapper: AuthenticationMappers.StateMapper
private cityMapper: AuthenticationMappers.CityMapper
private customerMapper: CustomerMappers.CustomerMapper
private authenticationApiMapper: AuthenticationApiMappers.CreateCustomerApiMapper
constructor(userAgent: string) {
this.errorAdapter = new ErrorMappers.ResponseErrorAdapter()
this.stateMapper = new AuthenticationMappers.StateMapper()
this.cityMapper = new AuthenticationMappers.CityMapper()
this.customerMapper = new CustomerMappers.CustomerMapper()
this.authenticationApiMapper = new AuthenticationApiMappers.CreateCustomerApiMapper()
this.api = new DominioApi(
new Configuration({
basePath: API_URL,
headers: {
'User-Agent': userAgent,
},
})
)
this.clienteApi = new ClienteApi(
new Configuration({
basePath: API_URL,
headers: {
'User-Agent': userAgent,
},
})
)
}
public getContext = async (): Promise<GetContext['Output']> => {
try {
const estados = await this.api.obterEstados()
const cidades = await this.api.obterMunicipios()
return { states: estados.map(this.stateMapper.mapApiModelToDomain), cities: cidades.map(this.cityMapper.mapApiModelToDomain) }
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
public verifyCPF = async (input: VerifyCPF['Input']): Promise<VerifyCPF['Output']> => {
try {
await this.clienteApi.iniciarPrimeiroAcessoCliente({ iniciarPrimeiroAcessoRequestApiModel: { cpfcnpj: extractNumbers(input.cpf) } })
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
public createCustomer = async (input: CreateCustomer['Input']): Promise<CreateCustomer['Output']> => {
try {
const cliente = await this.clienteApi.criarUsuarioPrimeiroAcesso(this.authenticationApiMapper.mapDomainToApiModel(input))
return { customer: this.customerMapper.mapApiModelToDomain(cliente) }
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
public sendCode = async (input: SendCode['Input']): Promise<SendCode['Output']> => {
try {
await this.clienteApi.enviarCodigoPrimeiroAcessoCliente({
enviarCodigoPrimeiroAcessoRequestApiModel: { cpfcnpj: extractNumbers(input.cpf), email: input.email },
})
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
public verifyCode = async (input: VerifyCode['Input']): Promise<VerifyCode['Output']> => {
try {
await this.clienteApi.validarCodigoPrimeiroAcessoCliente({
validarCodigoPrimeiroAcessoRequestApiModel: { cpfcnpj: extractNumbers(input.cpf), codigo: extractNumbers(input.code) },
})
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
public createPassword = async (input: CreatePassword['Input']): Promise<CreatePassword['Output']> => {
try {
await this.clienteApi.definirSenhaPrimeiroAcessoCliente({
definirSenhaPrimeiroAcessoRequestApiModel: { cpfcnpj: extractNumbers(input.cpf), codigo: extractNumbers(input.code), senha: input.password },
})
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
public getLoggedCustomer = async (): Promise<GetLoggedCustomer['Output']> => {
try {
const usuario = await this.clienteApi.obterUsuarioLogado()
return this.customerMapper.mapApiModelToDomain(usuario)
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
}
export class AuthenticationRepositoryImplFactory {
static create(userAgent: UserAgent) {
const repository = new AuthenticationRepositoryImpl(mapUserAgentToString(userAgent))
return repository
}
}
export * from './session'
export * from './authentication'
export * from './project'
import { GetProjectContext, GetProjects, SubmitProjects } from '@agiliza/api/domain'
import { AgenteApi, Configuration } from '@microcredito/client'
import { ErrorMappers, ProjectMappers } from '../mappers'
import { ProjectApiMappers } from '../mappers/api'
import { ContextoProjeto } from '../mappers/domain/project'
import { API_URL, mapUserAgentToString, SESSION_KEY, UserAgent } from './shared'
export interface ProjectRepository {
getContext(): Promise<GetProjectContext['Output']>
getProjects(input: GetProjects['Input']): Promise<GetProjects['Output']>
submitProjects(input: SubmitProjects['Input']): Promise<SubmitProjects['Output']>
}
export class ProjectRepositoryImpl implements ProjectRepository {
private api: AgenteApi
private errorAdapter: ErrorMappers.ResponseErrorAdapter
private projectStatusMapper: ProjectMappers.GetProjectContextMapper
private getProjectApiMapper: ProjectApiMappers.GetProjectsApiMapper
private projectMapper: ProjectMappers.ProjectMapper
constructor(userAgent: string, accessToken: string) {
this.errorAdapter = new ErrorMappers.ResponseErrorAdapter()
this.projectStatusMapper = new ProjectMappers.GetProjectContextMapper()
this.projectMapper = new ProjectMappers.ProjectMapper()
this.getProjectApiMapper = new ProjectApiMappers.GetProjectsApiMapper()
this.projectMapper = new ProjectMappers.ProjectMapper()
this.api = new AgenteApi(
new Configuration({
basePath: API_URL,
accessToken,
headers: {
'User-Agent': userAgent,
},
})
)
}
public getContext = async (): Promise<GetProjectContext['Output']> => {
try {
const contexto: ContextoProjeto = { situacoes: await this.api.obterSituacoesProjeto() }
return this.projectStatusMapper.mapApiModelToDomain(contexto)
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
public getProjects = async (input: GetProjects['Input']): Promise<GetProjects['Output']> => {
try {
const response = await this.api.buscarProjetos(this.getProjectApiMapper.mapDomainToApiModel(input))
return response.map(this.projectMapper.mapApiModelToDomain)
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
public submitProjects = async (input: SubmitProjects['Input']): Promise<SubmitProjects['Output']> => {
try {
await this.api.submeterProjetos({ submeterProjetosRequestApiModel: { ids: input.ids } })
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
}
export class ProjectRepositoryImplFactory {
static create(userAgent: UserAgent) {
const accessToken = localStorage.getItem(SESSION_KEY) || ''
const repository = new ProjectRepositoryImpl(mapUserAgentToString(userAgent), accessToken)
return repository
}
}
import { extractNumbers } from '@agiliza/utils/extractors'
import { ClienteApi, Configuration } from '@microcredito/client'
import { AgenteApi, Configuration } from '@microcredito/client'
import { Customer } from '../domain'
import { CustomerMappers, SessionAdapters, SessionApiAdapters as Adapters } from '../mappers'
import { Broker } from '../domain'
import { SessionAdapters, SessionApiAdapters as Adapters, UserMappers } from '../mappers'
import { API_URL, mapUserAgentToString, SESSION_KEY, UserAgent } from './shared'
export interface SessionRepository {
login(username: string, password: string): Promise<Customer>
login(username: string, password: string): Promise<void>
logout(): void
connect(): void
connect(): Promise<Broker>
}
export class SessionRepositoryImpl implements SessionRepository {
private customer: string
private api: ClienteApi
private api: AgenteApi
private userAgent: string
private loginApiAdapter: Adapters.LoginApiAdapter
private errorAdapter: SessionAdapters.LoginErrorAdapter
private customerMapper: CustomerMappers.CustomerMapper
private userMapper: UserMappers.BrokerMapper
constructor(userAgent: string) {
this.customer = userAgent
this.errorAdapter = new SessionAdapters.LoginErrorAdapter()
this.loginApiAdapter = new Adapters.LoginApiAdapter()
this.customerMapper = new CustomerMappers.CustomerMapper()
this.api = new ClienteApi(
this.userMapper = new UserMappers.BrokerMapper()
this.userAgent = userAgent
this.api = new AgenteApi(
new Configuration({
basePath: API_URL,
headers: {
......@@ -37,37 +37,53 @@ export class SessionRepositoryImpl implements SessionRepository {
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(
// const clienteApi = new ClienteApi(
// new Configuration({
// basePath: API_URL,
// accessToken: accessToken.token,
// headers: {
// 'User-Agent': this.customer,
// },
// })
// )
// const cliente = await clienteApi.obterUsuarioLogado()
// return this.customerMapper.mapApiModelToDomain(cliente)
} catch (e) {
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
public logout = () => {
localStorage.removeItem(SESSION_KEY)
}
public connect = async () => {
const accessToken = localStorage.getItem(SESSION_KEY)
if (accessToken) {
const api = new AgenteApi(
new Configuration({
basePath: API_URL,
accessToken: accessToken.token,
accessToken,
headers: {
'User-Agent': this.customer,
'User-Agent': this.userAgent,
},
})
)
const cliente = await clienteApi.obterUsuarioLogado()
return this.customerMapper.mapApiModelToDomain(cliente)
try {
const usuario = await api.obterUsuarioLogado()
return this.userMapper.mapApiModelToDomain(usuario)
} catch (e) {
localStorage.removeItem(SESSION_KEY)
const result = await this.errorAdapter.mapApiModelToDomain(e)
throw result
}
}
public logout = () => {
localStorage.removeItem(SESSION_KEY)
}
public connect = () => {
const sessionKey = localStorage.getItem(SESSION_KEY) || 'a'
if (sessionKey) return
else throw new Error()
// return await new Promise<void>((res, rej) => {
// })
} else throw new Error()
}
}
export class SessionRepositoryImplFactory {
static create(userAgent: UserAgent) {
console.log(userAgent)
const repository = new SessionRepositoryImpl(mapUserAgentToString(userAgent))
return repository
}
......
const config = await fetch('./config.json').then((res) => res.json())
const { API_URL, APP_NAME_CUSTOMER, SESSION_KEY_CUSTOMER } = config
const { API_URL, APP_NAME_CUSTOMER, SESSION_KEY_BROKER } = config
export { API_URL }
export const SESSION_KEY = SESSION_KEY_CUSTOMER
export const SESSION_KEY = SESSION_KEY_BROKER
export const APP_NAME = APP_NAME_CUSTOMER
......
// import { initialState as profileInitState, reducer as profile, State as Profiles } from './profiles'
import project, { initialState as projectInitState, Store as ProjectStore } from './project'
import { initialState as systemInitState, reducer as system, State as System } from './system'
// import { initialState as userInitState, reducer as user, State as Users } from './users'
export interface EntitiesState {
// user: Users
// profile: Profiles
system: System
project: ProjectStore
}
const reducers = {
// user,
// profile,
system
}
export const initialState: EntitiesState = {
// user: userInitState,
// profile: profileInitState,
system: systemInitState
system: systemInitState,
project: projectInitState,
}
const reducers = {
system,
project,
}
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 { createSelector } from 'reselect'
import { Project, ProjectContext } from '@agiliza/api/domain'
import { entries, values } from '@agiliza/utils/method'
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 getContext = (state: Store) =>
entries(state).reduce((entities, [k, v]) => {
return { ...entities, [k]: values(v.byId) }
}, {} as ProjectContext)
export const getProjects = createSelector(getById('projects'), getAllIds('projects'), (byId, allIds) => allIds.map((id) => byId[id] as Project))
import { normalize, schema } from 'normalizr'
import { Project, ProjectContext } from '@agiliza/api/domain'
import { NormalizedEntity, WithNormalizedEntity } from '@agiliza/utils/method'
export type NormalizedContext = WithNormalizedEntity<ProjectContext>
export interface NormalizedProjects {
projects: NormalizedEntity<Project>
}
const projectsSchema = new schema.Array(new schema.Entity('projects'))
const contextSchemas: Record<keyof ProjectContext, any> = {
statuses: new schema.Array(new schema.Entity('statuses')),
}
export const normalizeContext = (context: ProjectContext) => {
const { entities } = normalize(context, contextSchemas)
const normalizedEntities = entities as unknown as NormalizedContext
return normalizedEntities
}
export const normalizeProjects = (projects: Project[]) => {
const { entities } = normalize(projects, projectsSchema)
const normalizedEntities = entities as unknown as NormalizedProjects
return normalizedEntities
}
import { GetProjects, Project, ProjectContext } from '@agiliza/api/domain'
import { types as fetchTypes } from '@agiliza/redux/useCases/project'
import { EntityStore, entries, keys, WithEntityStore } from '@agiliza/utils/method'
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import { PREFIX } from '../shared'
import { normalizeContext, normalizeProjects } from './shared'
export interface Store extends WithEntityStore<ProjectContext> {
projects: EntityStore<Project>
}
export const initialState: Store = {
statuses: { byId: {}, allIds: [] },
projects: { byId: {}, allIds: [] },
}
export default createSlice({
name: `${PREFIX}/context`,
initialState,
reducers: {},
extraReducers: {
[fetchTypes.getContext.fulfilled]: (state, action: PayloadAction<ProjectContext>) => {
const normalized = normalizeContext(action.payload)
entries(normalized).forEach(([k, v]) => {
state[k].byId = v
state[k].allIds = keys(v)
})
},
[fetchTypes.getProjects.fulfilled]: (state, action: PayloadAction<GetProjects['Output']>) => {
const normalized = normalizeProjects(action.payload)
state.projects.byId = normalized.projects
state.projects.allIds = keys(normalized.projects)
},
},
})
export const PREFIX = 'entities'
import deepmerge from 'deepmerge'
import { AnyAction, combineReducers, Middleware, Reducer } from 'redux'
import { createLogger } from 'redux-logger'
import { combineEpics, createEpicMiddleware, Epic } from 'redux-observable'
import { configureStore } from '@reduxjs/toolkit'
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'
import entitiesReducer, { EntitiesState, initialState as entitiesInitState } from './entities'
import { errorMiddleware } from './middlewares'
import { errorMiddleware, printMiddleware } from './middlewares'
import {
initialState as sessionInitState,
reducer as sessionReducer,
......@@ -43,13 +42,18 @@ const rootReducer = (state, action: AnyAction) => {
return combinedReducers(state, action)
}
const middlewares = !process.env.PRODUCTION ? [createLogger({ collapsed: true }), errorMiddleware] : [errorMiddleware]
const defaultMiddleware = getDefaultMiddleware({
serializableCheck: false,
})
const middlewares = !process.env.PRODUCTION ? [/*createLogger({ collapsed: true }), */ errorMiddleware, printMiddleware] : [errorMiddleware]
const epicMiddleware = createEpicMiddleware()
const store = configureStore({
reducer: rootReducer,
middleware: [...middlewares, epicMiddleware] as Middleware[],
middleware: [...defaultMiddleware, ...middlewares, epicMiddleware] as Middleware[],
preloadedState: {
session: sessionInitState,
ui: uiInitState,
......
import { Customer } from '@agiliza/api/domain'
import { Broker, User } from '@agiliza/api/domain'
import { types as loginTypes } from '@agiliza/redux/ui/login'
import { types as authenticationTypes } from '@agiliza/redux/useCases/authentication'
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
export interface State {
......@@ -8,7 +7,7 @@ export interface State {
authenticating: boolean
authenticated: boolean
error?: string
customer?: Customer
broker?: Broker
}
export const initialState: State = {
......@@ -22,22 +21,15 @@ const session = createSlice({
initialState,
reducers: {},
extraReducers: {
[loginTypes.login.fulfilled]: (state, action: PayloadAction<Customer>) => {
[loginTypes.login.fulfilled]: (state, action: PayloadAction<User>) => {
state.authenticated = true
state.customer = action.payload
console.log(action.payload)
},
[loginTypes.logout.fulfilled]: (state) => {
state.authenticated = false
},
[loginTypes.connect.fulfilled]: (state) => {
[loginTypes.connect.fulfilled]: (state, action: PayloadAction<Broker>) => {
state.authenticated = true
},
// [authenticationTypes.createCustomer.fulfilled]: (state, action: PayloadAction<Customer>) => {
// state.customer = action.payload
// },
[authenticationTypes.getLoggedCustomer.fulfilled]: (state, action: PayloadAction<Customer>) => {
state.customer = action.payload
state.broker = action.payload
},
},
})
......
......@@ -4,4 +4,3 @@ export const isAuthenticating = (state: State) => state.authenticating
export const isAuthenticated = (state: State) => state.authenticated
export const isInitializing = (state: State) => state.initializing
export const getError = (state: State) => state.error
export const getCustomer = (state: State) => state.customer
......@@ -41,11 +41,12 @@ export const actions = {
thunkApi.dispatch({ type: 'RESET_STORE' })
return
}),
connect: createAsyncThunk(`${prefix}/connect`, (_, thunkApi) => {
connect: createAsyncThunk(`${prefix}/connect`, async (_, thunkApi) => {
const useCase = SessionRepositoryImplFactory.create(appPlatform)
try {
useCase.connect()
return await useCase.connect()
} catch (e) {
thunkApi.dispatch({ type: 'RESET_STORE' })
return thunkApi.rejectWithValue(e)
}
}),
......
import authentication, {
initialState as authenticationInitialState,
State as AuthenticationState
} from './authentication'
import project, { initialState as projectInitialState, State as ProjectState } from './project'
export interface UseCasesState {
authentication: AuthenticationState
project: ProjectState
}
const reducers = {
authentication,
export const initialState: UseCasesState = {
project: projectInitialState,
}
export const initialState: UseCasesState = {
authentication: authenticationInitialState,
const reducers = {
project,
}
export default reducers
import { State } from './slice'
export const isFetching = (state: State) => state.fetching
export const isSendingCode = (state: State) => state.sendingCode
export const isSearching = (state: State) => state.searching
export const isSubmitting = (state: State) => state.submitting
import {
CreateCustomer,
CreatePassword,
GetLoggedCustomer,
SendCode,
VerifyCode,
VerifyCPF
} from '@agiliza/api/domain'
import { AuthenticationRepositoryImplFactory } from '@agiliza/api/useCases'
import { GetProjects, SubmitProjects } from '@agiliza/api/domain'
import { ProjectRepositoryImplFactory } from '@agiliza/api/useCases'
import { appPlatform } from '@agiliza/constants/platform'
import {
createAsyncReducers,
......@@ -20,75 +13,39 @@ const prefix = 'useCases/authentication'
export interface State {
fetching: boolean
sendingCode: boolean
searching: boolean
submitting: boolean
}
export const initialState: State = {
fetching: false,
sendingCode: false,
searching: false,
submitting: false,
}
export const actions = {
getContext: createAsyncThunk(`${prefix}/getContext`, async (_, thunkApi) => {
const useCase = AuthenticationRepositoryImplFactory.create(appPlatform)
const useCase = ProjectRepositoryImplFactory.create(appPlatform)
try {
return await useCase.getContext()
} catch (e) {
return thunkApi.rejectWithValue(e)
}
}),
verifyCPF: createAsyncThunk(`${prefix}/verifyCPF`, async (input: WithSuccess<VerifyCPF['Input']>, thunkApi) => {
const useCase = AuthenticationRepositoryImplFactory.create(appPlatform)
try {
await useCase.verifyCPF(input)
input.onSuccess && input.onSuccess()
} catch (e) {
return thunkApi.rejectWithValue(e)
}
}),
createCustomer: createAsyncThunk(`${prefix}/createCustomer`, async (input: WithSuccess<CreateCustomer['Input']>, thunkApi) => {
const useCase = AuthenticationRepositoryImplFactory.create(appPlatform)
try {
const customer = await useCase.createCustomer(input)
input.onSuccess && input.onSuccess()
return customer
} catch (e) {
return thunkApi.rejectWithValue(e)
}
}),
sendCode: createAsyncThunk(`${prefix}/sendCode`, async (input: WithSuccess<SendCode['Input']>, thunkApi) => {
const useCase = AuthenticationRepositoryImplFactory.create(appPlatform)
getProjects: createAsyncThunk(`${prefix}/getProjects`, async (input: GetProjects['Input'], thunkApi) => {
const useCase = ProjectRepositoryImplFactory.create(appPlatform)
try {
await useCase.sendCode(input)
input.onSuccess && input.onSuccess()
} catch (e) {
return thunkApi.rejectWithValue(e)
}
}),
verifyCode: createAsyncThunk(`${prefix}/verifyCode`, async (input: WithSuccess<VerifyCode['Input']>, thunkApi) => {
const useCase = AuthenticationRepositoryImplFactory.create(appPlatform)
try {
await useCase.verifyCode(input)
input.onSuccess && input.onSuccess()
} catch (e) {
return thunkApi.rejectWithValue(e)
}
}),
createPassword: createAsyncThunk(`${prefix}/createPassword`, async (input: WithSuccess<CreatePassword['Input']>, thunkApi) => {
const useCase = AuthenticationRepositoryImplFactory.create(appPlatform)
try {
await useCase.createPassword(input)
input.onSuccess && input.onSuccess()
return await useCase.getProjects(input)
} catch (e) {
return thunkApi.rejectWithValue(e)
}
}),
getLoggedCustomer: createAsyncThunk(`${prefix}/getLoggedCustomer`, async (input: WithSuccess<GetLoggedCustomer['Input']>, thunkApi) => {
const useCase = AuthenticationRepositoryImplFactory.create(appPlatform)
submitProjects: createAsyncThunk(`${prefix}/submitProjects`, async (input: WithSuccess<SubmitProjects['Input']>, thunkApi) => {
const useCase = ProjectRepositoryImplFactory.create(appPlatform)
try {
const customer = await useCase.getLoggedCustomer()
const broker = await useCase.submitProjects(input)
input.onSuccess && input.onSuccess()
return customer
return broker
} catch (e) {
return thunkApi.rejectWithValue(e)
}
......@@ -102,7 +59,8 @@ const slice = createSlice({
reducers: {},
extraReducers: {
...values(types).reduce((reducers, type) => ({ ...reducers, ...createAsyncReducers(type) }), {}),
...createAsyncReducers(types.sendCode, 'sendingCode'),
...createAsyncReducers(types.getProjects, 'searching'),
...createAsyncReducers(types.submitProjects, 'submitting'),
},
})
......
import React from 'react'
import { Typography } 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 {}
const Dashboard = (props: Props) => {
const { classes } = props
return (
<div className={classes.pageContent}>
<Typography variant="h5">AGILIZA - PORTAL AGENTE</Typography>
</div>
)
}
export default withStyles(styles)(Dashboard)
export { default } from './Dashboard'
export * from './Dashboard'
import { createStyles, Theme } from '@material-ui/core/styles'
import sharedStyles from '../shared-styles'
export default (theme: Theme) =>
createStyles({
...sharedStyles(theme),
})
......@@ -9,6 +9,7 @@ import { StoreState } from '@agiliza/redux'
import { isAuthenticated } from '@agiliza/redux/session/selectors'
import { actions } from '@agiliza/redux/ui/login'
import { isFetching } from '@agiliza/redux/ui/login/selectors'
import { maskCPFCNPJ } from '@agiliza/utils/masks'
import InputAdornment from '@material-ui/core/InputAdornment'
import Typography from '@material-ui/core/Typography'
import AccountCircle from '@material-ui/icons/AccountCircle'
......@@ -51,9 +52,10 @@ const Login = (props: Props) => {
<TextFieldWithIcon
autoFocus
required
value={username}
value={maskCPFCNPJ(username)}
onChange={(evt) => setUsername(evt.target.value)}
label="Usuário"
type="tel"
className={classes.usernameTxtField}
InputProps={{
startAdornment: (
......
......@@ -2,9 +2,8 @@ import cn from 'classnames'
import React from 'react'
import ItemWithIcon from '@agiliza/components/atoms/ItemWithIcon'
import ProfileIcon from '@agiliza/components/particles/Icons/SecurityProfileIcon'
import List from '@material-ui/core/List'
import { ExitToApp, People as PeopleIcon } from '@material-ui/icons'
import { ExitToApp, Visibility as VisibilityIcon } from '@material-ui/icons'
import withStyles from '@material-ui/styles/withStyles'
import { styles } from './styles'
......@@ -19,14 +18,11 @@ interface ListItem {
}
export const PATHS = {
user: '/usuarios',
profiles: '/perfis',
dashboard: '/dashboard',
projects: '/projetos',
}
export const drawerListItems: ListItem[] = [
{ label: 'Usuários', path: PATHS.user, Icon: PeopleIcon },
{ label: 'Perfis de Acesso', path: PATHS.profiles, Icon: ProfileIcon },
]
export const drawerListItems: ListItem[] = [{ label: 'Projetos', path: PATHS.projects, Icon: VisibilityIcon }]
type ExtendedTypes = RouteComponentProps & WithStyles<typeof styles>
......
import React, { lazy, Suspense, useEffect } from 'react'
import React, { lazy, Suspense } from 'react'
import { SkeletonTheme } from 'react-loading-skeleton'
import { Redirect, Route, RouteComponentProps, Switch } 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 { actions as drawerActions } from '@agiliza/redux/ui/drawer'
import { actions as loginActions } from '@agiliza/redux/ui/login'
import { useTheme } from '@material-ui/core/styles'
import { Typography } from '@material-ui/core'
import { useTheme, withStyles, WithStyles } from '@material-ui/core/styles'
import connect, { ConnectedProps } from './connect'
import DrawerItems, { PATHS } from './DrawerItems'
import styles from './styles'
const User = lazy(() => import('@curio/ui/dist/views/User'))
const SecurityProfile = lazy(() => import('@curio/ui/dist/views/SecurityProfile'))
const Dashboard = lazy(() => import('../Dashboard'))
const Projects = lazy(() => import('@agiliza/views/Projects/pages/Searcher'))
type BaseProps = RouteComponentProps & ConnectedProps
type BaseProps = RouteComponentProps & ConnectedProps & WithStyles<typeof styles>
interface Props extends BaseProps {
toggleDrawer: typeof drawerActions.toggleDrawer
logout: typeof loginActions.logout
}
const Main = (props: Props) => {
const theme = useTheme()
const { drawerOpen, toggleDrawer, logout, fetchMenu, ...routeProps } = props
const { classes, drawerOpen, toggleDrawer, logout, ...routeProps } = props
useEffect(() => {
fetchMenu()
}, [])
const { history } = routeProps
return (
<>
<div className={classes.pageContainer}>
<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} />
<SkeletonTheme color={theme.palette.grey[500]} highlightColor={theme.palette.grey[300]}>
<Suspense fallback={<CircularProgress />}>
<Switch>
<Route path={PATHS.user} render={() => <User onNavClick={toggleDrawer} />} />
<Route path={PATHS.profiles} render={() => <SecurityProfile onNavClick={toggleDrawer} />} />
<Redirect from="/" to={PATHS.user} />
<Route path={PATHS.dashboard} render={() => <Dashboard />} />
<Route path={PATHS.projects} render={() => <Projects />} />
<Redirect from="/" to={PATHS.projects} />
</Switch>
</Suspense>
</SkeletonTheme>
</>
</div>
)
}
export default connect(Main)
export default connect(withStyles(styles)(Main))
......@@ -4,26 +4,26 @@ import { bindActionCreators, Dispatch } from 'redux'
import { StoreState } from '@agiliza/redux'
import { actions as drawerActions } from '@agiliza/redux/ui/drawer'
import { isDrawerOpen } from '@agiliza/redux/ui/drawer/selectors'
import { actions as systemActions, selectors as systemSelectors } from '@agiliza/redux/ui/system'
import { actions as loginActions } from '@agiliza/redux/ui/login'
export interface ConnectedProps {
drawerOpen: boolean
fetchingMenu: boolean
fetchMenu: typeof systemActions.fetchMenu
toggleDrawer: typeof drawerActions.toggleDrawer
logout: typeof loginActions.logout
}
const mapStateToProps = (state: StoreState) => ({
type StateProps = Pick<ConnectedProps, 'drawerOpen'>
type DispatchProps = Pick<ConnectedProps, 'logout' | 'toggleDrawer'>
const mapStateToProps = (state: StoreState): StateProps => ({
drawerOpen: isDrawerOpen(state.ui.drawer),
fetchMenu: systemActions.fetchMenu,
fetchingMenu: systemSelectors.isFetching(state.ui.system),
})
const mapDispatchToProps = (dispatch: Dispatch) =>
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps =>
bindActionCreators(
{
toggleDrawer: drawerActions.toggleDrawer,
fetchMenu: systemActions.fetchMenu,
logout: loginActions.logout,
},
dispatch
)
......
import { createStyles, Theme } from '@material-ui/core/styles'
import sharedStyles from '../shared-styles'
export default (theme: Theme) => {
return createStyles({
...sharedStyles(theme),
pageContainer: {
height: '100vh',
display: 'flex',
flexDirection: 'column',
// padding: theme.spacing(2),
paddingTop: 0,
paddingBottom: 0,
justifyContent: 'flex-start',
},
appTitle: { flexGrow: 1, fontSize: '100%', textTransform: 'uppercase' },
titleAnchor: { cursor: 'pointer' },
})
}
import React, { useEffect, useMemo, useState } from 'react'
import { Project } from '@agiliza/api/domain'
import ButtonWithProgress from '@agiliza/components/atoms/ButtonWithProgress'
import { useFormState } from '@agiliza/utils/hooks/state'
import { ContextButton, DatePicker, PageTitle, SelectField, Table } from '@curio/components'
import { Grid, IconButton } from '@material-ui/core'
import { withStyles, WithStyles } from '@material-ui/core/styles'
import { Search as SearchIcon, Visibility as VisibilityIcon } from '@material-ui/icons'
import { connected, ConnectedProps } from './connect'
import styles from './styles'
interface State {
beginDate: Date | null
endDate: Date | null
statuses: number[]
}
const initState: State = {
beginDate: null,
endDate: null,
statuses: [],
}
const tableColumns = ['ID', 'Número processo', 'Situação', 'Ações']
type ExtendedProps = WithStyles<typeof styles> & ConnectedProps
interface Props extends ExtendedProps {}
const Searcher = (props: Props) => {
const { classes, searching, submitting, projects, context } = props
const { state, actions } = useFormState('searcher', initState)
const { beginDate, endDate, statuses } = state
const [selectedProjects, setSelectedProjects] = useState<string[]>([])
const [status, setStatus] = useState('')
useEffect(() => {
props.getContext()
}, [])
const handleChangeDate = (type: keyof Pick<State, 'beginDate' | 'endDate'>) => (date: Date | null) => {
actions.update({ [type]: date })
}
const handleSearch = () => {
props.getProjects({
beginDate,
endDate,
statuses: [Number(status)],
})
}
const tableKeys = useMemo(() => {
const id = (p: Project) => p.id
const processNumber = (p: Project) => p.processNumber
const situation = (p: Project) => context.statuses.find((st) => st.id === p.status.id)?.description || ''
const mapToActions = (p: Project) => (
<ContextButton
size="small"
menuId={`entity-${p.id}-actions`}
menuItems={[
{
label: 'Visualizar',
icon: <VisibilityIcon />,
},
]}
/>
)
return [id, processNumber, situation, mapToActions]
}, [projects])
const handleRowClick = (prj: Project) => {
const newSelectedProjects = selectedProjects.indexOf(prj.id) !== -1 ? selectedProjects.filter((p) => p !== prj.id) : [...selectedProjects, prj.id]
setSelectedProjects(newSelectedProjects)
}
const handleSubmitClick = () => {
props.submitProjects({ ids: selectedProjects, onSuccess: () => props.getProjects({ beginDate, endDate, statuses }) })
}
return (
<div className={classes.pageContent}>
<PageTitle title="Buscar projetos" />
<Grid container spacing={2} className={classes.fieldsContainer}>
<Grid item xs={3}>
<DatePicker
id="begin-date"
label="Data início"
value={beginDate}
onChange={handleChangeDate('beginDate')}
format="dd/MM/yyyy"
className={classes.datePicker}
/>
</Grid>
<Grid item xs={3}>
<DatePicker
id="end-date"
label="Data fim"
value={endDate}
onChange={handleChangeDate('endDate')}
format="dd/MM/yyyy"
className={classes.datePicker}
/>
</Grid>
<Grid item xs={5}>
<SelectField
id="statuses-select-field"
label="Situação"
value={status}
onChange={(vl) => setStatus(vl)}
items={context.statuses.map((mR) => ({ label: mR.description, value: mR.id }))}
variant="outlined"
shrink={false}
/>
</Grid>
<Grid item xs={1}>
<IconButton onClick={handleSearch} className={classes.btnSearch}>
<SearchIcon />
</IconButton>
</Grid>
</Grid>
<div className={classes.submitBtnContainer}>
<ButtonWithProgress fetching={submitting} color="primary" disabled={!selectedProjects.length} onClick={handleSubmitClick}>
Submeter projetos
</ButtonWithProgress>
</div>
<Table<Project>
size="small"
columns={tableColumns}
keys={tableKeys}
data={projects}
fetching={searching}
selectedRows={selectedProjects}
onRowClick={handleRowClick}
/>
</div>
)
}
export default connected(withStyles(styles)(Searcher))
import { connect } from 'react-redux'
import { bindActionCreators, Dispatch } from 'redux'
import { Project, ProjectContext } from '@agiliza/api/domain'
import { StoreState } from '@agiliza/redux'
import * as entProject from '@agiliza/redux/entities/project'
import * as ucProject from '@agiliza/redux/useCases/project'
export interface ConnectedProps {
fetching: boolean
searching: boolean
submitting: boolean
context: ProjectContext
projects: Project[]
getContext: typeof ucProject.actions.getContext
getProjects: typeof ucProject.actions.getProjects
submitProjects: typeof ucProject.actions.submitProjects
}
type StateProps = Pick<ConnectedProps, 'context' | 'projects' | 'fetching' | 'searching' | 'submitting'>
type DispatchProps = Pick<ConnectedProps, 'getContext' | 'getProjects' | 'submitProjects'>
const mapStateToProps = (state: StoreState): StateProps => ({
fetching: ucProject.selectors.isFetching(state.useCases.project),
searching: ucProject.selectors.isSearching(state.useCases.project),
submitting: ucProject.selectors.isSubmitting(state.useCases.project),
context: entProject.selectors.getContext(state.entities.project),
projects: entProject.selectors.getProjects(state.entities.project),
})
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps =>
bindActionCreators(
{
getContext: ucProject.actions.getContext,
getProjects: ucProject.actions.getProjects,
submitProjects: ucProject.actions.submitProjects,
},
dispatch
)
export const connected = connect(mapStateToProps, mapDispatchToProps)
export { default } from './Searcher'
export * from './Searcher'
import { flexColumn } from '@agiliza/constants/styles'
import { defaultToobarHeight } from '@agiliza/theme'
import sharedStyles from '@agiliza/views/shared-styles'
import { createStyles, Theme } from '@material-ui/core/styles'
export const sharedStyles = (theme: Theme) => ({
pageContainer: { height: '100%' },
contentContainer: {
padding: theme.spacing(2),
height: `calc(100% - ${defaultToobarHeight * 2}px)`,
...flexColumn,
},
})
export default (theme: Theme) => {
return createStyles({
...sharedStyles(theme),
fieldsContainer: { display: 'flex', width: '50%' },
datePicker: { width: '100%' },
btnSearch: { margin: theme.spacing(1) },
submitBtnContainer: { width: '100%', marginTop: theme.spacing(2) },
})
}
import { createHashHistory } from 'history'
import React, { lazy, Suspense } from 'react'
import React, { lazy, Suspense, useEffect } from 'react'
import { connect } from 'react-redux'
import { Route, Router, Switch } from 'react-router'
import { bindActionCreators, Dispatch } from 'redux'
......@@ -11,6 +11,7 @@ import { isAuthenticated, isAuthenticating, isInitializing } from '@agiliza/redu
import { actions as drawerActions } from '@agiliza/redux/ui/drawer'
import { isDrawerOpen } from '@agiliza/redux/ui/drawer/selectors'
import { getError } from '@agiliza/redux/ui/error/selectors'
import * as uiLogin from '@agiliza/redux/ui/login'
const Login = lazy(() => import('./Login'))
const Main = lazy(() => import('./Main'))
......@@ -21,11 +22,16 @@ interface Props {
error: string
authenticated: boolean
authenticating: boolean
connect: typeof uiLogin.actions.connect
}
const Views = (props: Props) => {
const { authenticating } = props
useEffect(() => {
props.connect()
}, [])
if (authenticating) return <CircularProgress root />
return (
......@@ -51,6 +57,7 @@ const mapDispatchToProps = (dispatch: Dispatch) =>
bindActionCreators(
{
toggleDrawer: drawerActions.toggleDrawer,
connect: uiLogin.actions.connect,
},
dispatch
)
......
import { Theme } from '@material-ui/core'
import { createStyles } from '@material-ui/core/styles'
// import sharedStyles from '../../shared-styles'
export default (theme: Theme) => {
const display = 'flex'
return createStyles({
pageContent: {
height: `calc(100vh - ${theme.mixins.toolbar.minHeight}px)`,
padding: theme.spacing(2),
display: 'flex',
flexDirection: 'column',
overflowY: 'hidden',
},
title: {
flexGrow: 1,
fontSize: '100%',
},
circularProgressContainer: {
display: 'flex',
width: '100%',
height: '100%',
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
circularProgress: { position: 'absolute', top: '50%', left: '50%' },
container: { display: 'flex', flexDirection: 'column', flex: 1, height: '100%' },
inputContainer: { display, flexWrap: 'wrap' },
form: { display, flexWrap: 'wrap', alignItems: 'center' },
formContent: {
marginRight: theme.spacing(3),
flexWrap: 'wrap',
display,
flexDirection: 'column',
width: '85%',
},
})
}
import { createStyles } from '@material-ui/core/styles'
export const sharedStyles = () => createStyles({})
......@@ -88,7 +88,6 @@ const resolve = {
'@agiliza/views': pathResolve('src/views'),
'@agiliza/utils': pathResolve('src/utils'),
'@agiliza/public': pathResolve('public'),
'@material-ui/styles': path.resolve('.', 'node_modules', '@material-ui/styles'),
}, // Modified paths, modify tsconfig.json "paths"
extensions: ['.ts', '.tsx', '.js'],
}
......
......@@ -937,6 +937,28 @@
isomorphic-fetch "^2.2.1"
symbol-observable "^1.2.0"
"@curio/components@^0.1.6":
version "0.1.6"
resolved "https://nexus.dev.evologica.com.br/repository/npm/@curio/components/-/components-0.1.6.tgz#a6b69b17af2ab2966c97016372cddbc35f0eef87"
integrity sha512-AVblcKODqCqforRww+1buMRMDMNyDN75N6TqYsRwM34onRlstcT4wQXLv0gZA1qZrCMu9E9TAcKjVy3RKgQ1Dw==
dependencies:
"@curio/client" "1.3.3"
"@date-io/date-fns" "^1.0.0"
"@dynamo/components" "0.71.0"
"@dynamo/curio" "0.71.0"
"@dynamo/material-ui" "0.71.0"
"@material-ui/lab" "4.0.0-alpha.58"
"@material-ui/pickers" "^3.3.10"
"@reduxjs/toolkit" "^1.2.5"
"@xstate/react" "^1.3.3"
classnames "^2.2.6"
date-fns "^2.11.0"
deepmerge "^4.2.2"
immer "^8.0.1"
p-min-delay "^4.0.0"
react-loading-skeleton "^2.0.1"
xstate "^4.19.1"
"@curio/ui@^0.1.0":
version "0.1.3"
resolved "https://nexus.dev.evologica.com.br/repository/npm/@curio/ui/-/ui-0.1.3.tgz#df75896375abcc7dd144fb3981060325b4c4efac"
......@@ -986,6 +1008,15 @@
classnames "2.2.6"
immer "^5.0.0"
"@dynamo/components@0.71.0", "@dynamo/components@^0.71.0":
version "0.71.0"
resolved "https://nexus.dev.evologica.com.br/repository/npm/@dynamo/components/-/components-0.71.0.tgz#62cb8c2110ce021ba47af9d1758daedb6540d017"
integrity sha512-zFqPOQBYua4Hqsy6si9Q0a/5ctRQCmK7jrrhVpf/fhZ4uiDiOkpNt5+SiaGfgqYnV6kWCQH10TKIZFQROeFNOw==
dependencies:
"@dynamo/utils" "^0.71.0"
classnames "2.2.6"
immer "^5.0.0"
"@dynamo/curio@0.70.1":
version "0.70.1"
resolved "https://nexus.dev.evologica.com.br/repository/npm/@dynamo/curio/-/curio-0.70.1.tgz#201f30fefccf67f3c958e19407a4a6163c10d0ca"
......@@ -993,6 +1024,13 @@
dependencies:
"@dynamo/utils" "^0.70.1"
"@dynamo/curio@0.71.0":
version "0.71.0"
resolved "https://nexus.dev.evologica.com.br/repository/npm/@dynamo/curio/-/curio-0.71.0.tgz#18b95ea403ad19a5412676d1b330a762b7842059"
integrity sha512-e0FC/jhrVZ0usd2yhl3AbOSTQwoA1yjh0VyI/mcIlvhoIXewsPT7iqhuqZTM2kPu+YDpcPt+gy6VfoxAibLr/g==
dependencies:
"@dynamo/utils" "^0.71.0"
"@dynamo/material-ui@0.70.1":
version "0.70.1"
resolved "https://nexus.dev.evologica.com.br/repository/npm/@dynamo/material-ui/-/material-ui-0.70.1.tgz#233f09fef2d653a0c4e3a2a64299d0e508c46cd7"
......@@ -1004,6 +1042,17 @@
"@types/react-text-mask" "^5.4.4"
classnames "^2.2.6"
"@dynamo/material-ui@0.71.0":
version "0.71.0"
resolved "https://nexus.dev.evologica.com.br/repository/npm/@dynamo/material-ui/-/material-ui-0.71.0.tgz#2ae718a90a73c50391600e6869d05ba661709fed"
integrity sha512-rQAif2ZYpUuHYBgWIUI0kIBUewz1niH/e64qt0SEaxbwHw3on4sOjcqq0n7WGGV2yt0qkIFPG3Fk2tVscSvs4A==
dependencies:
"@date-io/date-fns" "^1.3.13"
"@dynamo/components" "^0.71.0"
"@dynamo/utils" "^0.71.0"
"@types/react-text-mask" "^5.4.4"
classnames "^2.2.6"
"@dynamo/utils@^0.70.1":
version "0.70.1"
resolved "https://nexus.dev.evologica.com.br/repository/npm/@dynamo/utils/-/utils-0.70.1.tgz#759c40f975369833c465b94346146ad362c92b23"
......@@ -1013,6 +1062,15 @@
react-text-mask "^5.4.3"
text-mask-addons "^3.8.0"
"@dynamo/utils@^0.71.0":
version "0.71.0"
resolved "https://nexus.dev.evologica.com.br/repository/npm/@dynamo/utils/-/utils-0.71.0.tgz#48b4f9365d47b62ed1a7f49b3e3e50ebd5bb01ec"
integrity sha512-FpNEMHjpVOaZfn8kNaJ9EdC/+sWDQDGgj9BpFWF52lubHOo6Wn6hsuK8YlrOAJy16OVlLuAaj6xzgGs9Pt7LdA==
dependencies:
date-fns "^2.8.1"
react-text-mask "^5.4.3"
text-mask-addons "^3.8.0"
"@emotion/cache@^10.0.27":
version "10.0.29"
resolved "https://nexus.dev.evologica.com.br/repository/npm/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0"
......@@ -1199,10 +1257,10 @@
prop-types "^15.7.2"
react-is "^16.8.0 || ^17.0.0"
"@microcredito/client@^0.7.18":
version "0.7.18"
resolved "https://nexus.dev.evologica.com.br/repository/npm/@microcredito/client/-/client-0.7.18.tgz#2584e73d379cbd4ab0aa3f22944b789d3662f67f"
integrity sha1-JYTnPTecvUqwqj8ilEt4nTZi9n8=
"@microcredito/client@^0.7.22":
version "0.7.22"
resolved "https://nexus.dev.evologica.com.br/repository/npm-internal/@microcredito/client/-/client-0.7.22.tgz#a387ff194e6b1efea37027a447bb5b411edfd126"
integrity sha1-o4f/GU5rHv6jcCekR7tbQR7f0SY=
"@nodelib/fs.scandir@2.1.4":
version "2.1.4"
......
{
"name": "agiliza",
"name": "agiliza-cliente",
"version": "0.0.1",
"license": "ISC",
"repository": "https://gitlab.dev.evologica.com.br/evologica/agiliza",
......
......@@ -8,6 +8,6 @@ server.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist', 'index.html'))
})
server.listen(3000, () => {
console.log('Listening at http://localhost:3000/')
server.listen(3001, () => {
console.log('Listening at http://localhost:3001/')
})
......@@ -16,7 +16,7 @@ const DIST = path.join(__dirname, 'dist')
const defaultEnv = {
production: false,
port: 3000,
port: 3001,
analyze: false,
}
......@@ -114,12 +114,12 @@ const makeCommonPlugins = (env) => [
PUBLIC_PATH: '/',
NODE_ENV: env.production ? 'production' : 'development',
PRODUCTION: env.production,
APP_TITLE: 'Agiliza',
APP_TITLE: 'Agiliza - Cliente',
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, 'public', 'index.ejs'),
favicon: path.join(PUBLIC, 'images', 'favicon.png'),
title: 'Agiliza',
title: 'Agiliza - Cliente',
inject: false,
}),
new webpack.DefinePlugin({
......
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