content:dict = fileHandling.getDay(cookie["user_id"], year, month)
+ dummy = {"text": "", "date_written": "", "files": [], "tags": []}
+
if "days" not in content.keys():
- return {"text": "", "date_written": ""}
+ return dummy
for dayLog in content["days"]:
if dayLog["day"] == day:
for file in dayLog["files"]:
file["filename"] = security.decrypt_text(file["enc_filename"], enc_key)
file["type"] = security.decrypt_text(file["enc_type"], enc_key)
- return {"text": text, "date_written": date_written, "files": dayLog.get("files", [])}
+ return {"text": text, "date_written": date_written, "files": dayLog.get("files", []), "tags": dayLog.get("tags", [])}
- return {"text": "", "date_written": ""}
+ return dummy
def get_start_index(text, index):
# find a whitespace two places before the index
name: str
color: str
-@router.post("/saveTag")
-async def saveTag(tag: NewTag, cookie = Depends(users.isLoggedIn)):
+@router.post("/saveNewTag")
+async def saveNewTag(tag: NewTag, cookie = Depends(users.isLoggedIn)):
enc_key = security.get_enc_key(cookie["user_id"], cookie["derived_key"])
content:dict = fileHandling.getTags(cookie["user_id"])
if not fileHandling.writeTags(cookie["user_id"], content):
return {"success": False}
else:
- return {"success": True}
\ No newline at end of file
+ return {"success": True}
+
+
+class AddTagToLog(BaseModel):
+ day: int
+ month: int
+ year: int
+ tag_id: int
+
+@router.post("/addTagToLog")
+async def addTagToLog(data: AddTagToLog, cookie = Depends(users.isLoggedIn)):
+ content:dict = fileHandling.getDay(cookie["user_id"], data.year, data.month)
+ if "days" not in content.keys():
+ content["days"] = []
+
+ dayFound = False
+ for dayLog in content["days"]:
+ if dayLog["day"] != data.day:
+ continue
+ dayFound = True
+ if not "tags" in dayLog.keys():
+ dayLog["tags"] = []
+ if data.tag_id in dayLog["tags"]:
+ # fail silently
+ return {"success": True}
+ dayLog["tags"].append(data.tag_id)
+ break
+
+ if not dayFound:
+ content["days"].append({"day": data.day, "tags": [data.tag_id]})
+
+ if not fileHandling.writeDay(cookie["user_id"], data.year, data.month, content):
+ raise HTTPException(status_code=500, detail="Failed to write tag - error writing log")
+ return {"success": True}
+
+@router.post("/removeTagFromLog")
+async def removeTagFromLog(data: AddTagToLog, cookie = Depends(users.isLoggedIn)):
+ content:dict = fileHandling.getDay(cookie["user_id"], data.year, data.month)
+ if "days" not in content.keys():
+ raise HTTPException(status_code=500, detail="Day not found - json error")
+
+ for dayLog in content["days"]:
+ if dayLog["day"] != data.day:
+ continue
+ if not "tags" in dayLog.keys():
+ raise HTTPException(status_code=500, detail="Failed to remove tag - not found in log")
+ if not data.tag_id in dayLog["tags"]:
+ raise HTTPException(status_code=500, detail="Failed to remove tag - not found in log")
+ dayLog["tags"].remove(data.tag_id)
+ if not fileHandling.writeDay(cookie["user_id"], data.year, data.month, content):
+ raise HTTPException(status_code=500, detail="Failed to remove tag - error writing log")
+ return {"success": True}
+
\ No newline at end of file
currentLog = response.data.text;
filesOfDay = response.data.files;
+ selectedTags = response.data.tags;
+
savedLog = currentLog;
tinyMDE.setContent(currentLog);
// show the correct tags in the dropdown
$effect(() => {
+ if (tags.length === 0) {
+ filteredTags = [];
+ return;
+ }
+
// exclude already selected tags
let tagsWithoutSelected = tags.filter(
- (tag) => !selectedTags.find((selectedTag) => selectedTag.id === tag.id)
+ (tag) => !selectedTags.find((selectedTag) => selectedTag === tag.id)
);
if (searchTab === '') {
}, 0);
}
+ let showTagLoading = $state(false);
+
function selectTag(id) {
- selectedTags = [...selectedTags, tags.find((tag) => tag.id === id)];
+ showTagLoading = true;
+
+ axios
+ .post(API_URL + '/logs/addTagToLog', {
+ day: $selectedDate.getDate(),
+ month: $selectedDate.getMonth() + 1,
+ year: $selectedDate.getFullYear(),
+ tag_id: id
+ })
+ .then((response) => {
+ if (response.data.success) {
+ selectedTags = [...selectedTags, id];
+ } else {
+ // toast
+ const toast = new bootstrap.Toast(document.getElementById('toastErrorAddingTagToDay'));
+ toast.show();
+ }
+ })
+ .catch((error) => {
+ console.error(error);
+ // toast
+ const toast = new bootstrap.Toast(document.getElementById('toastErrorAddingTagToDay'));
+ toast.show();
+ })
+ .finally(() => {
+ showTagLoading = false;
+ });
+
searchTab = '';
}
function removeTag(id) {
- selectedTags = selectedTags.filter((tag) => tag.id !== id);
+ showTagLoading = true;
+
+ axios
+ .post(API_URL + '/logs/removeTagFromLog', {
+ day: $selectedDate.getDate(),
+ month: $selectedDate.getMonth() + 1,
+ year: $selectedDate.getFullYear(),
+ tag_id: id
+ })
+ .then((response) => {
+ if (response.data.success) {
+ selectedTags = selectedTags.filter((tag) => tag !== id);
+ } else {
+ // toast
+ const toast = new bootstrap.Toast(
+ document.getElementById('toastErrorRemovingTagFromDay')
+ );
+ toast.show();
+ }
+ })
+ .catch((error) => {
+ console.error(error);
+ // toast
+ const toast = new bootstrap.Toast(document.getElementById('toastErrorRemovingTagFromDay'));
+ toast.show();
+ })
+ .finally(() => {
+ showTagLoading = false;
+ });
}
let editTag = $state({});
function saveNewTag() {
isSavingNewTag = true;
axios
- .post(API_URL + '/logs/saveTag', {
+ .post(API_URL + '/logs/saveNewTag', {
icon: editTag.icon,
name: editTag.name,
color: editTag.color
tagModal.close();
} else {
// toast
- const toast = new bootstrap.Toast(document.getElementById('toastErrorSavingTag'));
+ const toast = new bootstrap.Toast(document.getElementById('toastErrorSavingNewTag'));
toast.show();
}
})
<div id="right" class="d-flex flex-column">
<div class="tags">
<div class="d-flex flex-row justify-content-between">
- <h3>Tags</h3>
+ <div class="d-flex flex-row">
+ <h3>Tags</h3>
+ {#if showTagLoading}
+ <div class="spinner-border ms-3" role="status">
+ <span class="visually-hidden">Loading...</span>
+ </div>
+ {/if}
+ </div>
<!-- svelte-ignore a11y_missing_attribute -->
<a
tabindex="-1"
</div>
{/if}
<div class="selectedTags d-flex flex-row flex-wrap">
- {#each selectedTags as tag (tag.id)}
- <Tag {tag} {removeTag} isRemovable="true" />
- {/each}
+ {#if tags.length !== 0}
+ {#each selectedTags as tag_id (tag_id)}
+ <div transition:slide={{ axis: 'x' }}>
+ <Tag tag={tags.find((tag) => tag.id === tag_id)} {removeTag} isRemovable="true" />
+ </div>
+ {/each}
+ {/if}
</div>
</div>
<div class="toast-container position-fixed bottom-0 end-0 p-3">
<div
- id="toastErrorSavingTag"
+ id="toastErrorRemovingTagFromDay"
+ class="toast align-items-center text-bg-danger"
+ role="alert"
+ aria-live="assertive"
+ aria-atomic="true"
+ >
+ <div class="d-flex">
+ <div class="toast-body">Fehler beim Enfternen des Tags!</div>
+ </div>
+ </div>
+
+ <div
+ id="toastErrorAddingTagToDay"
+ class="toast align-items-center text-bg-danger"
+ role="alert"
+ aria-live="assertive"
+ aria-atomic="true"
+ >
+ <div class="d-flex">
+ <div class="toast-body">Fehler beim Hinzufügen des Tags zum ausgewählten Datum!</div>
+ </div>
+ </div>
+
+ <div
+ id="toastErrorSavingNewTag"
class="toast align-items-center text-bg-danger"
role="alert"
aria-live="assertive"