Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ViewComposer: Generic View Component #27

Merged
merged 3 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion micro-ui/web/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"dependencies": {
"@egovernments/digit-ui-libraries": "1.8.0-beta",
"@egovernments/digit-ui-module-workbench": "1.0.0-beta",
"@egovernments/digit-ui-module-core": "1.8.0-beta.8",
"@egovernments/digit-ui-module-core": "1.8.0-beta.9",
"@egovernments/digit-ui-module-hrms": "1.8.0-beta.2",
"@egovernments/digit-ui-react-components": "1.8.0-beta.1",
"@egovernments/digit-ui-module-dss": "1.8.0-beta",
Expand Down
2 changes: 1 addition & 1 deletion micro-ui/web/micro-ui-internals/example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"@egovernments/digit-ui-libraries": "1.8.0-beta",
"@egovernments/digit-ui-module-workbench": "1.0.0-beta",
"@egovernments/digit-ui-module-dss": "1.8.0-beta",
"@egovernments/digit-ui-module-core": "1.8.0-beta.8",
"@egovernments/digit-ui-module-core": "1.8.0-beta.9",
"@egovernments/digit-ui-module-common": "1.8.0-beta",
"@egovernments/digit-ui-module-hrms": "1.8.0-beta.2",
"@egovernments/digit-ui-module-utilities": "1.0.0-beta",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Intro:

ViewComposer is basically a replacement of ApplicationDetails component which was a generic component for View Screens. That got very cluttered with custom logic. So to keep the business logic abstract and generic we made this component.

## High level steps to use:
1. Simply import it from react-components library
2. It expects two things as props -> data,isLoading
3. data contains all the details to show in the view screen with specific format, basically we'll be returning this data object from the hook call.

### Format of data expected by ViewComposer
Below is an example object:

<!-- {
cards:[
{
sections: [
{
type: "DATA",
sectionHeader: { value: "Section 1", inlineStyles: {} },
cardHeader: { value: "Card 2", inlineStyles: {} },
values: [
{
key: "key 1",
value: "value 1",
},
{
key: "key 2",
value: "value 2",
},
{
key: "key 3",
value: "value 3",
},
],
},
{
type: "DATA",
sectionHeader: { value: "Section 2", inlineStyles: { marginTop: "2rem" } },
// cardHeader:{value:"Card 1",inlineStyles:{}},
values: [
{
key: "key 1",
value: "value 1",
},
{
key: "key 2",
value: "value 2",
},
{
key: "key 3",
value: "value 3",
},
],
},
{
type: "DOCUMENTS",
documents: [
{
title: "WORKS_RELEVANT_DOCUMENTS",
BS: "Works",
values: [
{
title: "Proposal document",
documentType: "PROJECT_PROPOSAL",
documentUid: "cfed582b-31b0-42e9-985f-fb9bb4543670",
fileStoreId: "cfed582b-31b0-42e9-985f-fb9bb4543670",
},
{
title: "Finalised worklist",
documentType: "FINALIZED_WORKLIST",
documentUid: "f7543894-d3a1-4263-acb2-58b1383eebec",
fileStoreId: "f7543894-d3a1-4263-acb2-58b1383eebec",
},
{
title: "Feasibility analysis",
documentType: "FEASIBILITY_ANALYSIS",
documentUid: "c4fb4f5d-a4c3-472e-8991-e05bc2d671f5",
fileStoreId: "c4fb4f5d-a4c3-472e-8991-e05bc2d671f5",
},
],
},
],
inlineStyles: {
marginTop: "1rem",
},
},
{
type: "WFHISTORY",
businessService: "ESTIMATE",
applicationNo: "ES/2023-24/000828",
tenantId: "pg.citya",
timelineStatusPrefix: "TEST",
},
{
type: "WFACTIONS",
forcedActionPrefix: "TEST",
businessService: "ESTIMATE",
applicationNo: "ES/2023-24/000828",
tenantId: "pg.citya",
applicationDetails: {},
url: "/estimate/v1/_update",
moduleCode: "Estimate",
editApplicationNumber: undefined,
},
],
},
],
apiResponse:{},
additionalDetails:{}
} -->


4. Basically cards is an array of objects each representing a Card in the View Screen.
5. Each card can have multiple sections with the following types defined: [DATA,DOCUMENTS,WFHISTORY,WFACTIONS,COMPONENT]
6. We can render content based on these types defined.


#### Final Summary
1. Import ViewComposer
2. Write hook call that returns data expected by the ViewComposer
3. Pass in the data and isLoading props and Viola!





Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import React, { Fragment, useState } from "react";
import Card from "../../atoms/Card";
import { Loader } from "../../atoms/Loader";
import { RenderDataSection, RenderDocumentsSection, RenderWfActions, RenderWfHistorySection } from "./renderUtils";
import HorizontalNav from "../../atoms/HorizontalNav";
import CardSubHeader from "../../atoms/CardSubHeader";

// format of data expected by this component

// {
// cards:[
// {
// sections: [
// {
// type: "DATA",
// sectionHeader: { value: "Section 1", inlineStyles: {} },
// cardHeader: { value: "Card 2", inlineStyles: {} },
// values: [
// {
// key: "key 1",
// value: "value 1",
// },
// {
// key: "key 2",
// value: "value 2",
// },
// {
// key: "key 3",
// value: "value 3",
// },
// ],
// },
// {
// type: "DATA",
// sectionHeader: { value: "Section 2", inlineStyles: { marginTop: "2rem" } },
// // cardHeader:{value:"Card 1",inlineStyles:{}},
// values: [
// {
// key: "key 1",
// value: "value 1",
// },
// {
// key: "key 2",
// value: "value 2",
// },
// {
// key: "key 3",
// value: "value 3",
// },
// ],
// },
// {
// type: "DOCUMENTS",
// documents: [
// {
// title: "WORKS_RELEVANT_DOCUMENTS",
// BS: "Works",
// values: [
// {
// title: "Proposal document",
// documentType: "PROJECT_PROPOSAL",
// documentUid: "cfed582b-31b0-42e9-985f-fb9bb4543670",
// fileStoreId: "cfed582b-31b0-42e9-985f-fb9bb4543670",
// },
// {
// title: "Finalised worklist",
// documentType: "FINALIZED_WORKLIST",
// documentUid: "f7543894-d3a1-4263-acb2-58b1383eebec",
// fileStoreId: "f7543894-d3a1-4263-acb2-58b1383eebec",
// },
// {
// title: "Feasibility analysis",
// documentType: "FEASIBILITY_ANALYSIS",
// documentUid: "c4fb4f5d-a4c3-472e-8991-e05bc2d671f5",
// fileStoreId: "c4fb4f5d-a4c3-472e-8991-e05bc2d671f5",
// },
// ],
// },
// ],
// inlineStyles: {
// marginTop: "1rem",
// },
// },
// {
// type: "WFHISTORY",
// businessService: "ESTIMATE",
// applicationNo: "ES/2023-24/000828",
// tenantId: "pg.citya",
// timelineStatusPrefix: "TEST",
// },
// {
// type: "WFACTIONS",
// forcedActionPrefix: "TEST",
// businessService: "ESTIMATE",
// applicationNo: "ES/2023-24/000828",
// tenantId: "pg.citya",
// applicationDetails: {},
// url: "/estimate/v1/_update",
// moduleCode: "Estimate",
// editApplicationNumber: undefined,
// },
// ],
// },
// ],
// apiResponse:{},
// additionalDetails:{}
// }

const renderCardSectionJSX = (section) => {
const { type } = section;
switch (type) {
case "DATA":
return <RenderDataSection section={section} />;
case "DOCUMENTS":
return <RenderDocumentsSection section={section} />;
case "WFHISTORY":
return <RenderWfHistorySection section={section} />;
case "WFACTIONS":
return <RenderWfActions section={section} />;
case "COMPONENT":
const Component = Digit.ComponentRegistryService.getComponent(section.component);
return (
<>
{section.cardHeader && <CardSubHeader style={section?.cardHeader?.inlineStyles}>{section.cardHeader.value}</CardSubHeader>}
<Component {...section.props} />
</>
);
default:
return null;
}
};

//data is the response of the hook call for View Screen
const ViewComposer = ({ isLoading = false, data, ...props }) => {
const { cards } = data;
const [activeNav, setActiveNav] = useState(data?.horizontalNav?.activeByDefault);


if (isLoading) return <Loader />;

return (
<>
{/* This first {} is for rendering cards at the top without navigationKey(out of navbar) */}
{cards
?.filter((card) => !card?.navigationKey && card?.sections)
?.map((card, cardIdx) => {
const { sections } = card;
return (
<Card style={activeNav && card.navigationKey ? (activeNav !== card.navigationKey ? { display: "none" } : {}) : {}} className={"employeeCard-override"}>
{sections?.map((section, sectionIdx) => {
return renderCardSectionJSX(section);
})}
</Card>
);
})}
{/* This second section is for rendering cards that are part of the navBar) */}

<HorizontalNav
showNav={data?.horizontalNav?.showNav}
configNavItems={data?.horizontalNav?.configNavItems}
activeLink={activeNav}
setActiveLink={setActiveNav}
inFormComposer={false}
>
{cards
?.filter((card) => card?.navigationKey)
?.map((card, cardIdx) => {
const { sections } = card;
return (
<Card style={activeNav && card.navigationKey ? (activeNav !== card.navigationKey ? { display: "none" } : {}) : {}} className={"employeeCard-override"}>
{sections?.map((section, sectionIdx) => {
return renderCardSectionJSX(section);
})}
</Card>
);
})}
</HorizontalNav>
</>
);
};

export default ViewComposer;
Loading