templates/index.html (view raw)
1<!DOCTYPE html>
2<html>
3
4<head>
5 <title>Ricorrenze</title>
6 <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%2210 0 100 100%22><text y=%22.90em%22 font-size=%2290%22>📅</text></svg>"></link>
7 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
8 <style>
9 :root {
10 color-scheme: light dark;
11 --text: #000;
12 --bg: #fff;
13 --green: #4CAF50;
14 --hover-green: #45a049;
15 --red: #af4c4c;
16 --hover-red: #a14545;
17 }
18
19 @media (prefers-color-scheme: dark) {
20 :root {
21 color-scheme: dark light;
22 --text: #fff;
23 --bg: #121212;
24 --green: #265929;
25 --hover-green: #214d23;
26 --red: #592626;
27 --hover-red: #4d2121;
28 }
29 }
30
31 body {
32 font-family: Arial, sans-serif;
33 background-color: var(--bg);
34 color: var(--text);
35 }
36
37 table {
38 width: 100%;
39 border-collapse: collapse;
40 }
41
42 table,
43 th,
44 td {
45 border: 1px solid var(--text);
46 }
47
48 th,
49 td {
50 padding: 10px;
51 text-align: left;
52 }
53
54 th {
55 background-color: var(--bg);
56 }
57
58 .date-inputs {
59 display: flex;
60 align-items: center;
61 border: none;
62 gap: 2px;
63 }
64 .small-input {
65 width: 32px;
66 }
67 .big-input {
68 width: 100%;
69 }
70
71 .actions i {
72 cursor: pointer;
73 padding-right: 5px;
74 }
75
76 .cute-button {
77 margin-top: 20px;
78 background-color: var(--green);
79 border: none;
80 color: white;
81 padding: 10px 20px;
82 text-align: center;
83 text-decoration: none;
84 display: inline-block;
85 font-size: 16px;
86 margin: 4px 2px;
87 transition-duration: 0.4s;
88 cursor: pointer;
89 border-radius: 12px;
90 }
91
92 .cute-button:hover {
93 background-color: var(--hover-green);
94 }
95
96 .cute-button-red {
97 background-color: var(--red);
98 }
99
100 .cute-button-red:hover {
101 background-color: var(--hover-red);
102 }
103
104 .hidden {
105 display: none;
106 }
107 </style>
108</head>
109
110<body>
111 <h1>Ricorrenze</h1>
112 <table id="main-table">
113 <tr>
114 <th>Nome</th>
115 <th>Descrizione</th>
116 <th>Data (gg/mm)</th>
117 <th>Notifica</th>
118 <th>Inviata</th>
119 <th>Azioni</th>
120 </tr>
121 {{ range .Occurrences }}
122 <tr id="occurrence-{{ .ID }}">
123 <td>{{ .Name }}</td>
124 <td>{{ .Description }}</td>
125 <td>{{ padZero .Day }}/{{ padZero .Month }}</td>
126 <td><input type="checkbox" {{if .Notify}}checked{{end}} disabled></td>
127 <td><input type="checkbox" {{if .Notified}}checked{{end}} disabled></td>
128 <td class="actions">
129 <i class="fas fa-edit" title="Modifica" onclick="editOccurrence('{{ .ID }}')"></i>
130 <i class="fas fa-trash-alt" title="Elimina" onclick="deleteOccurrence('{{ .ID }}')"></i>
131 </td>
132 </tr>
133 {{ end }}
134 <tr id="occurrence-none" class="hidden">
135 <td colspan="6">Nessuna ricorrenza.</td>
136 </tr>
137 </table>
138 <div style="margin-top: 10px; text-align: center;">
139 <button id="add-row-button" class="cute-button" onclick="addNewOccurrenceRow()">
140 <i class="fas fa-plus"></i> Aggiungi</button>
141 <button id="save-row-button" class="cute-button hidden" onclick="saveOccurrence('0')">
142 <i class="fas fa-save"></i> Salva
143 </button>
144 <button id="cancel-row-button" class="cute-button cute-button-red hidden" onclick="cancelNewOccurrence()">
145 <i class="fas fa-times"></i> Annulla
146 </button>
147 </div>
148
149 <script>
150 const hiddenClass = 'hidden';
151 const addButton = document.getElementById('add-row-button');
152 const saveButton = document.getElementById('save-row-button');
153 const cancelButton = document.getElementById('cancel-row-button');
154 const mainTable = document.getElementById('main-table');
155 const noneRow = document.getElementById('occurrence-none');
156
157 function updateNoneRowDisplay() {
158 const rows = mainTable.getElementsByTagName('tr');
159 const l = rows.length
160 if (l === 2) {
161 noneRow.classList.remove(hiddenClass);
162 return;
163 }
164 noneRow.classList.add(hiddenClass);
165 }
166
167 function deleteOccurrence(id) {
168 if (confirm('Sei sicuro di voler eliminare questa ricorrenza?')) {
169 fetch(`/occurrences/${id}`, {
170 method: 'DELETE'
171 })
172 .then(response => {
173 if (!response.ok) {
174 console.error('Error:', response.status);
175 alert('Eliminazione fallita.');
176 return;
177 }
178 const deletedRow = document.getElementById(`occurrence-${id}`);
179 deletedRow.parentElement.removeChild(deletedRow);
180 updateNoneRowDisplay();
181 })
182 .catch(error => {
183 console.error('Error:', error);
184 alert('Non sono riuscito a contattare il backend.');
185 });
186 }
187 }
188
189 function padNumber(input, n=2) {
190 return input.toString().padStart(n, '0');
191 }
192
193 function createRow(id, name, description, day, month, notify, notified) {
194 return `
195 <td>${name}</td>
196 <td>${description}</td>
197 <td>${padNumber(day)}/${padNumber(month)}</td>
198 <td><input type="checkbox" ${notify ? 'checked' : ''} disabled></td>
199 <td><input type="checkbox" ${notified ? 'checked' : ''} disabled></td>
200 <td class="actions">
201 <i class="fas fa-edit" title="Edit" onclick="editOccurrence(${id})"></i>
202 <i class="fas fa-trash-alt" title="Delete" onclick="deleteOccurrence(${id})"></i>
203 </td>
204 `;
205 }
206
207 function createInputFields(id, name, description, day, month, notify, notified, isNew) {
208 return `
209 <td><input class="big-input" type="text" value="${name || ''}" id="name-${id}"></td>
210 <td><input class="big-input" type="text" value="${description || ''}" id="description-${id}"></td>
211 <td class="date-inputs"><input type="number" value="${day || ''}" id="day-${id}" class="small-input" min="1" max="31" onchange="this.value = padNumber(this.value);"> / <input type="number" value="${month || ''}" id="month-${id}" class="small-input" min="1" max="12" onchange="this.value = padNumber(this.value);"></td>
212 <td><input type="checkbox" id="notify-${id}" ${notify ? 'checked' : ''}></td>
213 <td><input type="checkbox" id="notified-${id}" ${notified ? 'checked' : ''}></td>
214 <td class="actions">
215 ${isNew ? '' : `
216 <i class="fas fa-save" title="Save" onclick="saveOccurrence(${id})"></i>
217 <i class="fas fa-times" title="Cancel" onclick="cancelEdit(${id}, '${name}', '${description}', ${day}, ${month}, ${notify})"></i>
218 `}
219 </td>
220 `;
221 }
222
223 function editOccurrence(id) {
224 const row = document.getElementById(`occurrence-${id}`);
225 const cells = row.getElementsByTagName('td');
226
227 const name = cells[0].innerText;
228 const description = cells[1].innerText;
229 const [day, month] = cells[2].innerText.split('/');
230 const notify = cells[3].getElementsByTagName('input')[0].checked;
231 const notified = cells[4].getElementsByTagName('input')[0].checked;
232
233 row.innerHTML = createInputFields(id, name, description, day, month, notify, notified, false);
234 }
235
236 function cancelEdit(id, name, description, day, month, notify) {
237 const row = document.getElementById(`occurrence-${id}`);
238 row.innerHTML = createRow(id, name, description, day, month, notify);
239 }
240
241 function saveOccurrence(id) {
242 const name = document.getElementById(`name-${id}`).value;
243 const description = document.getElementById(`description-${id}`).value;
244 const day = parseInt(document.getElementById(`day-${id}`).value);
245 const month = parseInt(document.getElementById(`month-${id}`).value);
246 const notify = document.getElementById(`notify-${id}`).checked;
247 const notified = document.getElementById(`notified-${id}`).checked;
248
249 const isNew = id === '0';
250 const updatedData = {
251 id: isNew ? undefined : id,
252 name: name,
253 description: description,
254 month: month,
255 day: day,
256 notify: notify,
257 notified: notified
258 };
259
260 fetch('/occurrences', {
261 method: 'POST',
262 headers: {
263 'Content-Type': 'application/json'
264 },
265 body: JSON.stringify(updatedData)
266 })
267 .then(response => {
268 if (!response.ok) {
269 console.error('Error:', response.status);
270 alert('Controlla che i campi siano validi.');
271 return;
272 }
273 if (isNew) {
274 cancelNewOccurrence();
275 mainTable.insertRow(-1).id = `occurrence-${id}`
276 }
277 updateRow(`occurrence-${id}`, response);
278 })
279 .catch(error => {
280 console.error('Error:', error);
281 alert('Non sono riuscito a contattare il backend.');
282 });
283 }
284
285 function addNewOccurrenceRow() {
286 const newRow = mainTable.insertRow(-1);
287 newRow.id = 'new-occurrence';
288 newRow.innerHTML = createInputFields('0', '', '', '', '', true, false, true);
289
290 hideAddButton();
291 updateNoneRowDisplay();
292 }
293 function hideAddButton() {
294 addButton.classList.add(hiddenClass);
295 saveButton.classList.remove(hiddenClass);
296 cancelButton.classList.remove(hiddenClass);
297 }
298
299 function showAddButton() {
300 addButton.classList.remove(hiddenClass);
301 saveButton.classList.add(hiddenClass);
302 cancelButton.classList.add(hiddenClass);
303 }
304
305 function updateRow(rowElementId, response) {
306 const newRow = document.getElementById(rowElementId);
307 response.json().then((res) => {
308 newRow.id = `occurrence-${res.id}`;
309 newRow.innerHTML = createRow(res.id, res.name, res.description, res.day, res.month, res.notify, res.notified);
310 updateNoneRowDisplay()
311 });
312 }
313
314 function cancelNewOccurrence() {
315 const newRow = document.getElementById('new-occurrence');
316 newRow.parentNode.removeChild(newRow);
317 showAddButton();
318 updateNoneRowDisplay();
319 }
320
321 updateNoneRowDisplay()
322 </script>
323
324</body>
325
326</html>