@vendure/dashboard 3.3.6-master-202507010922 → 3.3.6-master-202507011151

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,134 +1,134 @@
1
1
  {
2
- "name": "@vendure/dashboard",
3
- "private": false,
4
- "version": "3.3.6-master-202507010922",
5
- "type": "module",
6
- "repository": {
7
- "type": "git",
8
- "url": "https://github.com/vendure-ecommerce/vendure"
2
+ "name": "@vendure/dashboard",
3
+ "private": false,
4
+ "version": "3.3.6-master-202507011151",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/vendure-ecommerce/vendure"
9
+ },
10
+ "homepage": "https://www.vendure.io",
11
+ "funding": "https://github.com/sponsors/michaelbromley",
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "scripts": {
16
+ "dev": "vite",
17
+ "build:standalone": "vite build",
18
+ "build": "tsc --project tsconfig.plugin.json",
19
+ "watch": "tsc --project tsconfig.plugin.json --watch",
20
+ "test": "vitest run",
21
+ "lint": "eslint .",
22
+ "preview": "vite preview",
23
+ "generate-index": "node scripts/generate-index.js"
24
+ },
25
+ "module": "./src/lib/index.ts",
26
+ "main": "./src/lib/index.ts",
27
+ "types": "./src/lib/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./src/lib/index.d.ts",
31
+ "import": "./src/lib/index.ts",
32
+ "require": "./src/lib/index.ts"
9
33
  },
