Skip to content

Commit bd4dd08

Browse files
BAH-4119 | Migrate verification flow to v3 ABDM APIs (#92)
* 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 <arshiya.flamingo@gmail.com>
1 parent 456c075 commit bd4dd08

11 files changed

+346
-179
lines changed

src/api/apiUtils.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ export const parseAPIError = (error) => {
33
if (!error.response?.data) {
44
return Constants.serviceUnavailableError;
55
}
6-
var errorResponseData = error.response.data
6+
var errorResponseData = error.response.data;
7+
if (errorResponseData instanceof Array){
8+
errorResponseData = errorResponseData[0];
9+
}
710
if (errorResponseData.message)
811
return { "error": { "message": errorResponseData.message } }
912
if (errorResponseData.error?.message)

src/api/constants.js

+9-6
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,17 @@ export const generateABHAMobileOTP = "/v3/hip/generateMobileOtp"
2222
export const verifyMobileOTP = "/v3/hip/verifyMobileOtp"
2323
export const getAbhaAddressSuggestions = "/v3/hip/getAbhaAddressSuggestions"
2424
export const getPngCard = "/v3/hip/getAbhaCard";
25-
export const searchHealthId = "/v2/search/searchHealthIdToLogin"
26-
export const healthIdAuthInit = "/v2/auth/init"
27-
export const healthIdConfirmOtp = "/v2/hip/confirmOTP"
25+
export const searchAbhaAddress = "/v3/hip/verification/abhaAddress/search";
26+
export const abhaAddressVerificationRequestOtp = "/v3/hip/verification/abhaAddress/requestOtp";
27+
export const abhaAddressVerificationVerifyOtp = "/v3/hip/verification/abhaAddress/verifyOtp";
28+
export const abhaAddressVerificationGetProfile = "/v3/hip/verification/abhaAddress/getProfile";
29+
export const abhaAddressVerificationGetCard = "/v3/hip/verification/abhaAddress/getCard";
2830
export const createDefaultHealthId = "/v1/account/update/phr-address"
2931
export const updateHealthId = "/v2/hip/profile/updatePhrAddress"
30-
export const generateMobileOtp = "/v2/registration/mobile/login/generateOtp"
31-
export const verifyMobileOtp = "/v2/registration/mobile/login/verifyOtp"
32-
export const getPatientProfileInfo = "/v2/registration/mobile/login/userAuthorizedToken"
32+
export const verificationRequestOtp = "/v3/hip/verification/requestOtp"
33+
export const verificationVerifyOtp = "/v3/hip/verification/verifyOtp"
34+
export const verifyAbhaAccount= "/v3/hip/verification/verifyAbhaAccount"
35+
export const getPatientProfileInfo = "/v3/hip/verification/getAbhaProfile"
3336
export const mobileEmailInit = "/v1/phr/login/mobileEmail/init";
3437
export const mobileEmailPreverification = "/v1/phr/login/mobileEmail/preVerification";
3538
export const getUserToken = "/v1/phr/login/mobileEmail/getUserToken";

src/api/hipServiceApi.js

+79-39
Original file line numberDiff line numberDiff line change
@@ -386,53 +386,92 @@ export const createABHAAddress = async (abhaAddress) => {
386386
}
387387
}
388388

389-
export const searchHealthId = async (healthId) => {
389+
export const searchAbhaAddress = async (abhaAddress) => {
390390
const data = {
391-
"healthId": healthId
391+
"abhaAddress": abhaAddress
392392
};
393393
try {
394-
const response = await axios.post(Constants.hipServiceUrl + Constants.searchHealthId,data, Constants.headers);
394+
const response = await axios.post(Constants.hipServiceUrl + Constants.searchAbhaAddress,data, Constants.headers);
395395
return response;
396396
}
397397
catch (error) {
398-
if (error.response !== undefined)
399-
return error.response.data;
400-
else
401-
return Constants.serviceUnavailableError;
398+
return parseAPIError(error);
402399
}
403400
}
404-
405-
export const healthIdAuthInit = async (healthId, authMode) => {
401+
export const abhaAddressRequestOtp = async (abhaAddress, authMode) => {
406402
const data = {
407-
"healthId": healthId,
403+
"abhaAddress": abhaAddress,
408404
"authMethod": authMode,
409405
};
410406
try {
411-
const response = await axios.post(Constants.hipServiceUrl + Constants.healthIdAuthInit, data, Constants.headers);
407+
const response = await axios.post(Constants.hipServiceUrl + Constants.abhaAddressVerificationRequestOtp, data, Constants.headers);
412408
return response;
413409
}
414410
catch (error) {
415-
if (error.response !== undefined)
416-
return error.response.data;
417-
else
418-
return Constants.serviceUnavailableError;
411+
return parseAPIError(error);
419412
}
420413
};
421414

422-
export const healthIdConfirmOtp = async (otp, authMode) => {
415+
export const abhaAddressVerifyOtp = async (otp) => {
423416
const data = {
424417
"otp": otp,
418+
};
419+
try {
420+
const response = await axios.post(Constants.hipServiceUrl + Constants.abhaAddressVerificationVerifyOtp, data, Constants.headers);
421+
return response;
422+
}
423+
catch (error) {
424+
return parseAPIError(error);
425+
}
426+
};
427+
428+
export const getAbhaAddressProfile = async () => {
429+
try {
430+
const response = await axios.get(Constants.hipServiceUrl + Constants.abhaAddressVerificationGetProfile, Constants.headers);
431+
return response;
432+
}
433+
catch (error) {
434+
return parseAPIError(error);
435+
}
436+
};
437+
438+
export const getAbhaAddresCard = async () => {
439+
try {
440+
const response = await axios.get(Constants.hipServiceUrl + Constants.abhaAddressVerificationGetCard,{
441+
responseType: 'arraybuffer'
442+
});
443+
return response;
444+
}
445+
catch (error) {
446+
return parseAPIError(error);
447+
}
448+
}
449+
450+
451+
export const abhaNumberRequestOtp = async (abhaNumber, authMode) => {
452+
const data = {
453+
"abhaNumber": abhaNumber,
425454
"authMethod": authMode,
426455
};
427456
try {
428-
const response = await axios.post(Constants.hipServiceUrl + Constants.healthIdConfirmOtp, data, Constants.headers);
457+
const response = await axios.post(Constants.hipServiceUrl + Constants.verificationRequestOtp, data, Constants.headers);
429458
return response;
430459
}
431460
catch (error) {
432-
if (error.response !== undefined)
433-
return error.response.data;
434-
else
435-
return Constants.serviceUnavailableError;
461+
return parseAPIError(error);
462+
}
463+
};
464+
465+
export const abhaNumberVerifyOtp = async (otp) => {
466+
const data = {
467+
"otp": otp,
468+
};
469+
try {
470+
const response = await axios.post(Constants.hipServiceUrl + Constants.verificationVerifyOtp, data, Constants.headers);
471+
return response;
472+
}
473+
catch (error) {
474+
return parseAPIError(error);
436475
}
437476
};
438477

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

465504
export const mobileGenerateOtp = async (mobileNumber) => {
466505
const data = {
467-
"mobile": mobileNumber
506+
"mobileNumber": mobileNumber
468507
};
469508
try {
470-
const response = await axios.post(Constants.hipServiceUrl + Constants.generateMobileOtp, data, Constants.headers);
509+
const response = await axios.post(Constants.hipServiceUrl + Constants.verificationRequestOtp, data, Constants.headers);
471510
return response;
472511
}
473512
catch (error) {
474-
if (error.response !== undefined)
475-
return error.response.data;
476-
else
477-
return Constants.serviceUnavailableError;
513+
return parseAPIError(error);
478514
}
479515
};
480516

@@ -484,30 +520,34 @@ export const mobileVerifyOtp = async (otp) => {
484520
"otp": otp
485521
};
486522
try {
487-
const response = await axios.post(Constants.hipServiceUrl + Constants.verifyMobileOtp, data, Constants.headers);
523+
const response = await axios.post(Constants.hipServiceUrl + Constants.verificationVerifyOtp, data, Constants.headers);
488524
return response;
489525
}
490526
catch (error) {
491-
if (error.response !== undefined)
492-
return error.response.data;
493-
else
494-
return Constants.serviceUnavailableError;
527+
return parseAPIError(error);
495528
}
496529
};
497530

498-
export const getPatientProfile = async (healthId) => {
531+
export const verifyAbhaAccount = async (abhaNumber) => {
499532
const data = {
500-
"healthId": healthId
533+
"abhaNumber": abhaNumber
501534
};
502535
try {
503-
const response = await axios.post(Constants.hipServiceUrl + Constants.getPatientProfileInfo, data, Constants.headers);
536+
const response = await axios.post(Constants.hipServiceUrl + Constants.verifyAbhaAccount, data, Constants.headers);
504537
return response;
505538
}
506539
catch (error) {
507-
if (error.response !== undefined)
508-
return error.response.data;
509-
else
510-
return Constants.serviceUnavailableError;
540+
return parseAPIError(error);
541+
}
542+
};
543+
544+
export const getPatientProfile = async () => {
545+
try {
546+
const response = await axios.get(Constants.hipServiceUrl + Constants.getPatientProfileInfo, Constants.headers);
547+
return response;
548+
}
549+
catch (error) {
550+
return parseAPIError(error);
511551
}
512552
};
513553

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export const validateAbhaNumber = (abhaNumber) => {
2+
return /^\d{14}$/.test(abhaNumber);
3+
};
4+
export const formatAbhaNumber = (abhaNumber) => {
5+
let ABHA_NUMBER_REGEX = /^(\d{2})(\d{4})(\d{4})(\d{4})$/;
6+
const match = abhaNumber.match(ABHA_NUMBER_REGEX);
7+
if (match) {
8+
return `${match[1]}-${match[2]}-${match[3]}-${match[4]}`;
9+
}
10+
return abhaNumber;
11+
};
12+
13+
export const validateOtp = (otp) => {
14+
return /^\d{6}$/.test(otp);
15+
}
16+
17+
export const validateMobileNumber = (mobileNumber) => {
18+
return /^\d{10}$/.test(mobileNumber);
19+
}

src/components/Common/patientMapper.jsx

+4-5
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,16 @@ export function mapPatient(patient){
66
value: patient.mobile
77
}] : undefined;
88
var address = {
9-
line: [patient?.address],
10-
city: patient?.townName,
9+
city: patient?.townName || getCityFromAddressLine(patient?.address),
1110
district: patient?.districtName,
1211
state: patient?.stateName,
1312
pincode: patient?.pincode
1413
};
1514
return {
16-
healthIdNumber: patient?.healthIdNumber,
17-
id: patient?.healthId,
15+
healthIdNumber: patient?.abhaNumber,
16+
id: patient?.preferredAbhaAddress || patient?.abhaAddress,
1817
gender: patient.gender,
19-
name: patient.name,
18+
name: patient.name || patient.fullName,
2019
isBirthDateEstimated: patient?.birthdate !== undefined ? false : (patient?.monthOfBirth == null || patient?.dayOfBirth == null),
2120
dateOfBirth: patient?.birthdate === undefined ? getDate(patient) : patient?.birthdate.split('-').reverse().join('-'),
2221
address: address,

src/components/auth-modes/authModes.jsx

+17-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useState } from "react";
2-
import {authInit, fetchGlobalProperty, healthIdAuthInit} from '../../api/hipServiceApi';
2+
import {authInit, fetchGlobalProperty, abhaNumberRequestOtp, abhaAddressRequestOtp} from '../../api/hipServiceApi';
33
import OtpVerification from '../otp-verification/otpVerification';
44
import Spinner from '../spinner/spinner';
55
import {checkIfNotNull} from "../verifyHealthId/verifyHealthId";
@@ -9,7 +9,7 @@ import {enableDemographics} from "../../api/constants";
99
const AuthModes = (props) => {
1010
const [selectedAuthMode, setSelectedAuthMode] = useState('');
1111
const [showOtpField, setShowOtpField] = useState(false);
12-
const [errorHealthId, setErrorHealthId] = useState('');
12+
const [errorMessage, setErrorMessage] = useState('');
1313
const [showError, setShowError] = useState(false);
1414
const [loader, setLoader] = useState(false);
1515
const [ndhmDetails, setNdhmDetails] = [props.ndhmDetails,props.setNdhmDetails];
@@ -18,6 +18,7 @@ const AuthModes = (props) => {
1818

1919
const id = props.id;
2020
const authModes = props.authModes;
21+
const isVerifyByAbhaAddress = props.isVerifyByAbhaAddress;
2122
let authModesList = authModes !== undefined && authModes.length > 0 && authModes.map((item, i) => {
2223
return (
2324
<option key={i} value={item}>{item}</option>
@@ -32,13 +33,19 @@ const AuthModes = (props) => {
3233
setLoader(true);
3334
if(!props.isHealthNumberNotLinked){
3435
setShowError(false);
35-
const response = await healthIdAuthInit(id, selectedAuthMode);
36+
let response;
37+
if(isVerifyByAbhaAddress){
38+
response = await abhaAddressRequestOtp(id, selectedAuthMode);
39+
}
40+
else{
41+
response = await abhaNumberRequestOtp(id,selectedAuthMode);
42+
}
3643
if (response.data !== undefined) {
3744
setShowOtpField(true);
3845
}
3946
else {
4047
setShowError(true)
41-
setErrorHealthId(response.details[0].message || response.message);
48+
setErrorMessage(response.error.message);
4249
}
4350
}
4451
else {
@@ -52,15 +59,15 @@ const AuthModes = (props) => {
5259
const response = await authInit(id, selectedAuthMode);
5360
if (response.error !== undefined) {
5461
setShowError(true)
55-
setErrorHealthId(response.error.message);
62+
setErrorMessage(response.error.message);
5663
}
5764
else {
5865
setIsDirectAuth(selectedAuthMode === "DIRECT");
5966
props.setIsDemoAuth(selectedAuthMode === "DEMOGRAPHICS")
6067
setShowOtpField(true);
6168
}
6269
} else {
63-
setErrorHealthId("The selected Authentication Mode is currently not supported!");
70+
setErrorMessage("The selected Authentication Mode is currently not supported!");
6471
setShowError(true);
6572
}
6673
}
@@ -83,17 +90,17 @@ const AuthModes = (props) => {
8390
<div className="auth-modes-select-btn">
8491
<div className="auth-modes-select">
8592
<select id="auth-modes" onChange={onAuthModeSelected}>
86-
<option>Select auth mode..</option>
93+
<option value=''>Select auth mode..</option>
8794
{authModesList}
8895
</select>
8996
</div>
90-
<button type="button" disabled={showOtpField || isDirectAuth} onClick={authenticate}>Authenticate</button>
91-
{showError && <h6 className="error">{errorHealthId}</h6>}
97+
<button type="button" disabled={selectedAuthMode === '' || showOtpField || isDirectAuth} onClick={authenticate}>Authenticate</button>
98+
{showError && <h6 className="error">{errorMessage}</h6>}
9299
</div>
93100
</div>}
94101
{loader && <Spinner />}
95102
{isDirectAuth && <DirectAuth healthId={id} ndhmDetails={ndhmDetails} setNdhmDetails={setNdhmDetails}/>}
96-
{!isDirectAuth && showOtpField && <OtpVerification id={id} selectedAuthMode={selectedAuthMode} ndhmDetails={ndhmDetails} setNdhmDetails={setNdhmDetails} isHealthNumberNotLinked={props.isHealthNumberNotLinked}/>}
103+
{!isDirectAuth && showOtpField && <OtpVerification id={id} selectedAuthMode={selectedAuthMode} ndhmDetails={ndhmDetails} setNdhmDetails={setNdhmDetails} isHealthNumberNotLinked={props.isHealthNumberNotLinked} isVerifyByAbhaAddress={isVerifyByAbhaAddress}/>}
97104
</div>
98105
);
99106
}

src/components/creation/ABHACard.jsx

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, {useEffect, useState} from "react";
22
import './creation.scss';
33
import Spinner from "../spinner/spinner";
4-
import {getCard} from "../../api/hipServiceApi";
4+
import {getAbhaAddresCard, getCard} from "../../api/hipServiceApi";
55
import {GoVerified} from "react-icons/all";
66

77

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

1919
async function getPngCard() {
2020
if(imgUrl == null) {
21-
var response = await getCard();
21+
var response;
22+
if(props.isVerifyByAbhaAddress){
23+
response = await getAbhaAddresCard();
24+
}
25+
else{
26+
response = await getCard();
27+
}
2228
if (response) {
2329
setLoader(false);
2430
if (response.data === undefined) {

0 commit comments

Comments
 (0)