Skip to content

Commit

Permalink
updated UI to not have the user add slashes
Browse files Browse the repository at this point in the history
  • Loading branch information
shivankacker committed Oct 10, 2024
1 parent 86663d8 commit 16aa346
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 119 deletions.
2 changes: 1 addition & 1 deletion cypress/e2e/patient_spec/PatientRegistration.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe("Patient Creation with consultation", () => {
const phone_number = generatePhoneNumber();
const age = calculateAge();
const patientFacility = "Dummy Facility 40";
const patientDateOfBirth = "01/01/2001";
const patientDateOfBirth = "01012001";
const patientMenstruationStartDate = getRelativeDateString(-10);
const patientDateOfDelivery = getRelativeDateString(-20);
const patientOneName = "Patient With No Consultation";
Expand Down
72 changes: 17 additions & 55 deletions src/Components/Common/DateInputV2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ const DateInputV2: React.FC<Props> = ({
max,
outOfLimitsErrorMessage,
onChange,
position = "CENTER",
disabled,
placeholder,
setIsOpen,
Expand Down Expand Up @@ -206,22 +205,6 @@ const DateInputV2: React.FC<Props> = ({
return true;
};

const isDateWithinLimits = (parsedDate: dayjs.Dayjs): boolean => {
if (parsedDate?.isValid()) {
if (
(max && parsedDate.toDate() > max) ||
(min && parsedDate.toDate() < min)
) {
Notification.Error({
msg: outOfLimitsErrorMessage ?? "Cannot select date out of range",
});
return false;
}
return true;
}
return false;
};

const isSelectedMonth = (month: number) =>
month === datePickerHeaderDate.getMonth();

Expand Down Expand Up @@ -294,33 +277,9 @@ const DateInputV2: React.FC<Props> = ({
}, [isOpen]);

const dateFormat = `DD/MM/YYYY${time ? " hh:mm a" : ""}`;
const placeHolder = dateFormat.replace("a", "am/pm");

const getDisplayValue = (date: Date) => {
return dayjs(date).format(dateFormat);
};

const getPosition = () => {
switch (position) {
case "LEFT":
return "left-0";
case "LEFT-CENTER":
return "right-0 transform md:translate-x-1/2";
case "RIGHT":
return "right-0";
case "RIGHT-CENTER":
return "right-0 transform md:translate-x-1/2";
case "CENTER":
return "transform -translate-x-1/2";
case "TOP-LEFT":
return "bottom-full left-full";
case "TOP-RIGHT":
return "bottom-full right-0";
case "TOP-CENTER":
return "bottom-full left-1/2 transform -translate-x-1/2";
default:
return "left-0";
}
return "";
};

return (
Expand Down Expand Up @@ -358,7 +317,6 @@ const DateInputV2: React.FC<Props> = ({
</PopoverButton>
{open && (
<PopoverPanel
static
className={classNames(
`cui-dropdown-base absolute my-0.5 ${time ? "max-h-[80vh] w-full md:h-auto md:w-[400px]" : "w-72"} divide-y-0 rounded p-4`,
getPosition(),
Expand All @@ -367,19 +325,23 @@ const DateInputV2: React.FC<Props> = ({
>
<div
className={classNames(
"flex w-full items-center justify-between gap-y-4",
position?.includes("TOP")
? "flex-col-reverse"
: "flex-col",
"flex w-full flex-col items-center justify-between gap-y-4",
)}
>
{value && (
<DateTextInput
allowTime={!!time}
value={value}
onChange={onChange}
/>
)}
<DateTextInput
allowTime={!!time}
value={value}
onChange={onChange}
error={
value &&
(!dayjs(value).isValid() ||
(!!max && value > max) ||
(!!min && value < min))
? "Cannot select date out of range"
: undefined
}
/>

<div className="flex flex-col items-center gap-4 px-4 md:flex-row md:px-0">
<div className="flex flex-1 flex-col items-center justify-between">
<div className="flex">
Expand Down Expand Up @@ -647,7 +609,7 @@ const DateInputV2: React.FC<Props> = ({
<button
type="button"
key={j}
className={`flex aspect-square w-9 shrink-0 items-center justify-center rounded-md border transition-all ${(input.name === "Hours" && option === 12 ? [0, 12].includes(input.value) : input.value === option) ? "bg-primary-500 font-bold text-white" : "border-gray-300 hover:bg-secondary-300"} text-sm`}
className={`flex aspect-square w-9 shrink-0 items-center justify-center rounded-md border transition-all ${(input.name === "Hours" && option === 12 ? [0, 12].includes(input.value) : input.value === option) ? "border-primary-600 bg-primary-500 font-bold text-white" : "border-gray-200 hover:bg-secondary-300"} text-sm`}
onClick={() =>
input.onChange(option as any)
}
Expand Down
147 changes: 85 additions & 62 deletions src/Components/Common/DateTextInput.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { classNames } from "@/Utils/utils";
import dayjs from "dayjs";
import { Fragment, KeyboardEvent, useEffect, useState } from "react";

Expand All @@ -8,22 +9,24 @@ import { Fragment, KeyboardEvent, useEffect, useState } from "react";
* @param {boolean} props.allowTime - If true, shows time input fields (hour and minute).
* @param {Date} props.value - The current date value.
* @param {function(Date):void} props.onChange - Callback function when date value changes.
* @param {String} props.error - Shows an error if specified
*
* @returns {JSX.Element} The date text input component.
*/
export default function DateTextInput(props: {
allowTime: boolean;
value: Date;
value?: Date;
onChange: (date: Date) => unknown;
error?: string;
}) {
const { value, onChange, allowTime } = props;
const { value, onChange, allowTime, error } = props;

const [editingText, setDirtyEditingText] = useState({
date: `${value.getDate()}`,
month: `${value.getMonth() + 1}`,
year: `${value.getFullYear()}`,
hour: `${value.getHours()}`,
minute: `${value.getMinutes()}`,
date: `${value ? value?.getDate() : ""}`,
month: `${value ? value.getMonth() + 1 : ""} `,
year: `${value ? value.getFullYear() : ""}`,
hour: `${value ? value.getHours() : ""}`,
minute: `${value ? value.getMinutes() : ""}`,
});

const setEditingText = (et: typeof editingText) => {
Expand All @@ -32,10 +35,10 @@ export default function DateTextInput(props: {
parseInt(et.year),
parseInt(et.month) - 1,
parseInt(et.date),
parseInt(et.hour),
parseInt(et.minute),
allowTime ? parseInt(et.hour) : 0,
allowTime ? parseInt(et.minute) : 0,
);
if (dayjs(newDate).isValid()) {
if (et.year.length > 3 && dayjs(newDate).isValid()) {
onChange(newDate);
}
};
Expand All @@ -54,7 +57,6 @@ export default function DateTextInput(props: {
const value = Math.min(maxMap[index], parseInt(rawValue));
const finalValue =
rawValue !== "" ? ("000" + value).slice(key === "year" ? -4 : -2) : "";
console.log(finalValue);
return finalValue;
};

Expand Down Expand Up @@ -90,63 +92,84 @@ export default function DateTextInput(props: {
};

useEffect(() => {
const formatUnfocused = (value: number, id: number, digits: number = 2) => {
const activeElementIdRaw =
document.activeElement?.getAttribute("data-time-input");
const activeElementId = activeElementIdRaw
? parseInt(activeElementIdRaw)
: undefined;
if (id === activeElementId) return value;
return ("000" + value).slice(-digits);
};

setDirtyEditingText({
date: `${value.getDate()}`,
month: `${value.getMonth() + 1}`,
year: `${value.getFullYear()}`,
hour: `${value.getHours()}`,
minute: `${value.getMinutes()}`,
date: `${value ? formatUnfocused(value.getDate(), 0) : ""}`,
month: `${value ? formatUnfocused(value.getMonth() + 1, 1) : ""}`,
year: `${value ? formatUnfocused(value.getFullYear(), 2, 4) : ""}`,
hour: `${value ? formatUnfocused(value.getHours(), 3) : ""}`,
minute: `${value ? formatUnfocused(value.getMinutes(), 4) : ""}`,
});
}, [value]);

return (
<div className="flex items-center overflow-hidden w-full text-gray-600 cui-input-base px-4 py-0 bg-secondary-50">
{Object.entries(editingText)
.slice(0, allowTime ? 5 : 3)
.map(([key, val], i) => (
<Fragment key={i}>
<input
type="text"
value={val}
autoFocus={i === 0}
className={`text-black shadow-none bg-transparent border-none rounded-none outline-none ring-0 ${
key === "year" ? "w-[45px]" : "w-[20px]"
} px-0 placeholder:text-sm`}
placeholder={
"DDMMYYHHmm".slice(i * 2, i * 2 + 2) +
(key === "year" ? "YY" : "")
}
onKeyDown={(e) => handleKeyDown(e, i)}
data-time-input={i}
onChange={(e) => {
const value = e.target.value;
setEditingText({
...editingText,
[key]: value
.replace(/\D/g, "")
.slice(0, key === "year" ? 4 : 2),
});
if (
(value.endsWith("/") ||
value.endsWith(" ") ||
value.endsWith(":") ||
value.length > (key === "year" ? 3 : 1)) &&
i < 4
) {
goToInput(i + 1);
<div className="w-full">
<div
className={classNames(
`cui-input-base flex w-full cursor-text items-center overflow-hidden bg-secondary-50 px-4 py-0 text-gray-600`,
error && `!border-red-500`,
)}
onClick={(e) =>
e.target === e.currentTarget && goToInput(allowTime ? 4 : 2)
}
>
{Object.entries(editingText)
.slice(0, allowTime ? 5 : 3)
.map(([key, val], i) => (
<Fragment key={i}>
<input
type="text"
value={val}
autoFocus={i === 0}
className={`rounded-none border-none bg-transparent text-black shadow-none outline-none ring-0 ${
key === "year" ? "w-[45px]" : "w-[20px]"
} px-0 placeholder:text-xs`}
placeholder={
"DDMMYYHHmm".slice(i * 2, i * 2 + 2) +
(key === "year" ? "YY" : "")
}
}}
onBlur={(e) => handleBlur(e.target.value, key)}
/>
<span className="mx-1">
{["date", "month"].includes(key)
? "/"
: key === "hour"
? ":"
: " "}
</span>
</Fragment>
))}
onKeyDown={(e) => handleKeyDown(e, i)}
data-time-input={i}
onChange={(e) => {
const value = e.target.value;
setEditingText({
...editingText,
[key]: value
.replace(/\D/g, "")
.slice(0, key === "year" ? 4 : 2),
});
if (
(value.endsWith("/") ||
value.endsWith(" ") ||
value.endsWith(":") ||
value.length > (key === "year" ? 3 : 1)) &&
i < 4
) {
goToInput(i + 1);
}
}}
onBlur={(e) => handleBlur(e.target.value, key)}
/>
<span className="mx-1">
{["date", "month"].includes(key)
? "/"
: key === "hour"
? ":"
: " "}
</span>
</Fragment>
))}
</div>
{error && <span className="text-xs text-red-500">{error}</span>}
</div>
);
}
2 changes: 1 addition & 1 deletion src/Components/Symptoms/SymptomsBuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -294,14 +294,14 @@ const AddSymptom = (props: {
return (
<div className="flex w-full flex-wrap items-start gap-4 md:flex-nowrap">
<DateFormField
className="w-full md:w-36"
name="onset_date"
id="symptoms_onset_date"
placeholder="Date of onset"
disableFuture
value={onsetDate}
onChange={({ value }) => setOnsetDate(value)}
errorClassName="hidden"
position="CENTER"
/>
<div className="flex w-full flex-col gap-2">
<AutocompleteMultiSelectFormField
Expand Down

0 comments on commit 16aa346

Please sign in to comment.