π«π· Version franΓ§aise
A fully static banking app built for Genesys Cloud sales demonstrations. Simulates a white-label online bank β completely customisable (colours, logo, persona, balances, products) with no backend required.
Live demo: poninsor.github.io/demobanque/app
advisor.html): mirror interface for advisors to reply to clients, no client-side login required; live presence indicator (green/grey dot in messages.html) via a localStorage heartbeat updated every 15 s, synced instantly via the storage APIextraHeaders (X-User-FirstName, X-User-Email, etc.) auto-populated from the persona and configurable in Settings so Genesys Cloud Architect can route on context via the βGet SIP Headersβ action; active calls survive page navigation (state persisted to localStorage on beforeunload and resumed via SIP REPLACES on the next page, 20 s window); falls back to tel: when not configured; triggerable via contact.html?call=1 (chatbot use case); X-User- URL params (contact.html?call=1&X-User-ParentConnID=abc123) are automatically forwarded as extra SIP headers on the call; unified call entry point: all call buttons go through DemoGenesys.call() which delegates to AudioCodes or tel: based on configurationSalesforce object exposed in custom JavaScript with create/get/update helpers for the Task, Contact and Case objects, plus query(soql); requires a Connected App (PKCE required) and adding the app origin to the orgβs CORS allowlistjs-api.html): reference of the variables and functions available in custom JavaScript (Genesys + Salesforce helpers) with copyable examples, linked from Settings.json| URL | Description |
|---|---|
index.html |
Login β 8-digit account number + 6-digit PIN |
dashboard.html |
Dashboard β total wealth, recent transactions, spending chart |
account.html |
Current account detail β transaction list, projected balance |
transfer.html |
Transfer β 3-step wizard |
cards.html |
Cards β Visa Premier / Visa Classic |
beneficiaries.html |
Payees β Favourites and Organisations |
credits.html |
Loans β active loan + pre-approved offers |
messages.html |
Secure inbox β client-side conversation |
advisor.html |
Advisor view β full conversation list, real-time replies |
contact.html |
Contact us β channels, appointment booking, immediate callback |
settings.html |
Settings β 10 panels: backup, brand, persona, balances, products, language, security, Genesys Cloud, AudioCodes WebRTC, Salesforce |
js-api.html |
Documentation β variables and functions of the custom JavaScript (Genesys + Salesforce) with examples |
123456 to automatically create a new profileEverything is in Settings (settings.html):
.json before a Reset; import it afterwards to restore everythingSalesforce object in custom JavaScript (see js-api.html)The integration uses the Authorization Code + PKCE flow as a public client (no secret). Step by step in your Salesforce org:
settings.html URL, one per line. Live and local dev (β οΈ Salesforce does not ignore the port, add every port you use):
https://poninsor.github.io/demobanque/app/settings.html
http://localhost:5500/settings.html
refresh_token scope is not needed.All users may self-authorize (or Admin approved), IP Relaxation = Relax IP restrictions.https://poninsor.github.io
http://localhost:5500
test.salesforce.com), paste the Consumer Key, enable the toggle, Save, then Test.OAuth activation can take 2β10 minutes after creation. Common errors:
redirect_uri_mismatch(the Callback URL must match exactly β port,http/https,/app/); a CORS error in the console (origin missing from the allowlist).
OAuth configuration in Genesys Cloud The integration uses the Authorization Code + PKCE flow (no Client Secret). In your Genesys Cloud org, create an OAuth client of type Code Authorization with PKCE Required enabled, and authorise at least the following redirect URIs.
For the live demo on poninsor.github.io/demobanque:
https://poninsor.github.io/demobanque/app/index.html https://poninsor.github.io/demobanque/app/settings.html https://poninsor.github.io/demobanque/app/contact.htmlFor local development β Genesys Cloud ignores the port number for
localhost, so these three URIs cover all local ports:http://localhost/index.html http://localhost/settings.html http://localhost/contact.html
Open advisor.html in a second tab (no client-side login needed):
https://poninsor.github.io/demobanque/app/advisor.html
Optional URL parameter to open a specific conversation directly:
advisor.html?account=12345678
Messages are synchronised in real time between messages.html (client) and advisor.html (advisor) via the browserβs storage event API. In messages.html, a dot indicator shows whether the advisor currently has advisor.html open β the status updates instantly via the storage API and is polled every 30 s as a fallback.
To deselect an account in advisor.html, click on empty space in the conversations list.
app/
βββ index.html # Login
βββ dashboard.html
βββ account.html
βββ transfer.html
βββ cards.html
βββ beneficiaries.html
βββ credits.html
βββ messages.html
βββ advisor.html # Advisor view (no auth required)
βββ contact.html
βββ settings.html
βββ js-api.html # Custom JavaScript documentation (Genesys + Salesforce)
βββ config.js # DemoConfig β all localStorage logic
βββ genesys.js # DemoGenesys β Genesys Cloud integration
βββ salesforce.js # DemoSalesforce β OAuth PKCE + REST helpers (Task/Contact/Case)
βββ audiocodes.js # DemoAudioCodes β WebRTC custom integration (own UI on the standalone SDK)
βββ shell.js # Global behaviours (mobile nav, Messenger snippet)
βββ shell.css # App shell β layout, nav, bottom sheet (imports colors.css)
βββ colors.css # Design tokens β palette, type, spacing, shadows
βββ audiocodes.css # Floating call button + call panel (brand-aligned)
βββ assets/
β βββ logo.svg
β βββ logo-light.svg
β βββ logo-mark.svg
β βββ visa.svg
β βββ visa-white.svg
β βββ genesys.png
βββ lib/
βββ audiocodes/ # AudioCodes SDK β vendor files (never modify)
βββ click-to-call.js # standalone SDK (AudioCodesUA + JsSIP) β loaded at runtime
| Key | Contents |
|---|---|
demobank_v1 |
Main object β profiles, config, messages |
demobank_gc_token |
Genesys OAuth token cache { token, expiry, clientId } |
demobank_sf_token |
Salesforce OAuth token cache { token, instanceUrl, expiry, clientId } |
demobank_lang |
Global language preference, read before the profile loads |
demobank_adv_active |
Advisor heartbeat { accountId, ts } β present when advisor.html is open |
demobank_ac_restore |
AudioCodes call snapshot for restoration after page navigation |
demobank_settings_collapsed |
Settings page β array of collapsed panel ids (fold state) |
demobank_v1){
"accounts": {
"12345678": {
"pin": "123456",
"brandName": "DΓ©mo banque",
"slogan": "Ta banque, en plus simple.",
"primaryColor": "#FF4515",
"logoData": null,
"persona": {
"firstName": "Sophie",
"lastName": "Martin",
"email": "sophie.martin@example.fr",
"phone": "+33612345678",
"profileType": "Particulier β salariΓ©e cadre",
"advisor": "Camille Lefebvre β Paris 11"
},
"balances": { "checking": "12 480,57", "savings": "22 950,00", "pel": "0,00" },
"products": { "visaPremier": true, "visaClassic": true, "autoLoan": true, "assuranceVie": false },
"genesys": {
"region": "mypurecloud.ie",
"messengerSnippet": "",
"clientId": "",
"queueId": "",
"scriptId": "",
"callNumber": "3262",
"internalCallNumber": ""
},
"audiocodes": {
"enabled": false,
"domain": "",
"wssAddress": "",
"caller": "",
"password": "",
"extraHeaders": ""
},
"salesforce": {
"enabled": false,
"loginUrl": "https://login.salesforce.com",
"clientId": "",
"apiVersion": "v60.0"
},
"additionalJS": "alert(\"crΓ©ation d'un workitem\");",
"advisorAdditionalJS": "// Example: notify the customer by SMS when the advisor replies while the customer is offline.",
"language": "en",
"tutoiement": true,
"messages": null
}
},
"current": "12345678"
}
DemoConfig| Method | Description |
|---|---|
login(accountId, pin) |
Authenticates or creates a profile; returns { ok, isNew, msg } |
logout() |
Ends the session and redirects to index.html |
requireAuth() |
Guard β redirects if not logged in; call at the top of every protected page |
getCurrentAccountId() |
Returns the active account number ("12345678") or null |
getProfile() |
Returns the full profile object for the active account |
updateProfile(updates) |
Shallow-merges updates into the profile and persists |
deepUpdateProfile(key, value) |
Merges into a nested key (e.g. 'genesys') |
applyBranding([profile]) |
Applies the CSS palette + data-* bindings to the DOM |
generatePalette(hex) |
Generates the 10-stop palette (50β900) from a hex colour |
setLanguage(lang) |
Changes the language ('fr' or 'en') globally and in the profile |
getGlobalLang() |
Returns the active language |
getMessages() |
Returns the active accountβs messages (or defaults) |
addMessage(msg) |
Appends a message and persists |
getGenesys() |
Returns the active accountβs Genesys config |
getAudiocodes() |
Returns the active accountβs AudioCodes config |
getSalesforce() |
Returns the active accountβs Salesforce config |
executeAdditionalJS(runtime?) |
Executes the profileβs additionalJS snippet with injected variables (token, genesys, persona, message, fetchGenesys, etc.) |
executeAdvisorAdditionalJS(accountId, runtime?) |
Executes the target profileβs advisorAdditionalJS snippet with the same injected context |
getStorageUsageBytes() |
Estimates total localStorage usage in bytes (UTF-16, 2 bytes/char) |
purgeMessageAttachments(accountId) |
Removes fileData from all messages of an account; returns the count purged |
DemoSalesforceAvailable in custom JavaScript via the Salesforce variable (or globally as DemoSalesforce). All REST methods return a promise. See js-api.html for detailed documentation and examples.
| Method | Description |
|---|---|
createTask(fields) / getTask(id, fields?) / updateTask(id, fields) |
CRUD on the Task object (update = PATCH) |
createContact(...) / getContact(...) / updateContact(...) |
Same for Contact |
createCase(...) / getCase(...) / updateCase(...) |
Same for Case |
query(soql) |
Runs a SOQL query; returns { totalSize, records } |
sfFetch(path, init) / sfFetchJSON(path, init) |
Low-level access to the REST API (auto Bearer) |
isEnabled() |
true if the integration is enabled and a Consumer Key is set |
getTokenStatus() / clearToken() / redirectForAuth(sf, redirectUri) |
OAuth token management |
No build required, no dependencies to install.
node server.js # http://localhost:5500/
PORT=5500 node server.js # custom port
# or
npm start
server.js uses only Node.js built-in modules (Node 18+ required).
# Python (if Node is not available)
cd app && python3 -m http.server 5500
# VS Code: Live Server
# Right-click index.html β "Open with Live Server"
To start fresh:
messages.htmlsettings.htmlindex.html footer (clears all localStorage)The app is deployed on GitHub Pages from the app/ folder. No server configuration is needed (no routing rules, no server-side auth).
To deploy on Azure Static Web Apps, point the root at app/. No staticwebapp.config.json is required for a basic deployment.