From 3c0ce88f96908f599bdcef881b948cf9edfec44f Mon Sep 17 00:00:00 2001 From: Varsha Kumari Date: Thu, 13 Aug 2026 15:20:35 +0530 Subject: [PATCH 1/3] updated credit related apis --- Changelog.md | 4 + package.json | 2 +- src/store/mainStore.js | 212 +++++++------------- src/views/playground/SSIDashboardCredit.vue | 17 +- src/views/sa/components/CreditRecharge.vue | 2 +- 5 files changed, 89 insertions(+), 148 deletions(-) diff --git a/Changelog.md b/Changelog.md index 5836fdd..7ff50cd 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,10 @@ # Changelog ## [Unreleased] +### [3.14.2] - 2026-08-13 +### Modified +- Updated the credit API to fetch and activate credits from the dashboard instead of for a specific tenant. + ### [3.14.0] - 2026-08-07 ### Added - Added a toggle for mobile-assisted verification. diff --git a/package.json b/package.json index 03629fe..3224369 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "entity-developer-dashboard", - "version": "3.14.1", + "version": "3.14.2", "private": true, "scripts": { "serve": "vue-cli-service serve --mode production", diff --git a/src/store/mainStore.js b/src/store/mainStore.js index 18151c7..8da7338 100644 --- a/src/store/mainStore.js +++ b/src/store/mainStore.js @@ -8,6 +8,12 @@ import { RequestHandler, JWTExpiredErrorMessageHandling } from '../utils/utils.j const { apiServer, studioServer } = config; const apiServerBaseUrl = sanitizeUrl(apiServer.host) + apiServer.basePath; +const normalizeCredit = (credit) => ({ + ...credit, + totalCredits: credit?.apiCredit?.total ?? credit?.totalCredits ?? 0, + used: credit?.apiCredit?.used ?? credit?.used ?? 0, + creditScope: credit?.onChainAllowanceScopes ?? credit?.creditScope ?? [] +}); Vue.use(Vuex) @@ -377,10 +383,10 @@ const mainStore = { }, setKYCCredits: (state, payload) => { - state.kycCredits = payload + state.kycCredits = Array.isArray(payload) ? payload.map(normalizeCredit) : [] }, setSSICredits: (state, payload) => { - state.ssiCredits = payload + state.ssiCredits = Array.isArray(payload) ? payload.map(normalizeCredit) : [] }, setCompanies: (state, payload) => { state.companies = payload @@ -579,7 +585,7 @@ const mainStore = { return resp; }, creditRecharge: async ({ getters }, payload) => { - const url = `${apiServerBaseUrl}/credits/${payload.serviceId}`; + const url = `${apiServerBaseUrl}/app/${payload.serviceId}/credits; const resp = await RequestHandler(url, 'POST', payload, UtilsMixin.methods.getHeader(getters.getAuthToken), ) @@ -2699,36 +2705,23 @@ const mainStore = { }, // - KYC Credit - async fetchKYCCredits({ getters, commit, dispatch }) { - - if (!getters.getSelectedService || !getters.getSelectedService.tenantUrl) { - throw new Error('Tenant url is null or empty, service is not selected') + async fetchKYCCredits({ getters, commit }) { + const appId = getters.getSelectedService?.appId; + if (!appId) { + throw new Error('App Id is null or empty, service is not selected'); } - const url = `${sanitizeUrl(getters.getSelectedService.tenantUrl)}/api/v1/credit`; - // const url = `http://localhost:3001/api/v1/credit`; - - const authToken = getters.getSelectedService.access_token - const token = await dispatch('getValidToken', { - serviceId: getters.getSelectedService.appId, - grant_type: config.GRANT_TYPES_ENUM.CAVACH_API, - tokenStorageKey: "access_token" - }); - const headers = UtilsMixin.methods.getKycServiceHeader(token); - const resp = await fetch(url, { - method: 'GET', - headers - }) - const json = await resp.json() - if (!resp.ok || json.error) { - throw new Error(JWTExpiredErrorMessageHandling(json)) - } + const url = `${apiServerBaseUrl}/app/${appId}/credits`; + const resp = await RequestHandler( + url, + 'GET', + {}, + UtilsMixin.methods.getHeader(getters.getAuthToken) + ); + const credits = Array.isArray(resp) ? resp : (Array.isArray(resp?.data) ? resp.data : []); - if (json.data) { - commit('setKYCCredits', json.data) - return json.data - } - return [] + commit('setKYCCredits', credits); + return credits; }, async submitComplianceDetail({ getters, dispatch }, payload) { const { companyId, type, status, reasonDetail, reason, accessToken, serviceId } = payload; @@ -2797,43 +2790,25 @@ const mainStore = { }, // - KYC Credit - activateCredit({ getters, dispatch }, payload) { - return new Promise(function (resolve, reject) { - const { creditId } = payload - { - if (!getters.getSelectedService || !getters.getSelectedService.tenantUrl) { - return reject(new Error('Tenant url is null or empty, service is not selected')) - } - - if (!creditId) { - return reject(new Error('Credit Id is null or empty')) - } - const url = `${sanitizeUrl(getters.getSelectedService.tenantUrl)}/api/v1/credit/${creditId}/activate`; - const options = { - method: "POST", - headers: { - "Content-Type": "application/json", - "x-kyc-access-token": `${getters.getSelectedService.access_token}`, - "Origin": '*' - } - } - fetch(url, { - ...options - }) - .then(response => response.json()) - .then(json => { - if (json) { - dispatch('fetchKYCCredits') - resolve() - } else { - reject(new Error('Could not register DID for this service')) - } - }).catch(e => { - reject(e) - }) - } - }) + async activateCredit({ getters, dispatch }, payload) { + const appId = getters.getSelectedService?.appId; + const { creditId } = payload; + if (!appId) { + throw new Error('App Id is null or empty, service is not selected'); + } + if (!creditId) { + throw new Error('Credit Id is null or empty'); + } + const url = `${apiServerBaseUrl}/app/${appId}/credits/${creditId}/activate`; + const resp = await RequestHandler( + url, + 'POST', + {}, + UtilsMixin.methods.getHeader(getters.getAuthToken) + ); + await dispatch('fetchKYCCredits'); + return resp; }, @@ -3407,85 +3382,44 @@ const mainStore = { }, // eslint-disable-next-line - async fetchSSICredits({ getters, commit, dispatch }) { - if (!getters.getSelectedService || !getters.getSelectedService.tenantUrl) { - throw new Error('Tenant url is null or empty, service is not selected') + async fetchSSICredits({ getters, commit }) { + const appId = getters.getSelectedService?.appId; + if (!appId) { + throw new Error('App Id is null or empty, service is not selected'); } - const token = await dispatch('getValidToken', { - serviceId: getters.getSelectedService.appId, - grant_type: config.GRANT_TYPES_ENUM.SSI_API, - tokenStorageKey: "access_token" - }) - const url = `${sanitizeUrl(getters.getSelectedService.tenantUrl)}/api/v1/credit`; - const options = { - method: "GET", - headers: { - "Content-Type": "application/json", - "Authorization": `Bearer ${token}`, - "Origin": '*' - } - } + const url = `${apiServerBaseUrl}/app/${appId}/credits`; + const resp = await RequestHandler( + url, + 'GET', + {}, + UtilsMixin.methods.getHeader(getters.getAuthToken) + ); + const credits = Array.isArray(resp) ? resp : (Array.isArray(resp?.data) ? resp.data : []); - const resp = await fetch(url, { - ...options - }) - const json = await resp.json() - if (!resp.ok || json.error) { - const msg = Array.isArray(json.message) ? json.message.join(', ') : (json.message || json.error || 'Failed to fetch SSI credits'); - throw new Error(msg); - } - if (json) { - commit('setSSICredits', json) - return json - } - return [] + commit('setSSICredits', credits); + return credits; }, - activateSSICredit({ getters, dispatch }, payload) { - return new Promise(function (resolve, reject) { - const { creditId } = payload - { - if (!getters.getSelectedService || !getters.getSelectedService.tenantUrl) { - return reject(new Error('Tenant url is null or empty, service is not selected')) - } - - if (!creditId) { - return reject(new Error('Credit Id is null or empty')) - } - dispatch('getValidToken', { - serviceId: getters.getSelectedService.appId, - grant_type: config.GRANT_TYPES_ENUM.SSI_API, - tokenStorageKey: "access_token" - }).then((token) => { - const url = `${sanitizeUrl(getters.getSelectedService.tenantUrl)}/api/v1/credit/${creditId}/activate`; - const options = { - method: "POST", - headers: { - "Content-Type": "application/json", - "Authorization": `Bearer ${token}`, - "Origin": '*' - } - } - - return fetch(url, { - ...options - }) - }) - .then(response => response.json()) - .then(json => { - if (json) { - dispatch('fetchSSICredits') - resolve() - } else { - reject(new Error('Could not Activate credit for this service')) - } - }).catch(e => { - reject(e) - }) - } - }) + async activateSSICredit({ getters, dispatch }, payload) { + const appId = getters.getSelectedService?.appId; + const { creditId } = payload; + if (!appId) { + throw new Error('App Id is null or empty, service is not selected'); + } + if (!creditId) { + throw new Error('Credit Id is null or empty'); + } + const url = `${apiServerBaseUrl}/app/${appId}/credits/${creditId}/activate`; + const resp = await RequestHandler( + url, + 'POST', + {}, + UtilsMixin.methods.getHeader(getters.getAuthToken) + ); + await dispatch('fetchSSICredits'); + return resp; }, // eslint-disable-next-line async ssiDashboardAllowanceStats({ getters }, payload) { diff --git a/src/views/playground/SSIDashboardCredit.vue b/src/views/playground/SSIDashboardCredit.vue index 9bea145..a6626cf 100644 --- a/src/views/playground/SSIDashboardCredit.vue +++ b/src/views/playground/SSIDashboardCredit.vue @@ -852,13 +852,16 @@ export default { this.startTimer(); const creditsArr = Array.isArray(credits) ? credits : []; this.ssiCredits = creditsArr; - const credit = creditsArr.filter(each => { - if (each.status == 'Active') { - return each - } - }) - if (credit[0]?.credit) { - this.allowance.scope=credit[0].creditScope + const activeCredit = creditsArr.find(each => each.status === 'Active'); + if (activeCredit?.onChainAllowance) { + const { amount = 0, denom = 'uhid', usedAmount = 0 } = activeCredit.onChainAllowance; + this.allowance.spend_limit = [{ denom, amount: String(Math.max(amount - usedAmount, 0)) }]; + this.allowance.scope = activeCredit.onChainAllowanceScopes || []; + this.allowance.expiration = activeCredit.expiresAt || null; + } else { + this.allowance.spend_limit = [{ denom: 'uhid', amount: '0' }]; + this.allowance.scope = []; + this.allowance.expiration = null; } this.isLoading = false } catch (e) { diff --git a/src/views/sa/components/CreditRecharge.vue b/src/views/sa/components/CreditRecharge.vue index 0d4519d..5740e38 100644 --- a/src/views/sa/components/CreditRecharge.vue +++ b/src/views/sa/components/CreditRecharge.vue @@ -178,7 +178,7 @@ export default { serviceId: '', amount: '100', validityPeriod: '12', - validityPeriodUnit: 'MONTH', + validityPeriodUnit: 'Month', amountDenom: 'uHID', } }; From 059db4966a4011d5730682ca62ce6bdfb06bfd6f Mon Sep 17 00:00:00 2001 From: Varsha Kumari Date: Thu, 13 Aug 2026 15:21:32 +0530 Subject: [PATCH 2/3] fixed url --- src/store/mainStore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/store/mainStore.js b/src/store/mainStore.js index 8da7338..f617f97 100644 --- a/src/store/mainStore.js +++ b/src/store/mainStore.js @@ -585,7 +585,7 @@ const mainStore = { return resp; }, creditRecharge: async ({ getters }, payload) => { - const url = `${apiServerBaseUrl}/app/${payload.serviceId}/credits; + const url = `${apiServerBaseUrl}/app/${payload.serviceId}/credits`; const resp = await RequestHandler(url, 'POST', payload, UtilsMixin.methods.getHeader(getters.getAuthToken), ) From 1fdb2ea6218544523c2f7f455c81e4f80cd87a88 Mon Sep 17 00:00:00 2001 From: Varsha Kumari Date: Thu, 20 Aug 2026 12:08:04 +0530 Subject: [PATCH 3/3] fixed credit color issue in ID service --- Changelog.md | 3 ++- src/views/playground/KYCDashboardCredit.vue | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Changelog.md b/Changelog.md index 7ff50cd..8f64bda 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,7 +4,8 @@ ### [3.14.2] - 2026-08-13 ### Modified - Updated the credit API to fetch and activate credits from the dashboard instead of for a specific tenant. - +### Fixed +- Fixed the exhausted credit color issue in the ID Service dashboard. ### [3.14.0] - 2026-08-07 ### Added - Added a toggle for mobile-assisted verification. diff --git a/src/views/playground/KYCDashboardCredit.vue b/src/views/playground/KYCDashboardCredit.vue index 5d8c54a..7fb2841 100644 --- a/src/views/playground/KYCDashboardCredit.vue +++ b/src/views/playground/KYCDashboardCredit.vue @@ -307,14 +307,16 @@ export default { renderChart() { if (!Array.isArray(this.getKYCCredits)) return; - const expired = this.getKYCCredits.every(el => Date.now() > new Date(el.expiresAt)); const used = this.myKYCCredits.allUsedCredits || 0; const remaining = this.myKYCCredits.allRemainingCredits || 0; + const hasNoRemainingCredits = remaining <= 0; const dataToRender = (this.getKYCCredits.length === 0 || (used + remaining === 0)) ? [0, 1] : [used, remaining]; - const colors = expired ? ['#cbd5e1', '#f1f5f9'] : ['#94a3b8', '#3b82f6']; + const colors = hasNoRemainingCredits + ? ['#cbd5e1', '#94a3b8'] + : ['#94a3b8', '#3b82f6']; this.doughNutChart?.destroy(); const ctx = document.getElementById('doughNutChat');