Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!: use @tanstack/vue-query instead of useAsyncData #656

Merged
merged 3 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/dull-icons-report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"enspire": patch
---

Refactor internal strategy for making API requests
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
shamefully-hoist=true
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@

const { toast } = useToast()

const { data } = await useAsyncData<ClassroomData[]>('classroomStatuses', () => {
return $fetch<ClassroomData[]>(`/api/reservation/classroomId`, {
headers: useRequestHeaders(),
method: 'GET',
})
const { data, suspense } = useQuery<ClassroomData[]>({
queryKey: ['/api/reservation/classroomId'],
})
await suspense()

if (!data.value) {
toast({
Expand All @@ -32,12 +30,10 @@
data.value = data.value.sort((a: any, b: any) => a.name < b.name ? -1 : 1)
}

const { data: clubs } = await useAsyncData<AllClubs>('allClubs', () => {
return $fetch<AllClubs>(`/api/user/all_clubs`, {
headers: useRequestHeaders(),
method: 'GET',
})
const { data: clubs, suspense: clubsSuspense } = useQuery<AllClubs>({
queryKey: ['/api/user/all_clubs'],
})
await clubsSuspense()

if (!clubs.value) {
toast({
Expand Down Expand Up @@ -141,10 +137,10 @@
<FormItem>
<FormLabel>预约时间</FormLabel>
<FormControl>
<div class="flex flex-col sm:flex-row space-y-2 sm:space-y-0 sm:space-x-1 justify-start">

Check warning on line 140 in components/custom/CAS/ClassroomReservation/NewClassroomReservation.vue

View workflow job for this annotation

GitHub Actions / Lint

UnoCSS utilities are not ordered
<!-- This ToggleGroup should be implemented in a better way but anyway it works -->
<ToggleGroup :key="reloadKey" type="multiple" variant="outline">
<div class="text-muted-foreground text-sm text-center w-7">

Check warning on line 143 in components/custom/CAS/ClassroomReservation/NewClassroomReservation.vue

View workflow job for this annotation

GitHub Actions / Lint

UnoCSS utilities are not ordered
每周
</div>
<ToggleGroupItem value="mon" @click="day[1] = !day[1]">
Expand Down Expand Up @@ -180,7 +176,7 @@
<FormItem>
<FormLabel>选择教室</FormLabel>
<div v-if="!clubs || !data">
<Skeleton class="h-5 p-3 my-3" />

Check warning on line 179 in components/custom/CAS/ClassroomReservation/NewClassroomReservation.vue

View workflow job for this annotation

GitHub Actions / Lint

UnoCSS utilities are not ordered
</div>
<FormControl>
<Select v-model="formData.classroom" required>
Expand Down Expand Up @@ -260,7 +256,7 @@
</FormField>
<div class="py-2" />
<Button type="submit" :disabled="pending" class="mr-3">
<LoaderCircle v-if="pending" class="animate-spin mr-2" />

Check warning on line 259 in components/custom/CAS/ClassroomReservation/NewClassroomReservation.vue

View workflow job for this annotation

GitHub Actions / Lint

UnoCSS utilities are not ordered
<span v-if="!pending">提交预约</span>
<span v-if="pending">处理中...</span>
</Button>
Expand Down
12 changes: 3 additions & 9 deletions components/custom/CAS/Record/NewActivityRecord.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import * as z from 'zod'
import { Toaster } from '~/components/ui/toast'
import { cn } from '~/lib/utils'
import type { AllClubs } from '~/types/api/user/all_clubs'

Check failure on line 24 in components/custom/CAS/Record/NewActivityRecord.vue

View workflow job for this annotation

GitHub Actions / Lint

Expected "~/types/api/user/all_clubs" (internal-type) to come before "~/lib/utils" (internal)

const emit = defineEmits(['refresh'])

Expand All @@ -33,10 +33,6 @@

const selectedClub = ref<string>()

definePageMeta({
middleware: ['auth'],
})

const isLoading = ref(false)

const formSchema = toTypedSchema(z.object({
Expand All @@ -51,12 +47,10 @@
sTime: z.number().min(0).max(5),
}))

const { data } = await useAsyncData<AllClubs>('allClubsWithMemberships', async () => {
return await $fetch<AllClubs>('/api/user/all_clubs?includeMemberships=true', {
headers: useRequestHeaders(),
method: 'GET',
})
const { data, suspense } = useQuery<AllClubs>({
queryKey: ['/api/user/all_clubs'],
})
await suspense()

if (!data.value) {
throw createError({
Expand Down
28 changes: 10 additions & 18 deletions components/custom/CAS/Record/ViewMyActivityRecords.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<script setup lang="ts">
import type { Ref } from 'vue'
import type { MyRecords } from '~/types/api/cas/record/my'
import type { AllClubs } from '~/types/api/user/all_clubs'
import {
Card,
CardContent,
Expand All @@ -16,36 +18,26 @@
SelectValue,
} from '@/components/ui/select'
import { Toaster } from '~/components/ui/toast'
import type { MyRecords } from '~/types/api/cas/record/my'
import type { AllClubs } from '~/types/api/user/all_clubs'
import { columns } from './view-activity-records/columns'
import DataTable from './view-activity-records/DataTable.vue'
import { useQuery } from '@tanstack/vue-query';

Check failure on line 23 in components/custom/CAS/Record/ViewMyActivityRecords.vue

View workflow job for this annotation

GitHub Actions / Lint

Expected "@tanstack/vue-query" (external) to come before "./view-activity-records/DataTable.vue" (sibling)

Check failure on line 23 in components/custom/CAS/Record/ViewMyActivityRecords.vue

View workflow job for this annotation

GitHub Actions / Lint

Extra semicolon

const props = defineProps<{
refreshWatcher: Ref<boolean>
}>()

definePageMeta({
middleware: ['auth'],
})

const selectedClub = ref<string>()
const isLoading = ref(false)

const { data: clubs } = await useAsyncData<AllClubs>('allClubs', () => {
return $fetch<AllClubs>(`/api/user/all_clubs`, {
headers: useRequestHeaders(),
method: 'GET',
})
const { data: clubs, suspense } = useQuery<AllClubs>({
queryKey: ['/api/user/all_clubs'],
})
await suspense()

const { data, refresh } = await useAsyncData<MyRecords>('allRequests', () => {
return selectedClub.value
? $fetch<MyRecords>(`/api/cas/record/my?club=${selectedClub.value}`, {
headers: useRequestHeaders(),
method: 'GET',
})
: Promise.resolve({ total: 0, data: [] })
const { data, refetch: refresh } = useQuery<MyRecords>({
queryKey: [`/api/cas/record/my?club=`, selectedClub],
enabled: !!selectedClub.value,
placeholderData: { total: 0, data: [] },
})

async function onRefresh() {
Expand Down Expand Up @@ -123,7 +115,7 @@
</Button>
</div>
<div v-if="selectedClub" class="mb-4 text-sm">
<div class="rounded border p-2 mt-1 flex justify-between">

Check warning on line 118 in components/custom/CAS/Record/ViewMyActivityRecords.vue

View workflow job for this annotation

GitHub Actions / Lint

UnoCSS utilities are not ordered
<div class="flex items-center space-x-0.5">
<p class="font-bold">
C:
Expand Down
7 changes: 3 additions & 4 deletions components/custom/Index/announcements.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@
import type { Announcements } from '~/types/payloadcms/announcements'
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'

const { data } = await useAsyncData<Announcements>('allRequests', () => {
return $fetch('/api/cms/api/announcements', {
method: 'GET',
})
const { data, suspense } = useQuery<Announcements>({
queryKey: ['/api/cms/api/announcements'],
})
await suspense()
</script>

<template>
Expand Down
25 changes: 10 additions & 15 deletions components/custom/sidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,21 @@
import type { AllClubs } from '~/types/api/user/all_clubs'
import { Button } from '@/components/ui/button'
import { cn } from '@/lib/utils'
import { useClerk } from 'vue-clerk'

const clerk = useClerk()
const route = useRoute()

const isPresidentOrVicePresident = ref(false)
useState('isEnspireLoading').value = true

if (import.meta.client) {
if (clerk.user?.publicMetadata.binded) {
const clubs = await $fetch<AllClubs>(`/api/user/all_clubs`, {
headers: useRequestHeaders(),
method: 'GET',
})
if (clubs) {
useState('isEnspireLoading').value = false
if (clubs.president.length !== 0 || clubs.vice.length !== 0) {
isPresidentOrVicePresident.value = true
}
}
const { data: clubs, suspense } = useQuery<AllClubs>({
queryKey: ['/api/user/all_clubs'],
})
await suspense()

if (clubs.value) {
useState('isEnspireLoading').value = false
if (clubs.value.president.length !== 0 || clubs.value.vice.length !== 0) {
isPresidentOrVicePresident.value = true
}
}
</script>
Expand Down Expand Up @@ -64,7 +59,7 @@ if (import.meta.client) {
</Button>
</NuxtLink>
<NuxtLink v-if="[0, 1, 5, 6].includes(new Date().getMonth())" to="/cas/rating">
<Button :variant="route.name === 'cas-rating' ? 'secondary' : 'ghost'" class="w-full justify-start mt-1">
<Button :variant="route.name === 'cas-rating' ? 'secondary' : 'ghost'" class="mt-1 w-full justify-start">
<Icon class="mr-2 h-4 w-4" name="material-symbols:rate-review-outline" />
期末评价
</Button>
Expand Down
2 changes: 2 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import antfu from '@antfu/eslint-config'
import pluginQuery from '@tanstack/eslint-plugin-query'

export default antfu({
typescript: {
Expand All @@ -7,6 +8,7 @@ export default antfu({
vue: true,
ignores: ['components/ui/'],
unocss: true,
...pluginQuery.configs['flat/recommended'],
}, {
rules: {
'node/prefer-global/process': 'off',
Expand Down
15 changes: 15 additions & 0 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,20 @@ export default defineNuxtConfig({
client: true,
},

imports: {
presets: [
{
from: '@tanstack/vue-query',
imports: ['useQuery'],
},
],
},

vite: {
optimizeDeps: {
exclude: ['vee-validate'],
},
},

compatibilityDate: '2024-08-31',
})
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@nuxt/content": "^2.13.4",
"@radix-icons/vue": "^1.0.0",
"@sentry/nuxt": "^8.42.0",
"@tanstack/vue-query": "^5.62.8",
"@tanstack/vue-table": "^8.20.5",
"@unovis/ts": "^1.4.5",
"@unovis/vue": "^1.4.5",
Expand Down Expand Up @@ -71,6 +72,7 @@
"@nuxtjs/google-fonts": "^3.2.0",
"@prisma/client": "^6.0.1",
"@rollup/plugin-wasm": "^6.2.2",
"@tanstack/eslint-plugin-query": "^5.62.1",
"@types/node-fetch": "^2.6.12",
"@types/sanitize-html": "^2.13.0",
"@types/uuid": "^10.0.0",
Expand Down
10 changes: 4 additions & 6 deletions pages/cas/rating.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import type { InternalApi } from 'nitropack'
import { Button } from '@/components/ui/button'
import { Card, CardContent } from '@/components/ui/card'
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from '@/components/ui/select'
Expand Down Expand Up @@ -28,11 +29,8 @@ const formSchema = toTypedSchema(z.object({
comment: z.string().max(100).optional(),
}))

const { data } = await useAsyncData('allRequests', () => {
return $fetch('/api/club/rating/available', {
headers: useRequestHeaders(),
method: 'GET',
})
const { data } = await useQuery<InternalApi['/api/club/rating/available']['get']>({
queryKey: ['/api/club/rating/available'],
})

if (!data.value) {
Expand Down Expand Up @@ -91,7 +89,7 @@ function onSubmitRating() {
<SelectContent>
<SelectGroup v-if="data">
<SelectItem v-for="club in data" :key="club.id" :value="String(club.id)">
{{ typeof club.name === 'object' && 'zh' in club.name! ? club.name.zh : '' }}
{{ typeof club?.name === 'object' && 'zh' in club.name! ? club.name.zh : '' }}
</SelectItem>
</SelectGroup>
</SelectContent>
Expand Down
10 changes: 4 additions & 6 deletions pages/forms/[id].vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<script setup lang="ts">
import type { Form } from '~/types/data/forms'
import { useWindowSize } from '@vueuse/core'
import { useClerk } from 'vue-clerk'
import { toast } from '~/components/ui/toast'
import type { Form } from '~/types/data/forms'

const clerk = useClerk()

Expand All @@ -16,12 +16,10 @@ useHead({
title: 'Forms | Enspire',
})

const { data } = await useAsyncData<Form[]>('classroomStatuses', async () => {
return await $fetch<Form[]>(`/api/forms/open`, {
headers: useRequestHeaders(),
method: 'GET',
})
const { data, suspense } = useQuery<Form[]>({
queryKey: ['/api/forms/open'],
})
await suspense()

if (!data.value) {
toast({
Expand Down
16 changes: 7 additions & 9 deletions pages/forms/index.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import type { Form } from '~/types/data/forms'
import {
Card,
CardDescription,
Expand All @@ -8,7 +9,6 @@ import {
} from '@/components/ui/card'
import Toaster from '@/components/ui/toast/Toaster.vue'
import { toast } from '~/components/ui/toast'
import type { Form } from '~/types/data/forms'

definePageMeta({
middleware: ['auth'],
Expand All @@ -18,12 +18,10 @@ useHead({
title: 'Forms | Enspire',
})

const { data } = await useAsyncData<Form[]>('classroomStatuses', async () => {
return await $fetch<Form[]>(`/api/forms/open`, {
headers: useRequestHeaders(),
method: 'GET',
})
const { data, suspense } = useQuery<Form[]>({
queryKey: ['/api/forms/open'],
})
suspense()

if (!data.value) {
toast({
Expand All @@ -34,18 +32,18 @@ if (!data.value) {
</script>

<template>
<div class="font-bold flex items-center space-x-2 text-lg">
<div class="flex items-center text-lg font-bold space-x-2">
<Icon name="material-symbols:edit-square-outline" />
<div>可填写的表单</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4 mt-2">
<div class="grid grid-cols-1 mt-2 gap-4 md:grid-cols-2 xl:grid-cols-3">
<NuxtLink v-for="club in data" :key="club.id" :to="`/forms/${club.id}`">
<Card class="hover:underline">
<CardHeader>
<CardTitle>{{ club.title }}</CardTitle>
<CardDescription>{{ club.description }}</CardDescription>
</CardHeader>
<CardFooter class="text-muted-foreground text-sm flex items-center">
<CardFooter class="flex items-center text-sm text-muted-foreground">
<div>点击填写</div>
<Icon name="material-symbols:arrow-forward" />
</CardFooter>
Expand Down
8 changes: 3 additions & 5 deletions pages/manage/statuses.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,10 @@ const selectedPeriod = ref(time2period(utc8Time.hour() * 100 + utc8Time.minute()

let dataLoaded = false

const { data } = await useAsyncData<ClassroomData[]>('classroomStatuses', async () => {
return await $fetch<ClassroomData[]>(`/api/reservation/classroomId`, {
headers: useRequestHeaders(),
method: 'GET',
})
const { data, suspense } = useQuery<ClassroomData[]>({
queryKey: ['/api/reservation/classroomId'],
})
suspense()

if (data.value) {
data.value = data.value.sort((a: any, b: any) => a.name < b.name ? -1 : 1)
Expand Down
38 changes: 38 additions & 0 deletions plugins/vue-query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type {
DehydratedState,
VueQueryPluginOptions,
} from '@tanstack/vue-query'
import {
dehydrate,
hydrate,
QueryClient,
VueQueryPlugin,
} from '@tanstack/vue-query'
import { defaultQuery } from '~/queries/default'

export default defineNuxtPlugin((nuxt) => {
const vueQueryState = useState<DehydratedState | null>('vue-query')

// Modify your Vue Query global settings here
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 5000,
queryFn: defaultQuery,
},
},
})
const options: VueQueryPluginOptions = { queryClient }

nuxt.vueApp.use(VueQueryPlugin, options)

if (import.meta.server) {
nuxt.hooks.hook('app:rendered', () => {
vueQueryState.value = dehydrate(queryClient)
})
}

if (import.meta.client) {
hydrate(queryClient, vueQueryState.value)
}
})
Loading
Loading