@umituz/react-native-design-system 4.23.79 → 4.23.81

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.
Files changed (88) hide show
  1. package/package.json +10 -8
  2. package/src/atoms/AtomicInput.tsx +11 -48
  3. package/src/atoms/AtomicPicker.tsx +19 -94
  4. package/src/atoms/EmptyState.tsx +1 -1
  5. package/src/atoms/icon/AtomicIcon.tsx +0 -1
  6. package/src/atoms/icon/iconStore.ts +0 -2
  7. package/src/atoms/picker/components/PickerModal.tsx +40 -121
  8. package/src/device/infrastructure/services/PersistentDeviceIdService.ts +0 -4
  9. package/src/device/presentation/hooks/useDeviceInfo.ts +55 -149
  10. package/src/haptics/infrastructure/services/HapticService.ts +0 -1
  11. package/src/image/index.ts +2 -1
  12. package/src/image/presentation/hooks/useImageBatch.ts +2 -1
  13. package/src/index.ts +2 -2
  14. package/src/infinite-scroll/presentation/components/infinite-scroll-list.tsx +1 -1
  15. package/src/infinite-scroll/presentation/hooks/pagination.helper.ts +0 -5
  16. package/src/infinite-scroll/presentation/hooks/useInfiniteScroll.ts +4 -54
  17. package/src/init/createAppInitializer.ts +0 -1
  18. package/src/init/env/createEnvConfig.ts +0 -1
  19. package/src/init/useAppInitialization.ts +0 -1
  20. package/src/layouts/ScreenHeader/ScreenHeader.tsx +1 -1
  21. package/src/media/infrastructure/services/CardMediaOptimizerService.ts +0 -1
  22. package/src/media/infrastructure/services/CardMediaUploadService.ts +0 -1
  23. package/src/media/presentation/hooks/useCardMediaGeneration.ts +1 -1
  24. package/src/media/presentation/hooks/useCardMediaUpload.ts +1 -1
  25. package/src/media/presentation/hooks/useCardMediaValidation.ts +1 -1
  26. package/src/media/presentation/hooks/useCardMultimediaFlashcard.ts +1 -1
  27. package/src/media/presentation/hooks/useMedia.ts +0 -1
  28. package/src/media/presentation/hooks/useMediaGeneration.ts +1 -1
  29. package/src/media/presentation/hooks/useMediaUpload.ts +1 -1
  30. package/src/media/presentation/hooks/useMediaValidation.ts +1 -1
  31. package/src/media/presentation/hooks/useMultimediaFlashcard.ts +1 -1
  32. package/src/molecules/BaseModal.tsx +1 -3
  33. package/src/molecules/ConfirmationModalContent.tsx +1 -1
  34. package/src/molecules/ConfirmationModalMain.tsx +1 -1
  35. package/src/molecules/bottom-sheet/components/BottomSheetModal.tsx +0 -3
  36. package/src/molecules/bottom-sheet/components/filter/FilterBottomSheet.tsx +100 -179
  37. package/src/molecules/calendar/infrastructure/stores/useCalendarEvents.ts +0 -1
  38. package/src/molecules/confirmation-modal/useConfirmationModal.ts +1 -1
  39. package/src/molecules/countdown/components/Countdown.tsx +1 -1
  40. package/src/molecules/navigation/StackNavigator.tsx +0 -1
  41. package/src/molecules/navigation/TabsNavigator.tsx +0 -1
  42. package/src/molecules/navigation/utils/AppNavigation.ts +0 -8
  43. package/src/molecules/splash/components/SplashScreen.tsx +0 -4
  44. package/src/offline/infrastructure/events/NetworkEvents.ts +0 -1
  45. package/src/offline/infrastructure/utils/healthCheck.ts +0 -5
  46. package/src/offline/presentation/hooks/useOffline.ts +0 -1
  47. package/src/offline/presentation/hooks/useOfflineWithMutations.ts +0 -2
  48. package/src/onboarding/index.ts +0 -1
  49. package/src/onboarding/infrastructure/hooks/useOnboardingNavigation.ts +0 -1
  50. package/src/onboarding/infrastructure/storage/actions/storageHelpers.ts +0 -2
  51. package/src/onboarding/presentation/hooks/useOnboardingScreenHandlers.ts +0 -2
  52. package/src/onboarding/presentation/hooks/useOnboardingScreenState.ts +0 -1
  53. package/src/onboarding/presentation/screens/OnboardingScreen.tsx +0 -3
  54. package/src/organisms/FormContainer.tsx +1 -1
  55. package/src/services/api/ApiClient.ts +42 -135
  56. package/src/storage/cache/domain/Cache.ts +0 -2
  57. package/src/storage/cache/infrastructure/TTLCache.ts +0 -3
  58. package/src/storage/domain/utils/devUtils.ts +0 -3
  59. package/src/storage/infrastructure/adapters/StorageService.ts +0 -3
  60. package/src/storage/infrastructure/repositories/BaseStorageOperations.ts +0 -1
  61. package/src/tanstack/domain/config/QueryClientAccessor.ts +0 -1
  62. package/src/tanstack/domain/repositories/BaseRepository.ts +4 -4
  63. package/src/tanstack/domain/repositories/IBaseRepository.ts +3 -5
  64. package/src/tanstack/domain/repositories/RepositoryFactory.ts +0 -2
  65. package/src/tanstack/domain/repositories/mixins/repositoryInvalidationMethods.ts +10 -11
  66. package/src/tanstack/domain/repositories/mixins/repositoryQueryMethods.ts +11 -11
  67. package/src/tanstack/domain/utils/ErrorHelpers.ts +0 -1
  68. package/src/tanstack/infrastructure/config/PersisterConfig.ts +0 -7
  69. package/src/tanstack/infrastructure/config/QueryClientConfig.ts +0 -1
  70. package/src/tanstack/infrastructure/monitoring/DevMonitorLogger.ts +0 -6
  71. package/src/tanstack/presentation/hooks/useInvalidateQueries.ts +0 -4
  72. package/src/tanstack/presentation/hooks/useOptimisticUpdate.ts +0 -2
  73. package/src/tanstack/presentation/hooks/usePrefetch.ts +18 -119
  74. package/src/theme/core/CustomColors.ts +4 -122
  75. package/src/theme/infrastructure/storage/ThemeStorage.ts +0 -1
  76. package/src/typography/presentation/utils/textColorUtils.ts +36 -163
  77. package/src/exception/domain/entities/ExceptionEntity.ts +0 -115
  78. package/src/exception/domain/repositories/IExceptionRepository.ts +0 -37
  79. package/src/exception/index.ts +0 -66
  80. package/src/exception/infrastructure/services/ExceptionHandler.ts +0 -93
  81. package/src/exception/infrastructure/services/ExceptionLogger.ts +0 -142
  82. package/src/exception/infrastructure/services/ExceptionReporter.ts +0 -134
  83. package/src/exception/infrastructure/services/ExceptionService.ts +0 -166
  84. package/src/exception/infrastructure/storage/ExceptionStore.ts +0 -44
  85. package/src/exception/presentation/components/ErrorBoundary.tsx +0 -129
  86. package/src/exception/presentation/components/ExceptionEmptyState.tsx +0 -123
  87. package/src/exception/presentation/components/ExceptionErrorState.tsx +0 -122
  88. package/src/tanstack/presentation/hooks/utils/prefetchLogger.ts +0 -27
