records.blade.php 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222
  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">Prima nota</h2>
  6. </div>
  7. </header>
  8. <section id="subheader" class="">
  9. <div class="row g-3">
  10. <div class="col-md-3">
  11. Utente
  12. <select name="search_member_id" class="form-select filterMember" wire:model="filterMember">
  13. <option value="">--Seleziona--
  14. @foreach($members as $member)
  15. <option value="{{$member->id}}">{{$member->last_name}} {{$member->first_name}}
  16. @endforeach
  17. </select>
  18. </div>
  19. <div class="col-md-4">
  20. Causale
  21. <select name="search_causal_id[]" class="form-select filterCausals me-2" multiple="multiple" wire:model="filterCausals">
  22. @foreach($causals as $causal)
  23. <option value="{{$causal["id"]}}">{!!$causal["name"]!!}
  24. @endforeach
  25. </select>
  26. </div>
  27. <div class="col-md-2">
  28. Periodo
  29. <select wire:model="selectedPeriod" class="form-select" @if($isFiltering) disabled @endif style="height: 43px!important;">
  30. <option value="OGGI">Oggi</option>
  31. <option value="IERI">Ieri</option>
  32. <option value="MESE CORRENTE">Mese Corrente</option>
  33. <option value="MESE PRECEDENTE">Mese Precedente</option>
  34. <option value="ULTIMO TRIMESTRE">Ultimo Trimestre</option>
  35. <option value="ULTIMO QUADRIMESTRE">Ultimo Quadrimestre</option>
  36. </select>
  37. </div>
  38. <div class="col-md-3">
  39. <div class="prima--nota_buttons ms-auto" style="float:right; margin-top:25px;">
  40. <button class="btn--ui primary" wire:click="applyFilters" style="margin-right:5px;" @if($isFiltering) disabled @endif>
  41. @if($isFiltering)
  42. <i class="fas fa-spinner fa-spin"></i> CARICAMENTO...
  43. @else
  44. FILTRA
  45. @endif
  46. </button>
  47. <button class="btn--ui lightGrey reset reset" style="margin-left:5px;color:#10172A;" wire:click="resetFilters" @if($isFiltering) disabled @endif>RESET</button>
  48. </div>
  49. </div>
  50. </div>
  51. <div style="float:left; margin-top:10px; margin-bottom:10px;">
  52. {{-- <div class="dropdown">
  53. <button class="btn--ui_outline light dropdown-toggle" type="button" id="exportDropdown" data-bs-toggle="dropdown" aria-expanded="false"
  54. style="color:#10172A;" @if($isFiltering) disabled @endif>
  55. ESPORTA
  56. </button>
  57. <ul class="dropdown-menu" aria-labelledby="exportDropdown">
  58. <li><a class="dropdown-item" href="#" wire:click="openExportModal">Excel</a></li>
  59. <li><a class="dropdown-item" href="#" id="print">Stampa</a></li>
  60. </ul>
  61. </div> --}}
  62. <div class="dt-buttons btn-group flex-wrap">
  63. <button class="btn btn-secondary buttons-excel buttons-html5" tabindex="0" type="button" wire:click="openExportModal" style="border-top-right-radius: 0 !important;border-bottom-right-radius: 0 !important;">
  64. <span><i class="fa-solid fa-file-excel"></i></span>
  65. </button>
  66. <button class="btn btn-secondary buttons-print" tabindex="0" type="button" id="print" style="border-top-left-radius: 0 !important;border-bottom-left-radius: 0 !important;">
  67. <span><i class="fa-solid fa-print"></i></span>
  68. </button>
  69. </div>
  70. </div>
  71. </section>
  72. <section id="resume-table" class="scrollTable records-table" style="position: relative;">
  73. @if($isFiltering)
  74. <div class="loading-overlay">
  75. <div class="loading-content">
  76. <i class="fas fa-spinner fa-spin fa-3x"></i>
  77. <p>Caricamento dati in corso...</p>
  78. </div>
  79. </div>
  80. @endif
  81. <table class="table tablesaw tableHead tablesaw-stack" id="tablesaw-350" width="100%">
  82. <thead>
  83. <tr>
  84. <th scope="col">Data</th>
  85. <th scope="col" style="border-left:3px solid white;">Causale</th>
  86. <th scope="col" style="border-left:3px solid white;">Dettaglio Causale</th>
  87. <th scope="col" style="border-left:3px solid white;">Stato</th>
  88. <th scope="col" style="border-left:3px solid white;">Nominativo</th>
  89. @foreach($payments as $p)
  90. <th colspan="2" scope="col" style="text-align:center; border-left:3px solid white;">{{$p->name}}</th>
  91. @endforeach
  92. </tr>
  93. <tr>
  94. <th scope="col"></th>
  95. <th scope="col" style="border-left:3px solid white;"></th>
  96. <th scope="col" style="border-left:3px solid white;"></th>
  97. <th scope="col" style="border-left:3px solid white;"></th>
  98. <th scope="col" style="border-left:3px solid white;"></th>
  99. @foreach($payments as $p)
  100. @if($p->type == 'ALL')
  101. <th scope="col" style="text-align:center; border-left:3px solid white;">Entrate</th>
  102. <th scope="col" style="text-align:center">Uscite</th>
  103. @elseif($p->type == 'IN')
  104. <th scope="col" style="text-align:center; border-left:3px solid white;">Entrate</th>
  105. <th scope="col" style="text-align:center;"></th>
  106. @elseif($p->type == 'OUT')
  107. <th style="border-left:3px solid white;"></th>
  108. <th scope="col" style="text-align:center;">Uscite</th>
  109. @endif
  110. @endforeach
  111. </tr>
  112. </thead>
  113. <tbody id="checkall-target">
  114. @php $count = 0; @endphp
  115. @foreach($records as $causal => $record)
  116. <tr>
  117. @php
  118. $parts = explode("§", $causal);
  119. $d = $parts[0] ?? '';
  120. $c = $parts[1] ?? '';
  121. $n = $parts[2] ?? '';
  122. $det = $parts[3] ?? '';
  123. $del = $parts[4] ?? '';
  124. $detailParts = explode('|', $det);
  125. $isMultiple = count($detailParts) > 1;
  126. $displayDetail = $isMultiple ? 'Varie' : $det;
  127. @endphp
  128. <td style="background-color:{{$count % 2 == 0 ? 'white' : '#f2f4f7'}}">{{date("d/m/Y", strtotime($d))}}</td>
  129. <td style="border-left:3px solid white !important;background-color:{{$count % 2 == 0 ? 'white' : '#f2f4f7'}}">{{$c}}</td>
  130. <td style="border-left:3px solid white !important;background-color:{{$count % 2 == 0 ? 'white' : '#f2f4f7'}}">
  131. @if($isMultiple)
  132. <span class="varie-link" data-causals="{{implode('|', array_slice($detailParts, 1))}}" style="color: var(--color-blu); cursor: pointer; text-decoration: underline;">
  133. {{$displayDetail}}
  134. </span>
  135. @else
  136. {{$displayDetail}}
  137. @endif
  138. </td>
  139. <td style="border-left:3px solid white !important;background-color:{{$count % 2 == 0 ? 'white' : '#f2f4f7'}}">
  140. @if($del == 'DELETED')
  141. <span style='color:red'>Annullata</span>
  142. @endif
  143. </td>
  144. <td style="border-left:3px solid white !important;background-color:{{$count % 2 == 0 ? 'white' : '#f2f4f7'}}">{{$n}}</td>
  145. @foreach($payments as $p)
  146. @if(isset($record[$p->name]))
  147. <td style="text-align:right; border-left:3px solid white !important;background-color:{{$count % 2 == 0 ? 'white' : '#f2f4f7'}}">
  148. @if(isset($record[$p->name]["IN"]))
  149. <span class="tablesaw-cell-content " style="color:green">{{formatPrice($record[$p->name]["IN"])}}</span>
  150. @endif
  151. </td>
  152. <td style="text-align:right;background-color:{{$count % 2 == 0 ? 'white' : '#f2f4f7'}}">
  153. @if(isset($record[$p->name]["OUT"]))
  154. <span class="tablesaw-cell-content " style="color:red">{{formatPrice($record[$p->name]["OUT"])}}</span>
  155. @endif
  156. </td>
  157. @else
  158. <td style="border-left:3px solid white !important;background-color:{{$count % 2 == 0 ? 'white' : '#f2f4f7'}}"></td>
  159. <td style="background-color:{{$count % 2 == 0 ? 'white' : '#f2f4f7'}}"></td>
  160. @endif
  161. @endforeach
  162. </tr>
  163. @php $count++; @endphp
  164. @endforeach
  165. </tbody>
  166. <tfoot>
  167. <tr>
  168. <td></td>
  169. <td></td>
  170. <td></td>
  171. <td></td>
  172. <td><b>Totale</b></td>
  173. @foreach($payments as $p)
  174. @if(isset($totals[$p->name]))
  175. @if($p->type == 'ALL')
  176. <td style="text-align:right"><span class="tablesaw-cell-content primary" style="color:green; font-size:18px;"><b>{{formatPrice(isset($totals[$p->name]) ? $totals[$p->name]["IN"] : 0)}}</b></span></td>
  177. <td style="text-align:right"><span class="tablesaw-cell-content primary" style="color:red; font-size:18px;"><b>{{formatPrice(isset($totals[$p->name]) ? $totals[$p->name]["OUT"] : 0)}}</b></span></td>
  178. @elseif($p->type == 'IN')
  179. <td style="text-align:right"><span class="tablesaw-cell-content primary" style="color:green; font-size:18px;"><b>{{formatPrice(isset($totals[$p->name]) ? $totals[$p->name]["IN"] : 0)}}</b></span></td>
  180. <td style="text-align:right"><span class="tablesaw-cell-content primary" style="color:red; font-size:18px;"><b>&nbsp;</b></span></td>
  181. @elseif($p->type == 'OUT')
  182. <td style="text-align:right"><span class="tablesaw-cell-content primary" style="color:green; font-size:18px;"><b>&nbsp;</b></span></td>
  183. <td style="text-align:right"><span class="tablesaw-cell-content primary" style="color:red; font-size:18px;"><b>{{formatPrice(isset($totals[$p->name]) ? $totals[$p->name]["OUT"] : 0)}}</b></span></td>
  184. @endif
  185. @else
  186. @if($p->type == 'ALL')
  187. <td style="text-align:right"><span class="tablesaw-cell-content primary" style="color:green; font-size:18px;"><b>{{formatPrice(isset($totals[$p->name]) ? $totals[$p->name]["IN"] : 0)}}</b></span></td>
  188. <td style="text-align:right"><span class="tablesaw-cell-content primary" style="color:red; font-size:18px;"><b>{{formatPrice(isset($totals[$p->name]) ? $totals[$p->name]["OUT"] : 0)}}</b></span></td>
  189. @elseif($p->type == 'IN')
  190. <td style="text-align:right"><span class="tablesaw-cell-content primary" style="color:green; font-size:18px;"><b>{{formatPrice(isset($totals[$p->name]) ? $totals[$p->name]["IN"] : 0)}}</b></span></td>
  191. <td style="text-align:center"><span class="tablesaw-cell-content primary" style="color:red; font-size:18px;"><b>&nbsp;</b></span></td>
  192. @elseif($p->type == 'OUT')
  193. <td style="text-align:right"><span class="tablesaw-cell-content primary" style="color:green; font-size:18px;"><b>&nbsp;</b></span></td>
  194. <td style="text-align:center"><span class="tablesaw-cell-content primary" style="color:red; font-size:18px;"><b>{{formatPrice(isset($totals[$p->name]) ? $totals[$p->name]["OUT"] : 0)}}</b></span></td>
  195. @endif
  196. @endif
  197. @endforeach
  198. </tr>
  199. <tr style="display:none">
  200. <td></td>
  201. <td><b>Differenza</b></td>
  202. @foreach($payments as $p)
  203. @if(isset($totals[$p->name]))
  204. @php
  205. $diff = $totals[$p->name]["IN"] - $totals[$p->name]["OUT"];
  206. @endphp
  207. @if($diff < 0)
  208. <td></td>
  209. @endif
  210. <td style="text-align:right"><span class="tablesaw-cell-content primary" style="color:{{$diff > 0 ? 'green' : 'red'}}; font-size:18px;"><b>{{formatPrice($diff)}}</b></span></td>
  211. @if($diff > 0)
  212. <td></td>
  213. @endif
  214. @else
  215. <td colspan="2" style="text-align:right"><b>{{formatPrice(0)}}</b></td>
  216. @endif
  217. @endforeach
  218. </tr>
  219. </tfoot>
  220. </table>
  221. <button type="button" class="btn btn-floating btn-lg" id="btn-back-to-bottom"><i class="fas fa-arrow-down"></i></button>
  222. <button type="button" class="btn btn-floating btn-lg" id="btn-back-to-top"><i class="fas fa-arrow-up"></i></button>
  223. </section>
  224. <div class="modal fade" id="causalsModal" tabindex="-1" aria-labelledby="causalsModalLabel" aria-hidden="true">
  225. <div class="modal-dialog modal-lg">
  226. <div class="modal-content">
  227. <div class="modal-header modal-header-blu">
  228. <h5 class="modal-title" id="causalsModalLabel">
  229. <i class="me-2"></i>
  230. Dettaglio Causali
  231. </h5>
  232. <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="CHIUDI"></button>
  233. </div>
  234. <div class="modal-body">
  235. <div class="row">
  236. <div class="col-12">
  237. <div class="d-flex justify-content-between align-items-center mb-3">
  238. <h6 class="mb-0">
  239. <i class="me-2 text-primary"></i>
  240. Causali incluse:
  241. </h6>
  242. </div>
  243. <div class="border rounded" style="max-height: 400px; overflow-y: auto;">
  244. <ul id="causalsList" class="list-group list-group-flush mb-0">
  245. <!-- Causals will be populated here by JavaScript -->
  246. </ul>
  247. </div>
  248. </div>
  249. </div>
  250. </div>
  251. <div class="modal-footer" style="background-color: #FFF!important;">
  252. <button type="button" class="btn--ui lightGrey me-2" data-bs-dismiss="modal">CHIUDI</button>
  253. </div>
  254. </div>
  255. </div>
  256. </div>
  257. <div class="modal fade" id="exportModal" tabindex="-1" aria-labelledby="exportModalLabel" aria-hidden="true">
  258. <div class="modal-dialog">
  259. <div class="modal-content">
  260. <div class="modal-header modal-header-blu">
  261. <h5 class="modal-title" id="exportModalLabel">Seleziona Periodo per Export</h5>
  262. <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="CHIUDI"></button>
  263. </div>
  264. <div class="modal-body">
  265. <div class="row g-3">
  266. <div class="col-md-6">
  267. <label for="exportFromDate" class="form-label">Data Inizio</label>
  268. <input type="date" class="form-control" id="exportFromDate" wire:model.defer="exportFromDate">
  269. </div>
  270. <div class="col-md-6">
  271. <label for="exportToDate" class="form-label">Data Fine</label>
  272. <input type="date" class="form-control" id="exportToDate" wire:model.defer="exportToDate">
  273. </div>
  274. </div>
  275. <div class="row mt-4">
  276. <div class="col-12">
  277. <div class="form-check export-method-check">
  278. <input class="form-check-input" type="checkbox" id="sendViaEmail" wire:model.defer="sendViaEmail">
  279. <label class="form-check-label" for="sendViaEmail">
  280. <i class="fas fa-envelope me-2"></i>Invia via Email
  281. <small class="d-block text-muted mt-1">L'export verrà elaborato in background e inviato alla tua email</small>
  282. </label>
  283. </div>
  284. </div>
  285. </div>
  286. <div class="row mt-3" style="display: none;" id="emailAddressRow">
  287. <div class="col-12">
  288. <label for="exportEmailAddress" class="form-label">
  289. <i class="fas fa-envelope me-1"></i>Indirizzo Email
  290. </label>
  291. <input type="email" class="form-control" id="exportEmailAddress"
  292. wire:model.defer="exportEmailAddress"
  293. placeholder="inserisci@email.com">
  294. <div class="invalid-feedback" id="emailValidationFeedback">
  295. Inserisci un indirizzo email valido
  296. </div>
  297. <small class="form-text text-muted">
  298. Il file Excel verrà inviato a questo indirizzo
  299. </small>
  300. </div>
  301. </div>
  302. <div class="row mt-3" style="display: none;" id="emailSubjectRow">
  303. <div class="col-12">
  304. <label for="exportEmailSubject" class="form-label">
  305. <i class="fas fa-tag me-1"></i>Oggetto Email
  306. </label>
  307. <input type="text" class="form-control" id="exportEmailSubject"
  308. wire:model.defer="exportEmailSubject"
  309. placeholder="Prima Nota - Export">
  310. <small class="form-text text-muted">
  311. Personalizza l'oggetto dell'email
  312. </small>
  313. </div>
  314. </div>
  315. <div class="row mt-3">
  316. <div class="col-12">
  317. <div class="alert alert-info d-flex align-items-start">
  318. <i class="fas fa-info-circle me-2 mt-1"></i>
  319. <div>
  320. <strong>Informazioni Export:</strong>
  321. <ul class="mb-0 mt-1">
  322. <li>L'export includerà tutti i record nel periodo selezionato</li>
  323. <li>Verranno applicati i filtri attualmente attivi</li>
  324. <li id="emailProcessingInfo" style="display: none;">L'elaborazione avverrà in background, potrai continuare a usare l'applicazione</li>
  325. </ul>
  326. </div>
  327. </div>
  328. </div>
  329. </div>
  330. </div>
  331. <div class="modal-footer" style="background-color: #FFF!important;">
  332. <button type="button" class="btn--ui lightGrey me-2" data-bs-dismiss="modal">ANNULLA</button>
  333. <button type="button" class="btn--ui primary" onclick="handleExportClick()" id="exportButton">
  334. <span id="loadingState" style="display: none;">
  335. <div class="spinner-border spinner-border-sm me-2" role="status">
  336. <span class="visually-hidden">Loading...</span>
  337. </div>
  338. ELABORAZIONE...
  339. </span>
  340. <span id="normalState">
  341. <i class="fas fa-download me-1"></i>
  342. ESPORTA
  343. </span>
  344. </button>
  345. </div>
  346. </div>
  347. </div>
  348. </div>
  349. <div class="toast-container position-fixed top-0 end-0 p-3" style="z-index: 11000;">
  350. <!-- Toasts will be dynamically added here -->
  351. </div>
  352. </div>
  353. @push('scripts')
  354. <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
  355. @endpush
  356. @push('scripts')
  357. <link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
  358. <style>
  359. .loading-overlay {
  360. position: absolute;
  361. top: 0;
  362. left: 0;
  363. right: 0;
  364. bottom: 0;
  365. background-color: rgba(255, 255, 255, 0.9);
  366. display: flex;
  367. justify-content: center;
  368. align-items: center;
  369. z-index: 1000;
  370. border-radius: 4px;
  371. }
  372. .loading-content {
  373. text-align: center;
  374. color: var(--color-blu);
  375. }
  376. .loading-content i {
  377. margin-bottom: 15px;
  378. color: var(--color-blu);
  379. }
  380. .loading-content p {
  381. margin: 0;
  382. font-size: 16px;
  383. font-weight: 500;
  384. color: #10172A;
  385. }
  386. .modal {
  387. z-index: 9999 !important;
  388. }
  389. .modal-backdrop {
  390. z-index: 9998 !important;
  391. background-color: rgba(0, 0, 0, 0.6) !important;
  392. }
  393. .modal-content {
  394. border-radius: 8px;
  395. border: none;
  396. box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
  397. z-index: 10000 !important;
  398. }
  399. .modal-header {
  400. color: white;
  401. border-bottom: none;
  402. border-radius: 8px 8px 0 0;
  403. }
  404. .modal-header .btn-close {
  405. filter: invert(1);
  406. }
  407. .modal-title {
  408. font-weight: 600;
  409. }
  410. .varie-link:hover {
  411. color: #084c6b !important;
  412. text-decoration: underline !important;
  413. }
  414. #btn-back-to-top {
  415. background-color: var(--color-blu);
  416. color: white;
  417. position: fixed;
  418. display: none;
  419. }
  420. #btn-back-to-bottom {
  421. background-color: var(--color-blu);
  422. color: white;
  423. position: fixed;
  424. z-index: 9999;
  425. display: none;
  426. }
  427. button[disabled] {
  428. opacity: 0.7;
  429. cursor: not-allowed;
  430. }
  431. .btn--ui .fa-spinner {
  432. margin-right: 5px;
  433. }
  434. .scrollTable {
  435. margin-left: 0px;
  436. margin-right: 0px;
  437. padding: 15px;
  438. overflow-x: auto;
  439. overflow-y: auto;
  440. white-space: nowrap;
  441. border: 1px solid #ddd;
  442. }
  443. ::-webkit-scrollbar-thumb {
  444. background: #e4e4e4;
  445. border-radius: 10px;
  446. }
  447. table thead {
  448. position: sticky;
  449. z-index: 100;
  450. top: 0;
  451. }
  452. .select2-container--default .select2-selection--single {
  453. background-color: #E9F0F5;
  454. border: 0.0625rem solid #DFE5EB;
  455. font-size: 0.75rem;
  456. height: 38px !important;
  457. }
  458. .select2-selection__rendered {
  459. padding-top: 3px;
  460. }
  461. .select2 {
  462. width: 100% !important;
  463. }
  464. .select2-selection--multiple {
  465. overflow: hidden !important;
  466. height: auto !important;
  467. }
  468. .select2-container {
  469. box-sizing: border-box;
  470. display: inline-block;
  471. margin: 0;
  472. position: relative;
  473. vertical-align: middle;
  474. z-index: 999 !important;
  475. }
  476. .select2-dropdown {
  477. z-index: 999 !important;
  478. }
  479. .select2-container .select2-selection--single {
  480. box-sizing: border-box;
  481. cursor: pointer;
  482. display: block;
  483. height: 38px;
  484. user-select: none;
  485. -webkit-user-select: none;
  486. }
  487. .select2-container .select2-selection--single .select2-selection__rendered {
  488. display: block;
  489. padding-left: 8px;
  490. padding-right: 20px;
  491. overflow: hidden;
  492. text-overflow: ellipsis;
  493. white-space: nowrap;
  494. }
  495. button#exportDropdown.btn--ui_outline.light {
  496. font-weight: normal !important;
  497. }
  498. .btn--ui_outline.light.dropdown-toggle:active,
  499. .btn--ui_outline.light.dropdown-toggle:focus,
  500. .btn--ui_outline.light.dropdown-toggle.show {
  501. background-color: transparent !important;
  502. color: #10172A !important;
  503. box-shadow: none !important;
  504. }
  505. .btn--ui_outline.light.dropdown-toggle:hover {
  506. background-color: transparent !important;
  507. color: #10172A !important;
  508. }
  509. .form-select {
  510. height: 38px !important;
  511. }
  512. .form-control {
  513. height: 43px !important;
  514. }
  515. #exportModal .modal-body {
  516. padding: 1.5rem;
  517. }
  518. #exportModal .form-label {
  519. font-weight: 600;
  520. color: #10172A;
  521. margin-bottom: 0.5rem;
  522. }
  523. #exportModal .text-muted {
  524. font-size: 0.875rem;
  525. }
  526. .btn--ui[disabled] .fa-spinner {
  527. margin-right: 0.5rem;
  528. }
  529. body.modal-open {
  530. overflow: hidden;
  531. }
  532. .modal-dialog {
  533. z-index: 10001 !important;
  534. margin: 1.75rem auto;
  535. }
  536. .list-group-item {
  537. border-left: none;
  538. border-right: none;
  539. border-top: 1px solid #dee2e6;
  540. padding: 12px 15px;
  541. }
  542. .list-group-item:first-child {
  543. border-top: none;
  544. }
  545. .list-group-item:last-child {
  546. border-bottom: none;
  547. }
  548. @media (max-width: 768px) {
  549. .col-md-2, .col-md-3, .col-md-4 {
  550. margin-bottom: 10px;
  551. }
  552. .prima--nota_buttons {
  553. float: none !important;
  554. margin-top: 10px !important;
  555. text-align: center;
  556. }
  557. }
  558. .export-method-check {
  559. padding: 16px 16px 16px 50px;
  560. background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
  561. border-radius: 8px;
  562. border: 2px solid #e9ecef;
  563. transition: all 0.3s ease;
  564. cursor: pointer;
  565. position: relative;
  566. }
  567. .export-method-check:hover {
  568. border-color: var(--color-blu);
  569. background: linear-gradient(135deg, #e8f4f8 0%, #d1ecf1 100%);
  570. }
  571. .export-method-check .form-check-input {
  572. position: absolute;
  573. left: 16px;
  574. top: 50%;
  575. transform: translateY(-50%);
  576. margin: 0;
  577. width: 20px;
  578. height: 20px;
  579. background-color: #fff;
  580. border: 2px solid #dee2e6;
  581. border-radius: 4px;
  582. cursor: pointer;
  583. }
  584. .export-method-check .form-check-input:checked {
  585. background-color: var(--color-blu);
  586. border-color: var(--color-blu);
  587. }
  588. .export-method-check .form-check-input:checked ~ .form-check-label {
  589. color: var(--color-blu);
  590. font-weight: 600;
  591. }
  592. .export-method-check .form-check-label {
  593. font-weight: 500;
  594. color: #495057;
  595. cursor: pointer;
  596. margin-left: 0;
  597. display: block;
  598. }
  599. .form-check-input:focus {
  600. border-color: var(--color-blu);
  601. outline: 0;
  602. box-shadow: 0 0 0 0.2rem rgba(12, 97, 151, 0.25);
  603. }
  604. #emailAddressRow.show, #emailSubjectRow.show {
  605. display: block !important;
  606. animation: slideDown 0.3s ease-out;
  607. }
  608. @keyframes slideDown {
  609. from {
  610. opacity: 0;
  611. transform: translateY(-10px);
  612. }
  613. to {
  614. opacity: 1;
  615. transform: translateY(0);
  616. }
  617. }
  618. .invalid-feedback {
  619. display: none;
  620. }
  621. .is-invalid ~ .invalid-feedback {
  622. display: block;
  623. }
  624. .alert-info {
  625. background-color: rgba(12, 97, 151, 0.1);
  626. border-color: rgba(12, 97, 151, 0.2);
  627. color: var(--color-blu);
  628. }
  629. .spinner-border-sm {
  630. width: 1rem;
  631. height: 1rem;
  632. }
  633. .toast {
  634. min-width: 300px;
  635. }
  636. .toast-body {
  637. font-weight: 500;
  638. }
  639. .btn--ui:disabled {
  640. opacity: 0.7;
  641. cursor: not-allowed;
  642. }
  643. .list-group-item {
  644. border-left: none;
  645. border-right: none;
  646. border-top: 1px solid #dee2e6;
  647. padding: 12px 15px;
  648. }
  649. .list-group-item:first-child {
  650. border-top: none;
  651. }
  652. .list-group-item:last-child {
  653. border-bottom: none;
  654. }
  655. /* Enhanced styles for the causal modal with amounts */
  656. .list-group-item.d-flex {
  657. display: flex !important;
  658. justify-content: space-between !important;
  659. align-items: center !important;
  660. }
  661. .list-group-item .badge {
  662. font-size: 0.875rem;
  663. font-weight: 600;
  664. }
  665. .list-group-item:hover {
  666. background-color: rgba(12, 97, 151, 0.05);
  667. transition: background-color 0.2s ease;
  668. }
  669. #causalsModal .modal-body {
  670. padding: 1rem 0;
  671. }
  672. </style>
  673. <script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
  674. <script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
  675. <script src="/assets/js/aCollapTable.js"></script>
  676. @endpush
  677. @push('scripts')
  678. <script>
  679. function closeSelect2Dropdowns() {
  680. $('.filterCausals').each(function() {
  681. if ($(this).hasClass('select2-hidden-accessible')) {
  682. $(this).select2('close');
  683. }
  684. });
  685. $('.filterMember').each(function() {
  686. if ($(this).hasClass('select2-hidden-accessible')) {
  687. $(this).select2('close');
  688. }
  689. });
  690. }
  691. function load() {
  692. $(document).ready(function(){
  693. $(document).on("keypress", $('.filterCausals'), function (e) {
  694. setTimeout(() => {
  695. $(".select2-results__option").each(function(){
  696. var txt = $(this).html();
  697. var count = (txt.match(/-/g) || []).length;
  698. $(this).addClass('paddingLeftSelect' + count);
  699. });
  700. }, 100);
  701. });
  702. if (!$('.filterCausals').hasClass('select2-hidden-accessible')) {
  703. $('.filterCausals').select2({
  704. "language": {"noResults": function(){return "Nessun risultato";}},
  705. "dropdownParent": $('body'),
  706. "width": "100%"
  707. });
  708. }
  709. $('.filterCausals').off('change.customHandler').on('change.customHandler', function (e) {
  710. var data = $('.filterCausals').select2("val");
  711. @this.set('filterCausals', data);
  712. });
  713. $('.filterCausals').off('select2:open.customHandler').on('select2:open.customHandler', function (e) {
  714. if ($('#causalsModal').hasClass('show')) {
  715. $('#causalsModal').modal('hide');
  716. }
  717. setTimeout(() => {
  718. $(".select2-results__option").each(function(){
  719. var txt = $(this).html();
  720. var count = (txt.match(/-/g) || []).length;
  721. $(this).addClass('paddingLeftSelect' + count);
  722. });
  723. }, 100);
  724. });
  725. if (!$('.filterMember').hasClass('select2-hidden-accessible')) {
  726. $('.filterMember').select2({
  727. "language": {"noResults": function(){return "Nessun risultato";}},
  728. "dropdownParent": $('body'),
  729. "width": "100%"
  730. });
  731. }
  732. $('.filterMember').off('change.customHandler').on('change.customHandler', function (e) {
  733. var data = $('.filterMember').select2("val");
  734. @this.set('filterMember', data);
  735. });
  736. $('.filterMember').off('select2:open.customHandler').on('select2:open.customHandler', function (e) {
  737. if ($('#causalsModal').hasClass('show')) {
  738. $('#causalsModal').modal('hide');
  739. }
  740. });
  741. });
  742. }
  743. function printData() {
  744. var divToPrint = document.getElementById("tablesaw-350");
  745. newWin = window.open("");
  746. var htmlToPrint = '' +
  747. '<style type="text/css">' +
  748. 'table th, table td {' +
  749. 'border:1px solid #000;' +
  750. 'padding:0.5em;' +
  751. '}' +
  752. '</style>';
  753. htmlToPrint += divToPrint.outerHTML;
  754. newWin.document.write(htmlToPrint);
  755. newWin.document.close();
  756. newWin.print();
  757. newWin.close();
  758. }
  759. function scrollFunction() {
  760. const element = document.getElementById('resume-table');
  761. const mybuttonBottom = document.getElementById("btn-back-to-bottom");
  762. const mybutton = document.getElementById("btn-back-to-top");
  763. if (element.scrollTop > 20) {
  764. mybutton.style.display = "block";
  765. mybuttonBottom.style.display = "block";
  766. } else {
  767. mybutton.style.display = "none";
  768. mybuttonBottom.style.display = "none";
  769. }
  770. }
  771. function backToTop() {
  772. $('#resume-table').scrollTop(0);
  773. }
  774. function backToBottom() {
  775. $('#resume-table').scrollTop($('#resume-table')[0].scrollHeight);
  776. }
  777. $(document).ready(function() {
  778. load();
  779. document.querySelector("#print").addEventListener("click", function(){
  780. printData();
  781. });
  782. const element = document.getElementById('resume-table');
  783. element.onscroll = scrollFunction;
  784. const mybuttonBottom = document.getElementById("btn-back-to-bottom");
  785. const mybutton = document.getElementById("btn-back-to-top");
  786. mybutton.addEventListener("click", backToTop);
  787. mybuttonBottom.addEventListener("click", backToBottom);
  788. $(document).on('click', '.varie-link', function(e) {
  789. e.preventDefault();
  790. e.stopPropagation();
  791. closeSelect2Dropdowns();
  792. const causalsData = $(this).data('causals');
  793. if (causalsData) {
  794. const causals = causalsData.split('|');
  795. $('#causalsList').empty();
  796. causals.forEach(function(causal) {
  797. if (causal.trim()) {
  798. if (causal.includes(':::')) {
  799. const parts = causal.split(':::');
  800. const causalName = parts[0].trim();
  801. const amount = parts[1].trim();
  802. $('#causalsList').append(
  803. '<li class="list-group-item d-flex justify-content-between align-items-center">' +
  804. '<div>' +
  805. '<i class="fas fa-tags me-2" style="color: var(--color-blu);"></i>' +
  806. causalName +
  807. '</div>' +
  808. '<span class="badge bg-primary rounded-pill" style="background-color: var(--color-blu) !important;">' +
  809. amount +
  810. '</span>' +
  811. '</li>'
  812. );
  813. } else {
  814. $('#causalsList').append(
  815. '<li class="list-group-item">' +
  816. '<i class="fas fa-tags me-2" style="color: var(--color-blu);"></i>' +
  817. causal.trim() +
  818. '</li>'
  819. );
  820. }
  821. }
  822. });
  823. $('#causalsModal').modal('show');
  824. $('#causalsModal').on('shown.bs.modal', function () {
  825. $(this).find('.btn-close').focus();
  826. });
  827. }
  828. });
  829. });
  830. Livewire.on('load-table', () => {
  831. load();
  832. });
  833. Livewire.on('load-select', () => {
  834. load();
  835. });
  836. Livewire.on('filters-reset', () => {
  837. $('.filterMember').val('').trigger('change');
  838. $('.filterCausals').val('').trigger('change');
  839. load();
  840. });
  841. Livewire.on('show-export-modal', () => {
  842. $('#exportModal').modal('show');
  843. });
  844. Livewire.on('hide-export-modal', () => {
  845. $('#exportModal').modal('hide');
  846. });
  847. function showToast(type, message, duration = 5000) {
  848. const toastContainer = document.querySelector('.toast-container');
  849. if (!toastContainer) {
  850. console.error('Toast container not found');
  851. return;
  852. }
  853. const toastId = 'toast-' + Date.now();
  854. const toastColors = {
  855. success: 'bg-success',
  856. error: 'bg-danger',
  857. warning: 'bg-warning',
  858. info: 'bg-info'
  859. };
  860. const toastIcons = {
  861. success: 'fa-check-circle',
  862. error: 'fa-exclamation-circle',
  863. warning: 'fa-exclamation-triangle',
  864. info: 'fa-info-circle'
  865. };
  866. const toast = document.createElement('div');
  867. toast.id = toastId;
  868. toast.className = `toast align-items-center text-white ${toastColors[type]} border-0`;
  869. toast.setAttribute('role', 'alert');
  870. toast.innerHTML = `
  871. <div class="d-flex">
  872. <div class="toast-body">
  873. <i class="fas ${toastIcons[type]} me-2"></i>
  874. ${message}
  875. </div>
  876. <button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button>
  877. </div>
  878. `;
  879. toastContainer.appendChild(toast);
  880. if (typeof bootstrap !== 'undefined') {
  881. const bsToast = new bootstrap.Toast(toast, { delay: duration });
  882. bsToast.show();
  883. toast.addEventListener('hidden.bs.toast', function() {
  884. if (toastContainer.contains(toast)) {
  885. toastContainer.removeChild(toast);
  886. }
  887. });
  888. return bsToast;
  889. } else {
  890. toast.style.display = 'block';
  891. setTimeout(() => {
  892. if (toastContainer.contains(toast)) {
  893. toastContainer.removeChild(toast);
  894. }
  895. }, duration);
  896. }
  897. }
  898. document.addEventListener('DOMContentLoaded', function() {
  899. const sendViaEmailCheckbox = document.getElementById('sendViaEmail');
  900. const emailAddressRow = document.getElementById('emailAddressRow');
  901. const emailSubjectRow = document.getElementById('emailSubjectRow');
  902. const emailProcessingInfo = document.getElementById('emailProcessingInfo');
  903. const exportIcon = document.getElementById('exportIcon');
  904. const exportButtonText = document.getElementById('exportButtonText');
  905. const emailInput = document.getElementById('exportEmailAddress');
  906. function toggleEmailFields() {
  907. if (sendViaEmailCheckbox && sendViaEmailCheckbox.checked) {
  908. if (emailAddressRow) {
  909. emailAddressRow.style.display = 'block';
  910. emailAddressRow.classList.add('show');
  911. }
  912. if (emailSubjectRow) {
  913. emailSubjectRow.style.display = 'block';
  914. emailSubjectRow.classList.add('show');
  915. }
  916. if (emailProcessingInfo) {
  917. emailProcessingInfo.style.display = 'list-item';
  918. }
  919. if (exportIcon) exportIcon.className = 'fas fa-paper-plane me-1';
  920. if (exportButtonText) exportButtonText.textContent = 'INVIA EMAIL';
  921. } else {
  922. if (emailAddressRow) {
  923. emailAddressRow.style.display = 'none';
  924. emailAddressRow.classList.remove('show');
  925. }
  926. if (emailSubjectRow) {
  927. emailSubjectRow.style.display = 'none';
  928. emailSubjectRow.classList.remove('show');
  929. }
  930. if (emailProcessingInfo) {
  931. emailProcessingInfo.style.display = 'none';
  932. }
  933. if (exportIcon) exportIcon.className = 'fas fa-download me-1';
  934. if (exportButtonText) exportButtonText.textContent = 'ESPORTA';
  935. }
  936. }
  937. function validateEmail(email) {
  938. const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  939. return emailRegex.test(email);
  940. }
  941. if (sendViaEmailCheckbox) {
  942. sendViaEmailCheckbox.addEventListener('change', toggleEmailFields);
  943. }
  944. if (emailInput) {
  945. emailInput.addEventListener('blur', function() {
  946. if (sendViaEmailCheckbox && sendViaEmailCheckbox.checked && this.value) {
  947. if (validateEmail(this.value)) {
  948. this.classList.remove('is-invalid');
  949. this.classList.add('is-valid');
  950. } else {
  951. this.classList.remove('is-valid');
  952. this.classList.add('is-invalid');
  953. }
  954. }
  955. });
  956. emailInput.addEventListener('input', function() {
  957. this.classList.remove('is-invalid', 'is-valid');
  958. });
  959. }
  960. if (typeof $ !== 'undefined') {
  961. $('#exportModal').on('shown.bs.modal', function() {
  962. toggleEmailFields();
  963. });
  964. }
  965. });
  966. document.addEventListener('livewire:load', function () {
  967. console.log('Livewire loaded, setting up export event listeners');
  968. Livewire.on('export-email-queued', function() {
  969. console.log('Export email queued event received');
  970. showToast('info',
  971. '<strong>Export avviato!</strong><br>' +
  972. 'L\'elaborazione è in corso in background. Riceverai l\'email a breve.',
  973. 8000
  974. );
  975. });
  976. Livewire.on('export-email-sent', function() {
  977. console.log('Export email sent event received');
  978. showToast('success',
  979. '<strong>Email inviata!</strong><br>' +
  980. 'L\'export è stato completato e inviato alla tua email.',
  981. 6000
  982. );
  983. });
  984. Livewire.on('export-email-error', function(message) {
  985. console.log('Export email error event received:', message);
  986. showToast('error',
  987. '<strong>Errore nell\'export:</strong><br>' +
  988. (message || 'Si è verificato un errore durante l\'elaborazione.'),
  989. 10000
  990. );
  991. });
  992. Livewire.on('show-export-modal', function() {
  993. console.log('Show export modal event received');
  994. if (typeof $ !== 'undefined') {
  995. $('#exportModal').modal('show');
  996. }
  997. });
  998. Livewire.on('hide-export-modal', function() {
  999. console.log('Hide export modal event received');
  1000. if (typeof $ !== 'undefined') {
  1001. $('#exportModal').modal('hide');
  1002. }
  1003. });
  1004. });
  1005. if (typeof Livewire !== 'undefined') {
  1006. document.addEventListener('livewire:initialized', function () {
  1007. console.log('Livewire initialized, setting up export event listeners');
  1008. Livewire.on('export-email-queued', function() {
  1009. showToast('info',
  1010. '<strong>Export avviato!</strong><br>' +
  1011. 'L\'elaborazione è in corso in background. Riceverai l\'email a breve.',
  1012. 8000
  1013. );
  1014. });
  1015. Livewire.on('export-email-sent', function() {
  1016. showToast('success',
  1017. '<strong>Email inviata!</strong><br>' +
  1018. 'L\'export è stato completato e inviato alla tua email.',
  1019. 6000
  1020. );
  1021. });
  1022. Livewire.on('export-email-error', function(message) {
  1023. showToast('error',
  1024. '<strong>Errore nell\'export:</strong><br>' +
  1025. (message || 'Si è verificato un errore durante l\'elaborazione.'),
  1026. 10000
  1027. );
  1028. });
  1029. Livewire.on('show-export-modal', function() {
  1030. if (typeof $ !== 'undefined') {
  1031. $('#exportModal').modal('show');
  1032. }
  1033. });
  1034. Livewire.on('hide-export-modal', function() {
  1035. if (typeof $ !== 'undefined') {
  1036. $('#exportModal').modal('hide');
  1037. }
  1038. });
  1039. });
  1040. }
  1041. window.addEventListener('load', function() {
  1042. if (typeof showToast === 'function') {
  1043. console.log('showToast function is available globally');
  1044. } else {
  1045. console.error('showToast function is not available globally');
  1046. }
  1047. });
  1048. function handleExportClick() {
  1049. showExportLoading();
  1050. @this.call('exportWithDateRange');
  1051. }
  1052. function showExportLoading() {
  1053. document.getElementById('normalState').style.display = 'none';
  1054. document.getElementById('loadingState').style.display = 'inline-flex';
  1055. document.getElementById('exportButton').disabled = true;
  1056. }
  1057. function hideExportLoading() {
  1058. document.getElementById('normalState').style.display = 'inline-flex';
  1059. document.getElementById('loadingState').style.display = 'none';
  1060. document.getElementById('exportButton').disabled = false;
  1061. }
  1062. // Listen for when export is complete
  1063. Livewire.on('export-complete', function() {
  1064. hideExportLoading();
  1065. });
  1066. Livewire.on('hide-export-modal', function() {
  1067. hideExportLoading();
  1068. });
  1069. </script>
  1070. @endpush