@adlas/create-app 1.0.0
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/README.md +476 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +39 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/figma.d.ts +16 -0
- package/dist/commands/figma.d.ts.map +1 -0
- package/dist/commands/figma.js +172 -0
- package/dist/commands/figma.js.map +1 -0
- package/dist/commands/index.d.ts +5 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +5 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +1471 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/swagger.d.ts +16 -0
- package/dist/commands/swagger.d.ts.map +1 -0
- package/dist/commands/swagger.js +404 -0
- package/dist/commands/swagger.js.map +1 -0
- package/dist/commands/update.d.ts +15 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +93 -0
- package/dist/commands/update.js.map +1 -0
- package/package.json +63 -0
- package/templates/.vscode/extensions.json +9 -0
- package/templates/.vscode/launch.json +26 -0
- package/templates/.vscode/settings.json +67 -0
- package/templates/.vscode/tasks.json +21 -0
- package/templates/boilerplate/config/fonts.ts +10 -0
- package/templates/boilerplate/config/navigationUrls.ts +47 -0
- package/templates/boilerplate/config/site.ts +96 -0
- package/templates/boilerplate/libs/I18n.ts +15 -0
- package/templates/boilerplate/libs/I18nNavigation.ts +5 -0
- package/templates/boilerplate/libs/I18nRouting.ts +9 -0
- package/templates/boilerplate/libs/env.ts +21 -0
- package/templates/boilerplate/libs/react-query/ReactQueryProvider.tsx +21 -0
- package/templates/boilerplate/libs/react-query/index.ts +2 -0
- package/templates/boilerplate/libs/react-query/queryClient.ts +62 -0
- package/templates/boilerplate/libs/react-query/queryKeys.ts +5 -0
- package/templates/boilerplate/public/images/index.ts +1 -0
- package/templates/boilerplate/reset.d.ts +2 -0
- package/templates/boilerplate/styles/globals.css +308 -0
- package/templates/boilerplate/types/i18n.ts +10 -0
- package/templates/boilerplate/types/locale.ts +8 -0
- package/templates/boilerplate/utils/file/fileConfig.ts +123 -0
- package/templates/boilerplate/utils/file/fileValidation.ts +78 -0
- package/templates/boilerplate/utils/file/imageCompression.ts +182 -0
- package/templates/boilerplate/utils/file/index.ts +3 -0
- package/templates/boilerplate/utils/helpers.ts +55 -0
- package/templates/boilerplate/validations/auth.validation.ts +92 -0
- package/templates/boilerplate/validations/commonValidations.ts +258 -0
- package/templates/boilerplate/validations/zodErrorMap.ts +101 -0
- package/templates/configs/.env.example +8 -0
- package/templates/configs/.prettierignore +23 -0
- package/templates/configs/.prettierrc.cjs +26 -0
- package/templates/configs/.prettierrc.icons.cjs +11 -0
- package/templates/configs/Dockerfile +6 -0
- package/templates/configs/commitlint.config.ts +8 -0
- package/templates/configs/eslint.config.mjs +119 -0
- package/templates/configs/knip.config.ts +32 -0
- package/templates/configs/lefthook.yml +42 -0
- package/templates/configs/lint-staged.config.js +8 -0
- package/templates/configs/next.config.template.ts +77 -0
- package/templates/configs/next.config.ts +43 -0
- package/templates/configs/package.json +75 -0
- package/templates/configs/postcss.config.mjs +15 -0
- package/templates/configs/svgr.config.mjs +129 -0
- package/templates/configs/tsconfig.json +75 -0
- package/templates/docs/AI_QUICK_REFERENCE.md +379 -0
- package/templates/docs/ARCHITECTURE_PATTERNS.md +927 -0
- package/templates/docs/DOCUMENTATION_INDEX.md +411 -0
- package/templates/docs/FIGMA_TO_CODE_GUIDE.md +768 -0
- package/templates/docs/IMPLEMENTATION_GUIDE.md +892 -0
- package/templates/docs/PROJECT_OVERVIEW.md +302 -0
- package/templates/docs/REFACTOR_PROGRESS.md +1113 -0
- package/templates/docs/SHADCN_TO_HEROUI_MIGRATION.md +1375 -0
- package/templates/docs/UI_COMPONENTS_GUIDE.md +893 -0
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@adlas/create-app",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Adlas project initializer with Figma and Swagger integration",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/cli.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"create-adlas-app": "./dist/cli.js",
|
|
9
|
+
"adlas": "./dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"templates"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"dev": "tsc --watch",
|
|
18
|
+
"prepublishOnly": "pnpm run build",
|
|
19
|
+
"test": "vitest",
|
|
20
|
+
"link": "pnpm run build && npm link"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"nextjs",
|
|
24
|
+
"heroui",
|
|
25
|
+
"react",
|
|
26
|
+
"typescript",
|
|
27
|
+
"figma",
|
|
28
|
+
"swagger",
|
|
29
|
+
"cli",
|
|
30
|
+
"create-app",
|
|
31
|
+
"boilerplate",
|
|
32
|
+
"starter"
|
|
33
|
+
],
|
|
34
|
+
"author": "Adlas",
|
|
35
|
+
"license": "UNLICENSED",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/adlas/create-app.git"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/adlas/create-app#readme",
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/adlas/create-app/issues"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=18.0.0"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"axios": "^1.6.5",
|
|
49
|
+
"chalk": "^5.3.0",
|
|
50
|
+
"commander": "^12.0.0",
|
|
51
|
+
"execa": "^8.0.1",
|
|
52
|
+
"fs-extra": "^11.2.0",
|
|
53
|
+
"ora": "^8.0.1",
|
|
54
|
+
"prompts": "^2.4.2"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/fs-extra": "^11.0.4",
|
|
58
|
+
"@types/node": "^20.10.6",
|
|
59
|
+
"@types/prompts": "^2.4.9",
|
|
60
|
+
"typescript": "^5.3.3",
|
|
61
|
+
"vitest": "^1.1.1"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Use IntelliSense to learn about possible attributes.
|
|
3
|
+
// Hover to view descriptions of existing attributes.
|
|
4
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
+
"version": "0.2.0",
|
|
6
|
+
"configurations": [
|
|
7
|
+
{
|
|
8
|
+
"name": "Next.js: debug full stack",
|
|
9
|
+
"type": "node",
|
|
10
|
+
"request": "launch",
|
|
11
|
+
"program": "${workspaceFolder}/node_modules/next/dist/bin/next",
|
|
12
|
+
"runtimeArgs": ["--inspect"],
|
|
13
|
+
"skipFiles": ["<node_internals>/**"],
|
|
14
|
+
"env": {
|
|
15
|
+
"NEXT_PUBLIC_SENTRY_DISABLED": "true"
|
|
16
|
+
},
|
|
17
|
+
"serverReadyAction": {
|
|
18
|
+
"action": "debugWithChrome",
|
|
19
|
+
"killOnServerStop": true,
|
|
20
|
+
"pattern": "- Local:.+(https?://.+)",
|
|
21
|
+
"uriFormat": "%s",
|
|
22
|
+
"webRoot": "${workspaceFolder}"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"editor.tabSize": 2,
|
|
3
|
+
"editor.detectIndentation": false,
|
|
4
|
+
"search.exclude": {
|
|
5
|
+
"package-lock.json": true
|
|
6
|
+
},
|
|
7
|
+
|
|
8
|
+
// TypeScript
|
|
9
|
+
"typescript.tsdk": "node_modules/typescript/lib", // Use the workspace version of TypeScript
|
|
10
|
+
"typescript.enablePromptUseWorkspaceTsdk": true, // For security reasons it's require that users opt into using the workspace version of typescript
|
|
11
|
+
"typescript.preferences.autoImportSpecifierExcludeRegexes": [
|
|
12
|
+
// useRouter should be imported from `next/navigation` instead of `next/router`
|
|
13
|
+
"next/router",
|
|
14
|
+
// give priority for Link to next/link instead of lucide-react
|
|
15
|
+
"lucide-react",
|
|
16
|
+
// Not used in the project and conflicts with `use()` from React
|
|
17
|
+
"chai",
|
|
18
|
+
// Use Zod v4 instead of v3
|
|
19
|
+
"zod/v3",
|
|
20
|
+
// Sentry is imported with `import *`
|
|
21
|
+
"@sentry/nextjs"
|
|
22
|
+
],
|
|
23
|
+
|
|
24
|
+
// Vitest
|
|
25
|
+
"testing.automaticallyOpenTestResults": "neverOpen", // Don't open the test results automatically
|
|
26
|
+
|
|
27
|
+
// I18n
|
|
28
|
+
"i18n-ally.localesPaths": ["src/locales"],
|
|
29
|
+
"i18n-ally.keystyle": "nested",
|
|
30
|
+
|
|
31
|
+
// Enable Prettier formatter
|
|
32
|
+
"prettier.enable": true,
|
|
33
|
+
"editor.formatOnSave": true,
|
|
34
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
35
|
+
|
|
36
|
+
// Auto fix with ESLint on save (after formatting)
|
|
37
|
+
"editor.codeActionsOnSave": {
|
|
38
|
+
"source.addMissingImports": "explicit",
|
|
39
|
+
"source.fixAll.eslint": "explicit"
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
// Enable eslint for all supported languages
|
|
43
|
+
"eslint.validate": [
|
|
44
|
+
"javascript",
|
|
45
|
+
"javascriptreact",
|
|
46
|
+
"typescript",
|
|
47
|
+
"typescriptreact",
|
|
48
|
+
"vue",
|
|
49
|
+
"html",
|
|
50
|
+
"markdown",
|
|
51
|
+
"json",
|
|
52
|
+
"jsonc",
|
|
53
|
+
"yaml",
|
|
54
|
+
"toml",
|
|
55
|
+
"xml",
|
|
56
|
+
"gql",
|
|
57
|
+
"graphql",
|
|
58
|
+
"astro",
|
|
59
|
+
"svelte",
|
|
60
|
+
"css",
|
|
61
|
+
"less",
|
|
62
|
+
"scss",
|
|
63
|
+
"pcss",
|
|
64
|
+
"postcss",
|
|
65
|
+
"github-actions-workflow"
|
|
66
|
+
]
|
|
67
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
|
3
|
+
// for the documentation about the tasks.json format
|
|
4
|
+
"version": "2.0.0",
|
|
5
|
+
"tasks": [
|
|
6
|
+
{
|
|
7
|
+
"label": "Project wide type checking with TypeScript",
|
|
8
|
+
"type": "npm",
|
|
9
|
+
"script": "check:types",
|
|
10
|
+
"problemMatcher": ["$tsc"],
|
|
11
|
+
"group": {
|
|
12
|
+
"kind": "build",
|
|
13
|
+
"isDefault": true
|
|
14
|
+
},
|
|
15
|
+
"presentation": {
|
|
16
|
+
"clear": true,
|
|
17
|
+
"reveal": "never"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { IBM_Plex_Sans } from 'next/font/google';
|
|
2
|
+
|
|
3
|
+
const ibmPlexSans = IBM_Plex_Sans({
|
|
4
|
+
subsets: ['latin'],
|
|
5
|
+
variable: '--font-ibm-plex-sans',
|
|
6
|
+
display: 'swap',
|
|
7
|
+
weight: ['300', '400', '500', '600', '700'],
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export const fontVariables = ibmPlexSans.variable;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export const NAVIGATION_URLS = {
|
|
2
|
+
// Public routes
|
|
3
|
+
ROOT: '/',
|
|
4
|
+
// Auth routes
|
|
5
|
+
AUTH: {
|
|
6
|
+
INDEX: '/auth',
|
|
7
|
+
LOGIN: '/auth/login',
|
|
8
|
+
REGISTER: '/auth/register',
|
|
9
|
+
FORGET_PASSWORD: '/auth/forget-password',
|
|
10
|
+
RESET_PASSWORD: '/auth/reset-password',
|
|
11
|
+
},
|
|
12
|
+
// Dashboard routes
|
|
13
|
+
DASHBOARD: {
|
|
14
|
+
PROFILE: {
|
|
15
|
+
GIFT_PREVIEW: '/profile/gift-preview',
|
|
16
|
+
INDEX: '/profile',
|
|
17
|
+
MY_REQUESTS: '/profile/my-requests',
|
|
18
|
+
GIFT_LIST: '/profile/gift-list',
|
|
19
|
+
WISHLIST: '/profile/wishlist',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
PRODUCTS: {
|
|
23
|
+
INDEX: '/products',
|
|
24
|
+
DETAILS: (id: string) => `/products/${id}`,
|
|
25
|
+
},
|
|
26
|
+
CATEGORIES: {
|
|
27
|
+
INDEX: '/categories',
|
|
28
|
+
DETAIL: (id: string) => `/categories/${id}`,
|
|
29
|
+
},
|
|
30
|
+
GIFT_DETAILS: (id: string) => `/gift?id=${id}`,
|
|
31
|
+
SERVICES: {
|
|
32
|
+
INDEX: '/services',
|
|
33
|
+
CARE_INSTRUCTIONS: '/services/care-instructions',
|
|
34
|
+
DOWNLOADS: '/services/downloads',
|
|
35
|
+
GIFT_LIST: '/services/gift-list',
|
|
36
|
+
},
|
|
37
|
+
ABOUT: '/about',
|
|
38
|
+
CONTACT: '/contact',
|
|
39
|
+
QUALITY: '/quality',
|
|
40
|
+
IMPRINT: '/imprint',
|
|
41
|
+
DATA_PROTECTION: '/data-protection',
|
|
42
|
+
TERMS: '/terms',
|
|
43
|
+
NEWS: {
|
|
44
|
+
INDEX: '/news',
|
|
45
|
+
DETAIL: (slug: string) => `/news/${slug}`,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { Metadata, Viewport } from 'next';
|
|
2
|
+
import type { LocalePrefixMode } from 'next-intl/routing';
|
|
3
|
+
|
|
4
|
+
import { Locales, LOCALES } from '@/types/locale';
|
|
5
|
+
|
|
6
|
+
import { NAVIGATION_URLS } from './navigationUrls';
|
|
7
|
+
|
|
8
|
+
export type MenuItem = {
|
|
9
|
+
key: string;
|
|
10
|
+
labelKey: string;
|
|
11
|
+
href: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const localePrefix: LocalePrefixMode = 'always';
|
|
15
|
+
|
|
16
|
+
export const siteConfig = {
|
|
17
|
+
name: '',
|
|
18
|
+
description: '',
|
|
19
|
+
locales: [...LOCALES] as string[],
|
|
20
|
+
defaultLocale: Locales.DE,
|
|
21
|
+
localePrefix,
|
|
22
|
+
theme: {
|
|
23
|
+
lightColor: '#FFFFFF', // background color from theme
|
|
24
|
+
darkColor: '#000000', // primary/foreground color from theme
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const menuItems: MenuItem[] = [
|
|
29
|
+
{ key: 'home', labelKey: 'home', href: NAVIGATION_URLS.ROOT },
|
|
30
|
+
{ key: 'news', labelKey: 'news', href: NAVIGATION_URLS.NEWS.INDEX },
|
|
31
|
+
{ key: 'about', labelKey: 'about', href: NAVIGATION_URLS.ABOUT },
|
|
32
|
+
{ key: 'contact', labelKey: 'contact', href: NAVIGATION_URLS.CONTACT },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
// Viewport Configuration
|
|
36
|
+
export const siteViewport: Viewport = {
|
|
37
|
+
width: 'device-width',
|
|
38
|
+
initialScale: 1,
|
|
39
|
+
maximumScale: 5,
|
|
40
|
+
userScalable: true,
|
|
41
|
+
viewportFit: 'cover',
|
|
42
|
+
themeColor: [
|
|
43
|
+
{ media: '(prefers-color-scheme: light)', color: siteConfig.theme.lightColor },
|
|
44
|
+
{ media: '(prefers-color-scheme: dark)', color: siteConfig.theme.darkColor },
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Metadata Configuration
|
|
49
|
+
export const siteMetadata: Metadata = {
|
|
50
|
+
title: {
|
|
51
|
+
default: siteConfig.name,
|
|
52
|
+
template: `%s - ${siteConfig.name}`,
|
|
53
|
+
},
|
|
54
|
+
description: siteConfig.description,
|
|
55
|
+
icons: {
|
|
56
|
+
icon: [
|
|
57
|
+
{ url: '/favicon.ico', sizes: 'any' },
|
|
58
|
+
{ url: '/favicon-16x16.png', sizes: '16x16', type: 'image/png' },
|
|
59
|
+
{ url: '/favicon-32x32.png', sizes: '32x32', type: 'image/png' },
|
|
60
|
+
],
|
|
61
|
+
apple: [{ url: '/apple-touch-icon.png', sizes: '180x180', type: 'image/png' }],
|
|
62
|
+
other: [
|
|
63
|
+
{
|
|
64
|
+
rel: 'icon',
|
|
65
|
+
url: '/icon-192.png',
|
|
66
|
+
sizes: '192x192',
|
|
67
|
+
type: 'image/png',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
rel: 'icon',
|
|
71
|
+
url: '/icon-512.png',
|
|
72
|
+
sizes: '512x512',
|
|
73
|
+
type: 'image/png',
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
manifest: '/site.webmanifest',
|
|
78
|
+
appleWebApp: {
|
|
79
|
+
capable: true,
|
|
80
|
+
statusBarStyle: 'default',
|
|
81
|
+
title: siteConfig.name,
|
|
82
|
+
},
|
|
83
|
+
formatDetection: {
|
|
84
|
+
telephone: false,
|
|
85
|
+
},
|
|
86
|
+
robots: {
|
|
87
|
+
index: true,
|
|
88
|
+
follow: true,
|
|
89
|
+
},
|
|
90
|
+
openGraph: {
|
|
91
|
+
type: 'website',
|
|
92
|
+
siteName: siteConfig.name,
|
|
93
|
+
title: siteConfig.name,
|
|
94
|
+
description: siteConfig.description,
|
|
95
|
+
},
|
|
96
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { hasLocale } from 'next-intl';
|
|
2
|
+
import { getRequestConfig } from 'next-intl/server';
|
|
3
|
+
|
|
4
|
+
import { routing } from './I18nRouting';
|
|
5
|
+
|
|
6
|
+
export default getRequestConfig(async ({ requestLocale }) => {
|
|
7
|
+
// Typically corresponds to the `[locale]` segment
|
|
8
|
+
const requested = await requestLocale;
|
|
9
|
+
const locale = hasLocale(routing.locales, requested) ? requested : routing.defaultLocale;
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
locale,
|
|
13
|
+
messages: (await import(`../locales/${locale}.json`)).default,
|
|
14
|
+
};
|
|
15
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createEnv } from '@t3-oss/env-nextjs';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
export const Env = createEnv({
|
|
5
|
+
server: {
|
|
6
|
+
SALEOR_SERVER_TOKEN: z.string(),
|
|
7
|
+
},
|
|
8
|
+
client: {
|
|
9
|
+
NEXT_PUBLIC_SITE_URL: z.string(),
|
|
10
|
+
NEXT_PUBLIC_SALEOR_API_URL: z.string(),
|
|
11
|
+
},
|
|
12
|
+
shared: {
|
|
13
|
+
NODE_ENV: z.enum(['development', 'staging', 'production']).optional(),
|
|
14
|
+
},
|
|
15
|
+
runtimeEnv: {
|
|
16
|
+
NEXT_PUBLIC_SITE_URL: process.env.NEXT_PUBLIC_SITE_URL,
|
|
17
|
+
NEXT_PUBLIC_SALEOR_API_URL: process.env.NEXT_PUBLIC_SALEOR_API_URL,
|
|
18
|
+
SALEOR_SERVER_TOKEN: process.env.SALEOR_SERVER_TOKEN,
|
|
19
|
+
NODE_ENV: process.env.NODE_ENV,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import type { ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
import { QueryClientProvider } from '@tanstack/react-query';
|
|
6
|
+
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
|
|
7
|
+
|
|
8
|
+
import { queryClient } from './queryClient';
|
|
9
|
+
|
|
10
|
+
type ReactQueryProviderProps = {
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export function ReactQueryProvider({ children }: ReactQueryProviderProps) {
|
|
15
|
+
return (
|
|
16
|
+
<QueryClientProvider client={queryClient}>
|
|
17
|
+
{children}
|
|
18
|
+
<ReactQueryDevtools initialIsOpen={false} />
|
|
19
|
+
</QueryClientProvider>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { QueryCache, QueryClient as TanStackQueryClient } from '@tanstack/react-query';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
const REACT_QUERY_CONFIG = {
|
|
5
|
+
STALE_TIME: 5 * 60 * 1000, // 5 minutes
|
|
6
|
+
GC_TIME: 10 * 60 * 1000, // 10 minutes
|
|
7
|
+
RETRY_ATTEMPTS: 3,
|
|
8
|
+
RETRY_DELAY: 1000, // 1 second
|
|
9
|
+
REFETCH_ON_WINDOW_FOCUS: false,
|
|
10
|
+
REFETCH_ON_MOUNT: false,
|
|
11
|
+
} as const;
|
|
12
|
+
|
|
13
|
+
// Helper to check if error is an authentication/authorization error
|
|
14
|
+
function isAuthError(error: unknown): boolean {
|
|
15
|
+
if (error) {
|
|
16
|
+
return error.status === 401 || error.status === 403;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Check for GraphQL authentication errors
|
|
20
|
+
if (error) {
|
|
21
|
+
const message = error.message.toLowerCase();
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
message.includes('unauthorized') ||
|
|
25
|
+
message.includes('unauthenticated') ||
|
|
26
|
+
message.includes('forbidden') ||
|
|
27
|
+
message.includes('not authenticated')
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const queryClient = new TanStackQueryClient({
|
|
35
|
+
defaultOptions: {
|
|
36
|
+
queries: {
|
|
37
|
+
staleTime: REACT_QUERY_CONFIG.STALE_TIME,
|
|
38
|
+
gcTime: REACT_QUERY_CONFIG.GC_TIME,
|
|
39
|
+
refetchOnWindowFocus: REACT_QUERY_CONFIG.REFETCH_ON_WINDOW_FOCUS,
|
|
40
|
+
refetchOnMount: REACT_QUERY_CONFIG.REFETCH_ON_MOUNT,
|
|
41
|
+
retryDelay: REACT_QUERY_CONFIG.RETRY_DELAY,
|
|
42
|
+
retry(failureCount, error) {
|
|
43
|
+
// Don't retry on authentication/authorization errors
|
|
44
|
+
if (isAuthError(error)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return failureCount < REACT_QUERY_CONFIG.RETRY_ATTEMPTS;
|
|
49
|
+
},
|
|
50
|
+
// Disable experimental prefetch to prevent "setState during render" errors
|
|
51
|
+
experimental_prefetchInRender: false,
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
queryCache: new QueryCache({
|
|
55
|
+
onError: (_, query) => {
|
|
56
|
+
queryClient.removeQueries({
|
|
57
|
+
queryKey: query.queryKey,
|
|
58
|
+
type: 'inactive',
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
}),
|
|
62
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|