From 7d6ad935282a307ec03a728bb5ab1c021a8841f7 Mon Sep 17 00:00:00 2001 From: Truman Gao <106889354+tdgao@users.noreply.github.com> Date: Tue, 31 Mar 2026 11:08:33 -0700 Subject: [PATCH] feat: update purchase server flow (#5714) * implement server list empty state component * fix stories and adjust spacing * implement select plan design refresh * implement auth for empty server list * use refs instead of reactive * pnpm prepr * fix auth usage for empty servers list * move app auth provider setup to src/providers/setup * pnpm prepr --- apps/app-frontend/src/App.vue | 19 +- apps/app-frontend/src/providers/setup/auth.ts | 29 ++ apps/frontend/src/providers/setup/auth.ts | 17 +- .../billing/ModalBasedServerPlan.vue | 149 -------- .../billing/ModrinthServersPurchaseModal.vue | 9 +- .../billing/ServersPurchase0Plan.vue | 327 +++++++++++++----- packages/ui/src/components/servers/index.ts | 3 +- .../server-list-empty/ServerListEmpty.vue | 251 ++++++++++++++ .../grid-images/aircraft.png | Bin 0 -> 21840 bytes .../server-list-empty/grid-images/alex's.png | Bin 0 -> 19570 bytes .../grid-images/artifacts.png | Bin 0 -> 704 bytes .../server-list-empty/grid-images/biomes.png | Bin 0 -> 1167 bytes .../server-list-empty/grid-images/catac.png | Bin 0 -> 12710 bytes .../server-list-empty/grid-images/cobble.png | Bin 0 -> 17701 bytes .../grid-images/comforts.png | Bin 0 -> 990 bytes .../server-list-empty/grid-images/create.png | Bin 0 -> 22270 bytes .../server-list-empty/grid-images/create1.png | Bin 0 -> 20019 bytes .../server-list-empty/grid-images/create2.png | Bin 0 -> 20355 bytes .../server-list-empty/grid-images/create3.png | Bin 0 -> 21715 bytes .../server-list-empty/grid-images/creeper.png | Bin 0 -> 36105 bytes .../server-list-empty/grid-images/friends.png | Bin 0 -> 18513 bytes .../server-list-empty/grid-images/geo.png | Bin 0 -> 18242 bytes .../grid-images/naturalist.png | Bin 0 -> 22716 bytes .../server-list-empty/grid-images/seasons.png | Bin 0 -> 16140 bytes .../grid-images/travellers.png | Bin 0 -> 20052 bytes .../server-list-empty/grid-images/tree.png | Bin 0 -> 23739 bytes .../server-list-empty/grid-images/yum1.png | Bin 0 -> 14167 bytes .../server-list-empty/grid-images/yum2.png | Bin 0 -> 15751 bytes .../server-list-empty/grid-images/yum3.png | Bin 0 -> 13945 bytes .../server-list-empty/grid-images/yung.png | Bin 0 -> 15455 bytes .../layouts/wrapped/hosting/manage/index.vue | 46 +-- packages/ui/src/locales/en-US/index.json | 25 +- packages/ui/src/providers/auth.ts | 5 +- packages/ui/src/providers/index.ts | 2 +- .../servers/ServerListEmpty.stories.ts | 16 + 35 files changed, 596 insertions(+), 302 deletions(-) create mode 100644 apps/app-frontend/src/providers/setup/auth.ts delete mode 100644 packages/ui/src/components/billing/ModalBasedServerPlan.vue create mode 100644 packages/ui/src/components/servers/server-list-empty/ServerListEmpty.vue create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/aircraft.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/alex's.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/artifacts.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/biomes.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/catac.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/cobble.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/comforts.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/create.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/create1.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/create2.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/create3.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/creeper.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/friends.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/geo.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/naturalist.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/seasons.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/travellers.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/tree.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/yum1.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/yum2.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/yum3.png create mode 100644 packages/ui/src/components/servers/server-list-empty/grid-images/yung.png create mode 100644 packages/ui/src/stories/servers/ServerListEmpty.stories.ts diff --git a/apps/app-frontend/src/App.vue b/apps/app-frontend/src/App.vue index de2038604a..9efe0f30c9 100644 --- a/apps/app-frontend/src/App.vue +++ b/apps/app-frontend/src/App.vue @@ -40,7 +40,6 @@ import { OverflowMenu, PopupNotificationPanel, ProgressSpinner, - provideAuth, provideModalBehavior, provideModrinthClient, provideNotificationManager, @@ -58,7 +57,7 @@ import { openUrl } from '@tauri-apps/plugin-opener' import { type } from '@tauri-apps/plugin-os' import { saveWindowState, StateFlags } from '@tauri-apps/plugin-window-state' import { $fetch } from 'ofetch' -import { computed, onMounted, onUnmounted, provide, reactive, ref, watch, watchEffect } from 'vue' +import { computed, onMounted, onUnmounted, provide, ref, watch } from 'vue' import { RouterView, useRoute, useRouter } from 'vue-router' import ModrinthAppLogo from '@/assets/modrinth_app.svg?component' @@ -107,6 +106,7 @@ import { } from '@/providers/download-progress.ts' import { createServerInstall, provideServerInstall } from '@/providers/server-install' import { setupProviders } from '@/providers/setup' +import { setupAuthProvider } from '@/providers/setup/auth' import { useError } from '@/store/error.js' import { useLoading, useTheming } from '@/store/state' @@ -455,21 +455,10 @@ const credentials = ref() const modrinthLoginFlowWaitModal = ref() -const authProvider = reactive({ - session_token: null, - user: null, - requestSignIn: async (_redirectPath) => { - await signIn() - }, +setupAuthProvider(credentials, async (_redirectPath) => { + await signIn() }) -watchEffect(() => { - authProvider.session_token = credentials.value?.session ?? null - authProvider.user = credentials.value?.user ?? null -}) - -provideAuth(authProvider) - async function fetchCredentials() { const creds = await getCreds().catch(handleError) if (creds && creds.user_id) { diff --git a/apps/app-frontend/src/providers/setup/auth.ts b/apps/app-frontend/src/providers/setup/auth.ts new file mode 100644 index 0000000000..bf522c59a3 --- /dev/null +++ b/apps/app-frontend/src/providers/setup/auth.ts @@ -0,0 +1,29 @@ +import type { Labrinth } from '@modrinth/api-client' +import { type AuthProvider, provideAuth } from '@modrinth/ui' +import { type Ref, ref, watchEffect } from 'vue' + +type AppCredentials = { + session?: string | null + user?: Labrinth.Users.v2.User | null +} + +export function setupAuthProvider( + credentials: Ref, + requestSignIn: (redirectPath: string) => void | Promise, +) { + const sessionToken = ref(null) + const user = ref(null) + + const authProvider: AuthProvider = { + session_token: sessionToken, + user, + requestSignIn, + } + + watchEffect(() => { + sessionToken.value = credentials.value?.session ?? null + user.value = credentials.value?.user ?? null + }) + + provideAuth(authProvider) +} diff --git a/apps/frontend/src/providers/setup/auth.ts b/apps/frontend/src/providers/setup/auth.ts index 3681f6e4f1..ae717324b0 100644 --- a/apps/frontend/src/providers/setup/auth.ts +++ b/apps/frontend/src/providers/setup/auth.ts @@ -1,12 +1,15 @@ import type { Labrinth } from '@modrinth/api-client' import { type AuthProvider, provideAuth } from '@modrinth/ui' -import { reactive, watchEffect } from 'vue' +import { ref, watchEffect } from 'vue' export function setupAuthProvider(auth: Awaited>) { const router = useRouter() - const authProvider = reactive({ - session_token: null, - user: null, + const sessionToken = ref(null) + const user = ref(null) + + const authProvider: AuthProvider = { + session_token: sessionToken, + user, requestSignIn: async (redirectPath: string) => { await router.push({ path: '/auth/sign-in', @@ -15,11 +18,11 @@ export function setupAuthProvider(auth: Awaited>) { }, }) }, - }) + } watchEffect(() => { - authProvider.session_token = auth.value.token || null - authProvider.user = (auth.value.user as Labrinth.Users.v2.User | null) ?? null + sessionToken.value = auth.value.token || null + user.value = (auth.value.user as Labrinth.Users.v2.User | null) ?? null }) provideAuth(authProvider) diff --git a/packages/ui/src/components/billing/ModalBasedServerPlan.vue b/packages/ui/src/components/billing/ModalBasedServerPlan.vue deleted file mode 100644 index ce363cccca..0000000000 --- a/packages/ui/src/components/billing/ModalBasedServerPlan.vue +++ /dev/null @@ -1,149 +0,0 @@ - - - diff --git a/packages/ui/src/components/billing/ModrinthServersPurchaseModal.vue b/packages/ui/src/components/billing/ModrinthServersPurchaseModal.vue index 323d9f3df4..487f3e4f9d 100644 --- a/packages/ui/src/components/billing/ModrinthServersPurchaseModal.vue +++ b/packages/ui/src/components/billing/ModrinthServersPurchaseModal.vue @@ -283,6 +283,10 @@ function handleChooseCustom() { selectedPlan.value = undefined } +function handleProceed() { + setStep(nextStep.value) +} + // When the user explicitly wants to change or add a payment method from Review // we must disable the auto-skip behavior, clear any selected method, and // navigate to the Payment step so Stripe Elements can mount. @@ -328,7 +332,7 @@ function goToBreadcrumbStep(id: string) { -
+
- +