|
| 1 | + |
| 2 | +<script th:inline="javascript"> |
| 3 | + let serverState = /*[[${entry}]]*/ null; |
| 4 | + let clientId = /*[[${client.id}]]*/ null; |
| 5 | + let entryId = /*[[${entryId}]]*/ null; |
| 6 | + let entryDate = /*[[${#temporals.format((entry?.date ?: entryDate), T(pro.qyoga.l10n.DateFormatsKt).RUSSIAN_DATE_FORMAT_PATTERN)}]]*/ null; |
| 7 | + |
| 8 | + let localStateKey = `qyoga.journalEntryForm.${clientId}.${entryId || "new"}`; |
| 9 | + |
| 10 | + let localState = localStorage.getItem(localStateKey) ? JSON.parse(localStorage.getItem(localStateKey)) : null; |
| 11 | + |
| 12 | + let formData; |
| 13 | + if (serverState == null) { |
| 14 | + formData = localState || {version: 0, date: entryDate}; |
| 15 | + } else if (serverState.version === localState?.version) { |
| 16 | + formData = localState |
| 17 | + } else { |
| 18 | + formData = {...serverState} |
| 19 | + } |
| 20 | + |
| 21 | + function entryData() { |
| 22 | + let hasUnsavedEdits = serverState != null && localState != null && !shallowEqual(serverState, localState); |
| 23 | + let newCardWasntSaved = serverState == null && localState != null; |
| 24 | + return { |
| 25 | + form: formData, |
| 26 | + serverState: serverState, |
| 27 | + hasUnsavedChanges: hasUnsavedEdits || newCardWasntSaved |
| 28 | + } |
| 29 | + } |
| 30 | + |
| 31 | + function saveLocalState(formData) { |
| 32 | + localStorage.setItem(localStateKey, JSON.stringify(formData)); |
| 33 | + } |
| 34 | + |
| 35 | + function resetLocalState() { |
| 36 | + localStorage.removeItem(localStateKey); |
| 37 | + } |
| 38 | + |
| 39 | + function isChanged(form, key) { |
| 40 | + return serverState != null && serverState[key] !== form[key]; |
| 41 | + } |
| 42 | + |
| 43 | + window.addEventListener("htmx:afterSettle", () => { |
| 44 | + document.querySelectorAll(".form-control").forEach(it => { |
| 45 | + it.setAttribute("x-model", "form." + it.name); |
| 46 | + it.setAttribute(":class", "isChanged(form, '" + it.name + "') ? 'border-warning' : ''"); |
| 47 | + }); |
| 48 | + }); |
| 49 | + |
| 50 | +</script> |
| 51 | + |
1 | 52 | <div id="createJournalEntryTabContent"> |
2 | 53 | <style> |
3 | 54 | /* For medium screens and larger */ |
|
20 | 71 |
|
21 | 72 | <form hx-swap="outerHtml" id="journalEntryFrom" |
22 | 73 | th:fragment="journalEntryFrom" |
23 | | - th:hx-post="${formAction}"> |
| 74 | + th:hx-post="${formAction}" |
| 75 | + x-data="entryData()" |
| 76 | + x-init="$watch('form', (form) => saveLocalState(form))"> |
| 77 | + |
| 78 | + <input |
| 79 | + name="version" |
| 80 | + th:value="${entry?.version ?: 0}" |
| 81 | + type="hidden" |
| 82 | + > |
| 83 | + |
| 84 | + <div class="alert alert-warning w-100" |
| 85 | + role="alert" |
| 86 | + x-show="hasUnsavedChanges"> |
| 87 | + <i class="fa-solid fa-triangle-exclamation"></i> |
| 88 | + В карточке восстановлены несохранённые данные прошлой сессии |
| 89 | + </div> |
| 90 | + |
24 | 91 | <div class="row"> |
25 | 92 | <div class="mb-3 col-12 col-md-2"> |
26 | 93 | <label class="form-label" for="date-input">Дата</label> |
|
45 | 112 | hx-target="#therapeuticTasks" |
46 | 113 | hx-trigger="input[inputType != 'insertReplacementText' && target.value.length > 2] delay:0.3s" |
47 | 114 | list="therapeuticTasks" |
48 | | - th:value="${entry?.therapeuticTask?.entity?.name ?: ''}" |
| 115 | + th:value="${entry?.therapeuticTaskName ?: ''}" |
49 | 116 | type="text" |
50 | 117 | > |
51 | 118 | <datalist id="therapeuticTasks"></datalist> |
|
55 | 122 | <label class="form-label" for="text-input">Запись</label> |
56 | 123 | <textarea class="form-control full-height" |
57 | 124 | id="text-input" name="journalEntryText" required rows="12" |
58 | | - th:text="${entry?.entryText ?: ''}" |
| 125 | + th:text="${entry?.journalEntryText ?: ''}" |
59 | 126 | ></textarea> |
60 | 127 | </div> |
61 | 128 |
|
62 | 129 | <div class="row g-2 justify-content-end"> |
63 | 130 | <div class="col-6 col-sm-auto text-center"> |
64 | | - <a class="btn btn-outline-danger" style="min-width: 110px;" |
| 131 | + <a @click="resetLocalState()" |
| 132 | + class="btn btn-outline-danger" |
| 133 | + style="min-width: 110px;" |
65 | 134 | th:href="@{/therapist/clients/{id}/journal(id=${client.id})}"> |
66 | 135 | Отмена |
67 | 136 | </a> |
68 | 137 | </div> |
69 | 138 | <div class="col-6 col-sm-auto text-center"> |
70 | | - <button class="btn btn-outline-success" name="confirmButton" style="min-width: 110px;"> |
| 139 | + <button |
| 140 | + @click="resetLocalState()" |
| 141 | + class="btn btn-outline-success" |
| 142 | + name="confirmButton" |
| 143 | + style="min-width: 110px;"> |
71 | 144 | Сохранить |
72 | 145 | </button> |
73 | 146 | </div> |
|
0 commit comments