pi-kiosk-shared 2.0.0 → 2.1.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 +6 -6
- package/dist/api.d.ts +9 -10
- package/dist/api.js +9 -10
- package/dist/config/deployment.js +3 -3
- package/dist/config/environments.d.ts +7 -0
- package/dist/config/environments.d.ts.map +1 -0
- package/dist/config/environments.js +25 -23
- package/dist/config/environments.js.map +1 -0
- package/dist/config/environments.test.d.ts +1 -0
- package/dist/config/environments.test.js +49 -0
- package/dist/errors.d.ts +0 -12
- package/dist/errors.js +0 -24
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/types.d.ts +17 -161
- package/dist/types.js +1 -17
- package/dist/utils/simple.test.d.ts +1 -0
- package/dist/utils/simple.test.js +45 -0
- package/dist/utils.d.ts +0 -6
- package/dist/utils.js +4 -29
- package/dist/validation.d.ts +1 -15
- package/dist/validation.js +1 -60
- package/package.json +1 -4
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
# pi-kiosk
|
|
1
|
+
# @pi-kiosk/shared
|
|
2
2
|
|
|
3
3
|
Shared components, utilities, and types for the Pi Kiosk system.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install pi-kiosk
|
|
8
|
+
npm install @pi-kiosk/shared
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Usage
|
|
@@ -13,7 +13,7 @@ npm install pi-kiosk-shared
|
|
|
13
13
|
### Components
|
|
14
14
|
|
|
15
15
|
```tsx
|
|
16
|
-
import { ErrorDisplay, LoadingSpinner } from 'pi-kiosk
|
|
16
|
+
import { ErrorDisplay, LoadingSpinner } from '@pi-kiosk/shared';
|
|
17
17
|
|
|
18
18
|
function MyComponent() {
|
|
19
19
|
return (
|
|
@@ -28,7 +28,7 @@ function MyComponent() {
|
|
|
28
28
|
### Types
|
|
29
29
|
|
|
30
30
|
```tsx
|
|
31
|
-
import { Product, ApiResponse, KioskStatus } from 'pi-kiosk
|
|
31
|
+
import { Product, ApiResponse, KioskStatus } from '@pi-kiosk/shared';
|
|
32
32
|
|
|
33
33
|
const product: Product = {
|
|
34
34
|
id: 1,
|
|
@@ -45,7 +45,7 @@ const product: Product = {
|
|
|
45
45
|
### Hooks
|
|
46
46
|
|
|
47
47
|
```tsx
|
|
48
|
-
import { useApi, useErrorHandler } from 'pi-kiosk
|
|
48
|
+
import { useApi, useErrorHandler } from '@pi-kiosk/shared';
|
|
49
49
|
|
|
50
50
|
function MyComponent() {
|
|
51
51
|
const api = useApi();
|
|
@@ -58,7 +58,7 @@ function MyComponent() {
|
|
|
58
58
|
### Utilities
|
|
59
59
|
|
|
60
60
|
```tsx
|
|
61
|
-
import { formatPrice, validateEmail } from 'pi-kiosk
|
|
61
|
+
import { formatPrice, validateEmail } from '@pi-kiosk/shared';
|
|
62
62
|
|
|
63
63
|
const price = formatPrice(25.5); // "25,50 Kč"
|
|
64
64
|
const isValid = validateEmail('user@example.com'); // true
|
package/dist/api.d.ts
CHANGED
|
@@ -8,20 +8,19 @@ export declare const API_ENDPOINTS: {
|
|
|
8
8
|
readonly PAYMENT_COMPLETE_MULTI: "/api/payments/complete-multi";
|
|
9
9
|
readonly PAYMENT_CANCEL: "/api/payments/cancel";
|
|
10
10
|
readonly PAYMENT_START_MONITORING: "/api/payments/start-monitoring";
|
|
11
|
-
readonly PAYMENT_STOP_MONITORING: "/api/payments/stop-monitoring";
|
|
12
11
|
readonly PAYMENT_THEPAY_CREATE: "/api/payments/create-thepay";
|
|
13
12
|
readonly PAYMENT_THEPAY_STATUS: "/api/payments/thepay-status/:paymentId";
|
|
14
13
|
readonly PAYMENT_THEPAY_CANCEL: "/api/payments/thepay-cancel";
|
|
15
14
|
readonly PAYMENT_THEPAY_METHODS: "/api/payments/thepay-methods";
|
|
16
|
-
readonly ADMIN_LOGIN: "/
|
|
17
|
-
readonly ADMIN_PRODUCTS: "/
|
|
18
|
-
readonly ADMIN_PRODUCTS_INVENTORY: "/
|
|
19
|
-
readonly ADMIN_PRODUCT_INVENTORY: "/
|
|
20
|
-
readonly ADMIN_PRODUCT_INVENTORY_UPDATE: "/
|
|
21
|
-
readonly ADMIN_PRODUCT_KIOSK_VISIBILITY: "/
|
|
22
|
-
readonly ADMIN_KIOSKS: "/
|
|
23
|
-
readonly ADMIN_KIOSK_DETAILS: "/
|
|
24
|
-
readonly ADMIN_LOGS: "/
|
|
15
|
+
readonly ADMIN_LOGIN: "/admin/login";
|
|
16
|
+
readonly ADMIN_PRODUCTS: "/admin/products";
|
|
17
|
+
readonly ADMIN_PRODUCTS_INVENTORY: "/admin/products/inventory/:kioskId";
|
|
18
|
+
readonly ADMIN_PRODUCT_INVENTORY: "/admin/products/:id/inventory";
|
|
19
|
+
readonly ADMIN_PRODUCT_INVENTORY_UPDATE: "/admin/products/:productId/inventory/:kioskId";
|
|
20
|
+
readonly ADMIN_PRODUCT_KIOSK_VISIBILITY: "/admin/products/:productId/kiosk/:kioskId";
|
|
21
|
+
readonly ADMIN_KIOSKS: "/admin/kiosks";
|
|
22
|
+
readonly ADMIN_KIOSK_DETAILS: "/admin/kiosks/:id";
|
|
23
|
+
readonly ADMIN_LOGS: "/admin/logs";
|
|
25
24
|
readonly HEALTH: "/health";
|
|
26
25
|
readonly CHECK_TRANSACTIONS: "/api/check-new-transactions";
|
|
27
26
|
readonly EVENTS: "/events/:kioskId";
|
package/dist/api.js
CHANGED
|
@@ -11,22 +11,21 @@ export const API_ENDPOINTS = {
|
|
|
11
11
|
PAYMENT_COMPLETE_MULTI: '/api/payments/complete-multi',
|
|
12
12
|
PAYMENT_CANCEL: '/api/payments/cancel',
|
|
13
13
|
PAYMENT_START_MONITORING: '/api/payments/start-monitoring',
|
|
14
|
-
PAYMENT_STOP_MONITORING: '/api/payments/stop-monitoring',
|
|
15
14
|
// ThePay.eu payment endpoints
|
|
16
15
|
PAYMENT_THEPAY_CREATE: '/api/payments/create-thepay',
|
|
17
16
|
PAYMENT_THEPAY_STATUS: '/api/payments/thepay-status/:paymentId',
|
|
18
17
|
PAYMENT_THEPAY_CANCEL: '/api/payments/thepay-cancel',
|
|
19
18
|
PAYMENT_THEPAY_METHODS: '/api/payments/thepay-methods',
|
|
20
19
|
// Admin endpoints
|
|
21
|
-
ADMIN_LOGIN: '/
|
|
22
|
-
ADMIN_PRODUCTS: '/
|
|
23
|
-
ADMIN_PRODUCTS_INVENTORY: '/
|
|
24
|
-
ADMIN_PRODUCT_INVENTORY: '/
|
|
25
|
-
ADMIN_PRODUCT_INVENTORY_UPDATE: '/
|
|
26
|
-
ADMIN_PRODUCT_KIOSK_VISIBILITY: '/
|
|
27
|
-
ADMIN_KIOSKS: '/
|
|
28
|
-
ADMIN_KIOSK_DETAILS: '/
|
|
29
|
-
ADMIN_LOGS: '/
|
|
20
|
+
ADMIN_LOGIN: '/admin/login',
|
|
21
|
+
ADMIN_PRODUCTS: '/admin/products',
|
|
22
|
+
ADMIN_PRODUCTS_INVENTORY: '/admin/products/inventory/:kioskId',
|
|
23
|
+
ADMIN_PRODUCT_INVENTORY: '/admin/products/:id/inventory',
|
|
24
|
+
ADMIN_PRODUCT_INVENTORY_UPDATE: '/admin/products/:productId/inventory/:kioskId',
|
|
25
|
+
ADMIN_PRODUCT_KIOSK_VISIBILITY: '/admin/products/:productId/kiosk/:kioskId',
|
|
26
|
+
ADMIN_KIOSKS: '/admin/kiosks',
|
|
27
|
+
ADMIN_KIOSK_DETAILS: '/admin/kiosks/:id',
|
|
28
|
+
ADMIN_LOGS: '/admin/logs',
|
|
30
29
|
// System endpoints
|
|
31
30
|
HEALTH: '/health',
|
|
32
31
|
CHECK_TRANSACTIONS: '/api/check-new-transactions',
|
|
@@ -30,8 +30,8 @@ export const deploymentConfig = {
|
|
|
30
30
|
production: {
|
|
31
31
|
'NODE_ENV': 'production',
|
|
32
32
|
'REACT_APP_ENVIRONMENT': 'production',
|
|
33
|
-
'REACT_APP_API_URL': 'https://
|
|
34
|
-
'REACT_APP_WS_URL': 'wss://
|
|
33
|
+
'REACT_APP_API_URL': 'https://kiosk-prod.railway.app',
|
|
34
|
+
'REACT_APP_WS_URL': 'wss://kiosk-prod.railway.app',
|
|
35
35
|
'REACT_APP_PAYMENT_MODE': 'production',
|
|
36
36
|
'REACT_APP_ENABLE_MOCK_PAYMENTS': 'false',
|
|
37
37
|
'REACT_APP_SHOW_DEBUG_INFO': 'false',
|
|
@@ -131,7 +131,7 @@ export const railwayConfigs = {
|
|
|
131
131
|
source: './packages/backend',
|
|
132
132
|
env: {
|
|
133
133
|
...deploymentConfig.environmentVariables.production,
|
|
134
|
-
PORT: '
|
|
134
|
+
PORT: '3000'
|
|
135
135
|
}
|
|
136
136
|
},
|
|
137
137
|
{
|
|
@@ -10,6 +10,12 @@ export interface EnvironmentConfig {
|
|
|
10
10
|
kioskUrl: string;
|
|
11
11
|
adminUrl: string;
|
|
12
12
|
backendUrl: string;
|
|
13
|
+
sseHealthCheckInterval: number;
|
|
14
|
+
sseHealthCheckInitialInterval: number;
|
|
15
|
+
sseHealthCheckBackoffMultiplier: number;
|
|
16
|
+
sseHealthCheckMaxInterval: number;
|
|
17
|
+
sseHealthCheckMaxAttempts: number;
|
|
18
|
+
sseHealthCheckMaxTotalTime: number;
|
|
13
19
|
}
|
|
14
20
|
export declare const getCurrentEnvironment: () => Environment;
|
|
15
21
|
export declare const getEnvironmentConfig: () => EnvironmentConfig;
|
|
@@ -29,3 +35,4 @@ export declare const getUIConfig: () => {
|
|
|
29
35
|
showDebugInfo: boolean;
|
|
30
36
|
logLevel: "debug" | "info" | "warn" | "error";
|
|
31
37
|
};
|
|
38
|
+
//# sourceMappingURL=environments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environments.d.ts","sourceRoot":"","sources":["../../src/config/environments.ts"],"names":[],"mappings":"AAiDA,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,YAAY,CAAC;AAEvD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB,EAAE,OAAO,CAAC;IAC5B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;IAC/C,aAAa,EAAE,OAAO,CAAC;IACvB,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,6BAA6B,EAAE,MAAM,CAAC;IACtC,+BAA+B,EAAE,MAAM,CAAC;IACxC,yBAAyB,EAAE,MAAM,CAAC;IAClC,yBAAyB,EAAE,MAAM,CAAC;IAClC,0BAA0B,EAAE,MAAM,CAAC;CACpC;AA0DD,eAAO,MAAM,qBAAqB,QAAO,WAuBxC,CAAC;AAGF,eAAO,MAAM,oBAAoB,QAAO,iBAGvC,CAAC;AAGF,eAAO,MAAM,aAAa,QAAO,OAAoD,CAAC;AACtF,eAAO,MAAM,YAAY,QAAO,OAAmD,CAAC;AAGpF,eAAO,MAAM,aAAa,QAAO,MAA2C,CAAC;AAC7E,eAAO,MAAM,WAAW,QAAO,MAAyC,CAAC;AACzE,eAAO,MAAM,WAAW,QAAO,MAAyC,CAAC;AACzE,eAAO,MAAM,SAAS,QAAO,MAAuC,CAAC;AACrE,eAAO,MAAM,QAAQ,QAAO,MAAsC,CAAC;AAGnE,eAAO,MAAM,gBAAgB;;;;CAO5B,CAAC;AAEF,eAAO,MAAM,WAAW;;;CAMvB,CAAC"}
|
|
@@ -25,6 +25,11 @@ function getEnvBool(key, defaultValue) {
|
|
|
25
25
|
const value = getEnvVar(key, defaultValue.toString());
|
|
26
26
|
return value === 'true';
|
|
27
27
|
}
|
|
28
|
+
function getEnvNumber(key, defaultValue) {
|
|
29
|
+
const value = getEnvVar(key, defaultValue.toString());
|
|
30
|
+
const parsed = parseInt(value, 10);
|
|
31
|
+
return isNaN(parsed) ? defaultValue : parsed;
|
|
32
|
+
}
|
|
28
33
|
// Centralized service URLs configuration
|
|
29
34
|
const SERVICE_URLS = {
|
|
30
35
|
development: {
|
|
@@ -57,6 +62,13 @@ function getConfigForEnvironment(env) {
|
|
|
57
62
|
kioskUrl: getEnvVar('REACT_APP_KIOSK_URL', urls.kiosk),
|
|
58
63
|
adminUrl: getEnvVar('REACT_APP_ADMIN_URL', urls.admin),
|
|
59
64
|
backendUrl: getEnvVar('REACT_APP_BACKEND_URL', urls.backend),
|
|
65
|
+
// SSE Configuration
|
|
66
|
+
sseHealthCheckInterval: getEnvNumber('REACT_APP_SSE_HEALTH_CHECK_INTERVAL', 300000), // 5 minutes default (deprecated, use sseHealthCheckInitialInterval)
|
|
67
|
+
sseHealthCheckInitialInterval: getEnvNumber('REACT_APP_SSE_HEALTH_CHECK_INITIAL_INTERVAL', 300000), // 5 minutes default
|
|
68
|
+
sseHealthCheckBackoffMultiplier: getEnvNumber('REACT_APP_SSE_HEALTH_CHECK_BACKOFF_MULTIPLIER', 2), // Double interval on each failure
|
|
69
|
+
sseHealthCheckMaxInterval: getEnvNumber('REACT_APP_SSE_HEALTH_CHECK_MAX_INTERVAL', 1800000), // 30 minutes max
|
|
70
|
+
sseHealthCheckMaxAttempts: getEnvNumber('REACT_APP_SSE_HEALTH_CHECK_MAX_ATTEMPTS', 24), // 24 attempts (~2 hours at max interval)
|
|
71
|
+
sseHealthCheckMaxTotalTime: getEnvNumber('REACT_APP_SSE_HEALTH_CHECK_MAX_TOTAL_TIME', 7200000), // 2 hours default (7200000ms = 2 * 60 * 60 * 1000)
|
|
60
72
|
};
|
|
61
73
|
}
|
|
62
74
|
else {
|
|
@@ -75,6 +87,13 @@ function getConfigForEnvironment(env) {
|
|
|
75
87
|
kioskUrl: getEnvVar('REACT_APP_KIOSK_URL', urls.kiosk),
|
|
76
88
|
adminUrl: getEnvVar('REACT_APP_ADMIN_URL', urls.admin),
|
|
77
89
|
backendUrl: getEnvVar('REACT_APP_BACKEND_URL', urls.backend),
|
|
90
|
+
// SSE Configuration
|
|
91
|
+
sseHealthCheckInterval: getEnvNumber('REACT_APP_SSE_HEALTH_CHECK_INTERVAL', 300000), // 5 minutes default (deprecated, use sseHealthCheckInitialInterval)
|
|
92
|
+
sseHealthCheckInitialInterval: getEnvNumber('REACT_APP_SSE_HEALTH_CHECK_INITIAL_INTERVAL', 300000), // 5 minutes default
|
|
93
|
+
sseHealthCheckBackoffMultiplier: getEnvNumber('REACT_APP_SSE_HEALTH_CHECK_BACKOFF_MULTIPLIER', 2), // Double interval on each failure
|
|
94
|
+
sseHealthCheckMaxInterval: getEnvNumber('REACT_APP_SSE_HEALTH_CHECK_MAX_INTERVAL', 1800000), // 30 minutes max
|
|
95
|
+
sseHealthCheckMaxAttempts: getEnvNumber('REACT_APP_SSE_HEALTH_CHECK_MAX_ATTEMPTS', 24), // 24 attempts (~2 hours at max interval)
|
|
96
|
+
sseHealthCheckMaxTotalTime: getEnvNumber('REACT_APP_SSE_HEALTH_CHECK_MAX_TOTAL_TIME', 7200000), // 2 hours default (7200000ms = 2 * 60 * 60 * 1000)
|
|
78
97
|
};
|
|
79
98
|
}
|
|
80
99
|
}
|
|
@@ -84,13 +103,6 @@ export const getCurrentEnvironment = () => {
|
|
|
84
103
|
if (typeof process !== 'undefined' && process.env) {
|
|
85
104
|
return process.env.NODE_ENV === 'production' ? 'production' : 'development';
|
|
86
105
|
}
|
|
87
|
-
// Check if we're on Railway domain (most reliable for production detection)
|
|
88
|
-
if (typeof window !== 'undefined' && window.location) {
|
|
89
|
-
if (window.location.hostname.includes('railway.app') ||
|
|
90
|
-
window.location.hostname.includes('up.railway.app')) {
|
|
91
|
-
return 'production';
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
106
|
// Check for import.meta.env (Vite environment)
|
|
95
107
|
if (typeof window !== 'undefined') {
|
|
96
108
|
try {
|
|
@@ -101,24 +113,13 @@ export const getCurrentEnvironment = () => {
|
|
|
101
113
|
}
|
|
102
114
|
}
|
|
103
115
|
catch (e) {
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
try {
|
|
110
|
-
// @ts-ignore - Vite environment
|
|
111
|
-
const meta = globalThis.import?.meta;
|
|
112
|
-
if (meta && meta.env) {
|
|
113
|
-
const apiUrl = meta.env.VITE_API_URL || meta.env.REACT_APP_API_URL;
|
|
114
|
-
if (apiUrl && apiUrl.includes('railway.app')) {
|
|
115
|
-
return 'production';
|
|
116
|
-
}
|
|
116
|
+
// Fallback: check if we're on Railway domain
|
|
117
|
+
if (window.location &&
|
|
118
|
+
(window.location.hostname.includes('railway.app') ||
|
|
119
|
+
window.location.hostname.includes('up.railway.app'))) {
|
|
120
|
+
return 'production';
|
|
117
121
|
}
|
|
118
122
|
}
|
|
119
|
-
catch (e) {
|
|
120
|
-
// Ignore errors
|
|
121
|
-
}
|
|
122
123
|
}
|
|
123
124
|
return 'development';
|
|
124
125
|
};
|
|
@@ -152,3 +153,4 @@ export const getUIConfig = () => {
|
|
|
152
153
|
logLevel: config.logLevel,
|
|
153
154
|
};
|
|
154
155
|
};
|
|
156
|
+
//# sourceMappingURL=environments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environments.js","sourceRoot":"","sources":["../../src/config/environments.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Tests for environment configuration
|
|
2
|
+
import { getCurrentEnvironment, getEnvironmentConfig, isDevelopment, isProduction } from './environments';
|
|
3
|
+
describe('Environment Configuration', () => {
|
|
4
|
+
const originalEnv = process.env.NODE_ENV;
|
|
5
|
+
afterEach(() => {
|
|
6
|
+
process.env.NODE_ENV = originalEnv;
|
|
7
|
+
});
|
|
8
|
+
describe('getCurrentEnvironment', () => {
|
|
9
|
+
test('returns development for non-production environments', () => {
|
|
10
|
+
process.env.NODE_ENV = 'development';
|
|
11
|
+
expect(getCurrentEnvironment()).toBe('development');
|
|
12
|
+
process.env.NODE_ENV = 'test';
|
|
13
|
+
expect(getCurrentEnvironment()).toBe('development');
|
|
14
|
+
delete process.env.NODE_ENV;
|
|
15
|
+
expect(getCurrentEnvironment()).toBe('development');
|
|
16
|
+
});
|
|
17
|
+
test('returns production for production environment', () => {
|
|
18
|
+
process.env.NODE_ENV = 'production';
|
|
19
|
+
expect(getCurrentEnvironment()).toBe('production');
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe('getEnvironmentConfig', () => {
|
|
23
|
+
test('returns development config by default', () => {
|
|
24
|
+
process.env.NODE_ENV = 'development';
|
|
25
|
+
const config = getEnvironmentConfig();
|
|
26
|
+
expect(config.apiUrl).toBe('http://localhost:3015');
|
|
27
|
+
expect(config.enableMockPayments).toBe(true);
|
|
28
|
+
expect(config.showDebugInfo).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
test('returns production config for production', () => {
|
|
31
|
+
process.env.NODE_ENV = 'production';
|
|
32
|
+
const config = getEnvironmentConfig();
|
|
33
|
+
expect(config.enableMockPayments).toBe(false);
|
|
34
|
+
expect(config.showDebugInfo).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
describe('environment checks', () => {
|
|
38
|
+
test('isDevelopment works correctly', () => {
|
|
39
|
+
process.env.NODE_ENV = 'development';
|
|
40
|
+
expect(isDevelopment()).toBe(true);
|
|
41
|
+
expect(isProduction()).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
test('isProduction works correctly', () => {
|
|
44
|
+
process.env.NODE_ENV = 'production';
|
|
45
|
+
expect(isDevelopment()).toBe(false);
|
|
46
|
+
expect(isProduction()).toBe(true);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
package/dist/errors.d.ts
CHANGED
|
@@ -16,18 +16,6 @@ export declare class AuthenticationError extends AppError {
|
|
|
16
16
|
export declare class NotFoundError extends AppError {
|
|
17
17
|
constructor(resource?: string);
|
|
18
18
|
}
|
|
19
|
-
export declare class PaymentError extends AppError {
|
|
20
|
-
constructor(message?: string);
|
|
21
|
-
}
|
|
22
|
-
export declare class InventoryError extends AppError {
|
|
23
|
-
constructor(message?: string);
|
|
24
|
-
}
|
|
25
|
-
export declare class KioskError extends AppError {
|
|
26
|
-
constructor(message?: string);
|
|
27
|
-
}
|
|
28
|
-
export declare class DatabaseError extends AppError {
|
|
29
|
-
constructor(message?: string);
|
|
30
|
-
}
|
|
31
19
|
export interface ErrorResponse {
|
|
32
20
|
success: false;
|
|
33
21
|
error: {
|
package/dist/errors.js
CHANGED
|
@@ -35,30 +35,6 @@ export class NotFoundError extends AppError {
|
|
|
35
35
|
this.name = 'NotFoundError';
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
export class PaymentError extends AppError {
|
|
39
|
-
constructor(message = 'Chyba při zpracování platby') {
|
|
40
|
-
super(message, 'PAYMENT_ERROR', 400);
|
|
41
|
-
this.name = 'PaymentError';
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
export class InventoryError extends AppError {
|
|
45
|
-
constructor(message = 'Chyba při správě zásob') {
|
|
46
|
-
super(message, 'INVENTORY_ERROR', 400);
|
|
47
|
-
this.name = 'InventoryError';
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
export class KioskError extends AppError {
|
|
51
|
-
constructor(message = 'Chyba konfigurace kiosku') {
|
|
52
|
-
super(message, 'KIOSK_ERROR', 400);
|
|
53
|
-
this.name = 'KioskError';
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
export class DatabaseError extends AppError {
|
|
57
|
-
constructor(message = 'Chyba databáze') {
|
|
58
|
-
super(message, 'DATABASE_ERROR', 503);
|
|
59
|
-
this.name = 'DatabaseError';
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
38
|
export const formatError = (error, details) => {
|
|
63
39
|
const isAppError = error instanceof AppError;
|
|
64
40
|
return {
|
package/dist/index.d.ts
CHANGED
|
@@ -5,4 +5,9 @@ export * from './validation';
|
|
|
5
5
|
export * from './errors';
|
|
6
6
|
export * from './utils';
|
|
7
7
|
export * from './hooks/useErrorHandler';
|
|
8
|
+
export * from './hooks/useApi';
|
|
9
|
+
export * from './hooks/useAsyncOperation';
|
|
10
|
+
export * from './components/LoadingSpinner';
|
|
11
|
+
export * from './components/ErrorDisplay';
|
|
8
12
|
export * from './config/environments';
|
|
13
|
+
export * from './config/logger';
|
package/dist/index.js
CHANGED
|
@@ -7,4 +7,9 @@ export * from './errors';
|
|
|
7
7
|
export * from './utils';
|
|
8
8
|
// Note: ./utils exports getErrorMessage which shadows the one from ./errors
|
|
9
9
|
export * from './hooks/useErrorHandler';
|
|
10
|
+
export * from './hooks/useApi';
|
|
11
|
+
export * from './hooks/useAsyncOperation';
|
|
12
|
+
export * from './components/LoadingSpinner';
|
|
13
|
+
export * from './components/ErrorDisplay';
|
|
10
14
|
export * from './config/environments';
|
|
15
|
+
export * from './config/logger';
|
package/dist/types.d.ts
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
export declare enum TransactionStatus {
|
|
2
|
-
INITIATED = "INITIATED",
|
|
3
|
-
PENDING = "PENDING",
|
|
4
|
-
PROCESSING = "PROCESSING",
|
|
5
|
-
COMPLETED = "COMPLETED",
|
|
6
|
-
FAILED = "FAILED",
|
|
7
|
-
CANCELLED = "CANCELLED",
|
|
8
|
-
TIMEOUT = "TIMEOUT"
|
|
9
|
-
}
|
|
10
|
-
export declare enum ReceiptType {
|
|
11
|
-
PLAIN = "PLAIN",
|
|
12
|
-
INVOICE = "INVOICE",
|
|
13
|
-
PROFORMA = "PROFORMA"
|
|
14
|
-
}
|
|
15
1
|
export interface Product {
|
|
16
2
|
id: number;
|
|
17
3
|
name: string;
|
|
@@ -19,69 +5,12 @@ export interface Product {
|
|
|
19
5
|
description: string;
|
|
20
6
|
image?: string;
|
|
21
7
|
imageUrl?: string;
|
|
22
|
-
clickedOn: number;
|
|
23
|
-
qrCodesGenerated: number;
|
|
24
|
-
numberOfPurchases: number;
|
|
25
|
-
createdAt: string;
|
|
26
|
-
updatedAt: string;
|
|
27
|
-
}
|
|
28
|
-
export interface KioskProduct extends Product {
|
|
29
|
-
quantityInStock: number;
|
|
30
|
-
kioskClickedOn: number;
|
|
31
|
-
kioskNumberOfPurchases: number;
|
|
32
|
-
}
|
|
33
|
-
export interface Kiosk {
|
|
34
|
-
id: number;
|
|
35
|
-
name: string;
|
|
36
|
-
location: string;
|
|
37
|
-
description?: string;
|
|
38
|
-
isActive: boolean;
|
|
39
|
-
createdAt: string;
|
|
40
|
-
updatedAt: string;
|
|
41
|
-
}
|
|
42
|
-
export interface Customer {
|
|
43
|
-
id: number;
|
|
44
|
-
email: string;
|
|
45
|
-
name?: string;
|
|
46
|
-
firstContactAt: string;
|
|
47
|
-
purchasesRequested: number;
|
|
48
|
-
purchasesCompleted: number;
|
|
49
|
-
totalSpent: number;
|
|
50
|
-
}
|
|
51
|
-
export interface KioskInventory {
|
|
52
|
-
id: number;
|
|
53
|
-
kioskId: number;
|
|
54
|
-
productId: number;
|
|
55
8
|
quantityInStock: number;
|
|
56
|
-
active: boolean;
|
|
57
9
|
clickedOn: number;
|
|
58
|
-
qrCodesGenerated: number;
|
|
59
10
|
numberOfPurchases: number;
|
|
60
|
-
lastRestocked?: string;
|
|
61
|
-
createdAt: string;
|
|
62
|
-
updatedAt: string;
|
|
63
|
-
}
|
|
64
|
-
export interface Transaction {
|
|
65
|
-
id: number;
|
|
66
|
-
kioskId: number;
|
|
67
|
-
customerId: number;
|
|
68
|
-
productId?: number;
|
|
69
|
-
requestedAt: string;
|
|
70
|
-
completedAt?: string;
|
|
71
|
-
status: TransactionStatus;
|
|
72
|
-
amount: number;
|
|
73
|
-
paymentId?: string;
|
|
74
|
-
qrCodeData?: string;
|
|
75
|
-
variableSymbol?: string;
|
|
76
|
-
receiptType: ReceiptType;
|
|
77
|
-
fioTransactionId?: string;
|
|
78
|
-
lastFioCheckAt?: string;
|
|
79
|
-
fioCheckCount: number;
|
|
80
|
-
createdAt: string;
|
|
81
|
-
updatedAt: string;
|
|
82
11
|
}
|
|
83
12
|
export interface CartItem {
|
|
84
|
-
product:
|
|
13
|
+
product: Product;
|
|
85
14
|
quantity: number;
|
|
86
15
|
}
|
|
87
16
|
export interface Cart {
|
|
@@ -96,7 +25,6 @@ export interface PaymentData {
|
|
|
96
25
|
customerEmail: string;
|
|
97
26
|
qrCode: string;
|
|
98
27
|
paymentId: string;
|
|
99
|
-
status?: TransactionStatus;
|
|
100
28
|
}
|
|
101
29
|
export interface MultiProductPaymentData {
|
|
102
30
|
items: CartItem[];
|
|
@@ -104,9 +32,19 @@ export interface MultiProductPaymentData {
|
|
|
104
32
|
customerEmail: string;
|
|
105
33
|
qrCode: string;
|
|
106
34
|
paymentId: string;
|
|
107
|
-
status?: TransactionStatus;
|
|
108
35
|
}
|
|
109
|
-
export interface AdminProduct
|
|
36
|
+
export interface AdminProduct {
|
|
37
|
+
id: number;
|
|
38
|
+
name: string;
|
|
39
|
+
price: number;
|
|
40
|
+
description: string;
|
|
41
|
+
image: string;
|
|
42
|
+
imageUrl?: string;
|
|
43
|
+
clickedOn: number;
|
|
44
|
+
qrCodesGenerated: number;
|
|
45
|
+
numberOfPurchases: number;
|
|
46
|
+
createdAt: string;
|
|
47
|
+
updatedAt: string;
|
|
110
48
|
quantityInStock?: number;
|
|
111
49
|
active?: boolean;
|
|
112
50
|
}
|
|
@@ -124,93 +62,11 @@ export interface KioskStatus {
|
|
|
124
62
|
lastSeen: Date;
|
|
125
63
|
salesToday: number;
|
|
126
64
|
}
|
|
127
|
-
export
|
|
65
|
+
export interface WebSocketMessage {
|
|
128
66
|
type: string;
|
|
67
|
+
updateType?: string;
|
|
68
|
+
data?: any;
|
|
129
69
|
kioskId?: number;
|
|
130
70
|
timestamp?: string;
|
|
131
|
-
[key: string]: any;
|
|
132
|
-
};
|
|
133
|
-
export type ScreenType = 'products' | 'payment' | 'confirmation' | 'admin-login' | 'admin-dashboard';
|
|
134
|
-
export interface CreateQRPaymentRequest {
|
|
135
|
-
productId: number;
|
|
136
|
-
customerEmail: string;
|
|
137
|
-
kioskId: number;
|
|
138
|
-
}
|
|
139
|
-
export interface CreateQRPaymentResponse {
|
|
140
|
-
paymentId: string;
|
|
141
|
-
qrCodeData: string;
|
|
142
|
-
amount: number;
|
|
143
|
-
customerEmail: string;
|
|
144
|
-
variableSymbol: string;
|
|
145
|
-
}
|
|
146
|
-
export interface CreateMultiQRPaymentRequest {
|
|
147
|
-
items: Array<{
|
|
148
|
-
productId: number;
|
|
149
|
-
quantity: number;
|
|
150
|
-
}>;
|
|
151
|
-
totalAmount: number;
|
|
152
|
-
customerEmail: string;
|
|
153
|
-
kioskId: number;
|
|
154
|
-
}
|
|
155
|
-
export interface CreateMultiQRPaymentResponse {
|
|
156
|
-
paymentId: string;
|
|
157
|
-
qrCodeData: string;
|
|
158
|
-
amount: number;
|
|
159
|
-
customerEmail: string;
|
|
160
|
-
variableSymbol: string;
|
|
161
|
-
}
|
|
162
|
-
export interface PaymentStatusResponse {
|
|
163
|
-
paymentId: string;
|
|
164
|
-
status: TransactionStatus;
|
|
165
|
-
amount: number;
|
|
166
|
-
customerEmail: string;
|
|
167
|
-
requestedAt: string;
|
|
168
|
-
completedAt?: string;
|
|
169
|
-
}
|
|
170
|
-
export interface StartMonitoringRequest {
|
|
171
|
-
paymentId: string;
|
|
172
|
-
}
|
|
173
|
-
export interface StartMonitoringResponse {
|
|
174
|
-
paymentId: string;
|
|
175
|
-
status: string;
|
|
176
|
-
monitoringStartTime?: number;
|
|
177
|
-
}
|
|
178
|
-
export interface ThePayCreateRequest {
|
|
179
|
-
items: Array<{
|
|
180
|
-
productId: number;
|
|
181
|
-
quantity: number;
|
|
182
|
-
price: number;
|
|
183
|
-
}>;
|
|
184
|
-
totalAmount: number;
|
|
185
|
-
customerEmail: string;
|
|
186
|
-
kioskId: number;
|
|
187
|
-
}
|
|
188
|
-
export interface ThePayCreateResponse {
|
|
189
|
-
paymentId: string;
|
|
190
|
-
thepayPaymentId: string;
|
|
191
|
-
paymentUrl: string;
|
|
192
|
-
amount: number;
|
|
193
|
-
customerEmail: string;
|
|
194
|
-
kioskId: number;
|
|
195
|
-
}
|
|
196
|
-
export interface ThePayStatusResponse {
|
|
197
|
-
paymentId: string;
|
|
198
|
-
status: string;
|
|
199
|
-
amount: number;
|
|
200
|
-
customerEmail: string;
|
|
201
|
-
}
|
|
202
|
-
export interface ThePayMethodsResponse {
|
|
203
|
-
methods: Array<{
|
|
204
|
-
name: string;
|
|
205
|
-
enabled: boolean;
|
|
206
|
-
}>;
|
|
207
|
-
}
|
|
208
|
-
export interface InventoryUpdateRequest {
|
|
209
|
-
quantityInStock: number;
|
|
210
|
-
}
|
|
211
|
-
export interface VisibilityToggleRequest {
|
|
212
|
-
visible: boolean;
|
|
213
|
-
}
|
|
214
|
-
export interface ProductClickRequest {
|
|
215
|
-
kioskId: number;
|
|
216
71
|
}
|
|
72
|
+
export type ScreenType = 'products' | 'payment' | 'confirmation' | 'admin-login' | 'admin-dashboard';
|
package/dist/types.js
CHANGED
|
@@ -1,18 +1,2 @@
|
|
|
1
1
|
// Shared types across all packages
|
|
2
|
-
|
|
3
|
-
export var TransactionStatus;
|
|
4
|
-
(function (TransactionStatus) {
|
|
5
|
-
TransactionStatus["INITIATED"] = "INITIATED";
|
|
6
|
-
TransactionStatus["PENDING"] = "PENDING";
|
|
7
|
-
TransactionStatus["PROCESSING"] = "PROCESSING";
|
|
8
|
-
TransactionStatus["COMPLETED"] = "COMPLETED";
|
|
9
|
-
TransactionStatus["FAILED"] = "FAILED";
|
|
10
|
-
TransactionStatus["CANCELLED"] = "CANCELLED";
|
|
11
|
-
TransactionStatus["TIMEOUT"] = "TIMEOUT";
|
|
12
|
-
})(TransactionStatus || (TransactionStatus = {}));
|
|
13
|
-
export var ReceiptType;
|
|
14
|
-
(function (ReceiptType) {
|
|
15
|
-
ReceiptType["PLAIN"] = "PLAIN";
|
|
16
|
-
ReceiptType["INVOICE"] = "INVOICE";
|
|
17
|
-
ReceiptType["PROFORMA"] = "PROFORMA";
|
|
18
|
-
})(ReceiptType || (ReceiptType = {}));
|
|
2
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Tests for shared utilities
|
|
2
|
+
import { validateEmail, formatPrice, generatePaymentId, getErrorMessage } from '../utils';
|
|
3
|
+
describe('Shared Utilities', () => {
|
|
4
|
+
describe('validateEmail', () => {
|
|
5
|
+
test('validates correct email addresses', () => {
|
|
6
|
+
expect(validateEmail('test@example.com')).toBe(true);
|
|
7
|
+
expect(validateEmail('user.name+tag@domain.co.uk')).toBe(true);
|
|
8
|
+
});
|
|
9
|
+
test('rejects invalid email addresses', () => {
|
|
10
|
+
expect(validateEmail('')).toBe(false);
|
|
11
|
+
expect(validateEmail('invalid')).toBe(false);
|
|
12
|
+
expect(validateEmail('test@')).toBe(false);
|
|
13
|
+
expect(validateEmail('@domain.com')).toBe(false);
|
|
14
|
+
expect(validateEmail('test..test@domain.com')).toBe(false);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
describe('formatPrice', () => {
|
|
18
|
+
test('formats prices correctly', () => {
|
|
19
|
+
expect(formatPrice(100)).toBe('100 Kč');
|
|
20
|
+
expect(formatPrice(25.5)).toBe('25.5 Kč');
|
|
21
|
+
expect(formatPrice(0)).toBe('0 Kč');
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
describe('generatePaymentId', () => {
|
|
25
|
+
test('generates unique payment IDs', () => {
|
|
26
|
+
const id1 = generatePaymentId();
|
|
27
|
+
const id2 = generatePaymentId();
|
|
28
|
+
expect(id1).toMatch(/^pay-\d+$/);
|
|
29
|
+
expect(id2).toMatch(/^pay-\d+$/);
|
|
30
|
+
expect(id1).not.toBe(id2);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe('getErrorMessage', () => {
|
|
34
|
+
test('returns user-friendly error messages', () => {
|
|
35
|
+
const fetchError = new Error('Failed to fetch');
|
|
36
|
+
expect(getErrorMessage(fetchError)).toBe('Problém s připojením. Zkuste to znovu.');
|
|
37
|
+
const authError = new Error('401 Unauthorized');
|
|
38
|
+
expect(getErrorMessage(authError)).toBe('Neplatné přihlašovací údaje.');
|
|
39
|
+
const genericError = new Error('Something went wrong');
|
|
40
|
+
expect(getErrorMessage(genericError)).toBe('Something went wrong');
|
|
41
|
+
const emptyError = new Error('');
|
|
42
|
+
expect(getErrorMessage(emptyError)).toBe('Něco se pokazilo. Zkuste to znovu.');
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
});
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
export declare const validateEmail: (email: string) => boolean;
|
|
2
2
|
export declare const formatPrice: (price: number) => string;
|
|
3
|
-
export declare const PRICE_PRECISION = 2;
|
|
4
|
-
export declare const roundPrice: (price: number) => number;
|
|
5
|
-
export declare const parsePrice: (value: string | number) => number;
|
|
6
|
-
export declare const validatePrice: (price: number) => boolean;
|
|
7
|
-
export declare const priceToString: (price: number) => string;
|
|
8
|
-
export declare const stringToPrice: (priceStr: string) => number;
|
|
9
3
|
export declare const getKioskIdFromUrl: () => number;
|
|
10
4
|
export declare const getKioskSecretFromUrl: () => string | undefined;
|
|
11
5
|
export declare const formatDate: (date: Date | string) => string;
|
package/dist/utils.js
CHANGED
|
@@ -7,32 +7,7 @@ export const validateEmail = (email) => {
|
|
|
7
7
|
return emailRegex.test(email);
|
|
8
8
|
};
|
|
9
9
|
export const formatPrice = (price) => {
|
|
10
|
-
return
|
|
11
|
-
style: 'currency',
|
|
12
|
-
currency: 'CZK',
|
|
13
|
-
minimumFractionDigits: 2,
|
|
14
|
-
maximumFractionDigits: 2
|
|
15
|
-
}).format(price);
|
|
16
|
-
};
|
|
17
|
-
// Price precision handling utilities
|
|
18
|
-
export const PRICE_PRECISION = 2; // 2 decimal places for CZK
|
|
19
|
-
export const roundPrice = (price) => {
|
|
20
|
-
return Math.round(price * 100) / 100;
|
|
21
|
-
};
|
|
22
|
-
export const parsePrice = (value) => {
|
|
23
|
-
const num = typeof value === 'string' ? parseFloat(value) : value;
|
|
24
|
-
return roundPrice(num);
|
|
25
|
-
};
|
|
26
|
-
export const validatePrice = (price) => {
|
|
27
|
-
return !isNaN(price) && price > 0 && price <= 999999.99;
|
|
28
|
-
};
|
|
29
|
-
// Convert decimal to string for API calls to avoid precision issues
|
|
30
|
-
export const priceToString = (price) => {
|
|
31
|
-
return price.toFixed(PRICE_PRECISION);
|
|
32
|
-
};
|
|
33
|
-
// Convert string back to number for calculations
|
|
34
|
-
export const stringToPrice = (priceStr) => {
|
|
35
|
-
return parseFloat(priceStr);
|
|
10
|
+
return `${price} Kč`;
|
|
36
11
|
};
|
|
37
12
|
export const getKioskIdFromUrl = () => {
|
|
38
13
|
const urlParams = new URLSearchParams(window.location.search);
|
|
@@ -87,13 +62,13 @@ export const addToCart = (cart, product, quantity = 1) => {
|
|
|
87
62
|
else {
|
|
88
63
|
cart.items.push({ product, quantity });
|
|
89
64
|
}
|
|
90
|
-
cart.totalAmount =
|
|
65
|
+
cart.totalAmount = cart.items.reduce((sum, item) => sum + (item.product.price * item.quantity), 0);
|
|
91
66
|
cart.totalItems = cart.items.reduce((sum, item) => sum + item.quantity, 0);
|
|
92
67
|
return cart;
|
|
93
68
|
};
|
|
94
69
|
export const removeFromCart = (cart, productId) => {
|
|
95
70
|
cart.items = cart.items.filter((item) => item.product.id !== productId);
|
|
96
|
-
cart.totalAmount =
|
|
71
|
+
cart.totalAmount = cart.items.reduce((sum, item) => sum + (item.product.price * item.quantity), 0);
|
|
97
72
|
cart.totalItems = cart.items.reduce((sum, item) => sum + item.quantity, 0);
|
|
98
73
|
return cart;
|
|
99
74
|
};
|
|
@@ -104,7 +79,7 @@ export const updateCartItemQuantity = (cart, productId, quantity) => {
|
|
|
104
79
|
return removeFromCart(cart, productId);
|
|
105
80
|
}
|
|
106
81
|
item.quantity = quantity;
|
|
107
|
-
cart.totalAmount =
|
|
82
|
+
cart.totalAmount = cart.items.reduce((sum, item) => sum + (item.product.price * item.quantity), 0);
|
|
108
83
|
cart.totalItems = cart.items.reduce((sum, item) => sum + item.quantity, 0);
|
|
109
84
|
}
|
|
110
85
|
return cart;
|
package/dist/validation.d.ts
CHANGED
|
@@ -10,9 +10,6 @@ export declare const validators: {
|
|
|
10
10
|
positiveNumber: (value: number, fieldName: string) => string | null;
|
|
11
11
|
username: (value: string) => string | null;
|
|
12
12
|
password: (value: string) => string | null;
|
|
13
|
-
kioskId: (value: number) => string | null;
|
|
14
|
-
quantity: (value: number, fieldName?: string) => string | null;
|
|
15
|
-
price: (value: number, fieldName?: string) => string | null;
|
|
16
13
|
};
|
|
17
14
|
export interface ValidationSchema {
|
|
18
15
|
[field: string]: Array<(value: any) => string | null>;
|
|
@@ -28,18 +25,7 @@ export declare const validationSchemas: {
|
|
|
28
25
|
};
|
|
29
26
|
product: {
|
|
30
27
|
name: ((value: any) => string | null)[];
|
|
31
|
-
price: ((value:
|
|
28
|
+
price: ((value: any) => string | null)[];
|
|
32
29
|
description: ((value: any) => string | null)[];
|
|
33
30
|
};
|
|
34
|
-
kioskId: {
|
|
35
|
-
kioskId: ((value: number) => string | null)[];
|
|
36
|
-
};
|
|
37
|
-
inventory: {
|
|
38
|
-
quantityInStock: ((value: number, fieldName?: string) => string | null)[];
|
|
39
|
-
};
|
|
40
|
-
payment: {
|
|
41
|
-
productId: ((value: any) => string | null)[];
|
|
42
|
-
kioskId: ((value: number) => string | null)[];
|
|
43
|
-
amount: ((value: number, fieldName?: string) => string | null)[];
|
|
44
|
-
};
|
|
45
31
|
};
|
package/dist/validation.js
CHANGED
|
@@ -59,39 +59,6 @@ export const validators = {
|
|
|
59
59
|
return `Heslo musí mít alespoň ${APP_CONFIG.MIN_PASSWORD_LENGTH} znaků`;
|
|
60
60
|
}
|
|
61
61
|
return null;
|
|
62
|
-
},
|
|
63
|
-
kioskId: (value) => {
|
|
64
|
-
if (value === null || value === undefined)
|
|
65
|
-
return null;
|
|
66
|
-
if (!Number.isInteger(value) || value <= 0) {
|
|
67
|
-
return 'Kiosk ID musí být kladné celé číslo';
|
|
68
|
-
}
|
|
69
|
-
return null;
|
|
70
|
-
},
|
|
71
|
-
quantity: (value, fieldName = 'Množství') => {
|
|
72
|
-
if (value === null || value === undefined)
|
|
73
|
-
return null;
|
|
74
|
-
if (!Number.isInteger(value) || value < 0) {
|
|
75
|
-
return `${fieldName} musí být nezáporné celé číslo`;
|
|
76
|
-
}
|
|
77
|
-
return null;
|
|
78
|
-
},
|
|
79
|
-
price: (value, fieldName = 'Cena') => {
|
|
80
|
-
if (value === null || value === undefined)
|
|
81
|
-
return null;
|
|
82
|
-
if (isNaN(value) || value <= 0) {
|
|
83
|
-
return `${fieldName} musí být kladné číslo`;
|
|
84
|
-
}
|
|
85
|
-
// Check for reasonable price range (0.01 to 999999.99)
|
|
86
|
-
if (value < 0.01 || value > 999999.99) {
|
|
87
|
-
return `${fieldName} musí být v rozsahu 0,01 - 999 999,99 Kč`;
|
|
88
|
-
}
|
|
89
|
-
// Check for precision (max 2 decimal places)
|
|
90
|
-
const rounded = Math.round(value * 100) / 100;
|
|
91
|
-
if (Math.abs(value - rounded) > 0.001) {
|
|
92
|
-
return `${fieldName} může mít maximálně 2 desetinná místa`;
|
|
93
|
-
}
|
|
94
|
-
return null;
|
|
95
62
|
}
|
|
96
63
|
};
|
|
97
64
|
export const validateSchema = (data, schema) => {
|
|
@@ -137,36 +104,10 @@ export const validationSchemas = {
|
|
|
137
104
|
],
|
|
138
105
|
price: [
|
|
139
106
|
(value) => validators.required(value),
|
|
140
|
-
validators.
|
|
107
|
+
(value) => validators.positiveNumber(value, 'Cena')
|
|
141
108
|
],
|
|
142
109
|
description: [
|
|
143
110
|
(value) => validators.maxLength(value, APP_CONFIG.MAX_DESCRIPTION_LENGTH, 'Popis')
|
|
144
111
|
]
|
|
145
|
-
},
|
|
146
|
-
kioskId: {
|
|
147
|
-
kioskId: [
|
|
148
|
-
(value) => validators.required(value),
|
|
149
|
-
validators.kioskId
|
|
150
|
-
]
|
|
151
|
-
},
|
|
152
|
-
inventory: {
|
|
153
|
-
quantityInStock: [
|
|
154
|
-
(value) => validators.required(value),
|
|
155
|
-
validators.quantity
|
|
156
|
-
]
|
|
157
|
-
},
|
|
158
|
-
payment: {
|
|
159
|
-
productId: [
|
|
160
|
-
(value) => validators.required(value),
|
|
161
|
-
(value) => validators.positiveNumber(value, 'ID produktu')
|
|
162
|
-
],
|
|
163
|
-
kioskId: [
|
|
164
|
-
(value) => validators.required(value),
|
|
165
|
-
validators.kioskId
|
|
166
|
-
],
|
|
167
|
-
amount: [
|
|
168
|
-
(value) => validators.required(value),
|
|
169
|
-
validators.price
|
|
170
|
-
]
|
|
171
112
|
}
|
|
172
113
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-kiosk-shared",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Shared components and utilities for Pi Kiosk system",
|
|
6
6
|
"keywords": [
|
|
@@ -31,9 +31,6 @@
|
|
|
31
31
|
"test": "jest",
|
|
32
32
|
"test:watch": "jest --watch",
|
|
33
33
|
"test:coverage": "jest --coverage",
|
|
34
|
-
"test:unit": "jest --testPathPattern=src/__tests__/unit",
|
|
35
|
-
"test:fast": "jest --testPathPattern=src/__tests__/unit --watch",
|
|
36
|
-
"test:debug": "jest --testPathPattern=src/__tests__/unit --verbose",
|
|
37
34
|
"clean": "rimraf dist",
|
|
38
35
|
"publish:local": "npm run build && npm pack --pack-destination ../",
|
|
39
36
|
"prepublishOnly": "npm run build",
|