feat: refactor news and migrate rest of useFetch to $dropFetch

This commit is contained in:
DecDuck
2025-03-14 13:12:04 +11:00
parent bd1cb67cd0
commit 1de9ebdfa5
23 changed files with 299 additions and 297 deletions

View File

@@ -46,16 +46,22 @@ const article = defineModel<Article | undefined>();
const deleteLoading = ref(false);
const router = useRouter();
const news = useNews();
if (!news.value) {
news.value = await fetchNews();
}
async function deleteArticle() {
try {
if (!article.value) return;
if (!article.value || !news.value) return;
deleteLoading.value = true;
await news.remove(article.value.id);
await $dropFetch(`/api/v1/admin/news/${article.value.id}`, { method: "DELETE" });
const index = news.value.findIndex((e) => e.id == article.value?.id);
news.value.splice(index, 1);
article.value = undefined;
await router.push('/news');
router.push("/news");
} catch (e: any) {
createModal(
ModalType.Notification,
@@ -69,4 +75,4 @@ async function deleteArticle() {
deleteLoading.value = false;
}
}
</script>
</script>

View File

@@ -4,13 +4,13 @@
<button
v-if="user?.admin"
@click="modalOpen = !modalOpen"
class="inline-flex items-center gap-x-2 px-4 py-2 rounded-lg bg-blue-600 text-white font-semibold font-display shadow-sm transition-all duration-200 hover:bg-blue-500 hover:scale-105 hover:shadow-blue-500/25 hover:shadow-lg active:scale-95"
class="transition inline-flex w-full items-center px-4 gap-x-2 py-2 bg-zinc-800 hover:bg-zinc-700 text-zinc-200 font-semibold text-sm shadow-sm"
>
<PlusIcon
class="h-5 w-5 transition-transform duration-200"
:class="{ 'rotate-90': modalOpen }"
/>
<span>New Article</span>
<span>New article</span>
</button>
<ModalTemplate size-class="sm:max-w-[80vw]" v-model="modalOpen">
@@ -207,14 +207,16 @@ import {
XCircleIcon,
XMarkIcon,
} from "@heroicons/vue/24/solid";
import type { Article } from "@prisma/client";
import { micromark } from "micromark";
import type { SerializeObject } from "nitropack/types";
const emit = defineEmits<{
refresh: [];
}>();
const news = useNews();
if(!news.value){
news.value = await fetchNews();
}
const user = useUser();
const news = useNews();
const modalOpen = ref(false);
const loading = ref(false);
@@ -348,11 +350,13 @@ async function createArticle() {
formData.append("content", newArticle.value.content);
formData.append("tags", JSON.stringify(newArticle.value.tags));
await $dropFetch("/api/v1/admin/news", {
const createdArticle = await $dropFetch("/api/v1/admin/news", {
method: "POST",
body: formData,
});
news.value?.push(createdArticle);
// Reset form
newArticle.value = {
title: "",
@@ -361,8 +365,6 @@ async function createArticle() {
tags: [],
};
emit("refresh");
modalOpen.value = false;
} catch (e) {
error.value = (e as any)?.statusMessage ?? "An unknown error occured.";

View File

@@ -116,19 +116,21 @@ import { ref, computed } from "vue";
import { MagnifyingGlassIcon } from "@heroicons/vue/24/solid";
import { micromark } from "micromark";
const news = useNews();
if(!news.value){
news.value = await fetchNews();
}
const route = useRoute();
const searchQuery = ref("");
const dateFilter = ref("all");
const selectedTags = ref<string[]>([]);
const { data: articles, refresh: refreshArticles } = await useNews().getAll();
defineExpose({ refresh: refreshArticles });
// Get unique tags from all articles
const availableTags = computed(() => {
if (!articles.value) return [];
if (!news.value) return [];
const tags = new Set<string>();
articles.value.forEach((article) => {
news.value.forEach((article) => {
article.tags.forEach((tag) => tags.add(tag.name));
});
return Array.from(tags);
@@ -159,10 +161,10 @@ const formatExcerpt = (excerpt: string) => {
};
const filteredArticles = computed(() => {
if (!articles.value) return [];
if (!news.value) return [];
// filter articles based on search, date, and tags
return articles.value.filter((article) => {
return news.value.filter((article) => {
const matchesSearch =
article.title.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
article.description