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
68 .actions i {
69 cursor: pointer;
70 padding-right: 5px;
71 }
72
73 .cute-button {
74 margin-top: 20px;
75 background-color: var(--green);
76 border: none;
77 color: white;
78 padding: 10px 20px;
79 text-align: center;
80 text-decoration: none;
81 display: inline-block;
82 font-size: 16px;
83 margin: 4px 2px;
84 transition-duration: 0.4s;
85 cursor: pointer;
86 border-radius: 12px;
87 }
88
89 .cute-button:hover {
90 background-color: var(--hover-green);
91 }
92
93 .cute-button-red {
94 background-color: var(--red);
95 }
96
97 .cute-button-red:hover {
98 background-color: var(--hover-red);
99 }
100
101 .hidden {
102 display: none;
103 }
104 </style>
105</head>
106
107<body>
108 <h1>Ricorrenze</h1>
109 <table id="main-table">
110 <tr>
111 <th>ID</th>
112 <th>Nome</th>
113 <th>Descrizione</th>
114 <th>Data (gg/mm)</th>
115 <th>Notifica</th>
116 <th>Azioni</th>
117 </tr>
118 {{ range .Occurrences }}
119 <tr id="occurrence-{{ .ID }}">
120 <td>{{ .ID }}</td>
121 <td>{{ .Name }}</td>
122 <td>{{ .Description }}</td>
123 <td>{{ padZero .Day }}/{{ padZero .Month }}</td>
124 <td><input type="checkbox" {{if .Notify}}checked{{end}} disabled></td>
125 <td class="actions">
126 <i class="fas fa-edit" title="Modifica" onclick="editOccurrence('{{ .ID }}')"></i>
127 <i class="fas fa-trash-alt" title="Elimina" onclick="deleteOccurrence('{{ .ID }}')"></i>
128 </td>
129 </tr>
130 {{ end }}
131 <tr id="occurrence-none" class="hidden">
132 <td colspan="6">Nessuna ricorrenza.</td>
133 </tr>
134 </table>
135 <div style="margin-top: 10px; text-align: center;">
136 <button id="add-row-button" class="cute-button" onclick="addNewOccurrenceRow()">
137 <i class="fas fa-plus"></i> Aggiungi</button>
138 <button id="save-row-button" class="cute-button hidden" onclick="saveOccurrence('0')">
139 <i class="fas fa-save"></i> Salva
140 </button>
141 <button id="cancel-row-button" class="cute-button cute-button-red hidden" onclick="cancelNewOccurrence()">
142 <i class="fas fa-times"></i> Annulla
143 </button>
144 </div>
145
146 <script>
147 const hiddenClass = 'hidden';
148 const addButton = document.getElementById('add-row-button');
149 const saveButton = document.getElementById('save-row-button');
150 const cancelButton = document.getElementById('cancel-row-button');
151 const mainTable = document.getElementById('main-table');
152 const noneRow = document.getElementById('occurrence-none');
153
154 function updateNoneRowDisplay() {
155 const rows = mainTable.getElementsByTagName('tr');
156 const l = rows.length
157 if (l === 2) {
158 noneRow.classList.remove(hiddenClass);
159 return;
160 }
161 noneRow.classList.add(hiddenClass);
162 }
163
164 function deleteOccurrence(id) {
165 if (confirm('Sei sicuro di voler eliminare questa ricorrenza?')) {
166 fetch(`/occurrences/${id}`, {
167 method: 'DELETE'
168 })
169 .then(response => {
170 if (!response.ok) {
171 console.error('Error:', response.status);
172 alert('Eliminazione fallita.');
173 return;
174 }
175 const deletedRow = document.getElementById(`occurrence-${id}`);
176 deletedRow.parentElement.removeChild(deletedRow);
177 updateNoneRowDisplay();
178 })
179 .catch(error => {
180 console.error('Error:', error);
181 alert('Non sono riuscito a contattare il backend.');
182 });
183 }
184 }
185
186 function padNumber(input, n=2) {
187 return input.toString().padStart(n, '0');
188 }
189
190 function createRow(id, name, description, day, month, notify) {
191 return `
192 <td>${id}</td>
193 <td>${name}</td>
194 <td>${description}</td>
195 <td>${padNumber(day)}/${padNumber(month)}</td>
196 <td><input type="checkbox" ${notify ? 'checked' : ''} disabled></td>
197 <td class="actions">
198 <i class="fas fa-edit" title="Edit" onclick="editOccurrence(${id})"></i>
199 <i class="fas fa-trash-alt" title="Delete" onclick="deleteOccurrence(${id})"></i>
200 </td>
201 `;
202 }
203
204 function createInputFields(id, name, description, day, month, notify, isNew) {
205 return `
206 <td>${isNew ? '' : id}</td>
207 <td><input type="text" value="${name || ''}" id="name-${id}"></td>
208 <td><input type="text" value="${description || ''}" id="description-${id}"></td>
209 <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>
210 <td><input type="checkbox" id="notify-${id}" ${notify ? 'checked' : ''}></td>
211 <td class="actions">
212 ${isNew ? '' : `
213 <i class="fas fa-save" title="Save" onclick="saveOccurrence(${id})"></i>
214 <i class="fas fa-times" title="Cancel" onclick="cancelEdit(${id}, '${name}', '${description}', ${day}, ${month}, ${notify})"></i>
215 `}
216 </td>
217 `;
218 }
219
220 function editOccurrence(id) {
221 const row = document.getElementById(`occurrence-${id}`);
222 const cells = row.getElementsByTagName('td');
223
224 const name = cells[1].innerText;
225 const description = cells[2].innerText;
226 const [day, month] = cells[3].innerText.split('/');
227 const notify = cells[4].getElementsByTagName('input')[0].checked;
228
229 row.innerHTML = createInputFields(id, name, description, day, month, notify, false);
230 }
231
232 function cancelEdit(id, name, description, day, month, notify) {
233 const row = document.getElementById(`occurrence-${id}`);
234 row.innerHTML = createRow(id, name, description, day, month, notify);
235 }
236
237 function saveOccurrence(id) {
238 const name = document.getElementById(`name-${id}`).value;
239 const description = document.getElementById(`description-${id}`).value;
240 const day = parseInt(document.getElementById(`day-${id}`).value);
241 const month = parseInt(document.getElementById(`month-${id}`).value);
242 const notify = document.getElementById(`notify-${id}`).checked;
243
244 const isNew = id === '0';
245 const updatedData = {
246 id: isNew ? undefined : id,
247 name: name,
248 description: description,
249 month: month,
250 day: day,
251 notify: notify
252 };
253
254 fetch('/occurrences', {
255 method: 'POST',
256 headers: {
257 'Content-Type': 'application/json'
258 },
259 body: JSON.stringify(updatedData)
260 })
261 .then(response => {
262 if (!response.ok) {
263 console.error('Error:', response.status);
264 alert('Controlla che i campi siano validi.');
265 return;
266 }
267 if (isNew) {
268 cancelNewOccurrence();
269 mainTable.insertRow(-1).id = `occurrence-${id}`
270 }
271 updateRow(`occurrence-${id}`, response);
272 })
273 .catch(error => {
274 console.error('Error:', error);
275 alert('Non sono riuscito a contattare il backend.');
276 });
277 }
278
279 function addNewOccurrenceRow() {
280 const newRow = mainTable.insertRow(-1);
281 newRow.id = 'new-occurrence';
282 newRow.innerHTML = createInputFields('0', '', '', '', '', true, true);
283
284 hideAddButton();
285 updateNoneRowDisplay();
286 }
287 function hideAddButton() {
288 addButton.classList.add(hiddenClass);
289 saveButton.classList.remove(hiddenClass);
290 cancelButton.classList.remove(hiddenClass);
291 }
292
293 function showAddButton() {
294 addButton.classList.remove(hiddenClass);
295 saveButton.classList.add(hiddenClass);
296 cancelButton.classList.add(hiddenClass);
297 }
298
299 function updateRow(rowElementId, response) {
300 const newRow = document.getElementById(rowElementId);
301 response.json().then((res) => {
302 newRow.id = `occurrence-${res.id}`;
303 newRow.innerHTML = createRow(res.id, res.name, res.description, res.day, res.month, res.notify);
304 updateNoneRowDisplay()
305 });
306 }
307
308 function cancelNewOccurrence() {
309 const newRow = document.getElementById('new-occurrence');
310 newRow.parentNode.removeChild(newRow);
311 showAddButton();
312 updateNoneRowDisplay();
313 }
314
315 updateNoneRowDisplay()
316 </script>
317
318</body>
319
320</html>