demobanque

πŸ‡«πŸ‡· Version franΓ§aise

DΓ©mo banque

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


Features


Pages

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

Getting started

Login

  1. Open the app
  2. Enter any 8-digit number as the account number
  3. Use passcode 123456 to automatically create a new profile
  4. First login redirects to Settings to configure the demo

Configuring the demo

Everything is in Settings (settings.html):

Create the Salesforce Connected App (OAuth + PKCE)

The integration uses the Authorization Code + PKCE flow as a public client (no secret). Step by step in your Salesforce org:

  1. Setup β†’ App Manager β†’ New Connected App (choose Create a Connected App).
  2. Fill in Connected App Name and Contact Email.
  3. Tick Enable OAuth Settings.
  4. Callback URL β€” the exact 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
    
  5. Selected OAuth Scopes: at least Manage user data via APIs (api). The refresh_token scope is not needed.
  6. Tick Require Proof Key for Code Exchange (PKCE) Extension for Supported Authorization Flows.
  7. Untick Require Secret for Web Server Flow and Require Secret for Refresh Token Flow (public client, no secret).
  8. Save, then Manage β†’ Edit Policies: Permitted Users = All users may self-authorize (or Admin approved), IP Relaxation = Relax IP restrictions.
  9. Manage Consumer Details β†’ copy the Consumer Key (the Consumer Secret is not used).
  10. Setup β†’ CORS β†’ New: add the app origin (scheme + host + port, no path) β€” covers both the token exchange and REST calls:
    https://poninsor.github.io
    http://localhost:5500
    
  11. In Settings β†’ Salesforce: pick the environment (Production / Sandbox 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.html

For 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

Advisor view

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.


Technical architecture

Stack

File structure

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

Global localStorage keys

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)

localStorage schema (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"
}

Public API β€” 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

Public API β€” DemoSalesforce

Available 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

Running locally

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).

Alternatives

# 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"

Reset

To start fresh:


Deployment

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.