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

Added Timeline UI for Bed Activity #6901

Merged
merged 48 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
f86db24
BedActivityTimeline component added
thedevildude Dec 23, 2023
2e98352
In Use indicator added to BedActivityTimeLine
thedevildude Dec 24, 2023
e0544c5
Merge branch 'develop' into fix#6771
thedevildude Dec 24, 2023
032f061
fixed deepscan failure due to missing key prop
thedevildude Dec 24, 2023
6fc492e
UI revision | reduced IN USE size | created BedTitleSuffix component
thedevildude Dec 25, 2023
4c7efb1
moved BedActivityTimeline one level up
thedevildude Dec 25, 2023
37d5f2f
Merge branch 'develop' into fix#6771
thedevildude Dec 31, 2023
25bfea0
Merge branch 'develop' into fix#6771
thedevildude Jan 6, 2024
a61ae30
Merge branch 'develop' into fix#6771
thedevildude Jan 13, 2024
d3c1a9f
Merge branch 'develop' into fix#6771
thedevildude Jan 20, 2024
9c32733
Merge branch 'develop' into fix#6771
thedevildude Jan 31, 2024
fb9ba13
Timeline note accepts react node | Bed timeline ui changed
thedevildude Jan 31, 2024
ac487c5
Merge branch 'develop' into fix#6771
thedevildude Feb 6, 2024
96f3f5d
Merge branch 'develop' into fix#6771
thedevildude Feb 15, 2024
2b148ba
Merge branch 'develop' into fix#6771
thedevildude Feb 20, 2024
7af1dcc
improved logic for showing asset changes
thedevildude Feb 20, 2024
f684c83
Merge branch 'develop' into fix#6771
thedevildude Feb 22, 2024
6cf66f8
moved all input fields to one row
thedevildude Feb 22, 2024
a45f0fe
changed in use badge color
thedevildude Feb 22, 2024
68f6148
Merge branch 'develop' into fix#6771
thedevildude Feb 27, 2024
6f3b397
Merge branch 'develop' into fix#6771
thedevildude Mar 5, 2024
8576acd
Merge branch 'develop' into fix#6771
thedevildude Mar 8, 2024
67acf1f
Introduced i button popover to BedActivityTimeline
thedevildude Mar 8, 2024
6ca4811
Added Asset diffing function
thedevildude Mar 8, 2024
a007d21
minor css change
thedevildude Mar 11, 2024
2a5600c
Merge branch 'develop' into fix#6771
thedevildude Mar 12, 2024
5c65689
added icons for adding and removing asset
thedevildude Mar 12, 2024
64b6227
no assets linked text added
thedevildude Mar 12, 2024
a569bac
Merge branch 'develop' into fix#6771
thedevildude Mar 14, 2024
1a201b2
moved input fields back to different lines
thedevildude Mar 14, 2024
dd5fb56
changed in use bed timeline node icon to l-bed
thedevildude Mar 14, 2024
ff05af3
added missing key props to map objects
thedevildude Mar 14, 2024
324765e
Merge branch 'develop' into fix#6771
thedevildude Mar 16, 2024
f5de85d
Merge branch 'develop' into fix#6771
thedevildude Mar 20, 2024
70ae129
added icon style customizability for Timeline Node
thedevildude Mar 20, 2024
58d2d1e
fixed null value error
thedevildude Mar 20, 2024
693a482
icon color changed for first node
thedevildude Mar 20, 2024
635abba
added divider between form and timeline | moved button to right
thedevildude Mar 21, 2024
109ba66
Merge branch 'develop' into fix#6771
thedevildude Apr 4, 2024
e82cf99
Refactor BedAllocationNode and BedTimelineAsset components
thedevildude Apr 4, 2024
506ba0c
Merge branch 'develop' into fix#6771
nihal467 Apr 8, 2024
13de128
Merge branch 'develop' into fix#6771
thedevildude Apr 16, 2024
ad7dfd5
fixed linting
thedevildude Apr 17, 2024
f1eeb29
Merge branch 'develop' into fix#6771
thedevildude Apr 17, 2024
97acb93
fixed linting
thedevildude Apr 18, 2024
3c490bc
Merge branch 'develop' into fix#6771
thedevildude Apr 21, 2024
b43b1fa
Merge branch 'develop' into fix#6771
nihal467 Apr 23, 2024
b4afe28
minor fixes based on review
rithviknishad Apr 24, 2024
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
16 changes: 13 additions & 3 deletions src/CAREUI/display/Timeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ export interface TimelineEvent<TType = string> {
timestamp: string;
by: PerformedByModel | undefined;
icon: IconName;
notes?: string;
iconStyle?: string;
iconWrapperStyle?: string;
notes?: string | React.ReactNode;
cancelled?: boolean;
}