@@ -1,134 +0,0 @@
1
- /**
2
- * Exception Reporter Service
3
- *
4
- * Handles reporting exceptions to external services.
5
- *
6
- * SOLID: Single Responsibility - Only exception reporting
7
- * DRY: Centralized reporting logic
8
- * KISS: Simple reporting interface
9
- */
10
-
11
- import type { ExceptionEntity } from '../../domain/entities/ExceptionEntity';
12
-
13
- export interface ExceptionReporterConfig {
14
- enabled: boolean;
15
- endpoint?: string;
16
- apiKey?: string;
17
- environment: 'development' | 'staging' | 'production';
18
- }
19
-
20
- export class ExceptionReporter {
21
- private config: ExceptionReporterConfig;
22
-
23
- constructor(config: ExceptionReporterConfig) {
24
- this.config = config;
25
- }
26
-
27
- /**
28
- * Report exception to external service
29
- */
30
- async reportException(exception: ExceptionEntity): Promise<boolean> {
31
- if (!this.config.enabled) {
32
- return false;
33
- }
34
-
35
- try {
36
- // Default console reporting for development
37
- if (this.config.environment === 'development') {
38
- return this.reportToConsole(exception);
39
- }
40
-
41
- // External service reporting
42
- if (this.config.endpoint) {
43
- return await this.reportToExternalService(exception);
44
- }
45
-
46
- return false;
47
- } catch (error) {
48
- // Don't throw in reporter to avoid infinite loops
49
- console.warn('Exception reporting failed:', error);
50
- return false;
51
- }
52
- }
53
-
54
- /**
55
- * Report to console (development)
56
- */
57
- private reportToConsole(exception: ExceptionEntity): boolean {
58
- const level = this.getConsoleLevel(exception.severity);
59
-
60
- console[level](
61
- `[${exception.severity.toUpperCase()}] ${exception.category}:`,
62
- exception.message,
63
- {
64
- id: exception.id,
65
- timestamp: exception.timestamp,
66
- context: exception.context,
67
- stack: exception.stackTrace,
68
- }
69
- );
70
-
71
- return true;
72
- }
73
-
74
- /**
75
- * Report to external service
76
- */
77
- private async reportToExternalService(exception: ExceptionEntity): Promise<boolean> {
78
- if (!this.config.endpoint) {
79
- return false;
80
- }
81
-
82
- const response = await fetch(this.config.endpoint, {
83
- method: 'POST',
84
- headers: {
85
- 'Content-Type': 'application/json',
86
- ...(this.config.apiKey && { 'Authorization': `Bearer ${this.config.apiKey}` }),
87
- },
88
- body: JSON.stringify({
89
- id: exception.id,
90
- message: exception.message,
91
- severity: exception.severity,
92
- category: exception.category,
93
- timestamp: exception.timestamp,
94
- context: exception.context,
95
- stackTrace: exception.stackTrace,
96
- environment: this.config.environment,
97
- }),
98
- });
99
-
100
- return response.ok;
101
- }
102
-
103
- /**
104
- * Get console level for severity
105
- */
106
- private getConsoleLevel(severity: ExceptionEntity['severity']): 'log' | 'warn' | 'error' {
107
- switch (severity) {
108
- case 'fatal':
109
- case 'error':
110
- return 'error';
111
- case 'warning':
112
- return 'warn';
113
- default:
114
- return 'log';
115
- }
116
- }
117
-
118
- /**
119
- * Update reporter configuration
120
- */
121
- updateConfig(config: Partial<ExceptionReporterConfig>): void {
122
- this.config = { ...this.config, ...config };
123
- }
124
- }
125
-
126
-
127
-
128
-
129
-
130
-
131
-
132
-
133
-
134
-
@@ -1,166 +0,0 @@
1
- /**
2
- * Exception Service - Infrastructure Layer
3
- *
4
- * Facade for exception handling using composition.
5
- * Delegates to specialized services for specific operations.
6
- *
7
- * SOLID: Facade pattern - Single entry point, delegates to specialists
8
- * DRY: Avoids code duplication by composing smaller services
9
- * KISS: Simple interface, complex operations delegated
10
- */
11
-
12
- import type {
13
- ExceptionEntity,
14
- ExceptionContext,
15
- ExceptionSeverity,
16
- ExceptionCategory,
17
- } from '../../domain/entities/ExceptionEntity';
18
- import { ExceptionHandler } from './ExceptionHandler';
19
- import { ExceptionReporter } from './ExceptionReporter';
20
- import { ExceptionLogger } from './ExceptionLogger';
21
- import { useExceptionStore } from '../storage/ExceptionStore';
22
-
23
- export class ExceptionService {
24
- private logger: ExceptionLogger | null = null;
25
- private reporter: ExceptionReporter | null = null;
26
- private reporterConfig: ExceptionReporter['config'];
27
-
28
- constructor(reporterConfig?: ExceptionReporter['config']) {
29
- this.reporterConfig = reporterConfig || {
30
- enabled: false,
31
- environment: 'development'
32
- };
33
- }
34
-
35
- private ensureInitialized() {
36
- if (!this.logger) {
37
- this.logger = new ExceptionLogger();
38
- this.reporter = new ExceptionReporter(this.reporterConfig);
39
- }
40
- }
41
-
42
- /**
43
- * Handle an exception
44
- */
45
- async handleException(
46
- error: Error,
47
- severity: ExceptionSeverity = 'error',
48
- category: ExceptionCategory = 'unknown',
49
- context: ExceptionContext = {},
50
- ): Promise<void> {
51
- this.ensureInitialized();
52
-
53
- const exception = ExceptionHandler.createException(error, severity, category, context);
54
-
55
- // Add to store
56
- useExceptionStore.getState().addException(exception);
57
-
58
- // Log locally
59
- await this.logger!.logException(exception);
60
-
61
- // Report to external service if needed
62
- if (ExceptionHandler.shouldReportException(exception)) {
63
- await this.reporter!.reportException(exception);
64
- }
65
-
66
- // Mark as handled
67
- useExceptionStore.getState().markAsHandled(exception.id);
68
- }
69
-
70
- /**
71
- * Handle network errors
72
- */
73
- async handleNetworkError(error: Error, context: ExceptionContext = {}): Promise<void> {
74
- await this.handleException(error, 'error', 'network', context);
75
- }
76
-
77
- /**
78
- * Handle validation errors
79
- */
80
- async handleValidationError(error: Error, context: ExceptionContext = {}): Promise<void> {
81
- await this.handleException(error, 'warning', 'validation', context);
82
- }
83
-
84
- /**
85
- * Handle authentication errors
86
- */
87
- async handleAuthError(error: Error, context: ExceptionContext = {}): Promise<void> {
88
- await this.handleException(error, 'error', 'authentication', context);
89
- }
90
-
91
- /**
92
- * Handle system errors
93
- */
94
- async handleSystemError(error: Error, context: ExceptionContext = {}): Promise<void> {
95
- await this.handleException(error, 'fatal', 'system', context);
96
- }
97
-
98
- /**
99
- * Get stored exceptions
100
- */
101
- async getStoredExceptions(): Promise<ExceptionEntity[]> {
102
- this.ensureInitialized();
103
- return this.logger!.getStoredExceptions();
104
- }
105
-
106
- /**
107
- * Get exception statistics
108
- */
109
- async getExceptionStats() {
110
- this.ensureInitialized();
111
- return this.logger!.getExceptionStats();
112
- }
113
-
114
- /**
115
- * Clear stored exceptions
116
- */
117
- async clearStoredExceptions(): Promise<void> {
118
- this.ensureInitialized();
119
- await this.logger!.clearStoredExceptions();
120
- }
121
-
122
- /**
123
- * Update reporter configuration
124
- */
125
- updateReporterConfig(config: Partial<ExceptionReporter['config']>): void {
126
- this.ensureInitialized();
127
- this.reporter!.updateConfig(config);
128
- }
129
-
130
- /**
131
- * Set max stored exceptions
132
- */
133
- setMaxStoredExceptions(limit: number): void {
134
- this.ensureInitialized();
135
- this.logger!.setMaxStoredExceptions(limit);
136
- }
137
-
138
- /**
139
- * Handle storage/permission errors
140
- */
141
- async handleStorageError(error: Error, context: ExceptionContext = {}): Promise<void> {
142
- await this.handleException(error, 'error', 'storage', context);
143
- }
144
-
145
- /**
146
- * Handle fatal errors
147
- */
148
- async handleFatalError(error: Error, context: ExceptionContext = {}): Promise<void> {
149
- await this.handleException(error, 'fatal', 'system', context);
150
- }
151
-
152
- /**
153
- * Clear all exceptions
154
- */
155
- clearExceptions(): void {
156
- useExceptionStore.getState().clearExceptions();
157
- }
158
- }
159
-
160
- // Export default instance - lazy initialization
161
- export const exceptionService = new ExceptionService();
162
-
163
-
164
-
165
-
166
-
@@ -1,44 +0,0 @@
1
- /**
2
- * Exception Store
3
- * Zustand store for exception state management
4
- */
5
-
6
- import { createStore } from '../../../storage';
7
- import type { ExceptionEntity } from '../../domain/entities/ExceptionEntity';
8
-
9
- interface ExceptionState {
10
- exceptions: ExceptionEntity[];
11
- }
12
-
13
- interface ExceptionActions {
14
- addException: (exception: ExceptionEntity) => void;
15
- clearExceptions: () => void;
16
- markAsHandled: (id: string) => void;
17
- }
18
-
19
- export const useExceptionStore = createStore<ExceptionState, ExceptionActions>({
20
- name: 'exception-store',
21
- initialState: {
22
- exceptions: [],
23
- },
24
- persist: false,
25
- actions: (set: (state: Partial<ExceptionState>) => void, get: () => ExceptionState) => ({
26
- addException: (exception: ExceptionEntity) =>
27
- set({ exceptions: [...get().exceptions, exception] }),
28
- clearExceptions: () => set({ exceptions: [] }),
29
- markAsHandled: (id: string) =>
30
- set({
31
- exceptions: get().exceptions.map((e: ExceptionEntity) =>
32
- e.id === id ? { ...e, handled: true } : e
33
- ),
34
- }),
35
- }),
36
- });
37
-
38
- /**
39
- * Hook to get exceptions from store
40
- */
41
- export const useExceptions = () => {
42
- const exceptions = useExceptionStore((state: ExceptionState) => state.exceptions);
43
- return exceptions;
44
- };
@@ -1,129 +0,0 @@
1
- /**
2
- * Error Boundary Component
3
- * React 19 compatible - Functional component with hooks
4
- */
5
-
6
- import React, { ReactNode, useState, useCallback } from 'react';
7
- import { View, StyleSheet, TouchableOpacity } from 'react-native';
8
- import { AtomicText } from '../../../atoms';
9
- import { exceptionService } from '../../infrastructure/services/ExceptionService';
10
- import { useAppDesignTokens } from '../../../theme';
11
-
12
- interface Props {
13
- children: ReactNode;
14
- fallback?: ReactNode;
15
- onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
16
- }
17
-
18
- interface ErrorInfo {
19
- error: Error;
20
- componentStack: string | null;
21
- }
22
-
23
- export const ErrorBoundary: React.FC<Props> = ({
24
- children,
25
- fallback,
26
- onError
27
- }) => {
28
- const [errorState, setErrorState] = useState<{
29
- hasError: boolean;
30
- error: Error | null;
31
- }>({
32
- hasError: false,
33
- error: null,
34
- });
35
-
36
- const tokens = useAppDesignTokens();
37
-
38
- // Global error handler for React 19
39
- useCallback((error: Error, errorInfo: React.ErrorInfo) => {
40
- // Log error to exception service
41
- exceptionService.handleFatalError(error, {
42
- componentStack: errorInfo.componentStack ?? undefined,
43
- screen: 'ErrorBoundary',
44
- });
45
-
46
- // Update state
47
- setErrorState({
48
- hasError: true,
49
- error,
50
- });
51
-
52
- // Call external onError if provided
53
- if (onError) {
54
- onError(error, errorInfo);
55
- }
56
- }, [onError]);
57
-
58
- // Reset error state
59
- const resetError = useCallback(() => {
60
- setErrorState({
61
- hasError: false,
62
- error: null,
63
- });
64
- }, []);
65
-
66
- // If there's an error, render fallback
67
- if (errorState.hasError) {
68
- if (fallback) {
69
- return <>{fallback}</>;
70
- }
71
-
72
- return (
73
- <View style={[styles.container, { backgroundColor: tokens.colors.error.background }]}>
74
- <View style={styles.content}>
75
- <AtomicText variant="h3" style={styles.title}>
76
- Something went wrong
77
- </AtomicText>
78
-
79
- {errorState.error && (
80
- <AtomicText variant="body" style={styles.message}>
81
- {errorState.error.message}
82
- </AtomicText>
83
- )}
84
-
85
- <TouchableOpacity
86
- style={[styles.button, { backgroundColor: tokens.colors.primary }]}
87
- onPress={resetError}
88
- >
89
- <AtomicText variant="button" style={styles.buttonText}>
90
- Try Again
91
- </AtomicText>
92
- </TouchableOpacity>
93
- </View>
94
- </View>
95
- );
96
- }
97
-
98
- return <>{children}</>;
99
- };
100
-
101
- const styles = StyleSheet.create({
102
- container: {
103
- flex: 1,
104
- justifyContent: 'center',
105
- alignItems: 'center',
106
- padding: 20,
107
- },
108
- content: {
109
- alignItems: 'center',
110
- maxWidth: 400,
111
- },
112
- title: {
113
- marginBottom: 10,
114
- textAlign: 'center',
115
- },
116
- message: {
117
- marginBottom: 20,
118
- textAlign: 'center',
119
- opacity: 0.7,
120
- },
121
- button: {
122
- paddingHorizontal: 20,
123
- paddingVertical: 12,
124
- borderRadius: 8,
125
- },
126
- buttonText: {
127
- color: '#fff',
128
- },
129
- });
@@ -1,123 +0,0 @@
1
- /**
2
- * Empty State Component
3
- * Displays when no data is available
4
- *
5
- * Presentation Layer - UI Component
6
- */
7
-
8
- import React, { useMemo } from "react";
9
- import { View, StyleSheet, TouchableOpacity } from "react-native";
10
- import { AtomicIcon, AtomicText } from "../../../atoms";
11
- import { useAppDesignTokens } from "../../../theme";
12
-
13
- export interface ExceptionEmptyStateProps {
14
- icon?: string;
15
- title: string;
16
- description?: string;
17
- actionLabel?: string;
18
- onAction?: () => void;
19
- illustration?: React.ReactNode;
20
- }
21
-
22
- export const ExceptionEmptyState: React.FC<ExceptionEmptyStateProps> = ({
23
- icon = "inbox",
24
- title,
25
- description,
26
- actionLabel,
27
- onAction,
28
- illustration,
29
- }) => {
30
- const tokens = useAppDesignTokens();
31
-
32
- const styles = useMemo(
33
- () =>
34
- StyleSheet.create({
35
- actionButton: {
36
- borderRadius: tokens.borders.radius.md,
37
- marginTop: tokens.spacing.sm,
38
- paddingHorizontal: tokens.spacing.lg,
39
- paddingVertical: tokens.spacing.md,
40
- },
41
- actionButtonText: {
42
- // AtomicText handles typography
43
- },
44
- container: {
45
- alignItems: "center",
46
- flex: 1,
47
- justifyContent: "center",
48
- padding: tokens.spacing.xl,
49
- },
50
- description: {
51
- marginBottom: tokens.spacing.lg,
52
- maxWidth: 280,
53
- },
54
- iconContainer: {
55
- alignItems: "center",
56
- borderRadius: 60,
57
- height: 120,
58
- justifyContent: "center",
59
- marginBottom: tokens.spacing.lg,
60
- width: 120,
61
- },
62
- title: {
63
- marginBottom: tokens.spacing.sm,
64
- },
65
- }),
66
- [tokens],
67
- );
68
-
69
- return (
70
- <View style={styles.container}>
71
- {illustration ? (
72
- illustration
73
- ) : (
74
- <View
75
- style={[
76
- styles.iconContainer,
77
- { backgroundColor: tokens.colors.surface },
78
- ]}
79
- >
80
- <AtomicIcon name={icon} size="xxl" color="secondary" />
81
- </View>
82
- )}
83
-
84
- <AtomicText
85
- type="headlineSmall"
86
- color="primary"
87
- style={[styles.title, { textAlign: "center" }]}
88
- >
89
- {title}
90
- </AtomicText>
91
-
92
- {description && (
93
- <AtomicText
94
- type="bodyMedium"
95
- color="secondary"
96
- style={[styles.description, { textAlign: "center" }]}
97
- >
98
- {description}
99
- </AtomicText>
100
- )}
101
-
102
- {actionLabel && onAction && (
103
- <TouchableOpacity
104
- style={[
105
- styles.actionButton,
106
- { backgroundColor: tokens.colors.primary },
107
- ]}
108
- onPress={onAction}
109
- activeOpacity={0.8}
110
- >
111
- <AtomicText
112
- type="labelLarge"
113
- color="onPrimary"
114
- style={styles.actionButtonText}
115
- >
116
- {actionLabel}
117
- </AtomicText>
118
- </TouchableOpacity>
119
- )}
120
- </View>
121
- );
122
- };
123
-
@@ -1,122 +0,0 @@
1
- /**
2
- * Error State Component
3
- * Generic error display with retry action
4
- *
5
- * Presentation Layer - UI Component
6
- */
7
-
8
- import React, { useMemo } from "react";
9
- import { View, StyleSheet, TouchableOpacity } from "react-native";
10
- import {
11
- AtomicIcon,
12
- AtomicText,
13
- useIconName,
14
- } from "../../../atoms";
15
- import {
16
- useAppDesignTokens,
17
- } from "../../../theme";
18
-
19
- export interface ExceptionErrorStateProps {
20
- /** Icon name (interpreted by app's icon renderer) */
21
- icon?: string;
22
- /** Error title */
23
- title: string;
24
- /** Error description */
25
- description?: string;
26
- /** Retry button label */
27
- actionLabel?: string;
28
- /** Retry action callback */
29
- onAction?: () => void;
30
- /** Custom illustration instead of icon */
31
- illustration?: React.ReactNode;
32
- }
33
-
34
- export const ExceptionErrorState: React.FC<ExceptionErrorStateProps> = ({
35
- icon,
36
- title,
37
- description,
38
- actionLabel,
39
- onAction,
40
- illustration,
41
- }) => {
42
- const tokens = useAppDesignTokens();
43
- const alertCircleIcon = useIconName('alertCircle');
44
- const refreshIcon = useIconName('refresh');
45
- const displayIcon = icon || alertCircleIcon;
46
-
47
- const styles = useMemo(
48
- () =>
49
- StyleSheet.create({
50
- actionButton: {
51
- alignItems: "center",
52
- borderRadius: tokens.borders.radius.full,
53
- flexDirection: "row",
54
- gap: tokens.spacing.sm,
55
- marginTop: tokens.spacing.sm,
56
- paddingHorizontal: tokens.spacing.lg,
57
- paddingVertical: tokens.spacing.md,
58
- },
59
- container: {
60
- alignItems: "center",
61
- flex: 1,
62
- justifyContent: "center",
63
- padding: tokens.spacing.xl,
64
- },
65
- description: {
66
- marginBottom: tokens.spacing.lg,
67
- maxWidth: 280,
68
- textAlign: "center",
69
- },
70
- iconContainer: {
71
- alignItems: "center",
72
- borderRadius: 60,
73
- height: 120,
74
- justifyContent: "center",
75
- marginBottom: tokens.spacing.lg,
76
- width: 120,
77
- },
78
- title: {
79
- marginBottom: tokens.spacing.sm,
80
- textAlign: "center",
81
- },
82
- }),
83
- [tokens],
84
- );
85
-
86
- return (
87
- <View style={styles.container}>
88
- {illustration ? (
89
- illustration
90
- ) : (
91
- <View
92
- style={[styles.iconContainer, { backgroundColor: tokens.colors.surface }]}
93
- >
94
- <AtomicIcon name={displayIcon as never} size="xxl" color="secondary" />
95
- </View>
96
- )}
97
-
98
- <AtomicText type="headlineSmall" color="primary" style={styles.title}>
99
- {title}
100
- </AtomicText>
101
-
102
- {description && (
103
- <AtomicText type="bodyMedium" color="secondary" style={styles.description}>
104
- {description}
105
- </AtomicText>
106
- )}
107
-
108
- {actionLabel && onAction && (
109
- <TouchableOpacity
110
- style={[styles.actionButton, { backgroundColor: tokens.colors.primary }]}
111
- onPress={onAction}
112
- activeOpacity={0.8}
113
- >
114
- <AtomicIcon name={refreshIcon} size="sm" color="onPrimary" />
115
- <AtomicText type="labelLarge" color="onPrimary">
116
- {actionLabel}
117
- </AtomicText>
118
- </TouchableOpacity>
119
- )}
120
- </View>
121
- );
122
- };