Skip to content

Commit

Permalink
Add service request history to asset (#5417)
Browse files Browse the repository at this point in the history
* add service request history to asset

* Add edit history

* change api routes

* Fix "note" key
  • Loading branch information
Ashesh3 authored Aug 25, 2023
1 parent edc0705 commit 8277753
Show file tree
Hide file tree
Showing 16 changed files with 479 additions and 43 deletions.
4 changes: 2 additions & 2 deletions src/Components/Assets/AssetImportModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ const AssetImportModal = ({ open, onClose, facility }: Props) => {
manufacturer: asset.manufacturer,
meta: { ...asset.meta },
warranty_amc_end_of_validity: asset.warranty_amc_end_of_validity,
last_serviced_on: asset.last_serviced_on,
notes: asset.notes,
last_serviced_on: asset.last_service.serviced_on,
note: asset.last_service.note,
cancelToken: { promise: {} },
});

Expand Down
161 changes: 151 additions & 10 deletions src/Components/Assets/AssetManage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import {
AssetClass,
assetClassProps,
AssetData,
AssetService,
AssetTransaction,
} from "./AssetTypes";
import { statusType, useAbortableEffect } from "../../Common/utils";
import { useDispatch } from "react-redux";
import {
deleteAsset,
getAsset,
listAssetService,
listAssetTransaction,
} from "../../Redux/actions";
import Pagination from "../Common/Pagination";
Expand All @@ -30,6 +32,9 @@ import * as Notification from "../../Utils/Notifications.js";
import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor";
import Uptime from "../Common/Uptime";
import useAuthUser from "../../Common/hooks/useAuthUser";
import dayjs from "dayjs";
import RelativeDateUserMention from "../Common/RelativeDateUserMention";
import { AssetServiceEditModal } from "./AssetServiceEditModal";

