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

[WIP] Integrate LiveKit for doctor connect #5147

Closed
wants to merge 3 commits into from
Closed
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
707 changes: 692 additions & 15 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"coronasafe Contributors"
],
"homepage": "https://care.coronasafe.in",
"proxy": "https://careapi.coronasafe.in",
"proxy": "http://127.0.0.1:8000",
"main": "./src/index.tsx",
"keywords": [
"Coronasafe",
Expand All @@ -35,6 +35,8 @@
"@googlemaps/react-wrapper": "^1.1.35",
"@googlemaps/typescript-guards": "^2.0.0",
"@headlessui/react": "^1.7.3",
"@livekit/components-react": "^0.4.1",
"@livekit/react-components": "^1.1.0",
"@loadable/component": "^5.15.0",
"@material-ui/core": "^4.11.4",
"@material-ui/lab": "^4.0.0-alpha.58",
Expand Down Expand Up @@ -68,6 +70,7 @@
"i18next": "^22.0.6",
"i18next-browser-languagedetector": "^7.0.0",
"libphonenumber-js": "^1.10.13",
"livekit-client": "^1.6.8",
"lodash": "^4.17.21",
"moment": "^2.29.4",
"postcss-loader": "^7.0.2",
Expand Down
81 changes: 81 additions & 0 deletions src/Common/LiveKit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { LiveKitRoom } from "@livekit/react-components";
import "@livekit/react-components/dist/index.css";
import { useEffect, useState } from "react";
import ButtonV2 from "../Components/Common/components/ButtonV2";
import { getLiveKitToken } from "../Redux/actions";
import { Error } from "../Utils/Notifications";
import { useDispatch } from "react-redux";

export const LiveKit = (props: {
sourceUsername: string;
targetUsername: string;
}) => {
const dispatch = useDispatch<any>();
const [status, setStatus] = useState("Disconnected");
const [connect, setConnect] = useState(false);
const [token, setToken] = useState("");

const getToken = async () => {
const tokenData = await dispatch(
getLiveKitToken({
source: props.sourceUsername,
target: props.targetUsername,
})
);
if (tokenData) {
setToken(tokenData.access);
console.log(tokenData);
} else {
Error({
msg: "Error fetching token",
});
}
};

useEffect(() => {
async function fetchData() {
getToken();
}
fetchData();
}, []);

return (
<div className="roomContainer">
<p className="text-md">Welcome {props.sourceUsername} !</p>
<p className="font-semibold text-md my-4">
Status:{" "}
<span
className={status === "Connected" ? "text-green-600" : "text-red-500"}
>
{status}
</span>
</p>
<ButtonV2
onClick={() => {
setConnect(!connect);
if (status != "Connected") {
setStatus("Connecting...");
} else {
setStatus("Disconnected");
}
}}
variant={status === "Connected" ? "danger" : "primary"}
>
{status === "Connected" ? "Disconnect" : "Connect"}
</ButtonV2>
{connect && token && (
<LiveKitRoom
token={token}
url="wss://livekit.ohc.network"
onConnected={() => {
setStatus("Connected");
}}
onLeave={() => {
setStatus("Disconnected");
setConnect(false);
}}
/>
)}
</div>
);
};
60 changes: 60 additions & 0 deletions src/Components/Facility/DoctorLiveConnect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { useState, useEffect } from "react";

import loadable from "@loadable/component";
import { useDispatch, useSelector } from "react-redux";
import { getFacilityUsers } from "../../Redux/actions";
const PageTitle = loadable(() => import("../Common/PageTitle"));
import { LiveKit } from "../../Common/LiveKit";
import { get } from "lodash";

const DoctorLiveConnect = (props: { facilityId: string; userId: string }) => {
const { facilityId, userId } = props;
const [user, setUser] = useState<any>(null);
const { currentUser } = useSelector((state) => state) as any;

const dispatchAction: any = useDispatch();
useEffect(() => {
const fetchUsers = async () => {
if (facilityId) {
const res = await dispatchAction(getFacilityUsers(facilityId));
if (res && res.data) {
setUser(res.data.results.find((user: any) => user.id == userId));
}
} else {
setUser(null);
}
};
fetchUsers();
}, [facilityId]);

return (
user && (
<div className="px-2 pb-2">
<PageTitle title="Doctor Live Connect" />
<div className="flex flex-col xl:flex-row gap-8">
<div className="bg-white rounded-lg md:rounded-xl w-full flex service-panel">
<div className="w-full md:p-8 md:pt-6 p-6 pt-4 flex flex-col justify-between gap-6">
<div>
<div className="flex flex-wrap items-center gap-2 justify-between w-full">
<div className="flex items-center gap-3">
<span className="text-2xl md:text-3xl font-bold break-words">
Connect to Doctor {user.first_name} {user.last_name}
</span>
</div>
</div>
<div className="mt-8">
<LiveKit
sourceUsername={get(currentUser, "data.username", "")}
targetUsername={user.username}
/>
</div>
</div>
</div>
</div>
</div>
</div>
)
);
};

export default DoctorLiveConnect;
23 changes: 21 additions & 2 deletions src/Components/Facility/DoctorVideoSlideover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getFacilityUsers } from "../../Redux/actions";
import { UserAssignedModel } from "../Users/models";
import { SkillObjectModel } from "../Users/models";
import CareIcon from "../../CAREUI/icons/CareIcon";
import { Link } from "raviger";

