Skip to content

Commit

Permalink
Remove pin-code autofill feature (#10291)
Browse files Browse the repository at this point in the history
  • Loading branch information
rithviknishad authored Jan 31, 2025
1 parent e4b291a commit 71439ba
Show file tree
Hide file tree
Showing 23 changed files with 63 additions and 492 deletions.
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 @@ -176,41 +165,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 @@ -375,22 +329,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

0 comments on commit 71439ba

Please sign in to comment.