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