feat(124): sms templates CRUD + order picker
- Nowa tabela sms_templates (name + body + is_active) + minimalny CRUD.
- /settings/sms-templates: lista + formularz z paleta zmiennych (pill chips).
- Wydzielono Sms\SmsVariableResolver ze wspolna logika placeholderow;
Email\VariableResolver staje sie cienka fasada — EmailSendingService bez zmian.
- Dropdown "Wybierz szablon" w zakladce SMS na /orders/{id} z fetch
GET /orders/{id}/sms/template + OrderProAlerts.confirm przy nadpisaniu.
- Stopka SMSPLANET dalej doklejana wylacznie przez SmsConversationService
(Phase 122 contract preserved).
- Sidebar Ustawien: nowy link "Szablony SMS".
Migration: 20260512_000112_create_sms_templates.sql (CREATE TABLE).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
96
public/assets/js/modules/sms-template-picker.js
Normal file
96
public/assets/js/modules/sms-template-picker.js
Normal file
@@ -0,0 +1,96 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
if (window.__smsTemplatePickerBound) return;
|
||||
window.__smsTemplatePickerBound = true;
|
||||
|
||||
function findTarget(picker) {
|
||||
var targetId = picker.getAttribute('data-message-target');
|
||||
if (!targetId) return null;
|
||||
return document.getElementById(targetId);
|
||||
}
|
||||
|
||||
function applyBody(textarea, body) {
|
||||
textarea.value = body;
|
||||
textarea.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
textarea.focus();
|
||||
}
|
||||
|
||||
function bind(picker) {
|
||||
if (picker.dataset.smsPickerBound === '1') return;
|
||||
picker.dataset.smsPickerBound = '1';
|
||||
|
||||
picker.addEventListener('change', function () {
|
||||
var templateId = parseInt(picker.value, 10);
|
||||
var orderId = parseInt(picker.getAttribute('data-order-id'), 10);
|
||||
if (!templateId || !orderId) {
|
||||
return;
|
||||
}
|
||||
var textarea = findTarget(picker);
|
||||
if (!textarea) {
|
||||
picker.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
var doFetch = function () {
|
||||
picker.disabled = true;
|
||||
fetch('/orders/' + orderId + '/sms/template?template_id=' + templateId, {
|
||||
headers: { 'Accept': 'application/json' },
|
||||
credentials: 'same-origin'
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (data) {
|
||||
if (data && data.ok && typeof data.body === 'string') {
|
||||
applyBody(textarea, data.body);
|
||||
} else if (window.OrderProAlerts && window.OrderProAlerts.alert) {
|
||||
window.OrderProAlerts.alert({
|
||||
title: 'Nie udalo sie wczytac szablonu',
|
||||
message: (data && data.error) ? String(data.error) : 'Sprobuj ponownie.'
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(function () {})
|
||||
.finally(function () {
|
||||
picker.disabled = false;
|
||||
picker.value = '';
|
||||
});
|
||||
};
|
||||
|
||||
var current = (textarea.value || '').trim();
|
||||
if (current === '') {
|
||||
doFetch();
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.OrderProAlerts && typeof window.OrderProAlerts.confirm === 'function') {
|
||||
var triggered = false;
|
||||
var run = function () { if (!triggered) { triggered = true; doFetch(); } };
|
||||
var result = window.OrderProAlerts.confirm({
|
||||
title: 'Zamiana tresci',
|
||||
message: 'Tekst w polu wiadomosci zostanie nadpisany trescia szablonu. Kontynuowac?',
|
||||
confirmLabel: 'Wstaw szablon',
|
||||
danger: false,
|
||||
onConfirm: run,
|
||||
onCancel: function () { picker.value = ''; }
|
||||
});
|
||||
if (result && typeof result.then === 'function') {
|
||||
result.then(function (ok) { if (ok) run(); else picker.value = ''; });
|
||||
}
|
||||
} else if (window.confirm('Tekst w polu wiadomosci zostanie nadpisany. Kontynuowac?')) {
|
||||
doFetch();
|
||||
} else {
|
||||
picker.value = '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
document.querySelectorAll('[data-sms-template-picker]').forEach(bind);
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user