1763 lines
90 KiB
JavaScript
1763 lines
90 KiB
JavaScript
/**
|
||
* App UI editor: screen → keys mapping and tablet mocks matching current Android layouts.
|
||
* Screens with multiple states expose `variants` (chip picker in the editor).
|
||
*/
|
||
|
||
/** @typedef {{ id: string, label: string, focusKeys?: string[], mock: () => string }} AppUiVariant */
|
||
/** @typedef {{ id: string, label: string, hint?: string, keys: string[], mock?: () => string, variants?: AppUiVariant[] }} AppUiScreen */
|
||
|
||
function f(key, cls = '', tag = 'input') {
|
||
const safe = String(key).replace(/"/g, '');
|
||
if (tag === 'textarea') {
|
||
return `<textarea class="aq-field ${cls}" data-appui-key="${safe}" rows="2" spellcheck="true"></textarea>`;
|
||
}
|
||
return `<input type="text" class="aq-field ${cls}" data-appui-key="${safe}" spellcheck="true">`;
|
||
}
|
||
|
||
function iconHelp() {
|
||
return `<span class="aq-icon-btn" aria-hidden="true"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="9"/><path d="M9.5 9a2.5 2.5 0 115 1c0 1.5-2.5 2-2.5 3.5"/><circle cx="12" cy="17" r=".8" fill="currentColor" stroke="none"/></svg></span>`;
|
||
}
|
||
function iconRefresh() {
|
||
return `<span class="aq-icon-btn" aria-hidden="true"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12a9 9 0 11-3-6.7"/><polyline points="21 3 21 9 15 9"/></svg></span>`;
|
||
}
|
||
function iconPerson() {
|
||
return `<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>`;
|
||
}
|
||
function iconLock() {
|
||
return `<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"><rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V8a4 4 0 018 0v3"/></svg>`;
|
||
}
|
||
function iconBack() {
|
||
return `<span class="aq-icon-btn aq-icon-btn-lg" aria-hidden="true"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg></span>`;
|
||
}
|
||
function iconChevron() {
|
||
return `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>`;
|
||
}
|
||
function langChip() {
|
||
return `<span class="aq-lang-chip">Deutsch ${iconChevron()}</span>`;
|
||
}
|
||
|
||
function toastBanner(key, cls = '') {
|
||
return `<div class="aq-toast ${cls}">${f(key, 'aq-toast-field')}</div>`;
|
||
}
|
||
|
||
/** Client note row as on opening_screen (ClientNoteUi.bindRow). */
|
||
function clientNoteRow({ hasNote = false, pending = false } = {}) {
|
||
const preview = hasNote
|
||
? `<span class="aq-note-preview">Beispielnotiz…</span>`
|
||
: f('client_note_add', 'aq-muted aq-sm');
|
||
const actionLabel = hasNote ? 'client_note_edit' : 'client_note_add_action';
|
||
const badge = pending
|
||
? `<span class="aq-note-pending">${f('client_note_pending', 'aq-xs')}</span>`
|
||
: '';
|
||
return `
|
||
<div class="aq-note-row">
|
||
<div class="aq-note-icon-well" aria-hidden="true">
|
||
<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="#fff" stroke-width="2"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
|
||
</div>
|
||
<div class="aq-note-main">
|
||
<div class="aq-note-label-row">
|
||
${f('client_note_for_client', 'aq-note-label')}
|
||
${badge}
|
||
</div>
|
||
${preview}
|
||
</div>
|
||
<div class="aq-btn-pill aq-btn-primary aq-note-cta-pill">${f(actionLabel, 'aq-field-on-primary aq-xs')}</div>
|
||
</div>`;
|
||
}
|
||
|
||
/** Settings bottom sheet (HandlerOpeningScreen.showSettingsSheet — handle + logout only, no title). */
|
||
function settingsSheet() {
|
||
return `
|
||
<div class="aq-sheet-scrim">
|
||
<div class="aq-bottom-sheet">
|
||
<div class="aq-sheet-handle" aria-hidden="true"></div>
|
||
<div class="aq-btn-pill aq-btn-danger aq-sheet-logout">${f('logout', 'aq-field-on-primary')}</div>
|
||
</div>
|
||
</div>`;
|
||
}
|
||
|
||
/** Client note editor bottom sheet (ClientNoteUi.showEditor — bottom_sheet_client_note.xml). */
|
||
function clientNoteEditorSheet({ errorKey = null } = {}) {
|
||
const err = errorKey
|
||
? `<div class="aq-field-error">${f(errorKey, 'aq-sm')}</div>`
|
||
: '';
|
||
return `
|
||
<div class="aq-sheet-scrim">
|
||
<div class="aq-bottom-sheet">
|
||
<div class="aq-sheet-handle" aria-hidden="true"></div>
|
||
<div class="aq-note-editor-header">
|
||
<div class="aq-note-icon-well aq-note-icon-well-sm" aria-hidden="true">
|
||
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="#fff" stroke-width="2"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
|
||
</div>
|
||
<div>
|
||
${f('client_note_title', 'aq-sheet-title')}
|
||
${f('client_note_for_client', 'aq-muted aq-sm')}
|
||
</div>
|
||
</div>
|
||
<div class="aq-outlined aq-mt">${f('client_note_hint', 'aq-outlined-input aq-note-input', 'textarea')}</div>
|
||
${err}
|
||
<div class="aq-btn-pill aq-btn-primary aq-mt">${f('save', 'aq-field-on-primary')}</div>
|
||
<div class="aq-btn-outline aq-note-cancel aq-mt">${f('cancel', 'aq-sm')}</div>
|
||
</div>
|
||
</div>`;
|
||
}
|
||
|
||
function homeHeaderChrome({ status = 'online', note = 'empty' } = {}) {
|
||
const statusChip = status === 'offline'
|
||
? `<div class="aq-status-chip offline">
|
||
<span class="aq-dot"></span>
|
||
${f('offline', 'aq-status-text')}
|
||
</div>`
|
||
: `<div class="aq-status-chip online">
|
||
<span class="aq-dot"></span>
|
||
${f('online', 'aq-status-text')}
|
||
</div>`;
|
||
const noteRow = note === 'none'
|
||
? ''
|
||
: clientNoteRow({
|
||
hasNote: note === 'filled' || note === 'pending',
|
||
pending: note === 'pending',
|
||
});
|
||
return `
|
||
<div class="aq-card aq-header-card">
|
||
<div class="aq-header-row">
|
||
<div class="aq-header-titles">
|
||
${f('hub_welcome_back', 'aq-muted aq-sm')}
|
||
<div class="aq-coach-name">demoCounselor</div>
|
||
</div>
|
||
${statusChip}
|
||
${iconHelp()}
|
||
${iconRefresh()}
|
||
</div>
|
||
<div class="aq-divider"></div>
|
||
<div class="aq-dual-chips">
|
||
<div class="aq-chip-col">
|
||
${f('language', 'aq-label-xs')}
|
||
<div class="aq-control-chip">Deutsch ${iconChevron()}</div>
|
||
</div>
|
||
<div class="aq-chip-col">
|
||
${f('active_client', 'aq-label-xs')}
|
||
<div class="aq-control-chip aq-control-chip-person">
|
||
<span class="aq-chip-lead">${iconPerson()}</span>
|
||
<span class="aq-chip-value">demoClient</span>
|
||
${iconChevron()}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
${noteRow}
|
||
</div>`;
|
||
}
|
||
|
||
function homeDock() {
|
||
const iconReview = `<svg class="aq-dock-icon" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/></svg>`;
|
||
const iconUpload = `<svg class="aq-dock-icon" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="16 16 12 12 8 16"/><line x1="12" y1="12" x2="12" y2="21"/><path d="M20.39 18.39A5 5 0 0018 9h-1.26A8 8 0 103 16.3"/></svg>`;
|
||
return `
|
||
<div class="aq-hub-dock">
|
||
<div class="aq-dock-btn review">${iconReview}${f('review_scores', 'aq-field-on-primary aq-xs')}</div>
|
||
<div class="aq-dock-btn upload">${iconUpload}${f('upload', 'aq-field-on-primary aq-xs')}</div>
|
||
</div>`;
|
||
}
|
||
|
||
function homeNextStep(titleKey, bodyKey, actionKey) {
|
||
return `
|
||
<div class="aq-next-step">
|
||
<div class="aq-eyebrow">${f('next_step_label', 'aq-eyebrow-field')}</div>
|
||
<div class="aq-next-step-body">
|
||
<div class="aq-next-step-copy">
|
||
${f(titleKey, 'aq-bold')}
|
||
${f(bodyKey, 'aq-muted aq-sm')}
|
||
</div>
|
||
${actionKey ? `<div class="aq-btn-pill aq-btn-primary aq-btn-compact">${f(actionKey, 'aq-field-on-primary aq-xs')}</div>` : ''}
|
||
</div>
|
||
</div>`;
|
||
}
|
||
|
||
/** In-group Ampelkategorie / Punkteprüfung badge (view_category_review_badge.xml). */
|
||
function categoryReviewBadge({ band = 'yellow' } = {}) {
|
||
const lamp = band === 'green'
|
||
? '<span class="lamp green"></span><span class="lamp off"></span><span class="lamp off"></span>'
|
||
: band === 'red'
|
||
? '<span class="lamp off"></span><span class="lamp off"></span><span class="lamp red"></span>'
|
||
: '<span class="lamp off"></span><span class="lamp yellow"></span><span class="lamp off"></span>';
|
||
return `
|
||
<div class="aq-category-review-badge">
|
||
<div class="aq-traffic aq-traffic-compact">${lamp}</div>
|
||
<div class="aq-category-review-copy">
|
||
${f('next_step_review_title', 'aq-category-review-title')}
|
||
${f('next_step_review_body', 'aq-category-review-body', 'textarea')}
|
||
</div>
|
||
</div>`;
|
||
}
|
||
|
||
/** Process-complete / Ampelkategorie panel (view_process_complete_panel.xml). */
|
||
function processCompleteBadge({
|
||
mode = 'complete',
|
||
showUpload = false,
|
||
} = {}) {
|
||
const review = mode === 'review';
|
||
const titleKey = review ? 'next_step_review_title' : 'process_complete_title';
|
||
const bodyKey = review ? 'next_step_review_body' : 'process_complete_hub_body';
|
||
const actionKey = review ? 'process_complete_set_category' : (
|
||
mode === 'edit' ? 'process_complete_edit_category' : 'process_complete_set_category'
|
||
);
|
||
const tone = review ? 'review' : 'complete';
|
||
const icon = review
|
||
? `<div class="aq-traffic aq-traffic-compact"><span class="lamp off"></span><span class="lamp yellow"></span><span class="lamp off"></span></div>`
|
||
: `<div class="aq-process-complete-icon-well" aria-hidden="true">✓</div>`;
|
||
const upload = showUpload
|
||
? `<div class="aq-btn-complete-outline aq-mt">${f('upload', 'aq-xs')}</div>`
|
||
: '';
|
||
return `
|
||
<div class="aq-process-complete aq-process-${tone}">
|
||
<div class="aq-process-complete-top">
|
||
${icon}
|
||
<div class="aq-process-complete-copy">
|
||
${f(titleKey, `aq-bold aq-process-complete-title`)}
|
||
${f(bodyKey, 'aq-sm aq-process-complete-body', 'textarea')}
|
||
</div>
|
||
</div>
|
||
<div class="aq-btn-complete aq-mt">${f(actionKey, 'aq-field-on-primary aq-xs')}</div>
|
||
${upload}
|
||
</div>`;
|
||
}
|
||
|
||
/** Save-only questionnaire footer (questionnaire_all_in_one has only btnSave, no previous). */
|
||
function qnFooter({ progressPct = 0, showProgress = true } = {}) {
|
||
const progress = showProgress
|
||
? `<div class="aq-progress-row">
|
||
${f('questionnaire_progress_answered', 'aq-muted aq-xs aq-progress-label-end')}
|
||
<div class="aq-progress-track"><div class="aq-progress-fill" style="width:${progressPct}%"></div></div>
|
||
</div>`
|
||
: '';
|
||
return `
|
||
<div class="aq-qn-footer">
|
||
${progress}
|
||
<div class="aq-btn-pill aq-btn-primary aq-mt">${f('save', 'aq-field-on-primary')}</div>
|
||
</div>`;
|
||
}
|
||
|
||
function helpShell(topicTitleKey, introKey, sections) {
|
||
const sectionHtml = sections.map((s, i) => `
|
||
<div class="aq-help-section${i ? ' aq-mt' : ''}">
|
||
<div class="aq-help-section-header">
|
||
<span class="aq-step">${i + 1}</span>
|
||
${f(s.titleKey, 'aq-bold aq-sm aq-help-section-title')}
|
||
</div>
|
||
<div class="aq-help-screenshot-box" aria-hidden="true"></div>
|
||
${f(s.bodyKey, 'aq-muted aq-xs aq-mt', 'textarea')}
|
||
</div>`).join('<div class="aq-divider aq-mt"></div>');
|
||
|
||
return `
|
||
<div class="aq-screen aq-help">
|
||
<div class="aq-toolbar">
|
||
<span class="aq-toolbar-back">‹</span>
|
||
${f('help_title', 'aq-screen-title')}
|
||
</div>
|
||
<div class="aq-help-body">
|
||
<div class="aq-card aq-picker-row">
|
||
${f('language', 'aq-muted aq-sm aq-picker-label')}
|
||
${langChip()}
|
||
</div>
|
||
<div class="aq-card aq-picker-row">
|
||
${f('help_topic', 'aq-muted aq-sm aq-picker-label')}
|
||
<div class="aq-control-chip">${f(topicTitleKey, 'aq-sm')} ${iconChevron()}</div>
|
||
</div>
|
||
<div class="aq-help-current">
|
||
<span class="aq-zone-pill">${f('help_this_page', 'aq-xs')}</span>
|
||
${f(topicTitleKey, 'aq-bold aq-mt')}
|
||
${f(introKey, 'aq-muted aq-sm', 'textarea')}
|
||
<div class="aq-divider"></div>
|
||
${sectionHtml}
|
||
</div>
|
||
</div>
|
||
</div>`;
|
||
}
|
||
|
||
function syncPhaseMock(statusKey, subtitleKey, progressPct, finished = false) {
|
||
const stage = finished
|
||
? `<div class="aq-sync-stage aq-sync-stage-done"><span class="aq-sync-check" aria-hidden="true">✓</span></div>`
|
||
: `<div class="aq-sync-stage"><div class="aq-sync-ring"></div></div>`;
|
||
// 7 checkpoint phases: preparing(10%), questionnaires(25%), client_info(40%), answers(55%), processing(70%), saving(85%), finished(100%)
|
||
const phases = [10, 25, 40, 55, 70, 85, 100];
|
||
const dots = phases.map(p => `<div class="aq-sync-dot${p <= progressPct ? ' done' : ''}"></div>`).join('');
|
||
return `
|
||
<div class="aq-screen aq-sync">
|
||
${f('sync_title', 'aq-muted aq-sync-title')}
|
||
${stage}
|
||
${f(statusKey, 'aq-sync-status')}
|
||
${f(subtitleKey, 'aq-muted aq-sm aq-sync-sub', 'textarea')}
|
||
<div class="aq-sync-bar"><div class="aq-sync-bar-fill" style="width:${progressPct}%"></div></div>
|
||
<div class="aq-sync-checkpoints" aria-hidden="true">${dots}</div>
|
||
</div>`;
|
||
}
|
||
|
||
/**
|
||
* Branded app dialog (dialog_app_message.xml).
|
||
* @param {'info'|'warning'|'logout'|'danger'} tone
|
||
*/
|
||
function dialogMock({
|
||
titleKey,
|
||
messageKey,
|
||
primaryKey,
|
||
secondaryKey = null,
|
||
detailsKeys = null,
|
||
tone = 'info',
|
||
}) {
|
||
const details = detailsKeys?.length
|
||
? `<div class="aq-dialog-details">${detailsKeys.map(k => f(k, 'aq-sm aq-dialog-detail-line')).join('')}</div>`
|
||
: '';
|
||
const secondary = secondaryKey
|
||
? `<div class="aq-btn-text">${f(secondaryKey, 'aq-muted')}</div>`
|
||
: '';
|
||
const primaryCls = tone === 'logout' || tone === 'danger'
|
||
? 'aq-btn-pill aq-btn-danger'
|
||
: 'aq-btn-pill aq-btn-primary';
|
||
return `
|
||
<div class="aq-screen aq-dialogs">
|
||
<div class="aq-dialog aq-dialog-${tone}">
|
||
<div class="aq-dialog-icon ${tone}" aria-hidden="true"></div>
|
||
${f(titleKey, 'aq-dialog-title')}
|
||
${f(messageKey, 'aq-muted aq-sm aq-dialog-msg', 'textarea')}
|
||
${details}
|
||
<div class="aq-dialog-actions-col">
|
||
<div class="${primaryCls}">${f(primaryKey, 'aq-field-on-primary')}</div>
|
||
${secondary}
|
||
</div>
|
||
</div>
|
||
</div>`;
|
||
}
|
||
|
||
function scoreCalculatedMock() {
|
||
return `
|
||
<div class="aq-screen aq-score-notice">
|
||
<div class="aq-score-hero">
|
||
<div class="aq-score-icon" aria-hidden="true">✓</div>
|
||
${f('score_calculated_eyebrow', 'aq-score-eyebrow')}
|
||
${f('score_calculated_title', 'aq-score-title')}
|
||
</div>
|
||
<div class="aq-score-body">
|
||
<div class="aq-card aq-score-card">
|
||
${f('score_calculated_result_label', 'aq-muted aq-xs')}
|
||
<div class="aq-bold aq-mt">RHS Index · 27.0</div>
|
||
<div class="aq-band mid aq-mt">${f('category_yellow', 'aq-xs')}</div>
|
||
${f('score_calculated_band_hint', 'aq-muted aq-xs aq-mt')}
|
||
</div>
|
||
<div class="aq-card aq-score-card">
|
||
${f('score_calculated_next_label', 'aq-muted aq-xs')}
|
||
${f('score_calculated_next_title', 'aq-bold aq-mt')}
|
||
${f('score_calculated_body', 'aq-muted aq-sm', 'textarea')}
|
||
</div>
|
||
<div class="aq-btn-pill aq-btn-primary">${f('score_calculated_continue', 'aq-field-on-primary')}</div>
|
||
</div>
|
||
</div>`;
|
||
}
|
||
|
||
/** @type {AppUiScreen[]} */
|
||
export const APP_UI_SCREENS = [
|
||
{
|
||
id: 'auth',
|
||
label: 'Anmeldung',
|
||
hint: 'activity_auth.xml',
|
||
keys: [
|
||
'auth_title', 'auth_subtitle_login', 'auth_subtitle_change_password',
|
||
'auth_footer_accounts', 'username_hint', 'password_hint', 'login_btn', 'exit_btn',
|
||
'new_password_hint', 'confirm_password_hint', 'save_password_btn',
|
||
'password_too_short', 'passwords_dont_match', 'please_username_password',
|
||
'password_needs_prefix', 'password_rule_min_length', 'password_rule_uppercase',
|
||
'password_rule_number', 'password_rule_special', 'login_failed_with_reason',
|
||
'language', 'help_title',
|
||
],
|
||
variants: [
|
||
{
|
||
id: 'login',
|
||
label: 'Login',
|
||
focusKeys: [
|
||
'auth_title', 'auth_subtitle_login', 'username_hint', 'password_hint',
|
||
'login_btn', 'exit_btn', 'auth_footer_accounts', 'language', 'help_title',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-auth">
|
||
<div class="aq-auth-top">
|
||
<div class="aq-logo-well" aria-hidden="true"></div>
|
||
<div class="aq-auth-top-right">${iconHelp()}${langChip()}</div>
|
||
</div>
|
||
${f('auth_title', 'aq-auth-title')}
|
||
${f('auth_subtitle_login', 'aq-muted aq-auth-sub')}
|
||
<div class="aq-card aq-card-header">
|
||
<div class="aq-outlined">
|
||
<span class="aq-outlined-icon">${iconPerson()}</span>
|
||
${f('username_hint', 'aq-outlined-input')}
|
||
</div>
|
||
<div class="aq-outlined">
|
||
<span class="aq-outlined-icon">${iconLock()}</span>
|
||
${f('password_hint', 'aq-outlined-input')}
|
||
</div>
|
||
<div class="aq-btn-pill aq-btn-primary">${f('login_btn', 'aq-field-on-primary')}</div>
|
||
<div class="aq-btn-text">${f('exit_btn', 'aq-muted')}</div>
|
||
</div>
|
||
<div class="aq-auth-footer">${f('auth_footer_accounts', 'aq-muted aq-sm')}</div>
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'login_error',
|
||
label: 'Login Fehler',
|
||
focusKeys: [
|
||
'please_username_password', 'login_failed_with_reason',
|
||
'username_hint', 'password_hint', 'login_btn', 'exit_btn',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-auth">
|
||
<div class="aq-auth-top">
|
||
<div class="aq-logo-well" aria-hidden="true"></div>
|
||
<div class="aq-auth-top-right">${iconHelp()}${langChip()}</div>
|
||
</div>
|
||
${f('auth_title', 'aq-auth-title')}
|
||
${f('auth_subtitle_login', 'aq-muted aq-auth-sub')}
|
||
<div class="aq-card aq-card-header">
|
||
<div class="aq-outlined">
|
||
<span class="aq-outlined-icon">${iconPerson()}</span>
|
||
${f('username_hint', 'aq-outlined-input')}
|
||
</div>
|
||
<div class="aq-outlined">
|
||
<span class="aq-outlined-icon">${iconLock()}</span>
|
||
${f('password_hint', 'aq-outlined-input')}
|
||
</div>
|
||
<div class="aq-btn-pill aq-btn-primary">${f('login_btn', 'aq-field-on-primary')}</div>
|
||
<div class="aq-btn-text">${f('exit_btn', 'aq-muted')}</div>
|
||
</div>
|
||
<div class="aq-auth-footer">${f('auth_footer_accounts', 'aq-muted aq-sm')}</div>
|
||
${toastBanner('please_username_password')}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'login_failed',
|
||
label: 'Login fehlgeschlagen',
|
||
focusKeys: ['login_failed_with_reason', 'username_hint', 'password_hint', 'login_btn'],
|
||
mock: () => `
|
||
<div class="aq-screen aq-auth">
|
||
<div class="aq-auth-top">
|
||
<div class="aq-logo-well" aria-hidden="true"></div>
|
||
<div class="aq-auth-top-right">${iconHelp()}${langChip()}</div>
|
||
</div>
|
||
${f('auth_title', 'aq-auth-title')}
|
||
${f('auth_subtitle_login', 'aq-muted aq-auth-sub')}
|
||
<div class="aq-card aq-card-header">
|
||
<div class="aq-outlined">
|
||
<span class="aq-outlined-icon">${iconPerson()}</span>
|
||
${f('username_hint', 'aq-outlined-input')}
|
||
</div>
|
||
<div class="aq-outlined">
|
||
<span class="aq-outlined-icon">${iconLock()}</span>
|
||
${f('password_hint', 'aq-outlined-input')}
|
||
</div>
|
||
<div class="aq-btn-pill aq-btn-primary">${f('login_btn', 'aq-field-on-primary')}</div>
|
||
<div class="aq-btn-text">${f('exit_btn', 'aq-muted')}</div>
|
||
</div>
|
||
<div class="aq-auth-footer">${f('auth_footer_accounts', 'aq-muted aq-sm')}</div>
|
||
${toastBanner('login_failed_with_reason')}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'password',
|
||
label: 'Passwort ändern',
|
||
focusKeys: [
|
||
'auth_title', 'auth_subtitle_change_password', 'new_password_hint',
|
||
'confirm_password_hint', 'save_password_btn', 'auth_footer_accounts',
|
||
'password_needs_prefix', 'password_rule_min_length', 'password_rule_uppercase',
|
||
'password_rule_number', 'password_rule_special',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-auth">
|
||
<div class="aq-auth-top">
|
||
<div class="aq-logo-well" aria-hidden="true"></div>
|
||
<div class="aq-auth-top-right">${iconHelp()}${langChip()}</div>
|
||
</div>
|
||
${f('auth_title', 'aq-auth-title')}
|
||
${f('auth_subtitle_change_password', 'aq-muted aq-auth-sub')}
|
||
<div class="aq-card aq-card-header">
|
||
<div class="aq-outlined">
|
||
<span class="aq-outlined-icon">${iconLock()}</span>
|
||
${f('new_password_hint', 'aq-outlined-input')}
|
||
</div>
|
||
<div class="aq-pw-reqs">
|
||
${f('password_needs_prefix', 'aq-xs')}
|
||
${f('password_rule_min_length', 'aq-xs')}
|
||
${f('password_rule_uppercase', 'aq-xs')}
|
||
${f('password_rule_number', 'aq-xs')}
|
||
${f('password_rule_special', 'aq-xs')}
|
||
</div>
|
||
<div class="aq-outlined">
|
||
<span class="aq-outlined-icon">${iconLock()}</span>
|
||
${f('confirm_password_hint', 'aq-outlined-input')}
|
||
</div>
|
||
<div class="aq-btn-pill aq-btn-primary">${f('save_password_btn', 'aq-field-on-primary')}</div>
|
||
</div>
|
||
<div class="aq-auth-footer">${f('auth_footer_accounts', 'aq-muted aq-sm')}</div>
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'password_error',
|
||
label: 'Passwort Fehler',
|
||
focusKeys: ['password_too_short', 'passwords_dont_match', 'new_password_hint', 'confirm_password_hint'],
|
||
mock: () => `
|
||
<div class="aq-screen aq-auth">
|
||
<div class="aq-auth-top">
|
||
<div class="aq-logo-well" aria-hidden="true"></div>
|
||
<div class="aq-auth-top-right">${iconHelp()}${langChip()}</div>
|
||
</div>
|
||
${f('auth_title', 'aq-auth-title')}
|
||
${f('auth_subtitle_change_password', 'aq-muted aq-auth-sub')}
|
||
<div class="aq-card aq-card-header">
|
||
<div class="aq-outlined">
|
||
<span class="aq-outlined-icon">${iconLock()}</span>
|
||
${f('new_password_hint', 'aq-outlined-input')}
|
||
</div>
|
||
<div class="aq-pw-reqs">
|
||
${f('password_needs_prefix', 'aq-xs')}
|
||
${f('password_rule_min_length', 'aq-xs')}
|
||
${f('password_rule_uppercase', 'aq-xs')}
|
||
${f('password_rule_number', 'aq-xs')}
|
||
${f('password_rule_special', 'aq-xs')}
|
||
</div>
|
||
<div class="aq-outlined">
|
||
<span class="aq-outlined-icon">${iconLock()}</span>
|
||
${f('confirm_password_hint', 'aq-outlined-input')}
|
||
</div>
|
||
<div class="aq-btn-pill aq-btn-primary">${f('save_password_btn', 'aq-field-on-primary')}</div>
|
||
</div>
|
||
<div class="aq-auth-footer">${f('auth_footer_accounts', 'aq-muted aq-sm')}</div>
|
||
${toastBanner('password_too_short')}
|
||
</div>`,
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'home',
|
||
label: 'Startseite',
|
||
hint: 'opening_screen.xml + hub dock',
|
||
keys: [
|
||
'hub_welcome_back', 'language', 'active_client', 'online', 'offline',
|
||
'settings', 'logout', 'next_step_label', 'next_step_questionnaire_title',
|
||
'next_step_questionnaire_body', 'next_step_review_title', 'next_step_review_body',
|
||
'next_step_upload_title', 'next_step_upload_body', 'next_step_completed_title',
|
||
'next_step_completed_body', 'next_step_loading_title', 'next_step_loading_body',
|
||
'next_step_show_questionnaire', 'questionnaire_title', 'start', 'locked',
|
||
'questionnaire_chip_edit', 'questionnaire_chip_edit_pending',
|
||
'process_complete_title', 'process_complete_set_category', 'process_complete_edit_category',
|
||
'upload', 'review_scores', 'refresh_complete',
|
||
'help_title', 'client_note_for_client', 'client_note_add', 'client_note_edit',
|
||
'client_note_add_action', 'client_note_pending', 'process_complete_hub_body',
|
||
'questionnaire_unlock_2_rhs', 'questionnaire_unlock_3_integration_index',
|
||
'questionnaire_unlock_4_consultation_results', 'consultation_unlock_requires_rhs',
|
||
'review_required_before_continue', 'download_failed_use_offline', 'no_profile',
|
||
'cancel', 'save', 'client_note_title', 'client_note_hint', 'client_note_too_long',
|
||
'client_note_saved', 'client_note_saved_pending',
|
||
],
|
||
variants: [
|
||
{
|
||
id: 'questionnaire',
|
||
label: 'Nächster Fragebogen',
|
||
focusKeys: [
|
||
'hub_welcome_back', 'language', 'active_client', 'online', 'next_step_label',
|
||
'next_step_questionnaire_title', 'next_step_questionnaire_body',
|
||
'next_step_show_questionnaire', 'questionnaire_title', 'start', 'locked',
|
||
'questionnaire_unlock_2_rhs', 'questionnaire_unlock_3_integration_index',
|
||
'consultation_unlock_requires_rhs', 'review_scores', 'upload',
|
||
'client_note_for_client', 'client_note_add', 'client_note_add_action',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-home">
|
||
<div class="aq-home-scroll">
|
||
${homeHeaderChrome()}
|
||
${homeNextStep('next_step_questionnaire_title', 'next_step_questionnaire_body', 'next_step_show_questionnaire')}
|
||
<div class="aq-section-title">${f('questionnaire_title', 'aq-section-title-field')}</div>
|
||
<div class="aq-qn-card open">
|
||
<span class="aq-qn-name">Demografie</span>
|
||
<span class="aq-chip-start">${f('start', 'aq-chip-field')}</span>
|
||
</div>
|
||
<div class="aq-qn-card locked">
|
||
<div>
|
||
<div class="aq-qn-name">RHS</div>
|
||
${f('questionnaire_unlock_2_rhs', 'aq-qn-lock-hint')}
|
||
</div>
|
||
<span class="aq-chip-locked">${f('locked', 'aq-chip-field')}</span>
|
||
</div>
|
||
<div class="aq-qn-card locked">
|
||
<div>
|
||
<div class="aq-qn-name">Integrationsindex</div>
|
||
${f('questionnaire_unlock_3_integration_index', 'aq-qn-lock-hint')}
|
||
</div>
|
||
<span class="aq-chip-locked">${f('locked', 'aq-chip-field')}</span>
|
||
</div>
|
||
<div class="aq-qn-card locked">
|
||
<div>
|
||
<div class="aq-qn-name">Beratung</div>
|
||
${f('consultation_unlock_requires_rhs', 'aq-qn-lock-hint')}
|
||
</div>
|
||
<span class="aq-chip-locked">${f('locked', 'aq-chip-field')}</span>
|
||
</div>
|
||
</div>
|
||
${homeDock()}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'review',
|
||
label: 'Ampelkategorie',
|
||
focusKeys: [
|
||
'next_step_label', 'next_step_review_title', 'next_step_review_body',
|
||
'process_complete_set_category', 'review_scores', 'upload',
|
||
'questionnaire_chip_edit', 'questionnaire_title',
|
||
'review_required_before_continue',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-home">
|
||
<div class="aq-home-scroll">
|
||
${homeHeaderChrome({ note: 'filled' })}
|
||
${homeNextStep('next_step_review_title', 'next_step_review_body', 'process_complete_set_category')}
|
||
<div class="aq-section-title">${f('questionnaire_title', 'aq-section-title-field')}</div>
|
||
<div class="aq-qn-group">
|
||
<div class="aq-qn-card open">
|
||
<span class="aq-qn-name">Demografie</span>
|
||
<span class="aq-chip-edit">${f('questionnaire_chip_edit', 'aq-chip-field')}</span>
|
||
</div>
|
||
<div class="aq-qn-card open">
|
||
<span class="aq-qn-name">RHS</span>
|
||
<span class="aq-chip-edit">${f('questionnaire_chip_edit', 'aq-chip-field')}</span>
|
||
</div>
|
||
${categoryReviewBadge({ band: 'yellow' })}
|
||
</div>
|
||
</div>
|
||
${homeDock()}
|
||
${toastBanner('review_required_before_continue')}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'upload',
|
||
label: 'Upload bereit',
|
||
focusKeys: [
|
||
'next_step_label', 'next_step_upload_title', 'next_step_upload_body',
|
||
'upload', 'review_scores', 'questionnaire_chip_edit_pending',
|
||
'client_note_pending', 'client_note_edit',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-home">
|
||
<div class="aq-home-scroll">
|
||
${homeHeaderChrome({ note: 'pending' })}
|
||
${homeNextStep('next_step_upload_title', 'next_step_upload_body', 'upload')}
|
||
<div class="aq-section-title">${f('questionnaire_title', 'aq-section-title-field')}</div>
|
||
<div class="aq-qn-card open">
|
||
<span class="aq-qn-name">Demografie</span>
|
||
<span class="aq-chip-edit-pending">${f('questionnaire_chip_edit_pending', 'aq-chip-field')}</span>
|
||
</div>
|
||
</div>
|
||
${homeDock()}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'complete',
|
||
label: 'Abgeschlossen',
|
||
focusKeys: [
|
||
'process_complete_title', 'process_complete_hub_body',
|
||
'process_complete_set_category', 'upload',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-home">
|
||
<div class="aq-home-scroll">
|
||
${homeHeaderChrome()}
|
||
${processCompleteBadge({ mode: 'complete', showUpload: true })}
|
||
</div>
|
||
${homeDock()}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'complete_edit',
|
||
label: 'Abgeschlossen · Kategorie',
|
||
focusKeys: [
|
||
'process_complete_title', 'process_complete_hub_body',
|
||
'process_complete_edit_category',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-home">
|
||
<div class="aq-home-scroll">
|
||
${homeHeaderChrome()}
|
||
${processCompleteBadge({ mode: 'edit' })}
|
||
</div>
|
||
${homeDock()}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'set_category',
|
||
label: 'Ampelkategorie setzen',
|
||
focusKeys: [
|
||
'next_step_review_title', 'next_step_review_body',
|
||
'process_complete_set_category',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-home">
|
||
<div class="aq-home-scroll">
|
||
${homeHeaderChrome()}
|
||
${processCompleteBadge({ mode: 'review' })}
|
||
</div>
|
||
${homeDock()}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'completed_banner',
|
||
label: 'Nächster Schritt · Fertig',
|
||
focusKeys: [
|
||
'next_step_label', 'next_step_completed_title', 'next_step_completed_body',
|
||
'review_scores', 'upload', 'questionnaire_chip_edit',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-home">
|
||
<div class="aq-home-scroll">
|
||
${homeHeaderChrome()}
|
||
${homeNextStep('next_step_completed_title', 'next_step_completed_body', null)}
|
||
<div class="aq-section-title">${f('questionnaire_title', 'aq-section-title-field')}</div>
|
||
<div class="aq-qn-card open">
|
||
<span class="aq-qn-name">Demografie</span>
|
||
<span class="aq-chip-edit">${f('questionnaire_chip_edit', 'aq-chip-field')}</span>
|
||
</div>
|
||
</div>
|
||
${homeDock()}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'loading',
|
||
label: 'Laden',
|
||
focusKeys: [
|
||
'next_step_loading_title', 'next_step_loading_body', 'next_step_label',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-home">
|
||
<div class="aq-home-scroll">
|
||
${homeHeaderChrome()}
|
||
<div class="aq-next-step">
|
||
<div class="aq-eyebrow">${f('next_step_label', 'aq-eyebrow-field')}</div>
|
||
<div class="aq-next-step-body">
|
||
<div class="aq-next-step-copy">
|
||
${f('next_step_loading_title', 'aq-bold')}
|
||
${f('next_step_loading_body', 'aq-muted aq-sm')}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
${homeDock()}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'offline',
|
||
label: 'Offline',
|
||
focusKeys: [
|
||
'offline', 'hub_welcome_back', 'active_client', 'download_failed_use_offline',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-home">
|
||
<div class="aq-home-scroll">
|
||
${homeHeaderChrome({ status: 'offline' })}
|
||
${homeNextStep('next_step_questionnaire_title', 'next_step_questionnaire_body', 'next_step_show_questionnaire')}
|
||
</div>
|
||
${homeDock()}
|
||
${toastBanner('download_failed_use_offline')}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'settings',
|
||
label: 'Einstellungen',
|
||
focusKeys: ['settings', 'logout'],
|
||
mock: () => `
|
||
<div class="aq-screen aq-home">
|
||
<div class="aq-home-scroll">
|
||
${homeHeaderChrome()}
|
||
${homeNextStep('next_step_questionnaire_title', 'next_step_questionnaire_body', 'next_step_show_questionnaire')}
|
||
</div>
|
||
${homeDock()}
|
||
${settingsSheet()}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'refresh_done',
|
||
label: 'Aktualisiert',
|
||
focusKeys: ['refresh_complete'],
|
||
mock: () => `
|
||
<div class="aq-screen aq-home">
|
||
<div class="aq-home-scroll">
|
||
${homeHeaderChrome()}
|
||
${homeNextStep('next_step_questionnaire_title', 'next_step_questionnaire_body', 'next_step_show_questionnaire')}
|
||
</div>
|
||
${homeDock()}
|
||
${toastBanner('refresh_complete')}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'note_editor',
|
||
label: 'Notiz bearbeiten',
|
||
focusKeys: [
|
||
'client_note_title', 'client_note_for_client', 'client_note_hint',
|
||
'client_note_too_long', 'cancel', 'save',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-home">
|
||
<div class="aq-home-scroll">
|
||
${homeHeaderChrome({ note: 'filled' })}
|
||
${homeNextStep('next_step_questionnaire_title', 'next_step_questionnaire_body', 'next_step_show_questionnaire')}
|
||
</div>
|
||
${homeDock()}
|
||
${clientNoteEditorSheet({ errorKey: 'client_note_too_long' })}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'note_saved',
|
||
label: 'Notiz gespeichert',
|
||
focusKeys: [
|
||
'client_note_saved', 'client_note_saved_pending',
|
||
'client_note_for_client', 'client_note_edit', 'client_note_pending',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-home">
|
||
<div class="aq-home-scroll">
|
||
${homeHeaderChrome({ note: 'pending' })}
|
||
${homeNextStep('next_step_questionnaire_title', 'next_step_questionnaire_body', 'next_step_show_questionnaire')}
|
||
</div>
|
||
${homeDock()}
|
||
${toastBanner('client_note_saved_pending')}
|
||
</div>`,
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'client',
|
||
label: 'Klient wählen',
|
||
hint: 'view_client_select_gate.xml',
|
||
keys: [
|
||
'client_select_gate_title', 'client_select_gate_body', 'client_select_gate_hint',
|
||
'client_select_gate_count', 'client_picker_title', 'client_picker_subtitle',
|
||
'client_picker_search', 'client_picker_current', 'client_picker_recent',
|
||
'client_picker_all', 'client_picker_empty', 'client_picker_status_finished',
|
||
'client_picker_status_started', 'client_picker_status_new',
|
||
'client_picker_status_finished_pending_upload', 'client_picker_status_pending_upload',
|
||
'client_picker_status_next_step_category', 'client_picker_status_next',
|
||
'client_picker_category_assigned', 'client_picker_category_calculated',
|
||
'client_picker_score', 'client_picker_loading_title', 'client_picker_loading_body',
|
||
'active_client', 'language', 'no_clients_assigned', 'client', 'client_note',
|
||
],
|
||
variants: [
|
||
{
|
||
id: 'gate',
|
||
label: 'Gate',
|
||
focusKeys: [
|
||
'client_select_gate_title', 'client_select_gate_body', 'client_select_gate_hint',
|
||
'client_select_gate_count', 'client_picker_search', 'language',
|
||
'client_picker_status_finished', 'client_picker_status_started',
|
||
'client_picker_status_new',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-client-gate">
|
||
<div class="aq-card aq-header-card">
|
||
<div class="aq-gate-title-row">
|
||
<div class="aq-avatar-well">${iconPerson()}</div>
|
||
${f('client_select_gate_title', 'aq-screen-title')}
|
||
</div>
|
||
${f('client_select_gate_body', 'aq-body')}
|
||
${f('client_select_gate_hint', 'aq-muted aq-sm')}
|
||
${f('client_select_gate_count', 'aq-count')}
|
||
${f('language', 'aq-label-xs')}
|
||
<div class="aq-control-chip">Deutsch ${iconChevron()}</div>
|
||
</div>
|
||
<div class="aq-outlined aq-search">
|
||
<span class="aq-outlined-icon">${iconPerson()}</span>
|
||
${f('client_picker_search', 'aq-outlined-input')}
|
||
</div>
|
||
<div class="aq-client-card">
|
||
<div class="aq-client-stripe"></div>
|
||
<div class="aq-client-card-body">
|
||
<div class="aq-client-card-top">
|
||
<div class="aq-avatar-sm">${iconPerson()}</div>
|
||
<strong>demoClient</strong>
|
||
<span class="aq-badge-done">${f('client_picker_status_finished', 'aq-xs')}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="aq-client-card">
|
||
<div class="aq-client-stripe"></div>
|
||
<div class="aq-client-card-body">
|
||
<div class="aq-client-card-top">
|
||
<div class="aq-avatar-sm">${iconPerson()}</div>
|
||
<strong>demoClient2</strong>
|
||
</div>
|
||
<div class="aq-muted aq-xs">${f('client_picker_status_new', 'aq-xs')}</div>
|
||
</div>
|
||
</div>
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'list',
|
||
label: 'Liste',
|
||
focusKeys: [
|
||
'client_picker_title', 'client_picker_subtitle', 'client_picker_recent',
|
||
'client_picker_all', 'client_picker_current', 'client_picker_score',
|
||
'client_picker_category_assigned', 'client_picker_category_calculated',
|
||
'client_picker_status_finished_pending_upload', 'client_picker_status_pending_upload',
|
||
'client_picker_status_next_step_category', 'client_picker_status_next',
|
||
'client', 'client_picker_search',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-client-gate">
|
||
<div class="aq-card aq-header-card">
|
||
${f('client_picker_title', 'aq-screen-title')}
|
||
${f('client_picker_subtitle', 'aq-muted aq-sm')}
|
||
<div class="aq-outlined aq-search aq-mt">
|
||
<span class="aq-outlined-icon">${iconPerson()}</span>
|
||
${f('client_picker_search', 'aq-outlined-input')}
|
||
</div>
|
||
</div>
|
||
<div class="aq-label-xs aq-mt">${f('client_picker_current', 'aq-label-xs')}</div>
|
||
<div class="aq-client-card">
|
||
<div class="aq-client-stripe"></div>
|
||
<div class="aq-client-card-body">
|
||
<div class="aq-client-card-top">
|
||
<div class="aq-avatar-sm">${iconPerson()}</div>
|
||
<strong>${f('client', 'aq-xs')} demoA</strong>
|
||
</div>
|
||
<div class="aq-muted aq-xs">${f('client_picker_status_next', 'aq-xs')}</div>
|
||
<div class="aq-muted aq-xs">${f('client_picker_score', 'aq-xs')}: 27.0</div>
|
||
<div class="aq-muted aq-xs">${f('client_picker_category_calculated', 'aq-xs')}</div>
|
||
</div>
|
||
</div>
|
||
<div class="aq-label-xs aq-mt">${f('client_picker_recent', 'aq-label-xs')}</div>
|
||
<div class="aq-label-xs">${f('client_picker_all', 'aq-label-xs')}</div>
|
||
<div class="aq-client-card">
|
||
<div class="aq-client-stripe"></div>
|
||
<div class="aq-client-card-body">
|
||
<div class="aq-client-card-top">
|
||
<div class="aq-avatar-sm">${iconPerson()}</div>
|
||
<strong>demoB</strong>
|
||
<span class="aq-badge-done">${f('client_picker_status_pending_upload', 'aq-xs')}</span>
|
||
</div>
|
||
<div class="aq-muted aq-xs">${f('client_picker_status_finished_pending_upload', 'aq-xs')}</div>
|
||
<div class="aq-muted aq-xs">${f('client_picker_status_next_step_category', 'aq-xs')}</div>
|
||
<div class="aq-muted aq-xs">${f('client_picker_category_assigned', 'aq-xs')}</div>
|
||
</div>
|
||
</div>
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'loading',
|
||
label: 'Laden',
|
||
focusKeys: ['client_picker_loading_title', 'client_picker_loading_body'],
|
||
mock: () => `
|
||
<div class="aq-screen aq-client-gate">
|
||
<div class="aq-card aq-header-card">
|
||
${f('client_picker_loading_title', 'aq-screen-title')}
|
||
${f('client_picker_loading_body', 'aq-muted aq-sm', 'textarea')}
|
||
</div>
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'empty',
|
||
label: 'Leer',
|
||
focusKeys: ['client_picker_empty', 'no_clients_assigned'],
|
||
mock: () => `
|
||
<div class="aq-screen aq-client-gate">
|
||
<div class="aq-card aq-header-card">
|
||
${f('client_picker_title', 'aq-screen-title')}
|
||
${f('client_picker_empty', 'aq-muted aq-sm', 'textarea')}
|
||
${f('no_clients_assigned', 'aq-muted aq-sm aq-mt', 'textarea')}
|
||
</div>
|
||
</div>`,
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'questionnaire',
|
||
label: 'Fragebogen',
|
||
hint: 'questionnaire_all_in_one.xml · pick a question type',
|
||
keys: [
|
||
'coach_code', 'client_code', 'client_note_for_client', 'client_note_add',
|
||
'client_note_edit', 'client_note_add_action', 'client_note_pending',
|
||
'client_note_title', 'client_note_hint', 'client_note_too_long', 'cancel',
|
||
'save', 'previous', 'choose_answer', 'fill_all_fields', 'select_one_answer',
|
||
'select_one_answer_per_row', 'choose_more_elements', 'questionnaire_progress_answered',
|
||
'no_questions_available', 'questionnaire_missing_options', 'help_title', 'language',
|
||
'please_client_code', 'fill_both_fields', 'client_code_exists', 'no_profile',
|
||
'other_option', 'other_country', 'january', 'february', 'march', 'april', 'may',
|
||
'june', 'july', 'august', 'september', 'october', 'november', 'december',
|
||
],
|
||
variants: [
|
||
{
|
||
id: 'codes',
|
||
label: 'Codes',
|
||
focusKeys: [
|
||
'client_code', 'coach_code', 'please_client_code', 'fill_both_fields',
|
||
'client_code_exists', 'no_profile', 'previous', 'save',
|
||
'questionnaire_progress_answered', 'client_note_for_client',
|
||
'client_note_add', 'client_note_add_action',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-qn">
|
||
<div class="aq-qn-top">
|
||
${iconBack()}
|
||
<div class="aq-qn-top-right">${iconHelp()}${langChip()}</div>
|
||
</div>
|
||
<div class="aq-note-inset">${clientNoteRow()}</div>
|
||
<div class="aq-qn-scroll">
|
||
<div class="aq-card aq-q-card">
|
||
<div class="aq-muted aq-sm">${f('client_code', 'aq-sm')}</div>
|
||
<div class="aq-outlined aq-mt"><span class="aq-sample">demoClient</span></div>
|
||
<div class="aq-muted aq-sm aq-mt">${f('coach_code', 'aq-sm')}</div>
|
||
<div class="aq-outlined aq-mt"><span class="aq-sample">demoCounselor</span> ${iconLock()}</div>
|
||
</div>
|
||
</div>
|
||
${qnFooter({ progressPct: 5 })}
|
||
${toastBanner('fill_both_fields')}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'choice',
|
||
label: 'Auswahl',
|
||
focusKeys: [
|
||
'choose_answer', 'other_option', 'other_country', 'select_one_answer',
|
||
'choose_more_elements', 'previous', 'save', 'questionnaire_progress_answered',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-qn">
|
||
<div class="aq-qn-top">
|
||
${iconBack()}
|
||
<div class="aq-qn-top-right">${iconHelp()}${langChip()}</div>
|
||
</div>
|
||
<div class="aq-qn-scroll">
|
||
<div class="aq-card aq-q-card">
|
||
<div class="aq-bold aq-sm">Beispiel-Fragetext</div>
|
||
<div class="aq-option-row aq-mt"><span class="aq-radio"></span> Option A</div>
|
||
<div class="aq-option-row"><span class="aq-radio"></span> ${f('other_option', 'aq-sm')}</div>
|
||
<div class="aq-option-row"><span class="aq-radio"></span> ${f('other_country', 'aq-sm')}</div>
|
||
<div class="aq-spinner-prompt aq-mt">${f('choose_answer', 'aq-sm')}</div>
|
||
</div>
|
||
</div>
|
||
${qnFooter({ progressPct: 35 })}
|
||
${toastBanner('select_one_answer')}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'multi',
|
||
label: 'Mehrfachauswahl',
|
||
focusKeys: [
|
||
'choose_more_elements', 'other_option', 'previous', 'save',
|
||
'questionnaire_progress_answered',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-qn">
|
||
<div class="aq-qn-top">
|
||
${iconBack()}
|
||
<div class="aq-qn-top-right">${iconHelp()}${langChip()}</div>
|
||
</div>
|
||
<div class="aq-qn-scroll">
|
||
<div class="aq-card aq-q-card">
|
||
<div class="aq-bold aq-sm">Beispiel-Mehrfachauswahl</div>
|
||
<div class="aq-option-row aq-mt"><span class="aq-check">☑</span> Option A</div>
|
||
<div class="aq-option-row"><span class="aq-check">☐</span> ${f('other_option', 'aq-sm')}</div>
|
||
</div>
|
||
</div>
|
||
${qnFooter({ progressPct: 40 })}
|
||
${toastBanner('choose_more_elements')}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'date',
|
||
label: 'Datum',
|
||
focusKeys: [
|
||
'choose_answer', 'january', 'february', 'march', 'april', 'may', 'june',
|
||
'july', 'august', 'september', 'october', 'november', 'december',
|
||
'fill_all_fields', 'previous', 'save',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-qn">
|
||
<div class="aq-qn-top">
|
||
${iconBack()}
|
||
<div class="aq-qn-top-right">${iconHelp()}${langChip()}</div>
|
||
</div>
|
||
<div class="aq-qn-scroll">
|
||
<div class="aq-card aq-q-card">
|
||
<div class="aq-bold aq-sm">Beispiel-Datumsfrage</div>
|
||
<div class="aq-date-spinners aq-mt">
|
||
<div class="aq-date-col">
|
||
<div class="aq-spinner-field">15</div>
|
||
</div>
|
||
<div class="aq-date-col aq-date-col-open">
|
||
<div class="aq-spinner-field">${f('march', 'aq-sm')}</div>
|
||
<div class="aq-spinner-dropdown">
|
||
${f('january', 'aq-xs')}
|
||
${f('february', 'aq-xs')}
|
||
${f('march', 'aq-xs')}
|
||
${f('april', 'aq-xs')}
|
||
${f('may', 'aq-xs')}
|
||
${f('june', 'aq-xs')}
|
||
${f('july', 'aq-xs')}
|
||
${f('august', 'aq-xs')}
|
||
${f('september', 'aq-xs')}
|
||
${f('october', 'aq-xs')}
|
||
${f('november', 'aq-xs')}
|
||
${f('december', 'aq-xs')}
|
||
</div>
|
||
</div>
|
||
<div class="aq-date-col">
|
||
<div class="aq-spinner-field">${f('choose_answer', 'aq-xs')}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
${qnFooter({ progressPct: 0, showProgress: false })}
|
||
${toastBanner('fill_all_fields')}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'empty',
|
||
label: 'Leer / Fehler',
|
||
focusKeys: [
|
||
'no_questions_available', 'questionnaire_missing_options', 'previous',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-qn">
|
||
<div class="aq-qn-top">
|
||
${iconBack()}
|
||
<div class="aq-qn-top-right">${iconHelp()}${langChip()}</div>
|
||
</div>
|
||
<div class="aq-qn-scroll">
|
||
<div class="aq-card aq-q-card">
|
||
${f('no_questions_available', 'aq-muted aq-sm', 'textarea')}
|
||
</div>
|
||
</div>
|
||
${qnFooter({ progressPct: 0, showProgress: false })}
|
||
${toastBanner('questionnaire_missing_options')}
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'note',
|
||
label: 'Notiz',
|
||
focusKeys: [
|
||
'client_note_title', 'client_note_for_client', 'client_note_hint',
|
||
'client_note_too_long', 'cancel', 'save', 'client_note_edit',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-qn">
|
||
<div class="aq-qn-top">
|
||
${iconBack()}
|
||
<div class="aq-qn-top-right">${iconHelp()}${langChip()}</div>
|
||
</div>
|
||
<div class="aq-note-inset">${clientNoteRow({ hasNote: true })}</div>
|
||
<div class="aq-qn-scroll">
|
||
<div class="aq-card aq-q-card">
|
||
<div class="aq-bold aq-sm">Beispiel-Fragetext</div>
|
||
</div>
|
||
</div>
|
||
${clientNoteEditorSheet({ errorKey: 'client_note_too_long' })}
|
||
</div>`,
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'review',
|
||
label: 'Ampelkategorie',
|
||
hint: 'review_scores_screen.xml',
|
||
keys: [
|
||
'review_scores', 'review_scores_subtitle', 'review_scores_agree',
|
||
'review_scores_calculated_category', 'review_scores_coach_category',
|
||
'review_scores_empty', 'review_scores_pending_upload', 'review_scores_complete_title',
|
||
'review_scores_complete_body', 'review_scores_complete_body_uploaded',
|
||
'review_scores_done', 'review_scores_save_failed', 'review_scores_saved',
|
||
'review_scores_saved_pending', 'review_scores_set_category',
|
||
'review_scores_supervisor_notice', 'review_scores_supervisor_confirm_title',
|
||
'review_scores_supervisor_confirm_body', 'review_scores_supervisor_confirm_action',
|
||
'review_scores_total', 'category_green', 'category_yellow', 'category_red',
|
||
'score_calculated_title', 'score_calculated_body', 'score_calculated_eyebrow',
|
||
'score_calculated_result_label', 'score_calculated_next_label',
|
||
'score_calculated_next_title', 'score_calculated_band_hint', 'score_calculated_continue',
|
||
'points', 'help_title', 'not_done', 'previous',
|
||
],
|
||
variants: [
|
||
{
|
||
id: 'active',
|
||
label: 'Aktiv',
|
||
focusKeys: [
|
||
'review_scores', 'review_scores_subtitle', 'review_scores_agree',
|
||
'review_scores_calculated_category', 'review_scores_coach_category',
|
||
'review_scores_total', 'review_scores_set_category', 'category_green',
|
||
'category_yellow', 'category_red', 'not_done', 'points', 'previous',
|
||
'review_scores_supervisor_notice',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-review">
|
||
<div class="aq-review-header">
|
||
<div>
|
||
${f('review_scores', 'aq-screen-title')}
|
||
${f('review_scores_subtitle', 'aq-muted aq-sm')}
|
||
</div>
|
||
<div class="aq-review-header-actions">${langChip()}${iconHelp()}</div>
|
||
</div>
|
||
<div class="aq-supervisor-notice">${f('review_scores_supervisor_notice', 'aq-sm')}</div>
|
||
<div class="aq-card aq-profile-card">
|
||
<div class="aq-profile-top">
|
||
<div class="aq-traffic">
|
||
<span class="lamp off"></span>
|
||
<span class="lamp yellow"></span>
|
||
<span class="lamp off"></span>
|
||
</div>
|
||
<div>
|
||
<div class="aq-bold">RHS Index</div>
|
||
<div class="aq-muted aq-sm">${f('review_scores_total', 'aq-xs')}: 27.0 ${f('points', 'aq-xs')}</div>
|
||
</div>
|
||
</div>
|
||
<div class="aq-band-row">
|
||
<span class="aq-muted aq-xs">${f('review_scores_calculated_category', 'aq-xs')}</span>
|
||
<span class="aq-band mid">${f('category_yellow', 'aq-xs')}</span>
|
||
</div>
|
||
<div class="aq-band-row">
|
||
<span class="aq-muted aq-xs">${f('review_scores_coach_category', 'aq-xs')}</span>
|
||
<span class="aq-band none">${f('not_done', 'aq-xs')}</span>
|
||
</div>
|
||
<div class="aq-btn-pill aq-btn-primary aq-mt">${f('review_scores_agree', 'aq-field-on-primary aq-xs')}</div>
|
||
<div class="aq-label-xs aq-mt">${f('review_scores_set_category', 'aq-label-xs')}</div>
|
||
<div class="aq-band-btns">
|
||
<span class="aq-band-btn green">${f('category_green', 'aq-xs')}</span>
|
||
<span class="aq-band-btn yellow">${f('category_yellow', 'aq-xs')}</span>
|
||
<span class="aq-band-btn red">${f('category_red', 'aq-xs')}</span>
|
||
</div>
|
||
</div>
|
||
<div class="aq-btn-outline aq-review-previous">${f('previous', 'aq-sm')}</div>
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'empty',
|
||
label: 'Leer',
|
||
focusKeys: ['review_scores_empty', 'review_scores'],
|
||
mock: () => `
|
||
<div class="aq-screen aq-review">
|
||
<div class="aq-review-header">
|
||
<div>
|
||
${f('review_scores', 'aq-screen-title')}
|
||
${f('review_scores_empty', 'aq-muted aq-sm', 'textarea')}
|
||
</div>
|
||
<div class="aq-review-header-actions">${langChip()}${iconHelp()}</div>
|
||
</div>
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'complete',
|
||
label: 'Abgeschlossen',
|
||
focusKeys: [
|
||
'review_scores_complete_title', 'review_scores_complete_body',
|
||
'review_scores_complete_body_uploaded', 'review_scores_done',
|
||
'review_scores_pending_upload', 'review_scores_saved_pending', 'previous',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-review">
|
||
<div class="aq-review-header">
|
||
<div>
|
||
${f('review_scores', 'aq-screen-title')}
|
||
${f('review_scores_subtitle', 'aq-muted aq-sm')}
|
||
</div>
|
||
<div class="aq-review-header-actions">${langChip()}${iconHelp()}</div>
|
||
</div>
|
||
<div class="aq-card aq-profile-card">
|
||
${f('review_scores_complete_title', 'aq-bold')}
|
||
${f('review_scores_complete_body', 'aq-muted aq-sm', 'textarea')}
|
||
<div class="aq-muted aq-sm aq-mt">${f('review_scores_pending_upload', 'aq-sm')}</div>
|
||
<div class="aq-btn-pill aq-btn-primary aq-mt">${f('review_scores_done', 'aq-field-on-primary aq-xs')}</div>
|
||
</div>
|
||
<div class="aq-btn-outline aq-review-previous">${f('previous', 'aq-sm')}</div>
|
||
${toastBanner('review_scores_saved_pending')}
|
||
</div>`,
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'upload',
|
||
label: 'Hochladen',
|
||
hint: 'upload_overview_screen.xml',
|
||
keys: [
|
||
'upload', 'start_upload', 'upload_pending_subtitle', 'upload_summary',
|
||
'upload_nothing_pending', 'upload_prepare_failed', 'upload_failed_title',
|
||
'upload_success_title', 'upload_success_message', 'upload_success_questionnaires',
|
||
'upload_success_scoring_reviews', 'upload_success_client_notes',
|
||
'upload_success_sync_next', 'upload_item_scoring_review', 'upload_scoring_review_summary',
|
||
'cancel', 'previous', 'help_title', 'questions_filled', 'done', 'client_code',
|
||
'upload_connect_network_first', 'no_questionnaires', 'login_required', 'client_note',
|
||
],
|
||
variants: [
|
||
{
|
||
id: 'pending',
|
||
label: 'Ausstehend',
|
||
focusKeys: [
|
||
'upload_pending_subtitle', 'start_upload', 'upload_summary', 'upload',
|
||
'cancel', 'previous', 'client_code', 'done', 'questions_filled',
|
||
'upload_item_scoring_review', 'upload_scoring_review_summary',
|
||
'upload_connect_network_first', 'client_note',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-upload">
|
||
<div class="aq-card aq-header-card">
|
||
<div class="aq-header-row">
|
||
<div>
|
||
${f('upload_pending_subtitle', 'aq-muted aq-sm')}
|
||
${f('start_upload', 'aq-screen-title')}
|
||
</div>
|
||
<div class="aq-review-header-actions">${langChip()}${iconHelp()}</div>
|
||
</div>
|
||
<div class="aq-divider"></div>
|
||
<div class="aq-control-chip aq-summary-chip">${f('upload_summary', 'aq-sm')}</div>
|
||
</div>
|
||
<div class="aq-card aq-list-card">
|
||
<div class="aq-client-header">${f('client_code', 'aq-xs')}: demoClient</div>
|
||
<div class="aq-upload-row">
|
||
<div>
|
||
<div class="aq-bold">Demografie</div>
|
||
<div class="aq-muted aq-xs">✓ ${f('done', 'aq-xs')} · 12 ${f('questions_filled', 'aq-xs')}</div>
|
||
</div>
|
||
<span class="aq-chevron">›</span>
|
||
</div>
|
||
<div class="aq-upload-row">
|
||
<div>
|
||
<div class="aq-bold">${f('upload_item_scoring_review', 'aq-sm')}</div>
|
||
<div class="aq-muted aq-xs">${f('upload_scoring_review_summary', 'aq-xs')}</div>
|
||
</div>
|
||
</div>
|
||
<div class="aq-upload-row">
|
||
<div>
|
||
<div class="aq-bold">${f('client_note', 'aq-sm')}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="aq-upload-footer">
|
||
<div class="aq-btn-outline">${f('cancel', 'aq-sm')}</div>
|
||
<div class="aq-btn-square primary">${f('upload', 'aq-field-on-primary aq-sm')}</div>
|
||
</div>
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'empty',
|
||
label: 'Leer',
|
||
focusKeys: [
|
||
'upload_nothing_pending', 'no_questionnaires', 'start_upload',
|
||
'login_required', 'upload_connect_network_first',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-upload">
|
||
<div class="aq-card aq-header-card">
|
||
${f('start_upload', 'aq-screen-title')}
|
||
${f('upload_nothing_pending', 'aq-muted aq-sm aq-mt', 'textarea')}
|
||
${f('no_questionnaires', 'aq-muted aq-sm aq-mt', 'textarea')}
|
||
</div>
|
||
<div class="aq-upload-footer-hint">
|
||
${f('upload_connect_network_first', 'aq-muted aq-sm')}
|
||
</div>
|
||
${toastBanner('login_required')}
|
||
</div>`,
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'help',
|
||
label: 'Hilfe',
|
||
hint: 'activity_help.xml · pick a topic below',
|
||
keys: [
|
||
'help_title', 'help_topic', 'help_this_page', 'language',
|
||
'help_auth_title', 'help_auth_intro', 'help_auth_signin_title', 'help_auth_signin_body',
|
||
'help_auth_password_title', 'help_auth_password_body',
|
||
'help_opening_title', 'help_opening_intro', 'help_opening_pick_client_title',
|
||
'help_opening_pick_client_body', 'help_opening_home_title', 'help_opening_home_body',
|
||
'help_opening_client_lang_title', 'help_opening_client_lang_body',
|
||
'help_opening_questionnaires_title', 'help_opening_questionnaires_body',
|
||
'help_opening_complete_title', 'help_opening_complete_body',
|
||
'help_questionnaire_title', 'help_questionnaire_intro', 'help_questionnaire_header_title',
|
||
'help_questionnaire_header_body', 'help_questionnaire_answer_title',
|
||
'help_questionnaire_answer_body', 'help_questionnaire_save_title',
|
||
'help_questionnaire_save_body',
|
||
'help_category_title', 'help_category_intro', 'help_category_set_title',
|
||
'help_category_set_body', 'help_category_change_title', 'help_category_change_body',
|
||
'help_upload_title', 'help_upload_intro', 'help_upload_check_title',
|
||
'help_upload_check_body', 'help_upload_fix_title', 'help_upload_fix_body',
|
||
'help_upload_send_title', 'help_upload_send_body',
|
||
],
|
||
variants: [
|
||
{
|
||
id: 'auth',
|
||
label: 'Anmeldung',
|
||
focusKeys: [
|
||
'help_title', 'help_topic', 'help_this_page', 'language',
|
||
'help_auth_title', 'help_auth_intro', 'help_auth_signin_title',
|
||
'help_auth_signin_body', 'help_auth_password_title', 'help_auth_password_body',
|
||
],
|
||
mock: () => helpShell('help_auth_title', 'help_auth_intro', [
|
||
{ titleKey: 'help_auth_signin_title', bodyKey: 'help_auth_signin_body' },
|
||
{ titleKey: 'help_auth_password_title', bodyKey: 'help_auth_password_body' },
|
||
]),
|
||
},
|
||
{
|
||
id: 'opening',
|
||
label: 'Startseite',
|
||
focusKeys: [
|
||
'help_title', 'help_topic', 'help_this_page', 'language',
|
||
'help_opening_title', 'help_opening_intro', 'help_opening_pick_client_title',
|
||
'help_opening_pick_client_body', 'help_opening_home_title', 'help_opening_home_body',
|
||
'help_opening_client_lang_title', 'help_opening_client_lang_body',
|
||
'help_opening_questionnaires_title', 'help_opening_questionnaires_body',
|
||
'help_opening_complete_title', 'help_opening_complete_body',
|
||
],
|
||
mock: () => helpShell('help_opening_title', 'help_opening_intro', [
|
||
{ titleKey: 'help_opening_pick_client_title', bodyKey: 'help_opening_pick_client_body' },
|
||
{ titleKey: 'help_opening_home_title', bodyKey: 'help_opening_home_body' },
|
||
{ titleKey: 'help_opening_client_lang_title', bodyKey: 'help_opening_client_lang_body' },
|
||
{ titleKey: 'help_opening_questionnaires_title', bodyKey: 'help_opening_questionnaires_body' },
|
||
{ titleKey: 'help_opening_complete_title', bodyKey: 'help_opening_complete_body' },
|
||
]),
|
||
},
|
||
{
|
||
id: 'questionnaire',
|
||
label: 'Fragebogen',
|
||
focusKeys: [
|
||
'help_title', 'help_topic', 'help_this_page', 'language',
|
||
'help_questionnaire_title', 'help_questionnaire_intro',
|
||
'help_questionnaire_header_title', 'help_questionnaire_header_body',
|
||
'help_questionnaire_answer_title', 'help_questionnaire_answer_body',
|
||
'help_questionnaire_save_title', 'help_questionnaire_save_body',
|
||
],
|
||
mock: () => helpShell('help_questionnaire_title', 'help_questionnaire_intro', [
|
||
{ titleKey: 'help_questionnaire_header_title', bodyKey: 'help_questionnaire_header_body' },
|
||
{ titleKey: 'help_questionnaire_answer_title', bodyKey: 'help_questionnaire_answer_body' },
|
||
{ titleKey: 'help_questionnaire_save_title', bodyKey: 'help_questionnaire_save_body' },
|
||
]),
|
||
},
|
||
{
|
||
id: 'category',
|
||
label: 'Ampelkategorie',
|
||
focusKeys: [
|
||
'help_title', 'help_topic', 'help_this_page', 'language',
|
||
'help_category_title', 'help_category_intro',
|
||
'help_category_set_title', 'help_category_set_body',
|
||
'help_category_change_title', 'help_category_change_body',
|
||
],
|
||
mock: () => helpShell('help_category_title', 'help_category_intro', [
|
||
{ titleKey: 'help_category_set_title', bodyKey: 'help_category_set_body' },
|
||
{ titleKey: 'help_category_change_title', bodyKey: 'help_category_change_body' },
|
||
]),
|
||
},
|
||
{
|
||
id: 'upload',
|
||
label: 'Hochladen',
|
||
focusKeys: [
|
||
'help_title', 'help_topic', 'help_this_page', 'language',
|
||
'help_upload_title', 'help_upload_intro',
|
||
'help_upload_check_title', 'help_upload_check_body',
|
||
'help_upload_fix_title', 'help_upload_fix_body',
|
||
'help_upload_send_title', 'help_upload_send_body',
|
||
],
|
||
mock: () => helpShell('help_upload_title', 'help_upload_intro', [
|
||
{ titleKey: 'help_upload_check_title', bodyKey: 'help_upload_check_body' },
|
||
{ titleKey: 'help_upload_fix_title', bodyKey: 'help_upload_fix_body' },
|
||
{ titleKey: 'help_upload_send_title', bodyKey: 'help_upload_send_body' },
|
||
]),
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'sync',
|
||
label: 'Synchronisation',
|
||
hint: 'view_sync_progress_overlay.xml · pick a phase below',
|
||
keys: [
|
||
'sync_title',
|
||
'sync_status_preparing', 'sync_status_downloading_questionnaires',
|
||
'sync_status_downloading_client_info', 'sync_status_downloading_answers',
|
||
'sync_status_processing', 'sync_status_securely_saving', 'sync_status_finished',
|
||
'sync_subtitle_preparing', 'sync_subtitle_downloading_questionnaires',
|
||
'sync_subtitle_downloading_client_info', 'sync_subtitle_downloading_answers',
|
||
'sync_subtitle_processing', 'sync_subtitle_securely_saving', 'sync_subtitle_finished',
|
||
],
|
||
variants: [
|
||
{
|
||
id: 'preparing',
|
||
label: 'Vorbereitung',
|
||
focusKeys: ['sync_title', 'sync_status_preparing', 'sync_subtitle_preparing'],
|
||
mock: () => syncPhaseMock('sync_status_preparing', 'sync_subtitle_preparing', 10),
|
||
},
|
||
{
|
||
id: 'questionnaires',
|
||
label: 'Fragebögen',
|
||
focusKeys: [
|
||
'sync_title', 'sync_status_downloading_questionnaires',
|
||
'sync_subtitle_downloading_questionnaires',
|
||
],
|
||
mock: () => syncPhaseMock(
|
||
'sync_status_downloading_questionnaires',
|
||
'sync_subtitle_downloading_questionnaires',
|
||
25,
|
||
),
|
||
},
|
||
{
|
||
id: 'client_info',
|
||
label: 'Klienten',
|
||
focusKeys: [
|
||
'sync_title', 'sync_status_downloading_client_info',
|
||
'sync_subtitle_downloading_client_info',
|
||
],
|
||
mock: () => syncPhaseMock(
|
||
'sync_status_downloading_client_info',
|
||
'sync_subtitle_downloading_client_info',
|
||
40,
|
||
),
|
||
},
|
||
{
|
||
id: 'answers',
|
||
label: 'Antworten',
|
||
focusKeys: [
|
||
'sync_title', 'sync_status_downloading_answers',
|
||
'sync_subtitle_downloading_answers',
|
||
],
|
||
mock: () => syncPhaseMock(
|
||
'sync_status_downloading_answers',
|
||
'sync_subtitle_downloading_answers',
|
||
55,
|
||
),
|
||
},
|
||
{
|
||
id: 'processing',
|
||
label: 'Verarbeitung',
|
||
focusKeys: ['sync_title', 'sync_status_processing', 'sync_subtitle_processing'],
|
||
mock: () => syncPhaseMock('sync_status_processing', 'sync_subtitle_processing', 70),
|
||
},
|
||
{
|
||
id: 'saving',
|
||
label: 'Speichern',
|
||
focusKeys: [
|
||
'sync_title', 'sync_status_securely_saving', 'sync_subtitle_securely_saving',
|
||
],
|
||
mock: () => syncPhaseMock(
|
||
'sync_status_securely_saving',
|
||
'sync_subtitle_securely_saving',
|
||
85,
|
||
),
|
||
},
|
||
{
|
||
id: 'finished',
|
||
label: 'Fertig',
|
||
focusKeys: ['sync_title', 'sync_status_finished', 'sync_subtitle_finished'],
|
||
mock: () => syncPhaseMock('sync_status_finished', 'sync_subtitle_finished', 100, true),
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'dialogs',
|
||
label: 'Dialoge',
|
||
hint: 'dialog_app_message.xml + notices · pick a dialog below',
|
||
keys: [
|
||
'logout', 'logout_confirm_title', 'logout_confirm_message', 'logout_confirm_action',
|
||
'logout_offline_title', 'logout_offline_message', 'logout_pending_title',
|
||
'logout_pending_message', 'logout_pending_detail_questionnaires',
|
||
'logout_pending_detail_scoring', 'logout_pending_detail_notes',
|
||
'logout_pending_detail_in_progress',
|
||
'upload_pending_title', 'upload_pending_review_message', 'upload', 'later',
|
||
'review_scores_supervisor_confirm_title', 'review_scores_supervisor_confirm_body',
|
||
'review_scores_supervisor_confirm_action', 'cancel', 'ok',
|
||
'upload_success_title', 'upload_success_message', 'upload_success_questionnaires',
|
||
'upload_success_scoring_reviews', 'upload_success_client_notes',
|
||
'upload_success_sync_next', 'upload_failed_title', 'upload_nothing_pending',
|
||
'upload_prepare_failed', 'error', 'error_invalid_data', 'error_not_found',
|
||
'score_calculated_eyebrow', 'score_calculated_title', 'score_calculated_body',
|
||
'score_calculated_result_label', 'score_calculated_next_label',
|
||
'score_calculated_next_title', 'score_calculated_band_hint', 'score_calculated_continue',
|
||
'category_yellow', 'questionnaire_exit_title', 'questionnaire_exit_message', 'leave',
|
||
],
|
||
variants: [
|
||
{
|
||
id: 'logout_confirm',
|
||
label: 'Abmelden bestätigen',
|
||
focusKeys: [
|
||
'logout_confirm_title', 'logout_confirm_message', 'logout_confirm_action',
|
||
'cancel', 'logout',
|
||
],
|
||
mock: () => dialogMock({
|
||
titleKey: 'logout_confirm_title',
|
||
messageKey: 'logout_confirm_message',
|
||
primaryKey: 'logout_confirm_action',
|
||
secondaryKey: 'cancel',
|
||
tone: 'logout',
|
||
}),
|
||
},
|
||
{
|
||
id: 'logout_offline',
|
||
label: 'Abmelden offline',
|
||
focusKeys: ['logout_offline_title', 'logout_offline_message', 'ok'],
|
||
mock: () => dialogMock({
|
||
titleKey: 'logout_offline_title',
|
||
messageKey: 'logout_offline_message',
|
||
primaryKey: 'ok',
|
||
tone: 'warning',
|
||
}),
|
||
},
|
||
{
|
||
id: 'logout_pending',
|
||
label: 'Abmelden blockiert',
|
||
focusKeys: [
|
||
'logout_pending_title', 'logout_pending_message',
|
||
'logout_pending_detail_questionnaires', 'logout_pending_detail_scoring',
|
||
'logout_pending_detail_notes', 'logout_pending_detail_in_progress', 'ok',
|
||
],
|
||
mock: () => dialogMock({
|
||
titleKey: 'logout_pending_title',
|
||
messageKey: 'logout_pending_message',
|
||
primaryKey: 'ok',
|
||
detailsKeys: [
|
||
'logout_pending_detail_questionnaires',
|
||
'logout_pending_detail_scoring',
|
||
'logout_pending_detail_notes',
|
||
'logout_pending_detail_in_progress',
|
||
],
|
||
tone: 'warning',
|
||
}),
|
||
},
|
||
{
|
||
id: 'upload_pending',
|
||
label: 'Upload bereit',
|
||
focusKeys: [
|
||
'upload_pending_title', 'upload_pending_review_message', 'upload', 'later',
|
||
],
|
||
mock: () => dialogMock({
|
||
titleKey: 'upload_pending_title',
|
||
messageKey: 'upload_pending_review_message',
|
||
primaryKey: 'upload',
|
||
secondaryKey: 'later',
|
||
tone: 'info',
|
||
}),
|
||
},
|
||
{
|
||
id: 'supervisor',
|
||
label: 'Supervision',
|
||
focusKeys: [
|
||
'review_scores_supervisor_confirm_title',
|
||
'review_scores_supervisor_confirm_body',
|
||
'review_scores_supervisor_confirm_action', 'cancel',
|
||
],
|
||
mock: () => dialogMock({
|
||
titleKey: 'review_scores_supervisor_confirm_title',
|
||
messageKey: 'review_scores_supervisor_confirm_body',
|
||
primaryKey: 'review_scores_supervisor_confirm_action',
|
||
secondaryKey: 'cancel',
|
||
tone: 'warning',
|
||
}),
|
||
},
|
||
{
|
||
id: 'upload_success',
|
||
label: 'Upload OK',
|
||
focusKeys: [
|
||
'upload_success_title', 'upload_success_message',
|
||
'upload_success_questionnaires', 'upload_success_scoring_reviews',
|
||
'upload_success_client_notes', 'upload_success_sync_next', 'ok',
|
||
],
|
||
mock: () => dialogMock({
|
||
titleKey: 'upload_success_title',
|
||
messageKey: 'upload_success_message',
|
||
primaryKey: 'ok',
|
||
detailsKeys: [
|
||
'upload_success_questionnaires',
|
||
'upload_success_scoring_reviews',
|
||
'upload_success_client_notes',
|
||
'upload_success_sync_next',
|
||
],
|
||
tone: 'info',
|
||
}),
|
||
},
|
||
{
|
||
id: 'upload_failed',
|
||
label: 'Upload Fehler',
|
||
focusKeys: [
|
||
'upload_failed_title', 'upload_prepare_failed', 'ok', 'cancel',
|
||
],
|
||
mock: () => dialogMock({
|
||
titleKey: 'upload_failed_title',
|
||
messageKey: 'upload_prepare_failed',
|
||
primaryKey: 'ok',
|
||
secondaryKey: 'cancel',
|
||
tone: 'danger',
|
||
}),
|
||
},
|
||
{
|
||
id: 'exit_questionnaire',
|
||
label: 'Fragebogen verlassen',
|
||
focusKeys: [
|
||
'questionnaire_exit_title', 'questionnaire_exit_message', 'leave', 'cancel',
|
||
],
|
||
mock: () => `
|
||
<div class="aq-screen aq-dialogs">
|
||
<div class="aq-dialog aq-dialog-warning">
|
||
<div class="aq-dialog-icon warning" aria-hidden="true"></div>
|
||
${f('questionnaire_exit_title', 'aq-dialog-title')}
|
||
${f('questionnaire_exit_message', 'aq-muted aq-sm aq-dialog-msg', 'textarea')}
|
||
<div class="aq-dialog-actions-col">
|
||
<div class="aq-btn-pill aq-btn-danger">${f('leave', 'aq-field-on-primary')}</div>
|
||
<div class="aq-btn-text">${f('cancel', 'aq-muted')}</div>
|
||
</div>
|
||
</div>
|
||
</div>`,
|
||
},
|
||
{
|
||
id: 'error_invalid',
|
||
label: 'Fehler (Daten)',
|
||
focusKeys: ['error', 'error_invalid_data', 'ok'],
|
||
mock: () => dialogMock({
|
||
titleKey: 'error',
|
||
messageKey: 'error_invalid_data',
|
||
primaryKey: 'ok',
|
||
tone: 'danger',
|
||
}),
|
||
},
|
||
{
|
||
id: 'error_not_found',
|
||
label: 'Fehler (Nicht gefunden)',
|
||
focusKeys: ['error', 'error_not_found', 'ok'],
|
||
mock: () => dialogMock({
|
||
titleKey: 'error',
|
||
messageKey: 'error_not_found',
|
||
primaryKey: 'ok',
|
||
tone: 'danger',
|
||
}),
|
||
},
|
||
{
|
||
id: 'score_notice',
|
||
label: 'Punktzahl berechnet',
|
||
focusKeys: [
|
||
'score_calculated_eyebrow', 'score_calculated_title', 'score_calculated_body',
|
||
'score_calculated_result_label', 'score_calculated_next_label',
|
||
'score_calculated_next_title', 'score_calculated_band_hint',
|
||
'score_calculated_continue', 'category_yellow',
|
||
],
|
||
mock: () => scoreCalculatedMock(),
|
||
},
|
||
],
|
||
},
|
||
];
|
||
|
||
export function screenById(id) {
|
||
return APP_UI_SCREENS.find(s => s.id === id) || APP_UI_SCREENS[0];
|
||
}
|
||
|
||
/** @returns {AppUiVariant[]} */
|
||
export function getVariants(screen) {
|
||
if (screen.variants?.length) return screen.variants;
|
||
return [{
|
||
id: 'default',
|
||
label: screen.label,
|
||
focusKeys: screen.keys,
|
||
mock: screen.mock || (() => ''),
|
||
}];
|
||
}
|
||
|
||
export function variantById(screen, variantId) {
|
||
const variants = getVariants(screen);
|
||
return variants.find(v => v.id === variantId) || variants[0];
|
||
}
|
||
|
||
export function allScreenKeys() {
|
||
const set = new Set();
|
||
APP_UI_SCREENS.forEach(s => s.keys.forEach(k => set.add(k)));
|
||
return set;
|
||
}
|