diff --git a/packages/verify/src/embedded.js b/packages/verify/src/embedded.js index 44da1bd..cbac5bf 100644 --- a/packages/verify/src/embedded.js +++ b/packages/verify/src/embedded.js @@ -7,6 +7,7 @@ export default class AuthSession { this.key = key; this.listen = {}; this.locale = ''; + this.custom = null; this.endpoint = 'https://app.clicksign.com'; this.origin = `${window.location.protocol}://${window.location.host}`; } @@ -56,8 +57,32 @@ export default class AuthSession { return `${this.endpoint}${this.path}${this.params}`; } + // TODO: Definir nome do método combinando com o nome do query param (linha 81) + get data() { + if (!this.custom) return ''; + + return AuthSession.base64EncodeUrl(JSON.stringify({ custom: this.custom })); + } + + static base64EncodeUrl(value) { + let base64; + + if (typeof btoa === 'function') base64 = btoa(value); + else if (typeof Buffer !== 'undefined') base64 = Buffer.from(value, 'utf-8').toString('base64'); + else throw new Error('No base64 encoder available'); + + return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, ''); + } + get params() { - return `?origin=${this.origin}`; + const query = new URLSearchParams({ origin: this.origin }); + + // TODO: Definir nome do query param. Ex.: settings, payload, data, etc. + if (this.data) query.set('data', this.data); + + const queryToString = query.toString(); + + return queryToString ? `?${queryToString}` : ''; } get path() { diff --git a/packages/verify/src/embedded.spec.js b/packages/verify/src/embedded.spec.js index fd98825..33bbfeb 100644 --- a/packages/verify/src/embedded.spec.js +++ b/packages/verify/src/embedded.spec.js @@ -5,11 +5,21 @@ const sessionKey = 'foobar123'; const endpoint = 'https://example.com'; const originUrl = `${window.location.protocol}://${window.location.host}`; -function getSourceUrl(locale = '') { +function getDataParam(custom = null) { + if (!custom) return ''; + + return AuthSession.base64EncodeUrl(JSON.stringify({ custom })); +} + +function getSourceUrl(locale = '', custom = null) { const prefix = `${endpoint}/verify`; const verifyPath = locale ? `${prefix}/${locale}` : prefix; + const query = new URLSearchParams({ origin: originUrl }); + const data = getDataParam(custom); + + if (data) query.set('data', data); - return `${verifyPath}/sessions/${sessionKey}?origin=${originUrl}`; + return `${verifyPath}/sessions/${sessionKey}?${query.toString()}`; } function createContainerElement() { @@ -27,6 +37,8 @@ describe('AuthSession', () => { instance.endpoint = endpoint; instance.origin = originUrl; + instance.locale = ''; + instance.custom = null; instance.listen = {}; }); @@ -39,6 +51,7 @@ describe('AuthSession', () => { expect(instance.origin).toBe(originUrl); expect(instance.endpoint).toBe(endpoint); expect(instance.locale).toBe(''); + expect(instance.custom).toBeNull(); expect(instance.source).toBe(getSourceUrl()); }); @@ -102,6 +115,53 @@ describe('AuthSession', () => { }); }); + describe('Customization', () => { + it('should initialize custom as null by default', () => { + expect(instance.custom).toBeNull(); + }); + + it('should include custom colors in data query param in the iframe source URL when custom colors is set', () => { + const custom = { + colors: { + buttonTextColor: '#ffffff', + buttonBackgroundColor: '#000000', + }, + }; + + instance.custom = custom; + instance.start(containerElementId); + + const iframeElement = document.getElementById(containerElementId).children[0]; + const iframeSrcUrl = new URL(iframeElement.src); + + expect(instance.params).toContain('data='); + expect(instance.source).toBe(getSourceUrl('', custom)); + expect(iframeSrcUrl.searchParams.get('data')).toBe(getDataParam(custom)); + }); + }); + + describe('Query Params', () => { + it('should include origin query param in the iframe source URL', () => { + instance.start(containerElementId); + + const iframeElement = document.getElementById(containerElementId).children[0]; + const iframeSrcUrl = new URL(iframeElement.src); + + expect(instance.params).toBe(`?${new URLSearchParams({ origin: originUrl }).toString()}`); + expect(iframeSrcUrl.searchParams.get('origin')).toBe(originUrl); + }); + + it('should not include data query param when there is no payload', () => { + instance.start(containerElementId); + + const iframeElement = document.getElementById(containerElementId).children[0]; + const iframeSrcUrl = new URL(iframeElement.src); + + expect(instance.params).not.toContain('data='); + expect(iframeSrcUrl.searchParams.get('data')).toBeNull(); + }); + }); + describe('Events', () => { const eventMock = vi.fn(); const events = ['loaded', 'completed', 'error'];