// This file was created to separate the new account APIs since they have a new response structure // The new account APIs use phone numbers instead of emails for authentication import get from 'lodash/get' import isFunction from 'lodash/isFunction' import * as types from './types/sdk' type AccountType = 'patient' | 'provider' const warn = console.warn const accountClient = function({ client, requestUtils, _store, }: { client: any requestUtils: any _store: any }) { const dataPath = 'data' const { removeHeader } = requestUtils function _setAccountType(accountType: AccountType) { _store.accountType = accountType } function _setAuthOnClient(data: types.Auth) { const token = data.token || data.jwt_token const userId = data.user_id if (token) { requestUtils.setToken(token) requestUtils.setHeader('Authorization', `JWT ${token}`) } else { warn( 'You tried to set a JWT token on the account client but it was null or undefined', ) } if (userId) { requestUtils.setUserId(userId) } else { warn( 'You tried to set a user id on the account client but it was null or undefined', ) } } function _auth(accountType: AccountType) { return async function(params: { phone_number?: string phone?: string password: string }) { try { const { password = '' } = params const url = `/account/${accountType}/login/` const phone_number = params.phone_number || params.phone const postData = { phone_number, password } // Hacky fix because theres a glitch when we include this auth header removeHeader('Authorization') const response = await client.post(url, postData) const { data } = response if (data.error_code == 0) { _setAccountType(accountType) _setAuthOnClient(data.data) } return get(response, dataPath, null) } catch (error) { throw error } } } async function _authByVerificationCode(accountType: AccountType) { return async function(params: { phone_number?: string phone?: string phone_verification_code?: string }) { try { const { phone_verification_code = '' } = params const url = `/account/${accountType}/login/?method=sms_verify` const phone_number = params.phone_number || params.phone const postData = { phone_number, phone_verification_code } removeHeader('Authorization') const response = await client.post(url, postData) const { data } = response if (data.error_code == 0) { _setAccountType(accountType) _setAuthOnClient(data.data) } return get(response, dataPath, null) } catch (error) { throw error } } } function _authHeaderExists() { const headers = requestUtils.getCurrentHeaders() if ('Authorization' in headers) return true return false } function _changePassword(accountType: AccountType) { return async function( userId: string, params: { phone_number: string phone_verification_code: string password: string }, ) { try { const url = `/account/${accountType}/${userId}/password/` const response = await client.put(url, params) return get(response, dataPath, null) } catch (error) { throw error } } } function _createAccount(accountType: AccountType) { return async function( params: types.CreatePatientParams | types.CreateProviderParams, ) { try { const url = `/account/${accountType}/` const reApplyHeader = _tempStripAuthHeader() const response = await client.post(url, params) if (isFunction(reApplyHeader)) reApplyHeader() return get(response, dataPath, null) } catch (error) { throw error } } } function _fetchAccount(accountType: AccountType) { return async function(userId?: string) { try { userId = userId || requestUtils.getUserId() const url = `/account/${accountType}/${userId}/` const response = await client.get(url) return get(response, dataPath, null) } catch (error) { throw error } } } function _forgotPassword(accountType: AccountType) { return async function(params: types.AuthAccountVerificationCodeParams) { try { const url = `/account/${accountType}/forget_password/` const reApplyHeader = _tempStripAuthHeader() const response = await client.put(url, params) if (isFunction(reApplyHeader)) reApplyHeader() return get(response, dataPath, null) } catch (error) { throw error } } } function _fetchBlobs(accountType: AccountType) { return async function( userParams: types.FetchPatientBlobsParams = {}, ): Promise { try { const url = `/account/patient_blob/` const params: types.FetchPatientBlobsParams = {} if ('patient' in userParams) params.patient = userParams.patient if ('appointment' in userParams) { params.appointment = userParams.appointment } if ('max' in userParams) params.max_count = userParams.max if ('max_count' in userParams) params.max_count = userParams.max_count if ('maxCreatedAt' in userParams) { params.max_created_at = userParams.maxCreatedAt } else if ('max_created_at' in userParams) { params.max_created_at = userParams.max_created_at } const response = await client.get(url, { params }) return get(response, dataPath, null) } catch (error) { throw error } } } function _phoneNumberExists(accountType: AccountType) { return async function(phone_number: string = '') { try { const url = `/account/${accountType}/exists_phone_number/` const reApplyHeader = _tempStripAuthHeader() const response = await client.post(url, { phone_number }) if (isFunction(reApplyHeader)) reApplyHeader() return get(response, dataPath, null) } catch (error) { throw error } } } function _resetPassword(accountType: AccountType) { return async function( params: types.AuthAccountVerificationCodeParams | {} = {}, userId?: string, ) { try { userId = userId || requestUtils.getUserId() if (!params) { return warn( 'Tried to reset the accounts password but no parameters were present', ) } if (!userId) { return warn( 'Tried to reset the accounts password but no user_id was found.', ) } const url = `account/${accountType}/${userId}/phone_number/` const response = await client.put(url, params) return get(response, dataPath, null) } catch (error) { throw error } } } // Some APIs give an error when there is a Authorization header present. This func is used to temporarily // remove that header until the request is complete function _tempStripAuthHeader() { const authHeaderExists = _authHeaderExists() let authValue: any if (authHeaderExists) { authValue = requestUtils.getCurrentHeaders().Authorization } removeHeader('Authorization') if (authHeaderExists && authValue) { return () => requestUtils.setHeader('Authorization', authValue) } return false } function _updateAccount(accountType: AccountType) { return async function(params: types.PatientDocumentized, userId?: string) { try { userId = userId || requestUtils.getUserId() const url = `/account/${accountType}/${userId}/` const response = await client.put(url, params) return get(response, dataPath, null) } catch (error) { throw error } } } function _updatePhoneNumber(accountType: AccountType) { return async function( params: { phone_number: string; phone_verification_code: string }, userId?: string, ) { try { userId = userId || requestUtils.getUserId() const url = `/account/${accountType}/${userId}/phone_number` const response = await client.put(url, params) return get(response, dataPath, null) } catch (error) { throw error } } } return { // PATIENT METHODS patient: { auth: _auth('patient'), authByVerificationCode: _authByVerificationCode('patient'), create: _createAccount('patient'), // primaryId = patient id async createMember( params: types.CreatePatientMemberParams, userId?: string, ) { try { userId = userId || requestUtils.getUserId() const url = `/account/patient/${userId}/member/` const response = await client.post(url, params) return get(response, dataPath, null) } catch (error) { throw error } }, // primaryId = patient id async deleteMember(memberId: string, userId?: string) { try { userId = userId || requestUtils.getUserId() const url = `/account/patient/${userId}/deletemember/?member_id=${memberId}` const response = await client.delete(url) return get(response, dataPath, null) } catch (error) { throw error } }, fetchBlobs: _fetchBlobs('patient'), async fetchMembers(userId?: string) { try { userId = userId || requestUtils.getUserId() const url = `/account/patient/${userId}/members/` const response = await client.get(url) return get(response, dataPath, null) } catch (error) { throw error } }, forgotPassword: _forgotPassword('patient'), get: _fetchAccount('patient'), phoneNumberExists: _phoneNumberExists('patient'), resetPassword: _resetPassword('patient'), update: _updateAccount('patient'), updatePhoneNumber: _updatePhoneNumber('patient'), }, // PROVIDER METHODS provider: { auth: _auth('provider'), authByVerificationCode: _authByVerificationCode('patient'), changePassword: _changePassword('provider'), create: _createAccount('provider'), async createEmail(email: string, userId?: string) { try { userId = userId || requestUtils.getUserId() const url = `/account/provider/${userId}/email/` const response = client.put(url, { email }) return get(response, dataPath, null) } catch (error) { throw error } }, async createDocument(docName: string, data: string, userId?: string) { try { const id = userId || requestUtils.getUserId() const url = `/account/provider/${id}/${docName}/` const bodyParams = { base64text: data } const response = await client.post(url, bodyParams) return get(response, dataPath, null) } catch (error) { throw error } }, async fetchBankAccount() { try { const url = '/payment/dwolla/bank_account_detail/' const response = await client.get(url) return get(response, dataPath, null) } catch (error) { throw error } }, async fetchDocument(docName: string, userId?: string) { try { userId = userId || requestUtils.getUserId() const url = `/account/provider/${userId}/${docName}/` const response = await client.get(url) return get(response, dataPath, null) } catch (error) { throw error } }, fetchBlobs: _fetchBlobs('provider'), forgotPassword: _forgotPassword('provider'), get: _fetchAccount('provider'), async hasEmail(): Promise { try { const url = '/account/provider/exists_email/' const response = await client.get(url) return get(response, `${dataPath}.data.exists`, null) } catch (error) { throw error } }, phoneNumberExists: _phoneNumberExists('provider'), resetPassword: _resetPassword('provider'), async setEmail(email: string, userId?: string) { try { userId = userId || requestUtils.getUserId() const url = `/account/provider/${userId}/email/` const response = await client.put(url, { email }) return get(response, dataPath, null) } catch (error) { throw error } }, update: _updateAccount('provider'), async updateDocument( params: types.ProviderUpdateDocumentParams, userId?: string, ) { try { userId = userId || requestUtils.getUserId() const url = `/account/provider/${userId}/${params.name}/` const response = await client.post(url, { base64text: params.base64 }) return get(response, dataPath, null) } catch (error) { throw error } }, updatePhoneNumber: _updatePhoneNumber('provider'), }, // REFERRAL METHODS referral: { async authConfirm(referralId: string, token: string) { try { const url = `/referral/${referralId}/authenticate/?token=${token}` const reApplyHeader = _tempStripAuthHeader() const response = await client.get(url) if (isFunction(reApplyHeader)) reApplyHeader() return get(response, dataPath, null) } catch (error) { throw error } }, async authConfirmWithPatientId({ referral_id, patient_id, token, }: { referral_id: string patient_id: string token: string }) { try { const url = `/referral/${referral_id}/authenticate/?token=${token}&uid=${patient_id}` const reApplyHeader = _tempStripAuthHeader() const response = await client.get(url) if (isFunction(reApplyHeader)) reApplyHeader() return get(response, dataPath, null) } catch (error) { throw error } }, async completeProviderMeeting(id: string) { try { const url = `/referral/${id}/complete_provider_meeting/` const response = await client.get(url) return get(response, dataPath, null) } catch (error) { throw error } }, async fetchAppointment(id: string) { try { const url = `/referral/${id}/appointment/` const response = await client.get(url) return get(response, dataPath, null) } catch (error) { throw error } }, async get(referralId: string) { try { const url = `/referral/${referralId}/auth_status/` const response = await client.get(url) return get(response, dataPath, null) } catch (error) { throw error } }, async joinProviderMeeting(id: string) { try { const url = `/referral/${id}/join_provider_meeting/` const response = await client.get(url) return get(response, dataPath, null) } catch (error) { throw error } }, async request({ id, providerId, specialty, }: { id: string providerId: string specialty: string }) { try { const url = `/referral/${id}/refer/` const params: any = { specialty } if (providerId) params.provider_id = providerId const response = await client.get(url, { params }) return get(response, dataPath, null) } catch (error) { throw error } }, async saveDocumentation( referralId: string, data: { document_present_history_illness: string document_provider_note: string }, ) { try { const url = `/referral/${referralId}/documentation/` const response = await client.post(url, data) return get(response, dataPath, null) } catch (error) { throw error } }, async sendConfirmationSMS(phone_number: string) { try { const url = `/referral/` const response = await client.post(url, { phone_number }) return get(response, dataPath, null) } catch (error) { throw error } }, }, } } export default accountClient