export default function DoctorVideoSlideover(props: {
show: boolean;
Expand Down Expand Up @@ -85,7 +86,13 @@ export default function DoctorVideoSlideover(props: {
);
})
.map((doctor) => {
return <UserListItem key={doctor.id} user={doctor} />;
return (
<UserListItem
key={doctor.id}
user={doctor}
facilityId={facilityId}
/>
);
})}
</ul>
</div>
Expand All @@ -94,7 +101,7 @@ export default function DoctorVideoSlideover(props: {
);
}

function UserListItem(props: { user: UserAssignedModel }) {
function UserListItem(props: { user: UserAssignedModel; facilityId: string }) {
const user = props.user;
const icon =
user.user_type === "Doctor" ? "fa-user-doctor " : " fa-user-nurse";
Expand Down Expand Up @@ -144,6 +151,18 @@ function UserListItem(props: { user: UserAssignedModel }) {
{user.first_name} {user.last_name}
</span>
<div className="flex gap-2">
<Link
href={`/facility/${props.facilityId}/live_connect/${user.id}/`}
target="_blank"
rel="noopener noreferrer"
>
<div className="tooltip">
<span className="tooltip-text tooltip-left">
Connect on Care
</span>
<CareIcon className="care-l-video w-5 h-5" />
</div>
</Link>
<a
href={
user.alt_phone_number
Expand Down
4 changes: 4 additions & 0 deletions src/Redux/actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -911,3 +911,7 @@ export const HCXActions = {
return fireRequest("hcxMakeClaim", [], { claim });
},
};

export const getLiveKitToken = (params: object) => {
return fireRequest("getLiveKitToken", [], params);
};
5 changes: 5 additions & 0 deletions src/Redux/api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,11 @@ const routes: Routes = {
path: "/api/v1/hcx/make_claim/",
method: "POST",
},

getLiveKitToken: {
path: "/api/v1/livekit/get_token/",
method: "POST",
},
};

export default routes;
5 changes: 5 additions & 0 deletions src/Router/AppRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ import { UpdateFacilityMiddleware } from "../Components/Facility/UpdateFacilityM
import useConfig from "../Common/hooks/useConfig";
import ConsultationClaims from "../Components/Facility/ConsultationClaims";
import { handleSignOut } from "../Utils/utils";
import DoctorLiveConnect from "../Components/Facility/DoctorLiveConnect";

export default function AppRouter() {
const { static_black_logo, enable_hcx } = useConfig();
Expand Down Expand Up @@ -394,6 +395,10 @@ export default function AppRouter() {
tab={tab}
/>
),
"/facility/:facilityId/live_connect/:userId": ({
facilityId,
userId,
}: any) => <DoctorLiveConnect facilityId={facilityId} userId={userId} />,
"/not-found": () => <Error404 />,
};

Expand Down
4 changes: 4 additions & 0 deletions src/style/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ body {
@apply font-sans text-gray-900 w-full h-full antialiased;
}

.react-tiny-popover-container {
color: white !important;
}

h1,
h2,
h3,
Expand Down