Skip to content
This repository was archived by the owner on Apr 22, 2022. It is now read-only.

Websocket #35

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@
"dependencies": {
"@data-driven-forms/pf4-component-mapper": "2.21.1",
"@data-driven-forms/react-form-renderer": "2.21.1",
"@patternfly/patternfly": "4.87.1",
"@patternfly/react-core": "4.97.0",
"@patternfly/react-table": "4.23.0",
"@konveyor/lib-ui": "^2.0.0",
"@patternfly/patternfly": "4.90.5",
"@patternfly/react-core": "4.101.2",
"@patternfly/react-table": "4.23.13",
"@react-keycloak/web": "^3.4.0",
"@redhat-cloud-services/frontend-components-notifications": "2.2.3",
"@testing-library/jest-dom": "^5.11.4",
Expand All @@ -30,14 +31,18 @@
"jest-enzyme": "^7.1.2",
"keycloak-js": "^12.0.1",
"lint-staged": "^10.4.2",
"lodash": "^4.17.21",
"moment": "^2.29.1",
"prettier": "^2.1.2",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-dropzone": "^11.3.1",
"react-moment": "^1.1.1",
"react-redux": "^7.2.1",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.0",
"react-test-renderer": "^16.13.1",
"react-use-websocket": "^2.5.0",
"redux": "^4.0.5",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.3.0",
Expand Down Expand Up @@ -112,6 +117,7 @@
"@testing-library/react-hooks": "^3.4.2",
"@types/enzyme": "^3.10.7",
"@types/enzyme-adapter-react-16": "^1.0.6",
"@types/lodash": "^4.14.168",
"@types/react-redux": "^7.1.9",
"@types/react-router-dom": "^5.1.6",
"@types/redux-logger": "^3.0.8",
Expand Down
51 changes: 46 additions & 5 deletions src/api/models.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
export type EntityEventType = "CREATED" | "UPDATED" | "DELETED";

export interface WsMessage {
type: "event";
spec: EntityEvent;
}

export interface EntityEvent {
id: string;
event: EntityEventType;
entity: string;
}

export interface PageQuery {
page: number;
perPage: number;
Expand Down Expand Up @@ -45,15 +58,43 @@ export interface SUNATCredentials {
password?: string;
}

export type DeliveryStatus =
| "SCHEDULED_TO_DELIVER"
| "NEED_TO_CHECK_TICKET"
| "COULD_NOT_BE_DELIVERED"
| "DELIVERED";

export interface UBLDocument {
id?: string;
deliveryStatus: string;
fileInfo: FileInfo;
createdOn: number;

retries: number;
willRetryOn: number;

fileContentValid?: boolean;
fileContentValidationError?: string;
fileContent?: UBLDocumentFileContent;

sunat?: UBLDocumentSunat;
sunatDeliveryStatus: DeliveryStatus;
sunatEvents: UBLDocumentEvent[];
}

export interface FileInfo {
export interface UBLDocumentFileContent {
ruc: string;
documentID: string;
documentType: string;
filename: string;
ruc: string;
}

export interface UBLDocumentSunat {
code: string;
status: "ACEPTADO" | "RECHAZADO" | "EXCEPCION" | "BAJA" | "EN_PROCESO";
description: string;
ticket: string;
}

export interface UBLDocumentEvent {
status: "default" | "success" | "danger" | "warning" | "info";
description: string;
createdOn: number;
}
Binary file added src/images/sunat.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
91 changes: 69 additions & 22 deletions src/pages/companies/company-list/company-list.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { useCallback, useEffect, useState } from "react";
import { Link, RouteComponentProps } from "react-router-dom";
import { useDispatch } from "react-redux";
import useWebSocket from "react-use-websocket";
import { useKeycloak } from "@react-keycloak/web";

import {
Bullseye,
Expand All @@ -16,9 +18,11 @@ import {
ToolbarItem,
} from "@patternfly/react-core";
import {
cellWidth,
IActions,
ICell,
IExtraData,
IRow,
IRowData,
sortable,
} from "@patternfly/react-table";
Expand All @@ -43,7 +47,7 @@ import { DeleteWithMatchModalContainer } from "shared/containers";

import { formatPath, Paths } from "Paths";
import { CompanySortBy, CompanySortByQuery } from "api/rest";
import { Company, SortByQuery } from "api/models";
import { Company, WsMessage, SortByQuery } from "api/models";
import { getAxiosErrorMessage } from "utils/modelUtils";

import { Welcome } from "./components/welcome";
Expand Down Expand Up @@ -80,6 +84,7 @@ export interface CompanyListProps extends RouteComponentProps {}

export const CompanyList: React.FC<CompanyListProps> = ({ history }) => {
const dispatch = useDispatch();
const { keycloak } = useKeycloak();

const [filterText, setFilterText] = useState("");

Expand Down Expand Up @@ -120,13 +125,54 @@ export const CompanyList: React.FC<CompanyListProps> = ({ history }) => {
);
}, [filterText, paginationQuery, sortByQuery, fetchCompanies]);

const socketUrl = "ws://localhost:8080/companies";

const {
lastJsonMessage: eventMsg,
sendJsonMessage: sendEventMessage,
} = useWebSocket(socketUrl, {
onOpen: () => {
sendEventMessage({
authentication: {
token: keycloak.token,
},
});
},
shouldReconnect: (event: CloseEvent) => event.code !== 1011,
share: true,
});

useEffect(() => {
if (eventMsg) {
const event: WsMessage = eventMsg as WsMessage;

switch (event.spec.event) {
case "CREATED":
if (
paginationQuery.page === 1 &&
!sortByQuery &&
!(companies?.data || []).find((f) => f.id === event.spec.id)
) {
refreshTable();
}
break;
case "DELETED":
if (companies && companies.data.find((f) => f.id === event.spec.id)) {
refreshTable();
}
break;
}
}
}, [eventMsg, companies, paginationQuery, sortByQuery, refreshTable]);

const columns: ICell[] = [
{ title: "Name", transforms: [sortable] },
{ title: "Name", transforms: [sortable, cellWidth(40)] },
{ title: "Description" },
];

const itemsToRow = (items: Company[]) => {
return items.map((item) => ({
const rows: IRow[] = [];
companies?.data.forEach((item) => {
rows.push({
[COMPANY_FIELD]: item,
cells: [
{
Expand All @@ -140,8 +186,8 @@ export const CompanyList: React.FC<CompanyListProps> = ({ history }) => {
title: item.description,
},
],
}));
};
});
});

const actions: IActions = [
{
Expand Down Expand Up @@ -176,7 +222,7 @@ export const CompanyList: React.FC<CompanyListProps> = ({ history }) => {
row,
() => {
dispatch(deleteWithMatchModalActions.closeModal());
refreshTable();
// refreshTable();
},
(error) => {
dispatch(deleteWithMatchModalActions.closeModal());
Expand Down Expand Up @@ -222,16 +268,15 @@ export const CompanyList: React.FC<CompanyListProps> = ({ history }) => {
<PageSection>
<AppTableWithControls
count={companies ? companies.meta.count : 0}
items={companies ? companies.data : []}
itemsToRow={itemsToRow}
pagination={paginationQuery}
sortBy={sortByQuery}
handlePaginationChange={handlePaginationChange}
handleSortChange={handleSortChange}
columns={columns}
rows={rows}
actions={actions}
isLoading={isFetching}
loadingVariant="skeleton"
loadingVariant="none"
fetchError={fetchError}
filtersApplied={filterText.trim().length > 0}
toolbarToggle={
Expand All @@ -240,18 +285,20 @@ export const CompanyList: React.FC<CompanyListProps> = ({ history }) => {
</ToolbarGroup>
}
toolbar={
<ToolbarGroup variant="button-group">
<ToolbarItem>
<Button
type="button"
aria-label="new-company"
variant={ButtonVariant.primary}
onClick={handleOnNewCompany}
>
New company
</Button>
</ToolbarItem>
</ToolbarGroup>
<>
<ToolbarGroup variant="button-group">
<ToolbarItem>
<Button
type="button"
aria-label="new-company"
variant={ButtonVariant.primary}
onClick={handleOnNewCompany}
>
New company
</Button>
</ToolbarItem>
</ToolbarGroup>
</>
}
noDataState={
<EmptyState variant={EmptyStateVariant.small}>
Expand Down
66 changes: 65 additions & 1 deletion src/pages/companies/new-company/new-company.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import React, { useState } from "react";
import { RouteComponentProps } from "react-router-dom";

import { Alert, PageSection, Stack, StackItem } from "@patternfly/react-core";
import {
Alert,
Button,
Flex,
FlexItem,
PageSection,
Stack,
StackItem,
} from "@patternfly/react-core";

import FormRenderer from "@data-driven-forms/react-form-renderer/dist/cjs/form-renderer";
import Pf4FormTemplate from "@data-driven-forms/pf4-component-mapper/dist/cjs/form-template";
Expand Down Expand Up @@ -30,11 +38,44 @@ export interface NewCompanyFormValues {
};
}

const BETA_TEMPLATE: NewCompanyFormValues = {
name: "",
description: "This is a test company",
credentials: {
username: "12345678959MODDATOS",
password: "MODDATOS",
},
webServices: {
factura: "https://e-beta.sunat.gob.pe/ol-ti-itcpfegem-beta/billService",
guia:
"https://e-beta.sunat.gob.pe/ol-ti-itemision-guia-gem-beta/billService",
retenciones:
"https://e-beta.sunat.gob.pe/ol-ti-itemision-otroscpe-gem-beta/billService",
},
};

const PROD_TEMPLATE: NewCompanyFormValues = {
name: "",
description: "",
credentials: {
username: "",
password: "",
},
webServices: {
factura: "https://e-factura.sunat.gob.pe/ol-ti-itcpfegem/billService",
guia:
"https://e-guiaremision.sunat.gob.pe/ol-ti-itemision-guia-gem/billService",
retenciones:
"https://e-factura.sunat.gob.pe/ol-ti-itemision-otroscpe-gem/billService",
},
};

export interface CompanyListProps extends RouteComponentProps {}

export const NewCompany: React.FC<CompanyListProps> = ({ history }) => {
const dispatch = useDispatch();
const [conflictErrorMsg, setConflictErrorMsg] = useState("");
const [initialValues, setInitialValues] = useState<NewCompanyFormValues>();

const handleOnSubmit = (formValues: any) => {
return createCompany(formValues)
Expand All @@ -57,16 +98,39 @@ export const NewCompany: React.FC<CompanyListProps> = ({ history }) => {
history.push(Paths.companyList);
};

const applyBetaTemplate = () => {
setInitialValues(BETA_TEMPLATE);
};

const applyProdTemplate = () => {
setInitialValues(PROD_TEMPLATE);
};

return (
<PageSection variant="light">
<Stack hasGutter>
<StackItem>
<Flex>
<FlexItem>
<Button variant="secondary" onClick={applyBetaTemplate}>
Beta
</Button>
</FlexItem>
<FlexItem>
<Button variant="secondary" onClick={applyProdTemplate}>
Prod
</Button>
</FlexItem>
</Flex>
</StackItem>
{conflictErrorMsg && (
<StackItem>
<Alert variant="danger" title={conflictErrorMsg} />
</StackItem>
)}
<StackItem>
<FormRenderer
initialValues={initialValues}
schema={newCompanySchema}
FormTemplate={(props) => (
<Pf4FormTemplate submitLabel="Create" {...props} />
Expand Down
Loading