Skip to content

Commit

Permalink
BAH-4119 | Migrate verification flow to v3 ABDM APIs (#92)
Browse files Browse the repository at this point in the history
* BAH-4119.Add. ABDM v3 APIs Verify Abha Address Using Mobile number.

* BAH-4119. Add. ABDM v3 APIs for verify by Abha Number.

* BAH-4119| Add. ABDM v3 APIs for Abha Address Verification flow.

* BAH-4119. Add. ABDM v3 API error handling.

* BAH-4119 | Add. Validations for user input in verification flow

* BAH-4119 | Add. Dropdown based identifier selection for verification flow

* BAH-4119 | Add. API Error handling for verification by mobile number

* BAH-4119 | Add. Validation for abha address verification input

---------

Co-authored-by: arshiyaTW2021 <[email protected]>
  • Loading branch information
mohan-13 and arshiya2125 authored Dec 5, 2024
1 parent 456c075 commit bd4dd08
Show file tree
Hide file tree
Showing 11 changed files with 346 additions and 179 deletions.
5 changes: 4 additions & 1 deletion src/api/apiUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ export const parseAPIError = (error) => {
if (!error.response?.data) {
return Constants.serviceUnavailableError;
}
var errorResponseData = error.response.data
var errorResponseData = error.response.data;
if (errorResponseData instanceof Array){
errorResponseData = errorResponseData[0];
}
if (errorResponseData.message)
return { "error": { "message": errorResponseData.message } }
if (errorResponseData.error?.message)
Expand Down
15 changes: 9 additions & 6 deletions src/api/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,17 @@ export const generateABHAMobileOTP = "/v3/hip/generateMobileOtp"
export const verifyMobileOTP = "/v3/hip/verifyMobileOtp"
export const getAbhaAddressSuggestions = "/v3/hip/getAbhaAddressSuggestions"
export const getPngCard = "/v3/hip/getAbhaCard";
export const searchHealthId = "/v2/search/searchHealthIdToLogin"
export const healthIdAuthInit = "/v2/auth/init"
export const healthIdConfirmOtp = "/v2/hip/confirmOTP"
export const searchAbhaAddress = "/v3/hip/verification/abhaAddress/search";
export const abhaAddressVerificationRequestOtp = "/v3/hip/verification/abhaAddress/requestOtp";
export const abhaAddressVerificationVerifyOtp = "/v3/hip/verification/abhaAddress/verifyOtp";
export const abhaAddressVerificationGetProfile = "/v3/hip/verification/abhaAddress/getProfile";
export const abhaAddressVerificationGetCard = "/v3/hip/verification/abhaAddress/getCard";
export const createDefaultHealthId = "/v1/account/update/phr-address"
export const updateHealthId = "/v2/hip/profile/updatePhrAddress"
export const generateMobileOtp = "/v2/registration/mobile/login/generateOtp"
export const verifyMobileOtp = "/v2/registration/mobile/login/verifyOtp"
export const getPatientProfileInfo = "/v2/registration/mobile/login/userAuthorizedToken"
export const verificationRequestOtp = "/v3/hip/verification/requestOtp"
export const verificationVerifyOtp = "/v3/hip/verification/verifyOtp"
export const verifyAbhaAccount= "/v3/hip/verification/verifyAbhaAccount"
export const getPatientProfileInfo = "/v3/hip/verification/getAbhaProfile"
export const mobileEmailInit = "/v1/phr/login/mobileEmail/init";
export const mobileEmailPreverification = "/v1/phr/login/mobileEmail/preVerification";
export const getUserToken = "/v1/phr/login/mobileEmail/getUserToken";
Expand Down
118 changes: 79 additions & 39 deletions src/api/hipServiceApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -386,53 +386,92 @@ export const createABHAAddress = async (abhaAddress) => {
}
}

export const searchHealthId = async (healthId) => {
export const searchAbhaAddress = async (abhaAddress) => {
const data = {
"healthId": healthId
"abhaAddress": abhaAddress
};
try {
const response = await axios.post(Constants.hipServiceUrl + Constants.searchHealthId,data, Constants.headers);
const response = await axios.post(Constants.hipServiceUrl + Constants.searchAbhaAddress,data, Constants.headers);
return response;
}
catch (error) {
if (error.response !== undefined)
return error.response.data;
else
return Constants.serviceUnavailableError;
return parseAPIError(error);
}
}

export const healthIdAuthInit = async (healthId, authMode) => {
export const abhaAddressRequestOtp = async (abhaAddress, authMode) => {
const data = {
"healthId": healthId,
"abhaAddress": abhaAddress,
"authMethod": authMode,
};
try {
const response = await axios.post(Constants.hipServiceUrl + Constants.healthIdAuthInit, data, Constants.headers);
const response = await axios.post(Constants.hipServiceUrl + Constants.abhaAddressVerificationRequestOtp, data, Constants.headers);
return response;
}
catch (error) {
if (error.response !== undefined)
return error.response.data;
else
return Constants.serviceUnavailableError;
return parseAPIError(error);
}
};

export const healthIdConfirmOtp = async (otp, authMode) => {
export const abhaAddressVerifyOtp = async (otp) => {
const data = {
"otp": otp,
};
try {
const response = await axios.post(Constants.hipServiceUrl + Constants.abhaAddressVerificationVerifyOtp, data, Constants.headers);
return response;
}
catch (error) {
return parseAPIError(error);
}
};

export const getAbhaAddressProfile = async () => {
try {
const response = await axios.get(Constants.hipServiceUrl + Constants.abhaAddressVerificationGetProfile, Constants.headers);
return response;
}
catch (error) {
return parseAPIError(error);
}
};

export const getAbhaAddresCard = async () => {
try {
const response = await axios.get(Constants.hipServiceUrl + Constants.abhaAddressVerificationGetCard,{
responseType: 'arraybuffer'
});
return response;
}
catch (error) {
return parseAPIError(error);
}
}


export const abhaNumberRequestOtp = async (abhaNumber, authMode) => {
const data = {
"abhaNumber": abhaNumber,
"authMethod": authMode,
};
try {
const response = await axios.post(Constants.hipServiceUrl + Constants.healthIdConfirmOtp, data, Constants.headers);
const response = await axios.post(Constants.hipServiceUrl + Constants.verificationRequestOtp, data, Constants.headers);
return response;
}
catch (error) {
if (error.response !== undefined)
return error.response.data;
else
return Constants.serviceUnavailableError;
return parseAPIError(error);
}
};

export const abhaNumberVerifyOtp = async (otp) => {
const data = {
"otp": otp,
};
try {
const response = await axios.post(Constants.hipServiceUrl + Constants.verificationVerifyOtp, data, Constants.headers);
return response;
}
catch (error) {
return parseAPIError(error);
}
};

Expand Down Expand Up @@ -464,17 +503,14 @@ export const updateHealthId = async (healthId) => {

export const mobileGenerateOtp = async (mobileNumber) => {
const data = {
"mobile": mobileNumber
"mobileNumber": mobileNumber
};
try {
const response = await axios.post(Constants.hipServiceUrl + Constants.generateMobileOtp, data, Constants.headers);
const response = await axios.post(Constants.hipServiceUrl + Constants.verificationRequestOtp, data, Constants.headers);
return response;
}
catch (error) {
if (error.response !== undefined)
return error.response.data;
else
return Constants.serviceUnavailableError;
return parseAPIError(error);
}
};

Expand All @@ -484,30 +520,34 @@ export const mobileVerifyOtp = async (otp) => {
"otp": otp
};
try {
const response = await axios.post(Constants.hipServiceUrl + Constants.verifyMobileOtp, data, Constants.headers);
const response = await axios.post(Constants.hipServiceUrl + Constants.verificationVerifyOtp, data, Constants.headers);
return response;
}
catch (error) {
if (error.response !== undefined)
return error.response.data;
else
return Constants.serviceUnavailableError;
return parseAPIError(error);
}
};

export const getPatientProfile = async (healthId) => {
export const verifyAbhaAccount = async (abhaNumber) => {
const data = {
"healthId": healthId
"abhaNumber": abhaNumber
};
try {
const response = await axios.post(Constants.hipServiceUrl + Constants.getPatientProfileInfo, data, Constants.headers);
const response = await axios.post(Constants.hipServiceUrl + Constants.verifyAbhaAccount, data, Constants.headers);
return response;
}
catch (error) {
if (error.response !== undefined)
return error.response.data;
else
return Constants.serviceUnavailableError;
return parseAPIError(error);
}
};

export const getPatientProfile = async () => {
try {
const response = await axios.get(Constants.hipServiceUrl + Constants.getPatientProfileInfo, Constants.headers);
return response;
}
catch (error) {
return parseAPIError(error);
}
};

Expand Down
19 changes: 19 additions & 0 deletions src/components/Common/FormatAndValidationUtils.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export const validateAbhaNumber = (abhaNumber) => {
return /^\d{14}$/.test(abhaNumber);
};
export const formatAbhaNumber = (abhaNumber) => {
let ABHA_NUMBER_REGEX = /^(\d{2})(\d{4})(\d{4})(\d{4})$/;
const match = abhaNumber.match(ABHA_NUMBER_REGEX);
if (match) {
return `${match[1]}-${match[2]}-${match[3]}-${match[4]}`;
}
return abhaNumber;
};

export const validateOtp = (otp) => {
return /^\d{6}$/.test(otp);
}

export const validateMobileNumber = (mobileNumber) => {
return /^\d{10}$/.test(mobileNumber);
}
9 changes: 4 additions & 5 deletions src/components/Common/patientMapper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,16 @@ export function mapPatient(patient){
value: patient.mobile
}] : undefined;
var address = {
line: [patient?.address],
city: patient?.townName,
city: patient?.townName || getCityFromAddressLine(patient?.address),
district: patient?.districtName,
state: patient?.stateName,
pincode: patient?.pincode
};
return {
healthIdNumber: patient?.healthIdNumber,
id: patient?.healthId,
healthIdNumber: patient?.abhaNumber,
id: patient?.preferredAbhaAddress || patient?.abhaAddress,
gender: patient.gender,
name: patient.name,
name: patient.name || patient.fullName,
isBirthDateEstimated: patient?.birthdate !== undefined ? false : (patient?.monthOfBirth == null || patient?.dayOfBirth == null),
dateOfBirth: patient?.birthdate === undefined ? getDate(patient) : patient?.birthdate.split('-').reverse().join('-'),
address: address,
Expand Down
27 changes: 17 additions & 10 deletions src/components/auth-modes/authModes.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState } from "react";
import {authInit, fetchGlobalProperty, healthIdAuthInit} from '../../api/hipServiceApi';
import {authInit, fetchGlobalProperty, abhaNumberRequestOtp, abhaAddressRequestOtp} from '../../api/hipServiceApi';
import OtpVerification from '../otp-verification/otpVerification';
import Spinner from '../spinner/spinner';
import {checkIfNotNull} from "../verifyHealthId/verifyHealthId";
Expand All @@ -9,7 +9,7 @@ import {enableDemographics} from "../../api/constants";
const AuthModes = (props) => {
const [selectedAuthMode, setSelectedAuthMode] = useState('');
const [showOtpField, setShowOtpField] = useState(false);
const [errorHealthId, setErrorHealthId] = useState('');
const [errorMessage, setErrorMessage] = useState('');
const [showError, setShowError] = useState(false);
const [loader, setLoader] = useState(false);
const [ndhmDetails, setNdhmDetails] = [props.ndhmDetails,props.setNdhmDetails];
Expand All @@ -18,6 +18,7 @@ const AuthModes = (props) => {

const id = props.id;
const authModes = props.authModes;
const isVerifyByAbhaAddress = props.isVerifyByAbhaAddress;
let authModesList = authModes !== undefined && authModes.length > 0 && authModes.map((item, i) => {
return (
<option key={i} value={item}>{item}</option>
Expand All @@ -32,13 +33,19 @@ const AuthModes = (props) => {
setLoader(true);
if(!props.isHealthNumberNotLinked){
setShowError(false);
const response = await healthIdAuthInit(id, selectedAuthMode);
let response;
if(isVerifyByAbhaAddress){
response = await abhaAddressRequestOtp(id, selectedAuthMode);
}
else{
response = await abhaNumberRequestOtp(id,selectedAuthMode);
}
if (response.data !== undefined) {
setShowOtpField(true);
}
else {
setShowError(true)
setErrorHealthId(response.details[0].message || response.message);
setErrorMessage(response.error.message);
}
}
else {
Expand All @@ -52,15 +59,15 @@ const AuthModes = (props) => {
const response = await authInit(id, selectedAuthMode);
if (response.error !== undefined) {
setShowError(true)
setErrorHealthId(response.error.message);
setErrorMessage(response.error.message);
}
else {
setIsDirectAuth(selectedAuthMode === "DIRECT");
props.setIsDemoAuth(selectedAuthMode === "DEMOGRAPHICS")
setShowOtpField(true);
}
} else {
setErrorHealthId("The selected Authentication Mode is currently not supported!");
setErrorMessage("The selected Authentication Mode is currently not supported!");
setShowError(true);
}
}
Expand All @@ -83,17 +90,17 @@ const AuthModes = (props) => {
<div className="auth-modes-select-btn">
<div className="auth-modes-select">
<select id="auth-modes" onChange={onAuthModeSelected}>
<option>Select auth mode..</option>
<option value=''>Select auth mode..</option>
{authModesList}
</select>
</div>
<button type="button" disabled={showOtpField || isDirectAuth} onClick={authenticate}>Authenticate</button>
{showError && <h6 className="error">{errorHealthId}</h6>}
<button type="button" disabled={selectedAuthMode === '' || showOtpField || isDirectAuth} onClick={authenticate}>Authenticate</button>
{showError && <h6 className="error">{errorMessage}</h6>}
</div>
</div>}
{loader && <Spinner />}
{isDirectAuth && <DirectAuth healthId={id} ndhmDetails={ndhmDetails} setNdhmDetails={setNdhmDetails}/>}
{!isDirectAuth && showOtpField && <OtpVerification id={id} selectedAuthMode={selectedAuthMode} ndhmDetails={ndhmDetails} setNdhmDetails={setNdhmDetails} isHealthNumberNotLinked={props.isHealthNumberNotLinked}/>}
{!isDirectAuth && showOtpField && <OtpVerification id={id} selectedAuthMode={selectedAuthMode} ndhmDetails={ndhmDetails} setNdhmDetails={setNdhmDetails} isHealthNumberNotLinked={props.isHealthNumberNotLinked} isVerifyByAbhaAddress={isVerifyByAbhaAddress}/>}
</div>
);
}
Expand Down
10 changes: 8 additions & 2 deletions src/components/creation/ABHACard.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, {useEffect, useState} from "react";
import './creation.scss';
import Spinner from "../spinner/spinner";
import {getCard} from "../../api/hipServiceApi";
import {getAbhaAddresCard, getCard} from "../../api/hipServiceApi";
import {GoVerified} from "react-icons/all";


Expand All @@ -18,7 +18,13 @@ const ABHACard = (props) => {

async function getPngCard() {
if(imgUrl == null) {
var response = await getCard();
var response;
if(props.isVerifyByAbhaAddress){
response = await getAbhaAddresCard();
}
else{
response = await getCard();
}
if (response) {
setLoader(false);
if (response.data === undefined) {
Expand Down
Loading

0 comments on commit bd4dd08

Please sign in to comment.