10
- "homepage": "https://www.vendure.io",
11
- "funding": "https://github.com/sponsors/michaelbromley",
12
- "publishConfig": {
13
- "access": "public"
14
- },
15
- "scripts": {
16
- "dev": "vite",
17
- "build:standalone": "vite build",
18
- "build": "tsc --project tsconfig.plugin.json",
19
- "watch": "tsc --project tsconfig.plugin.json --watch",
20
- "test": "vitest run",
21
- "lint": "eslint .",
22
- "preview": "vite preview",
23
- "generate-index": "node ./generate-index.js"
24
- },
25
- "module": "./src/lib/index.ts",
26
- "main": "./src/lib/index.ts",
27
- "types": "./src/lib/index.d.ts",
28
- "exports": {
29
- ".": {
30
- "types": "./src/lib/index.d.ts",
31
- "import": "./src/lib/index.ts",
32
- "require": "./src/lib/index.ts"
33
- },
34
- "./plugin": {
35
- "types": "./dist/plugin/index.d.ts",
36
- "import": "./dist/plugin/index.js",
37
- "require": "./dist/plugin/index.js"
38
- }
39
- },
40
- "files": [
41
- "dist",
42
- "src",
43
- "vite",
44
- "lingui.config.js",
45
- "index.html"
46
- ],
47
- "dependencies": {
48
- "@dnd-kit/core": "^6.3.1",
49
- "@dnd-kit/modifiers": "^9.0.0",
50
- "@dnd-kit/sortable": "^10.0.0",
51
- "@hookform/resolvers": "^4.1.3",
52
- "@lingui/babel-plugin-lingui-macro": "^5.2.0",
53
- "@lingui/cli": "^5.2.0",
54
- "@lingui/core": "^5.2.0",
55
- "@lingui/react": "^5.2.0",
56
- "@lingui/vite-plugin": "^5.2.0",
57
- "@radix-ui/react-accordion": "^1.2.3",
58
- "@radix-ui/react-alert-dialog": "^1.1.6",
59
- "@radix-ui/react-avatar": "^1.1.3",
60
- "@radix-ui/react-checkbox": "^1.1.4",
61
- "@radix-ui/react-collapsible": "^1.1.3",
62
- "@radix-ui/react-dialog": "^1.1.6",
63
- "@radix-ui/react-dropdown-menu": "^2.1.6",
64
- "@radix-ui/react-hover-card": "^1.1.6",
65
- "@radix-ui/react-label": "^2.1.2",
66
- "@radix-ui/react-popover": "^1.1.6",
67
- "@radix-ui/react-scroll-area": "^1.2.3",
68
- "@radix-ui/react-select": "^2.1.6",
69
- "@radix-ui/react-separator": "^1.1.2",
70
- "@radix-ui/react-slot": "^1.1.2",
71
- "@radix-ui/react-switch": "^1.1.3",
72
- "@radix-ui/react-tabs": "^1.1.3",
73
- "@radix-ui/react-tooltip": "^1.1.8",
74
- "@tailwindcss/vite": "^4.1.5",
75
- "@tanstack/eslint-plugin-query": "^5.66.1",
76
- "@tanstack/react-query": "^5.66.7",
77
- "@tanstack/react-query-devtools": "^5.68.0",
78
- "@tanstack/react-router": "^1.105.0",
79
- "@tanstack/react-table": "^8.21.2",
80
- "@tanstack/router-devtools": "^1.105.0",
81
- "@tanstack/router-plugin": "^1.105.0",
82
- "@tiptap/pm": "^2.11.5",
83
- "@tiptap/react": "^2.11.5",
84
- "@tiptap/starter-kit": "^2.11.5",
85
- "@types/react": "^19.0.10",
86
- "@types/react-dom": "^19.0.4",
87
- "@types/react-grid-layout": "^1.3.5",
88
- "@uidotdev/usehooks": "^2.4.1",
89
- "@vendure/common": "^3.3.6-master-202507010922",
90
- "@vendure/core": "^3.3.6-master-202507010922",
91
- "@vitejs/plugin-react": "^4.3.4",
92
- "awesome-graphql-client": "^2.1.0",
93
- "class-variance-authority": "^0.7.1",
94
- "clsx": "^2.1.1",
95
- "cmdk": "^1.0.0",
96
- "date-fns": "^3.6.0",
97
- "gql.tada": "^1.8.10",
98
- "graphql": "^16.10.0",
99
- "json-edit-react": "^1.23.1",
100
- "lucide-react": "^0.475.0",
101
- "motion": "^12.6.2",
102
- "next-themes": "^0.4.6",
103
- "react": "^19.0.0",
104
- "react-day-picker": "^9.6.7",
105
- "react-dom": "^19.0.0",
106
- "react-dropzone": "^14.3.8",
107
- "react-grid-layout": "^1.5.1",
108
- "react-hook-form": "^7.54.2",
109
- "recharts": "^2.15.1",
110
- "sonner": "^2.0.1",
111
- "tailwind-merge": "^3.2.0",
112
- "tailwindcss": "^4.1.5",
113
- "tailwindcss-animate": "^1.0.7",
114
- "tsconfig-paths": "^4.2.0",
115
- "tw-animate-css": "^1.2.9",
116
- "vite": "^6.3.5",
117
- "zod": "^3.24.2"
118
- },
119
- "devDependencies": {
120
- "@eslint/js": "^9.19.0",
121
- "@types/node": "^22.13.4",
122
- "eslint": "^9.19.0",
123
- "eslint-plugin-react": "^7.37.4",
124
- "eslint-plugin-react-hooks": "^5.0.0",
125
- "eslint-plugin-react-refresh": "^0.4.18",
126
- "globals": "^15.14.0",
127
- "vite-plugin-dts": "^4.5.3"
128
- },
129
- "optionalDependencies": {
130
- "lightningcss-linux-arm64-musl": "^1.29.3",
131
- "lightningcss-linux-x64-musl": "^1.29.1"
132
- },
133
- "gitHead": "ea754102804748c447cf9c1d28d9bbc5cc0a333b"
34
+ "./plugin": {
35
+ "types": "./dist/plugin/index.d.ts",
36
+ "import": "./dist/plugin/index.js",
37
+ "require": "./dist/plugin/index.js"
38
+ }
39
+ },
40
+ "files": [
41
+ "dist",
42
+ "src",
43
+ "vite",
44
+ "lingui.config.js",
45
+ "index.html"
46
+ ],
47
+ "dependencies": {
48
+ "@dnd-kit/core": "^6.3.1",
49
+ "@dnd-kit/modifiers": "^9.0.0",
50
+ "@dnd-kit/sortable": "^10.0.0",
51
+ "@hookform/resolvers": "^4.1.3",
52
+ "@lingui/babel-plugin-lingui-macro": "^5.2.0",
53
+ "@lingui/cli": "^5.2.0",
54
+ "@lingui/core": "^5.2.0",
55
+ "@lingui/react": "^5.2.0",
56
+ "@lingui/vite-plugin": "^5.2.0",
57
+ "@radix-ui/react-accordion": "^1.2.3",
58
+ "@radix-ui/react-alert-dialog": "^1.1.6",
59
+ "@radix-ui/react-avatar": "^1.1.3",
60
+ "@radix-ui/react-checkbox": "^1.1.4",
61
+ "@radix-ui/react-collapsible": "^1.1.3",
62
+ "@radix-ui/react-dialog": "^1.1.6",
63
+ "@radix-ui/react-dropdown-menu": "^2.1.6",
64
+ "@radix-ui/react-hover-card": "^1.1.6",
65
+ "@radix-ui/react-label": "^2.1.2",
66
+ "@radix-ui/react-popover": "^1.1.6",
67
+ "@radix-ui/react-scroll-area": "^1.2.3",
68
+ "@radix-ui/react-select": "^2.1.6",
69
+ "@radix-ui/react-separator": "^1.1.2",
70
+ "@radix-ui/react-slot": "^1.1.2",
71
+ "@radix-ui/react-switch": "^1.1.3",
72
+ "@radix-ui/react-tabs": "^1.1.3",
73
+ "@radix-ui/react-tooltip": "^1.1.8",
74
+ "@tailwindcss/vite": "^4.1.5",
75
+ "@tanstack/eslint-plugin-query": "^5.66.1",
76
+ "@tanstack/react-query": "^5.66.7",
77
+ "@tanstack/react-query-devtools": "^5.68.0",
78
+ "@tanstack/react-router": "^1.105.0",
79
+ "@tanstack/react-table": "^8.21.2",
80
+ "@tanstack/router-devtools": "^1.105.0",
81
+ "@tanstack/router-plugin": "^1.105.0",
82
+ "@tiptap/pm": "^2.11.5",
83
+ "@tiptap/react": "^2.11.5",
84
+ "@tiptap/starter-kit": "^2.11.5",
85
+ "@types/react": "^19.0.10",
86
+ "@types/react-dom": "^19.0.4",
87
+ "@types/react-grid-layout": "^1.3.5",
88
+ "@uidotdev/usehooks": "^2.4.1",
89
+ "@vendure/common": "^3.3.6-master-202507011151",
90
+ "@vendure/core": "^3.3.6-master-202507011151",
91
+ "@vitejs/plugin-react": "^4.3.4",
92
+ "awesome-graphql-client": "^2.1.0",
93
+ "class-variance-authority": "^0.7.1",
94
+ "clsx": "^2.1.1",
95
+ "cmdk": "^1.0.0",
96
+ "date-fns": "^3.6.0",
97
+ "gql.tada": "^1.8.10",
98
+ "graphql": "^16.10.0",
99
+ "json-edit-react": "^1.23.1",
100
+ "lucide-react": "^0.475.0",
101
+ "motion": "^12.6.2",
102
+ "next-themes": "^0.4.6",
103
+ "react": "^19.0.0",
104
+ "react-day-picker": "^9.6.7",
105
+ "react-dom": "^19.0.0",
106
+ "react-dropzone": "^14.3.8",
107
+ "react-grid-layout": "^1.5.1",
108
+ "react-hook-form": "^7.54.2",
109
+ "recharts": "^2.15.1",
110
+ "sonner": "^2.0.1",
111
+ "tailwind-merge": "^3.2.0",
112
+ "tailwindcss": "^4.1.5",
113
+ "tailwindcss-animate": "^1.0.7",
114
+ "tsconfig-paths": "^4.2.0",
115
+ "tw-animate-css": "^1.2.9",
116
+ "vite": "^6.3.5",
117
+ "zod": "^3.24.2"
118
+ },
119
+ "devDependencies": {
120
+ "@eslint/js": "^9.19.0",
121
+ "@types/node": "^22.13.4",
122
+ "eslint": "^9.19.0",
123
+ "eslint-plugin-react": "^7.37.4",
124
+ "eslint-plugin-react-hooks": "^5.0.0",
125
+ "eslint-plugin-react-refresh": "^0.4.18",
126
+ "globals": "^15.14.0",
127
+ "vite-plugin-dts": "^4.5.3"
128
+ },
129
+ "optionalDependencies": {
130
+ "lightningcss-linux-arm64-musl": "^1.29.3",
131
+ "lightningcss-linux-x64-musl": "^1.29.1"
132
+ },
133
+ "gitHead": "a707c76b649dd13d245fec107e4c4c7ccc23866b"
134
134
  }
