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

FWF-4343:[Feature]-Client form listing page. #2576

Draft
wants to merge 9 commits into
base: develop
Choose a base branch
from
42 changes: 21 additions & 21 deletions forms-flow-web/src/apiManager/services/bpmFormServices.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,53 +11,53 @@ import {
import { replaceUrl } from "../../helper/helper";
import { setFormSearchLoading } from "../../actions/checkListActions";

export const fetchBPMFormList = (
export const fetchBPMFormList = ({
pageNo,
limit,
formSort,
formName,
formType,
showForOnlyCreateSubmissionUsers,
...rest
) => {
const done = rest.length ? rest[0] : () => { };
includeSubmissionsCount,
done = () => {},
}) => {
return (dispatch) => {
let sortBy = formSort.activeKey;
let sortOrder = formSort[sortBy].sortOrder ;
let url = `${API.FORM}?pageNo=${pageNo}&limit=${limit}&sortBy=${sortBy
}&sortOrder=${sortOrder}`;
if (formType) {
url += `&formType=${formType}`;
}
if (formName) {
url += `&search=${encodeURIComponent(formName)}`;
let sortBy = formSort.activeKey;
let sortOrder = formSort[sortBy]?.sortOrder;
let url = `${API.FORM}?pageNo=${pageNo}&limit=${limit}&sortBy=${sortBy}&sortOrder=${sortOrder}`;

const queryParams = [];

if (formType) queryParams.push(`formType=${formType}`);
if (formName) queryParams.push(`search=${encodeURIComponent(formName)}`);
if (typeof showForOnlyCreateSubmissionUsers === "boolean") {
queryParams.push(`showForOnlyCreateSubmissionUsers=${showForOnlyCreateSubmissionUsers}`);
}
if(showForOnlyCreateSubmissionUsers){
url += `&showForOnlyCreateSubmissionUsers=${showForOnlyCreateSubmissionUsers}`;
if (typeof includeSubmissionsCount === "boolean") {
queryParams.push(`includeSubmissionsCount=${includeSubmissionsCount}`);
}

const queryString = queryParams.length ? `&${queryParams.join("&")}` : "";
url += queryString;

RequestService.httpGETRequest(url, {}, StorageService.get(StorageService.User.AUTH_TOKEN))
.then((res) => {
if (res.data) {
if (res.data) {
dispatch(setBPMFormList(res.data));
dispatch(setBPMFormListLoading(false));
//dispatch(setBPMLoader(false));
dispatch(setBpmFormLoading(false));
dispatch(setFormSearchLoading(false));

done(null, res.data);
} else {
dispatch(setBPMFormListLoading(false));
//console.log("Error", res);
dispatch(serviceActionError(res));
dispatch(setFormSearchLoading(false));
//dispatch(setBPMTaskLoader(false));
}
})
.catch((error) => {
//console.log("Error", error);
dispatch(setBPMFormListLoading(false));
dispatch(serviceActionError(error));
//dispatch(setBPMTaskLoader(false));
done(error);
});
};
Expand Down
3 changes: 2 additions & 1 deletion forms-flow-web/src/apiManager/services/bpmServices.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ export const formatForms = (forms) => {
description:form.description,
created: form.created,
formType: form.formType,
modified:form.modified
modified:form.modified,
submissionsCount:form.submissionsCount
};
});
};
Expand Down
236 changes: 145 additions & 91 deletions forms-flow-web/src/components/Form/constants/ClientTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
MULTITENANCY_ENABLED,
} from "../../../constants/constants";
import { useTranslation, Translation } from "react-i18next";
import DOMPurify from "dompurify";
import DOMPurify from "dompurify";
import { TableFooter } from "@formsflow/components";
import LoadingOverlay from "react-loading-overlay-ts";
import SortableHeader from '../../CustomComponents/SortableHeader';
Expand All @@ -28,6 +28,7 @@ function ClientTable() {
const limit = useSelector((state) => state.bpmForms.limit);
const totalForms = useSelector((state) => state.bpmForms.totalForms);
const formsort = useSelector((state) => state.bpmForms.sort);
const [expandedRowIndex, setExpandedRowIndex] = useState(null);

const searchFormLoading = useSelector(
(state) => state.formCheckList.searchFormLoading
Expand All @@ -47,8 +48,19 @@ function ClientTable() {
{ text: "All", value: totalForms },
];

const handleSort = (key) => {
const newSortOrder = formsort[key].sortOrder === "asc" ? "desc" : "asc";
const stripHtml = (html) => {
let doc = new DOMParser().parseFromString(html, 'text/html');
return doc.body.textContent || "";
};

const handleKeyPress = (e, index) => {
if (e.key === "Enter" || e.key === " ") {
toggleRow(index);
}
};

const handleSort = (key) => {
const newSortOrder = formsort[key]?.sortOrder === "asc" ? "desc" : "asc";

// Reset all other columns to default (ascending) except the active one
const updatedSort = Object.keys(formsort).reduce((acc, columnKey) => {
Expand Down Expand Up @@ -107,118 +119,160 @@ function ClientTable() {
);
};

const extractContent = (htmlContent) => {
const sanitizedHtml = DOMPurify.sanitize(htmlContent);
const tempElement = document.createElement("div");
tempElement.innerHTML = sanitizedHtml;

// Get the text content from the sanitized HTML
const textContent = tempElement.textContent || tempElement.innerText || "";
return textContent;
const toggleRow = (index) => {
setExpandedRowIndex(prevIndex => prevIndex === index ? null : index);
};

function formatDate(isoString) {
const date = new Date(isoString);
const options = {
month: "short",
day: "numeric",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
hour12: true,
};
let formattedDate = date.toLocaleString("en-US", options);
return formattedDate.replace(/(\w{3}) (\d{1,2}), (\d{4}),/, "$1 $2, $3");
}

return (

<LoadingOverlay
active={searchFormLoading}
spinner
text={t("Loading...")}
>
<div>
<div className="table-responsive" style={{ maxHeight: "75vh", overflowY: "auto" }}>
<table className="table custom-table table-responsive-sm">
<thead>
<LoadingOverlay
active={searchFormLoading}
spinner
text={t("Loading...")}
>
<div className="min-height-400">
<div className="custom-tables-wrapper">
<table className="table custom-tables table-responsive-sm">
<thead className="table-header">
<tr>
<th className="col-3">
<th className="w-20">
<SortableHeader
columnKey="formName"
title="Form Name"
currentSort={formsort}
handleSort={handleSort}
className="d-flex justify-content-start"
columnKey="formName"
title="Form Name"
currentSort={formsort}
handleSort={handleSort}
className="gap-2"
/>
</th>
<th className="col-7">{t("Form Description")}</th>
<th className="col-2"></th>
<th className="w-30" scope="col">{t("Description")}</th>

<th className="w-13" scope="col">
<SortableHeader
columnKey="submissionCount"
title="Submissions"
currentSort={formsort}
handleSort={handleSort}
className="gap-2" />
</th>

<th className="w-13" scope="col">
<SortableHeader
columnKey="modified"
title={t("Latest Submission")}
currentSort={formsort}
handleSort={handleSort}
className="gap-2" />
</th>
<th className="w-12" colSpan="4" aria-label="Select a Form"></th>
</tr>
</thead>
{formData?.length ? (
<tbody>
{formData.map((e, index) => (
<React.Fragment key={index}>
<tr>
<td className="col-3">
<span
data-testid={`form-title-${e._id}`}
className="mt-2"
>
{e.title}
</span>
</td>
<td
data-testid={`form-description${e._id}`} className="col-7">
{extractContent(e.description)}
</td>

<td className="col-2">
<button
data-testid={`form-submit-button-${e._id}`}
className="btn btn-primary"
onClick={() => submitNewForm(e._id)}
>
<Translation>{(t) => t("Submit New")}</Translation>
</button>
</td>
</tr>

{index === openIndex && (
{formData.map((e, index) => {
const isExpanded = expandedRowIndex === index;
return (
<React.Fragment key={index}>
<tr>
<td colSpan={10}>
<div className="bg-white p-3">
<h4>
<strong>{t("Form Description")}</strong>
</h4>

<div
className="form-description-p-tag "
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(e?.description, {
ADD_ATTR: ["target"],
}),
}}
/>
<td className="w-20">
<span
data-testid={`form-title-${e._id}`}
className="mt-2 text-container"
>
{e.title}
</span>
</td>
<td className="w-30">
<span
className={` cursor-pointer ${isExpanded ? "text-container-expand" : "text-container"}`}
role="button"
tabIndex="0"
aria-expanded={isExpanded} // Adds accessibility
onClick={() => toggleRow(index)}
onKeyDown={(e) => handleKeyPress(e, index)}
>
{stripHtml(e.description ? e.description : "")}
</span>
</td>
<td
data-testid={`Submissions-count-${e._id}`} className="w-13">
{e.submissionsCount}
</td>
<td
data-testid={`latest-submission-${e._id}`} className="w-13">
{formatDate(e.modified)}
</td>

<td className=" w-12 ">
<div className="d-flex justify-content-end">
<button
data-testid={`form-submit-button-${e._id}`}
className="btn btn-secondary btn-table"
onClick={() => submitNewForm(e._id)}
>
<Translation>{(t) => t("Select")}</Translation>
</button>
</div>
</td>
</tr>
)}
</React.Fragment>
))}

{index === openIndex && (
<tr>
<td colSpan={10}>
<div className="bg-white p-3">
<h4>
<strong>{t("Form Description")}</strong>
</h4>

<div
className="form-description-p-tag "
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(e?.description, {
ADD_ATTR: ["target"],
}),
}}
/>
</div>
</td>
</tr>
)}
</React.Fragment>
);
})}
{formData.length ? (
<TableFooter
limit={limit}
activePage={pageNo}
totalCount={totalForms}
handlePageChange={handlePageChange}
onLimitChange={onSizePerPageChange}
pageOptions={pageOptions}
/>
) : (
<td colSpan={3}></td>
)}
</tbody>
) : !searchFormLoading ? (
noDataFound()
) : (
null
)}
</table>
</div>
</div>

{formData.length ? (
<table className="table">
<tfoot>
<TableFooter
limit={limit}
activePage={pageNo}
totalCount={totalForms}
handlePageChange={handlePageChange}
onLimitChange={onSizePerPageChange}
pageOptions={pageOptions}
/>
</tfoot>
</table>
) : null}
</LoadingOverlay>
</div>
</LoadingOverlay>

);
}
Expand Down
4 changes: 2 additions & 2 deletions forms-flow-web/src/routes/Design/Forms/List.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,9 @@ const List = React.memo((props) => {
}, []);

const fetchForms = () => {
let filters = [pageNo, limit, formSort, searchText];
let filters = {pageNo, limit, formSort, searchText};
dispatch(setFormSearchLoading(true));
dispatch(fetchBPMFormList(...filters));
dispatch(fetchBPMFormList({...filters}));
};
const onClose = () => {
setNewFormModal(false);
Expand Down
Loading
Loading