@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 +131 -131
- package/src/lib/components/shared/detail-page-button.tsx +1 -1
- package/src/lib/framework/extension-api/use-dashboard-extensions.ts +2 -1
- package/src/lib/framework/form-engine/use-generated-form.tsx +5 -8
- package/src/lib/framework/page/use-detail-page.ts +4 -4
- package/src/lib/framework/page/use-extended-router.tsx +4 -5
- package/src/lib/hooks/use-channel.ts +2 -1
- package/src/lib/hooks/use-extended-detail-query.ts +2 -1
- package/src/lib/hooks/use-extended-list-query.ts +3 -2
- package/src/lib/hooks/use-grouped-permissions.ts +4 -2
- package/src/lib/hooks/use-page-block.tsx +1 -1
- package/src/lib/hooks/use-page.tsx +2 -2
- package/src/lib/hooks/use-permissions.ts +3 -2
- package/src/lib/hooks/use-server-config.ts +2 -1
- package/src/lib/hooks/use-theme.ts +2 -1
- package/src/lib/providers/auth.tsx +34 -11
package/package.json
CHANGED
|
@@ -1,134 +1,134 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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,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
|
|
2
|
-
import { PageContext } from '
|
|
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,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 {
|
|
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']>('
|
|
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: () =>
|
|
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
|
-
//
|
|
154
|
+
// Handle status transitions based on query state
|
|
145
155
|
React.useEffect(() => {
|
|
146
|
-
|
|
147
|
-
if (
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
|
|
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
|