@@ -20,7 +20,7 @@ export function DetailPageButton({
20
20
  }
21
21
  return (
22
22
  <Button asChild variant="ghost" disabled={disabled}>
23
- <Link to={href ?? `./${id}`} search={search ?? {}}>
23
+ <Link to={href ?? `./${id}`} search={search ?? {}} preload={false}>
24
24
  {label}
25
25
  {!disabled && <ChevronRight className="h-3 w-3 text-muted-foreground" />}
26
26
  </Link>
@@ -1,7 +1,8 @@
1
- import { onExtensionSourceChange } from '@/framework/extension-api/define-dashboard-extension.js';
2
1
  import { useEffect, useState } from 'react';
3
2
  import { runDashboardExtensions } from 'virtual:dashboard-extensions';
4
3
 
4
+ import { onExtensionSourceChange } from './define-dashboard-extension.js';
5
+
5
6
  /**
6
7
  * @description
7
8
  * This hook is used to load dashboard extensions via the `virtual:dashboard-extensions` module,
@@ -1,16 +1,13 @@
1
- import { getOperationVariablesFields } from '@/framework/document-introspection/get-document-structure.js';
2
- import {
3
- createFormSchemaFromFields,
4
- getDefaultValuesFromFields,
5
- } from '@/framework/form-engine/form-schema-tools.js';
6
- import { transformRelationFields } from '@/framework/form-engine/utils.js';
7
- import { useChannel } from '@/hooks/use-channel.js';
8
- import { useServerConfig } from '@/hooks/use-server-config.js';
9
1
  import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
10
2
  import { zodResolver } from '@hookform/resolvers/zod';
11
3
  import { VariablesOf } from 'gql.tada';
12
4
  import { FormEvent } from 'react';
13
5
  import { useForm } from 'react-hook-form';
6
+ import { useChannel } from '../../hooks/use-channel.js';
7
+ import { useServerConfig } from '../../hooks/use-server-config.js';
8
+ import { getOperationVariablesFields } from '../document-introspection/get-document-structure.js';
9
+ import { createFormSchemaFromFields, getDefaultValuesFromFields } from './form-schema-tools.js';
10
+ import { transformRelationFields } from './utils.js';
14
11
 
15
12
  export interface GeneratedFormOptions<
16
13
  T extends TypedDocumentNode<any, any>,
@@ -1,7 +1,3 @@
1
- import { NEW_ENTITY_PATH } from '@/constants.js';
2
- import { api, Variables } from '@/graphql/api.js';
3
- import { useCustomFieldConfig } from '@/hooks/use-custom-field-config.js';
4
- import { useExtendedDetailQuery } from '@/hooks/use-extended-detail-query.js';
5
1
  import { removeReadonlyCustomFields } from '@/lib/utils.js';
6
2
  import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
7
3
  import {
@@ -16,6 +12,10 @@ import { DocumentNode } from 'graphql';
16
12
  import { FormEvent } from 'react';
17
13
  import { UseFormReturn } from 'react-hook-form';
18
14
 
15
+ import { NEW_ENTITY_PATH } from '../../constants.js';
16
+ import { api, Variables } from '../../graphql/api.js';
17
+ import { useCustomFieldConfig } from '../../hooks/use-custom-field-config.js';
18
+ import { useExtendedDetailQuery } from '../../hooks/use-extended-detail-query.js';
19
19
  import { addCustomFields } from '../document-introspection/add-custom-fields.js';
20
20
  import {
21
21
  getEntityName,
@@ -1,10 +1,9 @@
1
- import { ErrorPage } from '@/components/shared/error-page.js';
2
- import { useDashboardExtensions } from '@/framework/extension-api/use-dashboard-extensions.js';
3
- import { ListPage } from '@/framework/page/list-page.js';
4
- import { extensionRoutes } from '@/framework/page/page-api.js';
5
- import { AUTHENTICATED_ROUTE_PREFIX } from '@/constants.js';
6
1
  import { AnyRoute, createRoute, Router } from '@tanstack/react-router';
7
2
  import { useMemo } from 'react';
3
+ import { ErrorPage } from '../../components/shared/error-page.js';
4
+ import { AUTHENTICATED_ROUTE_PREFIX } from '../../constants.js';
5
+ import { useDashboardExtensions } from '../extension-api/use-dashboard-extensions.js';
6
+ import { extensionRoutes } from './page-api.js';
8
7
 
9
8
  /**
10
9
  * Extends the TanStack Router with additional routes for each dashboard
@@ -1,6 +1,7 @@
1
- import { ChannelContext } from '@/providers/channel-provider.js';
2
1
  import * as React from 'react';
3
2
 
3
+ import { ChannelContext } from '../providers/channel-provider.js';
4
+
4
5
  // Hook to use the channel context
5
6
 
6
7
  /**
@@ -1,9 +1,10 @@
1
- import { extendDetailFormQuery } from '@/framework/document-extension/extend-detail-form-query.js';
2
1
  import { useLingui } from '@/lib/trans.js';
3
2
  import { DocumentNode } from 'graphql';
4
3
  import { useEffect, useMemo, useRef } from 'react';
5
4
  import { toast } from 'sonner';
6
5
 
6
+ import { extendDetailFormQuery } from '../framework/document-extension/extend-detail-form-query.js';
7
+
7
8
  /**
8
9
  * @description
9
10
  * Extends a detail page query document with any registered extensions provided by
@@ -1,10 +1,11 @@
1
- import { getListQueryDocuments } from '@/framework/data-table/data-table-extensions.js';
2
- import { extendDocument } from '@/framework/document-extension/extend-document.js';
3
1
  import { useLingui } from '@/lib/trans.js';
4
2
  import { DocumentNode } from 'graphql';
5
3
  import { useEffect, useMemo, useRef } from 'react';
6
4
  import { toast } from 'sonner';
7
5
 
6
+ import { getListQueryDocuments } from '../framework/data-table/data-table-extensions.js';
7
+ import { extendDocument } from '../framework/document-extension/extend-document.js';
8
+
8
9
  import { usePageBlock } from './use-page-block.js';
9
10
  import { usePage } from './use-page.js';
10
11
 
@@ -1,7 +1,9 @@
1
- import { useServerConfig } from '@/hooks/use-server-config.js';
2
- import { ServerConfig } from '@/providers/server-config.js';
3
1
  import { useMemo } from 'react';
4
2
 
3
+ import { ServerConfig } from '../providers/server-config.js';
4
+
5
+ import { useServerConfig } from './use-server-config.js';
6
+
5
7
  export function useGroupedPermissions() {
6
8
  const serverConfig = useServerConfig();
7
9
  const permissionDefinitions = serverConfig?.permissions ?? [];
@@ -1,5 +1,5 @@
1
- import { PageBlockContext } from '@/framework/layout-engine/page-block-provider.js';
2
1
  import { useContext } from 'react';
2
+ import { PageBlockContext } from '../framework/layout-engine/page-block-provider.js';
3
3
 
4
4
  export function usePageBlock() {
5
5
  const pageBlock = useContext(PageBlockContext);
@@ -1,5 +1,5 @@
1
- import { useContext } from "react";
2
- import { PageContext } from '@/framework/layout-engine/page-provider.js';
1
+ import { useContext } from 'react';
2
+ import { PageContext } from '../framework/layout-engine/page-provider.js';
3
3
 
4
4
  export function usePage() {
5
5
  const page = useContext(PageContext);
@@ -1,7 +1,8 @@
1
- import { useAuth } from '@/hooks/use-auth.js';
2
- import { useChannel } from '@/hooks/use-channel.js';
3
1
  import { Permission } from '@vendure/common/lib/generated-types';
4
2
 
3
+ import { useAuth } from './use-auth.js';
4
+ import { useChannel } from './use-channel.js';
5
+
5
6
  /**
6
7
  * @description
7
8
  * **Status: Developer Preview**
@@ -1,4 +1,5 @@
1
- import { ServerConfigContext } from '@/providers/server-config.js';
2
1
  import React from 'react';
3
2
 
3
+ import { ServerConfigContext } from '../providers/server-config.js';
4
+
4
5
  export const useServerConfig = () => React.useContext(ServerConfigContext);
@@ -1,6 +1,7 @@
1
- import { ThemeProviderContext } from '@/providers/theme-provider.js';
2
1
  import { useContext } from 'react';
3
2
 
3
+ import { ThemeProviderContext } from '../providers/theme-provider.js';
4
+
4
5
  export const useTheme = () => {
5
6
  const context = useContext(ThemeProviderContext);
6
7
 
@@ -1,5 +1,5 @@
1
1
  import { api } from '@/graphql/api.js';
2
- import { ResultOf, graphql } from '@/graphql/graphql.js';
2
+ import { graphql, ResultOf } from '@/graphql/graphql.js';
3
3
  import { useUserSettings } from '@/hooks/use-user-settings.js';
4
4
  import { useQuery, useQueryClient } from '@tanstack/react-query';
5
5
  import * as React from 'react';
@@ -14,7 +14,7 @@ import * as React from 'react';
14
14
  * @since 3.3.0
15
15
  */
16
16
  export interface AuthContext {
17
- status: 'authenticated' | 'verifying' | 'unauthenticated';
17
+ status: 'initial' | 'authenticated' | 'verifying' | 'unauthenticated';
18
18
  authenticationError?: string;
19
19
  isAuthenticated: boolean;
20
20
  login: (username: string, password: string, onSuccess?: () => void) => void;
@@ -71,8 +71,9 @@ const CurrentUserQuery = graphql(`
71
71
  export const AuthContext = React.createContext<AuthContext | null>(null);
72
72
 
73
73
  export function AuthProvider({ children }: { children: React.ReactNode }) {
74
- const [status, setStatus] = React.useState<AuthContext['status']>('unauthenticated');
74
+ const [status, setStatus] = React.useState<AuthContext['status']>('initial');
75
75
  const [authenticationError, setAuthenticationError] = React.useState<string | undefined>();
76
+ const [isLoginLogoutInProgress, setIsLoginLogoutInProgress] = React.useState(false);
76
77
  const { settings, setActiveChannelId } = useUserSettings();
77
78
  const queryClient = useQueryClient();
78
79
 
@@ -84,7 +85,10 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
84
85
  refetch: refetchCurrentUser,
85
86
  } = useQuery({
86
87
  queryKey: ['currentUser'],
87
- queryFn: () => api.query(CurrentUserQuery),
88
+ queryFn: () => {
89
+ return api.query(CurrentUserQuery);
90
+ },
91
+ retry: false, // Disable retries to avoid waiting for multiple attempts
88
92
  });
89
93
 
90
94
  // Set active channel if needed
@@ -97,6 +101,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
97
101
  // Auth actions
98
102
  const login = React.useCallback(
99
103
  (username: string, password: string, onLoginSuccess?: () => void) => {
104
+ setIsLoginLogoutInProgress(true);
100
105
  setStatus('verifying');
101
106
  api.mutate(LoginMutation)({ username, password })
102
107
  .then(async data => {
@@ -106,15 +111,18 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
106
111
  // Invalidate all queries to ensure fresh data after login
107
112
  await queryClient.invalidateQueries();
108
113
  setStatus('authenticated');
114
+ setIsLoginLogoutInProgress(false);
109
115
  onLoginSuccess?.();
110
116
  } else {
111
117
  setAuthenticationError(data?.login.message);
112
118
  setStatus('unauthenticated');
119
+ setIsLoginLogoutInProgress(false);
113
120
  }
114
121
  })
115
122
  .catch(error => {
116
123
  setAuthenticationError(error.message);
117
124
  setStatus('unauthenticated');
125
+ setIsLoginLogoutInProgress(false);
118
126
  });
119
127
  },
120
128
  [refetchCurrentUser, queryClient],
@@ -122,6 +130,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
122
130
 
123
131
  const logout = React.useCallback(
124
132
  async (onLogoutSuccess?: () => void) => {
133
+ setIsLoginLogoutInProgress(true);
125
134
  setStatus('verifying');
126
135
  api.mutate(LogOutMutation)({}).then(async data => {
127
136
  if (data?.logout.success) {
@@ -131,6 +140,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
131
140
  localStorage.removeItem('vendure-selected-channel');
132
141
  localStorage.removeItem('vendure-selected-channel-token');
133
142
  setStatus('unauthenticated');
143
+ setIsLoginLogoutInProgress(false);
134
144
  onLogoutSuccess?.();
135
145
  }
136
146
  });
@@ -141,15 +151,28 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
141
151
  // Determine isAuthenticated from currentUserData
142
152
  const isAuthenticated = !!currentUserData?.me?.id;
143
153
 
144
- // Set status based on query result (only if not in the middle of login/logout)
154
+ // Handle status transitions based on query state
145
155
  React.useEffect(() => {
146
- if (status === 'verifying') return;
147
- if (currentUserError || !currentUserData?.me?.id) {
148
- setStatus('unauthenticated');
149
- } else {
150
- setStatus('authenticated');
156
+ // Don't change status if we're in the middle of login/logout
157
+ if (isLoginLogoutInProgress) {
158
+ return;
159
+ }
160
+
161
+ // If query is loading and we haven't started verifying yet, set to verifying
162
+ if (isLoading && status === 'initial') {
163
+ setStatus('verifying');
164
+ return;
165
+ }
166
+
167
+ // If query has completed (not loading) and we're in verifying state, determine final status
168
+ if (!isLoading && status === 'verifying') {
169
+ if (currentUserError || !currentUserData?.me?.id) {
170
+ setStatus('unauthenticated');
171
+ } else {
172
+ setStatus('authenticated');
173
+ }
151
174
  }
152
- }, [currentUserData, currentUserError]);
175
+ }, [isLoading, currentUserData, currentUserError, status, isLoginLogoutInProgress]);
153
176
 
154
177
  return (
155
178
  <AuthContext.Provider