A small frontend prototype of a support operator panel (active / archived dialogs, message list, reply templates, confirmation modals, toast notifications).
The backend is currently emulated with mock data and local in-JS stores.
| Login | Operator panel |
|---|---|
![]() |
![]() |
| Chat with attachments | Reply templates |
|---|---|
![]() |
![]() |
- Open
index.htmlin any modern browser (Chrome, Firefox, Edge). - To emulate login, use any username (min. 3 characters, Latin letters/digits/
._-) and password (min. 6 characters). - After login, the list of active dialogs is available. The archive is switched via the project menu (three dots → "Open archived chats").
- No bundler: plain scripts in
js/, loaded via<script defer>inindex.html. - Modules (IIFE) share a single internal context object,
window.SC:js/auth.js— Auth / login screen module (state machine, validation); exportswindow.Auth.js/store.js— state, cached DOM refs, mock dialog data,MessageStore(normalized), archive seeding flag.js/messages.js— message utilities, attachment helpers (inline image / file), message rendering, demo-data seeding.js/modals.js— reply templates modal (CRUD),TemplatesStore, image preview modal.js/dialogs.js— dialog list rendering, selection, origin badges, switch-to-operator, active/archive toggle, SLA timer pills.js/chat-ui.js— chat footer (AI banner / operator composer), list event delegation, pagination, custom select, popup/context menus.js/logout-modal.js,js/unsubscribe-modal.js,js/toasts.js— confirmation modals and service toasts.js/app.js— initialization, event wiring, and the single publicwindow.AppAPI.
- Dialog / message data is mock (arrays + in-memory MessageStore). The archive is seeded lazily.
- Reply templates — local in-memory store (CRUD).
- Messages support attachments (inline image / file) with upgrade / fallback rendering.
All stable functions are aggregated in the window.AppAPI object (versioned). Existing globals (Auth, showServiceNotification, app.dialogs, etc.) are kept for backward compatibility, but the unified API is recommended.
Version 1.0.1 (patch): added attachment support (inline image / file) for client messages (author: 'client'). Previously client attachments were ignored during rendering.
console.log(AppAPI.version) // '1.0.0'| Method | Description |
|---|---|
isAuthed() |
Returns true/false — whether a (mock) token exists. |
getPhase() |
Current state machine phase: `unauthenticated |
showLogin() |
Show the login screen. |
showApp() |
Force-show the application (used after a successful login). |
logout() |
Log out (clears the token and returns to the login screen). |
| Method | Description |
|---|---|
select(id) |
Select a dialog and display its messages. |
getById(id) |
Get the dialog object (active or archived). |
toggleArchive() |
Toggle Active ↔ Archive mode (re-renders the list). |
switchToOperator(id, {source}) |
Hand a dialog over from the bot to an operator (updates the badge and footer). |
timers.set(id, value, opts) |
Set a timer pill (text, opts.datetime, auto-show). |
timers.show(id) |
Show the timer. |
timers.hide(id) |
Hide the timer. |
| Method | Description |
|---|---|
add(dialogId, { author, text, attachments, createdAt }) |
Locally add a message (demo) to the given dialog. Returns the message object. `author: client |
{
id: string | number,
name: string,
size?: '123 KB',
contentType?: string, // MIME
url?: string, // for inline preview
downloadUrl?: string, // download link
displayHint?: 'inline-image' | 'file'
}If displayHint is not specified, the system tries to classify it itself (image/* and size <= 800KB → inline image).
Example of adding a client message with attachments (since version 1.0.1):
AppAPI.dialogs.select(3);
AppAPI.messages.add(3, {
author: 'client',
text: 'Here is a file and a screenshot',
attachments: [
{
id: 'cimg1',
name: 'screen.png',
size: '120 KB',
contentType: 'image/png',
url: 'https://picsum.photos/seed/client123/320/180'
},
{
id: 'cdoc1',
name: 'spec.pdf',
size: '250 KB',
contentType: 'application/pdf',
downloadUrl: 'https://example.com/spec.pdf'
}
]
});| Method | Description |
|---|---|
open() |
Open the templates modal (CRUD via the UI). |
| Method | Description |
|---|---|
logout() |
Open the logout confirmation modal. |
unsubscribe(dialogId) |
Open the "Unsubscribe" modal for the dialog's user. |
AppAPI.notify('Saved', 'Changes applied');
AppAPI.notify('Info without text');
Timeout options (legacy): { timeout: 6000 }.
AppAPI.ping(); // { ok:true, ts: 173..., phase: 'authenticated' }
// Select a dialog and add an operator message
AppAPI.dialogs.select(3);
AppAPI.messages.add(3, { author:'operator', text:'Good afternoon! How can I help?' });
// Hand over from bot to operator
AppAPI.dialogs.switchToOperator(3);
// Set an SLA timer
AppAPI.dialogs.timers.set(3, '15m', { datetime: new Date().toISOString() });
// Show templates
AppAPI.templates.open();
// Notification
AppAPI.notify('Done', 'Template saved');| Event | detail |
|---|---|
auth:change |
{ phase, error } — dispatched when the auth state changes. |
Example:
window.addEventListener('auth:change', e => console.log('Auth phase:', e.detail.phase));- No real network layer (login / messages / templates).
- Message ids are generated locally (
temp:*). - Handoff to an operator does not call the server — it is just a mutation of a local array.
- Image previews use the public
picsum.photos(can be replaced with a CDN).
- Replace
loginRequestwith a fetch to the API (+ error handling). - Move
MOCK_DIALOGSandARCHIVE_DIALOGSto a paginated list endpoint. - Upgrade
MessageStoreto two-way synchronization (WebSocket / SSE / polling). - Move TemplatesStore to REST (CRUD endpoints) + optimistic UI.
- Add delivery statuses (sent/delivered/read) based on server events.
Unless agreed otherwise, consider the code delivered as-is as part of a freelance task; further modularity work can be done separately.