Expand Down Expand Up @@ -126,9 +128,17 @@ interface TimelineNodeTitleProps {
export const TimelineNodeTitle = (props: TimelineNodeTitleProps) => {
return (
<>
<div className="relative flex h-6 w-6 flex-none items-center justify-center rounded-full bg-gray-200 transition-all duration-200 ease-in-out group-hover:bg-primary-500">
<div
className={classNames(
props.event.iconWrapperStyle,
"relative flex h-6 w-6 flex-none items-center justify-center rounded-full bg-gray-200 transition-all duration-200 ease-in-out group-hover:bg-primary-500",
)}
>
<CareIcon
className="text-base text-gray-700 transition-all duration-200 ease-in-out group-hover:text-white"
className={classNames(
props.event.iconStyle,
"text-base text-gray-700 transition-all duration-200 ease-in-out group-hover:text-white",
)}
aria-hidden="true"
icon={props.event.icon}
/>
Expand Down
260 changes: 260 additions & 0 deletions src/Components/Facility/Consultations/BedActivityTimeline.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
import Chip from "../../../CAREUI/display/Chip";
import Timeline, {
TimelineEvent,
TimelineNode,
TimelineNodeTitle,
} from "../../../CAREUI/display/Timeline";
import CareIcon from "../../../CAREUI/icons/CareIcon";
import { classNames, formatDateTime, relativeTime } from "../../../Utils/utils";
import { AssetData } from "../../Assets/AssetTypes";
import { CurrentBed } from "../models";
import { Popover, Transition } from "@headlessui/react";
import { Fragment } from "react";

interface AssetDiff {
newlyLinkedAssets: AssetData[];
existingAssets: AssetData[];
unlinkedAssets: AssetData[];
}

const getAssetDiff = (a: AssetData[], b: AssetData[]): AssetDiff => {
const newlyLinkedAssets: AssetData[] = [];
const existingAssets: AssetData[] = [];
const unlinkedAssets: AssetData[] = [];

const bMap: Map<string, AssetData> = new Map();
b.forEach((asset) => bMap.set(asset.id, asset));
a.forEach((asset) => {
if (!bMap.has(asset.id)) {
unlinkedAssets.push(asset);
} else {
existingAssets.push(asset);
}
});
b.forEach((asset) => {
if (!a.find((aAsset) => aAsset.id === asset.id)) {
newlyLinkedAssets.push(asset);
}
});

return {
newlyLinkedAssets,
existingAssets,
unlinkedAssets,
};
};

interface Props {
consultationBeds: CurrentBed[];
loading?: boolean;
}

export default function BedActivityTimeline({
consultationBeds,
loading,
}: Props) {
return (
<>
<Timeline
className={classNames(
"py-4 md:px-3",
loading && "animate-pulse opacity-70",
)}
name="bed-allocation"
>
{consultationBeds.map((bed, index) => {
return (
<BedAllocationNode
key={`activity-${bed.id}`}
bed={bed}
prevBed={consultationBeds[index + 1] ?? undefined}
isLastNode={index === consultationBeds.length - 1}
/>
);
})}
</Timeline>
</>
);
}

const BedAllocationNode = ({
bed,
prevBed,
isLastNode,
}: {
bed: CurrentBed;
prevBed?: CurrentBed;
isLastNode: boolean;
}) => {
const { newlyLinkedAssets, existingAssets, unlinkedAssets } = getAssetDiff(
prevBed?.assets_objects ?? [],
bed.assets_objects ?? [],
);
const event: TimelineEvent = {
type: "allocated",
timestamp: bed.start_date,
by: undefined,
icon: "l-bed",
iconWrapperStyle: bed.end_date === null ? "bg-green-500" : "",
iconStyle: bed.end_date === null ? "text-white" : "",
notes:
newlyLinkedAssets.length === 0 &&
existingAssets.length === 0 &&
unlinkedAssets.length === 0 ? (
""
) : (
<BedTimelineAsset
newlyLinkedAssets={newlyLinkedAssets}
existingAssets={existingAssets}
unlinkedAssets={unlinkedAssets}
/>
),
};

return (
<>
<TimelineNode
name="bed"
event={event}
title={
<BedTimelineNodeTitle
event={event}
titleSuffix={<BedTitleSuffix bed={bed} prevBed={prevBed} />}
bed={bed}
/>
}
isLast={isLastNode}
/>
</>
);
};

const BedTimelineAsset = ({
newlyLinkedAssets,
existingAssets,
unlinkedAssets,
}: {
newlyLinkedAssets: AssetData[];
existingAssets: AssetData[];
unlinkedAssets: AssetData[];
}) => {
return (
<div className="flex flex-col gap-1">
<p className="text-md font-semibold">Assets</p>
{newlyLinkedAssets.length === 0 &&
existingAssets.length === 0 &&
unlinkedAssets.length === 0 && (
<p className="text-gray-500">No assets linked</p>
)}
{newlyLinkedAssets.length > 0 &&
newlyLinkedAssets.map((newAsset) => (
<div key={newAsset.id} className="flex gap-1 text-primary">
<CareIcon icon="l-plus-circle" />
<span>{newAsset.name}</span>
</div>
))}
{existingAssets.length > 0 &&
existingAssets.map((existingAsset) => (
<div key={existingAsset.id} className="flex gap-1">
<CareIcon icon="l-check-circle" />
<span>{existingAsset.name}</span>
</div>
))}
{unlinkedAssets.length > 0 &&
unlinkedAssets.map((unlinkedAsset) => (
<div key={unlinkedAsset.id} className="flex gap-1 text-gray-500">
<CareIcon icon="l-minus-circle" />
<span className="line-through">{unlinkedAsset.name}</span>
</div>
))}
</div>
);
};

const BedTimelineNodeTitle = (props: {
event: TimelineEvent;
titleSuffix: React.ReactNode;
bed: CurrentBed;
}) => {
const { event, titleSuffix, bed } = props;

return (
<TimelineNodeTitle event={event}>
<div className="flex w-full justify-between gap-2">
<p className="flex-auto py-0.5 text-xs leading-5 text-gray-600 md:w-2/3">
{titleSuffix}
</p>
<div className="md:w-fit">
<BedActivityIButtonPopover bed={bed} />
</div>
</div>
</TimelineNodeTitle>
);
};

const BedTitleSuffix = ({
bed,
prevBed,
}: {
bed: CurrentBed;
isLastNode?: boolean;
prevBed?: CurrentBed;
}) => {
return (
<div className="flex flex-col">
<div className="flex gap-x-2">
<span>{formatDateTime(bed.start_date).split(";")[0]}</span>
<span className="text-gray-500">-</span>
<span>{formatDateTime(bed.start_date).split(";")[1]}</span>
</div>
<p>
{bed.bed_object.id === prevBed?.bed_object.id
? "Asset changed in" + " "
: "Transferred to" + " "}
<span className="font-semibold">{`${bed.bed_object.name} (${bed.bed_object.bed_type}) in ${bed.bed_object.location_object?.name}`}</span>
{bed.end_date === null && (
<Chip
text="In Use"
startIcon="l-notes"
size="small"
variant="primary"
className="ml-5"
/>
)}
</p>
</div>
);
};

const BedActivityIButtonPopover = ({
bed,
}: {
event?: TimelineEvent;
bed?: CurrentBed;
}) => {
return (
<Popover className="relative text-sm text-gray-500 md:text-base">
<Popover.Button>
<CareIcon
icon="l-info-circle"
className="cursor-pointer text-gray-500 hover:text-gray-600"
/>
</Popover.Button>
<Transition
as={Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Popover.Panel className="absolute z-10 -ml-20 mt-2 w-48 -translate-x-1/2 rounded-lg border border-gray-200 bg-gray-100 p-2 shadow">
<p className="text-xs text-gray-600">
updated {relativeTime(bed?.start_date)}
</p>
</Popover.Panel>
</Transition>
</Popover>
);
};
Loading
Loading