From 1de9ebdfa5bdec8aa4e2c2bd0677867ed1823270 Mon Sep 17 00:00:00 2001 From: DecDuck Date: Fri, 14 Mar 2025 13:12:04 +1100 Subject: [PATCH] feat: refactor news and migrate rest of useFetch to $dropFetch --- components/DeleteNewsModal.vue | 14 +- ...Create.vue => NewsArticleCreateButton.vue} | 20 +- components/NewsDirectory.vue | 16 +- composables/collection.ts | 10 +- composables/news.ts | 63 ++-- composables/request.ts | 6 +- composables/user.ts | 3 +- pages/admin/index.vue | 3 +- pages/admin/library/[id]/import.vue | 6 +- pages/admin/library/[id]/index.vue | 13 +- pages/admin/library/import.vue | 3 +- pages/admin/library/index.vue | 3 +- pages/admin/users/auth/index.vue | 5 +- pages/admin/users/auth/simple/index.vue | 8 +- pages/admin/users/index.vue | 3 +- pages/client/[id]/callback.vue | 30 +- pages/library/index.vue | 23 +- pages/news.vue | 299 +++++++++--------- pages/news/[id]/index.vue | 18 +- pages/news/index.vue | 19 +- pages/store/[id]/index.vue | 4 +- pages/store/index.vue | 18 +- server/internal/news/index.ts | 9 + 23 files changed, 299 insertions(+), 297 deletions(-) rename components/{NewsArticleCreate.vue => NewsArticleCreateButton.vue} (96%) diff --git a/components/DeleteNewsModal.vue b/components/DeleteNewsModal.vue index 475c8bd..27692e4 100644 --- a/components/DeleteNewsModal.vue +++ b/components/DeleteNewsModal.vue @@ -46,16 +46,22 @@ const article = defineModel
(); 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; } } - + diff --git a/components/NewsArticleCreate.vue b/components/NewsArticleCreateButton.vue similarity index 96% rename from components/NewsArticleCreate.vue rename to components/NewsArticleCreateButton.vue index da29f58..ac49083 100644 --- a/components/NewsArticleCreate.vue +++ b/components/NewsArticleCreateButton.vue @@ -4,13 +4,13 @@ @@ -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."; diff --git a/components/NewsDirectory.vue b/components/NewsDirectory.vue index 58a6c3d..bf33ac9 100644 --- a/components/NewsDirectory.vue +++ b/components/NewsDirectory.vue @@ -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([]); -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(); - 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 diff --git a/composables/collection.ts b/composables/collection.ts index 320d00c..afc5142 100644 --- a/composables/collection.ts +++ b/composables/collection.ts @@ -9,10 +9,7 @@ export const useCollections = async () => { // @ts-expect-error const state = useState("collections", () => undefined); if (state.value === undefined) { - const headers = useRequestHeaders(["cookie"]); - state.value = await $dropFetch("/api/v1/collection", { - headers, - }); + state.value = await $dropFetch("/api/v1/collection"); } return state; @@ -41,8 +38,5 @@ export const useLibrary = async () => { export async function refreshLibrary() { const state = useState("library"); - const headers = useRequestHeaders(["cookie"]); - state.value = await $dropFetch("/api/v1/collection/default", { - headers, - }); + state.value = await $dropFetch("/api/v1/collection/default"); } diff --git a/composables/news.ts b/composables/news.ts index cda4c77..620d8b7 100644 --- a/composables/news.ts +++ b/composables/news.ts @@ -1,35 +1,40 @@ -export const useNews = () => { - const getAll = async (options?: { - limit?: number; - skip?: number; - orderBy?: "asc" | "desc"; - tags?: string[]; - search?: string; - }) => { - const query = new URLSearchParams(); +import type { Article } from "@prisma/client"; +import type { SerializeObject } from "nitropack"; - if (options?.limit) query.set("limit", options.limit.toString()); - if (options?.skip) query.set("skip", options.skip.toString()); - if (options?.orderBy) query.set("order", options.orderBy); - if (options?.tags?.length) query.set("tags", options.tags.join(",")); - if (options?.search) query.set("search", options.search); +export const useNews = () => + useState< + | Array< + SerializeObject< + Article & { + tags: Array<{ id: string; name: string }>; + author: { displayName: string; id: string } | null; + } + > + > + | undefined + >("news", () => undefined); - return await useFetch(`/api/v1/news?${query.toString()}`); - }; +export const fetchNews = async (options?: { + limit?: number; + skip?: number; + orderBy?: "asc" | "desc"; + tags?: string[]; + search?: string; +}) => { + const query = new URLSearchParams(); - const getById = async (id: string) => { - return await useFetch(`/api/v1/news/${id}`); - }; + if (options?.limit) query.set("limit", options.limit.toString()); + if (options?.skip) query.set("skip", options.skip.toString()); + if (options?.orderBy) query.set("order", options.orderBy); + if (options?.tags?.length) query.set("tags", options.tags.join(",")); + if (options?.search) query.set("search", options.search); - const remove = async (id: string) => { - return await $dropFetch(`/api/v1/admin/news/${id}`, { - method: "DELETE", - }); - }; + const news = useNews(); - return { - getAll, - getById, - remove, - }; + // @ts-ignore + const newValue = await $dropFetch(`/api/v1/news?${query.toString()}`); + + news.value = newValue; + + return newValue; }; diff --git a/composables/request.ts b/composables/request.ts index bfc2b54..b8b6c79 100644 --- a/composables/request.ts +++ b/composables/request.ts @@ -31,7 +31,11 @@ export const $dropFetch: DropFetch = async (request, opts) => { if (!getCurrentInstance()?.proxy) { return (await $fetch(request, opts)) as any; } - const { data, error } = await useFetch(request, opts as any); + const headers = useRequestHeaders(["cookie"]); + const { data, error } = await useFetch(request, { + ...opts, + headers: { ...opts?.headers, ...headers }, + } as any); if (error.value) throw error.value; return data.value as any; }; diff --git a/composables/user.ts b/composables/user.ts index 6fe8d85..7c1f189 100644 --- a/composables/user.ts +++ b/composables/user.ts @@ -6,11 +6,10 @@ import type { User } from "@prisma/client"; export const useUser = () => useState(undefined); export const updateUser = async () => { - const headers = useRequestHeaders(["cookie"]); const user = useUser(); if (user.value === null) return; // SSR calls have to be after uses - user.value = await $dropFetch("/api/v1/user", { headers }); + user.value = await $dropFetch("/api/v1/user"); }; diff --git a/pages/admin/index.vue b/pages/admin/index.vue index 6068318..4e233b6 100644 --- a/pages/admin/index.vue +++ b/pages/admin/index.vue @@ -176,6 +176,5 @@ useHead({ title: "Home", }); -const headers = useRequestHeaders(["cookie"]); -const libraryState = await $dropFetch("/api/v1/admin/library", { headers }); +const libraryState = await $dropFetch("/api/v1/admin/library"); diff --git a/pages/admin/library/[id]/import.vue b/pages/admin/library/[id]/import.vue index 47c1219..348de3b 100644 --- a/pages/admin/library/[id]/import.vue +++ b/pages/admin/library/[id]/import.vue @@ -551,13 +551,9 @@ definePageMeta({ const router = useRouter(); const route = useRoute(); -const headers = useRequestHeaders(["cookie"]); const gameId = route.params.id.toString(); const versions = await $dropFetch( - `/api/v1/admin/import/version?id=${encodeURIComponent(gameId)}`, - { - headers, - } + `/api/v1/admin/import/version?id=${encodeURIComponent(gameId)}` ); const currentlySelectedVersion = ref(-1); const versionSettings = ref<{ diff --git a/pages/admin/library/[id]/index.vue b/pages/admin/library/[id]/index.vue index d8beecb..986fe76 100644 --- a/pages/admin/library/[id]/index.vue +++ b/pages/admin/library/[id]/index.vue @@ -321,7 +321,10 @@ {{ item.delta ? "Upgrade mode" : "" }}
- +
+ + + + + diff --git a/pages/news/[id]/index.vue b/pages/news/[id]/index.vue index 0f52c4a..8bc3da9 100644 --- a/pages/news/[id]/index.vue +++ b/pages/news/[id]/index.vue @@ -70,10 +70,7 @@ -
+
@@ -85,16 +82,19 @@ import { TrashIcon } from "@heroicons/vue/24/outline"; import { micromark } from "micromark"; const route = useRoute(); -const { data: article } = await useNews().getById(route.params.id as string); const currentlyDeleting = ref(); const user = useUser(); - -if (!article.value) { +const news = useNews(); +if (!news.value) { + news.value = await fetchNews(); +} +const article = computed(() => news.value?.find((e) => e.id == route.params.id)); +if (!article.value) throw createError({ statusCode: 404, - message: "Article not found", + statusMessage: "Article not found", + fatal: true, }); -} // Render markdown content const renderedContent = computed(() => { diff --git a/pages/news/index.vue b/pages/news/index.vue index 99cb4c1..f36648e 100644 --- a/pages/news/index.vue +++ b/pages/news/index.vue @@ -10,8 +10,6 @@ Stay up to date with the latest updates and announcements.

- - @@ -83,9 +81,17 @@