3a-ecommerce-utils 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 +163 -0
- package/dist/chunk-PEAZVBSD.mjs +597 -0
- package/dist/client-DYGi_pyp.d.mts +87 -0
- package/dist/client-DYGi_pyp.d.ts +87 -0
- package/dist/index.d.mts +496 -0
- package/dist/index.d.ts +496 -0
- package/dist/index.js +17707 -0
- package/dist/index.mjs +17043 -0
- package/dist/validation/server.d.mts +50 -0
- package/dist/validation/server.d.ts +50 -0
- package/dist/validation/server.js +518 -0
- package/dist/validation/server.mjs +168 -0
- package/package.json +69 -0
- package/src/api/address.queries.ts +96 -0
- package/src/api/category.queries.ts +85 -0
- package/src/api/coupon.queries.ts +120 -0
- package/src/api/dashboard.queries.ts +35 -0
- package/src/api/errorHandler.ts +164 -0
- package/src/api/graphqlClient.ts +113 -0
- package/src/api/index.ts +10 -0
- package/src/api/logger.client.ts +89 -0
- package/src/api/logger.ts +135 -0
- package/src/api/order.queries.ts +211 -0
- package/src/api/product.queries.ts +144 -0
- package/src/api/review.queries.ts +56 -0
- package/src/api/user.queries.ts +232 -0
- package/src/assets/3A.png +0 -0
- package/src/assets/index.ts +1 -0
- package/src/assets.d.ts +29 -0
- package/src/auth.ts +176 -0
- package/src/config/jest.backend.config.js +42 -0
- package/src/config/jest.frontend.config.js +50 -0
- package/src/config/postcss.config.js +6 -0
- package/src/config/tailwind.config.ts +70 -0
- package/src/config/tsconfig.base.json +36 -0
- package/src/config/vite.config.ts +86 -0
- package/src/config/vitest.base.config.ts +74 -0
- package/src/config/webpack.base.config.ts +126 -0
- package/src/constants/index.ts +312 -0
- package/src/cookies.ts +104 -0
- package/src/helpers.ts +400 -0
- package/src/index.ts +32 -0
- package/src/validation/client.ts +287 -0
- package/src/validation/index.ts +3 -0
- package/src/validation/server.ts +32 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { ErrorType } from "@e-commerce/types";
|
|
2
|
+
|
|
3
|
+
export interface AppError {
|
|
4
|
+
type: ErrorType;
|
|
5
|
+
message: string;
|
|
6
|
+
originalError?: any;
|
|
7
|
+
statusCode?: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class ErrorHandler {
|
|
11
|
+
static handle(error: any): AppError {
|
|
12
|
+
if (error.code === 'ECONNABORTED' || error.message === 'Network Error') {
|
|
13
|
+
return {
|
|
14
|
+
type: ErrorType.NETWORK_ERROR,
|
|
15
|
+
message: 'Unable to connect to the server. Please check your internet connection.',
|
|
16
|
+
originalError: error,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (error.response) {
|
|
21
|
+
const { status, data } = error.response;
|
|
22
|
+
|
|
23
|
+
switch (status) {
|
|
24
|
+
case 401:
|
|
25
|
+
return {
|
|
26
|
+
type: ErrorType.AUTHENTICATION_ERROR,
|
|
27
|
+
message: data?.message || 'Authentication failed. Please log in again.',
|
|
28
|
+
statusCode: status,
|
|
29
|
+
originalError: error,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
case 403:
|
|
33
|
+
return {
|
|
34
|
+
type: ErrorType.AUTHORIZATION_ERROR,
|
|
35
|
+
message: data?.message || 'You do not have permission to perform this action.',
|
|
36
|
+
statusCode: status,
|
|
37
|
+
originalError: error,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
case 404:
|
|
41
|
+
return {
|
|
42
|
+
type: ErrorType.NOT_FOUND_ERROR,
|
|
43
|
+
message: data?.message || 'The requested resource was not found.',
|
|
44
|
+
statusCode: status,
|
|
45
|
+
originalError: error,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
case 422:
|
|
49
|
+
return {
|
|
50
|
+
type: ErrorType.VALIDATION_ERROR,
|
|
51
|
+
message: data?.message || 'Invalid input data.',
|
|
52
|
+
statusCode: status,
|
|
53
|
+
originalError: error,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
case 500:
|
|
57
|
+
case 502:
|
|
58
|
+
case 503:
|
|
59
|
+
case 504:
|
|
60
|
+
return {
|
|
61
|
+
type: ErrorType.SERVER_ERROR,
|
|
62
|
+
message: data?.message || 'A server error occurred. Please try again later.',
|
|
63
|
+
statusCode: status,
|
|
64
|
+
originalError: error,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
default:
|
|
68
|
+
return {
|
|
69
|
+
type: ErrorType.UNKNOWN_ERROR,
|
|
70
|
+
message: data?.message || 'An unexpected error occurred.',
|
|
71
|
+
statusCode: status,
|
|
72
|
+
originalError: error,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (error.graphQLErrors && error.graphQLErrors.length > 0) {
|
|
78
|
+
const gqlError = error.graphQLErrors[0];
|
|
79
|
+
return {
|
|
80
|
+
type: ErrorType.UNKNOWN_ERROR,
|
|
81
|
+
message: gqlError.message || 'A GraphQL error occurred.',
|
|
82
|
+
originalError: error,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
type: ErrorType.UNKNOWN_ERROR,
|
|
88
|
+
message: error.message || 'An unexpected error occurred.',
|
|
89
|
+
originalError: error,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
static getErrorMessage(error: any): string {
|
|
94
|
+
return this.handle(error).message;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
static isAuthError(error: any): boolean {
|
|
98
|
+
const handled = this.handle(error);
|
|
99
|
+
return (
|
|
100
|
+
handled.type === ErrorType.AUTHENTICATION_ERROR ||
|
|
101
|
+
handled.type === ErrorType.AUTHORIZATION_ERROR
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
static shouldRetry(error: any): boolean {
|
|
106
|
+
const handled = this.handle(error);
|
|
107
|
+
return handled.type === ErrorType.NETWORK_ERROR || handled.type === ErrorType.SERVER_ERROR;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface NotificationOptions {
|
|
112
|
+
type: 'success' | 'error' | 'warning' | 'info';
|
|
113
|
+
message: string;
|
|
114
|
+
duration?: number;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export class ErrorNotifier {
|
|
118
|
+
private static notifyCallback?: (options: NotificationOptions) => void;
|
|
119
|
+
|
|
120
|
+
static setNotifyCallback(callback: (options: NotificationOptions) => void): void {
|
|
121
|
+
this.notifyCallback = callback;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
static notifyError(error: any): void {
|
|
125
|
+
const handled = ErrorHandler.handle(error);
|
|
126
|
+
if (this.notifyCallback) {
|
|
127
|
+
this.notifyCallback({
|
|
128
|
+
type: 'error',
|
|
129
|
+
message: handled.message,
|
|
130
|
+
duration: 5000,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
static notifySuccess(message: string): void {
|
|
136
|
+
if (this.notifyCallback) {
|
|
137
|
+
this.notifyCallback({
|
|
138
|
+
type: 'success',
|
|
139
|
+
message,
|
|
140
|
+
duration: 3000,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
static notifyWarning(message: string): void {
|
|
146
|
+
if (this.notifyCallback) {
|
|
147
|
+
this.notifyCallback({
|
|
148
|
+
type: 'warning',
|
|
149
|
+
message,
|
|
150
|
+
duration: 4000,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
static notifyInfo(message: string): void {
|
|
156
|
+
if (this.notifyCallback) {
|
|
157
|
+
this.notifyCallback({
|
|
158
|
+
type: 'info',
|
|
159
|
+
message,
|
|
160
|
+
duration: 3000,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
|
|
2
|
+
|
|
3
|
+
export interface GraphQLResponse<T = any> {
|
|
4
|
+
data?: T;
|
|
5
|
+
errors?: Array<{
|
|
6
|
+
message: string;
|
|
7
|
+
locations?: Array<{ line: number; column: number }>;
|
|
8
|
+
path?: string[];
|
|
9
|
+
extensions?: any;
|
|
10
|
+
}>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface GraphQLClientConfig {
|
|
14
|
+
url: string;
|
|
15
|
+
headers?: Record<string, string>;
|
|
16
|
+
tokenStorageKey?: string;
|
|
17
|
+
onError?: (error: Error) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class GraphQLClient {
|
|
21
|
+
private client: AxiosInstance;
|
|
22
|
+
private tokenStorageKey: string;
|
|
23
|
+
private onError?: (error: Error) => void;
|
|
24
|
+
|
|
25
|
+
constructor(config: GraphQLClientConfig) {
|
|
26
|
+
this.tokenStorageKey = config.tokenStorageKey || 'auth_token';
|
|
27
|
+
this.onError = config.onError;
|
|
28
|
+
|
|
29
|
+
this.client = axios.create({
|
|
30
|
+
baseURL: config.url,
|
|
31
|
+
headers: {
|
|
32
|
+
'Content-Type': 'application/json',
|
|
33
|
+
...config.headers,
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
this.setupInterceptors();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private setupInterceptors(): void {
|
|
41
|
+
|
|
42
|
+
this.client.interceptors.request.use(
|
|
43
|
+
(config) => {
|
|
44
|
+
if (typeof window !== 'undefined') {
|
|
45
|
+
const token = localStorage.getItem(this.tokenStorageKey);
|
|
46
|
+
if (token) {
|
|
47
|
+
config.headers.Authorization = `Bearer ${token}`;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return config;
|
|
51
|
+
},
|
|
52
|
+
(error) => {
|
|
53
|
+
return Promise.reject(error);
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
this.client.interceptors.response.use(
|
|
58
|
+
(response) => {
|
|
59
|
+
|
|
60
|
+
if (response.data.errors && response.data.errors.length > 0) {
|
|
61
|
+
const error = new Error(response.data.errors[0].message);
|
|
62
|
+
if (this.onError) {
|
|
63
|
+
this.onError(error);
|
|
64
|
+
}
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
return response;
|
|
68
|
+
},
|
|
69
|
+
(error) => {
|
|
70
|
+
if (this.onError) {
|
|
71
|
+
this.onError(error);
|
|
72
|
+
}
|
|
73
|
+
return Promise.reject(error);
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async request<T = any>(
|
|
79
|
+
query: string,
|
|
80
|
+
variables?: Record<string, any>,
|
|
81
|
+
config?: AxiosRequestConfig
|
|
82
|
+
): Promise<T> {
|
|
83
|
+
try {
|
|
84
|
+
const response = await this.client.post<GraphQLResponse<T>>('', { query, variables }, config);
|
|
85
|
+
return response.data.data as T;
|
|
86
|
+
} catch (error: any) {
|
|
87
|
+
throw new Error(error?.response?.data?.errors?.[0]?.message || error.message);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
setToken(token: string): void {
|
|
92
|
+
if (typeof window !== 'undefined') {
|
|
93
|
+
localStorage.setItem(this.tokenStorageKey, token);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
clearToken(): void {
|
|
98
|
+
if (typeof window !== 'undefined') {
|
|
99
|
+
localStorage.removeItem(this.tokenStorageKey);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
getToken(): string | null {
|
|
104
|
+
if (typeof window !== 'undefined') {
|
|
105
|
+
return localStorage.getItem(this.tokenStorageKey);
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function createGraphQLClient(config: GraphQLClientConfig): GraphQLClient {
|
|
112
|
+
return new GraphQLClient(config);
|
|
113
|
+
}
|
package/src/api/index.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './user.queries';
|
|
2
|
+
export * from './product.queries';
|
|
3
|
+
export * from './order.queries';
|
|
4
|
+
export * from './coupon.queries';
|
|
5
|
+
export * from './category.queries';
|
|
6
|
+
export * from './dashboard.queries';
|
|
7
|
+
export * from './review.queries';
|
|
8
|
+
export * from './address.queries';
|
|
9
|
+
export * from './graphqlClient';
|
|
10
|
+
export * from './logger.client';
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { LogLevel } from '@e-commerce/types';
|
|
2
|
+
|
|
3
|
+
export interface LogEntry {
|
|
4
|
+
level: LogLevel;
|
|
5
|
+
message: string;
|
|
6
|
+
timestamp: string;
|
|
7
|
+
data?: any;
|
|
8
|
+
context?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Client-safe Logger for frontend applications
|
|
13
|
+
* Uses console only, no file system access
|
|
14
|
+
*/
|
|
15
|
+
export class Logger {
|
|
16
|
+
private static logs: LogEntry[] = [];
|
|
17
|
+
private static maxLogs = 1000;
|
|
18
|
+
private static enableConsole = true;
|
|
19
|
+
|
|
20
|
+
static configure(options: { maxLogs?: number; enableConsole?: boolean }) {
|
|
21
|
+
if (options.maxLogs !== undefined) this.maxLogs = options.maxLogs;
|
|
22
|
+
if (options.enableConsole !== undefined) this.enableConsole = options.enableConsole;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private static addLog(entry: LogEntry) {
|
|
26
|
+
this.logs.push(entry);
|
|
27
|
+
if (this.logs.length > this.maxLogs) this.logs.shift();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private static format(entry: LogEntry) {
|
|
31
|
+
return `[${entry.timestamp}] [${entry.level}]${entry.context ? ` [${entry.context}]` : ''}: ${
|
|
32
|
+
entry.message
|
|
33
|
+
}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static debug(message: string, data?: any, context?: string) {
|
|
37
|
+
this.log(LogLevel.DEBUG, message, data, context);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static info(message: string, data?: any, context?: string) {
|
|
41
|
+
this.log(LogLevel.INFO, message, data, context);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static warn(message: string, data?: any, context?: string) {
|
|
45
|
+
this.log(LogLevel.WARN, message, data, context);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static error(message: string, error?: any, context?: string) {
|
|
49
|
+
this.log(LogLevel.ERROR, message, error, context);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private static log(level: LogLevel, message: string, data?: any, context?: string) {
|
|
53
|
+
const entry: LogEntry = {
|
|
54
|
+
level,
|
|
55
|
+
message,
|
|
56
|
+
timestamp: new Date().toISOString(),
|
|
57
|
+
data,
|
|
58
|
+
context,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
this.addLog(entry);
|
|
62
|
+
|
|
63
|
+
if (!this.enableConsole) return;
|
|
64
|
+
|
|
65
|
+
const formatted = this.format(entry);
|
|
66
|
+
|
|
67
|
+
switch (level) {
|
|
68
|
+
case LogLevel.ERROR:
|
|
69
|
+
console.error(formatted, data ?? '');
|
|
70
|
+
break;
|
|
71
|
+
case LogLevel.WARN:
|
|
72
|
+
console.warn(formatted, data ?? '');
|
|
73
|
+
break;
|
|
74
|
+
case LogLevel.INFO:
|
|
75
|
+
console.info(formatted, data ?? '');
|
|
76
|
+
break;
|
|
77
|
+
default:
|
|
78
|
+
console.debug(formatted, data ?? '');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static getLogs(level?: LogLevel): LogEntry[] {
|
|
83
|
+
return level ? this.logs.filter((l) => l.level === level) : [...this.logs];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
static clearLogs() {
|
|
87
|
+
this.logs = [];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side Logger with file system support
|
|
3
|
+
* For frontend apps, use logger.client.ts instead
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { LogLevel } from '@e-commerce/types';
|
|
9
|
+
|
|
10
|
+
export interface LogEntry {
|
|
11
|
+
level: LogLevel;
|
|
12
|
+
message: string;
|
|
13
|
+
timestamp: string;
|
|
14
|
+
data?: any;
|
|
15
|
+
context?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Log level priority for filtering
|
|
19
|
+
const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {
|
|
20
|
+
[LogLevel.DEBUG]: 0,
|
|
21
|
+
[LogLevel.INFO]: 1,
|
|
22
|
+
[LogLevel.WARN]: 2,
|
|
23
|
+
[LogLevel.ERROR]: 3,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export class Logger {
|
|
27
|
+
private static logs: LogEntry[] = [];
|
|
28
|
+
private static maxLogs = 1000;
|
|
29
|
+
private static enableConsole = true;
|
|
30
|
+
private static enableFile = false;
|
|
31
|
+
private static logFilePath = path.join(process.cwd(), 'logs/app.log');
|
|
32
|
+
private static logLevel: LogLevel = LogLevel.DEBUG;
|
|
33
|
+
|
|
34
|
+
static configure(options: {
|
|
35
|
+
maxLogs?: number;
|
|
36
|
+
enableConsole?: boolean;
|
|
37
|
+
enableFile?: boolean;
|
|
38
|
+
logFilePath?: string;
|
|
39
|
+
logLevel?: LogLevel | string;
|
|
40
|
+
}) {
|
|
41
|
+
if (options.maxLogs !== undefined) this.maxLogs = options.maxLogs;
|
|
42
|
+
if (options.enableConsole !== undefined) this.enableConsole = options.enableConsole;
|
|
43
|
+
if (options.enableFile !== undefined) this.enableFile = options.enableFile;
|
|
44
|
+
if (options.logFilePath) this.logFilePath = options.logFilePath;
|
|
45
|
+
if (options.logLevel) {
|
|
46
|
+
const level =
|
|
47
|
+
typeof options.logLevel === 'string'
|
|
48
|
+
? (options.logLevel.toUpperCase() as LogLevel)
|
|
49
|
+
: options.logLevel;
|
|
50
|
+
if (Object.values(LogLevel).includes(level)) {
|
|
51
|
+
this.logLevel = level;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private static shouldLog(level: LogLevel): boolean {
|
|
57
|
+
return LOG_LEVEL_PRIORITY[level] >= LOG_LEVEL_PRIORITY[this.logLevel];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private static addLog(entry: LogEntry) {
|
|
61
|
+
this.logs.push(entry);
|
|
62
|
+
if (this.logs.length > this.maxLogs) this.logs.shift();
|
|
63
|
+
|
|
64
|
+
if (this.enableFile) {
|
|
65
|
+
fs.mkdirSync(path.dirname(this.logFilePath), { recursive: true });
|
|
66
|
+
fs.appendFileSync(this.logFilePath, JSON.stringify(entry) + '\n');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private static format(entry: LogEntry) {
|
|
71
|
+
return `[${entry.timestamp}] [${entry.level}]${entry.context ? ` [${entry.context}]` : ''}: ${
|
|
72
|
+
entry.message
|
|
73
|
+
}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
static debug(message: string, data?: any, context?: string) {
|
|
77
|
+
this.log(LogLevel.DEBUG, message, data, context);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static info(message: string, data?: any, context?: string) {
|
|
81
|
+
this.log(LogLevel.INFO, message, data, context);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
static warn(message: string, data?: any, context?: string) {
|
|
85
|
+
this.log(LogLevel.WARN, message, data, context);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static error(message: string, error?: any, context?: string) {
|
|
89
|
+
this.log(LogLevel.ERROR, message, error, context);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private static log(level: LogLevel, message: string, data?: any, context?: string) {
|
|
93
|
+
// Check if this log level should be logged based on configured level
|
|
94
|
+
if (!this.shouldLog(level)) return;
|
|
95
|
+
|
|
96
|
+
const entry: LogEntry = {
|
|
97
|
+
level,
|
|
98
|
+
message,
|
|
99
|
+
timestamp: new Date().toISOString(),
|
|
100
|
+
data,
|
|
101
|
+
context,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
this.addLog(entry);
|
|
105
|
+
|
|
106
|
+
if (!this.enableConsole) return;
|
|
107
|
+
|
|
108
|
+
const formatted = this.format(entry);
|
|
109
|
+
|
|
110
|
+
switch (level) {
|
|
111
|
+
case LogLevel.ERROR:
|
|
112
|
+
console.error(formatted, data ?? '');
|
|
113
|
+
break;
|
|
114
|
+
case LogLevel.WARN:
|
|
115
|
+
console.warn(formatted, data ?? '');
|
|
116
|
+
break;
|
|
117
|
+
case LogLevel.INFO:
|
|
118
|
+
console.info(formatted, data ?? '');
|
|
119
|
+
break;
|
|
120
|
+
default:
|
|
121
|
+
console.debug(formatted, data ?? '');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
static getLogs(level?: LogLevel): LogEntry[] {
|
|
126
|
+
return level ? this.logs.filter((l) => l.level === level) : [...this.logs];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static clearLogs() {
|
|
130
|
+
this.logs = [];
|
|
131
|
+
if (this.enableFile && fs.existsSync(this.logFilePath)) {
|
|
132
|
+
fs.unlinkSync(this.logFilePath);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
export const GET_ORDERS_QUERY = `
|
|
2
|
+
query GetOrders($page: Int, $limit: Int, $customerId: String) {
|
|
3
|
+
orders(page: $page, limit: $limit, customerId: $customerId) {
|
|
4
|
+
orders {
|
|
5
|
+
id
|
|
6
|
+
orderNumber
|
|
7
|
+
customerId
|
|
8
|
+
customerEmail
|
|
9
|
+
items {
|
|
10
|
+
productId
|
|
11
|
+
productName
|
|
12
|
+
quantity
|
|
13
|
+
price
|
|
14
|
+
subtotal
|
|
15
|
+
}
|
|
16
|
+
subtotal
|
|
17
|
+
tax
|
|
18
|
+
shipping
|
|
19
|
+
discount
|
|
20
|
+
total
|
|
21
|
+
orderStatus
|
|
22
|
+
paymentStatus
|
|
23
|
+
paymentMethod
|
|
24
|
+
shippingAddress {
|
|
25
|
+
street
|
|
26
|
+
city
|
|
27
|
+
state
|
|
28
|
+
zip
|
|
29
|
+
country
|
|
30
|
+
}
|
|
31
|
+
notes
|
|
32
|
+
createdAt
|
|
33
|
+
updatedAt
|
|
34
|
+
}
|
|
35
|
+
pagination {
|
|
36
|
+
page
|
|
37
|
+
limit
|
|
38
|
+
total
|
|
39
|
+
pages
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
export const GET_ORDER_QUERY = `
|
|
46
|
+
query GetOrder($id: ID!) {
|
|
47
|
+
order(id: $id) {
|
|
48
|
+
id
|
|
49
|
+
orderNumber
|
|
50
|
+
customerId
|
|
51
|
+
customerEmail
|
|
52
|
+
items {
|
|
53
|
+
productId
|
|
54
|
+
productName
|
|
55
|
+
quantity
|
|
56
|
+
price
|
|
57
|
+
subtotal
|
|
58
|
+
}
|
|
59
|
+
subtotal
|
|
60
|
+
tax
|
|
61
|
+
shipping
|
|
62
|
+
total
|
|
63
|
+
orderStatus
|
|
64
|
+
paymentStatus
|
|
65
|
+
paymentMethod
|
|
66
|
+
shippingAddress {
|
|
67
|
+
street
|
|
68
|
+
city
|
|
69
|
+
state
|
|
70
|
+
zip
|
|
71
|
+
country
|
|
72
|
+
}
|
|
73
|
+
notes
|
|
74
|
+
createdAt
|
|
75
|
+
updatedAt
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
`;
|
|
79
|
+
|
|
80
|
+
export const GET_ORDERS_BY_CUSTOMER_QUERY = `
|
|
81
|
+
query GetOrdersByCustomer($customerId: String!) {
|
|
82
|
+
ordersByCustomer(customerId: $customerId) {
|
|
83
|
+
id
|
|
84
|
+
orderNumber
|
|
85
|
+
customerId
|
|
86
|
+
customerEmail
|
|
87
|
+
items {
|
|
88
|
+
productId
|
|
89
|
+
productName
|
|
90
|
+
quantity
|
|
91
|
+
price
|
|
92
|
+
subtotal
|
|
93
|
+
}
|
|
94
|
+
subtotal
|
|
95
|
+
tax
|
|
96
|
+
shipping
|
|
97
|
+
total
|
|
98
|
+
orderStatus
|
|
99
|
+
paymentStatus
|
|
100
|
+
paymentMethod
|
|
101
|
+
shippingAddress {
|
|
102
|
+
street
|
|
103
|
+
city
|
|
104
|
+
state
|
|
105
|
+
zip
|
|
106
|
+
country
|
|
107
|
+
}
|
|
108
|
+
notes
|
|
109
|
+
createdAt
|
|
110
|
+
updatedAt
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
`;
|
|
114
|
+
|
|
115
|
+
export const CREATE_ORDER_MUTATION = `
|
|
116
|
+
mutation CreateOrder($input: CreateOrderInput!) {
|
|
117
|
+
createOrder(input: $input) {
|
|
118
|
+
order {
|
|
119
|
+
id
|
|
120
|
+
orderNumber
|
|
121
|
+
customerId
|
|
122
|
+
customerEmail
|
|
123
|
+
sellerId
|
|
124
|
+
items {
|
|
125
|
+
productId
|
|
126
|
+
productName
|
|
127
|
+
quantity
|
|
128
|
+
price
|
|
129
|
+
sellerId
|
|
130
|
+
subtotal
|
|
131
|
+
}
|
|
132
|
+
subtotal
|
|
133
|
+
tax
|
|
134
|
+
shipping
|
|
135
|
+
discount
|
|
136
|
+
couponCode
|
|
137
|
+
total
|
|
138
|
+
orderStatus
|
|
139
|
+
paymentStatus
|
|
140
|
+
paymentMethod
|
|
141
|
+
shippingAddress {
|
|
142
|
+
street
|
|
143
|
+
city
|
|
144
|
+
state
|
|
145
|
+
zip
|
|
146
|
+
country
|
|
147
|
+
}
|
|
148
|
+
notes
|
|
149
|
+
createdAt
|
|
150
|
+
updatedAt
|
|
151
|
+
}
|
|
152
|
+
orders {
|
|
153
|
+
id
|
|
154
|
+
orderNumber
|
|
155
|
+
customerId
|
|
156
|
+
customerEmail
|
|
157
|
+
sellerId
|
|
158
|
+
items {
|
|
159
|
+
productId
|
|
160
|
+
productName
|
|
161
|
+
quantity
|
|
162
|
+
price
|
|
163
|
+
sellerId
|
|
164
|
+
subtotal
|
|
165
|
+
}
|
|
166
|
+
subtotal
|
|
167
|
+
tax
|
|
168
|
+
shipping
|
|
169
|
+
discount
|
|
170
|
+
total
|
|
171
|
+
orderStatus
|
|
172
|
+
paymentStatus
|
|
173
|
+
createdAt
|
|
174
|
+
}
|
|
175
|
+
orderCount
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
`;
|
|
179
|
+
|
|
180
|
+
export const UPDATE_ORDER_STATUS_MUTATION = `
|
|
181
|
+
mutation UpdateOrderStatus($id: ID!, $status: OrderStatus!) {
|
|
182
|
+
updateOrderStatus(id: $id, status: $status) {
|
|
183
|
+
id
|
|
184
|
+
orderNumber
|
|
185
|
+
orderStatus
|
|
186
|
+
updatedAt
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
`;
|
|
190
|
+
|
|
191
|
+
export const UPDATE_PAYMENT_STATUS_MUTATION = `
|
|
192
|
+
mutation UpdatePaymentStatus($id: ID!, $status: PaymentStatus!) {
|
|
193
|
+
updatePaymentStatus(id: $id, status: $status) {
|
|
194
|
+
id
|
|
195
|
+
orderNumber
|
|
196
|
+
paymentStatus
|
|
197
|
+
updatedAt
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
`;
|
|
201
|
+
|
|
202
|
+
export const CANCEL_ORDER_MUTATION = `
|
|
203
|
+
mutation CancelOrder($id: ID!) {
|
|
204
|
+
cancelOrder(id: $id) {
|
|
205
|
+
id
|
|
206
|
+
orderNumber
|
|
207
|
+
orderStatus
|
|
208
|
+
updatedAt
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
`;
|