interface AssetManageProps {
assetId: string;
Expand All @@ -54,11 +59,18 @@ const AssetManage = (props: AssetManageProps) => {
const [transactionDetails, setTransactionDetails] = useState<
ReactElement | ReactElement[]
>();
const [services, setServices] = useState<AssetService[]>([]);
const [servicesDetails, setServiceDetails] = useState<
ReactElement | ReactElement[]
>();
const [isLoading, setIsLoading] = useState<boolean>(false);
const dispatch = useDispatch<any>();
const limit = 14;
const authUser = useAuthUser();
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
const [serviceEditData, setServiceEditData] = useState<
AssetService & { open: boolean; viewOnly?: boolean }
>();

const fetchData = useCallback(
async (status: statusType) => {
Expand All @@ -73,13 +85,17 @@ const AssetManage = (props: AssetManageProps) => {
? { qr_code_id: assetData.qr_code_id }
: { external_id: assetId };

const transactionsData = await dispatch(
listAssetTransaction({
...transactionFilter,
limit,
offset,
})
);
const [transactionsData, servicesData] = await Promise.all([
dispatch(
listAssetTransaction({
...transactionFilter,
limit,
offset,
})
),
dispatch(listAssetService({}, assetId)),
]);

if (transactionsData?.data) {
setTransactions(transactionsData.data.results);
setTotalCount(transactionsData.data.count);
Expand All @@ -88,6 +104,13 @@ const AssetManage = (props: AssetManageProps) => {
msg: "Error fetching transactions",
});
}
if (servicesData?.data) {
setServices(servicesData.data.results);
} else {
Notification.Error({
msg: "Error fetching service logs",
});
}
} else {
navigate("/not-found");
}
Expand Down Expand Up @@ -174,10 +197,89 @@ const AssetManage = (props: AssetManageProps) => {
}
};

const populateServiceTableRows = (txns: AssetService[]) => {
if (txns.length > 0) {
setServiceDetails(
services.map((service: AssetService) => (
<tr key={`service_id_${service.id}`}>
<td className="whitespace-nowrap px-6 py-4 text-center text-sm leading-5 text-gray-500">
<span className="font-medium text-gray-900">
{dayjs(service.serviced_on).format("DD MMM YYYY")}
</span>
</td>
<td className="whitespace-nowrap px-6 py-4 text-center text-sm leading-5 text-gray-500">
<span className="whitespace-break-spaces break-words font-medium text-gray-900">
{service.note || "--"}
</span>
</td>
<td className="whitespace-nowrap px-6 py-4 text-center text-sm leading-5 text-gray-500">
<span className="font-medium text-gray-900">
{formatDate(service.created_date)}
</span>
</td>
<td className="whitespace-nowrap px-6 py-4 text-center text-sm leading-5 text-gray-500">
<span className="flex justify-center font-medium text-gray-900">
{service.edits?.length > 1 ? (
<RelativeDateUserMention
actionDate={service.edits?.[0]?.edited_on}
user={service.edits?.[0]?.edited_by}
/>
) : (
"--"
)}
</span>
</td>
<td className="gap-4 whitespace-nowrap px-6 py-4 text-left text-sm leading-5">
<ButtonV2
authorizeFor={NonReadOnlyUsers}
onClick={() => {
setServiceEditData({ ...service, open: true });
}}
className="mr-2"
>
<CareIcon icon="l-pen" className="text-lg" />
</ButtonV2>
<ButtonV2
authorizeFor={NonReadOnlyUsers}
tooltip={service.edits?.length < 2 ? "No previous edits" : ""}
tooltipClassName="tooltip-left"
disabled={service.edits?.length < 2}
onClick={() => {
setServiceEditData({
...service,
open: true,
viewOnly: true,
});
}}
>
<CareIcon icon="l-eye" className="text-lg" />
</ButtonV2>
</td>
</tr>
))
);
} else {
setServiceDetails(
<tr>
<td
className="whitespace-nowrap px-6 py-4 text-center text-sm leading-5 text-gray-500"
colSpan={4}
>
<h5>No Service Logs Found</h5>
</td>
</tr>
);
}
};

useEffect(() => {
populateTableRows(transactions);
}, [transactions]);

useEffect(() => {
populateServiceTableRows(services);
}, [services]);

if (isLoading) return <Loading />;
if (isPrintMode) return <PrintPreview />;

Expand Down Expand Up @@ -378,13 +480,13 @@ const AssetManage = (props: AssetManageProps) => {
label: "Last serviced on",
icon: "wrench",
content:
asset?.last_serviced_on &&
formatDate(asset?.last_serviced_on),
asset?.last_service?.serviced_on &&
formatDate(asset?.last_service?.serviced_on),
},
{
label: "Notes",
icon: "notes",
content: asset?.notes,
content: asset?.last_service?.note,
},
].map(detailBlock)}
</div>
Expand All @@ -409,6 +511,33 @@ const AssetManage = (props: AssetManageProps) => {
{asset?.id &&
asset?.asset_class &&
asset?.asset_class != AssetClass.NONE && <Uptime assetId={asset?.id} />}
<div className="mb-4 mt-8 text-xl font-semibold">Service History</div>
<div className="min-w-full overflow-hidden overflow-x-auto align-middle shadow sm:rounded-lg">
<table className="min-w-full divide-y divide-gray-200">
<thead>
<tr>
<th className="bg-gray-50 px-6 py-3 text-center text-xs font-medium uppercase leading-4 tracking-wider text-gray-500">
Serviced on
</th>
<th className="bg-gray-50 px-6 py-3 text-center text-xs font-medium uppercase leading-4 tracking-wider text-gray-500">
Note
</th>
<th className="bg-gray-50 px-6 py-3 text-center text-xs font-medium uppercase leading-4 tracking-wider text-gray-500">
Created on
</th>
<th className="bg-gray-50 px-6 py-3 text-center text-xs font-medium uppercase leading-4 tracking-wider text-gray-500">
Last Updated
</th>
<th className="bg-gray-50 px-6 py-3 text-center text-xs font-medium uppercase leading-4 tracking-wider text-gray-500">
Edit
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200 bg-white">
{servicesDetails}
</tbody>
</table>
</div>
<div className="mb-4 mt-8 text-xl font-semibold">Transaction History</div>
<div className="min-w-full overflow-hidden overflow-x-auto align-middle shadow sm:rounded-lg">
<table className="min-w-full divide-y divide-gray-200">
Expand Down Expand Up @@ -443,6 +572,18 @@ const AssetManage = (props: AssetManageProps) => {
/>
</div>
)}
{serviceEditData && (
<AssetServiceEditModal
asset={asset}
service_record={serviceEditData}
handleClose={() =>
setServiceEditData({ ...serviceEditData, open: false })
}
handleUpdate={() => fetchData({ aborted: false })}
show={serviceEditData.open}
viewOnly={serviceEditData.viewOnly}
/>
)}
</div>
);
};
Expand Down
Loading

0 comments on commit 8277753

Please sign in to comment.