sms_comunications.blade.php 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. <div class="col card--ui" id="card--dashboard">
  2. <header id="title--section" style="display:none !important" class="d-flex align-items-center justify-content-between">
  3. <div class="title--section_name d-flex align-items-center justify-content-between">
  4. <i class="ico--ui title_section utenti me-2"></i>
  5. <h2 class="primary">Sms</h2>
  6. </div>
  7. @if(!$showForm)
  8. <div class="title--section_addButton" wire:click="add()" style="cursor: pointer;" wire:ignore>
  9. <div class="btn--ui entrata d-flex justify-items-between">
  10. <a href="#" style="color:white;">Aggiungi</a>
  11. </div>
  12. </div>
  13. @endif
  14. </header>
  15. <a class="btn--ui lightGrey" @if(!$showForm) href="/settings?type=comunicazioni" @else href="/sms_comunications" @endif><i class="fa-solid fa-arrow-left"></i></a><br/><br/>
  16. {{-- LISTA MESSAGGI --}}
  17. <section id="resume-table" @if($showForm) style="display:none" @endif>
  18. <div wire:ignore>
  19. <table class="table tablesaw tableHead tablesaw-stack" id="tablesaw-350" width="100%">
  20. <thead>
  21. <tr>
  22. <th>ID</th>
  23. <th>Oggetto</th>
  24. <th># Destinatari</th>
  25. <th>Stato</th>
  26. <th>Programmato per</th>
  27. <th>Data invio</th>
  28. <th>Data creazione</th>
  29. <th>...</th>
  30. </tr>
  31. </thead>
  32. <tbody id="checkall-target">
  33. @foreach($records as $record)
  34. @php
  35. $state = $record->status;
  36. if (!$state) {
  37. if (($record->recipients_sent_count ?? 0) > 0 && ($record->recipients_failed_count ?? 0) > 0) {
  38. $state = 'partial';
  39. } elseif (($record->recipients_sent_count ?? 0) > 0) {
  40. $state = 'sent';
  41. } elseif (!empty($record->schedule_at)) {
  42. $state = 'scheduled';
  43. } else {
  44. $state = 'draft';
  45. }
  46. }
  47. $badgeMap = [
  48. 'draft' => 'secondary',
  49. 'processing' => 'info',
  50. 'scheduled' => 'primary',
  51. 'partial' => 'warning',
  52. 'sent' => 'success',
  53. 'failed' => 'danger',
  54. ];
  55. @endphp
  56. <tr id="row_email_{{ $record->id }}">
  57. <td>{{ $record->id }}</td>
  58. <td><strong>{{ $record->subject }}</strong></td>
  59. <td style="padding-right: 20px">{{ $record->recipients_count ?? $record->recipients()->count() }}</td>
  60. <td><span class="badge bg-{{$badgeMap[$state]}}">{{ $record->status }}</span></td>
  61. <td>
  62. @if(!empty($record->schedule_at))
  63. {{ optional($record->schedule_at)->setTimezone('Europe/Rome')->format('d M Y - H:i') }}
  64. @endif
  65. </td>
  66. <td>
  67. @if(!empty($record->sent_at))
  68. {{ optional($record->sent_at)->setTimezone('Europe/Rome')->format('d M Y - H:i') }}
  69. @endif
  70. </td>
  71. <td>{{ optional($record->created_at)->setTimezone('Europe/Rome')->format('d M Y - H:i') }}</td>
  72. <td class="d-flex gap-2">
  73. <button type="button" class="btn" wire:click="edit({{ $record->id }})" data-bs-toggle="tooltip" data-bs-trigger="hover focus" data-bs-placement="bottom" title="Modifica">
  74. <i class="fa-regular fa-pen-to-square"></i>
  75. </button>
  76. <button type="button" class="btn" wire:click="duplicate({{ $record->id }})" data-bs-toggle="tooltip" data-bs-trigger="hover focus" data-bs-placement="bottom" title="Duplica">
  77. <i class="fa-solid fa-copy"></i>
  78. </button>
  79. @if(in_array($record->status, ['draft','failed']))
  80. <button type="button" class="btn text-danger"
  81. onclick="if (confirm('Eliminare definitivamente questo sms?')) { Livewire.find('{{ $this->id }}').call('deleteMessage', {{ $record->id }}); }"
  82. data-bs-toggle="tooltip" title="Elimina">
  83. <i class="fa-solid fa-trash"></i>
  84. </button>
  85. @endif
  86. </td>
  87. </tr>
  88. @endforeach
  89. </tbody>
  90. </table>
  91. </div>
  92. </section>
  93. {{-- FORM MESSAGGIO --}}
  94. <section wire:key="email-form" @if(!$showForm) style="display:none" @endif>
  95. <div class="container">
  96. @if ($error)
  97. <div class="alert alert-danger" role="alert">{{ $error }}</div>
  98. @endif
  99. @if ($success)
  100. <div class="alert alert-success" role="alert">{{ $success }}</div>
  101. @endif
  102. <div class="row">
  103. <div class="col">
  104. <form>
  105. {{-- Oggetto --}}
  106. <div class="row mb-5">
  107. <div class="col">
  108. <div class="form--item">
  109. <h4>Oggetto</h4>
  110. <input type="text" class="form-control @error('subject') is-invalid @enderror" id="subject" wire:model.defer="subject" placeholder="Oggetto sms" @if($locked) disabled @endif>
  111. @error('subject')
  112. <div class="invalid-feedback">{{ $message }}</div>
  113. @enderror
  114. </div>
  115. </div>
  116. </div>
  117. {{-- Messaggio (CKEditor → content_html) --}}
  118. <div class="row mb-5">
  119. <div class="col">
  120. <div class="form--item">
  121. <h4>Messaggio</h4>
  122. <textarea class="form-control" id="message" wire:model="content"></textarea>
  123. @error('content')
  124. <div class="invalid-feedback d-block">{{ $message }}</div>
  125. @enderror
  126. </div>
  127. </div>
  128. </div>
  129. {{-- Destinatari (selezionati) --}}
  130. <div class="row mb-5">
  131. <div class="col-12 mb-2">
  132. <h4>Destinatari</h4>
  133. <div class="recipients">
  134. @if (empty($recipients))
  135. <span>Nessun destinatario selezionato</span>
  136. @else
  137. @foreach ($recipients as $r)
  138. @php
  139. $fullName = trim(($r['last_name'] ?? '').' '.($r['first_name'] ?? ''));
  140. @endphp
  141. <div class="recipient">
  142. <span class="recipient-name">{{ $fullName !== '' ? $fullName : '—' }}</span>
  143. <span class="recipient-email">({{ $r['phone'] }})</span>
  144. </div>
  145. @endforeach
  146. @endif
  147. </div>
  148. @error('recipients') <div class="invalid-feedback d-block">{{ $message }}</div> @enderror
  149. </div>
  150. @if(!$locked)
  151. <div class="col"></div>
  152. <div class="col-auto">
  153. <a style="cursor:pointer" class="addRecipients btn--ui"><i class="fa-solid fa-plus"></i></a>
  154. </div>
  155. @endif
  156. </div>
  157. {{-- FILTRI + TABELLA DESTINATARI --}}
  158. <div class="row mb-5" wire:ignore id="addRecipientsRow" style="display: none">
  159. <div class="col-xs-12">
  160. <div class="showFilter" style="display: none">
  161. <hr size="1">
  162. <div class="row g-3">
  163. <div class="col-md-3">
  164. <div class="row">
  165. <div class="col-md-12 mb-2"><b>Età</b></div>
  166. <div class="col-12">
  167. <div class="row mb-2">
  168. <div class="col-3"><label class="form-check-label ms-2">Da</label></div>
  169. <div class="col-9"><input class="form-control" type="number" name="txtFromYear"></div>
  170. </div>
  171. </div>
  172. <div class="col-12">
  173. <div class="row">
  174. <div class="col-3"><label class="form-check-label ms-2">A</label></div>
  175. <div class="col-9"><input class="form-control" type="number" name="txtToYear"></div>
  176. </div>
  177. </div>
  178. </div>
  179. </div>
  180. {{-- Altri filtri come da tua UI esistente --}}
  181. <div class="col-md-3">
  182. <div class="row">
  183. <div class="col-md-12 mb-2"><b>Tipologia di tesseramento</b></div>
  184. <div class="col-12">
  185. <select name="filterCards" class="form-select filterCards">
  186. <option value="">Tutte
  187. @foreach(getCards() as $card)
  188. <option value="{{$card->id}}">{{$card->name}}
  189. @endforeach
  190. </select>
  191. </div>
  192. </div>
  193. </div>
  194. <div class="col-md-3">
  195. <div class="row">
  196. <div class="col-md-12 mb-2"><b>Stato tesseramento</b></div>
  197. <div class="col-12">
  198. <select name="filterStatus" class="form-select filterStatus" multiple="multiple">
  199. <option value="2">Attivo
  200. <option value="1">Sospeso
  201. <option value="0">Non tesserato
  202. </select>
  203. </div>
  204. </div>
  205. </div>
  206. <div class="col-md-3">
  207. <div class="row">
  208. <div class="col-md-12 mb-2"><b>Gruppo di interesse</b></div>
  209. <div class="col-12">
  210. <select name="filterCategories" class="form-select filterCategories" multiple="multiple">
  211. <option value="">Tutte</option>
  212. @foreach($categories as $category)
  213. <option value="{{$category["id"]}}">
  214. {!! str_repeat('&bull; ', $category["indentation"] ?? 0) !!}{{$category["name"]}}
  215. </option>
  216. @endforeach
  217. </select>
  218. </div>
  219. </div>
  220. </div>
  221. <div class="col-md-3">
  222. <div class="row">
  223. <div class="col-md-12 mb-2"><b>Anno di nascita</b></div>
  224. <div class="col-12">
  225. <div class="row mb-2">
  226. <div class="col-3"><label class="form-check-label ms-2" >Da</label></div>
  227. <div class="col-9"><input class="form-control " type="number" name="txtFromYearYear"></div>
  228. </div>
  229. </div>
  230. <div class="col-12">
  231. <div class="row">
  232. <div class="col-3"><label class="form-check-label ms-2" >A</label></div>
  233. <div class="col-9"><input class="form-control " type="number" name="txtToYearYear"></div>
  234. </div>
  235. </div>
  236. </div>
  237. </div>
  238. <div class="col-md-3">
  239. <div class="row">
  240. <div class="col-md-12 mb-2"><b>Corso</b></div>
  241. <div class="col-12">
  242. <select name="filterCourses" class="form-select filterCourses" multiple="multiple">
  243. <option value="">Tutti</option>
  244. @foreach($courses as $course)
  245. <option value="{{ $course['id'] }}">
  246. {!! str_repeat('&bull; ', $course['indentation'] ?? 0) !!}{{ $course['name'] }}
  247. </option>
  248. @endforeach
  249. </select>
  250. </div>
  251. </div>
  252. </div>
  253. <div class="col-md-3">
  254. <div class="row">
  255. <div class="col-md-12 mb-2"><b>Scadenza certificato medico</b></div>
  256. <div class="col-12">
  257. <select name="filterScadenza" class="form-select filterScadenza" multiple="multiple">
  258. <option value="1">Scaduti
  259. <option value="2">In scadenza
  260. <option value="3">Non consegnato
  261. <option value="4">Validi
  262. </select>
  263. </div>
  264. </div>
  265. </div>
  266. <div class="col-md-3">
  267. <div class="row">
  268. <div class="col-md-12 mb-2"><b>Tipologia certificato medico</b></div>
  269. <div class="col-12">
  270. <select name="filterCertificateType" class="form-select filterCertificateType" multiple="multiple">
  271. <option value="">Tutti
  272. <option value="N">Non agonistico
  273. <option value="A">Agonistico
  274. </select>
  275. </div>
  276. </div>
  277. </div>
  278. </div>
  279. <div class="row g-3">
  280. <div class="col-md-12" style="text-align:right">
  281. <button class="btn--ui lightGrey" onclick="resetFilters(event)">Reset</button>
  282. <button class="btn--ui" onclick="event.preventDefault();loadDataTable()">FILTRA</button>
  283. </div>
  284. </div>
  285. <hr size="1">
  286. </div>
  287. </div>
  288. <div class="col-xs-12">
  289. <table id="recipients-table" class="table tablesaw tableHead tablesaw-stack w-100">
  290. <thead>
  291. <tr>
  292. <th></th>
  293. <th>Cognome</th>
  294. <th>Nome</th>
  295. <th>Email</th>
  296. <th>Telefono</th>
  297. <th>Età</th>
  298. <th>Anno</th>
  299. <th>Stato</th>
  300. <th>Certificato</th>
  301. <th>Gruppi</th>
  302. {{-- <th>Corsi</th> --}}
  303. </tr>
  304. </thead>
  305. <tbody></tbody>
  306. </table>
  307. </div>
  308. </div>
  309. {{-- Opzioni invio --}}
  310. <div class="row mb-5">
  311. <div class="col">
  312. <h4>Opzioni di Invio</h4>
  313. <div class="d-flex gap-3 comunication-send-options">
  314. <label class="form-check">
  315. <input class="form-check-input" type="radio" wire:model="mode" value="now">
  316. <i class="fas fa-envelope me-2"></i> <span>Invia subito</span>
  317. </label>
  318. <label class="form-check">
  319. <input class="form-check-input" type="radio" wire:model="mode" value="schedule">
  320. <i class="fas fa-clock me-2"></i> <span>Programma</span>
  321. </label>
  322. </div>
  323. </div>
  324. </div>
  325. @if(!$locked && $mode === 'schedule')
  326. <div class="row mb-5">
  327. <div class="col-md-6">
  328. <label for="scheduledDateTime" class="form-label">Data e Ora di Invio</label>
  329. <input type="datetime-local" class="form-control @error('schedule_at') is-invalid @enderror" id="scheduledDateTime" wire:model="schedule_at">
  330. @error('schedule_at') <div class="invalid-feedback">{{ $message }}</div> @enderror
  331. </div>
  332. </div>
  333. @endif
  334. <div class="form--item mt-5 mb-5 d-flex gap-2">
  335. @if(!$locked)
  336. <a class="btn--ui lightGrey" href="/sms_comunications">Annulla</a>
  337. <button type="button" class="btn--ui" onclick="submitSMS('draft')" style="margin-right: auto">Salva bozza</button>
  338. @if($mode==='now')
  339. <button type="button" class="btn--ui" onclick="submitSMS('send')">Invia ora</button>
  340. @else
  341. <button type="button" class="btn--ui" onclick="submitSMS('schedule')">Salva & Programma</button>
  342. @endif
  343. @else
  344. <a class="btn--ui lightGrey" href="/sms_comunications">Torna indietro</a>
  345. @endif
  346. </div>
  347. </form>
  348. </div>
  349. </div>
  350. </div>
  351. </section>
  352. <input type="hidden" name="timezone" id="timezone" wire:model="timezone">
  353. </div>
  354. @if (session()->has('success'))
  355. <div class="alert alert-success alert-dismissible fade show mt-3" role="alert">
  356. {{ session('success') }}
  357. <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
  358. </div>
  359. @endif
  360. @if (session()->has('error'))
  361. <div class="alert alert-danger alert-dismissible fade show mt-3" role="alert">
  362. {{ session('error') }}
  363. <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
  364. </div>
  365. @endif
  366. @push('scripts')
  367. <link href="/css/datatables.css" rel="stylesheet" />
  368. <script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
  369. <script src="/assets/js/datatables.js"></script>
  370. <script src="https://cdn.datatables.net/buttons/3.0.2/js/buttons.dataTables.js"></script>
  371. <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
  372. <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/pdfmake.min.js"></script>
  373. <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/vfs_fonts.js"></script>
  374. <link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
  375. <script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
  376. @endpush
  377. @push('scripts')
  378. <script type="text/javascript">
  379. document.addEventListener('livewire:load', () => {
  380. if (!$.fn.DataTable.isDataTable('#tablesaw-350')) {
  381. loadArchiveDataTable();
  382. }
  383. window.addEventListener('sms-deleted', (e) => {
  384. const id = e.detail?.id;
  385. const table = $('#tablesaw-350');
  386. if (!id || !$.fn.DataTable.isDataTable(table)) return;
  387. const dt = table.DataTable();
  388. const rowEl = document.getElementById('row_email_' + id);
  389. if (rowEl) {
  390. dt.row(rowEl).remove().draw(false);
  391. }
  392. });
  393. const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
  394. @this.set('timezone', tz);
  395. });
  396. window.addEventListener('init-recipients-table', (e) => {
  397. const selected = e.detail?.selected || [];
  398. loadDataTable(selected);
  399. const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
  400. @this.set('timezone', tz);
  401. });
  402. function loadArchiveDataTable(){
  403. let date = new Date();
  404. let date_export = `${date.getFullYear()}${date.getMonth()}${date.getDate()}_`;
  405. let table = $('#tablesaw-350').DataTable();
  406. if ( $.fn.DataTable.isDataTable('#tablesaw-350') ) {
  407. table.destroy();
  408. }
  409. $('#tablesaw-350').DataTable({
  410. processing: true,
  411. thead: {
  412. 'th': {'background-color': 'blue'}
  413. },
  414. order: [[7, 'desc']],
  415. layout: {
  416. topStart : null,
  417. topEnd : null,
  418. top1A: {
  419. // buttons: [
  420. // {
  421. // extend: 'collection',
  422. // text: 'ESPORTA',
  423. buttons: [
  424. {
  425. extend: 'excelHtml5',
  426. text: '<i class="fa-solid fa-file-excel"></i>',
  427. action: newexportaction,
  428. title: date_export + 'SMS',
  429. exportOptions: {
  430. columns: ":not(':last')"
  431. }
  432. },
  433. {
  434. extend: 'pdfHtml5',
  435. text: '<i class="fa-solid fa-file-pdf"></i>',
  436. action: newexportaction,
  437. title: date_export + 'SMS',
  438. exportOptions: {
  439. columns: ":not(':last')"
  440. }
  441. },
  442. {
  443. extend: 'print',
  444. action: newexportaction,
  445. text: '<i class="fa-solid fa-print"></i>',
  446. title: date_export + 'SMS',
  447. exportOptions: {
  448. columns: ":not(':last')"
  449. }
  450. }
  451. ],
  452. // dropup: true
  453. // }
  454. // ]
  455. },
  456. top1B : {
  457. pageLength: {
  458. menu: [[10, 25, 50, 100, 100000], [10, 25, 50, 100, "Tutti"]]
  459. }
  460. },
  461. top1C :'search',
  462. bottomEnd: {
  463. paging: {
  464. boundaryNumbers: false
  465. }
  466. }
  467. },
  468. pagingType: 'first_last_numbers',
  469. language: {
  470. "url": "/assets/js/Italian.json",
  471. paginate: {
  472. first: '<i class="fa-solid fa-angles-left"></i>',
  473. last: '<i class="fa-solid fa-angles-right"></i>',
  474. }
  475. },
  476. fnInitComplete: function (oSettings, json) {
  477. var html = '&nbsp;<a href="#" class="addData btn--ui"><i class="fa-solid fa-plus"></i></a>';
  478. $(".dt-search").append(html);
  479. }
  480. });
  481. $('#tablesaw-350 thead tr th').addClass('col').css("background-color", "#f6f8fa");
  482. $(document).on("click",".addData",function() {
  483. @this.add();
  484. });
  485. }
  486. $(document).on("click",".showHideFilter",function() {
  487. $(".showFilter").toggle();
  488. $('.filterCards,.filterStatus,.filterScadenza,.filterCertificateType,.filterCategories,.filterCourses').each(function(){
  489. $(this).select2({
  490. language: { noResults: ()=>"Nessun risultato" }
  491. });
  492. });
  493. });
  494. $(document).on("click", ".addRecipients", function() {
  495. $("#addRecipientsRow").toggle();
  496. });
  497. window.resetFilters = function(event){
  498. if (event) event.preventDefault();
  499. $('.filterCards').val('').trigger('change');
  500. $('.filterStatus').val('').trigger('change');
  501. $('.filterScadenza').val('-1').trigger('change');
  502. $('.filterCertificateType').val('-1').trigger('change');
  503. $('.filterCategories').val('-1').trigger('change');
  504. $('.filterCourses').val('-1').trigger('change');
  505. $('input[name="txtFromYear"]').val('');
  506. $('input[name="txtToYear"]').val('');
  507. $('input[name="txtFromYearYear"]').val('');
  508. $('input[name="txtToYearYear"]').val('');
  509. loadDataTable();
  510. }
  511. function loadDataTable(preselected = []) {
  512. const selectedIds = new Set((preselected || []).map(x => parseInt(x, 10)).filter(Boolean));
  513. if ($.fn.DataTable.isDataTable('#recipients-table')) {
  514. $('#recipients-table').DataTable().destroy();
  515. }
  516. var fromYear = $('input[name="txtFromYear"]').val();
  517. var toYear = $('input[name="txtToYear"]').val();
  518. var fromYearYear = $('input[name="txtFromYearYear"]').val();
  519. var toYearYear = $('input[name="txtToYearYear"]').val();
  520. var filterCards = $('.filterCards').val();
  521. var filterStatus = $('.filterStatus').val();
  522. var filterScadenza = $('.filterScadenza').val();
  523. var filterCertificateType = $('.filterCertificateType').val();
  524. var filterCategories = $('.filterCategories').val();
  525. var filterCourses = $('.filterCourses').val();
  526. const dataTable = $('#recipients-table').DataTable({
  527. serverSide: true,
  528. ajax: '/get_recipients?cards=' + filterCards + "&filterCategories=" + filterCategories + "&filterCertificateType=" + filterCertificateType + "&filterScadenza=" + filterScadenza + "&filterStatus=" + filterStatus + "&fromYear=" + fromYear + "&toYear=" + toYear + "&fromYearYear=" + fromYearYear + "&toYearYear=" + toYearYear + "&filterCourses=" + (filterCourses || ""),
  529. columns: [
  530. {
  531. orderable: false,
  532. data: "id",
  533. render: function (data){
  534. const id = parseInt(data, 10);
  535. const checked = selectedIds.has(id) ? 'checked' : '';
  536. return `<input type="checkbox" value="${id}" ${checked} onclick="toggleRecipient(${id})" id="recipient_${id}"/>`;
  537. }
  538. },
  539. {
  540. data: "last_name",
  541. render: function (data){
  542. const d = data.split("|");
  543. const id = d[1], value = d[0];
  544. return `<label for="recipient_${id}">${value}</label>`;
  545. }
  546. },
  547. {
  548. data: "first_name",
  549. render: function (data){
  550. const d = data.split("|");
  551. const id = d[1], value = d[0];
  552. return `<label for="recipient_${id}">${value}</label>`;
  553. }
  554. },
  555. {
  556. data: "email",
  557. render: function (data){
  558. const d = data.split("|");
  559. const id = d[1], value = d[0];
  560. return `<label for="recipient_${id}">${value}</label>`;
  561. }
  562. },
  563. { data: "phone"},
  564. { data: "age", "type": "num", className:"dt-type-numeric"},
  565. { data: "year", className:"dt-type-numeric"},
  566. {
  567. data: "status",
  568. render: function (data){
  569. const d = data.split("|");
  570. return '<span class="tablesaw-cell-content"><span class="badge tessera-badge ' + d[0] + '">' + d[1] + '</span></span>';
  571. }
  572. },
  573. {
  574. data: "certificate",
  575. render: function (data){
  576. if (!data) return '<span class="tablesaw-cell-content d-flex align-items-center"><i class="ico--ui check absent me-2"></i>Non consegnato</span>';
  577. const d = data.split("|");
  578. const icon = d[0] === "0" ? "suspended" : (d[0] === "1" ? "due" : "active");
  579. const label = d[0] === "0" ? "Scaduto" : (d[0] === "1" ? "In scadenza" : "Scadenza");
  580. return '<span class="tablesaw-cell-content d-flex align-items-center"><i class="ico--ui check '+icon+' me-2"></i>'+label+' : '+d[1]+'</span>';
  581. }
  582. },
  583. { data: "categories" },
  584. ],
  585. order: [
  586. [1, 'asc']
  587. ],
  588. fixedHeader: false,
  589. thead: {
  590. 'th': {'background-color': 'blue'}
  591. },
  592. layout: {
  593. topStart : null,
  594. topEnd : null,
  595. top1A: null,
  596. top1B : {
  597. pageLength: {
  598. menu: [[10, 25, 50, 100, 100000], [10, 25, 50, 100, "Tutti"]]
  599. }
  600. },
  601. top1C :'search',
  602. bottomEnd: {
  603. paging: {
  604. boundaryNumbers: false
  605. }
  606. }
  607. },
  608. pagingType: 'first_last_numbers',
  609. language: {
  610. "url": "/assets/js/Italian.json",
  611. paginate: {
  612. first: '<i class="fa-solid fa-angles-left"></i>',
  613. last: '<i class="fa-solid fa-angles-right"></i>',
  614. }
  615. },
  616. fnInitComplete: function (oSettings, json) {
  617. var html = '&nbsp;<a style="cursor:pointer" class="showHideFilter btn--ui"><i class="fa-solid fa-sliders"></i></a>';
  618. $(".dt-search").append(html);
  619. }
  620. });
  621. $('#recipients-table thead tr th').addClass('col').css("background-color", "#f6f8fa");
  622. $('#recipients-table').on('draw.dt', function() { $('[data-bs-toggle="popover"]').popover() });
  623. }
  624. window.toggleRecipient = function(id) { @this.toggleRecipient(id); }
  625. window.submitSMS = function(action){
  626. if (action === 'draft') {
  627. @this.call('saveDraft');
  628. } else if (action === 'send') {
  629. @this.call('sendNow');
  630. } else {
  631. @this.call('scheduleMessage');
  632. }
  633. };
  634. window.addEventListener("scroll-top", (e) => {
  635. let wrapper = document.querySelector('#card--dashboard');
  636. if (wrapper) {
  637. wrapper.scrollTo({top: 0, behavior: 'smooth'});
  638. }
  639. });
  640. </script>
  641. {{-- END CKEditor --}}
  642. @endpush