Files
BetterDesk/web-nodejs/views/commercialization.ejs
T
UNITRONIX bb2ff08f65 Fix NTP server config not reaching betterdesk-server (Fixes #223).
Wire billing/NTP env from console .env into Go on Linux, Windows, and Docker; add OS NTP fallback and Commercialization settings UI to configure and restart the server.
2026-06-27 20:33:56 +02:00

217 lines
12 KiB
HTML

<%- include('layouts/main', {
title: title,
pageStyles: pageStyles,
pageScripts: pageScripts,
currentPage: currentPage,
breadcrumb: breadcrumb,
body: `
<div class="commercialization-page" data-active-tab="${typeof activeTab !== 'undefined' ? activeTab : 'overview'}">
<div class="page-header">
<h1>${activeTab === 'overview' ? _('commercialization.title') : _('commercialization.tabs.' + activeTab)} <span class="beta-badge" title="${_('commercialization.alpha_tooltip')}">${_('commercialization.alpha_badge')}</span></h1>
<p class="page-subtitle">${activeTab === 'overview' ? _('commercialization.subtitle') : _('commercialization.title')}</p>
</div>
<div id="timesync-banner" class="timesync-banner hidden"></div>
<section id="tab-overview" class="tab-panel ${activeTab === 'overview' ? '' : 'hidden'}">
<div class="card-grid">
<div class="stat-card" id="stat-clock">
<h3>${_('commercialization.clock.title')}</h3>
<p class="stat-value" id="clock-status"></p>
<p class="stat-meta" id="clock-offset"></p>
</div>
<div class="stat-card">
<h3>${_('commercialization.stats.active_sessions')}</h3>
<p class="stat-value" id="stat-active-sessions">0</p>
</div>
</div>
</section>
<section id="tab-packages" class="tab-panel ${activeTab === 'packages' ? '' : 'hidden'}">
<div class="panel-toolbar">
<button type="button" class="btn btn-primary" id="btn-new-package">${_('commercialization.packages.new')}</button>
</div>
<h3 class="section-heading">${_('commercialization.packages.heading')}</h3>
<div class="table-wrap">
<table class="data-table" id="packages-table">
<thead>
<tr>
<th>${_('commercialization.packages.name')}</th>
<th>${_('commercialization.packages.included_minutes')}</th>
<th>${_('commercialization.packages.overage_rate')}</th>
<th>${_('commercialization.packages.currency')}</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<h3 class="section-heading">${_('commercialization.contracts.title')}</h3>
<div class="panel-toolbar">
<button type="button" class="btn btn-primary" id="btn-new-contract">${_('commercialization.contracts.new')}</button>
</div>
<div class="table-wrap">
<table class="data-table" id="contracts-table">
<thead>
<tr>
<th>${_('commercialization.contracts.org')}</th>
<th>${_('commercialization.contracts.package')}</th>
<th>${_('commercialization.contracts.remaining')}</th>
<th>${_('commercialization.contracts.status')}</th>
<th>${_('commercialization.contracts.actions')}</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</section>
<section id="tab-sessions" class="tab-panel ${activeTab === 'sessions' ? '' : 'hidden'}">
<div class="panel-toolbar">
<button type="button" class="btn btn-secondary" id="btn-export-sessions">${_('commercialization.export.sessions_csv')}</button>
</div>
<div class="table-wrap">
<table class="data-table" id="sessions-table">
<thead>
<tr>
<th>${_('commercialization.sessions.device')}</th>
<th>${_('commercialization.sessions.operator')}</th>
<th>${_('commercialization.sessions.duration')}</th>
<th>${_('commercialization.sessions.phase')}</th>
<th>${_('commercialization.sessions.amount')}</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</section>
<section id="tab-reports" class="tab-panel ${activeTab === 'reports' ? '' : 'hidden'}">
<div class="panel-toolbar">
<button type="button" class="btn btn-secondary" id="btn-export-reports-csv">${_('commercialization.export.csv')}</button>
<button type="button" class="btn btn-secondary" id="btn-export-reports-pdf">${_('commercialization.export.pdf')}</button>
</div>
<div class="table-wrap">
<table class="data-table" id="reports-table">
<thead>
<tr>
<th>${_('commercialization.reports.session')}</th>
<th>${_('commercialization.reports.summary')}</th>
<th>${_('commercialization.reports.date')}</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</section>
<section id="tab-settings" class="tab-panel ${activeTab === 'settings' ? '' : 'hidden'}">
<div class="card">
<h3>${_('commercialization.clock.title')}</h3>
<p id="settings-clock-detail" class="text-muted"></p>
<dl class="clock-status-grid">
<div><dt>${_('commercialization.clock.status_offset')}</dt><dd id="clock-offset"></dd></div>
<div><dt>${_('commercialization.clock.status_server')}</dt><dd id="clock-ntp-server"></dd></div>
<div><dt>${_('commercialization.clock.status_os')}</dt><dd id="clock-os-sync"></dd></div>
<div><dt>${_('commercialization.clock.status_error')}</dt><dd id="clock-last-error"></dd></div>
</dl>
<button type="button" class="btn btn-secondary" id="btn-timesync-check">${_('commercialization.clock.check_now')}</button>
<form id="clock-settings-form" class="settings-form" style="margin-top: 1rem;">
<label class="form-label">${_('commercialization.clock.ntp_servers')}
<textarea id="clock-ntp-servers" class="form-control" rows="2" placeholder="pool.ntp.org,time.google.com"></textarea>
</label>
<p class="text-muted form-hint">${_('commercialization.clock.ntp_servers_hint')}</p>
<label class="form-label">${_('commercialization.clock.max_skew_ms')}
<input type="number" id="clock-max-skew" class="form-control" min="100" max="600000" step="100" value="2000">
</label>
<div class="form-group">
<label><input type="checkbox" id="clock-require-sync"> ${_('commercialization.clock.require_sync')}</label>
</div>
<div class="form-group">
<label><input type="checkbox" id="clock-trust-os"> ${_('commercialization.clock.trust_os')}</label>
</div>
<p class="text-muted form-hint">${_('commercialization.clock.trust_os_hint')}</p>
<button type="button" class="btn btn-primary" id="btn-save-clock-settings">${_('commercialization.clock.save')}</button>
</form>
</div>
<div class="card" style="margin-top: 1rem;">
<h3>${_('commercialization.notifications.title')}</h3>
<p class="text-muted">${_('commercialization.notifications.desc')}</p>
<p id="email-smtp-status" class="smtp-status-line"></p>
<p><a href="/settings#email">${_('commercialization.notifications.smtp_link')}</a></p>
<form id="email-notifications-form" class="settings-form">
<div class="form-group">
<label><input type="checkbox" id="notif-help-requests-enabled"> ${_('commercialization.notifications.help_requests_enabled')}</label>
</div>
<div class="form-group">
<label><input type="checkbox" id="notif-assigned-operators"> ${_('commercialization.notifications.notify_assigned_operators')}</label>
</div>
<div class="form-group">
<label><input type="checkbox" id="notif-fallback-alert"> ${_('commercialization.notifications.fallback_alert_email')}</label>
</div>
<div class="form-group">
<label><input type="checkbox" id="notif-folder-subject"> ${_('commercialization.notifications.include_folder_in_subject')}</label>
</div>
<button type="button" class="btn btn-primary" id="btn-save-email-notifications">${_('commercialization.notifications.save')}</button>
</form>
</div>
</section>
</div>
<div class="modal-overlay" id="package-modal">
<div class="modal" role="dialog" aria-modal="true">
<div class="modal-header">
<h2 class="modal-title">${_('commercialization.packages.create_title')}</h2>
<button type="button" class="modal-close" data-close-modal="package-modal">&times;</button>
</div>
<div class="modal-body">
<label class="form-label">${_('commercialization.packages.select_org')}
<select id="package-org-select" class="form-control" required></select>
</label>
<label class="form-label">${_('commercialization.packages.name')}
<input type="text" id="package-name" class="form-control" maxlength="128" required>
</label>
<label class="form-label">${_('commercialization.packages.included_minutes')}
<input type="number" id="package-minutes" class="form-control" value="600" min="1" step="1" required>
</label>
<label class="form-label">${_('commercialization.packages.overage_rate')}
<input type="number" id="package-overage" class="form-control" value="100" min="0" step="0.01" required>
</label>
<label class="form-label">${_('commercialization.packages.currency')}
<input type="text" id="package-currency" class="form-control" value="PLN" maxlength="8" required>
</label>
<p id="package-modal-error" class="form-error hidden"></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-close-modal="package-modal">${_('commercialization.form.cancel')}</button>
<button type="button" class="btn btn-primary" id="package-modal-submit">${_('commercialization.packages.create_submit')}</button>
</div>
</div>
</div>
<div class="modal-overlay" id="assign-modal">
<div class="modal" role="dialog" aria-modal="true">
<div class="modal-header">
<h2 class="modal-title">${_('commercialization.assign.title')}</h2>
<button type="button" class="modal-close" data-close-modal="assign-modal">&times;</button>
</div>
<div class="modal-body">
<label class="form-label">${_('commercialization.packages.select_org')}
<select id="assign-org-select" class="form-control" required></select>
</label>
<label class="form-label">${_('commercialization.contracts.package')}
<select id="assign-package-select" class="form-control" required></select>
</label>
<p id="assign-modal-error" class="form-error hidden"></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-close-modal="assign-modal">${_('commercialization.form.cancel')}</button>
<button type="button" class="btn btn-primary" id="assign-modal-submit">${_('commercialization.assign.submit')}</button>
</div>
</div>
</div>
`
}) %>