refactor: removing useAsyncData for tanstack query (#5262)
* refactor: most places with useAsyncData replaced with tanstack query * refactor report list and report view * refactor organization page to use tanstack query * fix types * refactor collection page and include proper loading state * fix followed projects proper loading state * fix 404 handling * fix organization loading and 404 states * pnpm prepr * refactor: remove useAsyncData on newsletter button * refactor: remove useAsyncData on auth globals fetch * refactor: settings/billing/index.vue to useQuery instead of useAsyncData * refactor: user page to remove useAsyncData * pnpm prepr * fix reports pages * fix notifications page * fix billing page cannot read properties of null and prop warnings * fix refresh causing 404 by removing useBaseFetch and use api-client * fix stale data after removing organization from project * pnpm prepr * fix news erroring in build * fix: project page loads header only after content * fix: user page tanstack problems (start on migrating away from useBaseFetch) * fix: start swapping useBaseFetch usages to api-client * Revert "fix: start swapping useBaseFetch usages to api-client" This reverts commit 3df3fab11d535159132b1288dd7cacc38282b553. * fix: remove debug logging * fix: lint --------- Co-authored-by: Calum H. <calum@modrinth.com> Co-authored-by: Calum H. (IMB11) <contact@cal.engineer>
This commit is contained in:
@@ -282,7 +282,7 @@
|
||||
<div v-if="navLinks.length > 2" class="mb-4 max-w-full overflow-x-auto">
|
||||
<NavTabs :links="navLinks" replace />
|
||||
</div>
|
||||
<div v-if="projects.length > 0">
|
||||
<div v-if="projects?.length > 0">
|
||||
<ProjectCardList
|
||||
v-if="route.params.projectType !== 'collections'"
|
||||
:layout="cosmetics.searchDisplayMode.user"
|
||||
@@ -331,7 +331,7 @@
|
||||
<div
|
||||
v-else-if="
|
||||
(route.params.projectType && route.params.projectType !== 'collections') ||
|
||||
(!route.params.projectType && collections.length === 0)
|
||||
(!route.params.projectType && collections?.length === 0)
|
||||
"
|
||||
class="error"
|
||||
>
|
||||
@@ -353,7 +353,7 @@
|
||||
class="collections-grid"
|
||||
>
|
||||
<nuxt-link
|
||||
v-for="collection in collections.sort(
|
||||
v-for="collection in (collections ?? []).sort(
|
||||
(a, b) => new Date(b.created) - new Date(a.created),
|
||||
)"
|
||||
:key="collection.id"
|
||||
@@ -404,7 +404,7 @@
|
||||
</nuxt-link>
|
||||
</div>
|
||||
<div
|
||||
v-if="route.params.projectType === 'collections' && collections.length === 0"
|
||||
v-if="route.params.projectType === 'collections' && collections?.length === 0"
|
||||
class="error"
|
||||
>
|
||||
<UpToDate class="icon" />
|
||||
@@ -425,7 +425,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="normal-page__sidebar">
|
||||
<div v-if="organizations.length > 0" class="card flex-card">
|
||||
<div v-if="organizations?.length > 0" class="card flex-card">
|
||||
<h2 class="text-lg text-contrast">
|
||||
{{ formatMessage(messages.profileOrganizations) }}
|
||||
</h2>
|
||||
@@ -492,6 +492,7 @@ import {
|
||||
commonMessages,
|
||||
ContentPageHeader,
|
||||
defineMessages,
|
||||
injectModrinthClient,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
NewModal,
|
||||
@@ -506,6 +507,8 @@ import {
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { isAdmin, isStaff, UserBadge } from '@modrinth/utils'
|
||||
import { useQuery, useQueryClient } from '@tanstack/vue-query'
|
||||
import { onServerPrefetch } from 'vue'
|
||||
|
||||
import TenMClubBadge from '~/assets/images/badges/10m-club.svg?component'
|
||||
import AlphaTesterBadge from '~/assets/images/badges/alpha-tester.svg?component'
|
||||
@@ -527,6 +530,7 @@ const auth = await useAuth()
|
||||
const cosmetics = useCosmetics()
|
||||
const tags = useGeneratedState()
|
||||
const config = useRuntimeConfig()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
const formatNumber = useFormatNumber()
|
||||
@@ -679,74 +683,81 @@ const messages = defineMessages({
|
||||
},
|
||||
})
|
||||
|
||||
let user, projects, organizations, collections, refreshUser
|
||||
try {
|
||||
;[
|
||||
{ data: user, refresh: refreshUser },
|
||||
{ data: projects },
|
||||
{ data: organizations },
|
||||
{ data: collections },
|
||||
] = await Promise.all([
|
||||
useAsyncData(`user/${route.params.id}`, () => useBaseFetch(`user/${route.params.id}`)),
|
||||
useAsyncData(
|
||||
`user/${route.params.id}/projects`,
|
||||
() => useBaseFetch(`user/${route.params.id}/projects`),
|
||||
{
|
||||
transform: (projects) => {
|
||||
for (const project of projects) {
|
||||
project.categories = project.categories.concat(project.loaders)
|
||||
project.project_type = data.$getProjectTypeForUrl(
|
||||
project.project_type,
|
||||
project.categories,
|
||||
tags.value,
|
||||
)
|
||||
}
|
||||
const client = injectModrinthClient()
|
||||
|
||||
return projects
|
||||
},
|
||||
},
|
||||
),
|
||||
useAsyncData(`user/${route.params.id}/organizations`, () =>
|
||||
useBaseFetch(`user/${route.params.id}/organizations`, {
|
||||
apiVersion: 3,
|
||||
}),
|
||||
),
|
||||
useAsyncData(`user/${route.params.id}/collections`, () =>
|
||||
useBaseFetch(`user/${route.params.id}/collections`, { apiVersion: 3 }),
|
||||
),
|
||||
const {
|
||||
data: user,
|
||||
error: userError,
|
||||
suspense: userSuspense,
|
||||
} = useQuery({
|
||||
queryKey: computed(() => ['user', route.params.id]),
|
||||
queryFn: () => client.labrinth.users_v2.get(route.params.id),
|
||||
})
|
||||
|
||||
watch(
|
||||
userError,
|
||||
(error) => {
|
||||
if (error) {
|
||||
const status = error.statusCode ?? error.status ?? 404
|
||||
showError({
|
||||
fatal: true,
|
||||
statusCode: status,
|
||||
message: formatMessage(messages.userNotFoundError),
|
||||
})
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
const { data: projects, suspense: projectsSuspense } = useQuery({
|
||||
queryKey: computed(() => ['user', route.params.id, 'projects']),
|
||||
queryFn: async () => {
|
||||
const projects = await client.labrinth.users_v2.getProjects(route.params.id)
|
||||
for (const project of projects) {
|
||||
project.categories = project.categories.concat(project.loaders)
|
||||
project.project_type = data.$getProjectTypeForUrl(
|
||||
project.project_type,
|
||||
project.categories,
|
||||
tags.value,
|
||||
)
|
||||
}
|
||||
return projects
|
||||
},
|
||||
})
|
||||
|
||||
const { data: organizations, suspense: orgsSuspense } = useQuery({
|
||||
queryKey: computed(() => ['user', route.params.id, 'organizations']),
|
||||
queryFn: () => client.labrinth.users_v2.getOrganizations(route.params.id),
|
||||
})
|
||||
|
||||
const { data: collections, suspense: collectionsSuspense } = useQuery({
|
||||
queryKey: computed(() => ['user', route.params.id, 'collections']),
|
||||
queryFn: () => client.labrinth.users_v2.getCollections(route.params.id),
|
||||
})
|
||||
|
||||
onServerPrefetch(async () => {
|
||||
await Promise.allSettled([
|
||||
userSuspense(),
|
||||
projectsSuspense(),
|
||||
orgsSuspense(),
|
||||
collectionsSuspense(),
|
||||
])
|
||||
} catch {
|
||||
throw createError({
|
||||
fatal: true,
|
||||
statusCode: 404,
|
||||
message: formatMessage(messages.userNotFoundError),
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const sortedOrgs = computed(() =>
|
||||
organizations.value ? [...organizations.value].sort((a, b) => a.name.localeCompare(b.name)) : [],
|
||||
)
|
||||
|
||||
if (!user.value) {
|
||||
throw createError({
|
||||
fatal: true,
|
||||
statusCode: 404,
|
||||
message: formatMessage(messages.userNotFoundError),
|
||||
})
|
||||
}
|
||||
|
||||
if (user.value.username !== route.params.id) {
|
||||
await navigateTo(`/user/${user.value.username}`, { redirectCode: 301 })
|
||||
}
|
||||
|
||||
const title = computed(() => `${user.value.username} - Modrinth`)
|
||||
const title = computed(() => (user.value ? `${user.value.username} - Modrinth` : 'Modrinth'))
|
||||
const description = computed(() =>
|
||||
user.value.bio
|
||||
user.value?.bio
|
||||
? formatMessage(messages.profileMetaDescriptionWithBio, {
|
||||
bio: user.value.bio,
|
||||
username: user.value.username,
|
||||
})
|
||||
: formatMessage(messages.profileMetaDescription, { username: user.value.username }),
|
||||
: user.value
|
||||
? formatMessage(messages.profileMetaDescription, { username: user.value.username })
|
||||
: '',
|
||||
)
|
||||
|
||||
useSeoMeta({
|
||||
@@ -754,7 +765,7 @@ useSeoMeta({
|
||||
description: () => description.value,
|
||||
ogTitle: () => title.value,
|
||||
ogDescription: () => description.value,
|
||||
ogImage: () => user.value.avatar_url ?? 'https://cdn.modrinth.com/placeholder.png',
|
||||
ogImage: () => user.value?.avatar_url ?? 'https://cdn.modrinth.com/placeholder.png',
|
||||
})
|
||||
|
||||
const projectTypes = computed(() => {
|
||||
@@ -838,15 +849,12 @@ async function copyPermalink() {
|
||||
await navigator.clipboard.writeText(`${config.public.siteUrl}/user/${user.value.id}`)
|
||||
}
|
||||
|
||||
const isAffiliate = computed(() => user.value.badges & UserBadge.AFFILIATE)
|
||||
const isAffiliate = computed(() => user.value?.badges & UserBadge.AFFILIATE)
|
||||
const isAdminViewing = computed(() => isAdmin(auth.value.user))
|
||||
|
||||
async function toggleAffiliate(id) {
|
||||
await useBaseFetch(`user/${id}`, {
|
||||
method: 'PATCH',
|
||||
body: { badges: user.value.badges ^ (1 << 7) },
|
||||
})
|
||||
refreshUser()
|
||||
await client.labrinth.users_v2.patch(id, { badges: user.value.badges ^ (1 << 7) })
|
||||
queryClient.invalidateQueries({ queryKey: ['user', route.params.id] })
|
||||
}
|
||||
|
||||
const navLinks = computed(() => [
|
||||
@@ -865,7 +873,7 @@ const navLinks = computed(() => [
|
||||
.sort((a, b) => a.label.localeCompare(b.label)),
|
||||
])
|
||||
|
||||
const selectedRole = ref(user.value.role)
|
||||
const selectedRole = ref(user.value?.role)
|
||||
const isSavingRole = ref(false)
|
||||
|
||||
const roleOptions = [
|
||||
@@ -893,12 +901,8 @@ function saveRoleEdit() {
|
||||
|
||||
isSavingRole.value = true
|
||||
|
||||
useBaseFetch(`user/${user.value.id}`, {
|
||||
method: 'PATCH',
|
||||
body: {
|
||||
role: selectedRole.value,
|
||||
},
|
||||
})
|
||||
client.labrinth.users_v2
|
||||
.patch(user.value.id, { role: selectedRole.value })
|
||||
.then(() => {
|
||||
user.value.role = selectedRole.value
|
||||
|
||||
|
||||
Reference in New Issue
Block a user