create-reactivite 1.1.0 → 1.2.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 +198 -197
- package/index.js +26 -1
- package/package.json +4 -3
- package/template/_gitignore +24 -0
- package/template2/.env.example +8 -0
- package/template2/.husky/pre-commit +4 -0
- package/template2/.prettierrc +5 -0
- package/template2/README.md +73 -0
- package/template2/__tests__/example.test.ts +20 -0
- package/template2/_gitignore +37 -0
- package/template2/app/[locale]/(private)/dashboard/page.tsx +52 -0
- package/template2/app/[locale]/(public)/login/page.tsx +83 -0
- package/template2/app/[locale]/layout.tsx +56 -0
- package/template2/app/[locale]/locales.ts +10 -0
- package/template2/app/[locale]/page.tsx +38 -0
- package/template2/app/api/clear-session/route.ts +10 -0
- package/template2/app/globals.css +127 -0
- package/template2/app/layout.tsx +7 -0
- package/template2/app/page.tsx +6 -0
- package/template2/components/AuthEventListener.tsx +22 -0
- package/template2/components/theme-provider.tsx +78 -0
- package/template2/components/ui/button.tsx +60 -0
- package/template2/components/ui/card.tsx +92 -0
- package/template2/components/ui/input.tsx +21 -0
- package/template2/components/ui/label.tsx +24 -0
- package/template2/components/ui/sonner.tsx +40 -0
- package/template2/components.json +22 -0
- package/template2/config/constants.ts +7 -0
- package/template2/config/env.ts +5 -0
- package/template2/contexts/translation-context.tsx +70 -0
- package/template2/eslint.config.mjs +18 -0
- package/template2/hoc/provider.tsx +27 -0
- package/template2/lib/paramsSerializer.ts +40 -0
- package/template2/lib/utils.ts +6 -0
- package/template2/locales/az.json +20 -0
- package/template2/locales/en.json +20 -0
- package/template2/next-env.d.ts +6 -0
- package/template2/next.config.ts +17 -0
- package/template2/orval.config.ts +66 -0
- package/template2/package.json +62 -0
- package/template2/pnpm-lock.yaml +6804 -0
- package/template2/postcss.config.mjs +7 -0
- package/template2/public/.gitkeep +0 -0
- package/template2/scripts/fix-generated-types.mjs +13 -0
- package/template2/services/generated/.gitkeep +2 -0
- package/template2/services/httpClient/httpClient.ts +70 -0
- package/template2/services/httpClient/orvalMutator.ts +10 -0
- package/template2/store/example-store.tsx +16 -0
- package/template2/store/user-store.tsx +29 -0
- package/template2/testing/msw/handlers/index.ts +6 -0
- package/template2/testing/msw/server.ts +4 -0
- package/template2/tsconfig.json +34 -0
- package/template2/tsconfig.tsbuildinfo +1 -0
- package/template2/vitest.config.ts +17 -0
- package/template2/vitest.setup.ts +7 -0
|
File without changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Post-processing hook for orval output.
|
|
2
|
+
// Runs after `npm run generate`. Add codemods here if your backend schema needs
|
|
3
|
+
// tweaks the generator can't express. No-op when nothing is generated yet.
|
|
4
|
+
import { existsSync } from 'node:fs';
|
|
5
|
+
|
|
6
|
+
const GENERATED_DIR = new URL('../services/generated/', import.meta.url);
|
|
7
|
+
|
|
8
|
+
if (!existsSync(GENERATED_DIR)) {
|
|
9
|
+
console.log('fix-generated-types: services/generated yox, keçildi.');
|
|
10
|
+
process.exit(0);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
console.log('fix-generated-types: generated tipləri yoxlandı (no-op).');
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import axios, { AxiosInstance, AxiosResponse, AxiosError } from 'axios';
|
|
2
|
+
import { toast } from 'sonner';
|
|
3
|
+
import { useUserStore } from '@/store/user-store';
|
|
4
|
+
import { env } from '@/config/env';
|
|
5
|
+
import { AXIOS_TIMEOUT_MS } from '@/config/constants';
|
|
6
|
+
import { paramsSerializer } from '@/lib/paramsSerializer';
|
|
7
|
+
|
|
8
|
+
export const httpClient: AxiosInstance = axios.create({
|
|
9
|
+
baseURL: env.apiBaseUrl,
|
|
10
|
+
withCredentials: true,
|
|
11
|
+
paramsSerializer,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
httpClient.defaults.timeout = AXIOS_TIMEOUT_MS;
|
|
15
|
+
|
|
16
|
+
type ServerErrorData = { message: string };
|
|
17
|
+
|
|
18
|
+
const errorMessageByCode: Record<number, string> = {
|
|
19
|
+
400: 'Validation error',
|
|
20
|
+
404: 'Not found',
|
|
21
|
+
500: 'Server error',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const setupInterceptors = () => {
|
|
25
|
+
httpClient.interceptors.request.use(
|
|
26
|
+
(requestConfig) => {
|
|
27
|
+
if (typeof window !== 'undefined') {
|
|
28
|
+
const locale =
|
|
29
|
+
document.cookie.match(/NEXT_LOCALE=([^;]+)/)?.[1] ?? 'az';
|
|
30
|
+
requestConfig.headers['Accept-Language'] = locale;
|
|
31
|
+
}
|
|
32
|
+
return requestConfig;
|
|
33
|
+
},
|
|
34
|
+
(error: AxiosError) => Promise.reject(error),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
httpClient.interceptors.response.use(
|
|
38
|
+
(response: AxiosResponse) => response,
|
|
39
|
+
(error: AxiosError) => {
|
|
40
|
+
if (error.response) {
|
|
41
|
+
const errorStatus = error.response.status;
|
|
42
|
+
const errorData = error.response.data as ServerErrorData;
|
|
43
|
+
|
|
44
|
+
if (errorStatus === 401 || errorStatus === 403) {
|
|
45
|
+
const store = useUserStore.getState();
|
|
46
|
+
if (store.isAuthenticated()) {
|
|
47
|
+
store.clearUser();
|
|
48
|
+
window.dispatchEvent(new CustomEvent('auth:unauthorized'));
|
|
49
|
+
}
|
|
50
|
+
return Promise.reject(error);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (errorStatus in errorMessageByCode) {
|
|
54
|
+
toast.error(errorData?.message ?? errorMessageByCode[errorStatus]);
|
|
55
|
+
} else if (errorData?.message) {
|
|
56
|
+
toast.error(errorData.message);
|
|
57
|
+
} else {
|
|
58
|
+
toast.error(`Server status ${errorStatus}`);
|
|
59
|
+
}
|
|
60
|
+
} else if (error.request) {
|
|
61
|
+
toast.error('Network error. Check your connection.');
|
|
62
|
+
} else {
|
|
63
|
+
toast.error(`Unexpected error: ${error.message}`);
|
|
64
|
+
}
|
|
65
|
+
return Promise.reject(error);
|
|
66
|
+
},
|
|
67
|
+
);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
setupInterceptors();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AxiosRequestConfig } from 'axios';
|
|
2
|
+
import { httpClient } from './httpClient';
|
|
3
|
+
|
|
4
|
+
export const customMutator = <T>(config: AxiosRequestConfig): Promise<T> => {
|
|
5
|
+
const { signal, ...rest } = config;
|
|
6
|
+
return httpClient({
|
|
7
|
+
...rest,
|
|
8
|
+
...(signal instanceof AbortSignal ? { signal } : {}),
|
|
9
|
+
}).then(({ data }) => data);
|
|
10
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { create } from 'zustand';
|
|
2
|
+
|
|
3
|
+
type CounterState = {
|
|
4
|
+
count: number;
|
|
5
|
+
increment: () => void;
|
|
6
|
+
decrement: () => void;
|
|
7
|
+
reset: () => void;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// Minimal store to show the non-persisted pattern. Delete or replace.
|
|
11
|
+
export const useExampleStore = create<CounterState>((set) => ({
|
|
12
|
+
count: 0,
|
|
13
|
+
increment: () => set((s) => ({ count: s.count + 1 })),
|
|
14
|
+
decrement: () => set((s) => ({ count: s.count - 1 })),
|
|
15
|
+
reset: () => set({ count: 0 }),
|
|
16
|
+
}));
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { create } from 'zustand';
|
|
2
|
+
import { persist } from 'zustand/middleware';
|
|
3
|
+
|
|
4
|
+
export type User = {
|
|
5
|
+
id: string;
|
|
6
|
+
email: string;
|
|
7
|
+
fullName?: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type UserState = {
|
|
11
|
+
user: User | null;
|
|
12
|
+
setUser: (value: User | null) => void;
|
|
13
|
+
clearUser: () => void;
|
|
14
|
+
isAuthenticated: () => boolean;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const useUserStore = create<UserState>()(
|
|
18
|
+
persist(
|
|
19
|
+
(set, get) => ({
|
|
20
|
+
user: null,
|
|
21
|
+
setUser: (value) => set({ user: value }),
|
|
22
|
+
clearUser: () => set({ user: null }),
|
|
23
|
+
isAuthenticated: () => get().user !== null,
|
|
24
|
+
}),
|
|
25
|
+
{
|
|
26
|
+
name: 'user_authenticated',
|
|
27
|
+
},
|
|
28
|
+
),
|
|
29
|
+
);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2017",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"module": "esnext",
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"jsx": "react-jsx",
|
|
15
|
+
"incremental": true,
|
|
16
|
+
"plugins": [
|
|
17
|
+
{
|
|
18
|
+
"name": "next"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"paths": {
|
|
22
|
+
"@/*": ["./*"]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"include": [
|
|
26
|
+
"next-env.d.ts",
|
|
27
|
+
"**/*.ts",
|
|
28
|
+
"**/*.tsx",
|
|
29
|
+
".next/types/**/*.ts",
|
|
30
|
+
".next/dev/types/**/*.ts",
|
|
31
|
+
"**/*.mts"
|
|
32
|
+
],
|
|
33
|
+
"exclude": ["node_modules"]
|
|
34
|
+
}
|