Files
Website/resources/js/views/dashboard/MediaList.vue
2023-04-18 10:21:55 +10:00

324 lines
9.4 KiB
Vue

<template>
<SMMastHead
title="Media"
:back-link="{ name: 'dashboard' }"
back-title="Return to Dashboard" />
<SMMessage
v-if="formMessage.message"
:type="formMessage.type"
:message="formMessage.message"
:icon="formMessage.icon" />
<SMContainer>
<SMToolbar>
<template #left>
<SMButton
:to="{ name: 'workshops' }"
type="primary"
label="Upload Media" />
</template>
<template #right>
<SMInput
v-model="search"
label="Search"
:small="true"
style="max-width: 350px"
:show-clear="true">
<template #append>
<SMButton
type="primary"
label="Search"
icon="search-outline"
@click="handleClickSearch" />
</template>
</SMInput>
</template>
</SMToolbar>
<SMPagination
:model-value="pageValue"
:total="total"
:per-page="perPage" />
<SMTable :headers="headers" :items="items" @row-click="handleRowClick">
<template #item-size="item">
{{ bytesReadable(item.size) }}
</template>
<template #item-actions="item">
<SMButton
label="Edit"
:dropdown="{
download: 'Download',
delete: 'Delete',
}"
size="medium"
@click="handleClick(item, $event)"></SMButton>
</template>
</SMTable>
</SMContainer>
<!-- @click-row="handleClickRow" -->
<!-- <EasyDataTable
v-model:server-options="serverOptions"
:server-items-length="serverItemsLength"
:loading="formLoading"
:headers="headers"
:items="items"
:search-value="search">
<template #loading>
<SMLoadingIcon />
</template>
<template #item-size="item">
{{ bytesReadable(item.size) }}
</template>
<template #item-actions="item">
<div class="action-wrapper">
<SMButton
label="Edit"
:dropdown="{
download: 'Download',
delete: 'Delete',
}"
size="medium"
@click="handleClick(item, $event)"></SMButton>
</div>
</template>
</EasyDataTable> -->
</template>
<script setup lang="ts">
import { reactive, ref, watch } from "vue";
import { useRouter } from "vue-router";
import EasyDataTable from "vue3-easy-data-table";
import { openDialog } from "../../components/SMDialog";
import SMDialogConfirm from "../../components/dialogs/SMDialogConfirm.vue";
import SMButton from "../../components/SMButton.vue";
import SMFileLink from "../../components/SMFileLink.vue";
import SMLoadingIcon from "../../components/SMLoadingIcon.vue";
import SMMessage from "../../components/SMMessage.vue";
import SMToolbar from "../../components/SMToolbar.vue";
import { api } from "../../helpers/api";
import { Media, UserResponse } from "../../helpers/api.types";
import { SMDate } from "../../helpers/datetime";
import { debounce } from "../../helpers/debounce";
import { bytesReadable } from "../../helpers/types";
import { useUserStore } from "../../store/UserStore";
import { useToastStore } from "../../store/ToastStore";
import SMInput from "../../components/SMInput.vue";
import SMMastHead from "../../components/SMMastHead.vue";
import SMTable from "../../components/SMTable.vue";
import SMPagination from "../../components/SMPagination.vue";
const router = useRouter();
const search = ref("");
const userStore = useUserStore();
const toastStore = useToastStore();
const headers = [
{ text: "Name", value: "title", sortable: true },
{ text: "Size", value: "size", sortable: true },
// { text: "Permission", value: "permission", sortable: true },
{ text: "Uploaded By", value: "username", sortable: true },
{ text: "Created", value: "created_at", sortable: true },
// { text: "Updated", value: "updated_at", sortable: true },
{ text: "Actions", value: "actions" },
];
const items = ref([]);
let users = {};
const formLoading = ref(false);
const formMessage = reactive({
message: "",
type: "error",
icon: "",
});
const serverItemsLength = ref(0);
const serverOptions = ref({
page: 1,
rowsPerPage: 25,
sortBy: null,
sortType: null,
});
const total = 108;
const perPage = 25;
const pageValue = ref(1);
const handleRowClick = (item) => {
alert(JSON.stringify(item));
};
const handleClick = (item, extra: string): void => {
if (extra.length == 0) {
handleEdit(item);
} else if (extra.toLowerCase() == "delete") {
handleDelete(item);
}
};
const loadFromServer = async () => {
formLoading.value = true;
formMessage.type = "error";
formMessage.icon = "alert-circle-outline";
formMessage.message = "";
try {
let params = {};
if (serverOptions.value.sortBy) {
params["sort"] = serverOptions.value.sortBy;
if (
serverOptions.value.sortType &&
serverOptions.value.sortType === "desc"
) {
params["sort"] = "-" + params["sort"];
}
}
params["page"] = serverOptions.value.page;
params["limit"] = serverOptions.value.rowsPerPage;
if (search.value.length > 0) {
params["title"] = search.value;
}
let res = await api.get({
url: "/media",
params: params,
});
if (!res.data.media) {
throw new Error("The server is currently not available");
}
items.value = [];
res.data.media.forEach(async (row) => {
if (Object.keys(users).includes(row.user_id) === false) {
try {
const userResult = await api.get({
url: "/users/{id}",
params: {
id: row.user_id,
},
});
const data = userResult.data as UserResponse;
users[row.user_id] = data.user.username;
} catch (error) {
users[row.user_id] = "Unknown";
}
}
if (Object.keys(users).includes(row.user_id)) {
row["username"] = users[row.user_id];
} else {
row["username"] = "--";
}
if (row.created_at !== "undefined") {
row.created_at = new SMDate(row.created_at, {
format: "ymd",
utc: true,
}).relative();
}
if (row.updated_at !== "undefined") {
row.updated_at = new SMDate(row.updated_at, {
format: "ymd",
utc: true,
}).relative();
}
items.value.push(row);
});
serverItemsLength.value = res.data.total;
} catch (err) {
// formMessage.message = parseErrorTyp(err);
} finally {
formLoading.value = false;
}
};
loadFromServer();
watch(
serverOptions,
(value) => {
loadFromServer();
},
{ deep: true }
);
const debouncedFilter = debounce(loadFromServer, 1000);
watch(search, (value) => {
debouncedFilter();
});
const handleClickRow = (item) => {
router.push({ name: "dashboard-media-edit", params: { id: item.id } });
};
const handleEdit = (item) => {
router.push({ name: "dashboard-media-edit", params: { id: item.id } });
};
/**
* Request to delete a media item from the server.
*
* @param {Media} item The media object to delete.
*/
const handleDelete = async (item: Media) => {
let result = await openDialog(SMDialogConfirm, {
title: "Delete File?",
text: `Are you sure you want to delete the file <strong>${item.title}</strong>?`,
cancel: {
type: "secondary",
label: "Cancel",
},
confirm: {
type: "danger",
label: "Delete File",
},
});
if (result) {
try {
let r = await api.delete({
url: "/media/{id}",
params: {
id: item.id,
},
});
toastStore.addToast({
title: "File Deleted",
content: `The file ${item.title} has been deleted.`,
type: "success",
});
loadFromServer();
} catch (error) {
toastStore.addToast({
title: "Error Deleting File",
content:
error.data?.message ||
"An unexpected server error occurred",
type: "danger",
});
}
}
};
const handleDownload = (item) => {
window.open(item.url, "_blank");
};
</script>
<style lang="scss">
body[data-route-name="page-dashboard-media-list"] {
.table tr td:last-of-type {
padding-left: 0;
text-align: center;
&:before {
display: none;
}
}
}
</style>