diff --git a/cypress/e2e/auth_spec/ForgotPassword.cy.ts b/cypress/e2e/auth_spec/ForgotPassword.cy.ts deleted file mode 100644 index c1b1db7ecad..00000000000 --- a/cypress/e2e/auth_spec/ForgotPassword.cy.ts +++ /dev/null @@ -1,17 +0,0 @@ -describe("Forgot Password", () => { - beforeEach(() => { - cy.awaitUrl("/", true); - cy.get("button").contains("Forgot password?").click().wait(100); - }); - - it("Send Password Reset Link", () => { - cy.get("input[id='forgot_username']").type("dummy_user_1"); - cy.contains("Send Reset Link").click().wait(1000); - cy.contains("Password Reset Email Sent").should("exist"); - }); - - it("Go to Login page", () => { - cy.get("button").contains("Back to login").click(); - cy.url().should("contain", "/"); - }); -}); diff --git a/cypress/e2e/auth_spec/auth.cy.ts b/cypress/e2e/auth_spec/auth.cy.ts deleted file mode 100644 index b2bd7b634c0..00000000000 --- a/cypress/e2e/auth_spec/auth.cy.ts +++ /dev/null @@ -1,23 +0,0 @@ -describe("Authorisation/Authentication", () => { - beforeEach(() => { - cy.awaitUrl("/", true); - }); - - it("Try login as admin with correct password", () => { - cy.loginByApi("devdistrictadmin", "Coronasafe@123"); - cy.awaitUrl("/facility"); - cy.get("#user-profile-name").click(); - cy.get("#sign-out-button").contains("Sign Out").click(); - cy.url().should("include", "/"); - }); - - it("Try login as admin with incorrect password", () => { - cy.log("Logging in the user: devdistrictadmin:Coronasafe@123"); - - cy.awaitUrl("/", true); - cy.get("input[id='username']").type("devdistrictadmin"); - cy.get("input[id='password']").type("coronasafe@123"); - cy.get("button").contains("Login").click(); - cy.contains("No active account").should("exist"); - }); -}); diff --git a/cypress/e2e/facility_spec/FacilityManage.cy.ts b/cypress/e2e/facility_spec/FacilityManage.cy.ts index 10074e81166..02c14958ccf 100644 --- a/cypress/e2e/facility_spec/FacilityManage.cy.ts +++ b/cypress/e2e/facility_spec/FacilityManage.cy.ts @@ -1,5 +1,3 @@ -import { v4 as uuidv4 } from "uuid"; - import FacilityPage from "../../pageobject/Facility/FacilityCreation"; import FacilityManage from "../../pageobject/Facility/FacilityManage"; import LoginPage from "../../pageobject/Login/LoginPage"; @@ -14,11 +12,10 @@ describe("Facility Manage Functions", () => { const facilityUpdatedMiddleware = "updated.coronasafe.live"; const facilityMiddlewareSuccessfullNotification = "Facility middleware updated successfully"; - const facilityHfridUpdateButton = "Link Health Facility"; - const facilityHfridToastNotificationText = - /Health Facility config updated successfully|Health ID registration failed/; - const facilityHfrId = "IN180000018"; - const facilityUpdatedHfrId = uuidv4(); + // const facilityHfridUpdateButton = "Link Health Facility"; + // const facilityHfridToastNotificationText = /Health Facility config updated successfully|Health ID registration failed/; + // const facilityHfrId = "IN180000018"; + // const facilityUpdatedHfrId = uuidv4(); const doctorCapacity = "5"; const doctorModifiedCapacity = "7"; const totalCapacity = "100"; @@ -79,36 +76,37 @@ describe("Facility Manage Functions", () => { facilityManage.verifyMiddlewareAddressValue(facilityUpdatedMiddleware); }); - it("Configure Facility Health ID", () => { - facilityPage.clickManageFacilityDropdown(); - facilityManage.clickFacilityConfigureButton(); - // verify mandatory field error message - facilityManage.clearHfrId(); - facilityManage.clickButtonWithText(facilityHfridUpdateButton); - facilityManage.checkErrorMessageVisibility( - "Health Facility Id is required", - ); - // add facility health ID and verify notification - facilityManage.typeHfrId(facilityHfrId); - facilityManage.clickButtonWithText(facilityHfridUpdateButton); - facilityManage.verifySuccessMessageVisibilityAndContent( - facilityHfridToastNotificationText, - true, - ); - // update the existing middleware - facilityPage.clickManageFacilityDropdown(); - facilityManage.clickFacilityConfigureButton(); - facilityManage.typeHfrId(facilityUpdatedHfrId); - facilityManage.clickButtonWithText(facilityHfridUpdateButton); - facilityManage.verifySuccessMessageVisibilityAndContent( - facilityHfridToastNotificationText, - true, - ); - // verify its reflection - facilityPage.clickManageFacilityDropdown(); - facilityManage.clickFacilityConfigureButton(); - facilityManage.verifyHfrIdValue(facilityUpdatedHfrId); - }); + // TODO: enable this test after configuring testing specs for plugs + // it("Configure Facility Health ID", () => { + // facilityPage.clickManageFacilityDropdown(); + // facilityManage.clickFacilityConfigureButton(); + // // verify mandatory field error message + // facilityManage.clearHfrId(); + // facilityManage.clickButtonWithText(facilityHfridUpdateButton); + // facilityManage.checkErrorMessageVisibility( + // "Health Facility Id is required", + // ); + // // add facility health ID and verify notification + // facilityManage.typeHfrId(facilityHfrId); + // facilityManage.clickButtonWithText(facilityHfridUpdateButton); + // facilityManage.verifySuccessMessageVisibilityAndContent( + // facilityHfridToastNotificationText, + // true, + // ); + // // update the existing middleware + // facilityPage.clickManageFacilityDropdown(); + // facilityManage.clickFacilityConfigureButton(); + // facilityManage.typeHfrId(facilityUpdatedHfrId); + // facilityManage.clickButtonWithText(facilityHfridUpdateButton); + // facilityManage.verifySuccessMessageVisibilityAndContent( + // facilityHfridToastNotificationText, + // true, + // ); + // // verify its reflection + // facilityPage.clickManageFacilityDropdown(); + // facilityManage.clickFacilityConfigureButton(); + // facilityManage.verifyHfrIdValue(facilityUpdatedHfrId); + // }); it("Modify doctor capacity in Facility detail page", () => { // Add a doctor capacity diff --git a/cypress/e2e/homepage_spec/UserLogin.cy.ts b/cypress/e2e/homepage_spec/UserLogin.cy.ts new file mode 100644 index 00000000000..ab00bd80ff1 --- /dev/null +++ b/cypress/e2e/homepage_spec/UserLogin.cy.ts @@ -0,0 +1,48 @@ +import LoginPage from "pageobject/Login/LoginPage"; + +const loginPage = new LoginPage(); +const userName = "dummy_user_1"; +const forgotPasswordHeading = "Forgot password?"; + +describe("User login workflow with correct and incorrect passwords", () => { + beforeEach(() => { + cy.awaitUrl("/", true); + }); + + it("Log in as admin with correct password", () => { + loginPage.loginManuallyAsDistrictAdmin(); + loginPage.interceptFacilityReq(); + loginPage.verifyFacilityReq(); + loginPage.ensureLoggedIn(); + loginPage.clickSignOutBtn(); + loginPage.verifyLoginPageUrl(); + }); + + it("Display an error when logging in as admin with incorrect password", () => { + loginPage.interceptLoginReq(); + loginPage.loginManuallyAsDistrictAdmin(false); + loginPage.verifyLoginReq(); + cy.verifyNotification("No active account found with the given credentials"); + cy.closeNotification(); + }); +}); + +describe("Reset user's password using email", () => { + beforeEach(() => { + cy.awaitUrl("/", true); + }); + + it("Send a password reset link and navigate back to the login page", () => { + loginPage.clickForgotPasswordButton(forgotPasswordHeading); + loginPage.verifyForgotPasswordHeading([forgotPasswordHeading]); + loginPage.fillUserNameInForgotPasswordForm(userName); + loginPage.interceptResetLinkReq(); + loginPage.clickSendResetLinkBtn(); + loginPage.verifyResetLinkReq(); + cy.verifyNotification("Password Reset Email Sent"); + cy.closeNotification(); + loginPage.clickBackButton(); + loginPage.verifyLoginPageUrl(); + loginPage.verifyLoginButtonPresence(); + }); +}); diff --git a/cypress/e2e/auth_spec/redirect.cy.ts b/cypress/e2e/homepage_spec/redirect.cy.ts similarity index 100% rename from cypress/e2e/auth_spec/redirect.cy.ts rename to cypress/e2e/homepage_spec/redirect.cy.ts diff --git a/cypress/e2e/patient_spec/PatientInvestigation.cy.ts b/cypress/e2e/patient_spec/PatientInvestigation.cy.ts index 380adf2c37e..7426890d5a6 100644 --- a/cypress/e2e/patient_spec/PatientInvestigation.cy.ts +++ b/cypress/e2e/patient_spec/PatientInvestigation.cy.ts @@ -7,7 +7,7 @@ describe("Patient Investigation Creation from Patient consultation page", () => const loginPage = new LoginPage(); const patientPage = new PatientPage(); const patientInvestigation = new PatientInvestigation(); - const patientName = "Dummy Patient 12"; + const patientName = "Dummy Patient 14"; before(() => { loginPage.loginAsDistrictAdmin(); diff --git a/cypress/e2e/users_spec/UsersManage.cy.ts b/cypress/e2e/users_spec/UsersManage.cy.ts index 9ed4fe34ec7..8899d951175 100644 --- a/cypress/e2e/users_spec/UsersManage.cy.ts +++ b/cypress/e2e/users_spec/UsersManage.cy.ts @@ -7,10 +7,12 @@ describe("Manage User", () => { const loginPage = new LoginPage(); const userPage = new UserPage(); const manageUserPage = new ManageUserPage(); - const usernametolinkfacilitydoc1 = "dummydoctor4"; - const usernametolinkfacilitydoc2 = "dummydoctor5"; - const usernametolinkfacilitydoc3 = "dummydoctor6"; - const usernametolinkskill = "devdoctor"; + const usernameToLinkFacilitydoc1 = "dummydoctor4"; + const usernameToLinkFacilitydoc2 = "dummydoctor5"; + const usernameToLinkFacilitydoc3 = "dummydoctor6"; + const usernameToLinkSkill = "devdoctor"; + const firstNameUserSkill = "Dev"; + const lastNameUserSkill = "Doctor"; const userCreationPage = new UserCreationPage(); const usernameforworkinghour = "devdistrictadmin"; const usernamerealname = "Dummy Doctor"; @@ -53,8 +55,11 @@ describe("Manage User", () => { it("linking skills for a doctor users and verify its reflection in doctor connect", () => { // select a doctor user and link and unlink same skill twice and verify the badge is only shown once in doctor connect - userPage.typeInSearchInput(usernametolinkskill); - userPage.checkUsernameText(usernametolinkskill); + userPage.clickAdvancedFilters(); + userPage.typeInFirstName(firstNameUserSkill); + userPage.typeInLastName(lastNameUserSkill); + userPage.applyFilter(); + userPage.checkUsernameText(usernameToLinkSkill); manageUserPage.clicklinkedskillbutton(); manageUserPage.selectSkillFromDropdown(linkedskill); manageUserPage.clickAddSkillButton(); @@ -94,8 +99,8 @@ describe("Manage User", () => { it("linking and unlinking facility for multiple users, and confirm reflection in user cards and doctor connect", () => { // verify the user doesn't have any home facility - userPage.typeInSearchInput(usernametolinkfacilitydoc1); - userPage.checkUsernameText(usernametolinkfacilitydoc1); + userPage.typeInSearchInput(usernameToLinkFacilitydoc1); + userPage.checkUsernameText(usernameToLinkFacilitydoc1); manageUserPage.assertHomeFacility("No Home Facility"); // Link a new facility and ensure it is under linked facility - doctor username (1) manageUserPage.clickFacilitiesTab(); @@ -107,8 +112,8 @@ describe("Manage User", () => { manageUserPage.clickCloseSlideOver(); // Link a new facility and ensure it is under home facility - doctor username (2) userPage.clearSearchInput(); - userPage.typeInSearchInput(usernametolinkfacilitydoc2); - userPage.checkUsernameText(usernametolinkfacilitydoc2); + userPage.typeInSearchInput(usernameToLinkFacilitydoc2); + userPage.checkUsernameText(usernameToLinkFacilitydoc2); manageUserPage.clickFacilitiesTab(); manageUserPage.selectFacilityFromDropdown(facilitytolinkusername); manageUserPage.clickLinkFacility(); @@ -118,13 +123,13 @@ describe("Manage User", () => { manageUserPage.clickCloseSlideOver(); // verify the home facility doctor id have reflection in user card userPage.clearSearchInput(); - userPage.typeInSearchInput(usernametolinkfacilitydoc2); - userPage.checkUsernameText(usernametolinkfacilitydoc2); + userPage.typeInSearchInput(usernameToLinkFacilitydoc2); + userPage.checkUsernameText(usernameToLinkFacilitydoc2); manageUserPage.assertHomeFacility(facilitytolinkusername); // Link a new facility and unlink the facility from the doctor username (3) userPage.clearSearchInput(); - userPage.typeInSearchInput(usernametolinkfacilitydoc3); - userPage.checkUsernameText(usernametolinkfacilitydoc3); + userPage.typeInSearchInput(usernameToLinkFacilitydoc3); + userPage.checkUsernameText(usernameToLinkFacilitydoc3); manageUserPage.clickFacilitiesTab(); manageUserPage.selectFacilityFromDropdown(facilitytolinkusername); manageUserPage.clickLinkFacility(); diff --git a/cypress/pageobject/Login/LoginPage.ts b/cypress/pageobject/Login/LoginPage.ts index 38b8aeee2af..07eb4486d17 100644 --- a/cypress/pageobject/Login/LoginPage.ts +++ b/cypress/pageobject/Login/LoginPage.ts @@ -13,16 +13,20 @@ class LoginPage { cy.loginByApi("staffdev", "Coronasafe@123"); } - loginManuallyAsDistrictAdmin(): void { + loginManuallyAsDistrictAdmin(isCorrectCredentials: boolean = true): void { cy.get("input[id='username']").type("devdistrictadmin"); - cy.get("input[id='password']").type("Coronasafe@123"); - cy.get("button").contains("Login").click(); + if (isCorrectCredentials) { + cy.get("input[id='password']").type("Coronasafe@123"); + } else { + cy.get("input[id='password']").type("Corona"); + } + cy.submitButton("Login"); } loginManuallyAsNurse(): void { cy.get("input[id='username']").click().type("dummynurse1"); cy.get("input[id='password']").click().type("Coronasafe@123"); - cy.get("button").contains("Login").click(); + cy.submitButton("Login"); } login(username: string, password: string): void { @@ -38,6 +42,58 @@ class LoginPage { clickSignOutBtn(): void { cy.verifyAndClickElement("#sign-out-button", "Sign Out"); } + + fillUserNameInForgotPasswordForm(userName: string): void { + cy.get("#forgot_username").type(userName); + } + + clickSendResetLinkBtn(): void { + cy.verifyAndClickElement("#send-reset-link-btn", "Send Reset Link"); + } + + verifyLoginPageUrl(): void { + cy.url().should("include", "/"); + } + + clickBackButton(): void { + cy.verifyAndClickElement("#back-to-login-btn", "Back to login"); + } + + clickForgotPasswordButton(text: string): void { + cy.verifyAndClickElement("#forgot-pass-btn", text); + } + + interceptFacilityReq(): void { + cy.intercept("GET", "**/api/v1/facility/**").as("getFacilities"); + } + + verifyFacilityReq(): void { + cy.wait("@getFacilities").its("response.statusCode").should("eq", 200); + } + + interceptLoginReq(): void { + cy.intercept("POST", "**/api/v1/auth/login").as("userLogin"); + } + + verifyLoginReq(): void { + cy.wait("@userLogin").its("response.statusCode").should("eq", 401); + } + + interceptResetLinkReq(): void { + cy.intercept("POST", "**/api/v1/password_reset").as("resetLink"); + } + + verifyResetLinkReq(): void { + cy.wait("@resetLink").its("response.statusCode").should("eq", 200); + } + + verifyLoginButtonPresence(): void { + cy.verifyContentPresence("#login-button", ["Login"]); + } + + verifyForgotPasswordHeading(text: string[]): void { + cy.verifyContentPresence("#forgot-password-heading", text); + } } export default LoginPage; diff --git a/src/App.tsx b/src/App.tsx index 62a173c8409..d3fec38dbed 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -11,23 +11,27 @@ import HistoryAPIProvider from "@/Providers/HistoryAPIProvider"; import Routers from "@/Routers"; import { FeatureFlagsProvider } from "@/Utils/featureFlags"; +import { PubSubProvider } from "./Utils/pubsubContext"; + const App = () => { return ( }> - - - }> - - - - + + + + }> + + + + - {/* Integrations */} - - - - - + {/* Integrations */} + + + + + + ); }; diff --git a/src/Routers/AppRouter.tsx b/src/Routers/AppRouter.tsx index c8f6fbec83e..686094c9be1 100644 --- a/src/Routers/AppRouter.tsx +++ b/src/Routers/AppRouter.tsx @@ -4,8 +4,6 @@ import { useEffect, useState } from "react"; import IconIndex from "@/CAREUI/icons/Index"; -import ABDMFacilityRecords from "@/components/ABDM/ABDMFacilityRecords"; -import HealthInformation from "@/components/ABDM/HealthInformation"; import { DesktopSidebar, MobileSidebar, @@ -60,13 +58,6 @@ const Routes: AppRoutes = { "/notifications/:id": ({ id }) => , "/notice_board": () => , - "/abdm/health-information/:id": ({ id }) => ( - - ), - "/facility/:facilityId/abdm": ({ facilityId }) => ( - - ), - "/session-expired": () => , "/not-found": () => , "/icons": () => , diff --git a/src/Utils/pubsubContext.tsx b/src/Utils/pubsubContext.tsx new file mode 100644 index 00000000000..f1e76850913 --- /dev/null +++ b/src/Utils/pubsubContext.tsx @@ -0,0 +1,81 @@ +import { createContext, useContext, useState } from "react"; + +export type Handler = (message: unknown) => Promise; +export type PubSubContext = { + subscribe: (topic: string, handler: Handler) => void; + unsubscribe: (topic: string, handler: Handler) => void; + publish: (topic: string, message: unknown) => void; + subscribers: Record>; + setSubscribers: React.Dispatch< + React.SetStateAction>> + >; +}; + +const PubSubContext = createContext(null); + +export const PubSubProvider = ({ children }: { children: React.ReactNode }) => { + const [subscribers, setSubscribers] = useState>>( + {}, + ); + + const subscribe = (topic: string, handler: Handler) => { + setSubscribers((prev) => ({ + ...prev, + [topic]: new Set([...(prev[topic] || []), handler]), + })); + }; + + const unsubscribe = (topic: string, handler: Handler) => { + setSubscribers((prev) => { + const handlers = prev[topic]; + if (!handlers) { + return prev; + } + + const newHandlers = new Set(handlers); + newHandlers.delete(handler); + + if (newHandlers.size === 0) { + const { [topic]: _, ...rest } = prev; + return rest; + } + + return { + ...prev, + [topic]: newHandlers, + }; + }); + }; + + const publish = (topic: string, message: unknown) => { + if (!subscribers[topic]) { + return; + } + + subscribers[topic].forEach(async (handler) => { + try { + await handler(message); + } catch (error) { + console.error(`Handler failed for topic ${topic}:`, error); + } + }); + }; + + return ( + + {children} + + ); +}; + +export const usePubSub = () => { + const context = useContext(PubSubContext); + + if (!context) { + throw new Error("usePubSub must be used within PubSubProvider"); + } + + return context; +}; diff --git a/src/Utils/request/api.tsx b/src/Utils/request/api.tsx index e1777364b3f..d6d30dfce85 100644 --- a/src/Utils/request/api.tsx +++ b/src/Utils/request/api.tsx @@ -1,14 +1,3 @@ -import { AbhaNumberModel } from "@/components/ABDM/types/abha"; -import { - ConsentRequestModel, - CreateConsentTBody, -} from "@/components/ABDM/types/consent"; -import { - IHealthFacility, - IcreateHealthFacilityTBody, - IpartialUpdateHealthFacilityTBody, -} from "@/components/ABDM/types/health-facility"; -import { HealthInformationModel } from "@/components/ABDM/types/health-information"; import { AssetBedBody, AssetBedModel, @@ -1347,246 +1336,6 @@ const routes = { TBody: Type(), }, - abdm: { - consent: { - list: { - path: "/api/abdm/consent/", - method: "GET", - TRes: Type>(), - }, - - create: { - path: "/api/abdm/consent/", - method: "POST", - TRes: Type(), - TBody: Type(), - }, - - get: { - path: "/api/abdm/consent/{id}/", - method: "GET", - }, - - checkStatus: { - path: "/api/abdm/v3/hiu/consent_request_status/", - method: "POST", - TBody: Type<{ - consent_request: string; - }>(), - TRes: Type<{ - detail: string; - }>(), - }, - }, - - healthInformation: { - get: { - path: "/api/abdm/health_information/{artefactId}", - method: "GET", - TRes: Type(), - }, - }, - - healthFacility: { - list: { - path: "/api/abdm/health_facility/", - method: "GET", - }, - - create: { - path: "/api/abdm/health_facility/", - method: "POST", - TRes: Type(), - TBody: Type(), - }, - - get: { - path: "/api/abdm/health_facility/{facility_id}/", - method: "GET", - TRes: Type(), - }, - - update: { - path: "/api/abdm/health_facility/{facility_id}/", - method: "PUT", - TRes: Type(), - TBody: Type(), - }, - - partialUpdate: { - path: "/api/abdm/health_facility/{facility_id}/", - method: "PATCH", - TRes: Type(), - TBody: Type(), - }, - - registerAsService: { - path: "/api/abdm/health_facility/{facility_id}/register_service/", - method: "POST", - TRes: Type(), - TBody: Type(), - }, - }, - - abhaNumber: { - get: { - path: "/api/abdm/abha_number/{abhaNumberId}/", - method: "GET", - TRes: Type(), - }, - create: { - path: "/api/abdm/abha_number/", - method: "POST", - TBody: Type>(), - TRes: Type(), - }, - }, - - healthId: { - abhaCreateSendAadhaarOtp: { - path: "/api/abdm/v3/health_id/create/send_aadhaar_otp/", - method: "POST", - TBody: Type<{ - aadhaar: string; - transaction_id?: string; - }>(), - TRes: Type<{ - transaction_id: string; - detail: string; - }>(), - }, - - abhaCreateVerifyAadhaarOtp: { - path: "/api/abdm/v3/health_id/create/verify_aadhaar_otp/", - method: "POST", - TBody: Type<{ - transaction_id: string; - otp: string; - mobile: string; - }>(), - TRes: Type<{ - transaction_id: string; - detail: string; - is_new: boolean; - abha_number: AbhaNumberModel; - }>(), - }, - - abhaCreateLinkMobileNumber: { - path: "/api/abdm/v3/health_id/create/link_mobile_number/", - method: "POST", - TBody: Type<{ - transaction_id: string; - mobile: string; - }>(), - TRes: Type<{ - transaction_id: string; - detail: string; - }>(), - }, - - abhaCreateVerifyMobileNumber: { - path: "/api/abdm/v3/health_id/create/verify_mobile_otp/", - method: "POST", - TBody: Type<{ - transaction_id: string; - otp: string; - }>(), - TRes: Type<{ - transaction_id: string; - detail: string; - }>(), - }, - - abhaCreateAbhaAddressSuggestion: { - path: "/api/abdm/v3/health_id/create/abha_address_suggestion/", - method: "POST", - TBody: Type<{ - transaction_id: string; - }>(), - TRes: Type<{ - transaction_id: string; - abha_addresses: string[]; - }>(), - }, - - abhaCreateEnrolAbhaAddress: { - path: "/api/abdm/v3/health_id/create/enrol_abha_address/", - method: "POST", - TBody: Type<{ - transaction_id: string; - abha_address: string; - }>(), - TRes: Type<{ - detail?: string; - transaction_id: string; - health_id: string; - preferred_abha_address: string; - abha_number: AbhaNumberModel; - }>(), - }, - - linkAbhaNumberAndPatient: { - path: "/api/abdm/v3/health_id/link_patient/", - method: "POST", - TBody: Type<{ - abha_number: string; - patient: string; - }>(), - TRes: Type<{ - detail: string; - }>(), - }, - - abhaLoginCheckAuthMethods: { - path: "/api/abdm/v3/health_id/login/check_auth_methods/", - method: "POST", - TBody: Type<{ - abha_address: string; - }>(), - TRes: Type<{ - abha_number: string; - auth_methods: string[]; - }>(), - }, - - abhaLoginSendOtp: { - path: "/api/abdm/v3/health_id/login/send_otp/", - method: "POST", - TBody: Type<{ - type: "abha-number" | "abha-address" | "mobile" | "aadhaar"; - value: string; - otp_system: "abdm" | "aadhaar"; - }>(), - TRes: Type<{ - transaction_id: string; - detail: string; - }>(), - }, - - abhaLoginVerifyOtp: { - path: "/api/abdm/v3/health_id/login/verify_otp/", - method: "POST", - TBody: Type<{ - type: "abha-number" | "abha-address" | "mobile" | "aadhaar"; - otp: string; - transaction_id: string; - otp_system: "abdm" | "aadhaar"; - }>(), - TRes: Type<{ - abha_number: AbhaNumberModel; - created: boolean; - }>(), - }, - - getAbhaCard: { - path: "/api/abdm/v3/health_id/abha_card", - method: "GET", - TRes: Type(), - }, - }, - }, - // Prescription endpoints listPrescriptions: { diff --git a/src/common/constants.tsx b/src/common/constants.tsx index b917ea1aa68..857796d7c88 100644 --- a/src/common/constants.tsx +++ b/src/common/constants.tsx @@ -1,6 +1,5 @@ import { IconName } from "@/CAREUI/icons/CareIcon"; -import { ConsentHIType, ConsentPurpose } from "@/components/ABDM/types/consent"; import { SortOption } from "@/components/Common/SortDropdown"; import { PatientCategory, @@ -8,10 +7,10 @@ import { } from "@/components/Facility/models"; import { PhoneNumberValidator } from "@/components/Form/FieldValidators"; -import { SchemaType } from "@/common/schemaParser"; - import { dateQueryString } from "@/Utils/utils"; +import { SchemaType } from "./schemaParser"; + export const RESULTS_PER_PAGE_LIMIT = 14; export const PAGINATION_LIMIT = 36; @@ -1142,26 +1141,6 @@ export const AssetImportSchema: SchemaType = { }, }; -// ABDM -export const ABDM_CONSENT_PURPOSE = [ - "CAREMGT", - "BTG", - "PUBHLTH", - "HPAYMT", - "DSRCH", - "PATRQT", -] as ConsentPurpose[]; - -export const ABDM_HI_TYPE = [ - "Prescription", - "DiagnosticReport", - "OPConsultation", - "DischargeSummary", - "ImmunizationRecord", - "HealthDocumentRecord", - "WellnessRecord", -] as ConsentHIType[]; - export const USER_TYPES_MAP = { Pharmacist: "Pharmacist", Volunteer: "Volunteer", diff --git a/src/components/ABDM/ABDMFacilityRecords.tsx b/src/components/ABDM/ABDMFacilityRecords.tsx deleted file mode 100644 index ef3a1da8ab4..00000000000 --- a/src/components/ABDM/ABDMFacilityRecords.tsx +++ /dev/null @@ -1,202 +0,0 @@ -import { Link } from "raviger"; -import { useTranslation } from "react-i18next"; - -import CareIcon from "@/CAREUI/icons/CareIcon"; - -import ButtonV2 from "@/components/Common/ButtonV2"; -import Loading from "@/components/Common/Loading"; -import Page from "@/components/Common/Page"; - -import routes from "@/Utils/request/api"; -import useQuery from "@/Utils/request/useQuery"; -import { classNames, formatDateTime } from "@/Utils/utils"; - -interface IProps { - facilityId: string; -} - -const TableHeads = [ - "consent__patient", - "consent__status", - "created_on", - "updated_on", - "consent__hi_range", - "expires_on", - "consent__hi_types", -]; - -export default function ABDMFacilityRecords({ facilityId }: IProps) { - const { t } = useTranslation(); - - const { - data: consentsResult, - loading, - refetch, - } = useQuery(routes.abdm.consent.list, { - query: { facility: facilityId, ordering: "-created_date" }, - }); - - if (loading) { - return ; - } - - return ( - -
-
-
-
-
-
- - - - {TableHeads.map((head) => ( - - ))} - - - - - {consentsResult?.results.map((consent) => ( - - - - - - - - - - - - - - - - - - ))} - -
- {t(head)} - - refetch()} - ghost - className="max-w-2xl text-sm text-secondary-700 hover:text-secondary-900" - > - {t("refresh")} - - {t("view")} -
- {consent.patient_abha_object?.name} -

- ({consent.patient_abha}) -

-
- {new Date( - consent.consent_artefacts?.[0]?.expiry ?? - consent.expiry, - ) < new Date() - ? t("consent__status__EXPIRED") - : t( - `consent__status__${ - consent.consent_artefacts?.[0]?.status ?? - consent.status - }`, - )} - - {formatDateTime(consent.created_date)} - - {consent.status === "EXPIRED" || - new Date( - consent.consent_artefacts?.[0]?.expiry ?? - consent.expiry, - ) < new Date() ? ( -

- {formatDateTime( - consent.consent_artefacts?.[0]?.expiry ?? - consent.expiry, - )} - - {t("expired_on")} - -

- ) : consent.status === "REQUESTED" ? ( - "-" - ) : ( -

- {formatDateTime(consent.modified_date)} - - {t(`${consent.status.toLowerCase()}_on`)} - -

- )} -
- {formatDateTime( - consent.consent_artefacts?.[0]?.from_time ?? - consent.from_time, - )}{" "} -
- {formatDateTime( - consent.consent_artefacts?.[0]?.to_time ?? - consent.to_time, - )} -
- {formatDateTime( - consent.consent_artefacts?.[0]?.expiry ?? - consent.expiry, - )} - -
- {( - consent.consent_artefacts?.[0]?.hi_types ?? - consent.hi_types - )?.map((hiType) => ( - - {t(`consent__hi_type__${hiType}`)} - - ))} -
-
-
- new Date() - ? "cursor-pointer text-primary-600 hover:text-primary-900" - : "pointer-events-none cursor-not-allowed text-secondary-600 opacity-70", - )} - > - {t("view")} - -
-
-
-
- {consentsResult?.results.length === 0 && ( -
-

- {t("no_records_found")} -

-
- )} -
-
-
-
- ); -} diff --git a/src/components/ABDM/ABDMRecordsTab.tsx b/src/components/ABDM/ABDMRecordsTab.tsx deleted file mode 100644 index 3b6f2493fb4..00000000000 --- a/src/components/ABDM/ABDMRecordsTab.tsx +++ /dev/null @@ -1,205 +0,0 @@ -import dayjs from "dayjs"; -import { Link } from "raviger"; -import { useTranslation } from "react-i18next"; - -import CareIcon from "@/CAREUI/icons/CareIcon"; - -import { - ConsentArtefactModel, - ConsentRequestModel, -} from "@/components/ABDM/types/consent"; -import ButtonV2 from "@/components/Common/ButtonV2"; -import Loading from "@/components/Common/Loading"; - -import * as Notification from "@/Utils/Notifications"; -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; -import useQuery from "@/Utils/request/useQuery"; -import { classNames, formatName } from "@/Utils/utils"; - -interface IConsentArtefactCardProps { - artefact: ConsentArtefactModel; -} - -function ConsentArtefactCard({ artefact }: IConsentArtefactCardProps) { - const { t } = useTranslation(); - - return ( - -
-
-
- {artefact.hip} -
-

- {t("created_on")} {dayjs(artefact.created_date).fromNow()} -

-
-
-
- {artefact.status} -
-
- {dayjs(artefact.from_time).format("MMM DD YYYY")} -{" "} - {dayjs(artefact.to_time).format("MMM DD YYYY")} -
-

- {t("expires_on")} {dayjs(artefact.expiry).fromNow()} -

-
-
-
- {artefact.hi_types.map((hiType) => { - return ( -
- {t(`consent__hi_type__${hiType}`)} -
- ); - })} -
- - ); -} - -interface IConsentRequestCardProps { - consent: ConsentRequestModel; -} - -function ConsentRequestCard({ consent }: IConsentRequestCardProps) { - const { t } = useTranslation(); - - return ( -
-
-
-
- {t(`consent__purpose__${consent.purpose}`)} -
-
- {formatName(consent.requester)} -
-
-
-
- {dayjs(consent.from_time).format("MMM DD YYYY")} -{" "} - {dayjs(consent.to_time).format("MMM DD YYYY")} -
-

- {t("expires_on")} {dayjs(consent.expiry).fromNow()} -

-
-
- { - const { res, data } = await request( - routes.abdm.consent.checkStatus, - { - body: { - consent_request: consent.id, - }, - }, - ); - - if (res?.status === 202) { - Notification.Success({ - msg: data?.detail ?? t("checking_consent_status"), - }); - Notification.Warn({ - msg: t("async_operation_warning"), - }); - } - }} - ghost - className="max-w-2xl text-sm text-secondary-700 hover:text-secondary-900" - > - {t("check_status")} - -

- {t("created_on")} {dayjs(consent.created_date).fromNow()} -

-

- {t("modified_on")} {dayjs(consent.modified_date).fromNow()} -

-
-
- {consent.consent_artefacts?.length ? ( -
- {consent.consent_artefacts?.map((artefact) => ( - - ))} -
- ) : ( -
-

- {consent.status === "REQUESTED" - ? t("consent_request_waiting_approval") - : t("consent_request_rejected")} -

-
- )} -
- {consent.hi_types.map((hiType) => { - return ( -
- {t(`consent__hi_type__${hiType}`)} -
- ); - })} -
-
- ); -} - -interface IProps { - patientId: string; -} - -export default function ABDMRecordsTab({ patientId }: IProps) { - const { t } = useTranslation(); - - const { data, loading } = useQuery(routes.abdm.consent.list, { - query: { - patient: patientId, - ordering: "-created_date", - }, - }); - - if (loading) { - ; - } - - if (!data?.results.length) { - return ( -
-

- {t("no_records_found")} -

-

- {t("raise_consent_request")} -

-
- ); - } - - return ( -
- {data?.results.map((record) => { - return ; - })} -
- ); -} diff --git a/src/components/ABDM/ABHAProfileModal.tsx b/src/components/ABDM/ABHAProfileModal.tsx deleted file mode 100644 index 3fc874ca86e..00000000000 --- a/src/components/ABDM/ABHAProfileModal.tsx +++ /dev/null @@ -1,164 +0,0 @@ -import { QRCodeSVG } from "qrcode.react"; -import { useRef } from "react"; -import { useTranslation } from "react-i18next"; - -import CareIcon from "@/CAREUI/icons/CareIcon"; - -import { AbhaNumberModel } from "@/components/ABDM/types/abha"; -import DialogModal from "@/components/Common/Dialog"; - -import * as Notify from "@/Utils/Notifications"; -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; -import { formatDateTime } from "@/Utils/utils"; - -interface IProps { - patientId?: string; - abha?: AbhaNumberModel; - show: boolean; - onClose: () => void; -} - -const ABHAProfileModal = ({ patientId, show, onClose, abha }: IProps) => { - const { t } = useTranslation(); - - const printRef = useRef(null); - - const downloadAbhaCard = async (type: "pdf" | "png") => { - if (!patientId || !abha?.abha_number) return; - - Notify.Success({ msg: t("downloading_abha_card") }); - - const { res, data } = await request(routes.abdm.healthId.getAbhaCard, { - query: { abha_id: abha?.abha_number }, - }); - - if (res?.status === 200 && data) { - const imageUrl = URL.createObjectURL(data); - - if (type === "png") { - const downloadLink = document.createElement("a"); - downloadLink.href = imageUrl; - downloadLink.download = "abha.png"; - downloadLink.click(); - URL.revokeObjectURL(imageUrl); - } else { - const printWindow = window.open("", "_blank"); - const htmlPopup = ` - - - Print Image - - - - - - - `; - printWindow?.document.write(htmlPopup); - printWindow?.document.close(); - printWindow?.addEventListener("load", () => { - printWindow?.print(); - URL.revokeObjectURL(imageUrl); - }); - } - } - }; - - return ( - -

{t("abha_profile")}

-
- downloadAbhaCard("pdf")} - icon="l-print" - className="cursor-pointer" - /> - downloadAbhaCard("png")} - icon="l-import" - className="cursor-pointer" - /> -
- - } - show={show} - onClose={onClose} - className="max-w-[500px]" - fixedWidth={false} - > -
-
- -
-
- {[ - { - label: t("full_name"), - value: - abha?.name || - `${abha?.first_name} ${abha?.middle_name} ${abha?.last_name}`, - }, - { label: t("date_of_birth"), value: abha?.date_of_birth }, - { label: t("gender"), value: abha?.gender }, - { label: t("abha_number"), value: abha?.abha_number }, - { - label: t("abha_address"), - value: abha?.health_id?.split("@")[0], - }, - { label: t("email"), value: abha?.email }, - ].map((item, index) => - item.value ? ( -
-
{item.label}
-
{item.value}
-
- ) : null, - )} -
-
- -
- {abha?.created_date && ( -
- {t("created_on")}: - {formatDateTime(abha.created_date)} -
- )} - {abha?.modified_date && ( -
- {t("modified_on")}: - {formatDateTime(abha.modified_date)} -
- )} -
-
- ); -}; - -export default ABHAProfileModal; diff --git a/src/components/ABDM/ConfigureHealthFacility.tsx b/src/components/ABDM/ConfigureHealthFacility.tsx deleted file mode 100644 index ba3eb325dec..00000000000 --- a/src/components/ABDM/ConfigureHealthFacility.tsx +++ /dev/null @@ -1,243 +0,0 @@ -import { navigate } from "raviger"; -import { useReducer, useState } from "react"; -import { useTranslation } from "react-i18next"; - -import { IHealthFacility } from "@/components/ABDM/types/health-facility"; -import { Submit } from "@/components/Common/ButtonV2"; -import Loading from "@/components/Common/Loading"; -import TextFormField from "@/components/Form/FormFields/TextFormField"; -import { FieldChangeEvent } from "@/components/Form/FormFields/Utils"; - -import * as Notification from "@/Utils/Notifications"; -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; -import useQuery from "@/Utils/request/useQuery"; -import { classNames } from "@/Utils/utils"; - -const initForm = { - health_facility: null as IHealthFacility | null, - hf_id: "", -}; - -const initialState = { - form: { ...initForm }, - errors: {} as Partial>, -}; - -const FormReducer = ( - state = initialState, - action: - | { - type: "set_form"; - form: typeof initialState.form; - } - | { - type: "set_error"; - errors: typeof initialState.errors; - }, -) => { - switch (action.type) { - case "set_form": { - return { - ...state, - form: action.form, - }; - } - case "set_error": { - return { - ...state, - errors: action.errors, - }; - } - default: - return state; - } -}; - -export interface IConfigureHealthFacilityProps { - facilityId: string; -} - -export const ConfigureHealthFacility = ( - props: IConfigureHealthFacilityProps, -) => { - const { t } = useTranslation(); - - const [state, dispatch] = useReducer(FormReducer, initialState); - const { facilityId } = props; - const [isLoading, setIsLoading] = useState(false); - - const { loading } = useQuery(routes.abdm.healthFacility.get, { - pathParams: { facility_id: facilityId }, - silent: true, - onResponse(res) { - if (res.data) { - dispatch({ - type: "set_form", - form: { - ...state.form, - health_facility: res.data, - hf_id: res.data.hf_id, - }, - }); - } - }, - }); - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setIsLoading(true); - - if (!state.form.hf_id) { - dispatch({ - type: "set_error", - errors: { hf_id: t("health_facility__validation__hf_id_required") }, - }); - setIsLoading(false); - return; - } - - let response = null; - let responseData = null; - if (state.form.hf_id === state.form.health_facility?.hf_id) { - const { res, data } = await request( - routes.abdm.healthFacility.registerAsService, - { - pathParams: { - facility_id: facilityId, - }, - }, - ); - response = res; - responseData = data; - } else if (state.form.health_facility) { - const { res, data } = await request( - routes.abdm.healthFacility.partialUpdate, - { - pathParams: { - facility_id: facilityId, - }, - body: { - hf_id: state.form.hf_id, - }, - }, - ); - response = res; - responseData = data; - } else { - const { res, data } = await request(routes.abdm.healthFacility.create, { - body: { - facility: facilityId, - hf_id: state.form.hf_id, - }, - silent: true, - }); - response = res; - responseData = data; - } - - if (response?.ok && responseData?.registered) { - Notification.Success({ - msg: t("health_facility__config_update_success"), - }); - navigate(`/facility/${facilityId}`); - } else { - if (responseData?.registered === false) { - Notification.Warn({ - msg: - responseData?.detail || - t("health_facility__config_registration_error"), - }); - navigate(`/facility/${facilityId}`); - } else { - Notification.Error({ - msg: - responseData?.detail || t("health_facility__config_update_error"), - }); - } - } - setIsLoading(false); - }; - - const handleChange = (e: FieldChangeEvent) => { - dispatch({ - type: "set_form", - form: { ...state.form, [e.name]: e.value }, - }); - }; - - if (loading || isLoading) { - return ; - } - - return ( -
-
-
-
- - {state.form.health_facility?.registered ? ( - <> -
- - {t("health_facility__registered_1.1")}{" "} - - {t("health_facility__registered_1.2")} - - - - {t("health_facility__registered_2")} - -
- {t("health_facility__registered_3")} - - ) : ( - <> -
- - {t("health_facility__not_registered_1.1")}{" "} - - {t("health_facility__not_registered_1.2")} - - - - {t("health_facility__not_registered_2")} - - {t("health_facility__not_registered_3")} -
- - )} -

- } - required - value={state.form.hf_id} - onChange={handleChange} - error={state.errors?.hf_id} - /> -
-
-
- -
-
-
- ); -}; diff --git a/src/components/ABDM/FetchRecordsModal.tsx b/src/components/ABDM/FetchRecordsModal.tsx deleted file mode 100644 index 9433374f931..00000000000 --- a/src/components/ABDM/FetchRecordsModal.tsx +++ /dev/null @@ -1,246 +0,0 @@ -import dayjs from "dayjs"; -import { navigate } from "raviger"; -import { useState } from "react"; -import { useTranslation } from "react-i18next"; - -import { AbhaNumberModel } from "@/components/ABDM/types/abha"; -import { ConsentHIType, ConsentPurpose } from "@/components/ABDM/types/consent"; -import ButtonV2 from "@/components/Common/ButtonV2"; -import DialogModal from "@/components/Common/Dialog"; -import DateFormField from "@/components/Form/FormFields/DateFormField"; -import DateRangeFormField from "@/components/Form/FormFields/DateRangeFormField"; -import { - MultiSelectFormField, - SelectFormField, -} from "@/components/Form/FormFields/SelectFormField"; -import TextFormField from "@/components/Form/FormFields/TextFormField"; - -import { useMessageListener } from "@/hooks/useMessageListener"; - -import { ABDM_CONSENT_PURPOSE, ABDM_HI_TYPE } from "@/common/constants"; - -import * as Notification from "@/Utils/Notifications"; -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; - -const getDate = (value: string | Date) => - (value && dayjs(value).isValid() && dayjs(value).toDate()) || undefined; - -interface IProps { - abha?: AbhaNumberModel; - show: boolean; - onClose: () => void; -} - -export default function FetchRecordsModal({ abha, show, onClose }: IProps) { - const { t } = useTranslation(); - - const [idVerificationStatus, setIdVerificationStatus] = useState< - "pending" | "in-progress" | "verified" | "failed" - >("verified"); - const [purpose, setPurpose] = useState("CAREMGT"); - const [fromDate, setFromDate] = useState( - dayjs().subtract(30, "day").toDate(), - ); - const [toDate, setToDate] = useState(dayjs().toDate()); - const [isMakingConsentRequest, setIsMakingConsentRequest] = useState(false); - const [hiTypes, setHiTypes] = useState([]); - const [expiryDate, setExpiryDate] = useState( - dayjs().add(30, "day").toDate(), - ); - const [errors, setErrors] = useState>({}); - // const notificationSubscriptionState = useNotificationSubscriptionState([ - // show, - // ]); - - useMessageListener((data) => { - if (data.type === "MESSAGE" && data.from === "patients/on_find") { - if (data.message?.patient?.id === abha?.health_id) { - setIdVerificationStatus("verified"); - setErrors({ - ...errors, - health_id: "", - }); - } - } - }); - - return ( - - {/* {["unsubscribed", "subscribed_on_other_device"].includes( - notificationSubscriptionState, - ) && ( -

- {" "} - Notifications needs to be enabled on this device to verify the - patient. -

- )} */} - -
- null} - disabled - label={t("consent_request__patient_identifier")} - name="health_id" - error={errors.health_id} - className="flex-1" - /> - - {/* { - const { res } = await request(routes.abha.findPatient, { - body: { - id: abha?.health_id, - }, - reattempts: 0, - }); - - if (res?.status) { - setIdVerificationStatus("in-progress"); - } - }} - loading={idVerificationStatus === "in-progress"} - ghost={idVerificationStatus === "verified"} - disabled={ - idVerificationStatus === "verified" || - ["unsubscribed", "subscribed_on_other_device"].includes( - notificationSubscriptionState, - ) - } - className={classNames( - "mt-1.5 !py-3", - idVerificationStatus === "verified" && - "disabled:cursor-auto disabled:bg-transparent disabled:text-primary-600", - )} - > - {idVerificationStatus === "in-progress" && ( - - )} - {idVerificationStatus === "verified" && } - { - { - pending: "Verify Patient", - "in-progress": "Verifying", - verified: "Verified", - failed: "Retry", - }[idVerificationStatus] - } - */} -
- t(`consent__purpose__${o}`)} - optionValue={(o) => o} - value={purpose} - onChange={({ value }) => setPurpose(value)} - required - /> - - { - setFromDate(e.value.start!); - setToDate(e.value.end!); - }} - label={t("consent_request__date_range")} - required - /> - - { - setHiTypes(ABDM_HI_TYPE); - }} - > - {t("select_all")} - - ) - } - value={hiTypes} - optionLabel={(option) => t(`consent__hi_type__${option}`)} - optionValue={(option) => option} - onChange={(e) => setHiTypes(e.value)} - required - /> - - setExpiryDate(e.value!)} - label={t("consent_request__expiry")} - required - disablePast - /> - -
- { - if (idVerificationStatus !== "verified") { - setErrors({ - ...errors, - health_id: t("verify_patient_identifier"), - }); - - return; - } - - setIsMakingConsentRequest(true); - const { res } = await request(routes.abdm.consent.create, { - body: { - patient_abha: abha?.health_id as string, - hi_types: hiTypes, - purpose, - from_time: fromDate, - to_time: toDate, - expiry: expiryDate, - }, - }); - - if (res?.status === 201) { - Notification.Success({ - msg: t("consent_requested_successfully"), - }); - - navigate( - `/facility/${abha?.patient_object?.facility}/abdm`, - // ?? `/facility/${abha?.patient_object?.facility}/patient/${abha?.patient_object?.id}/consultation/${abha?.patient_object?.last_consultation?.id}/abdm`, - ); - } - setIsMakingConsentRequest(false); - onClose(); - }} - disabled={idVerificationStatus !== "verified"} - loading={isMakingConsentRequest} - > - {t("request_consent")} - -
-
- ); -} diff --git a/src/components/ABDM/HealthInformation.tsx b/src/components/ABDM/HealthInformation.tsx deleted file mode 100644 index e147f050131..00000000000 --- a/src/components/ABDM/HealthInformation.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { HIProfile } from "hi-profiles"; -import { useTranslation } from "react-i18next"; - -import Loading from "@/components/Common/Loading"; -import Page from "@/components/Common/Page"; - -import routes from "@/Utils/request/api"; -import useQuery from "@/Utils/request/useQuery"; - -interface IProps { - artefactId: string; -} - -export default function HealthInformation({ artefactId }: IProps) { - const { t } = useTranslation(); - - const { data, loading, error } = useQuery(routes.abdm.healthInformation.get, { - pathParams: { artefactId }, - silent: true, - }); - - if (loading) { - return ; - } - - const parseData = (data: string) => { - try { - return JSON.parse(data); - } catch (e) { - return JSON.parse( - data.replace(/"/g, '\\"').replace(/'/g, '"'), // eslint-disable-line - ); - } - }; - - return ( - -
- {!!error?.is_archived && ( - <> -

- {t("hi__record_archived__title")} -

-
- {t("hi__record_archived_description")} -
-

- {t("hi__record_archived_on")}{" "} - {new Date(error?.archived_time as string).toLocaleString()} -{" "} - {error?.archived_reason as string} -

- - )} - {error && !error?.is_archived && ( - <> -

- {t("hi__record_not_fetched_title")} -

-
- {t("hi__record_not_fetched_description")} -
-

- {t("hi__waiting_for_record")} -

- - )} - {data?.data.map((item) => ( - - ))} -
-
- ); -} diff --git a/src/components/ABDM/LinkAbhaNumber/CreateWithAadhaar.tsx b/src/components/ABDM/LinkAbhaNumber/CreateWithAadhaar.tsx deleted file mode 100644 index d2697633bea..00000000000 --- a/src/components/ABDM/LinkAbhaNumber/CreateWithAadhaar.tsx +++ /dev/null @@ -1,740 +0,0 @@ -import { useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; - -import useMultiStepForm, { - InjectedStepProps, -} from "@/components/ABDM/LinkAbhaNumber/useMultiStepForm"; -import { AbhaNumberModel } from "@/components/ABDM/types/abha"; -import ButtonV2, { ButtonWithTimer } from "@/components/Common/ButtonV2"; -import CheckBoxFormField from "@/components/Form/FormFields/CheckBoxFormField"; -import OtpFormField from "@/components/Form/FormFields/OtpFormField"; -import PhoneNumberFormField from "@/components/Form/FormFields/PhoneNumberFormField"; -import TextFormField from "@/components/Form/FormFields/TextFormField"; -import { validateRule } from "@/components/Users/UserAdd"; - -import * as Notify from "@/Utils/Notifications"; -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; -import { classNames } from "@/Utils/utils"; - -const MAX_OTP_RESEND_ALLOWED = 2; - -type ICreateWithAadhaarProps = { - onSuccess: (abhaNumber: AbhaNumberModel) => void; -}; - -type Memory = { - aadhaarNumber: string; - mobileNumber: string; - - isLoading: boolean; - validationError: string; - - transactionId: string; - abhaNumber: AbhaNumberModel | null; - - resendOtpCount: number; -}; - -export default function CreateWithAadhaar({ - onSuccess, -}: ICreateWithAadhaarProps) { - const { currentStep } = useMultiStepForm( - [ - , - , - , - , - , - , - ], - { - aadhaarNumber: "", - mobileNumber: "+91", - isLoading: false, - validationError: "", - transactionId: "", - abhaNumber: null, - resendOtpCount: 0, - }, - ); - - return
{currentStep}
; -} - -type IEnterAadhaarProps = InjectedStepProps; - -function EnterAadhaar({ memory, setMemory, next }: IEnterAadhaarProps) { - const { t } = useTranslation(); - const [disclaimerAccepted, setDisclaimerAccepted] = useState([ - false, - false, - false, - false, - ]); - - const validateAadhaar = () => { - if ( - memory?.aadhaarNumber.length !== 12 && - memory?.aadhaarNumber.length !== 16 - ) { - setMemory((prev) => ({ - ...prev, - validationError: t("aadhaar_validation_length_error"), - })); - return false; - } - - if (memory?.aadhaarNumber.includes(" ")) { - setMemory((prev) => ({ - ...prev, - validationError: t("aadhaar_validation_space_error"), - })); - return false; - } - - return true; - }; - - const handleSubmit = async () => { - if (!validateAadhaar()) return; - - setMemory((prev) => ({ ...prev, isLoading: true })); - - const { res, data } = await request( - routes.abdm.healthId.abhaCreateSendAadhaarOtp, - { - body: { - aadhaar: memory!.aadhaarNumber, - }, - }, - ); - - if (res?.status === 200 && data) { - setMemory((prev) => ({ ...prev, transactionId: data.transaction_id })); - Notify.Success({ - msg: data.detail ?? t("aadhaar_otp_send_success"), - }); - next(); - } - - setMemory((prev) => ({ ...prev, isLoading: false })); - }; - - return ( -
-
- - setMemory((prev) => ({ ...prev, aadhaarNumber: value })) - } - error={memory?.validationError} - /> - - {t("aadhaar_number_will_not_be_stored")} - -
- -
- {disclaimerAccepted.map((isAccepted, i) => ( - { - setDisclaimerAccepted( - disclaimerAccepted.map((v, j) => (j === i ? e.value : v)), - ); - }} - className="mr-2 rounded border-gray-700" - labelClassName="text-xs text-gray-800" - errorClassName="hidden" - /> - ))} -
- -
- !v) || - memory?.aadhaarNumber.length === 0 - } - onClick={handleSubmit} - > - {t("send_otp")} - -
-
- ); -} - -type IVerifyAadhaarProps = InjectedStepProps; - -function VerifyAadhaar({ memory, setMemory, next }: IVerifyAadhaarProps) { - const { t } = useTranslation(); - const [otp, setOtp] = useState(""); - - const validateMobileNumber = () => { - const phone = memory?.mobileNumber.replace("+91", "").replace(/ /g, ""); - if (phone?.length !== 10) { - setMemory((prev) => ({ - ...prev, - validationError: t("mobile_number_validation_error"), - })); - return false; - } - - return true; - }; - - const handleSubmit = async () => { - if (!validateMobileNumber()) return; - - setMemory((prev) => ({ ...prev, isLoading: true })); - - const { res, data } = await request( - routes.abdm.healthId.abhaCreateVerifyAadhaarOtp, - { - body: { - otp: otp, - transaction_id: memory?.transactionId, - mobile: memory?.mobileNumber.replace("+91", "").replace(/ /g, ""), - }, - }, - ); - - if (res?.status === 200 && data) { - setMemory((prev) => ({ - ...prev, - transactionId: data.transaction_id, - abhaNumber: data.abha_number, - resendOtpCount: 0, - })); - Notify.Success({ - msg: data.detail ?? t("otp_verification_success"), - }); - next(); - } - - setMemory((prev) => ({ ...prev, isLoading: false })); - }; - - const handleResendOtp = async () => { - setMemory((prev) => ({ ...prev, isLoading: true })); - - const { res, data } = await request( - routes.abdm.healthId.abhaCreateSendAadhaarOtp, - { - body: { - aadhaar: memory!.aadhaarNumber, - // transaction_id: memory?.transactionId, - }, - silent: true, - }, - ); - - if (res?.status === 200 && data) { - setMemory((prev) => ({ - ...prev, - transactionId: data.transaction_id, - resendOtpCount: prev.resendOtpCount + 1, - })); - Notify.Success({ - msg: data.detail ?? t("aadhaar_otp_send_success"), - }); - } else { - setMemory((prev) => ({ - ...prev, - resendOtpCount: Infinity, - })); - Notify.Success({ - msg: t("aadhaar_otp_send_error"), - }); - } - - setMemory((prev) => ({ ...prev, isLoading: false })); - }; - - return ( -
-
- - setMemory((prev) => ({ ...prev, aadhaarNumber: value })) - } - /> - - {t("aadhaar_number_will_not_be_stored")} - -
- -
- setOtp(value as string)} - value={otp} - label={t("enter_aadhaar_otp")} - disabled={memory?.isLoading} - /> -
- -
- } - name="mobile_number" - value={memory?.mobileNumber} - onChange={(e) => { - if (!memory?.mobileNumber.startsWith("+91")) { - setMemory((prev) => ({ - ...prev, - validationError: t("only_indian_mobile_numbers_supported"), - })); - return; - } - - setMemory((prev) => ({ ...prev, mobileNumber: e.value })); - }} - error={memory?.validationError} - errorClassName="text-xs text-red-500" - types={["mobile"]} - /> -
- -
- 6 || memory?.mobileNumber.length === 0} - onClick={handleSubmit} - > - {t("verify_otp")} - - - {(memory?.resendOtpCount ?? 0) < MAX_OTP_RESEND_ALLOWED && ( - - {t("resend_otp")} - - )} -
-
- ); -} - -type IHandleExistingAbhaNumberProps = InjectedStepProps & { - onSuccess: (abhaNumber: AbhaNumberModel) => void; -}; - -function HandleExistingAbhaNumber({ - memory, - onSuccess, - next, -}: IHandleExistingAbhaNumberProps) { - const { t } = useTranslation(); - - // skip this step for new abha number - useEffect(() => { - if (memory?.abhaNumber?.new) { - next(); - } - }, [memory?.abhaNumber, memory?.mobileNumber]); // eslint-disable-line - - return ( -
-

- {t("abha_number_exists")} -

-

- {t("abha_number_exists_description")} -

-
- - {t("create_new_abha_address")} - - onSuccess(memory?.abhaNumber as AbhaNumberModel)} - > - {t("use_existing_abha_address")} - -

