Skip to content

Commit

Permalink
Add weekly working hours field for users (#5981)
Browse files Browse the repository at this point in the history
* Add weekly working hours field for users

* UI fixes
  • Loading branch information
Ashesh3 authored Aug 3, 2023
1 parent 802f5e8 commit 9249158
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 37 deletions.
136 changes: 117 additions & 19 deletions src/Components/Users/ManageUsers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { useCallback, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";

import { AdvancedFilterButton } from "../../CAREUI/interactive/FiltersSlideover";
import ButtonV2 from "../Common/components/ButtonV2";
import ButtonV2, { Submit } from "../Common/components/ButtonV2";
import CareIcon from "../../CAREUI/icons/CareIcon";
import ConfirmHomeFacilityUpdateDialog from "./ConfirmHomeFacilityUpdateDialog";
import CountBlock from "../../CAREUI/display/Count";
Expand All @@ -36,6 +36,7 @@ import useFilters from "../../Common/hooks/useFilters";
import useWindowDimensions from "../../Common/hooks/useWindowDimensions";
import CircularProgress from "../Common/components/CircularProgress.js";
import Page from "../Common/components/Page.js";
import TextFormField from "../Form/FormFields/TextFormField.js";

const Loading = loadable(() => import("../Common/Loading"));

Expand All @@ -59,10 +60,12 @@ export default function ManageUsers() {
const [districtName, setDistrictName] = useState<string>();
const [expandFacilityList, setExpandFacilityList] = useState(false);
const [selectedUser, setSelectedUser] = useState<any | null>(null);
const [expandWorkingHours, setExpandWorkingHours] = useState(false);
const state: any = useSelector((state) => state);
const { currentUser } = state;
const isSuperuser = currentUser.data.is_superuser;
const userType = currentUser.data.user_type;
const [weeklyHours, setWeeklyHours] = useState<any>(0);
const userIndex = USER_TYPES.indexOf(userType);
const userTypes = isSuperuser
? [...USER_TYPES]
Expand Down Expand Up @@ -143,6 +146,30 @@ export default function ManageUsers() {
setUserData({ show: false, username: "", name: "" });
};

const handleWorkingHourSubmit = async () => {
const username = selectedUser;
if (!username || weeklyHours < 0 || weeklyHours > 168) return;
const res = await dispatch(
partialUpdateUser(username, {
weekly_working_hours: weeklyHours,
})
);

if (res?.data) {
Notification.Success({
msg: "Working hours updated successfully",
});
setExpandWorkingHours(false);
setSelectedUser(null);
} else {
Notification.Error({
msg: "Error while updating working hours: " + (res.data.detail || ""),
});
}
setWeeklyHours(0);
fetchData({ aborted: false });
};

const handleSubmit = async () => {
const username = userData.username;
const res = await dispatch(deleteUser(username));
Expand Down Expand Up @@ -194,10 +221,13 @@ export default function ManageUsers() {
id={`usr_${idx}`}
className=" mt-6 w-full md:px-4 lg:w-1/2 xl:w-1/3"
>
<div className="relative block h-full cursor-pointer overflow-visible rounded-lg bg-white shadow hover:border-primary-500">
<div className="flex h-full flex-col justify-between pb-36 sm:pb-28 md:pb-24">
<div className="relative block h-full overflow-visible rounded-lg bg-white shadow hover:border-primary-500">
<div className="flex h-full flex-col justify-between">
<div className="px-6 py-4">
<div className="flex flex-col flex-wrap justify-between gap-3 lg:flex-row">
<div
className="flex-wra p flex
flex-col justify-between gap-3 lg:flex-row"
>
{user.username && (
<div
id="username"
Expand Down Expand Up @@ -247,6 +277,7 @@ export default function ManageUsers() {
variant="danger"
ghost
border
className="float-right"
onClick={() => handleDelete(user)}
>
Delete
Expand All @@ -259,10 +290,10 @@ export default function ManageUsers() {
isExtremeSmallScreen
? " flex-wrap "
: " flex-col justify-between md:flex-row "
} gap-2 md:grid md:grid-cols-4`}
} gap-2 md:grid md:grid-cols-2`}
>
{user.user_type && (
<div className="col-span-2">
<div className="col-span-1">
<UserDetails id="role" title="Role">
<div className="break-all font-semibold">
{user.user_type}
Expand All @@ -271,7 +302,7 @@ export default function ManageUsers() {
</div>
)}
{user.district_object && (
<div className="col-span-2">
<div className="col-span-1">
<UserDetails id="district" title="District">
<div className="font-semibold">
{user.district_object.name}
Expand All @@ -281,7 +312,7 @@ export default function ManageUsers() {
)}
{user.user_type === "Doctor" && (
<>
<div className="col-span-2">
<div className="col-span-1">
<UserDetails
id="doctor-qualification"
title="Qualification"
Expand All @@ -295,7 +326,7 @@ export default function ManageUsers() {
)}
</UserDetails>
</div>
<div className="col-span-2">
<div className="col-span-1">
<UserDetails id="doctor-experience" title="Experience">
{user.doctor_experience_commenced_on ? (
<span className="font-semibold">
Expand Down Expand Up @@ -339,11 +370,11 @@ export default function ManageUsers() {
className={`${
isExtremeSmallScreen
? "flex flex-wrap "
: "grid grid-cols-4 "
: "grid grid-cols-2 "
}`}
>
{user.created_by && (
<div className="col-span-2">
<div className="col-span-1">
<UserDetails id="created_by" title="Created by">
<div className="break-all font-semibold">
{user.created_by}
Expand All @@ -352,7 +383,7 @@ export default function ManageUsers() {
</div>
)}
{user.username && (
<div className="col-span-2">
<div className="col-span-1">
<UserDetails id="home_facility" title="Home Facility">
<span className="block font-semibold">
{user.home_facility_object?.name ||
Expand All @@ -362,8 +393,21 @@ export default function ManageUsers() {
</div>
)}
</div>
{user.username && (
<div className="absolute bottom-0 left-0 flex w-full flex-col justify-between gap-2 p-4 sm:bottom-6 md:flex-row">
<div>
<UserDetails id="working-hours" title="Weekly working hours">
{user.weekly_working_hours ? (
<span className="font-semibold">
{user.weekly_working_hours} hours
</span>
) : (
<span className="text-gray-600">-</span>
)}
</UserDetails>
</div>
</div>
{user.username && (
<div className="mb-0 mt-auto flex w-full flex-col justify-between gap-2 p-4">
<div className="flex flex-col md:flex-row">
<ButtonV2
id="facilities"
className="flex w-full items-center md:w-1/2"
Expand All @@ -375,6 +419,7 @@ export default function ManageUsers() {
<CareIcon className="care-l-hospital text-lg" />
<p>Linked Facilities</p>
</ButtonV2>
<div className="mx-1 my-2 sm:my-0"></div>
<ButtonV2
id="skills"
className="flex w-full items-center md:w-1/2"
Expand All @@ -387,8 +432,24 @@ export default function ManageUsers() {
<p>Linked Skills</p>
</ButtonV2>
</div>
)}
</div>
{["DistrictAdmin", "StateAdmin"].includes(userType) && (
<div className="flex-col md:flex-row">
<ButtonV2
id="skills"
className="flex w-full items-center md:w-full"
onClick={() => {
setExpandWorkingHours(true);
setSelectedUser(user.username);
setWeeklyHours(user.weekly_working_hours);
}}
>
<CareIcon className="care-l-clock text-xl" />
<p>Set weekly working hours</p>
</ButtonV2>
</div>
)}
</div>
)}
</div>
</div>
</div>
Expand All @@ -397,7 +458,7 @@ export default function ManageUsers() {

if (isLoading || !users) {
manageUsers = <Loading />;
} else if (users && users.length) {
} else if (users?.length) {
manageUsers = (
<div>
<div className="flex flex-wrap md:-mx-4">{userList}</div>
Expand Down Expand Up @@ -433,6 +494,43 @@ export default function ManageUsers() {
>
<UserFacilities user={selectedUser} />
</SlideOverCustom>
<SlideOverCustom
open={expandWorkingHours}
setOpen={setExpandWorkingHours}
slideFrom="right"
title="Weekly working hours"
dialogClass="md:w-[400px]"
onCloseClick={() => {
setWeeklyHours(0);
}}
>
<div className="px-2">
<dt className="mb-3 text-sm font-medium leading-5 text-black">
Set weekly working hours for {selectedUser}
</dt>
<TextFormField
name="weekly_working_hours"
id="weekly_working_hours"
value={weeklyHours}
onChange={(e) => {
setWeeklyHours(e.value);
}}
error={
weeklyHours < 0 || weeklyHours > 168
? "Weekly working hours should be between 0 and 168"
: ""
}
required
label=""
type="number"
min={0}
max={168}
/>
<div className="mt-2 text-right">
<Submit onClick={handleWorkingHourSubmit} label="Update" />
</div>
</div>
</SlideOverCustom>

<div className="m-4 mt-5 grid grid-cols-1 sm:grid-cols-3 md:gap-5 md:px-2">
<CountBlock
Expand Down Expand Up @@ -628,7 +726,7 @@ function UserFacilities(props: { user: any }) {
{user?.home_facility_object && (
<div className="mt-2">
<div className="mb-2 ml-2 text-lg font-bold">Home Facility</div>
<div className="relative cursor-pointer rounded p-2 transition hover:bg-gray-200 focus:bg-gray-200 md:rounded-lg">
<div className="relative rounded p-2 transition hover:bg-gray-200 focus:bg-gray-200 md:rounded-lg">
<div className="flex items-center justify-between">
<span>{user?.home_facility_object?.name}</span>
<div className="flex items-center gap-2">
Expand Down Expand Up @@ -672,7 +770,7 @@ function UserFacilities(props: { user: any }) {
id={`facility_${i}`}
key={`facility_${i}`}
className={classNames(
"relative cursor-pointer rounded p-2 transition hover:bg-gray-200 focus:bg-gray-200 md:rounded-lg"
"relative rounded p-2 transition hover:bg-gray-200 focus:bg-gray-200 md:rounded-lg"
)}
>
<div className="flex items-center justify-between">
Expand Down
71 changes: 53 additions & 18 deletions src/Components/Users/UserProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type EditForm = {
doctor_qualification: string | undefined;
doctor_experience_commenced_on: number | string | undefined;
doctor_medical_council_registration: string | undefined;
weekly_working_hours: string | undefined;
};
type State = {
form: EditForm;
Expand All @@ -57,6 +58,7 @@ const initForm: EditForm = {
doctor_qualification: undefined,
doctor_experience_commenced_on: undefined,
doctor_medical_council_registration: undefined,
weekly_working_hours: undefined,
};

const initError: EditForm = Object.assign(
Expand Down Expand Up @@ -151,6 +153,7 @@ export default function UserProfile() {
),
doctor_medical_council_registration:
res.data.doctor_medical_council_registration,
weekly_working_hours: res.data.weekly_working_hours,
};
dispatch({
type: "set_form",
Expand Down Expand Up @@ -251,6 +254,20 @@ export default function UserProfile() {
invalidForm = true;
}
return;
case "weekly_working_hours":
if (!states.form[field]) {
errors[field] = "This field is required";
invalidForm = true;
} else if (
Number(states.form[field]) < 0 ||
Number(states.form[field]) > 168 ||
!/^\d+$/.test(states.form[field] ?? "")
) {
errors[field] =
"Weekly working hours must be a number between 0 and 168";
invalidForm = true;
}
return;
}
});
dispatch({ type: "set_error", errors });
Expand Down Expand Up @@ -306,6 +323,7 @@ export default function UserProfile() {
details.user_type === "Doctor"
? states.form.doctor_medical_council_registration
: undefined,
weekly_working_hours: states.form.weekly_working_hours,
};
const res = await dispatchAction(partialUpdateUser(username, data));
if (res && res.data) {
Expand Down Expand Up @@ -513,25 +531,33 @@ export default function UserProfile() {
{details.state_object?.name || "-"}
</dd>
</div>
<div className="my-2 sm:col-span-1">
<dt className="text-sm font-medium leading-5 text-black">
Skills
</dt>
<dd className="mt-1 text-sm leading-5 text-gray-900">
<div className="flex flex-wrap gap-2">
{details.skills && details.skills.length
? details.skills?.map((skill: SkillObjectModel) => {
return (
<span className="flex items-center gap-2 rounded-full border-gray-300 bg-gray-200 px-3 text-xs text-gray-700">
<p className="py-1.5">{skill.name}</p>
</span>
);
})
: "-"}
</div>
</dd>
</div>
<div className="my-2 sm:col-span-1">
<dt className="text-sm font-medium leading-5 text-black">
Weekly working hours
</dt>
<dd className="mt-1 text-sm leading-5 text-gray-900">
{details.weekly_working_hours ?? "-"}
</dd>
</div>
</dl>
<div className="my-2 sm:col-span-1">
<dt className="text-sm font-medium leading-5 text-black">
Skills
</dt>
<dd className="mt-1 text-sm leading-5 text-gray-900">
<div className="flex flex-wrap gap-2">
{details.skills && details.skills.length
? details.skills?.map((skill: SkillObjectModel) => {
return (
<span className="flex items-center gap-2 rounded-full border-gray-300 bg-gray-200 px-3 text-xs text-gray-700">
<p className="py-1.5">{skill.name}</p>
</span>
);
})
: "-"}
</div>
</dd>
</div>
</div>
)}

Expand Down Expand Up @@ -622,6 +648,15 @@ export default function UserProfile() {
/>
</>
)}
<TextFormField
{...fieldProps("weekly_working_hours")}
required
label="Weekly working hours"
className="col-span-6 sm:col-span-3"
type="number"
min={0}
max={168}
/>
</div>
</div>
<div className="bg-gray-50 px-4 py-3 text-right sm:px-6">
Expand Down

0 comments on commit 9249158

Please sign in to comment.