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

Remove pin-code autofill feature #10291

Merged
merged 5 commits into from
Jan 31, 2025
Merged
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
2 changes: 2 additions & 0 deletions cypress/e2e/facility_spec/facility_creation.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { generatePhoneNumber } from "@/utils/commonUtils";
import { generateFacilityData } from "@/utils/facilityData";

const LOCATION_HIERARCHY = {
state: "Kerala",
district: "Ernakulam",
localBody: "Aluva",
ward: "4",
};
Expand Down
13 changes: 12 additions & 1 deletion cypress/pageObject/facility/FacilityCreation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,18 @@ export class FacilityCreation {
.should("not.be.empty");
}

fillLocationHierarchy(location: { localBody: string; ward: string }) {
fillLocationHierarchy(location: {
state: string;
district: string;
localBody: string;
ward: string;
}) {
cy.typeAndSelectOption('[data-cy="select-state"]', location.state, false);
cy.typeAndSelectOption(
'[data-cy="select-district"]',
location.district,
false,
);
// Don't verify selection for local body (false parameter)
cy.typeAndSelectOption(
'[data-cy="select-local_body"]',
Expand Down
15 changes: 7 additions & 8 deletions src/Providers/PatientUserProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import { useAuthContext } from "@/hooks/useAuthUser";

import routes from "@/Utils/request/api";
import query from "@/Utils/request/query";
import { AppointmentPatient } from "@/pages/Patient/Utils";
import { TokenData } from "@/types/auth/otpToken";
import { Patient } from "@/types/emr/newPatient";

export type PatientUserContextType = {
patients?: AppointmentPatient[];
selectedPatient: AppointmentPatient | null;
setSelectedPatient: (patient: AppointmentPatient) => void;
patients?: Patient[];
selectedPatient: Patient | null;
setSelectedPatient: (patient: Patient) => void;
tokenData: TokenData;
};

Expand All @@ -25,9 +25,8 @@ interface Props {
}

export default function PatientUserProvider({ children }: Props) {
const [patients, setPatients] = useState<AppointmentPatient[]>([]);
const [selectedPatient, setSelectedPatient] =
useState<AppointmentPatient | null>(null);
const [patients, setPatients] = useState<Patient[]>([]);
const [selectedPatient, setSelectedPatient] = useState<Patient | null>(null);

const { patientToken: tokenData } = useAuthContext();

Expand All @@ -44,7 +43,7 @@ export default function PatientUserProvider({ children }: Props) {
useEffect(() => {
if (userData?.results && userData.results.length > 0) {
setPatients(userData.results);
const localPatient: AppointmentPatient | undefined = JSON.parse(
const localPatient: Patient | undefined = JSON.parse(
localStorage.getItem("selectedPatient") || "{}",
);
const selectedPatient =
Expand Down
36 changes: 1 addition & 35 deletions src/Utils/permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,9 @@ import { UserModel } from "@/components/Users/models";

import { UserBase } from "@/types/user/user";

// To do: Rewrite to check if belongs to same org and in higher
// hierarchy
/* const checkIfStateOrDistrictAdminInSameLocation = (
authUser: UserBaseModel,
targetUser: UserBaseModel,
) => {
const hasLocation = Boolean(
targetUser.state_object || targetUser.district_object,
);

const isStateAdminOfSameState =
authUser.user_type === "StateAdmin" &&
targetUser.state_object?.id === authUser.state;

const isDistrictAdminOfSameDistrict =
authUser.user_type === "DistrictAdmin" &&
targetUser.district_object?.id === authUser.district;

return (
hasLocation && (isStateAdminOfSameState || isDistrictAdminOfSameDistrict)
);
};
*/
export const showUserDelete = (authUser: UserModel, targetUser: UserBase) => {
// Auth user should be higher in hierarchy than target user
// User can't delete their own account
/* if (
USER_TYPES.indexOf(authUser.user_type) <=
USER_TYPES.indexOf(targetUser.user_type) ||
authUser.username === targetUser.username
)
return false; */
// To do: check above
//return checkIfStateOrDistrictAdminInSameLocation(authUser, targetUser);
if (authUser.username === targetUser.username) return false;
return false;
};
Expand All @@ -55,8 +24,5 @@ export const editUserPermissions = (
authUser: UserModel,
targetUser: UserBase,
) => {
if (authUser.username === targetUser.username) return true;
return false;
// To do: check above
//return checkIfStateOrDistrictAdminInSameLocation(authUser, targetUser);
return authUser.username === targetUser.username;
};
9 changes: 3 additions & 6 deletions src/Utils/request/api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@ import {
} from "@/components/Users/models";

import { PaginatedResponse } from "@/Utils/request/types";
import {
AppointmentPatient,
AppointmentPatientRegister,
} from "@/pages/Patient/Utils";
import { AppointmentPatientRegister } from "@/pages/Patient/Utils";
import { Encounter, EncounterEditRequest } from "@/types/emr/encounter";
import { MedicationStatement } from "@/types/emr/medicationStatement";
import { PartialPatientModel, Patient } from "@/types/emr/newPatient";
Expand Down Expand Up @@ -625,7 +622,7 @@ const routes = {
getPatient: {
path: "/api/v1/otp/patient/",
method: "GET",
TRes: Type<PaginatedResponse<AppointmentPatient>>(),
TRes: Type<PaginatedResponse<Patient>>(),
auth: {
key: "Authorization",
value: "Bearer {token}",
Expand All @@ -636,7 +633,7 @@ const routes = {
path: "/api/v1/otp/patient/",
method: "POST",
TBody: Type<Partial<AppointmentPatientRegister>>(),
TRes: Type<AppointmentPatient>(),
TRes: Type<Patient>(),
auth: {
key: "Authorization",
value: "Bearer {token}",
Expand Down
29 changes: 16 additions & 13 deletions src/Utils/utils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { differenceInMinutes, format } from "date-fns";
import { toPng } from "html-to-image";
import { toast } from "sonner";

import dayjs from "@/Utils/dayjs";
import { Time } from "@/Utils/types";
import { Patient } from "@/types/emr/newPatient";
import { PatientModel } from "@/types/emr/patient";
import {
Organization,
OrganizationParent,
} from "@/types/organization/organization";
import { Quantity } from "@/types/questionnaire/quantity";

const DATE_FORMAT = "DD/MM/YYYY";
Expand Down Expand Up @@ -105,18 +108,6 @@ export const classNames = (...classes: (string | boolean | undefined)[]) => {
return classes.filter(Boolean).join(" ");
};

export const getPincodeDetails = async (pincode: string, apiKey: string) => {
const response = await fetch(
`https://api.data.gov.in/resource/6176ee09-3d56-4a3b-8115-21841576b2f6?api-key=${apiKey}&format=json&filters[pincode]=${pincode}&limit=1`,
);
const data = await response.json();
if (!data.records || data.records.length === 0) {
toast.error("Invalid pincode");
return null;
}
return data.records[0];
};

export const isUserOnline = (user: { last_login: DateLike }) => {
return user.last_login
? dayjs().subtract(5, "minutes").isBefore(user.last_login)
Expand Down Expand Up @@ -281,3 +272,15 @@ export const conditionalArrayAttribute = <T>(
) => {
return condition ? attributes : [];
};

export const stringifyGeoOrganization = (org: Organization) => {
const levels: string[] = [];

let current: OrganizationParent | undefined = org;
while (current?.name) {
levels.push(current.name);
current = current.parent;
}

return levels.join(", ");
};
22 changes: 0 additions & 22 deletions src/common/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -768,25 +768,3 @@ export const PREVIEWABLE_FILE_EXTENSIONS = [
"gif",
"webp",
] as const;

export const HEADER_CONTENT_TYPES = {
pdf: "application/pdf",
txt: "text/plain",
jpeg: "image/jpeg",
jpg: "image/jpeg",
doc: "application/msword",
xls: "application/vnd.ms-excel",
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
epub: "application/epub+zip",
gif: "image/gif",
html: "text/html",
htm: "text/html",
mp4: "video/mp4",
png: "image/png",
ppt: "application/vnd.ms-powerpoint",
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
svg: "image/svg+xml",
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
} as const;

export const ADMIN_USER_TYPES = ["DistrictAdmin", "StateAdmin"] as const;
7 changes: 1 addition & 6 deletions src/components/Common/FacilitySelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ interface BaseFacilitySelectProps {
disabled?: boolean;
multiple?: boolean;
facilityType?: number;
district?: string;
state?: string;
showAll?: boolean;
showNOptions?: number | undefined;
freeText?: boolean;
Expand Down Expand Up @@ -100,10 +98,7 @@ export const FacilitySelect = ({
onChange={setSelected}
fetchData={facilitySearch}
showNOptions={showNOptions}
optionLabel={(option: any) =>
option.name +
(option.district_object ? `, ${option.district_object.name}` : "")
}
optionLabel={(option: any) => option.name}
compareBy="id"
className={className}
error={errors}
Expand Down
70 changes: 4 additions & 66 deletions src/components/Facility/FacilityForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ import { Textarea } from "@/components/ui/textarea";

import { FacilityModel } from "@/components/Facility/models";

import { useStateAndDistrictFromPincode } from "@/hooks/useStateAndDistrictFromPincode";

import { FACILITY_FEATURE_TYPES, FACILITY_TYPES } from "@/common/constants";
import { validatePincode } from "@/common/validation";

Expand All @@ -44,30 +42,21 @@ import validators from "@/Utils/validators";
import GovtOrganizationSelector from "@/pages/Organization/components/GovtOrganizationSelector";
import { BaseFacility } from "@/types/facility/facility";
import { Organization } from "@/types/organization/organization";
import organizationApi from "@/types/organization/organizationApi";

interface FacilityProps {
organizationId?: string;
facilityId?: string;
onSubmitSuccess?: () => void;
}

function extractHierarchyLevels(org: Organization | undefined): Organization[] {
const levels: Organization[] = [];
while (org && org.level_cache >= 0) {
levels.unshift(org as Organization);
org = org.parent as Organization | undefined;
}
return levels;
}

export default function FacilityForm(props: FacilityProps) {
export default function FacilityForm({
facilityId,
onSubmitSuccess,
}: FacilityProps) {
const { t } = useTranslation();
const queryClient = useQueryClient();
const [isGettingLocation, setIsGettingLocation] = useState(false);
const { facilityId, organizationId, onSubmitSuccess } = props;
const [selectedLevels, setSelectedLevels] = useState<Organization[]>([]);
const [showAutoFilledPincode, setShowAutoFilledPincode] = useState(false);

const facilityFormSchema = z.object({
facility_type: z.string().min(1, t("facility_type_required")),
Expand Down Expand Up @@ -172,41 +161,6 @@ export default function FacilityForm(props: FacilityProps) {
}
};

const { stateOrg, districtOrg } = useStateAndDistrictFromPincode({
pincode: form.watch("pincode")?.toString() || "",
});

const { data: org } = useQuery({
queryKey: ["organization", organizationId],
queryFn: query(organizationApi.get, {
pathParams: { id: organizationId },
}),
enabled: !!organizationId && !facilityId,
});

useEffect(() => {
if (facilityId) return;
const orgLevels = extractHierarchyLevels(org);
const districtMatch =
districtOrg && orgLevels.some((level) => level.name === districtOrg.name);
const levels: Organization[] = [];
if (districtMatch) return;
if (stateOrg) levels.push(stateOrg);
if (districtOrg) levels.push(districtOrg);
if (!stateOrg && !districtOrg && org) levels.push(org);

setSelectedLevels(levels);

if (levels.length == 2) {
setShowAutoFilledPincode(true);
const timer = setTimeout(() => {
setShowAutoFilledPincode(false);
}, 5000);
return () => clearTimeout(timer);
}
return () => setShowAutoFilledPincode(false);
}, [stateOrg, districtOrg, organizationId, facilityId]);

// Update form when facility data is loaded
useEffect(() => {
if (facilityData) {
Expand Down Expand Up @@ -367,22 +321,6 @@ export default function FacilityForm(props: FacilityProps) {
/>
</FormControl>
<FormMessage />
{showAutoFilledPincode && (
<div
role="status"
aria-live="polite"
className="flex items-center"
>
<CareIcon
icon="l-check-circle"
className="mr-2 text-sm text-green-500"
aria-hidden="true"
/>
<span className="text-sm text-primary-500">
{t("pincode_autofill")}
</span>
</div>
)}
</FormItem>
)}
/>
Expand Down
Loading
Loading