- {memory?.abhaNumber?.health_id} -

-
-
- ); -} - -type ILinkMobileNumberProps = InjectedStepProps; - -function LinkMobileNumber({ - memory, - goTo, - setMemory, - next, -}: ILinkMobileNumberProps) { - const { t } = useTranslation(); - - useEffect(() => { - if ( - memory?.abhaNumber?.mobile === - memory?.mobileNumber.replace("+91", "").replace(/ /g, "") - ) { - goTo(5); // skip linking mobile number - } - }, [memory?.abhaNumber, memory?.mobileNumber]); // eslint-disable-line - - const handleSubmit = async () => { - setMemory((prev) => ({ ...prev, isLoading: true })); - - const { res, data } = await request( - routes.abdm.healthId.abhaCreateLinkMobileNumber, - { - body: { - mobile: memory?.mobileNumber.replace("+91", "").replace(/ /g, ""), - transaction_id: memory?.transactionId, - }, - }, - ); - - if (res?.status === 200 && data) { - setMemory((prev) => ({ - ...prev, - transactionId: data.transaction_id, - })); - Notify.Success({ - msg: data.detail ?? t("mobile_otp_send_success"), - }); - next(); - } - - setMemory((prev) => ({ ...prev, isLoading: false })); - }; - - return ( -
-
- } - name="mobile_number" - value={memory?.mobileNumber} - disabled={true} - onChange={() => null} - types={["mobile"]} - /> -
- -

- {t("mobile_number_different_from_aadhaar_mobile_number")} -

- -
- - {t("send_otp")} - -
-
- ); -} - -type IVerifyMobileNumberProps = InjectedStepProps; - -function VerifyMobileNumber({ - memory, - setMemory, - next, -}: IVerifyMobileNumberProps) { - const { t } = useTranslation(); - const [otp, setOtp] = useState(""); - - const handleSubmit = async () => { - setMemory((prev) => ({ ...prev, isLoading: true })); - - const { res, data } = await request( - routes.abdm.healthId.abhaCreateVerifyMobileNumber, - { - body: { - transaction_id: memory?.transactionId, - otp: otp, - }, - }, - ); - - if (res?.status === 200 && data) { - setMemory((prev) => ({ - ...prev, - transactionId: data.transaction_id, - resendOtpCount: 0, - })); - Notify.Success({ - msg: data.detail ?? t("mobile_otp_verify_success"), - }); - next(); - } - - setMemory((prev) => ({ ...prev, isLoading: false })); - }; - - const handleResendOtp = async () => { - setMemory((prev) => ({ ...prev, isLoading: true })); - - const { res, data } = await request( - routes.abdm.healthId.abhaCreateLinkMobileNumber, - { - body: { - mobile: memory?.mobileNumber.replace("+91", "").replace(/ /g, ""), - transaction_id: memory?.transactionId, - }, - }, - ); - - if (res?.status === 200 && data) { - setMemory((prev) => ({ - ...prev, - transactionId: data.transaction_id, - resendOtpCount: prev.resendOtpCount + 1, - })); - Notify.Success({ - msg: data.detail ?? t("mobile_otp_send_success"), - }); - } else { - setMemory((prev) => ({ - ...prev, - resendOtpCount: Infinity, - })); - Notify.Success({ - msg: t("mobile_otp_send_error"), - }); - } - - setMemory((prev) => ({ ...prev, isLoading: false })); - }; - - return ( -
-
- } - name="mobile_number" - value={memory?.mobileNumber} - disabled={true} - onChange={() => null} - types={["mobile"]} - /> -
- -
- setOtp(value as string)} - value={otp} - label={t("enter_mobile_otp")} - disabled={memory?.isLoading} - /> -
- -
- - {t("verify_otp")} - - - {(memory?.resendOtpCount ?? 0) < MAX_OTP_RESEND_ALLOWED && ( - - {t("resend_otp")} - - )} -
-
- ); -} - -type IChooseAbhaAddressProps = InjectedStepProps & { - onSuccess: (abhaNumber: AbhaNumberModel) => void; -}; - -function ChooseAbhaAddress({ - memory, - setMemory, - onSuccess, -}: IChooseAbhaAddressProps) { - const { t } = useTranslation(); - const [healthId, setHealthId] = useState(""); - const [suggestions, setSuggestions] = useState([]); - - useEffect(() => { - const fetchSuggestions = async () => { - const { res, data } = await request( - routes.abdm.healthId.abhaCreateAbhaAddressSuggestion, - { - body: { - transaction_id: memory?.transactionId, - }, - }, - ); - - if (res?.status === 200 && data) { - setMemory((prev) => ({ ...prev, transactionId: data.transaction_id })); - setSuggestions(data.abha_addresses); - } - }; - - fetchSuggestions(); - }, [healthId, memory?.transactionId, setMemory]); - - const handleSubmit = async () => { - setMemory((prev) => ({ ...prev, isLoading: true })); - - const { res, data } = await request( - routes.abdm.healthId.abhaCreateEnrolAbhaAddress, - { - body: { - abha_address: healthId, - transaction_id: memory?.transactionId, - }, - }, - ); - - if (res?.status === 200 && data) { - setMemory((prev) => ({ - ...prev, - transactionId: data.transaction_id, - abhaNumber: data.abha_number, - })); - Notify.Success({ - msg: data.detail ?? t("abha_address_created_success"), - }); - onSuccess(data.abha_number); - } - - setMemory((prev) => ({ ...prev, isLoading: false })); - }; - - return ( -
- { - setHealthId(value); - }} - /> - -
- {validateRule( - healthId.length >= 4, - t("abha_address_validation_length_error"), - false, - )} - {validateRule( - Number.isNaN(Number(healthId[0])) && healthId[0] !== ".", - t("abha_address_validation_start_error"), - false, - )} - {validateRule( - healthId[healthId.length - 1] !== ".", - t("abha_address_validation_end_error"), - false, - )} - {validateRule( - /^[0-9a-zA-Z._]+$/.test(healthId), - t("abha_address_validation_character_error"), - false, - )} -
- - {suggestions.length > 0 && ( -
-

- {t("abha_address_suggestions")} -

-
- {suggestions - .filter((suggestion) => suggestion !== healthId) - .map((suggestion) => ( -

setHealthId(suggestion)} - className="cursor-pointer rounded-md bg-primary-400 px-2.5 py-1 text-xs text-white" - > - {suggestion} -

- ))} -
-
- )} - -
- - {t("create_abha_address")} - -
-
- ); -} diff --git a/src/components/ABDM/LinkAbhaNumber/LinkWithOtp.tsx b/src/components/ABDM/LinkAbhaNumber/LinkWithOtp.tsx deleted file mode 100644 index 9b8150dee86..00000000000 --- a/src/components/ABDM/LinkAbhaNumber/LinkWithOtp.tsx +++ /dev/null @@ -1,350 +0,0 @@ -import { useMemo, useState } from "react"; -import { useTranslation } from "react-i18next"; - -import useMultiStepForm, { - InjectedStepProps, -} from "@/components/ABDM/LinkAbhaNumber/useMultiStepForm"; -import { AbhaNumberModel } from "@/components/ABDM/types/abha"; -import ButtonV2, { ButtonWithTimer } from "@/components/Common/ButtonV2"; -import Dropdown, { DropdownItem } from "@/components/Common/Menu"; -import CheckBoxFormField from "@/components/Form/FormFields/CheckBoxFormField"; -import OtpFormField from "@/components/Form/FormFields/OtpFormField"; -import TextFormField from "@/components/Form/FormFields/TextFormField"; - -import * as Notify from "@/Utils/Notifications"; -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; -import { classNames } from "@/Utils/utils"; - -const MAX_OTP_RESEND_ALLOWED = 2; - -type ILoginWithOtpProps = { - onSuccess: (abhaNumber: AbhaNumberModel) => void; -}; - -type Memory = { - id: string; - - isLoading: boolean; - validationError: string; - - transactionId: string; - type: "aadhaar" | "mobile" | "abha-number" | "abha-address"; - otp_system: "abdm" | "aadhaar"; - abhaNumber: AbhaNumberModel | null; - - resendOtpCount: number; -}; - -export default function LinkWithOtp({ onSuccess }: ILoginWithOtpProps) { - const { currentStep } = useMultiStepForm( - [ - , - , - ], - { - id: "", - isLoading: false, - validationError: "", - transactionId: "", - type: "aadhaar", - otp_system: "aadhaar", - abhaNumber: null, - resendOtpCount: 0, - }, - ); - - return
{currentStep}
; -} - -type IEnterIdProps = InjectedStepProps; - -const supportedAuthMethods = ["AADHAAR_OTP", "MOBILE_OTP"]; - -function EnterId({ memory, setMemory, next }: IEnterIdProps) { - const { t } = useTranslation(); - const [disclaimerAccepted, setDisclaimerAccepted] = useState([ - false, - false, - false, - ]); - const [authMethods, setAuthMethods] = useState([]); - - const valueType = useMemo(() => { - const id = memory?.id; - const isNumeric = !isNaN(Number(id?.trim())); - - if (isNumeric && (id?.length === 12 || id?.length === 16)) { - return "aadhaar"; - } else if (isNumeric && id?.length === 10) { - return "mobile"; - } else if (isNumeric && id?.length === 14) { - return "abha-number"; - } else { - return "abha-address"; - } - }, [memory?.id]); - - const handleGetAuthMethods = async () => { - setMemory((prev) => ({ ...prev, isLoading: true })); - - if (valueType === "aadhaar") { - setAuthMethods(["AADHAAR_OTP"]); - } else if (valueType === "mobile") { - setAuthMethods(["MOBILE_OTP"]); - } else { - const { res, data, error } = await request( - routes.abdm.healthId.abhaLoginCheckAuthMethods, - { - body: { - abha_address: memory?.id.replace(/-/g, "").replace(/ /g, ""), - }, - silent: true, - }, - ); - - if (res?.status === 200 && data) { - const methods = data.auth_methods.filter((method: string) => - supportedAuthMethods.find((supported) => supported === method), - ); - - if (methods.length === 0) { - Notify.Warn({ msg: t("get_auth_mode_error") }); - } - } else { - Notify.Error({ msg: error?.message ?? t("get_auth_mode_error") }); - } - } - - setMemory((prev) => ({ ...prev, isLoading: false })); - }; - - const handleSendOtp = async (authMethod: string) => { - if (!supportedAuthMethods.includes(authMethod)) { - Notify.Warn({ msg: t("auth_method_unsupported") }); - return; - } - - const otp_system: "aadhaar" | "abdm" = - authMethod === "AADHAAR_OTP" ? "aadhaar" : "abdm"; - - setMemory((prev) => ({ - ...prev, - isLoading: true, - type: valueType, - otp_system, - })); - - const { res, data } = await request(routes.abdm.healthId.abhaLoginSendOtp, { - body: { - value: memory?.id, - type: valueType, - otp_system, - }, - }); - - if (res?.status === 200 && data) { - setMemory((prev) => ({ - ...prev, - transactionId: data.transaction_id, - })); - Notify.Success({ msg: data.detail ?? t("send_otp_success") }); - next(); - } - - setMemory((prev) => ({ ...prev, isLoading: false })); - }; - - return ( -
-
- { - setMemory((prev) => ({ ...prev, id: value })); - setAuthMethods([]); - }} - error={memory?.validationError} - /> - - {t("any_id_description")} - -
- -
- {disclaimerAccepted.map((isAccepted, i) => ( - { - setDisclaimerAccepted( - disclaimerAccepted.map((v, j) => (j === i ? e.value : v)), - ); - }} - className="mr-2 rounded border-gray-700" - labelClassName="text-xs text-gray-800" - errorClassName="hidden" - /> - ))} -
- -
- {authMethods.length === 0 ? ( - !v) || memory?.id.length === 0 - } - onClick={handleGetAuthMethods} - > - {t("get_auth_methods")} - - ) : ( - - {authMethods.map((method) => ( - handleSendOtp(method)}> - {t(`abha__auth_method__${method}`)} - - ))} - - )} -
-
- ); -} - -type IVerifyIdProps = InjectedStepProps & { - onSuccess: (abhaNumber: AbhaNumberModel) => void; -}; - -function VerifyId({ memory, setMemory, onSuccess }: IVerifyIdProps) { - const { t } = useTranslation(); - const [otp, setOtp] = useState(""); - - const handleSubmit = async () => { - setMemory((prev) => ({ ...prev, isLoading: true })); - - const { res, data } = await request( - routes.abdm.healthId.abhaLoginVerifyOtp, - { - body: { - type: memory?.type, - transaction_id: memory?.transactionId, - otp, - otp_system: memory?.otp_system, - }, - }, - ); - - if (res?.status === 200 && data) { - Notify.Success({ msg: t("verify_otp_success") }); - onSuccess(data.abha_number); - } - - setMemory((prev) => ({ ...prev, isLoading: false })); - }; - - const handleResendOtp = async () => { - setMemory((prev) => ({ ...prev, isLoading: true })); - - const { res, data } = await request(routes.abdm.healthId.abhaLoginSendOtp, { - body: { - value: memory?.id, - type: memory?.type, - otp_system: memory?.otp_system, - }, - }); - - if (res?.status === 200 && data) { - setMemory((prev) => ({ - ...prev, - transactionId: data.transaction_id, - resendOtpCount: (prev.resendOtpCount ?? 0) + 1, - })); - Notify.Success({ msg: data.detail ?? t("send_otp_success") }); - } else { - setMemory((prev) => ({ - ...prev, - resendOtpCount: Infinity, - })); - Notify.Error({ msg: t("send_otp_error") }); - } - - setMemory((prev) => ({ ...prev, isLoading: false })); - }; - - return ( -
-
- null} - /> - - {t("any_id_description")} - -
- -
- setOtp(value as string)} - value={otp} - label={t("enter_otp")} - disabled={memory?.isLoading} - /> -
- -
- - {t("verify_and_link")} - - - {(memory?.resendOtpCount ?? 0) < MAX_OTP_RESEND_ALLOWED && ( - - {t("resend_otp")} - - )} -
-
- ); -} diff --git a/src/components/ABDM/LinkAbhaNumber/LinkWithQr.tsx b/src/components/ABDM/LinkAbhaNumber/LinkWithQr.tsx deleted file mode 100644 index 712d28943b4..00000000000 --- a/src/components/ABDM/LinkAbhaNumber/LinkWithQr.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { IDetectedBarcode, Scanner } from "@yudiel/react-qr-scanner"; -import { useState } from "react"; -import { useTranslation } from "react-i18next"; - -import { ABHAQRContent, AbhaNumberModel } from "@/components/ABDM/types/abha"; - -import * as Notification from "@/Utils/Notifications"; -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; - -type ILoginWithQrProps = { - onSuccess: (abhaNumber: AbhaNumberModel) => void; -}; - -export default function LinkWithQr({ onSuccess }: ILoginWithQrProps) { - const { t } = useTranslation(); - const [isLoading, setIsLoading] = useState(false); - - return ( -
- { - if (detectedCodes.length === 0) return; - - const scannedValue = detectedCodes[0].rawValue; - if (!scannedValue || isLoading) return; - - try { - const qrData = JSON.parse(scannedValue) as ABHAQRContent; - - setIsLoading(true); - const { res, data } = await request(routes.abdm.abhaNumber.create, { - body: { - abha_number: qrData.hidn, - health_id: qrData.hid || qrData.phr, - name: qrData.name, - gender: qrData.gender, - date_of_birth: qrData.dob, - address: qrData.address, - district: qrData.district_name || qrData["dist name"], - state: qrData.state_name || qrData["state name"], - mobile: qrData.mobile, - }, - }); - - if (res?.status === 201 && data) { - onSuccess(data); - } - setIsLoading(false); - } catch (e) { - Notification.Error({ - msg: t("abha__qr_scanning_error"), - }); - } - }} - onError={(e: unknown) => { - const errorMessage = e instanceof Error ? e.message : "Unknown error"; - Notification.Error({ - msg: errorMessage, - }); - }} - scanDelay={3000} - constraints={{ - facingMode: "environment", - }} - /> -
- ); -} diff --git a/src/components/ABDM/LinkAbhaNumber/index.tsx b/src/components/ABDM/LinkAbhaNumber/index.tsx deleted file mode 100644 index 45cd0b34d02..00000000000 --- a/src/components/ABDM/LinkAbhaNumber/index.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import { useState } from "react"; -import { useTranslation } from "react-i18next"; - -import CreateWithAadhaar from "@/components/ABDM/LinkAbhaNumber/CreateWithAadhaar"; -import LinkWithOtp from "@/components/ABDM/LinkAbhaNumber/LinkWithOtp"; -import LinkWithQr from "@/components/ABDM/LinkAbhaNumber/LinkWithQr"; -import { AbhaNumberModel } from "@/components/ABDM/types/abha"; -import ButtonV2 from "@/components/Common/ButtonV2"; -import DialogModal from "@/components/Common/Dialog"; - -import { classNames } from "@/Utils/utils"; - -interface ILinkAbhaNumberProps { - show: boolean; - onClose: () => void; - onSuccess: (abhaNumber: AbhaNumberModel) => void; -} - -const ABHA_LINK_OPTIONS = { - create_with_aadhaar: { - title: "abha_link_options__create_with_aadhaar__title", - description: "abha_link_options__create_with_aadhaar__description", - disabled: false, - value: "create_with_aadhaar", - create: true, - }, - link_with_otp: { - title: "abha_link_options__link_with_otp__title", - description: "abha_link_options__link_with_otp__description", - disabled: false, - value: "link_with_otp", - create: false, - }, - create_with_driving_license: { - title: "abha_link_options__create_with_driving_license__title", - description: "abha_link_options__create_with_driving_license__description", - disabled: true, - value: "create_with_driving_license", - create: true, - }, - link_with_demographics: { - title: "abha_link_options__link_with_demographics__title", - description: "abha_link_options__link_with_demographics__description", - disabled: true, - value: "link_with_demographics", - create: false, - }, - link_with_qr: { - title: "abha_link_options__link_with_qr__title", - description: "abha_link_options__link_with_qr__description", - disabled: false, - value: "link_with_qr", - create: false, - }, -}; - -export default function LinkAbhaNumber({ - show, - onClose, - onSuccess, -}: ILinkAbhaNumberProps) { - const { t } = useTranslation(); - const [currentAbhaLinkOption, setCurrentAbhaLinkOption] = useState< - keyof typeof ABHA_LINK_OPTIONS - >("create_with_aadhaar"); - - return ( - - {currentAbhaLinkOption === "create_with_aadhaar" && ( - - )} - - {currentAbhaLinkOption === "link_with_otp" && ( - - )} - - {currentAbhaLinkOption === "link_with_qr" && ( - - )} - -
-

- setCurrentAbhaLinkOption( - ABHA_LINK_OPTIONS[currentAbhaLinkOption].create - ? "link_with_otp" - : "create_with_aadhaar", - ) - } - className="cursor-pointer text-center text-sm text-blue-800" - > - {ABHA_LINK_OPTIONS[currentAbhaLinkOption].create - ? t("link_existing_abha_profile") - : t("create_new_abha_profile")} -

-
- -
-

- {t("try_different_abha_linking_option")} -

-
- {Object.values(ABHA_LINK_OPTIONS) - .filter( - (option) => - option.value !== currentAbhaLinkOption && - ABHA_LINK_OPTIONS[currentAbhaLinkOption]?.create === - option.create, - ) - .sort((a) => (a.disabled ? 1 : -1)) - .map((option) => ( - - setCurrentAbhaLinkOption( - option.value as keyof typeof ABHA_LINK_OPTIONS, - ) - } - ghost - tooltip={ - option.disabled - ? t("abha_link_options__disabled_tooltip") - : t(option.description) - } - disabled={option.disabled} - tooltipClassName="top-full mt-1" - className={classNames( - "w-full border border-gray-400 text-secondary-800", - !option.disabled && "hover:border-primary-100", - )} - > - {t(option.title)} - - ))} -
-
-
- ); -} diff --git a/src/components/ABDM/LinkAbhaNumber/useMultiStepForm.ts b/src/components/ABDM/LinkAbhaNumber/useMultiStepForm.ts deleted file mode 100644 index 79bc9ec71c6..00000000000 --- a/src/components/ABDM/LinkAbhaNumber/useMultiStepForm.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { - Dispatch, - ReactElement, - SetStateAction, - cloneElement, - useCallback, - useMemo, - useState, -} from "react"; - -export interface InjectedStepProps { - currentStepIndex: number; - isFirstStep: boolean; - isLastStep: boolean; - next: () => void; - prev: () => void; - goTo: (step: number) => void; - memory: T | null; - setMemory: Dispatch>; -} - -export default function useMultiStepForm( - steps: ReactElement[], - initialValues?: T, -) { - const [currentStepIndex, setCurrentStepIndex] = useState(0); - const [memory, setMemory] = useState(initialValues as T); - - const next = useCallback( - () => - setCurrentStepIndex((prev) => - steps.length - 1 > prev ? prev + 1 : prev, - ), - [steps.length], - ); - - const prev = useCallback( - () => setCurrentStepIndex((prev) => (prev > 0 ? prev - 1 : prev)), - [], - ); - - const goTo = useCallback( - (step: number) => - setCurrentStepIndex((prev) => - step >= 0 && step <= steps.length - 1 ? step : prev, - ), - [steps.length], - ); - - const options = useMemo( - () => ({ - currentStepIndex, - isFirstStep: currentStepIndex === 0, - isLastStep: currentStepIndex === steps.length - 1, - next, - prev, - goTo, - memory, - setMemory, - }), - [currentStepIndex, memory, next, prev, goTo, steps.length], - ); - - const currentStep = cloneElement(steps[currentStepIndex], { - ...options, - ...steps[currentStepIndex].props, - }); - - return { currentStep, ...options }; -} diff --git a/src/components/ABDM/types/abha.ts b/src/components/ABDM/types/abha.ts deleted file mode 100644 index f189bd111cb..00000000000 --- a/src/components/ABDM/types/abha.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { PatientModel } from "@/components/Patient/models"; - -export type AbhaNumberModel = { - id: number; - external_id: string; - created_date: string; - modified_date: string; - abha_number: string; - health_id: string; - name: string; - first_name: string | null; - middle_name: string | null; - last_name: string | null; - gender: "F" | "M" | "O"; - date_of_birth: string | null; - address: string | null; - district: string | null; - state: string | null; - pincode: string | null; - mobile: string | null; - email: string | null; - profile_photo: string | null; - new: boolean; - patient: string | null; - patient_object: PatientModel | null; -}; - -export type ABHAQRContent = { - hidn: string; - name: string; - gender: "M" | "F" | "O"; - dob: string; - mobile: string; - address: string; - distlgd: string; - statelgd: string; -} & ({ hid: string; phr?: never } | { phr: string; hid?: never }) & - ( - | { district_name: string; "dist name"?: never } - | { "dist name": string; district_name?: never } - ) & - ( - | { state_name: string; "state name"?: never } - | { "state name": string; state_name?: never } - ); diff --git a/src/components/ABDM/types/consent.ts b/src/components/ABDM/types/consent.ts deleted file mode 100644 index a5041f5767d..00000000000 --- a/src/components/ABDM/types/consent.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { AbhaNumberModel } from "@/components/ABDM/types/abha"; -import { UserBaseModel } from "@/components/Users/models"; - -export type ConsentPurpose = - | "CAREMGT" - | "BTG" - | "PUBHLTH" - | "HPAYMT" - | "DSRCH" - | "PATRQT"; - -export type ConsentStatus = - | "REQUESTED" - | "GRANTED" - | "DENIED" - | "EXPIRED" - | "REVOKED"; - -export type ConsentHIType = - | "Prescription" - | "DiagnosticReport" - | "OPConsultation" - | "DischargeSummary" - | "ImmunizationRecord" - | "HealthDocumentRecord" - | "WellnessRecord"; - -export type ConsentAccessMode = "VIEW" | "STORE" | "QUERY" | "STREAM"; - -export type ConsentFrequencyUnit = "HOUR" | "DAY" | "WEEK" | "MONTH" | "YEAR"; - -export type ConsentCareContext = { - patientReference: string; - careContextReference: string; -}; - -export type ConsentModel = { - id: string; - consent_id: null | string; - - patient_abha: string; - care_contexts: ConsentCareContext[]; - - status: ConsentStatus; - purpose: ConsentPurpose; - hi_types: ConsentHIType[]; - - access_mode: ConsentAccessMode; - from_time: string; - to_time: string; - expiry: string; - - frequency_unit: ConsentFrequencyUnit; - frequency_value: number; - frequency_repeats: number; - - hip: null | string; - hiu: null | string; - - created_date: string; - modified_date: string; -}; - -export type CreateConsentTBody = { - patient_abha: string; - hi_types: ConsentHIType[]; - purpose: ConsentPurpose; - from_time: Date | string; - to_time: Date | string; - expiry: Date | string; - - access_mode?: ConsentAccessMode; - frequency_unit?: ConsentFrequencyUnit; - frequency_value?: number; - frequency_repeats?: number; - hip?: null | string; -}; - -export type ConsentArtefactModel = { - consent_request: string; - - cm: null | string; -} & ConsentModel; - -export type ConsentRequestModel = { - requester: UserBaseModel; - patient_abha_object: AbhaNumberModel; - consent_artefacts: ConsentArtefactModel[]; -} & ConsentModel; diff --git a/src/components/ABDM/types/health-facility.ts b/src/components/ABDM/types/health-facility.ts deleted file mode 100644 index 419003dbf8e..00000000000 --- a/src/components/ABDM/types/health-facility.ts +++ /dev/null @@ -1,19 +0,0 @@ -export interface IHealthFacility { - id: string; - registered: boolean; - external_id: string; - created_date: string; - modified_date: string; - hf_id: string; - facility: string; - detail?: string; -} - -export interface IcreateHealthFacilityTBody { - facility: string; - hf_id: string; -} - -export interface IpartialUpdateHealthFacilityTBody { - hf_id: string; -} diff --git a/src/components/ABDM/types/health-information.ts b/src/components/ABDM/types/health-information.ts deleted file mode 100644 index eeb1c53a4fb..00000000000 --- a/src/components/ABDM/types/health-information.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type HealthInformationModel = { - data: { - content: string; - care_context_reference: string; - }[]; -}; diff --git a/src/components/Auth/Login.tsx b/src/components/Auth/Login.tsx index bcf0d4e3415..aab5f8df179 100644 --- a/src/components/Auth/Login.tsx +++ b/src/components/Auth/Login.tsx @@ -335,6 +335,7 @@ const Login = (props: { forgot?: boolean }) => { setForgotPassword(true); }} type="button" + id="forgot-pass-btn" className="text-sm text-primary-400 hover:text-primary-500" > {t("forget_password")} @@ -347,6 +348,7 @@ const Login = (props: { forgot?: boolean }) => { ) : ( -
+
{t("forget_password")}
-
+
{t("forget_password_instruction")} { ) : (