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

🛠 Upgrade the colors of tailwind input components + 🛠 Tailwind Consultation Form + 🛠 Tailiwnd discharge patient dialog #4309

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
d8bfef4
momentarily copied secondary until #4307 merged
rithviknishad Dec 14, 2022
f25a2a9
upgrade textarea colors as per figma
rithviknishad Dec 14, 2022
b3d92e1
consultation: replace mui label and textarea w. tw
rithviknishad Dec 14, 2022
97294bb
tailwind discharge modal
rithviknishad Dec 14, 2022
6a7b81a
Merge branch 'develop' into tailwind/update-form-field-colors/textarea
rithviknishad Dec 15, 2022
cb166c4
add hints to discharge modal
rithviknishad Dec 15, 2022
e17258d
upgrade `SelectMenuV2`
rithviknishad Dec 15, 2022
6e6417a
upgrade `TextFormField`
rithviknishad Dec 15, 2022
4b663b3
upgrade `MultiSelectMenuV2`
rithviknishad Dec 15, 2022
7c3d7cd
upgrade AutoCompleteAsync colors
rithviknishad Dec 15, 2022
30da9de
use CareIcons
rithviknishad Dec 15, 2022
2597504
upgrade `DateInputV2`
rithviknishad Dec 15, 2022
3e86b49
upgrade PhoneInput style to perfection
rithviknishad Dec 15, 2022
7a18b0f
place clear inside the phone input
rithviknishad Dec 15, 2022
f81f58b
fix padding
rithviknishad Dec 15, 2022
b4c0e7a
Merge branch 'develop' into tailwind/update-form-field-colors/textarea
rithviknishad Dec 16, 2022
5cb74ae
fix `SelectMenuV2` conflict
rithviknishad Dec 16, 2022
f9d5eb8
add missing verified by label
rithviknishad Dec 16, 2022
51a7792
Add form field comp: `PatientCategorySelect`
rithviknishad Dec 16, 2022
811a4c2
use PatientCategorySelect in consultation form
rithviknishad Dec 16, 2022
2374306
cleanup patient category tw-class mess
rithviknishad Dec 17, 2022
4eb6e1a
tw-comp: `SelectMenuFormField`
rithviknishad Dec 17, 2022
7ab706a
Upgrade consultation form
rithviknishad Dec 17, 2022
e77fa1c
tw-comp: `AutocompleteMultiselect`
rithviknishad Dec 17, 2022
28b410c
tw-comp: `AutocompleteV2` (single select, but not form field yet)
rithviknishad Dec 17, 2022
003f598
add hook: `useAsyncOptions` for use in async dropdowns
rithviknishad Dec 17, 2022
e9c5633
tw-comp: `DiagnosisAutocompleteFormField`
rithviknishad Dec 17, 2022
791bc62
MultiSelect, AutocompleteMulti: option chip + remove
rithviknishad Dec 17, 2022
8ffc385
consultation form: upgrade diag. and prov. diag.
rithviknishad Dec 17, 2022
2be9d23
replicate figma page layout for consultation
rithviknishad Dec 17, 2022
fc83a77
fix form submission
rithviknishad Dec 17, 2022
6989828
empty
rithviknishad Dec 17, 2022
c7d5bb3
Merge branch 'develop' into tailwind/update-form-field-colors/textarea
rithviknishad Dec 17, 2022
8cbf64e
Merge branch 'develop' into tailwind/update-form-field-colors/textarea
rithviknishad Dec 17, 2022
6c755c5
rename `SelectMenuFormField` -> `SelectFormField`
rithviknishad Dec 18, 2022
fbbe69f
tw-comp: `MultiSelectFormField`
rithviknishad Dec 18, 2022
2f0d466
Deprecate old `DateRangePicker`
rithviknishad Dec 18, 2022
e641cc4
tw-comp: `SymptomsSelect` Form Field
rithviknishad Dec 18, 2022
cc01dc4
show helpful descriptions in `SymptomsSelect`
rithviknishad Dec 18, 2022
8faa591
consultation form use new `SymptomsSelect`
rithviknishad Dec 18, 2022
2944ccd
so far it never felt the date input was getting disabled?
rithviknishad Dec 18, 2022
746da1d
let the dropdown be near the calendar for less mouse movement
rithviknishad Dec 18, 2022
b12dcdd
consultation form, use `DateFormFields`
rithviknishad Dec 18, 2022
ae39c80
Merge branch 'develop' into tailwind/update-form-field-colors/textarea
rithviknishad Dec 18, 2022
7a15f67
hide disabled fields
rithviknishad Dec 18, 2022
44a96c5
introduce style: `cui-input-base`
rithviknishad Dec 20, 2022
483f1ff
migrate select and multiselect to new colors
rithviknishad Dec 20, 2022
9855230
migrate text form field and text area
rithviknishad Dec 20, 2022
26d1a05
remove conflicting classes
rithviknishad Dec 20, 2022
46c4872
BRING BACK ORIGINAL GRAY PALLETE
rithviknishad Dec 20, 2022
4468b37
update Form Field label color
rithviknishad Dec 20, 2022
7c02f27
ensure cui-input-base is properly applied
rithviknishad Dec 20, 2022
9444e17
migrate autocomplete
rithviknishad Dec 20, 2022
ace0088
hack: make online user select to look consistent with the form
rithviknishad Dec 20, 2022
c903941
migrate autocomplete async design
rithviknishad Dec 20, 2022
da4f91d
improve consistency on dropdown options
rithviknishad Dec 20, 2022
f1e8c8e
adds class: `cui-dropdown-base`
rithviknishad Dec 20, 2022
6d8565c
migrate date picker
rithviknishad Dec 20, 2022
78ff23e
check-circle
rithviknishad Dec 20, 2022
03b5dc3
Merge branch 'develop' into tailwind/update-form-field-colors/textarea
rithviknishad Dec 21, 2022
dcec2b0
Merge branch 'develop' into tailwind/update-form-field-colors/textarea
rithviknishad Dec 21, 2022
350b52b
`cui-input-base` for prescription builder
rithviknishad Dec 21, 2022
b8cbc0a
`cui-input-base` for investigation builder
rithviknishad Dec 21, 2022
f266d69
fix memory loss of diagnosis select
rithviknishad Dec 21, 2022
4ba841e
autocomplete show loading or nothing found
rithviknishad Dec 21, 2022
cf2f2be
document: `useAsyncOptions`
rithviknishad Dec 21, 2022
771e215
fix issues w. state handling of DiagnosisSelect
rithviknishad Dec 21, 2022
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
2 changes: 1 addition & 1 deletion src/CAREUI/interactive/LegendInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export default function LegendInput(props: InputProps) {
required={props.required}
autoComplete={props.autoComplete}
className={classNames(
"w-full bg-gray-50 focus:bg-gray-100 cui-input",
"w-full border-gray-300 rounded-md shadow-sm bg-gray-50 focus:bg-gray-100 cui-input",
props.size === "small" && "text-xs px-3 py-2",
(!props.size || !["small", "large"].includes(props.size)) &&
"px-4 py-3",
Expand Down
52 changes: 25 additions & 27 deletions src/Common/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -210,20 +210,20 @@ export const MEDICAL_HISTORY_CHOICES: Array<OptionsType> = [
];

export const REVIEW_AT_CHOICES: Array<OptionsType> = [
{ id: 30, text: "30 minutes" },
{ id: 60, text: "1 hour" },
{ id: 120, text: "2 hours" },
{ id: 180, text: "3 hours" },
{ id: 240, text: "4 hours" },
{ id: 360, text: "6 hours" },
{ id: 480, text: "8 hours" },
{ id: 720, text: "12 hours" },
{ id: 1440, text: "24 hours" },
{ id: 2160, text: "36 hours" },
{ id: 2880, text: "48 hours" },
];

export const SYMPTOM_CHOICES: Array<OptionsType> = [
{ id: 30, text: "30 mins" },
{ id: 60, text: "1 hr" },
{ id: 120, text: "2 hr" },
{ id: 180, text: "3 hr" },
{ id: 240, text: "4 hr" },
{ id: 360, text: "6 hr" },
{ id: 480, text: "8 hr" },
{ id: 720, text: "12 hr" },
{ id: 1440, text: "24 hr" },
{ id: 2160, text: "36 hr" },
{ id: 2880, text: "48 hr" },
];

export const SYMPTOM_CHOICES = [
{ id: 1, text: "ASYMPTOMATIC" },
{ id: 2, text: "FEVER" },
{ id: 3, text: "SORE THROAT" },
Expand Down Expand Up @@ -287,20 +287,18 @@ export const ADMITTED_TO = [
{ id: "7", text: "Regular" },
];

export const PATIENT_CATEGORIES = [
{ id: "Comfort", text: "Comfort Care" },
{ id: "Stable", text: "Stable" },
{ id: "Moderate", text: "Slightly Abnormal" },
{ id: "Critical", text: "Critical" },
];
export type PatientCategoryID = "Comfort" | "Stable" | "Moderate" | "Critical";

export const PatientCategoryTailwindClass: Record<PatientCategory, string> = {
"Comfort Care": "patient-comfort",
Stable: "patient-stable",
"Slightly Abnormal": "patient-abnormal",
Critical: "patient-critical",
unknown: "patient-unknown",
};
export const PATIENT_CATEGORIES: {
id: PatientCategoryID;
text: PatientCategory;
twClass: string;
}[] = [
{ id: "Comfort", text: "Comfort Care", twClass: "patient-comfort" },
{ id: "Stable", text: "Stable", twClass: "patient-stable" },
{ id: "Moderate", text: "Slightly Abnormal", twClass: "patient-abnormal" },
{ id: "Critical", text: "Critical", twClass: "patient-critical" },
];

export const PATIENT_FILTER_CATEGORIES = PATIENT_CATEGORIES;

Expand Down
109 changes: 109 additions & 0 deletions src/Common/hooks/useAsyncOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { debounce } from "lodash";
import { useMemo, useState } from "react";
import { useDispatch } from "react-redux";

interface IUseAsyncOptionsArgs {
debounceInterval?: number;
}

/**
* Hook to implement async autocompletes with ease and typesafety.
*
* See `DiagnosisSelectFormField` for usage.
*
* **Example usage:**
* ```jsx
* const { fetchOptions, isLoading, options } = useAsyncOptions<Model>("id");
*
* return (
* <AutocompleteMultiselect
* ...
* options={options(props.value)}
* isLoading={isLoading}
* onQuery={(query) => fetchOptions(action({ query }))}
* optionValue={(option) => option}
* ...
* />
* );
* ```
*/
export function useAsyncOptions<T extends Record<string, unknown>>(
uniqueKey: keyof T,
args?: IUseAsyncOptionsArgs
) {
const dispatch = useDispatch<any>();
const [queryOptions, setQueryOptions] = useState<T[]>([]);
const [isLoading, setIsLoading] = useState(false);

const fetchOptions = useMemo(
() =>
debounce(async (action: any) => {
setIsLoading(true);
const res = await dispatch(action);
if (res?.data) setQueryOptions(res.data as T[]);
setIsLoading(false);
}, args?.debounceInterval ?? 300),
[dispatch, args?.debounceInterval]
);

const mergeValueWithQueryOptions = (selected?: T[]) => {
if (!selected?.length) return queryOptions;

return [
...queryOptions,
...selected.filter(
(obj) => !queryOptions.some((s) => s[uniqueKey] === obj[uniqueKey])
),
];
};

return {
/**
* Merges query options and selected options.
*
* **Example usage:**
* ```jsx
* const { isLoading } = useAsyncOptions<Model>("id");
*
* <AutocompleteMultiselect
* ...
* isLoading={isLoading}
* ...
* />
* ```
*/
fetchOptions,

/**
* Merges query options and selected options.
*
* **Example usage:**
* ```jsx
* const { options } = useAsyncOptions<Model>("id");
*
* <AutocompleteMultiselect
* ...
* onQuery={(query) => fetchOptions(action({ query }))}
* ...
* />
* ```
*/
isLoading,

/**
* Merges query options and selected options.
*
* **Example usage:**
* ```jsx
* const { options } = useAsyncOptions<Model>("id");
*
* <AutocompleteMultiselect
* ...
* options={options(props.value)}
* ...
* />
* ```
*/
options: mergeValueWithQueryOptions,
};
}
53 changes: 26 additions & 27 deletions src/Components/Common/DateInputV2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import { DropdownTransition } from "./components/HelperComponents";
import { Popover } from "@headlessui/react";
import { classNames } from "../../Utils/utils";
import CareIcon from "../../CAREUI/icons/CareIcon";

type DatePickerType = "date" | "month" | "year";
export type DatePickerPosition = "LEFT" | "RIGHT" | "CENTER";
Expand Down Expand Up @@ -126,10 +127,8 @@ const DateInputV2: React.FC<Props> = ({
year = datePickerHeaderDate.getFullYear()
) => {
const date = new Date(year, month, day);

if (min) if (date < min) return false;
if (max) if (date > max) return false;

return true;
};

Expand Down Expand Up @@ -183,51 +182,52 @@ const DateInputV2: React.FC<Props> = ({
};

return (
<div className={disabled ? "pointer-events-none opacity-0.8" : ""}>
<div>
<div className="container mx-auto text-black">
<Popover className="relative">
<Popover.Button className="w-full">
<Popover.Button disabled={disabled} className="w-full">
<input type="hidden" name="date" />
<input
type="text"
readOnly
className={`text-sm block py-3 px-4 w-full rounded placeholder:text-gray-500 focus:bg-white border-2 focus:border-primary-400 outline-none !ring-0 transition-all duration-200 ease-in-out ${className}`}
placeholder={placeholder ? placeholder : "Select date"}
disabled={disabled}
className={`cui-input-base cursor-pointer disabled:cursor-not-allowed ${className}`}
placeholder={placeholder || "Select date"}
value={value && format(value, "yyyy-MM-dd")}
/>
<div className="cursor-pointer absolute top-1/2 right-0 p-2 -translate-y-1/2">
<i className="fa-regular fa-calendar text-slate-500"></i>
<div className="absolute top-1/2 right-0 p-2 -translate-y-1/2">
<CareIcon className="care-l-calendar-alt text-lg text-gray-600" />
</div>
</Popover.Button>
<DropdownTransition>
<Popover.Panel
className={classNames(
"z-10 w-72 bg-white border border-slate-300 rounded-lg shadow p-4 absolute top-[110%]",
"cui-dropdown-base divide-y-0 w-72 p-4 absolute mt-0.5",
getPosition()
)}
>
<div className="flex justify-between items-center w-full mb-4">
<button
type="button"
disabled={!isDateWithinConstraints()}
className="transition ease-in-out duration-100 p-2 rounded inline-flex items-center justify-center aspect-square cursor-pointer hover:bg-slate-200"
className="transition ease-in-out duration-100 p-2 rounded inline-flex items-center justify-center aspect-square cursor-pointer hover:bg-gray-300"
onClick={decrement}
>
<i className="fa fa-arrow-left" />
<CareIcon className="care-l-angle-left-b text-lg" />
</button>

<div className="flex items-center justify-center text-sm">
{type === "date" && (
<div
onClick={showMonthPicker}
className="py-1 px-3 font-bold text-slate-900 text-center cursor-pointer hover:bg-slate-200 rounded"
className="py-1 px-3 font-medium text-black text-center cursor-pointer hover:bg-gray-300 rounded"
>
{format(datePickerHeaderDate, "MMMM")}
</div>
)}
<div
onClick={showYearPicker}
className="py-1 px-3 font-bold text-gray-900 cursor-pointer hover:bg-slate-200 rounded"
className="py-1 px-3 font-medium text-black cursor-pointer hover:bg-gray-300 rounded"
>
<p className="text-center">
{type == "year"
Expand All @@ -243,18 +243,18 @@ const DateInputV2: React.FC<Props> = ({
new Date().getFullYear() === year.getFullYear()) ||
!isDateWithinConstraints(getLastDay())
}
className="transition ease-in-out duration-100 h-full p-2 rounded inline-flex items-center justify-center aspect-square cursor-pointer hover:bg-slate-200"
className="transition ease-in-out duration-100 p-2 rounded inline-flex items-center justify-center aspect-square cursor-pointer hover:bg-gray-300"
onClick={increment}
>
<i className="fa fa-arrow-right" />
<CareIcon className="care-l-angle-right-b text-lg" />
</button>
</div>
{type === "date" && (
<>
<div className="flex flex-wrap">
<div className="flex flex-wrap mb-3">
{DAYS.map((day) => (
<div key={day} className="aspect-square w-[14.26%]">
<div className="text-slate-600 font-medium text-center text-sm">
<div className="text-gray-800 font-medium text-center text-sm">
{day}
</div>
</div>
Expand All @@ -272,11 +272,11 @@ const DateInputV2: React.FC<Props> = ({
<div
onClick={setDateValue(d)}
className={classNames(
"cursor-pointer flex items-center justify-center text-center h-full text-sm rounded leading-loose transition ease-in-out duration-100 text-slate-900 hover:bg-slate-200",
value &&
isSelectedDate(d) &&
"bg-primary-500 text-slate-100 font-bold",
!isDateWithinConstraints(d) && "!text-slate-300"
"cursor-pointer flex items-center justify-center text-center h-full text-sm rounded leading-loose transition ease-in-out duration-100 text-black",
value && isSelectedDate(d)
? "bg-primary-500 text-white font-bold"
: "hover:bg-gray-300",
!isDateWithinConstraints(d) && "!text-gray-300"
)}
>
{d}
Expand All @@ -294,10 +294,10 @@ const DateInputV2: React.FC<Props> = ({
<div
key={i}
className={classNames(
"cursor-pointer w-1/4 font-semibold py-4 px-2 text-center text-sm rounded-lg hover:bg-slate-200",
"cursor-pointer w-1/4 font-semibold py-4 px-2 text-center text-sm rounded-lg",
value && isSelectedMonth(i)
? "bg-primary-500 text-white"
: "text-slate-700 hover:bg-primary-600"
: "text-gray-700 hover:bg-gray-300"
)}
onClick={setMonthValue(i)}
>
Expand All @@ -323,10 +323,10 @@ const DateInputV2: React.FC<Props> = ({
<div
key={i}
className={classNames(
"cursor-pointer w-1/4 font-semibold py-4 px-2 text-center text-sm rounded-lg hover:bg-slate-200",
"cursor-pointer w-1/4 font-semibold py-4 px-2 text-center text-sm rounded-lg",
value && isSelectedYear(y)
? "bg-primary-500 text-white"
: "text-slate-700 hover:bg-primary-600"
: "text-gray-700 hover:bg-gray-300"
)}
onClick={setYearValue(y)}
>
Expand All @@ -346,7 +346,6 @@ const DateInputV2: React.FC<Props> = ({

DateInputV2.defaultProps = {
position: "CENTER",
className: "bg-gray-200 border-gray-200",
};

export default DateInputV2;
3 changes: 3 additions & 0 deletions src/Components/Common/DateRangePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ interface IDateRangePickerProps {
export const getDate = (value: any) =>
value && moment(value).isValid() ? moment(value) : null;

/**
* Deprecated. Use `DateRangeFormField` or `DateFormField` instead.
*/
export const DateRangePicker: React.FC<IDateRangePickerProps> = ({
label,
endDateId = "end_date",
Expand Down
45 changes: 45 additions & 0 deletions src/Components/Common/DiagnosisSelectFormField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { useAsyncOptions } from "../../Common/hooks/useAsyncOptions";
import { listICD11Diagnosis } from "../../Redux/actions";
import { ICD11DiagnosisModel } from "../Facility/models";
import { AutocompleteMutliSelect } from "../Form/FormFields/AutocompleteMultiselect";
import FormField from "../Form/FormFields/FormField";
import {
FormFieldBaseProps,
resolveFormFieldChangeEventHandler,
} from "../Form/FormFields/Utils";

type Props =
// | ({ multiple?: false | undefined } & FormFieldBaseProps<ICD11DiagnosisModel>) // uncomment when single select form field is required and implemented.
{ multiple: true } & FormFieldBaseProps<ICD11DiagnosisModel[]>;

export function DiagnosisSelectFormField(props: Props) {
const { name } = props;
const handleChange = resolveFormFieldChangeEventHandler(props);

const { fetchOptions, isLoading, options } =
useAsyncOptions<ICD11DiagnosisModel>("id");

if (!props.multiple) {
return (
<div className="bg-danger-500 text-white font-bold">
Component not implemented
</div>
);
}

return (
<FormField props={props}>
<AutocompleteMutliSelect
id={props.id}
disabled={props.disabled}
value={props.value || []}
options={options(props.value)}
optionLabel={(option) => option.label}
optionValue={(option) => option}
onQuery={(query) => fetchOptions(listICD11Diagnosis({ query }, ""))}
isLoading={isLoading}
onChange={(value) => handleChange({ name, value })}
/>
</FormField>
);
}
Loading