diff --git a/.cursor/rules/folderstructure.mdc b/.cursor/rules/folderstructure.mdc
new file mode 100644
index 0000000..3dca909
--- /dev/null
+++ b/.cursor/rules/folderstructure.mdc
@@ -0,0 +1,3 @@
+---
+alwaysApply: true
+---
diff --git a/README.md b/README.md
index 9541a03..e2c434a 100644
--- a/README.md
+++ b/README.md
@@ -1,698 +1,52 @@
-1. RADIOLOGIST APP - DETAILED WORKFLOW
-1.1 App Launch & Authentication
-App Launch → Biometric Auth → Dashboard Loading
- ↓
-Load Case Queue → Priority Sort → Display Cases
- ↓
-Critical (RED) → Urgent (ORANGE) → Routine (GREEN)
-1.2 Critical Finding Workflow (Acute Subdural Hemorrhage)
-STEP 1: Alert Reception
-Push Notification → "CRITICAL - Acute Subdural Hemorrhage"
- ↓
-Tap Notification → App Opens → Case Preview
- ↓
-Patient: John Doe, Age 45, Head Trauma
-AI Confidence: 93%
-Midline Shift: 7mm
+# NeoScan Radiologist App
-STEP 2: Full Case Review
-Case Preview → Open DICOM Viewer
- ↓
-AI Overlay ON → Hemorrhage Highlighted
- ↓
-Review Images → Confirm Finding → Add Observations
- ↓
-"Large acute subdural hemorrhage with mass effect"
+A next-generation radiology workflow app designed for rapid, AI-assisted case review and reporting. Built with a modular architecture and a Clinical Blue Interface theme.
-STEP 3: Report Generation
-Voice-to-Text → "Acute subdural hemorrhage..."
- ↓
-Review Text → Edit if needed → Submit Report
- ↓
-Preliminary Report Sent (< 5 minutes)
+## Features
+- Modular structure: Auth, Dashboard, Case Review, Reporting, Notifications, Analytics, Profile
+- Clinical Blue Interface theme
+- Biometric and PIN authentication
+- Real-time case queue with priority sorting
+- DICOM viewer with AI overlays
+- Voice-to-text reporting
+- Push notifications for critical findings
+- Redux state management
-STEP 4: System Learning
-System Logs → Radiologist Confirmation
- ↓
-Time Metrics Recorded → Model Improvement Data
-1.3 Routine Scan Workflow (Negative Finding)
-STEP 1: Queue Processing
-Dashboard → Routine Queue → Select Case
- ↓
-Patient: Jane Smith, Age 30, Headache
-AI: No acute abnormalities (99% confidence)
-
-STEP 2: Confirmation Review
-DICOM Viewer → Quick Review → Confirm Negative
- ↓
-"No acute intracranial abnormality"
-
-STEP 3: Report & Documentation
-Submit Report → System Logs Concordance
- ↓
-Next Case in Queue
-1.4 System Uncertainty Protocol
-AI Confidence 70-85% → "REVIEW RECOMMENDED"
- ↓
-Special Yellow Flag → Enhanced Attention Required
- ↓
-Detailed Review → Feedback to System
-
-3. RADIOLOGIST APP WIREFRAMES
-3.1 Login Screen
-+------------------------+
-| [HOSPITAL LOGO] |
-| |
-| Radiologist Portal |
-| |
-| [👤 Dr. Smith] |
-| [🔒 Biometric Login] |
-| |
-| [Face ID Icon] |
-| Touch to Login |
-| |
-| OR |
-| |
-| PIN: [****] |
-| [LOGIN] |
-| |
-| Emergency Access |
-+------------------------+
-3.2 Dashboard - Case Queue
-+------------------------+
-| Dr. Smith [🔔3][⚙️] |
-| On-Call Status: ACTIVE |
-| |
-| CRITICAL CASES |
-| 🔴 Bed 3 - Hemorrhage |
-| 📱 2 min ago |
-| AI: 93% confidence |
-| [REVIEW NOW] |
-| |
-| 🔴 Bed 7 - Stroke |
-| 📱 5 min ago |
-| AI: 87% confidence |
-| [REVIEW NOW] |
-| |
-| URGENT CASES (4) |
-| 🟡 Show All |
-| |
-| ROUTINE CASES (12) |
-| 🟢 Show All |
-+------------------------+
-3.3 Critical Case Details
-+------------------------+
-| ← CRITICAL CASE |
-| |
-| Patient: John Doe, 45M |
-| Bed: 3 | Time: 14:35 |
-| Clinical: Head trauma |
-| |
-| AI ANALYSIS: |
-| 🔴 Acute Subdural |
-| Confidence: 93% |
-| Midline Shift: 7mm |
-| Mass Effect: Present |
-| |
-| [VIEW DICOM IMAGES] |
-| [VOICE REPORT] |
-| [QUICK REPORT] |
-| |
-| Status: PENDING REVIEW |
-+------------------------+
-3.4 DICOM Viewer
-+------------------------+
-| ← John Doe - CT Brain |
-| |
-| [ CT SCAN IMAGE ]|
-| [ WITH AI OVERLAY ]|
-| [ HEMORRHAGE ]|
-| [ HIGHLIGHTED ]|
-| |
-| Tools: [🔍][📏][✏️] |
-| AI: [ON] Conf: 93% |
-| |
-| Measurements: |
-| • Hemorrhage: 3.2cm |
-| • Midline: 7mm shift |
-| |
-| [🎤 START REPORT] |
-+------------------------+
-3.5 Voice Report Interface
-+------------------------+
-| ← Voice Report |
-| |
-| [🎤 RECORDING 01:23] |
-| |
-| "There is a large |
-| acute subdural |
-| hemorrhage in the |
-| right frontoparietal |
-| region..." |
-| |
-| [PAUSE] [STOP] [PLAY] |
-| |
-| [SAVE DRAFT] |
-| [SUBMIT REPORT] |
-| |
-| Estimated: 2 min left |
-+------------------------+
-
-5.1 React Native Project Structure
-🏥 RADIOLOGIST APP STRUCTURE
-NeoScan_Radiologist/
-│
-├── app/
-│ ├── modules/ # 🌐 Feature-wise modular architecture
-│ │ ├── Auth/ # 🔐 Authentication Module
-│ │ │ ├── components/
-│ │ │ │ ├── BiometricLogin.tsx
-│ │ │ │ ├── PinInput.tsx
-│ │ │ │ ├── EmergencyAccess.tsx
-│ │ │ │ └── index.ts
-│ │ │ ├── screens/
-│ │ │ │ ├── LoginScreen.tsx
-│ │ │ │ ├── SetupBiometricScreen.tsx
-│ │ │ │ └── index.ts
-│ │ │ ├── hooks/
-│ │ │ │ ├── useAuth.ts
-│ │ │ │ ├── useBiometric.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── redux/
-│ │ │ │ ├── authSlice.ts
-│ │ │ │ ├── authActions.ts
-│ │ │ │ ├── authSelectors.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── services/
-│ │ │ │ ├── authAPI.ts
-│ │ │ │ ├── biometricService.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── __tests__/
-│ │ │ │ ├── AuthService.test.ts
-│ │ │ │ ├── LoginScreen.test.tsx
-│ │ │ │ └── authSlice.test.ts
-│ │ │ └── index.ts
-│ │ │
-│ │ ├── Dashboard/ # 📊 Dashboard Module
-│ │ │ ├── components/
-│ │ │ │ ├── CaseQueue.tsx
-│ │ │ │ ├── CaseCard.tsx
-│ │ │ │ ├── PriorityIndicator.tsx
-│ │ │ │ ├── StatsPanel.tsx
-│ │ │ │ ├── FilterBar.tsx
-│ │ │ │ └── index.ts
-│ │ │ ├── screens/
-│ │ │ │ ├── DashboardScreen.tsx
-│ │ │ │ ├── CaseListScreen.tsx
-│ │ │ │ └── index.ts
-│ │ │ ├── hooks/
-│ │ │ │ ├── useCaseQueue.ts
-│ │ │ │ ├── useRealTimeUpdates.ts
-│ │ │ │ ├── useFilterCases.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── redux/
-│ │ │ │ ├── dashboardSlice.ts
-│ │ │ │ ├── caseQueueSlice.ts
-│ │ │ │ ├── dashboardActions.ts
-│ │ │ │ ├── dashboardSelectors.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── services/
-│ │ │ │ ├── caseAPI.ts
-│ │ │ │ ├── websocketService.ts
-│ │ │ │ ├── notificationService.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── __tests__/
-│ │ │ │ ├── CaseQueue.test.tsx
-│ │ │ │ ├── dashboardSlice.test.ts
-│ │ │ │ └── caseAPI.test.ts
-│ │ │ └── index.ts
-│ │ │
-│ │ ├── CaseReview/ # 🔍 Case Review Module
-│ │ │ ├── components/
-│ │ │ │ ├── DICOMViewer.tsx
-│ │ │ │ ├── AIOverlay.tsx
-│ │ │ │ ├── MeasurementTools.tsx
-│ │ │ │ ├── AnnotationTools.tsx
-│ │ │ │ ├── CaseMetadata.tsx
-│ │ │ │ ├── PriorStudyComparison.tsx
-│ │ │ │ └── index.ts
-│ │ │ ├── screens/
-│ │ │ │ ├── CaseDetailsScreen.tsx
-│ │ │ │ ├── DICOMViewerScreen.tsx
-│ │ │ │ ├── ComparisonScreen.tsx
-│ │ │ │ └── index.ts
-│ │ │ ├── hooks/
-│ │ │ │ ├── useDICOMViewer.ts
-│ │ │ │ ├── useAIOverlay.ts
-│ │ │ │ ├── useMeasurements.ts
-│ │ │ │ ├── useAnnotations.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── redux/
-│ │ │ │ ├── caseReviewSlice.ts
-│ │ │ │ ├── dicomSlice.ts
-│ │ │ │ ├── aiAnalysisSlice.ts
-│ │ │ │ ├── caseReviewActions.ts
-│ │ │ │ ├── caseReviewSelectors.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── services/
-│ │ │ │ ├── dicomAPI.ts
-│ │ │ │ ├── aiAnalysisAPI.ts
-│ │ │ │ ├── dicomParser.ts
-│ │ │ │ ├── imageProcessor.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── __tests__/
-│ │ │ │ ├── DICOMViewer.test.tsx
-│ │ │ │ ├── AIOverlay.test.tsx
-│ │ │ │ ├── dicomParser.test.ts
-│ │ │ │ └── caseReviewSlice.test.ts
-│ │ │ └── index.ts
-│ │ │
-│ │ ├── Reporting/ # 📝 Reporting Module
-│ │ │ ├── components/
-│ │ │ │ ├── VoiceRecorder.tsx
-│ │ │ │ ├── ReportEditor.tsx
-│ │ │ │ ├── ReportTemplate.tsx
-│ │ │ │ ├── QuickReportButtons.tsx
-│ │ │ │ ├── ReportPreview.tsx
-│ │ │ │ └── index.ts
-│ │ │ ├── screens/
-│ │ │ │ ├── ReportingScreen.tsx
-│ │ │ │ ├── VoiceReportScreen.tsx
-│ │ │ │ ├── ReportHistoryScreen.tsx
-│ │ │ │ └── index.ts
-│ │ │ ├── hooks/
-│ │ │ │ ├── useVoiceRecording.ts
-│ │ │ │ ├── useReportGeneration.ts
-│ │ │ │ ├── useSpeechToText.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── redux/
-│ │ │ │ ├── reportingSlice.ts
-│ │ │ │ ├── voiceRecordingSlice.ts
-│ │ │ │ ├── reportingActions.ts
-│ │ │ │ ├── reportingSelectors.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── services/
-│ │ │ │ ├── reportAPI.ts
-│ │ │ │ ├── voiceToTextAPI.ts
-│ │ │ │ ├── reportTemplateService.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── __tests__/
-│ │ │ │ ├── VoiceRecorder.test.tsx
-│ │ │ │ ├── reportingSlice.test.ts
-│ │ │ │ └── voiceToTextAPI.test.ts
-│ │ │ └── index.ts
-│ │ │
-│ │ ├── Notifications/ # 🔔 Notifications Module
-│ │ │ ├── components/
-│ │ │ │ ├── NotificationPanel.tsx
-│ │ │ │ ├── AlertBanner.tsx
-│ │ │ │ ├── CriticalAlert.tsx
-│ │ │ │ ├── NotificationSettings.tsx
-│ │ │ │ └── index.ts
-│ │ │ ├── screens/
-│ │ │ │ ├── NotificationsScreen.tsx
-│ │ │ │ ├── AlertDetailsScreen.tsx
-│ │ │ │ └── index.ts
-│ │ │ ├── hooks/
-│ │ │ │ ├── useNotifications.ts
-│ │ │ │ ├── usePushNotifications.ts
-│ │ │ │ ├── useAlertHandling.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── redux/
-│ │ │ │ ├── notificationsSlice.ts
-│ │ │ │ ├── alertsSlice.ts
-│ │ │ │ ├── notificationActions.ts
-│ │ │ │ ├── notificationSelectors.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── services/
-│ │ │ │ ├── pushNotificationService.ts
-│ │ │ │ ├── alertService.ts
-│ │ │ │ ├── notificationAPI.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── __tests__/
-│ │ │ │ ├── NotificationPanel.test.tsx
-│ │ │ │ ├── alertService.test.ts
-│ │ │ │ └── notificationsSlice.test.ts
-│ │ │ └── index.ts
-│ │ │
-│ │ ├── Analytics/ # 📈 Analytics Module
-│ │ │ ├── components/
-│ │ │ │ ├── PerformanceMetrics.tsx
-│ │ │ │ ├── ResponseTimeChart.tsx
-│ │ │ │ ├── ConcordanceStats.tsx
-│ │ │ │ ├── WorkloadAnalysis.tsx
-│ │ │ │ └── index.ts
-│ │ │ ├── screens/
-│ │ │ │ ├── AnalyticsScreen.tsx
-│ │ │ │ ├── PerformanceScreen.tsx
-│ │ │ │ └── index.ts
-│ │ │ ├── hooks/
-│ │ │ │ ├── useAnalytics.ts
-│ │ │ │ ├── usePerformanceMetrics.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── redux/
-│ │ │ │ ├── analyticsSlice.ts
-│ │ │ │ ├── analyticsActions.ts
-│ │ │ │ ├── analyticsSelectors.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── services/
-│ │ │ │ ├── analyticsAPI.ts
-│ │ │ │ ├── metricsCollector.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── __tests__/
-│ │ │ │ ├── PerformanceMetrics.test.tsx
-│ │ │ │ ├── analyticsSlice.test.ts
-│ │ │ │ └── metricsCollector.test.ts
-│ │ │ └── index.ts
-│ │ │
-│ │ └── Profile/ # 👤 User Profile Module
-│ │ ├── components/
-│ │ │ ├── ProfileHeader.tsx
-│ │ │ ├── SettingsPanel.tsx
-│ │ │ ├── PreferencesForm.tsx
-│ │ │ ├── SecuritySettings.tsx
-│ │ │ └── index.ts
-│ │ ├── screens/
-│ │ │ ├── ProfileScreen.tsx
-│ │ │ ├── SettingsScreen.tsx
-│ │ │ ├── PreferencesScreen.tsx
-│ │ │ └── index.ts
-│ │ ├── hooks/
-│ │ │ ├── useProfile.ts
-│ │ │ ├── useSettings.ts
-│ │ │ └── index.ts
-│ │ ├── redux/
-│ │ │ ├── profileSlice.ts
-│ │ │ ├── settingsSlice.ts
-│ │ │ ├── profileActions.ts
-│ │ │ ├── profileSelectors.ts
-│ │ │ └── index.ts
-│ │ ├── services/
-│ │ │ ├── profileAPI.ts
-│ │ │ ├── settingsAPI.ts
-│ │ │ └── index.ts
-│ │ ├── __tests__/
-│ │ │ ├── ProfileHeader.test.tsx
-│ │ │ ├── profileSlice.test.ts
-│ │ │ └── profileAPI.test.ts
-│ │ └── index.ts
-│ │
-│ ├── navigation/ # 🧭 Navigation Setup
-│ │ ├── AppNavigator.tsx
-│ │ ├── AuthNavigator.tsx
-│ │ ├── MainNavigator.tsx
-│ │ ├── TabNavigator.tsx
-│ │ ├── ModalNavigator.tsx
-│ │ ├── navigationTypes.ts
-│ │ └── index.ts
-│ │
-│ ├── redux/ # 🗃️ Redux Store Setup
-│ │ ├── store.ts
-│ │ ├── rootReducer.ts
-│ │ ├── middleware.ts
-│ │ ├── persistConfig.ts
-│ │ └── index.ts
-│ │
-│ ├── constants/ # 📋 Global Constants
-│ │ ├── apiEndpoints.ts
-│ │ ├── appConstants.ts
-│ │ ├── errorMessages.ts
-│ │ ├── notificationTypes.ts
-│ │ ├── priorityLevels.ts
-│ │ └── index.ts
-│ │
-│ ├── App.tsx # 🎯 Root Component
-│ └── index.ts # 🚀 App Bootstrap
-│
-├── shared/ # ✅ Shared Components & Utilities
-│ ├── src/
-│ │ ├── components/ # 🎨 Global UI Components
-│ │ │ ├── Button/
-│ │ │ │ ├── Button.tsx
-│ │ │ │ ├── Button.styles.ts
-│ │ │ │ ├── Button.types.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── Input/
-│ │ │ │ ├── TextInput.tsx
-│ │ │ │ ├── SearchInput.tsx
-│ │ │ │ ├── Input.styles.ts
-│ │ │ │ ├── Input.types.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── Modal/
-│ │ │ │ ├── Modal.tsx
-│ │ │ │ ├── ConfirmModal.tsx
-│ │ │ │ ├── AlertModal.tsx
-│ │ │ │ ├── Modal.styles.ts
-│ │ │ │ ├── Modal.types.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── Card/
-│ │ │ │ ├── Card.tsx
-│ │ │ │ ├── InfoCard.tsx
-│ │ │ │ ├── Card.styles.ts
-│ │ │ │ ├── Card.types.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── Loading/
-│ │ │ │ ├── Spinner.tsx
-│ │ │ │ ├── LoadingOverlay.tsx
-│ │ │ │ ├── Loading.styles.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── Icons/
-│ │ │ │ ├── CustomIcon.tsx
-│ │ │ │ ├── IconButton.tsx
-│ │ │ │ ├── Icons.types.ts
-│ │ │ │ └── index.ts
-│ │ │ └── index.ts
-│ │ │
-│ │ ├── theme/ # 🎨 Design System
-│ │ │ ├── colors.ts
-│ │ │ ├── spacing.ts
-│ │ │ ├── typography.ts
-│ │ │ ├── shadows.ts
-│ │ │ ├── borderRadius.ts
-│ │ │ ├── animations.ts
-│ │ │ └── index.ts
-│ │ │
-│ │ ├── assets/ # 📁 Static Assets
-│ │ │ ├── icons/
-│ │ │ │ ├── critical-alert.svg
-│ │ │ │ ├── urgent-alert.svg
-│ │ │ │ ├── routine-alert.svg
-│ │ │ │ └── index.ts
-│ │ │ ├── images/
-│ │ │ │ ├── logo.png
-│ │ │ │ ├── placeholder.png
-│ │ │ │ └── index.ts
-│ │ │ ├── fonts/
-│ │ │ │ ├── Roboto-Regular.ttf
-│ │ │ │ ├── Roboto-Bold.ttf
-│ │ │ │ └── index.ts
-│ │ │ └── sounds/
-│ │ │ ├── critical-alert.wav
-│ │ │ ├── urgent-alert.wav
-│ │ │ └── routine-alert.wav
-│ │ │
-│ │ ├── utils/ # 🛠️ Utility Functions
-│ │ │ ├── dateTime/
-│ │ │ │ ├── formatDate.ts
-│ │ │ │ ├── timeAgo.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── validation/
-│ │ │ │ ├── validators.ts
-│ │ │ │ ├── schemas.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── helpers/
-│ │ │ │ ├── debounce.ts
-│ │ │ │ ├── throttle.ts
-│ │ │ │ ├── formatters.ts
-│ │ │ │ └── index.ts
-│ │ │ ├── constants/
-│ │ │ │ ├── regex.ts
-│ │ │ │ ├── formats.ts
-│ │ │ │ └── index.ts
-│ │ │ └── index.ts
-│ │ │
-│ │ ├── hooks/ # 🎣 Shared Custom Hooks
-│ │ │ ├── useTheme.ts
-│ │ │ ├── useDebounce.ts
-│ │ │ ├── useKeyboard.ts
-│ │ │ ├── useNetworkStatus.ts
-│ │ │ ├── useOrientation.ts
-│ │ │ └── index.ts
-│ │ │
-│ │ ├── types/ # 📝 TypeScript Types
-│ │ │ ├── common.ts
-│ │ │ ├── api.ts
-│ │ │ ├── navigation.ts
-│ │ │ ├── theme.ts
-│ │ │ └── index.ts
-│ │ │
-│ │ └── index.ts # 📦 Barrel Export
-│ │
-│ ├── package.json # 📦 Shared Package Config
-│ └── tsconfig.json # ⚙️ TypeScript Config
-│
-├── __tests__/ # 🧪 Global Tests
-│ ├── App.test.tsx
-│ ├── Navigation.test.tsx
-│ ├── Redux.test.tsx
-│ └── Integration.test.tsx
-│
-├── assets/ # 🖼️ App-wide Assets
-│ ├── images/
-│ ├── videos/
-│ └── audio/
-│
-├── android/ # 🤖 Android Native
-├── ios/ # 🍎 iOS Native
-├── index.js # 🎯 RN Entry Point
-├── package.json # 📦 Root Dependencies
-├── tsconfig.json # ⚙️ Base TypeScript Config
-├── metro.config.js # 📦 Metro Bundler Config
-├── babel.config.js # 🔄 Babel Config
-└── .eslintrc.js # 📏 ESLint Config
-
-
-Key Features:
-
-Real-time WebSocket connections
-Offline caching for critical cases
-Biometric authentication for radiologists
-Performance monitoring with timing metrics
-
-Radiologist App Options
-Option 1: "Clinical Gray Spectrum"
-
-Primary: #2C3E50 (Dark Blue-Gray)
-Secondary: #34495E (Medium Blue-Gray)
-Tertiary: #95A5A6 (Light Gray)
-Text Primary: #2C3E50 (Dark Blue-Gray)
-Text Secondary: #7F8C8D (Medium Gray)
-Text Muted: #BDC3C7 (Light Gray)
-Background: #F8F9FA (Light Gray)
-Background Alt: #E9ECEF (Darker Light Gray)
-Success: #27AE60 (Green)
-Warning: #F39C12 (Orange)
-Error: #E74C3C (Red)
-Info: #3498DB (Blue)
-
-Option 2: "Deep Tech Purple"
-
-Primary: #6C5CE7 (Modern Purple)
-Secondary: #A29BFE (Light Purple)
-Tertiary: #DDD6FE (Very Light Purple)
-Text Primary: #2D3436 (Charcoal)
-Text Secondary: #636E72 (Gray)
-Text Muted: #B2BEC3 (Light Gray)
-Background: #FFFFFF (White)
-Background Alt: #F8F7FF (Very Light Purple)
-Success: #00B894 (Teal)
-Warning: #FDCB6E (Yellow)
-Error: #FD79A8 (Pink)
-Info: #74B9FF (Light Blue)
-
-Option 3: "Dark Professional"
-
-Primary: #1A365D (Navy Blue)
-Secondary: #2D3748 (Dark Gray)
-Tertiary: #4A5568 (Medium Gray)
-Text Primary: #1A202C (Very Dark Gray)
-Text Secondary: #4A5568 (Medium Gray)
-Text Muted: #718096 (Light Gray)
-Background: #FFFFFF (White)
-Background Alt: #F7FAFC (Off White)
-Success: #38A169 (Green)
-Warning: #DD6B20 (Orange)
-Error: #E53E3E (Red)
-Info: #3182CE (Blue)
-
-Option 4: "Sophisticated Slate"
-
-Primary: #475569 (Slate Gray)
-Secondary: #64748B (Medium Slate)
-Tertiary: #CBD5E1 (Light Slate)
-Text Primary: #0F172A (Almost Black)
-Text Secondary: #475569 (Slate Gray)
-Text Muted: #94A3B8 (Light Slate)
-Background: #FFFFFF (White)
-Background Alt: #F8FAFC (Very Light Slate)
-Success: #059669 (Emerald)
-Warning: #D97706 (Amber)
-Error: #DC2626 (Red)
-Info: #0284C7 (Sky Blue)
-
-Radiologist App - "Clinical Blue Interface"
-Primary: #5B7CE6 (Blue Purple - from the selected buttons)
-Secondary: #7B94F0 (Light Blue Purple)
-Tertiary: #E8EFFF (Very Light Blue)
-Quaternary: #3B5998 (Deep Blue)
-Text Primary: #1A1D29 (Almost Black)
-Text Secondary: #4A5568 (Medium Gray)
-Text Muted: #9CA3AF (Light Gray)
-Background: #FFFFFF (White)
-Background Alt: #F8FAFF (Very Light Blue Tint)
-Background Accent: #F1F5FF (Soft Blue)
-Card Background: #FFFFFF (White with shadow)
-Success: #10B981 (Green - from the security icon)
-Warning: #F59E0B (Amber)
-Error: #EF4444 (Red)
-Info: #3B82F6 (Blue)
-Border: #E5E7EB (Light Gray)
-Selected State: #5B7CE6 (Same as Primary)
-Inactive State: #F3F4F6 (Light Gray)
-Shadow: rgba(91, 124, 230, 0.1) (Blue Shadow)
-Gradient Background: linear-gradient(135deg, #667eea 0%, #764ba2 100%)
-
-Dark professional Prefered
-
-```sh
-# Using npm
-npm start
-
-# OR using Yarn
-yarn start
+## Project Structure
+```
+app/
+ modules/ # Feature modules (Auth, Dashboard, CaseReview, ...)
+ navigation/ # Navigation setup
+ redux/ # Redux store setup
+ constants/ # Global constants
+shared/
+ src/
+ components/ # Shared UI components
+ theme/ # Design system (colors, typography, ...)
+ utils/ # Utility functions
+ hooks/ # Shared hooks
+ types/ # TypeScript types
+assets/ # App-wide assets
```
-## Step 2: Build and run your app
+## Theme
+- Primary: #5B7CE6
+- Secondary: #7B94F0
+- Tertiary: #E8EFFF
+- Quaternary: #3B5998
+- ... (see `shared/src/theme/colors.ts`)
-With Metro running, open a new terminal window/pane from the root of your React Native project, and use one of the following commands to build and run your Android or iOS app:
+## Setup
+1. Install dependencies:
+ ```sh
+ npm install
+ ```
+2. Run the app:
+ ```sh
+ npm run android # or npm run ios
+ ```
-### Android
-
-```sh
-# Using npm
-npm run android
-
-# OR using Yarn
-yarn android
-```
-
-### iOS
-
-For iOS, remember to install CocoaPods dependencies (this only needs to be run on first clone or after updating native deps).
-
-The first time you create a new project, run the Ruby bundler to install CocoaPods itself:
-
-```sh
-bundle install
-```
-
-Then, and every time you update your native dependencies, run:
-
-```sh
-bundle exec pod install
-```
-
-For more information, please visit [CocoaPods Getting Started guide](https://guides.cocoapods.org/using/getting-started.html).
-
-```sh
-# Using npm
-npm run ios
-
-# OR using Yarn
-yarn ios
-```
-
-If everything is set up correctly, you should see your new app running in the Android Emulator, iOS Simulator, or your connected device.
-
-This is one way to run your app — you can also build it directly from Android Studio or Xcode.
+## Copyright
+Design & Developed by Tech4Biz Solutions
+Copyright (c) Spurrin Innovations. All rights reserved.
diff --git a/app/modules/Auth/__tests__/BiometricLogin.test.tsx b/app/modules/Auth/__tests__/BiometricLogin.test.tsx
new file mode 100644
index 0000000..1887a8e
--- /dev/null
+++ b/app/modules/Auth/__tests__/BiometricLogin.test.tsx
@@ -0,0 +1,30 @@
+/*
+ * File: BiometricLogin.test.tsx
+ * Description: Test for BiometricLogin component
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { render, fireEvent } from '@testing-library/react-native';
+import BiometricLogin from '../components/BiometricLogin';
+
+jest.mock('../hooks/useBiometric', () => ({
+ useBiometric: () => ({ authenticate: jest.fn() })
+}));
+
+describe('BiometricLogin', () => {
+ it('renders button and triggers handler', () => {
+ const { getByText } = render();
+ const button = getByText('Login with Biometric');
+ expect(button).toBeTruthy();
+ fireEvent.press(button);
+ // No error means handler is called
+ });
+});
+
+/*
+ * End of File: BiometricLogin.test.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/__tests__/authAPI.test.ts b/app/modules/Auth/__tests__/authAPI.test.ts
new file mode 100644
index 0000000..8738ab0
--- /dev/null
+++ b/app/modules/Auth/__tests__/authAPI.test.ts
@@ -0,0 +1,26 @@
+/*
+ * File: authAPI.test.ts
+ * Description: Test for authAPI service
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { authAPI } from '../services/authAPI';
+
+jest.mock('apisauce', () => ({
+ create: () => ({ post: jest.fn(() => Promise.resolve({ ok: true, data: { id: '1', name: 'Dr. Smith', email: 'dr@hospital.com' } })) })
+}));
+
+describe('authAPI', () => {
+ it('calls login and returns data', async () => {
+ const response = await authAPI.login('dr@hospital.com', 'password');
+ expect(response.ok).toBe(true);
+ expect(response.data).toHaveProperty('email', 'dr@hospital.com');
+ });
+});
+
+/*
+ * End of File: authAPI.test.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/__tests__/authSlice.test.ts b/app/modules/Auth/__tests__/authSlice.test.ts
new file mode 100644
index 0000000..5244e11
--- /dev/null
+++ b/app/modules/Auth/__tests__/authSlice.test.ts
@@ -0,0 +1,40 @@
+/*
+ * File: authSlice.test.ts
+ * Description: Test for authSlice reducer
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import reducer, { loginSuccess, loginFailure } from '../redux/authSlice';
+
+const initialState = {
+ user: null,
+ loading: false,
+ error: null,
+ isAuthenticated: false,
+};
+
+describe('authSlice', () => {
+ it('handles loginSuccess', () => {
+ const user = { id: '1', name: 'Dr. Smith', email: 'dr@hospital.com' };
+ const state = reducer(initialState, loginSuccess(user));
+ expect(state.user).toEqual(user);
+ expect(state.isAuthenticated).toBe(true);
+ expect(state.loading).toBe(false);
+ expect(state.error).toBeNull();
+ });
+
+ it('handles loginFailure', () => {
+ const error = 'Invalid credentials';
+ const state = reducer(initialState, loginFailure(error));
+ expect(state.loading).toBe(false);
+ expect(state.error).toBe(error);
+ expect(state.isAuthenticated).toBe(false);
+ });
+});
+
+/*
+ * End of File: authSlice.test.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/components/BiometricLogin.tsx b/app/modules/Auth/components/BiometricLogin.tsx
new file mode 100644
index 0000000..8f9d6de
--- /dev/null
+++ b/app/modules/Auth/components/BiometricLogin.tsx
@@ -0,0 +1,32 @@
+/*
+ * File: BiometricLogin.tsx
+ * Description: Component for biometric login button
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { Button } from 'shared/src/components/Button';
+import { useBiometric } from '../hooks/useBiometric';
+
+/**
+ * BiometricLogin - button to trigger biometric authentication
+ */
+const BiometricLogin: React.FC = () => {
+ const { authenticate } = useBiometric();
+
+ const handleBiometric = async () => {
+ await authenticate();
+ // TODO: Handle result and login
+ };
+
+ return ;
+};
+
+export default BiometricLogin;
+
+/*
+ * End of File: BiometricLogin.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/components/EmergencyAccess.tsx b/app/modules/Auth/components/EmergencyAccess.tsx
new file mode 100644
index 0000000..85f6c55
--- /dev/null
+++ b/app/modules/Auth/components/EmergencyAccess.tsx
@@ -0,0 +1,28 @@
+/*
+ * File: EmergencyAccess.tsx
+ * Description: Component for emergency access button
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { Button } from 'shared/src/components/Button';
+
+/**
+ * EmergencyAccess - button to trigger emergency access
+ */
+const EmergencyAccess: React.FC = () => {
+ const handleEmergency = () => {
+ // TODO: Handle emergency access
+ };
+
+ return ;
+};
+
+export default EmergencyAccess;
+
+/*
+ * End of File: EmergencyAccess.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/components/PinInput.tsx b/app/modules/Auth/components/PinInput.tsx
new file mode 100644
index 0000000..9220313
--- /dev/null
+++ b/app/modules/Auth/components/PinInput.tsx
@@ -0,0 +1,69 @@
+/*
+ * File: PinInput.tsx
+ * Description: Component for PIN entry
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, StyleSheet, TextInput as RNTextInput } from 'react-native';
+import { Colors, Spacing, BorderRadius, Typography } from 'shared/src/theme';
+
+interface PinInputProps {
+ value: string;
+ onChange: (val: string) => void;
+ length?: number;
+}
+
+/**
+ * PinInput - input for entering PIN code
+ */
+const PinInput: React.FC = ({ value, onChange, length = 4 }) => {
+ return (
+
+ {Array.from({ length }).map((_, idx) => (
+ {
+ const newValue = value.substring(0, idx) + text + value.substring(idx + 1);
+ onChange(newValue);
+ }}
+ maxLength={1}
+ keyboardType="number-pad"
+ secureTextEntry
+ />
+ ))}
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flexDirection: 'row',
+ justifyContent: 'center',
+ marginVertical: Spacing.md,
+ },
+ input: {
+ width: 40,
+ height: 48,
+ marginHorizontal: Spacing.xs,
+ backgroundColor: Colors.backgroundAlt,
+ borderRadius: BorderRadius.md,
+ textAlign: 'center',
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.lg,
+ color: Colors.textPrimary,
+ borderWidth: 1,
+ borderColor: Colors.border,
+ },
+});
+
+export default PinInput;
+
+/*
+ * End of File: PinInput.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/components/index.ts b/app/modules/Auth/components/index.ts
new file mode 100644
index 0000000..a0bfbf7
--- /dev/null
+++ b/app/modules/Auth/components/index.ts
@@ -0,0 +1,16 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Auth components
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as BiometricLogin } from './BiometricLogin';
+export { default as PinInput } from './PinInput';
+export { default as EmergencyAccess } from './EmergencyAccess';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/hooks/index.ts b/app/modules/Auth/hooks/index.ts
new file mode 100644
index 0000000..9aca44c
--- /dev/null
+++ b/app/modules/Auth/hooks/index.ts
@@ -0,0 +1,15 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Auth hooks
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export * from './useAuth';
+export * from './useBiometric';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/hooks/useAuth.ts b/app/modules/Auth/hooks/useAuth.ts
new file mode 100644
index 0000000..52ca93b
--- /dev/null
+++ b/app/modules/Auth/hooks/useAuth.ts
@@ -0,0 +1,24 @@
+/*
+ * File: useAuth.ts
+ * Description: Custom hook for accessing auth state from redux
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { useSelector } from 'react-redux';
+import { selectUser, selectIsAuthenticated } from '../redux/authSelectors';
+
+/**
+ * useAuth - returns the current user and authentication status from redux state
+ */
+export const useAuth = () => {
+ const user = useSelector(selectUser);
+ const isAuthenticated = useSelector(selectIsAuthenticated);
+ return { user, isAuthenticated };
+};
+
+/*
+ * End of File: useAuth.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/hooks/useBiometric.ts b/app/modules/Auth/hooks/useBiometric.ts
new file mode 100644
index 0000000..532b64a
--- /dev/null
+++ b/app/modules/Auth/hooks/useBiometric.ts
@@ -0,0 +1,29 @@
+/*
+ * File: useBiometric.ts
+ * Description: Custom hook for biometric authentication (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+/**
+ * useBiometric - stub for biometric authentication
+ */
+export const useBiometric = () => {
+ const authenticate = async () => {
+ // TODO: Implement biometric authentication
+ // Example: return await biometricService.authenticate();
+ return true;
+ };
+ const isAvailable = async () => {
+ // TODO: Check if biometric is available
+ // Example: return await biometricService.isAvailable();
+ return true;
+ };
+ return { authenticate, isAvailable };
+};
+
+/*
+ * End of File: useBiometric.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/navigation/AuthNavigator.tsx b/app/modules/Auth/navigation/AuthNavigator.tsx
new file mode 100644
index 0000000..0c4c999
--- /dev/null
+++ b/app/modules/Auth/navigation/AuthNavigator.tsx
@@ -0,0 +1,51 @@
+/*
+ * File: AuthNavigator.tsx
+ * Description: Stack navigator for Auth module
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { createStackNavigator } from '@react-navigation/stack';
+import { LoginScreen, SetupBiometricScreen } from '../screens';
+import { Colors } from 'shared/src/theme';
+
+export type AuthStackParamList = {
+ Login: undefined;
+ SetupBiometric: undefined;
+};
+
+const Stack = createStackNavigator();
+
+/**
+ * AuthNavigator sets up stack navigation for Auth module
+ */
+const AuthNavigator: React.FC = () => (
+
+
+
+
+);
+
+export default AuthNavigator;
+
+/*
+ * End of File: AuthNavigator.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/navigation/index.ts b/app/modules/Auth/navigation/index.ts
new file mode 100644
index 0000000..4d84270
--- /dev/null
+++ b/app/modules/Auth/navigation/index.ts
@@ -0,0 +1,14 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Auth navigation
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as AuthNavigator } from './AuthNavigator';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/redux/authActions.ts b/app/modules/Auth/redux/authActions.ts
new file mode 100644
index 0000000..3131632
--- /dev/null
+++ b/app/modules/Auth/redux/authActions.ts
@@ -0,0 +1,38 @@
+/*
+ * File: authActions.ts
+ * Description: Async actions (thunks) for Auth state
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { createAsyncThunk } from '@reduxjs/toolkit';
+import { loginStart, loginSuccess, loginFailure } from './authSlice';
+import { authAPI } from '../services/authAPI';
+
+/**
+ * Thunk to login user
+ */
+export const login = createAsyncThunk(
+ 'auth/login',
+ async (credentials: { email: string; password: string }, { dispatch, rejectWithValue }) => {
+ try {
+ dispatch(loginStart());
+ const response = await authAPI.login(credentials.email, credentials.password);
+ if (response.ok && response.data) {
+ dispatch(loginSuccess(response.data));
+ } else {
+ dispatch(loginFailure(response.problem || 'Unknown error'));
+ return rejectWithValue(response.problem || 'Unknown error');
+ }
+ } catch (error: any) {
+ dispatch(loginFailure(error.message));
+ return rejectWithValue(error.message);
+ }
+ }
+);
+
+/*
+ * End of File: authActions.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/redux/authSelectors.ts b/app/modules/Auth/redux/authSelectors.ts
new file mode 100644
index 0000000..4dfccde
--- /dev/null
+++ b/app/modules/Auth/redux/authSelectors.ts
@@ -0,0 +1,19 @@
+/*
+ * File: authSelectors.ts
+ * Description: Selectors for Auth redux state
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { RootState } from 'app/redux/rootReducer';
+
+export const selectUser = (state: RootState) => state.auth.user;
+export const selectAuthLoading = (state: RootState) => state.auth.loading;
+export const selectAuthError = (state: RootState) => state.auth.error;
+export const selectIsAuthenticated = (state: RootState) => state.auth.isAuthenticated;
+
+/*
+ * End of File: authSelectors.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/redux/authSlice.ts b/app/modules/Auth/redux/authSlice.ts
new file mode 100644
index 0000000..301c6c9
--- /dev/null
+++ b/app/modules/Auth/redux/authSlice.ts
@@ -0,0 +1,73 @@
+/*
+ * File: authSlice.ts
+ * Description: Redux slice for Auth state management
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+
+// Sample user type
+export interface User {
+ id: string;
+ name: string;
+ email: string;
+}
+
+// Auth state type
+interface AuthState {
+ user: User | null;
+ loading: boolean;
+ error: string | null;
+ isAuthenticated: boolean;
+}
+
+const initialState: AuthState = {
+ user: null,
+ loading: false,
+ error: null,
+ isAuthenticated: false,
+};
+
+/**
+ * Auth slice for managing authentication state
+ */
+const authSlice = createSlice({
+ name: 'auth',
+ initialState,
+ reducers: {
+ loginStart(state) {
+ state.loading = true;
+ state.error = null;
+ },
+ loginSuccess(state, action: PayloadAction) {
+ state.user = action.payload;
+ state.isAuthenticated = true;
+ state.loading = false;
+ },
+ loginFailure(state, action: PayloadAction) {
+ state.loading = false;
+ state.error = action.payload;
+ state.isAuthenticated = false;
+ },
+ logout(state) {
+ state.user = null;
+ state.isAuthenticated = false;
+ },
+ },
+});
+
+export const {
+ loginStart,
+ loginSuccess,
+ loginFailure,
+ logout,
+} = authSlice.actions;
+
+export default authSlice.reducer;
+
+/*
+ * End of File: authSlice.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/redux/index.ts b/app/modules/Auth/redux/index.ts
new file mode 100644
index 0000000..37b349e
--- /dev/null
+++ b/app/modules/Auth/redux/index.ts
@@ -0,0 +1,16 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Auth redux
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as authReducer } from './authSlice';
+export * from './authActions';
+export * from './authSelectors';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/screens/LoginScreen.tsx b/app/modules/Auth/screens/LoginScreen.tsx
new file mode 100644
index 0000000..1fc7ce7
--- /dev/null
+++ b/app/modules/Auth/screens/LoginScreen.tsx
@@ -0,0 +1,79 @@
+/*
+ * File: LoginScreen.tsx
+ * Description: Login screen for user authentication
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React, { useState } from 'react';
+import { View, Text, StyleSheet } from 'react-native';
+import { TextInput } from 'shared/src/components/Input';
+import { Button } from 'shared/src/components/Button';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+import { useDispatch } from 'react-redux';
+import { login } from '../redux/authActions';
+
+/**
+ * LoginScreen - allows user to login with email and password
+ */
+const LoginScreen: React.FC = () => {
+ const [email, setEmail] = useState('');
+ const [password, setPassword] = useState('');
+ const dispatch = useDispatch();
+
+ const handleLogin = () => {
+ dispatch(login({ email, password }));
+ };
+
+ return (
+
+ Radiologist Portal
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: Colors.background,
+ justifyContent: 'center',
+ padding: Spacing.lg,
+ },
+ title: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.title,
+ color: Colors.primary,
+ marginBottom: Spacing.xl,
+ textAlign: 'center',
+ },
+ input: {
+ marginBottom: Spacing.md,
+ },
+ button: {
+ marginTop: Spacing.md,
+ },
+});
+
+export default LoginScreen;
+
+/*
+ * End of File: LoginScreen.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/screens/SetupBiometricScreen.tsx b/app/modules/Auth/screens/SetupBiometricScreen.tsx
new file mode 100644
index 0000000..464b4ff
--- /dev/null
+++ b/app/modules/Auth/screens/SetupBiometricScreen.tsx
@@ -0,0 +1,66 @@
+/*
+ * File: SetupBiometricScreen.tsx
+ * Description: Screen for setting up biometric authentication
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, StyleSheet } from 'react-native';
+import { Button } from 'shared/src/components/Button';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+import { useBiometric } from '../hooks/useBiometric';
+
+/**
+ * SetupBiometricScreen - allows user to setup biometric authentication
+ */
+const SetupBiometricScreen: React.FC = () => {
+ const { authenticate } = useBiometric();
+
+ const handleSetup = async () => {
+ await authenticate();
+ // TODO: Handle result and navigate
+ };
+
+ return (
+
+ Setup Biometric Login
+ Enable Face ID or Touch ID for quick and secure login.
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: Colors.background,
+ justifyContent: 'center',
+ padding: Spacing.lg,
+ },
+ title: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.title,
+ color: Colors.primary,
+ marginBottom: Spacing.lg,
+ textAlign: 'center',
+ },
+ info: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textSecondary,
+ marginBottom: Spacing.xl,
+ textAlign: 'center',
+ },
+ button: {
+ marginTop: Spacing.md,
+ },
+});
+
+export default SetupBiometricScreen;
+
+/*
+ * End of File: SetupBiometricScreen.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/screens/index.ts b/app/modules/Auth/screens/index.ts
new file mode 100644
index 0000000..fa12370
--- /dev/null
+++ b/app/modules/Auth/screens/index.ts
@@ -0,0 +1,15 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Auth screens
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as LoginScreen } from './LoginScreen';
+export { default as SetupBiometricScreen } from './SetupBiometricScreen';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/services/authAPI.ts b/app/modules/Auth/services/authAPI.ts
new file mode 100644
index 0000000..8536f5d
--- /dev/null
+++ b/app/modules/Auth/services/authAPI.ts
@@ -0,0 +1,27 @@
+/*
+ * File: authAPI.ts
+ * Description: API service for authentication using apisauce
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { create } from 'apisauce';
+
+const api = create({
+ baseURL: 'https://api.example.com', // TODO: Replace with actual endpoint
+ timeout: 10000,
+});
+
+/**
+ * login - authenticates user with email and password
+ */
+export const authAPI = {
+ login: (email: string, password: string) => api.post('/login', { email, password }),
+ // Add more endpoints as needed
+};
+
+/*
+ * End of File: authAPI.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/services/biometricService.ts b/app/modules/Auth/services/biometricService.ts
new file mode 100644
index 0000000..746d76a
--- /dev/null
+++ b/app/modules/Auth/services/biometricService.ts
@@ -0,0 +1,23 @@
+/*
+ * File: biometricService.ts
+ * Description: Service for biometric authentication (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export const biometricService = {
+ authenticate: async () => {
+ // TODO: Implement biometric authentication
+ return true;
+ },
+ isAvailable: async () => {
+ // TODO: Check if biometric is available
+ return true;
+ },
+};
+
+/*
+ * End of File: biometricService.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Auth/services/index.ts b/app/modules/Auth/services/index.ts
new file mode 100644
index 0000000..cb3d52d
--- /dev/null
+++ b/app/modules/Auth/services/index.ts
@@ -0,0 +1,15 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Auth services
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export * from './authAPI';
+export * from './biometricService';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/__tests__/DICOMViewer.test.tsx b/app/modules/CaseReview/__tests__/DICOMViewer.test.tsx
new file mode 100644
index 0000000..435be95
--- /dev/null
+++ b/app/modules/CaseReview/__tests__/DICOMViewer.test.tsx
@@ -0,0 +1,26 @@
+/*
+ * File: DICOMViewer.test.tsx
+ * Description: Test for DICOMViewer component
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { render } from '@testing-library/react-native';
+import DICOMViewer from '../components/DICOMViewer';
+
+describe('DICOMViewer', () => {
+ it('renders image and findings', () => {
+ const { getByText } = render(
+
+ );
+ expect(getByText(/AI: Hemorrhage/)).toBeTruthy();
+ expect(getByText(/93%/)).toBeTruthy();
+ });
+});
+
+/*
+ * End of File: DICOMViewer.test.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/__tests__/caseReviewSlice.test.ts b/app/modules/CaseReview/__tests__/caseReviewSlice.test.ts
new file mode 100644
index 0000000..cdef193
--- /dev/null
+++ b/app/modules/CaseReview/__tests__/caseReviewSlice.test.ts
@@ -0,0 +1,34 @@
+/*
+ * File: caseReviewSlice.test.ts
+ * Description: Test for caseReviewSlice reducer
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import reducer, { selectCase, setError, ReviewCase } from '../redux/caseReviewSlice';
+
+const initialState = {
+ selectedCase: null,
+ loading: false,
+ error: null,
+};
+
+describe('caseReviewSlice', () => {
+ it('handles selectCase', () => {
+ const reviewCase: ReviewCase = { id: '1', patientName: 'John Doe', images: [], aiFindings: 'None' };
+ const state = reducer(initialState, selectCase(reviewCase));
+ expect(state.selectedCase).toEqual(reviewCase);
+ });
+
+ it('handles setError', () => {
+ const error = 'Failed to load';
+ const state = reducer(initialState, setError(error));
+ expect(state.error).toBe(error);
+ });
+});
+
+/*
+ * End of File: caseReviewSlice.test.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/__tests__/dicomAPI.test.ts b/app/modules/CaseReview/__tests__/dicomAPI.test.ts
new file mode 100644
index 0000000..2b2dbea
--- /dev/null
+++ b/app/modules/CaseReview/__tests__/dicomAPI.test.ts
@@ -0,0 +1,26 @@
+/*
+ * File: dicomAPI.test.ts
+ * Description: Test for dicomAPI service
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { dicomAPI } from '../services/dicomAPI';
+
+jest.mock('apisauce', () => ({
+ create: () => ({ get: jest.fn(() => Promise.resolve({ ok: true, data: ['image1.png', 'image2.png'] })) })
+}));
+
+describe('dicomAPI', () => {
+ it('calls getImages and returns data', async () => {
+ const response = await dicomAPI.getImages('1');
+ expect(response.ok).toBe(true);
+ expect(Array.isArray(response.data)).toBe(true);
+ });
+});
+
+/*
+ * End of File: dicomAPI.test.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/components/AIOverlay.tsx b/app/modules/CaseReview/components/AIOverlay.tsx
new file mode 100644
index 0000000..b4a321e
--- /dev/null
+++ b/app/modules/CaseReview/components/AIOverlay.tsx
@@ -0,0 +1,54 @@
+/*
+ * File: AIOverlay.tsx
+ * Description: Component for displaying AI overlay graphics (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, StyleSheet } from 'react-native';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+
+interface AIOverlayProps {
+ findings: string;
+ confidence: number;
+}
+
+/**
+ * AIOverlay - displays AI overlay graphics (stub)
+ */
+const AIOverlay: React.FC = ({ findings, confidence }) => (
+
+ {/* TODO: Render overlay graphics */}
+ AI: {findings} ({confidence}%)
+
+);
+
+const styles = StyleSheet.create({
+ overlay: {
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: 'rgba(91, 124, 230, 0.1)',
+ },
+ text: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.md,
+ color: Colors.error,
+ backgroundColor: Colors.background,
+ padding: Spacing.xs,
+ borderRadius: 4,
+ },
+});
+
+export default AIOverlay;
+
+/*
+ * End of File: AIOverlay.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/components/AnnotationTools.tsx b/app/modules/CaseReview/components/AnnotationTools.tsx
new file mode 100644
index 0000000..3c91cda
--- /dev/null
+++ b/app/modules/CaseReview/components/AnnotationTools.tsx
@@ -0,0 +1,56 @@
+/*
+ * File: AnnotationTools.tsx
+ * Description: Component for annotation tools UI (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, StyleSheet, Button as RNButton } from 'react-native';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+
+interface AnnotationToolsProps {
+ annotations: any[];
+ addAnnotation: (a: any) => void;
+}
+
+/**
+ * AnnotationTools - UI for adding/viewing annotations (stub)
+ */
+const AnnotationTools: React.FC = ({ annotations, addAnnotation }) => (
+
+ Annotations
+ {annotations.map((a, idx) => (
+ {JSON.stringify(a)}
+ ))}
+ addAnnotation({ note: 'Sample annotation' })} />
+
+);
+
+const styles = StyleSheet.create({
+ container: {
+ marginVertical: Spacing.md,
+ padding: Spacing.md,
+ backgroundColor: Colors.backgroundAlt,
+ borderRadius: 8,
+ },
+ title: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.md,
+ color: Colors.primary,
+ marginBottom: Spacing.sm,
+ },
+ annotation: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.sm,
+ color: Colors.textSecondary,
+ },
+});
+
+export default AnnotationTools;
+
+/*
+ * End of File: AnnotationTools.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/components/CaseMetadata.tsx b/app/modules/CaseReview/components/CaseMetadata.tsx
new file mode 100644
index 0000000..95d173f
--- /dev/null
+++ b/app/modules/CaseReview/components/CaseMetadata.tsx
@@ -0,0 +1,52 @@
+/*
+ * File: CaseMetadata.tsx
+ * Description: Component for displaying case metadata (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, StyleSheet } from 'react-native';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+
+interface CaseMetadataProps {
+ caseData: any;
+}
+
+/**
+ * CaseMetadata - displays metadata for a case (stub)
+ */
+const CaseMetadata: React.FC = ({ caseData }) => (
+
+ Case Metadata
+ {JSON.stringify(caseData)}
+
+);
+
+const styles = StyleSheet.create({
+ container: {
+ marginVertical: Spacing.md,
+ padding: Spacing.md,
+ backgroundColor: Colors.backgroundAlt,
+ borderRadius: 8,
+ },
+ title: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.md,
+ color: Colors.primary,
+ marginBottom: Spacing.sm,
+ },
+ meta: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.sm,
+ color: Colors.textSecondary,
+ },
+});
+
+export default CaseMetadata;
+
+/*
+ * End of File: CaseMetadata.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/components/DICOMViewer.tsx b/app/modules/CaseReview/components/DICOMViewer.tsx
new file mode 100644
index 0000000..018a2a2
--- /dev/null
+++ b/app/modules/CaseReview/components/DICOMViewer.tsx
@@ -0,0 +1,53 @@
+/*
+ * File: DICOMViewer.tsx
+ * Description: Component for displaying a DICOM image with AI overlay (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Image, Text, StyleSheet } from 'react-native';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+
+interface DICOMViewerProps {
+ image: string;
+ findings: string;
+ confidence: number;
+}
+
+/**
+ * DICOMViewer - displays a DICOM image with AI overlay (stub)
+ */
+const DICOMViewer: React.FC = ({ image, findings, confidence }) => (
+
+
+ AI: {findings} ({confidence}%)
+ {/* TODO: Render overlay graphics */}
+
+);
+
+const styles = StyleSheet.create({
+ container: {
+ alignItems: 'center',
+ marginBottom: Spacing.md,
+ },
+ image: {
+ width: '100%',
+ height: 300,
+ backgroundColor: Colors.backgroundAlt,
+ marginBottom: Spacing.sm,
+ },
+ findings: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.md,
+ color: Colors.info,
+ },
+});
+
+export default DICOMViewer;
+
+/*
+ * End of File: DICOMViewer.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/components/MeasurementTools.tsx b/app/modules/CaseReview/components/MeasurementTools.tsx
new file mode 100644
index 0000000..dc97eb7
--- /dev/null
+++ b/app/modules/CaseReview/components/MeasurementTools.tsx
@@ -0,0 +1,56 @@
+/*
+ * File: MeasurementTools.tsx
+ * Description: Component for measurement tools UI (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, StyleSheet, Button as RNButton } from 'react-native';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+
+interface MeasurementToolsProps {
+ measurements: any[];
+ addMeasurement: (m: any) => void;
+}
+
+/**
+ * MeasurementTools - UI for adding/viewing measurements (stub)
+ */
+const MeasurementTools: React.FC = ({ measurements, addMeasurement }) => (
+
+ Measurements
+ {measurements.map((m, idx) => (
+ {JSON.stringify(m)}
+ ))}
+ addMeasurement({ length: Math.random() * 10 })} />
+
+);
+
+const styles = StyleSheet.create({
+ container: {
+ marginVertical: Spacing.md,
+ padding: Spacing.md,
+ backgroundColor: Colors.backgroundAlt,
+ borderRadius: 8,
+ },
+ title: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.md,
+ color: Colors.primary,
+ marginBottom: Spacing.sm,
+ },
+ measure: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.sm,
+ color: Colors.textSecondary,
+ },
+});
+
+export default MeasurementTools;
+
+/*
+ * End of File: MeasurementTools.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/components/PriorStudyComparison.tsx b/app/modules/CaseReview/components/PriorStudyComparison.tsx
new file mode 100644
index 0000000..c9ce9cd
--- /dev/null
+++ b/app/modules/CaseReview/components/PriorStudyComparison.tsx
@@ -0,0 +1,56 @@
+/*
+ * File: PriorStudyComparison.tsx
+ * Description: Component for comparing prior studies (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, StyleSheet } from 'react-native';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+
+interface PriorStudyComparisonProps {
+ prior: any;
+ current: any;
+}
+
+/**
+ * PriorStudyComparison - compares prior and current studies (stub)
+ */
+const PriorStudyComparison: React.FC = ({ prior, current }) => (
+
+ Prior Study
+ {JSON.stringify(prior)}
+ Current Study
+ {JSON.stringify(current)}
+
+);
+
+const styles = StyleSheet.create({
+ container: {
+ marginVertical: Spacing.md,
+ padding: Spacing.md,
+ backgroundColor: Colors.backgroundAlt,
+ borderRadius: 8,
+ },
+ title: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.md,
+ color: Colors.primary,
+ marginBottom: Spacing.sm,
+ },
+ data: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.sm,
+ color: Colors.textSecondary,
+ marginBottom: Spacing.md,
+ },
+});
+
+export default PriorStudyComparison;
+
+/*
+ * End of File: PriorStudyComparison.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/components/index.ts b/app/modules/CaseReview/components/index.ts
new file mode 100644
index 0000000..222de6c
--- /dev/null
+++ b/app/modules/CaseReview/components/index.ts
@@ -0,0 +1,19 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for CaseReview components
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as DICOMViewer } from './DICOMViewer';
+export { default as AIOverlay } from './AIOverlay';
+export { default as MeasurementTools } from './MeasurementTools';
+export { default as AnnotationTools } from './AnnotationTools';
+export { default as CaseMetadata } from './CaseMetadata';
+export { default as PriorStudyComparison } from './PriorStudyComparison';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/hooks/index.ts b/app/modules/CaseReview/hooks/index.ts
new file mode 100644
index 0000000..b38e4ca
--- /dev/null
+++ b/app/modules/CaseReview/hooks/index.ts
@@ -0,0 +1,17 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for CaseReview hooks
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export * from './useDICOMViewer';
+export * from './useAIOverlay';
+export * from './useMeasurements';
+export * from './useAnnotations';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/hooks/useAIOverlay.ts b/app/modules/CaseReview/hooks/useAIOverlay.ts
new file mode 100644
index 0000000..7db9f38
--- /dev/null
+++ b/app/modules/CaseReview/hooks/useAIOverlay.ts
@@ -0,0 +1,24 @@
+/*
+ * File: useAIOverlay.ts
+ * Description: Custom hook for AI overlay logic (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { useSelector } from 'react-redux';
+import { selectAIFindings, selectAIConfidence } from '../redux/caseReviewSelectors';
+
+/**
+ * useAIOverlay - returns AI findings and confidence (stub)
+ */
+export const useAIOverlay = () => {
+ const findings = useSelector(selectAIFindings);
+ const confidence = useSelector(selectAIConfidence);
+ return { findings, confidence };
+};
+
+/*
+ * End of File: useAIOverlay.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/hooks/useAnnotations.ts b/app/modules/CaseReview/hooks/useAnnotations.ts
new file mode 100644
index 0000000..ebbdcc1
--- /dev/null
+++ b/app/modules/CaseReview/hooks/useAnnotations.ts
@@ -0,0 +1,23 @@
+/*
+ * File: useAnnotations.ts
+ * Description: Custom hook for annotation tools (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { useState } from 'react';
+
+/**
+ * useAnnotations - manages annotations (stub)
+ */
+export const useAnnotations = () => {
+ const [annotations, setAnnotations] = useState([]);
+ const addAnnotation = (a: any) => setAnnotations(prev => [...prev, a]);
+ return { annotations, addAnnotation };
+};
+
+/*
+ * End of File: useAnnotations.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/hooks/useDICOMViewer.ts b/app/modules/CaseReview/hooks/useDICOMViewer.ts
new file mode 100644
index 0000000..c8df8b8
--- /dev/null
+++ b/app/modules/CaseReview/hooks/useDICOMViewer.ts
@@ -0,0 +1,24 @@
+/*
+ * File: useDICOMViewer.ts
+ * Description: Custom hook for DICOM viewer logic (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { useSelector } from 'react-redux';
+import { selectDICOMImages } from '../redux/caseReviewSelectors';
+
+/**
+ * useDICOMViewer - returns current DICOM image and navigation helpers (stub)
+ */
+export const useDICOMViewer = () => {
+ const images = useSelector(selectDICOMImages);
+ // TODO: Add navigation logic (next/prev image)
+ return { images };
+};
+
+/*
+ * End of File: useDICOMViewer.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/hooks/useMeasurements.ts b/app/modules/CaseReview/hooks/useMeasurements.ts
new file mode 100644
index 0000000..e702706
--- /dev/null
+++ b/app/modules/CaseReview/hooks/useMeasurements.ts
@@ -0,0 +1,23 @@
+/*
+ * File: useMeasurements.ts
+ * Description: Custom hook for measurement tools (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { useState } from 'react';
+
+/**
+ * useMeasurements - manages measurements (stub)
+ */
+export const useMeasurements = () => {
+ const [measurements, setMeasurements] = useState([]);
+ const addMeasurement = (m: any) => setMeasurements(prev => [...prev, m]);
+ return { measurements, addMeasurement };
+};
+
+/*
+ * End of File: useMeasurements.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/navigation/CaseReviewNavigator.tsx b/app/modules/CaseReview/navigation/CaseReviewNavigator.tsx
new file mode 100644
index 0000000..ce2743f
--- /dev/null
+++ b/app/modules/CaseReview/navigation/CaseReviewNavigator.tsx
@@ -0,0 +1,57 @@
+/*
+ * File: CaseReviewNavigator.tsx
+ * Description: Stack navigator for CaseReview module
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { createStackNavigator } from '@react-navigation/stack';
+import { CaseDetailsScreen, DICOMViewerScreen, ComparisonScreen } from '../screens';
+import { Colors } from 'shared/src/theme';
+
+export type CaseReviewStackParamList = {
+ CaseDetails: undefined;
+ DICOMViewer: undefined;
+ Comparison: undefined;
+};
+
+const Stack = createStackNavigator();
+
+/**
+ * CaseReviewNavigator sets up stack navigation for CaseReview module
+ */
+const CaseReviewNavigator: React.FC = () => (
+
+
+
+
+
+);
+
+export default CaseReviewNavigator;
+
+/*
+ * End of File: CaseReviewNavigator.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/navigation/index.ts b/app/modules/CaseReview/navigation/index.ts
new file mode 100644
index 0000000..c055846
--- /dev/null
+++ b/app/modules/CaseReview/navigation/index.ts
@@ -0,0 +1,14 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for CaseReview navigation
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as CaseReviewNavigator } from './CaseReviewNavigator';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/redux/aiAnalysisSlice.ts b/app/modules/CaseReview/redux/aiAnalysisSlice.ts
new file mode 100644
index 0000000..4e961bb
--- /dev/null
+++ b/app/modules/CaseReview/redux/aiAnalysisSlice.ts
@@ -0,0 +1,58 @@
+/*
+ * File: aiAnalysisSlice.ts
+ * Description: Redux slice for AI analysis state management
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+
+interface AIAnalysisState {
+ findings: string;
+ confidence: number;
+ loading: boolean;
+}
+
+const initialState: AIAnalysisState = {
+ findings: '',
+ confidence: 0,
+ loading: false,
+};
+
+/**
+ * aiAnalysisSlice for managing AI findings and confidence
+ */
+const aiAnalysisSlice = createSlice({
+ name: 'aiAnalysis',
+ initialState,
+ reducers: {
+ setFindings(state, action: PayloadAction) {
+ state.findings = action.payload;
+ },
+ setConfidence(state, action: PayloadAction) {
+ state.confidence = action.payload;
+ },
+ setLoading(state, action: PayloadAction) {
+ state.loading = action.payload;
+ },
+ clearAnalysis(state) {
+ state.findings = '';
+ state.confidence = 0;
+ },
+ },
+});
+
+export const {
+ setFindings,
+ setConfidence,
+ setLoading,
+ clearAnalysis,
+} = aiAnalysisSlice.actions;
+
+export default aiAnalysisSlice.reducer;
+
+/*
+ * End of File: aiAnalysisSlice.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/redux/caseReviewActions.ts b/app/modules/CaseReview/redux/caseReviewActions.ts
new file mode 100644
index 0000000..87df72a
--- /dev/null
+++ b/app/modules/CaseReview/redux/caseReviewActions.ts
@@ -0,0 +1,53 @@
+/*
+ * File: caseReviewActions.ts
+ * Description: Async actions (thunks) for CaseReview state
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { createAsyncThunk } from '@reduxjs/toolkit';
+import { setLoading, selectCase, setError } from './caseReviewSlice';
+import { setImages } from './dicomSlice';
+import { setFindings, setConfidence } from './aiAnalysisSlice';
+import { dicomAPI } from '../services/dicomAPI';
+import { aiAnalysisAPI } from '../services/aiAnalysisAPI';
+
+/**
+ * Thunk to fetch case details, DICOM images, and AI analysis
+ */
+export const fetchCaseDetails = createAsyncThunk(
+ 'caseReview/fetchCaseDetails',
+ async (caseId: string, { dispatch, rejectWithValue }) => {
+ try {
+ dispatch(setLoading(true));
+ // Fetch DICOM images
+ const dicomRes = await dicomAPI.getImages(caseId);
+ if (dicomRes.ok && dicomRes.data) {
+ dispatch(setImages(dicomRes.data));
+ } else {
+ dispatch(setError('Failed to load DICOM images'));
+ return rejectWithValue('Failed to load DICOM images');
+ }
+ // Fetch AI analysis
+ const aiRes = await aiAnalysisAPI.getAnalysis(caseId);
+ if (aiRes.ok && aiRes.data) {
+ dispatch(setFindings(aiRes.data.findings));
+ dispatch(setConfidence(aiRes.data.confidence));
+ } else {
+ dispatch(setError('Failed to load AI analysis'));
+ return rejectWithValue('Failed to load AI analysis');
+ }
+ dispatch(setLoading(false));
+ } catch (error: any) {
+ dispatch(setError(error.message));
+ dispatch(setLoading(false));
+ return rejectWithValue(error.message);
+ }
+ }
+);
+
+/*
+ * End of File: caseReviewActions.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/redux/caseReviewSelectors.ts b/app/modules/CaseReview/redux/caseReviewSelectors.ts
new file mode 100644
index 0000000..784d506
--- /dev/null
+++ b/app/modules/CaseReview/redux/caseReviewSelectors.ts
@@ -0,0 +1,21 @@
+/*
+ * File: caseReviewSelectors.ts
+ * Description: Selectors for CaseReview redux state
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { RootState } from 'app/redux/rootReducer';
+
+export const selectSelectedCase = (state: RootState) => state.caseReview.selectedCase;
+export const selectCaseReviewLoading = (state: RootState) => state.caseReview.loading;
+export const selectCaseReviewError = (state: RootState) => state.caseReview.error;
+export const selectDICOMImages = (state: RootState) => state.dicom.images;
+export const selectAIFindings = (state: RootState) => state.aiAnalysis.findings;
+export const selectAIConfidence = (state: RootState) => state.aiAnalysis.confidence;
+
+/*
+ * End of File: caseReviewSelectors.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/redux/caseReviewSlice.ts b/app/modules/CaseReview/redux/caseReviewSlice.ts
new file mode 100644
index 0000000..50d2d2d
--- /dev/null
+++ b/app/modules/CaseReview/redux/caseReviewSlice.ts
@@ -0,0 +1,66 @@
+/*
+ * File: caseReviewSlice.ts
+ * Description: Redux slice for CaseReview state management
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+
+// Sample case type
+export interface ReviewCase {
+ id: string;
+ patientName: string;
+ images: string[];
+ aiFindings: string;
+}
+
+// CaseReview state type
+interface CaseReviewState {
+ selectedCase: ReviewCase | null;
+ loading: boolean;
+ error: string | null;
+}
+
+const initialState: CaseReviewState = {
+ selectedCase: null,
+ loading: false,
+ error: null,
+};
+
+/**
+ * CaseReview slice for managing selected case and review state
+ */
+const caseReviewSlice = createSlice({
+ name: 'caseReview',
+ initialState,
+ reducers: {
+ selectCase(state, action: PayloadAction) {
+ state.selectedCase = action.payload;
+ },
+ clearCase(state) {
+ state.selectedCase = null;
+ },
+ setLoading(state, action: PayloadAction) {
+ state.loading = action.payload;
+ },
+ setError(state, action: PayloadAction) {
+ state.error = action.payload;
+ },
+ },
+});
+
+export const {
+ selectCase,
+ clearCase,
+ setLoading,
+ setError,
+} = caseReviewSlice.actions;
+
+export default caseReviewSlice.reducer;
+
+/*
+ * End of File: caseReviewSlice.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/redux/dicomSlice.ts b/app/modules/CaseReview/redux/dicomSlice.ts
new file mode 100644
index 0000000..7145013
--- /dev/null
+++ b/app/modules/CaseReview/redux/dicomSlice.ts
@@ -0,0 +1,59 @@
+/*
+ * File: dicomSlice.ts
+ * Description: Redux slice for DICOM image state management
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+
+interface DICOMState {
+ images: string[];
+ currentIndex: number;
+ loading: boolean;
+}
+
+const initialState: DICOMState = {
+ images: [],
+ currentIndex: 0,
+ loading: false,
+};
+
+/**
+ * dicomSlice for managing DICOM images and navigation
+ */
+const dicomSlice = createSlice({
+ name: 'dicom',
+ initialState,
+ reducers: {
+ setImages(state, action: PayloadAction) {
+ state.images = action.payload;
+ state.currentIndex = 0;
+ },
+ setCurrentIndex(state, action: PayloadAction) {
+ state.currentIndex = action.payload;
+ },
+ setLoading(state, action: PayloadAction) {
+ state.loading = action.payload;
+ },
+ clearImages(state) {
+ state.images = [];
+ state.currentIndex = 0;
+ },
+ },
+});
+
+export const {
+ setImages,
+ setCurrentIndex,
+ setLoading,
+ clearImages,
+} = dicomSlice.actions;
+
+export default dicomSlice.reducer;
+
+/*
+ * End of File: dicomSlice.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/redux/index.ts b/app/modules/CaseReview/redux/index.ts
new file mode 100644
index 0000000..0c96e5d
--- /dev/null
+++ b/app/modules/CaseReview/redux/index.ts
@@ -0,0 +1,18 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for CaseReview redux
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as caseReviewReducer } from './caseReviewSlice';
+export { default as dicomReducer } from './dicomSlice';
+export { default as aiAnalysisReducer } from './aiAnalysisSlice';
+export * from './caseReviewActions';
+export * from './caseReviewSelectors';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/screens/CaseDetailsScreen.tsx b/app/modules/CaseReview/screens/CaseDetailsScreen.tsx
new file mode 100644
index 0000000..bcc2b65
--- /dev/null
+++ b/app/modules/CaseReview/screens/CaseDetailsScreen.tsx
@@ -0,0 +1,83 @@
+/*
+ * File: CaseDetailsScreen.tsx
+ * Description: Screen for displaying case details
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, StyleSheet } from 'react-native';
+import { Button } from 'shared/src/components/Button';
+import { Card } from 'shared/src/components/Card';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+import { useSelector } from 'react-redux';
+import { selectSelectedCase } from '../redux/caseReviewSelectors';
+import { useAIOverlay } from '../hooks/useAIOverlay';
+
+/**
+ * CaseDetailsScreen - shows patient info, AI findings, and navigation to DICOM viewer
+ */
+const CaseDetailsScreen: React.FC = ({ navigation }) => {
+ const caseData = useSelector(selectSelectedCase);
+ const { findings, confidence } = useAIOverlay();
+
+ if (!caseData) {
+ return No case selected.;
+ }
+
+ return (
+
+
+ {caseData.patientName}
+ AI Findings:
+ {findings}
+ Confidence: {confidence}%
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: Colors.background,
+ justifyContent: 'center',
+ padding: Spacing.lg,
+ },
+ title: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.lg,
+ color: Colors.primary,
+ marginBottom: Spacing.md,
+ },
+ label: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textPrimary,
+ marginTop: Spacing.sm,
+ },
+ findings: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textSecondary,
+ marginBottom: Spacing.sm,
+ },
+ confidence: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.sm,
+ color: Colors.info,
+ marginBottom: Spacing.md,
+ },
+ button: {
+ marginTop: Spacing.md,
+ },
+});
+
+export default CaseDetailsScreen;
+
+/*
+ * End of File: CaseDetailsScreen.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/screens/ComparisonScreen.tsx b/app/modules/CaseReview/screens/ComparisonScreen.tsx
new file mode 100644
index 0000000..2065170
--- /dev/null
+++ b/app/modules/CaseReview/screens/ComparisonScreen.tsx
@@ -0,0 +1,63 @@
+/*
+ * File: ComparisonScreen.tsx
+ * Description: Screen for comparing prior studies
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, StyleSheet } from 'react-native';
+import { Card } from 'shared/src/components/Card';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+
+/**
+ * ComparisonScreen - shows prior/current images and findings (stub)
+ */
+const ComparisonScreen: React.FC = () => {
+ return (
+
+
+ Comparison
+ Prior Study:
+ [Prior Image/Findings Here]
+ Current Study:
+ [Current Image/Findings Here]
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: Colors.background,
+ justifyContent: 'center',
+ padding: Spacing.lg,
+ },
+ title: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.lg,
+ color: Colors.primary,
+ marginBottom: Spacing.md,
+ },
+ label: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textPrimary,
+ marginTop: Spacing.sm,
+ },
+ stub: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textSecondary,
+ marginBottom: Spacing.sm,
+ },
+});
+
+export default ComparisonScreen;
+
+/*
+ * End of File: ComparisonScreen.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/screens/DICOMViewerScreen.tsx b/app/modules/CaseReview/screens/DICOMViewerScreen.tsx
new file mode 100644
index 0000000..a31e926
--- /dev/null
+++ b/app/modules/CaseReview/screens/DICOMViewerScreen.tsx
@@ -0,0 +1,66 @@
+/*
+ * File: DICOMViewerScreen.tsx
+ * Description: Screen for viewing DICOM images
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, StyleSheet, Image } from 'react-native';
+import { Button } from 'shared/src/components/Button';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+import { useDICOMViewer } from '../hooks/useDICOMViewer';
+
+/**
+ * DICOMViewerScreen - shows current DICOM image and navigation controls (stub)
+ */
+const DICOMViewerScreen: React.FC = ({ navigation }) => {
+ const { images } = useDICOMViewer();
+ // TODO: Add navigation logic for images
+ const currentImage = images[0];
+
+ return (
+
+ DICOM Viewer
+ {currentImage ? (
+
+ ) : (
+ No images available.
+ )}
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: Colors.background,
+ justifyContent: 'center',
+ alignItems: 'center',
+ padding: Spacing.lg,
+ },
+ title: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.lg,
+ color: Colors.primary,
+ marginBottom: Spacing.md,
+ },
+ image: {
+ width: '100%',
+ height: 300,
+ backgroundColor: Colors.backgroundAlt,
+ marginBottom: Spacing.md,
+ },
+ button: {
+ marginTop: Spacing.md,
+ },
+});
+
+export default DICOMViewerScreen;
+
+/*
+ * End of File: DICOMViewerScreen.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/screens/index.ts b/app/modules/CaseReview/screens/index.ts
new file mode 100644
index 0000000..d50698d
--- /dev/null
+++ b/app/modules/CaseReview/screens/index.ts
@@ -0,0 +1,16 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for CaseReview screens
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as CaseDetailsScreen } from './CaseDetailsScreen';
+export { default as DICOMViewerScreen } from './DICOMViewerScreen';
+export { default as ComparisonScreen } from './ComparisonScreen';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/services/aiAnalysisAPI.ts b/app/modules/CaseReview/services/aiAnalysisAPI.ts
new file mode 100644
index 0000000..8b36ce8
--- /dev/null
+++ b/app/modules/CaseReview/services/aiAnalysisAPI.ts
@@ -0,0 +1,27 @@
+/*
+ * File: aiAnalysisAPI.ts
+ * Description: API service for fetching AI analysis using apisauce
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { create } from 'apisauce';
+
+const api = create({
+ baseURL: 'https://api.example.com', // TODO: Replace with actual endpoint
+ timeout: 10000,
+});
+
+/**
+ * getAnalysis - fetches AI analysis for a case
+ */
+export const aiAnalysisAPI = {
+ getAnalysis: (caseId: string) => api.get(`/cases/${caseId}/ai-analysis`),
+ // Add more endpoints as needed
+};
+
+/*
+ * End of File: aiAnalysisAPI.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/services/dicomAPI.ts b/app/modules/CaseReview/services/dicomAPI.ts
new file mode 100644
index 0000000..0705b22
--- /dev/null
+++ b/app/modules/CaseReview/services/dicomAPI.ts
@@ -0,0 +1,27 @@
+/*
+ * File: dicomAPI.ts
+ * Description: API service for fetching DICOM images using apisauce
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { create } from 'apisauce';
+
+const api = create({
+ baseURL: 'https://api.example.com', // TODO: Replace with actual endpoint
+ timeout: 10000,
+});
+
+/**
+ * getImages - fetches DICOM images for a case
+ */
+export const dicomAPI = {
+ getImages: (caseId: string) => api.get(`/cases/${caseId}/dicom`),
+ // Add more endpoints as needed
+};
+
+/*
+ * End of File: dicomAPI.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/services/dicomParser.ts b/app/modules/CaseReview/services/dicomParser.ts
new file mode 100644
index 0000000..377e86e
--- /dev/null
+++ b/app/modules/CaseReview/services/dicomParser.ts
@@ -0,0 +1,22 @@
+/*
+ * File: dicomParser.ts
+ * Description: Utility for parsing DICOM files (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+/**
+ * dicomParser - stub for parsing DICOM files
+ */
+export const dicomParser = {
+ parse: (file: any) => {
+ // TODO: Implement DICOM parsing logic
+ return {};
+ },
+};
+
+/*
+ * End of File: dicomParser.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/services/imageProcessor.ts b/app/modules/CaseReview/services/imageProcessor.ts
new file mode 100644
index 0000000..b26f348
--- /dev/null
+++ b/app/modules/CaseReview/services/imageProcessor.ts
@@ -0,0 +1,22 @@
+/*
+ * File: imageProcessor.ts
+ * Description: Utility for image processing (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+/**
+ * imageProcessor - stub for image processing utilities
+ */
+export const imageProcessor = {
+ process: (image: any) => {
+ // TODO: Implement image processing logic
+ return image;
+ },
+};
+
+/*
+ * End of File: imageProcessor.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/CaseReview/services/index.ts b/app/modules/CaseReview/services/index.ts
new file mode 100644
index 0000000..d7acbc8
--- /dev/null
+++ b/app/modules/CaseReview/services/index.ts
@@ -0,0 +1,17 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for CaseReview services
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export * from './dicomAPI';
+export * from './aiAnalysisAPI';
+export * from './dicomParser';
+export * from './imageProcessor';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/__tests__/CaseQueue.test.tsx b/app/modules/Dashboard/__tests__/CaseQueue.test.tsx
new file mode 100644
index 0000000..e47bc34
--- /dev/null
+++ b/app/modules/Dashboard/__tests__/CaseQueue.test.tsx
@@ -0,0 +1,34 @@
+/*
+ * File: CaseQueue.test.tsx
+ * Description: Test for CaseQueue component
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { render, fireEvent } from '@testing-library/react-native';
+import CaseQueue from '../components/CaseQueue';
+
+const mockCases = [
+ { id: '1', patientName: 'John Doe', status: 'critical', aiConfidence: 93, description: 'Head trauma' },
+ { id: '2', patientName: 'Jane Smith', status: 'routine', aiConfidence: 99, description: 'Headache' },
+];
+
+describe('CaseQueue', () => {
+ it('renders cases', () => {
+ const { getByText } = render( {}} />);
+ expect(getByText('John Doe')).toBeTruthy();
+ expect(getByText('Jane Smith')).toBeTruthy();
+ });
+
+ it('renders empty state', () => {
+ const { getByText } = render( {}} />);
+ expect(getByText('No cases in queue.')).toBeTruthy();
+ });
+});
+
+/*
+ * End of File: CaseQueue.test.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/__tests__/caseAPI.test.ts b/app/modules/Dashboard/__tests__/caseAPI.test.ts
new file mode 100644
index 0000000..bfd8907
--- /dev/null
+++ b/app/modules/Dashboard/__tests__/caseAPI.test.ts
@@ -0,0 +1,26 @@
+/*
+ * File: caseAPI.test.ts
+ * Description: Test for caseAPI service
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { caseAPI } from '../services/caseAPI';
+
+jest.mock('apisauce', () => ({
+ create: () => ({ get: jest.fn(() => Promise.resolve({ ok: true, data: [] })) })
+}));
+
+describe('caseAPI', () => {
+ it('calls getCases and returns data', async () => {
+ const response = await caseAPI.getCases();
+ expect(response.ok).toBe(true);
+ expect(Array.isArray(response.data)).toBe(true);
+ });
+});
+
+/*
+ * End of File: caseAPI.test.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/__tests__/dashboardSlice.test.ts b/app/modules/Dashboard/__tests__/dashboardSlice.test.ts
new file mode 100644
index 0000000..205f5a5
--- /dev/null
+++ b/app/modules/Dashboard/__tests__/dashboardSlice.test.ts
@@ -0,0 +1,37 @@
+/*
+ * File: dashboardSlice.test.ts
+ * Description: Test for dashboardSlice reducer
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import reducer, { fetchCasesSuccess, fetchCasesFailure } from '../redux/dashboardSlice';
+
+const initialState = {
+ caseQueue: [],
+ loading: false,
+ error: null,
+};
+
+describe('dashboardSlice', () => {
+ it('handles fetchCasesSuccess', () => {
+ const cases = [{ id: '1', patientName: 'John Doe', status: 'critical', aiConfidence: 93, description: 'Head trauma' }];
+ const state = reducer(initialState, fetchCasesSuccess(cases));
+ expect(state.caseQueue).toEqual(cases);
+ expect(state.loading).toBe(false);
+ expect(state.error).toBeNull();
+ });
+
+ it('handles fetchCasesFailure', () => {
+ const error = 'Failed to fetch';
+ const state = reducer(initialState, fetchCasesFailure(error));
+ expect(state.loading).toBe(false);
+ expect(state.error).toBe(error);
+ });
+});
+
+/*
+ * End of File: dashboardSlice.test.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/components/CaseCard.tsx b/app/modules/Dashboard/components/CaseCard.tsx
new file mode 100644
index 0000000..7eccf4f
--- /dev/null
+++ b/app/modules/Dashboard/components/CaseCard.tsx
@@ -0,0 +1,78 @@
+/*
+ * File: CaseCard.tsx
+ * Description: Component to display a single case card
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
+import { Card } from 'shared/src/components/Card';
+import { CustomIcon } from 'shared/src/components/Icons';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+import { Case } from '../redux/dashboardSlice';
+
+interface CaseCardProps {
+ item: Case;
+ onPress: (item: Case) => void;
+}
+
+/**
+ * CaseCard - displays a single case card
+ */
+const CaseCard: React.FC = ({ item, onPress }) => (
+ onPress(item)}>
+
+
+
+
+ {item.patientName}
+ {item.description}
+
+ {item.aiConfidence}%
+
+
+
+);
+
+const styles = StyleSheet.create({
+ card: {
+ marginBottom: Spacing.sm,
+ },
+ row: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
+ info: {
+ flex: 1,
+ marginLeft: Spacing.sm,
+ },
+ patient: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textPrimary,
+ },
+ desc: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.sm,
+ color: Colors.textSecondary,
+ },
+ confidence: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.md,
+ color: Colors.info,
+ marginLeft: Spacing.sm,
+ },
+});
+
+export default CaseCard;
+
+/*
+ * End of File: CaseCard.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/components/CaseQueue.tsx b/app/modules/Dashboard/components/CaseQueue.tsx
new file mode 100644
index 0000000..64041e0
--- /dev/null
+++ b/app/modules/Dashboard/components/CaseQueue.tsx
@@ -0,0 +1,95 @@
+/*
+ * File: CaseQueue.tsx
+ * Description: Component to display a list of cases in the queue
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, FlatList, StyleSheet, TouchableOpacity } from 'react-native';
+import { Card, InfoCard } from 'shared/src/components/Card';
+import { CustomIcon } from 'shared/src/components/Icons';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+import { Case } from '../redux/dashboardSlice';
+
+interface CaseQueueProps {
+ cases: Case[];
+ onSelect: (item: Case) => void;
+}
+
+/**
+ * CaseQueue - displays a list of cases in the queue
+ */
+const CaseQueue: React.FC = ({ cases, onSelect }) => {
+ if (!cases.length) {
+ return No cases in queue.;
+ }
+ return (
+ item.id}
+ renderItem={({ item }) => (
+ onSelect(item)}>
+
+
+
+
+ {item.patientName}
+ {item.description}
+
+ {item.aiConfidence}%
+
+
+
+ )}
+ />
+ );
+};
+
+const styles = StyleSheet.create({
+ card: {
+ marginBottom: Spacing.sm,
+ },
+ row: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
+ info: {
+ flex: 1,
+ marginLeft: Spacing.sm,
+ },
+ patient: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textPrimary,
+ },
+ desc: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.sm,
+ color: Colors.textSecondary,
+ },
+ confidence: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.md,
+ color: Colors.info,
+ marginLeft: Spacing.sm,
+ },
+ empty: {
+ textAlign: 'center',
+ color: Colors.textMuted,
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.md,
+ },
+});
+
+export default CaseQueue;
+
+/*
+ * End of File: CaseQueue.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/components/FilterBar.tsx b/app/modules/Dashboard/components/FilterBar.tsx
new file mode 100644
index 0000000..6f30a7d
--- /dev/null
+++ b/app/modules/Dashboard/components/FilterBar.tsx
@@ -0,0 +1,70 @@
+/*
+ * File: FilterBar.tsx
+ * Description: Component to filter cases by status
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, StyleSheet } from 'react-native';
+import { Button } from 'shared/src/components/Button';
+import { Colors, Spacing } from 'shared/src/theme';
+
+interface FilterBarProps {
+ filter: 'critical' | 'urgent' | 'routine';
+ onChange: (filter: 'critical' | 'urgent' | 'routine') => void;
+}
+
+/**
+ * FilterBar - allows filtering cases by status
+ */
+const FilterBar: React.FC = ({ filter, onChange }) => (
+
+
+);
+
+const styles = StyleSheet.create({
+ container: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ marginBottom: Spacing.md,
+ },
+ button: {
+ flex: 1,
+ marginHorizontal: Spacing.xs,
+ backgroundColor: Colors.inactiveState,
+ },
+ selected: {
+ backgroundColor: Colors.selectedState,
+ },
+ selectedText: {
+ color: Colors.background,
+ fontWeight: 'bold',
+ },
+});
+
+export default FilterBar;
+
+/*
+ * End of File: FilterBar.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/components/PriorityIndicator.tsx b/app/modules/Dashboard/components/PriorityIndicator.tsx
new file mode 100644
index 0000000..8baa7ca
--- /dev/null
+++ b/app/modules/Dashboard/components/PriorityIndicator.tsx
@@ -0,0 +1,61 @@
+/*
+ * File: PriorityIndicator.tsx
+ * Description: Component to display a colored dot and label for case priority
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, StyleSheet } from 'react-native';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+
+interface PriorityIndicatorProps {
+ status: 'critical' | 'urgent' | 'routine';
+}
+
+/**
+ * PriorityIndicator - displays a colored dot and label for case priority
+ */
+export const PriorityIndicator: React.FC = ({ status }) => {
+ const color =
+ status === 'critical'
+ ? Colors.error
+ : status === 'urgent'
+ ? Colors.warning
+ : Colors.success;
+ const label =
+ status === 'critical'
+ ? 'Critical'
+ : status === 'urgent'
+ ? 'Urgent'
+ : 'Routine';
+ return (
+
+
+ {label}
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
+ dot: {
+ width: 10,
+ height: 10,
+ borderRadius: 5,
+ marginRight: Spacing.xs,
+ },
+ label: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.sm,
+ },
+});
+
+/*
+ * End of File: PriorityIndicator.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/components/StatsPanel.tsx b/app/modules/Dashboard/components/StatsPanel.tsx
new file mode 100644
index 0000000..ad96e2b
--- /dev/null
+++ b/app/modules/Dashboard/components/StatsPanel.tsx
@@ -0,0 +1,70 @@
+/*
+ * File: StatsPanel.tsx
+ * Description: Component to display dashboard statistics (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, StyleSheet } from 'react-native';
+import { Card } from 'shared/src/components/Card';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+
+interface StatsPanelProps {
+ stats: { label: string; value: string | number }[];
+}
+
+/**
+ * StatsPanel - displays dashboard statistics (stub)
+ */
+const StatsPanel: React.FC = ({ stats }) => (
+
+ Statistics
+
+ {stats.map((stat, idx) => (
+
+ {stat.value}
+ {stat.label}
+
+ ))}
+
+
+);
+
+const styles = StyleSheet.create({
+ card: {
+ marginBottom: Spacing.md,
+ },
+ title: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textPrimary,
+ marginBottom: Spacing.sm,
+ },
+ statsRow: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ },
+ statItem: {
+ alignItems: 'center',
+ flex: 1,
+ },
+ statValue: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.lg,
+ color: Colors.primary,
+ },
+ statLabel: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.sm,
+ color: Colors.textSecondary,
+ },
+});
+
+export default StatsPanel;
+
+/*
+ * End of File: StatsPanel.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/components/index.ts b/app/modules/Dashboard/components/index.ts
new file mode 100644
index 0000000..f759f3f
--- /dev/null
+++ b/app/modules/Dashboard/components/index.ts
@@ -0,0 +1,18 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Dashboard components
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as CaseQueue } from './CaseQueue';
+export { default as CaseCard } from './CaseCard';
+export { PriorityIndicator } from './PriorityIndicator';
+export { default as StatsPanel } from './StatsPanel';
+export { default as FilterBar } from './FilterBar';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/hooks/index.ts b/app/modules/Dashboard/hooks/index.ts
new file mode 100644
index 0000000..fd24caf
--- /dev/null
+++ b/app/modules/Dashboard/hooks/index.ts
@@ -0,0 +1,16 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Dashboard hooks
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export * from './useCaseQueue';
+export * from './useRealTimeUpdates';
+export * from './useFilterCases';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/hooks/useCaseQueue.ts b/app/modules/Dashboard/hooks/useCaseQueue.ts
new file mode 100644
index 0000000..04aae78
--- /dev/null
+++ b/app/modules/Dashboard/hooks/useCaseQueue.ts
@@ -0,0 +1,22 @@
+/*
+ * File: useCaseQueue.ts
+ * Description: Custom hook for accessing the case queue from redux
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { useSelector } from 'react-redux';
+import { selectCaseQueue } from '../redux/dashboardSelectors';
+
+/**
+ * useCaseQueue - returns the current case queue from redux state
+ */
+export const useCaseQueue = () => {
+ return useSelector(selectCaseQueue);
+};
+
+/*
+ * End of File: useCaseQueue.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/hooks/useFilterCases.ts b/app/modules/Dashboard/hooks/useFilterCases.ts
new file mode 100644
index 0000000..945ff98
--- /dev/null
+++ b/app/modules/Dashboard/hooks/useFilterCases.ts
@@ -0,0 +1,22 @@
+/*
+ * File: useFilterCases.ts
+ * Description: Custom hook for filtering cases by status
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { useMemo } from 'react';
+import { Case } from '../redux/dashboardSlice';
+
+/**
+ * useFilterCases - returns filtered cases by status
+ */
+export const useFilterCases = (cases: Case[], status: 'critical' | 'urgent' | 'routine') => {
+ return useMemo(() => cases.filter(c => c.status === status), [cases, status]);
+};
+
+/*
+ * End of File: useFilterCases.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/hooks/useRealTimeUpdates.ts b/app/modules/Dashboard/hooks/useRealTimeUpdates.ts
new file mode 100644
index 0000000..a8b2a46
--- /dev/null
+++ b/app/modules/Dashboard/hooks/useRealTimeUpdates.ts
@@ -0,0 +1,27 @@
+/*
+ * File: useRealTimeUpdates.ts
+ * Description: Custom hook for subscribing to real-time updates (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { useEffect } from 'react';
+
+/**
+ * useRealTimeUpdates - subscribes to real-time updates (stub)
+ */
+export const useRealTimeUpdates = () => {
+ useEffect(() => {
+ // TODO: Connect to websocket and handle updates
+ // Example: websocketService.subscribe(...)
+ return () => {
+ // Cleanup subscription
+ };
+ }, []);
+};
+
+/*
+ * End of File: useRealTimeUpdates.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/navigation/DashboardNavigator.tsx b/app/modules/Dashboard/navigation/DashboardNavigator.tsx
new file mode 100644
index 0000000..e493c25
--- /dev/null
+++ b/app/modules/Dashboard/navigation/DashboardNavigator.tsx
@@ -0,0 +1,47 @@
+/*
+ * File: DashboardNavigator.tsx
+ * Description: Stack navigator for Dashboard module
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { createStackNavigator } from '@react-navigation/stack';
+import { DashboardScreen } from '../screens';
+import { Colors } from 'shared/src/theme';
+
+export type DashboardStackParamList = {
+ Dashboard: undefined;
+ // Add more screens here as needed
+};
+
+const Stack = createStackNavigator();
+
+/**
+ * DashboardNavigator sets up stack navigation for Dashboard module
+ */
+const DashboardNavigator: React.FC = () => (
+
+
+ {/* Add more screens here */}
+
+);
+
+export default DashboardNavigator;
+
+/*
+ * End of File: DashboardNavigator.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/navigation/index.ts b/app/modules/Dashboard/navigation/index.ts
new file mode 100644
index 0000000..645ddca
--- /dev/null
+++ b/app/modules/Dashboard/navigation/index.ts
@@ -0,0 +1,14 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Dashboard navigation
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as DashboardNavigator } from './DashboardNavigator';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/redux/caseQueueSlice.ts b/app/modules/Dashboard/redux/caseQueueSlice.ts
new file mode 100644
index 0000000..4086fc2
--- /dev/null
+++ b/app/modules/Dashboard/redux/caseQueueSlice.ts
@@ -0,0 +1,61 @@
+/*
+ * File: caseQueueSlice.ts
+ * Description: Redux slice for case queue state management
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+import { Case } from './dashboardSlice';
+
+interface CaseQueueState {
+ queue: Case[];
+ loading: boolean;
+ error: string | null;
+}
+
+const initialState: CaseQueueState = {
+ queue: [],
+ loading: false,
+ error: null,
+};
+
+/**
+ * Slice for managing the case queue
+ */
+const caseQueueSlice = createSlice({
+ name: 'caseQueue',
+ initialState,
+ reducers: {
+ fetchQueueStart(state) {
+ state.loading = true;
+ state.error = null;
+ },
+ fetchQueueSuccess(state, action: PayloadAction) {
+ state.queue = action.payload;
+ state.loading = false;
+ },
+ fetchQueueFailure(state, action: PayloadAction) {
+ state.loading = false;
+ state.error = action.payload;
+ },
+ clearQueue(state) {
+ state.queue = [];
+ },
+ },
+});
+
+export const {
+ fetchQueueStart,
+ fetchQueueSuccess,
+ fetchQueueFailure,
+ clearQueue,
+} = caseQueueSlice.actions;
+
+export default caseQueueSlice.reducer;
+
+/*
+ * End of File: caseQueueSlice.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/redux/dashboardActions.ts b/app/modules/Dashboard/redux/dashboardActions.ts
new file mode 100644
index 0000000..60e80ba
--- /dev/null
+++ b/app/modules/Dashboard/redux/dashboardActions.ts
@@ -0,0 +1,38 @@
+/*
+ * File: dashboardActions.ts
+ * Description: Async actions (thunks) for Dashboard state
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { createAsyncThunk } from '@reduxjs/toolkit';
+import { fetchCasesStart, fetchCasesSuccess, fetchCasesFailure } from './dashboardSlice';
+import { caseAPI } from '../services/caseAPI';
+
+/**
+ * Thunk to fetch case queue from API
+ */
+export const fetchCases = createAsyncThunk(
+ 'dashboard/fetchCases',
+ async (_, { dispatch, rejectWithValue }) => {
+ try {
+ dispatch(fetchCasesStart());
+ const response = await caseAPI.getCases();
+ if (response.ok && response.data) {
+ dispatch(fetchCasesSuccess(response.data));
+ } else {
+ dispatch(fetchCasesFailure(response.problem || 'Unknown error'));
+ return rejectWithValue(response.problem || 'Unknown error');
+ }
+ } catch (error: any) {
+ dispatch(fetchCasesFailure(error.message));
+ return rejectWithValue(error.message);
+ }
+ }
+);
+
+/*
+ * End of File: dashboardActions.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/redux/dashboardSelectors.ts b/app/modules/Dashboard/redux/dashboardSelectors.ts
new file mode 100644
index 0000000..3a9d462
--- /dev/null
+++ b/app/modules/Dashboard/redux/dashboardSelectors.ts
@@ -0,0 +1,18 @@
+/*
+ * File: dashboardSelectors.ts
+ * Description: Selectors for Dashboard redux state
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { RootState } from 'app/redux/rootReducer';
+
+export const selectCaseQueue = (state: RootState) => state.dashboard.caseQueue;
+export const selectDashboardLoading = (state: RootState) => state.dashboard.loading;
+export const selectDashboardError = (state: RootState) => state.dashboard.error;
+
+/*
+ * End of File: dashboardSelectors.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/redux/dashboardSlice.ts b/app/modules/Dashboard/redux/dashboardSlice.ts
new file mode 100644
index 0000000..ea88f17
--- /dev/null
+++ b/app/modules/Dashboard/redux/dashboardSlice.ts
@@ -0,0 +1,70 @@
+/*
+ * File: dashboardSlice.ts
+ * Description: Redux slice for Dashboard state management
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+
+// Sample case type
+export interface Case {
+ id: string;
+ patientName: string;
+ status: 'critical' | 'urgent' | 'routine';
+ aiConfidence: number;
+ description: string;
+}
+
+// Dashboard state type
+interface DashboardState {
+ caseQueue: Case[];
+ loading: boolean;
+ error: string | null;
+}
+
+const initialState: DashboardState = {
+ caseQueue: [],
+ loading: false,
+ error: null,
+};
+
+/**
+ * Dashboard slice for managing case queue and dashboard state
+ */
+const dashboardSlice = createSlice({
+ name: 'dashboard',
+ initialState,
+ reducers: {
+ fetchCasesStart(state) {
+ state.loading = true;
+ state.error = null;
+ },
+ fetchCasesSuccess(state, action: PayloadAction) {
+ state.caseQueue = action.payload;
+ state.loading = false;
+ },
+ fetchCasesFailure(state, action: PayloadAction) {
+ state.loading = false;
+ state.error = action.payload;
+ },
+ clearCases(state) {
+ state.caseQueue = [];
+ },
+ },
+});
+
+export const {
+ fetchCasesStart,
+ fetchCasesSuccess,
+ fetchCasesFailure,
+ clearCases,
+} = dashboardSlice.actions;
+
+export default dashboardSlice.reducer;
+
+/*
+ * End of File: dashboardSlice.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/redux/index.ts b/app/modules/Dashboard/redux/index.ts
new file mode 100644
index 0000000..672b141
--- /dev/null
+++ b/app/modules/Dashboard/redux/index.ts
@@ -0,0 +1,16 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Dashboard redux
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as dashboardReducer } from './dashboardSlice';
+export * from './dashboardActions';
+export * from './dashboardSelectors';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/screens/DashboardScreen.tsx b/app/modules/Dashboard/screens/DashboardScreen.tsx
new file mode 100644
index 0000000..3acaa22
--- /dev/null
+++ b/app/modules/Dashboard/screens/DashboardScreen.tsx
@@ -0,0 +1,175 @@
+/*
+ * File: DashboardScreen.tsx
+ * Description: Sample dashboard screen using Clinical Blue Interface and shared components
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React, { useState } from 'react';
+import { View, Text, StyleSheet, ScrollView } from 'react-native';
+import { Button } from 'shared/src/components/Button';
+import { Card, InfoCard } from 'shared/src/components/Card';
+import { TextInput, SearchInput } from 'shared/src/components/Input';
+import { Modal, ConfirmModal, AlertModal } from 'shared/src/components/Modal';
+import { Spinner, LoadingOverlay } from 'shared/src/components/Loading';
+import { CustomIcon, IconButton } from 'shared/src/components/Icons';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+
+/**
+ * DashboardScreen demonstrates usage of all shared, themed components.
+ * This is a reference implementation for other modules.
+ */
+const DashboardScreen: React.FC = () => {
+ const [modalVisible, setModalVisible] = useState(false);
+ const [confirmVisible, setConfirmVisible] = useState(false);
+ const [alertVisible, setAlertVisible] = useState(false);
+ const [loading, setLoading] = useState(false);
+ const [search, setSearch] = useState('');
+ const [input, setInput] = useState('');
+
+ return (
+
+ Dashboard
+
+
+ Welcome, Dr. Smith
+ On-Call Status: ACTIVE
+
+
+ Critical Cases
+
+
+ Bed 3 - Hemorrhage (93% AI)
+ setModalVisible(true)} style={styles.button} />
+
+
+
+ Routine Cases
+
+
+ Bed 12 - Headache (99% AI)
+ setConfirmVisible(true)} />
+
+
+
+ setAlertVisible(true)} style={styles.button} />
+ setLoading(true)} style={styles.button} />
+
+ {/* Modals */}
+ setModalVisible(false)}>
+ Critical Case Details
+ Patient: John Doe, 45M
+ setModalVisible(false)} style={styles.button} />
+
+ { setConfirmVisible(false); }}
+ onCancel={() => setConfirmVisible(false)}
+ />
+ setAlertVisible(false)}
+ />
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: Colors.background,
+ },
+ content: {
+ padding: Spacing.lg,
+ },
+ header: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.title,
+ color: Colors.primary,
+ marginBottom: Spacing.lg,
+ textAlign: 'center',
+ },
+ search: {
+ marginBottom: Spacing.md,
+ },
+ infoTitle: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.lg,
+ color: Colors.textPrimary,
+ marginBottom: Spacing.xs,
+ },
+ infoText: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textSecondary,
+ },
+ active: {
+ color: Colors.success,
+ fontWeight: 'bold',
+ },
+ cardTitle: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textPrimary,
+ marginBottom: Spacing.sm,
+ },
+ row: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ marginBottom: Spacing.sm,
+ },
+ criticalText: {
+ color: Colors.error,
+ flex: 1,
+ marginLeft: Spacing.sm,
+ fontFamily: Typography.fontFamily.regular,
+ },
+ routineText: {
+ color: Colors.success,
+ flex: 1,
+ marginLeft: Spacing.sm,
+ fontFamily: Typography.fontFamily.regular,
+ },
+ button: {
+ marginLeft: Spacing.sm,
+ },
+ input: {
+ marginVertical: Spacing.md,
+ },
+ spinner: {
+ marginVertical: Spacing.md,
+ },
+ modalTitle: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.lg,
+ color: Colors.primary,
+ marginBottom: Spacing.md,
+ textAlign: 'center',
+ },
+});
+
+export default DashboardScreen;
+
+/*
+ * End of File: DashboardScreen.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/screens/index.ts b/app/modules/Dashboard/screens/index.ts
new file mode 100644
index 0000000..597cc4c
--- /dev/null
+++ b/app/modules/Dashboard/screens/index.ts
@@ -0,0 +1,14 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Dashboard screens
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as DashboardScreen } from './DashboardScreen';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/services/caseAPI.ts b/app/modules/Dashboard/services/caseAPI.ts
new file mode 100644
index 0000000..4e71e5a
--- /dev/null
+++ b/app/modules/Dashboard/services/caseAPI.ts
@@ -0,0 +1,27 @@
+/*
+ * File: caseAPI.ts
+ * Description: API service for fetching cases using apisauce
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { create } from 'apisauce';
+
+const api = create({
+ baseURL: 'https://api.example.com', // TODO: Replace with actual endpoint
+ timeout: 10000,
+});
+
+/**
+ * getCases - fetches the list of cases from the server
+ */
+export const caseAPI = {
+ getCases: () => api.get('/cases'),
+ // Add more endpoints as needed
+};
+
+/*
+ * End of File: caseAPI.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/services/index.ts b/app/modules/Dashboard/services/index.ts
new file mode 100644
index 0000000..b73d4dc
--- /dev/null
+++ b/app/modules/Dashboard/services/index.ts
@@ -0,0 +1,16 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Dashboard services
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export * from './caseAPI';
+export * from './websocketService';
+export * from './notificationService';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/services/notificationService.ts b/app/modules/Dashboard/services/notificationService.ts
new file mode 100644
index 0000000..d6f9297
--- /dev/null
+++ b/app/modules/Dashboard/services/notificationService.ts
@@ -0,0 +1,20 @@
+/*
+ * File: notificationService.ts
+ * Description: Service for sending notifications (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+// Stub for notification service
+export const notificationService = {
+ sendNotification: (title: string, message: string) => {
+ // TODO: Implement notification logic
+ // Example: PushNotification.localNotification({ title, message })
+ },
+};
+
+/*
+ * End of File: notificationService.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Dashboard/services/websocketService.ts b/app/modules/Dashboard/services/websocketService.ts
new file mode 100644
index 0000000..994f0a8
--- /dev/null
+++ b/app/modules/Dashboard/services/websocketService.ts
@@ -0,0 +1,25 @@
+/*
+ * File: websocketService.ts
+ * Description: Service for real-time websocket updates (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+// Stub for websocket connection
+class WebsocketService {
+ subscribe(callback: (data: any) => void) {
+ // TODO: Implement websocket subscription
+ // Example: ws.onmessage = (event) => callback(event.data)
+ }
+ unsubscribe() {
+ // TODO: Implement unsubscribe logic
+ }
+}
+
+export const websocketService = new WebsocketService();
+
+/*
+ * End of File: websocketService.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/__tests__/ProfileHeader.test.tsx b/app/modules/Profile/__tests__/ProfileHeader.test.tsx
new file mode 100644
index 0000000..6ee04b3
--- /dev/null
+++ b/app/modules/Profile/__tests__/ProfileHeader.test.tsx
@@ -0,0 +1,25 @@
+/*
+ * File: ProfileHeader.test.tsx
+ * Description: Test for ProfileHeader component
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { render } from '@testing-library/react-native';
+import ProfileHeader from '../components/ProfileHeader';
+
+describe('ProfileHeader', () => {
+ it('renders avatar and name', () => {
+ const { getByText } = render(
+
+ );
+ expect(getByText('Dr. Smith')).toBeTruthy();
+ });
+});
+
+/*
+ * End of File: ProfileHeader.test.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/__tests__/profileAPI.test.ts b/app/modules/Profile/__tests__/profileAPI.test.ts
new file mode 100644
index 0000000..bb9ea56
--- /dev/null
+++ b/app/modules/Profile/__tests__/profileAPI.test.ts
@@ -0,0 +1,26 @@
+/*
+ * File: profileAPI.test.ts
+ * Description: Test for profileAPI service
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { profileAPI } from '../services/profileAPI';
+
+jest.mock('apisauce', () => ({
+ create: () => ({ get: jest.fn(() => Promise.resolve({ ok: true, data: { id: '1', name: 'Dr. Smith', email: 'dr@hospital.com' } })) })
+}));
+
+describe('profileAPI', () => {
+ it('calls getProfile and returns data', async () => {
+ const response = await profileAPI.getProfile('1');
+ expect(response.ok).toBe(true);
+ expect(response.data).toHaveProperty('email', 'dr@hospital.com');
+ });
+});
+
+/*
+ * End of File: profileAPI.test.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/__tests__/profileSlice.test.ts b/app/modules/Profile/__tests__/profileSlice.test.ts
new file mode 100644
index 0000000..0e16047
--- /dev/null
+++ b/app/modules/Profile/__tests__/profileSlice.test.ts
@@ -0,0 +1,37 @@
+/*
+ * File: profileSlice.test.ts
+ * Description: Test for profileSlice reducer
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import reducer, { fetchProfileSuccess, fetchProfileFailure, UserProfile } from '../redux/profileSlice';
+
+const initialState = {
+ userProfile: null,
+ loading: false,
+ error: null,
+};
+
+describe('profileSlice', () => {
+ it('handles fetchProfileSuccess', () => {
+ const user: UserProfile = { id: '1', name: 'Dr. Smith', email: 'dr@hospital.com' };
+ const state = reducer(initialState, fetchProfileSuccess(user));
+ expect(state.userProfile).toEqual(user);
+ expect(state.loading).toBe(false);
+ expect(state.error).toBeNull();
+ });
+
+ it('handles fetchProfileFailure', () => {
+ const error = 'Failed to fetch';
+ const state = reducer(initialState, fetchProfileFailure(error));
+ expect(state.loading).toBe(false);
+ expect(state.error).toBe(error);
+ });
+});
+
+/*
+ * End of File: profileSlice.test.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/components/PreferencesForm.tsx b/app/modules/Profile/components/PreferencesForm.tsx
new file mode 100644
index 0000000..ada5d76
--- /dev/null
+++ b/app/modules/Profile/components/PreferencesForm.tsx
@@ -0,0 +1,55 @@
+/*
+ * File: PreferencesForm.tsx
+ * Description: Component for user preferences form (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, StyleSheet } from 'react-native';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+
+interface PreferencesFormProps {
+ preferences: any;
+ onChange: (changes: any) => void;
+}
+
+/**
+ * PreferencesForm - displays user preferences form (stub)
+ */
+const PreferencesForm: React.FC = ({ preferences, onChange }) => (
+
+ Preferences
+ [Preferences Form Fields Here]
+
+);
+
+const styles = StyleSheet.create({
+ container: {
+ padding: Spacing.md,
+ backgroundColor: Colors.backgroundAlt,
+ borderRadius: 8,
+ },
+ title: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.md,
+ color: Colors.primary,
+ marginBottom: Spacing.md,
+ textAlign: 'center',
+ },
+ stub: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textSecondary,
+ textAlign: 'center',
+ marginTop: Spacing.lg,
+ },
+});
+
+export default PreferencesForm;
+
+/*
+ * End of File: PreferencesForm.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/components/ProfileHeader.tsx b/app/modules/Profile/components/ProfileHeader.tsx
new file mode 100644
index 0000000..092b471
--- /dev/null
+++ b/app/modules/Profile/components/ProfileHeader.tsx
@@ -0,0 +1,50 @@
+/*
+ * File: ProfileHeader.tsx
+ * Description: Component for displaying user avatar and name
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, Image, StyleSheet } from 'react-native';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+
+interface ProfileHeaderProps {
+ user: { name: string; avatar?: string };
+}
+
+/**
+ * ProfileHeader - displays user avatar and name
+ */
+const ProfileHeader: React.FC = ({ user }) => (
+
+ {user.avatar && }
+ {user.name}
+
+);
+
+const styles = StyleSheet.create({
+ container: {
+ alignItems: 'center',
+ marginBottom: Spacing.md,
+ },
+ avatar: {
+ width: 64,
+ height: 64,
+ borderRadius: 32,
+ marginBottom: Spacing.sm,
+ },
+ name: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.lg,
+ color: Colors.primary,
+ },
+});
+
+export default ProfileHeader;
+
+/*
+ * End of File: ProfileHeader.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/components/SecuritySettings.tsx b/app/modules/Profile/components/SecuritySettings.tsx
new file mode 100644
index 0000000..12e97e3
--- /dev/null
+++ b/app/modules/Profile/components/SecuritySettings.tsx
@@ -0,0 +1,55 @@
+/*
+ * File: SecuritySettings.tsx
+ * Description: Component for user security settings (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, StyleSheet } from 'react-native';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+
+interface SecuritySettingsProps {
+ security: any;
+ onChange: (changes: any) => void;
+}
+
+/**
+ * SecuritySettings - displays user security settings (stub)
+ */
+const SecuritySettings: React.FC = ({ security, onChange }) => (
+
+ Security Settings
+ [Security Options Here]
+
+);
+
+const styles = StyleSheet.create({
+ container: {
+ padding: Spacing.md,
+ backgroundColor: Colors.backgroundAlt,
+ borderRadius: 8,
+ },
+ title: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.md,
+ color: Colors.primary,
+ marginBottom: Spacing.md,
+ textAlign: 'center',
+ },
+ stub: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textSecondary,
+ textAlign: 'center',
+ marginTop: Spacing.lg,
+ },
+});
+
+export default SecuritySettings;
+
+/*
+ * End of File: SecuritySettings.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/components/SettingsPanel.tsx b/app/modules/Profile/components/SettingsPanel.tsx
new file mode 100644
index 0000000..b2c65fb
--- /dev/null
+++ b/app/modules/Profile/components/SettingsPanel.tsx
@@ -0,0 +1,75 @@
+/*
+ * File: SettingsPanel.tsx
+ * Description: Component for displaying and toggling user settings (stub)
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, StyleSheet, Switch } from 'react-native';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+
+interface SettingsPanelProps {
+ settings: { notificationsEnabled: boolean; darkMode: boolean; language: string };
+ onChange: (changes: Partial) => void;
+}
+
+/**
+ * SettingsPanel - displays and toggles user settings (stub)
+ */
+const SettingsPanel: React.FC = ({ settings, onChange }) => (
+
+ Settings
+
+ Notifications
+ onChange({ notificationsEnabled: v })} />
+
+
+ Dark Mode
+ onChange({ darkMode: v })} />
+
+
+ Language
+ {settings.language}
+
+
+);
+
+const styles = StyleSheet.create({
+ container: {
+ padding: Spacing.md,
+ backgroundColor: Colors.backgroundAlt,
+ borderRadius: 8,
+ },
+ title: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.md,
+ color: Colors.primary,
+ marginBottom: Spacing.md,
+ textAlign: 'center',
+ },
+ row: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ marginBottom: Spacing.md,
+ },
+ label: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textPrimary,
+ },
+ value: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textSecondary,
+ },
+});
+
+export default SettingsPanel;
+
+/*
+ * End of File: SettingsPanel.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/components/index.ts b/app/modules/Profile/components/index.ts
new file mode 100644
index 0000000..b5e2382
--- /dev/null
+++ b/app/modules/Profile/components/index.ts
@@ -0,0 +1,17 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Profile components
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as ProfileHeader } from './ProfileHeader';
+export { default as SettingsPanel } from './SettingsPanel';
+export { default as PreferencesForm } from './PreferencesForm';
+export { default as SecuritySettings } from './SecuritySettings';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/hooks/index.ts b/app/modules/Profile/hooks/index.ts
new file mode 100644
index 0000000..431f636
--- /dev/null
+++ b/app/modules/Profile/hooks/index.ts
@@ -0,0 +1,15 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Profile hooks
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export * from './useProfile';
+export * from './useSettings';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/hooks/useProfile.ts b/app/modules/Profile/hooks/useProfile.ts
new file mode 100644
index 0000000..4ff9d86
--- /dev/null
+++ b/app/modules/Profile/hooks/useProfile.ts
@@ -0,0 +1,22 @@
+/*
+ * File: useProfile.ts
+ * Description: Custom hook for accessing user profile from redux
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { useSelector } from 'react-redux';
+import { selectUserProfile } from '../redux/profileSelectors';
+
+/**
+ * useProfile - returns the current user profile from redux state
+ */
+export const useProfile = () => {
+ return useSelector(selectUserProfile);
+};
+
+/*
+ * End of File: useProfile.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/hooks/useSettings.ts b/app/modules/Profile/hooks/useSettings.ts
new file mode 100644
index 0000000..db2b931
--- /dev/null
+++ b/app/modules/Profile/hooks/useSettings.ts
@@ -0,0 +1,22 @@
+/*
+ * File: useSettings.ts
+ * Description: Custom hook for accessing user settings from redux
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { useSelector } from 'react-redux';
+import { selectUserSettings } from '../redux/profileSelectors';
+
+/**
+ * useSettings - returns the current user settings from redux state
+ */
+export const useSettings = () => {
+ return useSelector(selectUserSettings);
+};
+
+/*
+ * End of File: useSettings.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/navigation/ProfileNavigator.tsx b/app/modules/Profile/navigation/ProfileNavigator.tsx
new file mode 100644
index 0000000..8dfce43
--- /dev/null
+++ b/app/modules/Profile/navigation/ProfileNavigator.tsx
@@ -0,0 +1,57 @@
+/*
+ * File: ProfileNavigator.tsx
+ * Description: Stack navigator for Profile module
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { createStackNavigator } from '@react-navigation/stack';
+import { ProfileScreen, SettingsScreen, PreferencesScreen } from '../screens';
+import { Colors } from 'shared/src/theme';
+
+export type ProfileStackParamList = {
+ Profile: undefined;
+ Settings: undefined;
+ Preferences: undefined;
+};
+
+const Stack = createStackNavigator();
+
+/**
+ * ProfileNavigator sets up stack navigation for Profile module
+ */
+const ProfileNavigator: React.FC = () => (
+
+
+
+
+
+);
+
+export default ProfileNavigator;
+
+/*
+ * End of File: ProfileNavigator.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/navigation/index.ts b/app/modules/Profile/navigation/index.ts
new file mode 100644
index 0000000..9031afe
--- /dev/null
+++ b/app/modules/Profile/navigation/index.ts
@@ -0,0 +1,14 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Profile navigation
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as ProfileNavigator } from './ProfileNavigator';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/redux/index.ts b/app/modules/Profile/redux/index.ts
new file mode 100644
index 0000000..e944443
--- /dev/null
+++ b/app/modules/Profile/redux/index.ts
@@ -0,0 +1,17 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Profile redux
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as profileReducer } from './profileSlice';
+export { default as settingsReducer } from './settingsSlice';
+export * from './profileActions';
+export * from './profileSelectors';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/redux/profileActions.ts b/app/modules/Profile/redux/profileActions.ts
new file mode 100644
index 0000000..8bde495
--- /dev/null
+++ b/app/modules/Profile/redux/profileActions.ts
@@ -0,0 +1,38 @@
+/*
+ * File: profileActions.ts
+ * Description: Async actions (thunks) for Profile state
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { createAsyncThunk } from '@reduxjs/toolkit';
+import { fetchProfileStart, fetchProfileSuccess, fetchProfileFailure } from './profileSlice';
+import { profileAPI } from '../services/profileAPI';
+
+/**
+ * Thunk to fetch user profile from API
+ */
+export const fetchProfile = createAsyncThunk(
+ 'profile/fetchProfile',
+ async (userId: string, { dispatch, rejectWithValue }) => {
+ try {
+ dispatch(fetchProfileStart());
+ const response = await profileAPI.getProfile(userId);
+ if (response.ok && response.data) {
+ dispatch(fetchProfileSuccess(response.data));
+ } else {
+ dispatch(fetchProfileFailure(response.problem || 'Unknown error'));
+ return rejectWithValue(response.problem || 'Unknown error');
+ }
+ } catch (error: any) {
+ dispatch(fetchProfileFailure(error.message));
+ return rejectWithValue(error.message);
+ }
+ }
+);
+
+/*
+ * End of File: profileActions.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/redux/profileSelectors.ts b/app/modules/Profile/redux/profileSelectors.ts
new file mode 100644
index 0000000..f9ac272
--- /dev/null
+++ b/app/modules/Profile/redux/profileSelectors.ts
@@ -0,0 +1,19 @@
+/*
+ * File: profileSelectors.ts
+ * Description: Selectors for Profile redux state
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { RootState } from 'app/redux/rootReducer';
+
+export const selectUserProfile = (state: RootState) => state.profile.userProfile;
+export const selectProfileLoading = (state: RootState) => state.profile.loading;
+export const selectProfileError = (state: RootState) => state.profile.error;
+export const selectUserSettings = (state: RootState) => state.settings.settings;
+
+/*
+ * End of File: profileSelectors.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/redux/profileSlice.ts b/app/modules/Profile/redux/profileSlice.ts
new file mode 100644
index 0000000..ace93db
--- /dev/null
+++ b/app/modules/Profile/redux/profileSlice.ts
@@ -0,0 +1,76 @@
+/*
+ * File: profileSlice.ts
+ * Description: Redux slice for Profile state management
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+
+// Sample user profile type
+export interface UserProfile {
+ id: string;
+ name: string;
+ email: string;
+ avatar?: string;
+ role?: string;
+}
+
+// Profile state type
+interface ProfileState {
+ userProfile: UserProfile | null;
+ loading: boolean;
+ error: string | null;
+}
+
+const initialState: ProfileState = {
+ userProfile: null,
+ loading: false,
+ error: null,
+};
+
+/**
+ * Profile slice for managing user profile state
+ */
+const profileSlice = createSlice({
+ name: 'profile',
+ initialState,
+ reducers: {
+ fetchProfileStart(state) {
+ state.loading = true;
+ state.error = null;
+ },
+ fetchProfileSuccess(state, action: PayloadAction) {
+ state.userProfile = action.payload;
+ state.loading = false;
+ },
+ fetchProfileFailure(state, action: PayloadAction) {
+ state.loading = false;
+ state.error = action.payload;
+ },
+ updateProfile(state, action: PayloadAction>) {
+ if (state.userProfile) {
+ state.userProfile = { ...state.userProfile, ...action.payload };
+ }
+ },
+ clearProfile(state) {
+ state.userProfile = null;
+ },
+ },
+});
+
+export const {
+ fetchProfileStart,
+ fetchProfileSuccess,
+ fetchProfileFailure,
+ updateProfile,
+ clearProfile,
+} = profileSlice.actions;
+
+export default profileSlice.reducer;
+
+/*
+ * End of File: profileSlice.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/redux/settingsSlice.ts b/app/modules/Profile/redux/settingsSlice.ts
new file mode 100644
index 0000000..e44f2bb
--- /dev/null
+++ b/app/modules/Profile/redux/settingsSlice.ts
@@ -0,0 +1,63 @@
+/*
+ * File: settingsSlice.ts
+ * Description: Redux slice for user settings state management
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+
+export interface UserSettings {
+ notificationsEnabled: boolean;
+ darkMode: boolean;
+ language: string;
+}
+
+interface SettingsState {
+ settings: UserSettings;
+ loading: boolean;
+ error: string | null;
+}
+
+const initialState: SettingsState = {
+ settings: {
+ notificationsEnabled: true,
+ darkMode: false,
+ language: 'en',
+ },
+ loading: false,
+ error: null,
+};
+
+/**
+ * settingsSlice for managing user settings
+ */
+const settingsSlice = createSlice({
+ name: 'settings',
+ initialState,
+ reducers: {
+ updateSettings(state, action: PayloadAction>) {
+ state.settings = { ...state.settings, ...action.payload };
+ },
+ setSettingsLoading(state, action: PayloadAction) {
+ state.loading = action.payload;
+ },
+ setSettingsError(state, action: PayloadAction) {
+ state.error = action.payload;
+ },
+ },
+});
+
+export const {
+ updateSettings,
+ setSettingsLoading,
+ setSettingsError,
+} = settingsSlice.actions;
+
+export default settingsSlice.reducer;
+
+/*
+ * End of File: settingsSlice.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/screens/PreferencesScreen.tsx b/app/modules/Profile/screens/PreferencesScreen.tsx
new file mode 100644
index 0000000..41cfe53
--- /dev/null
+++ b/app/modules/Profile/screens/PreferencesScreen.tsx
@@ -0,0 +1,56 @@
+/*
+ * File: PreferencesScreen.tsx
+ * Description: Screen for user preferences
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, StyleSheet } from 'react-native';
+import { Card } from 'shared/src/components/Card';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+
+/**
+ * PreferencesScreen - shows stub content for preferences form
+ */
+const PreferencesScreen: React.FC = () => {
+ return (
+
+
+ Preferences
+ [Preferences Form Here]
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: Colors.background,
+ justifyContent: 'center',
+ padding: Spacing.lg,
+ },
+ title: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.lg,
+ color: Colors.primary,
+ marginBottom: Spacing.md,
+ textAlign: 'center',
+ },
+ stub: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textSecondary,
+ textAlign: 'center',
+ marginTop: Spacing.lg,
+ },
+});
+
+export default PreferencesScreen;
+
+/*
+ * End of File: PreferencesScreen.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/screens/ProfileScreen.tsx b/app/modules/Profile/screens/ProfileScreen.tsx
new file mode 100644
index 0000000..70315a5
--- /dev/null
+++ b/app/modules/Profile/screens/ProfileScreen.tsx
@@ -0,0 +1,77 @@
+/*
+ * File: ProfileScreen.tsx
+ * Description: Screen for displaying user profile
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, StyleSheet, Image } from 'react-native';
+import { Button } from 'shared/src/components/Button';
+import { Card } from 'shared/src/components/Card';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+import { useProfile } from '../hooks/useProfile';
+
+/**
+ * ProfileScreen - shows user info, avatar, and navigation to settings/preferences
+ */
+const ProfileScreen: React.FC = ({ navigation }) => {
+ const user = useProfile();
+
+ if (!user) {
+ return No profile loaded.;
+ }
+
+ return (
+
+
+ {user.avatar && }
+ {user.name}
+ {user.email}
+ navigation.navigate('Settings')} style={styles.button} />
+ navigation.navigate('Preferences')} style={styles.button} />
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: Colors.background,
+ justifyContent: 'center',
+ padding: Spacing.lg,
+ },
+ avatar: {
+ width: 80,
+ height: 80,
+ borderRadius: 40,
+ alignSelf: 'center',
+ marginBottom: Spacing.md,
+ },
+ name: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.lg,
+ color: Colors.primary,
+ textAlign: 'center',
+ marginBottom: Spacing.xs,
+ },
+ email: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textSecondary,
+ textAlign: 'center',
+ marginBottom: Spacing.md,
+ },
+ button: {
+ marginTop: Spacing.sm,
+ },
+});
+
+export default ProfileScreen;
+
+/*
+ * End of File: ProfileScreen.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/screens/SettingsScreen.tsx b/app/modules/Profile/screens/SettingsScreen.tsx
new file mode 100644
index 0000000..ee891bd
--- /dev/null
+++ b/app/modules/Profile/screens/SettingsScreen.tsx
@@ -0,0 +1,79 @@
+/*
+ * File: SettingsScreen.tsx
+ * Description: Screen for user settings
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, Text, StyleSheet, Switch } from 'react-native';
+import { Card } from 'shared/src/components/Card';
+import { Colors, Spacing, Typography } from 'shared/src/theme';
+import { useSettings } from '../hooks/useSettings';
+
+/**
+ * SettingsScreen - shows toggles for notifications/dark mode and language select (stub)
+ */
+const SettingsScreen: React.FC = () => {
+ const settings = useSettings();
+
+ return (
+
+
+ Settings
+
+ Notifications
+
+
+
+ Dark Mode
+
+
+
+ Language
+ {settings.language}
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: Colors.background,
+ justifyContent: 'center',
+ padding: Spacing.lg,
+ },
+ title: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.lg,
+ color: Colors.primary,
+ marginBottom: Spacing.md,
+ textAlign: 'center',
+ },
+ row: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ marginBottom: Spacing.md,
+ },
+ label: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textPrimary,
+ },
+ value: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textSecondary,
+ },
+});
+
+export default SettingsScreen;
+
+/*
+ * End of File: SettingsScreen.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/screens/index.ts b/app/modules/Profile/screens/index.ts
new file mode 100644
index 0000000..fbe6a35
--- /dev/null
+++ b/app/modules/Profile/screens/index.ts
@@ -0,0 +1,16 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Profile screens
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as ProfileScreen } from './ProfileScreen';
+export { default as SettingsScreen } from './SettingsScreen';
+export { default as PreferencesScreen } from './PreferencesScreen';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/services/index.ts b/app/modules/Profile/services/index.ts
new file mode 100644
index 0000000..87aadeb
--- /dev/null
+++ b/app/modules/Profile/services/index.ts
@@ -0,0 +1,15 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Profile services
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export * from './profileAPI';
+export * from './settingsAPI';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/services/profileAPI.ts b/app/modules/Profile/services/profileAPI.ts
new file mode 100644
index 0000000..8bf4b67
--- /dev/null
+++ b/app/modules/Profile/services/profileAPI.ts
@@ -0,0 +1,27 @@
+/*
+ * File: profileAPI.ts
+ * Description: API service for fetching user profile using apisauce
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { create } from 'apisauce';
+
+const api = create({
+ baseURL: 'https://api.example.com', // TODO: Replace with actual endpoint
+ timeout: 10000,
+});
+
+/**
+ * getProfile - fetches user profile by userId
+ */
+export const profileAPI = {
+ getProfile: (userId: string) => api.get(`/users/${userId}`),
+ // Add more endpoints as needed
+};
+
+/*
+ * End of File: profileAPI.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/modules/Profile/services/settingsAPI.ts b/app/modules/Profile/services/settingsAPI.ts
new file mode 100644
index 0000000..19f7d03
--- /dev/null
+++ b/app/modules/Profile/services/settingsAPI.ts
@@ -0,0 +1,27 @@
+/*
+ * File: settingsAPI.ts
+ * Description: API service for fetching user settings using apisauce
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { create } from 'apisauce';
+
+const api = create({
+ baseURL: 'https://api.example.com', // TODO: Replace with actual endpoint
+ timeout: 10000,
+});
+
+/**
+ * getSettings - fetches user settings by userId
+ */
+export const settingsAPI = {
+ getSettings: (userId: string) => api.get(`/users/${userId}/settings`),
+ // Add more endpoints as needed
+};
+
+/*
+ * End of File: settingsAPI.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/navigation/AppNavigator.tsx b/app/navigation/AppNavigator.tsx
new file mode 100644
index 0000000..ca5ec3b
--- /dev/null
+++ b/app/navigation/AppNavigator.tsx
@@ -0,0 +1,34 @@
+/*
+ * File: AppNavigator.tsx
+ * Description: Root navigator switching between Auth and App stacks
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { NavigationContainer } from '@react-navigation/native';
+import { useSelector } from 'react-redux';
+import { selectIsAuthenticated } from '../modules/Auth/redux/authSelectors';
+import AuthNavigator from './AuthNavigator';
+import TabNavigator from './TabNavigator';
+
+/**
+ * AppNavigator - root navigator for the app
+ * Shows Auth stack if not authenticated, TabNavigator if authenticated
+ */
+const AppNavigator: React.FC = () => {
+ const isAuthenticated = useSelector(selectIsAuthenticated);
+ return (
+
+ {isAuthenticated ? : }
+
+ );
+};
+
+export default AppNavigator;
+
+/*
+ * End of File: AppNavigator.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/navigation/AuthNavigator.tsx b/app/navigation/AuthNavigator.tsx
new file mode 100644
index 0000000..05bf5ad
--- /dev/null
+++ b/app/navigation/AuthNavigator.tsx
@@ -0,0 +1,14 @@
+/*
+ * File: AuthNavigator.tsx
+ * Description: Authentication stack navigator
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { AuthNavigator as default } from '../modules/Auth/navigation';
+
+/*
+ * End of File: AuthNavigator.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/app/navigation/TabNavigator.tsx b/app/navigation/TabNavigator.tsx
new file mode 100644
index 0000000..096255f
--- /dev/null
+++ b/app/navigation/TabNavigator.tsx
@@ -0,0 +1,56 @@
+/*
+ * File: TabNavigator.tsx
+ * Description: Bottom tab navigator with Dashboard, CaseReview, and Profile tabs
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import { DashboardNavigator } from '../modules/Dashboard/navigation';
+import { CaseReviewNavigator } from '../modules/CaseReview/navigation';
+import { ProfileNavigator } from '../modules/Profile/navigation';
+import { Colors } from 'shared/src/theme';
+import { CustomIcon } from 'shared/src/components/Icons';
+
+export type TabParamList = {
+ Dashboard: undefined;
+ CaseReview: undefined;
+ Profile: undefined;
+};
+
+const Tab = createBottomTabNavigator();
+
+/**
+ * TabNavigator - bottom tab navigation for main app
+ */
+const TabNavigator: React.FC = () => (
+ ({
+ headerShown: false,
+ tabBarActiveTintColor: Colors.primary,
+ tabBarInactiveTintColor: Colors.textMuted,
+ tabBarStyle: { backgroundColor: Colors.background },
+ tabBarIcon: ({ color, size }) => {
+ let iconName = '';
+ if (route.name === 'Dashboard') iconName = 'view-dashboard';
+ else if (route.name === 'CaseReview') iconName = 'file-search';
+ else if (route.name === 'Profile') iconName = 'account-circle';
+ return ;
+ },
+ })}
+ >
+
+
+
+
+);
+
+export default TabNavigator;
+
+/*
+ * End of File: TabNavigator.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index f98b33b..96d9564 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,8 +8,38 @@
"name": "NeoScan_Radiologist",
"version": "0.0.1",
"dependencies": {
+ "@react-native-async-storage/async-storage": "^2.1.0",
+ "@react-native-clipboard/clipboard": "^1.16.1",
+ "@react-native-community/netinfo": "^11.4.1",
+ "@react-native-voice/voice": "^3.2.4",
+ "@react-navigation/bottom-tabs": "^7.2.0",
+ "@react-navigation/native": "^7.0.14",
+ "@react-navigation/native-stack": "^7.2.0",
+ "@react-navigation/stack": "^7.1.1",
+ "@reduxjs/toolkit": "^2.5.1",
+ "apisauce": "^3.1.0",
+ "lottie-react-native": "^7.2.2",
"react": "19.0.0",
- "react-native": "0.79.0"
+ "react-native": "0.79.0",
+ "react-native-blob-util": "^0.22.2",
+ "react-native-config": "^1.5.5",
+ "react-native-gesture-handler": "^2.22.1",
+ "react-native-image-picker": "^7.2.3",
+ "react-native-linear-gradient": "^2.8.3",
+ "react-native-permissions": "^5.2.4",
+ "react-native-raw-bottom-sheet": "^3.0.0",
+ "react-native-reanimated": "^3.18.0",
+ "react-native-render-html": "^6.3.4",
+ "react-native-responsive-dimensions": "^3.1.1",
+ "react-native-safe-area-context": "^5.1.0",
+ "react-native-screens": "^4.5.0",
+ "react-native-share": "^12.0.9",
+ "react-native-svg": "^15.11.1",
+ "react-native-toast-message": "^2.2.1",
+ "react-native-tts": "^4.1.1",
+ "react-native-vector-icons": "^10.2.0",
+ "react-redux": "^9.2.0",
+ "redux-persist": "^6.0.0"
},
"devDependencies": {
"@babel/core": "^7.25.2",
@@ -140,7 +170,6 @@
"version": "7.27.3",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz",
"integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.27.3"
@@ -169,7 +198,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz",
"integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.27.1",
@@ -191,7 +219,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz",
"integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.27.1",
@@ -235,7 +262,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz",
"integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/traverse": "^7.27.1",
@@ -279,7 +305,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz",
"integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.27.1"
@@ -319,7 +344,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz",
"integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-member-expression-to-functions": "^7.27.1",
@@ -337,7 +361,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz",
"integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/traverse": "^7.27.1",
@@ -402,6 +425,92 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/highlight": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.9.tgz",
+ "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.25.9",
+ "chalk": "^2.4.2",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "license": "MIT"
+ },
+ "node_modules/@babel/highlight/node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/@babel/parser": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz",
@@ -685,7 +794,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz",
"integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
@@ -803,7 +911,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz",
"integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
@@ -836,7 +943,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz",
"integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
@@ -920,7 +1026,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz",
"integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-create-class-features-plugin": "^7.27.1",
@@ -954,7 +1059,6 @@
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.0.tgz",
"integrity": "sha512-IjM1IoJNw72AZFlj33Cu8X0q2XK/6AaVC3jQu+cgQ5lThWD5ajnuUAml80dqRmOhmPkTH8uAwnpMu9Rvj0LTRA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.27.3",
@@ -1257,7 +1361,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz",
"integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-module-transforms": "^7.27.1",
@@ -1343,7 +1446,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz",
"integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
@@ -1428,7 +1530,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz",
"integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1",
@@ -1650,7 +1751,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz",
"integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
@@ -1699,7 +1799,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz",
"integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
@@ -1731,7 +1830,6 @@
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.0.tgz",
"integrity": "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.27.3",
@@ -1784,7 +1882,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz",
"integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.27.1",
@@ -1914,6 +2011,25 @@
"@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0"
}
},
+ "node_modules/@babel/preset-typescript": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz",
+ "integrity": "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1",
+ "@babel/helper-validator-option": "^7.27.1",
+ "@babel/plugin-syntax-jsx": "^7.27.1",
+ "@babel/plugin-transform-modules-commonjs": "^7.27.1",
+ "@babel/plugin-transform-typescript": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
"node_modules/@babel/runtime": {
"version": "7.27.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz",
@@ -1994,6 +2110,18 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@egjs/hammerjs": {
+ "version": "2.0.17",
+ "resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
+ "integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hammerjs": "^2.0.36"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
"node_modules/@eslint-community/eslint-utils": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
@@ -2094,6 +2222,229 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
+ "node_modules/@expo/config-plugins": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-2.0.4.tgz",
+ "integrity": "sha512-JGt/X2tFr7H8KBQrKfbGo9hmCubQraMxq5sj3bqDdKmDOLcE1a/EDCP9g0U4GHsa425J8VDIkQUHYz3h3ndEXQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@expo/config-types": "^41.0.0",
+ "@expo/json-file": "8.2.30",
+ "@expo/plist": "0.0.13",
+ "debug": "^4.3.1",
+ "find-up": "~5.0.0",
+ "fs-extra": "9.0.0",
+ "getenv": "^1.0.0",
+ "glob": "7.1.6",
+ "resolve-from": "^5.0.0",
+ "slash": "^3.0.0",
+ "xcode": "^3.0.1",
+ "xml2js": "^0.4.23"
+ }
+ },
+ "node_modules/@expo/config-plugins/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/@expo/config-plugins/node_modules/fs-extra": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz",
+ "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==",
+ "license": "MIT",
+ "dependencies": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@expo/config-plugins/node_modules/glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@expo/config-plugins/node_modules/jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "license": "MIT",
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/@expo/config-plugins/node_modules/jsonfile/node_modules/universalify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+ "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/@expo/config-plugins/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/@expo/config-plugins/node_modules/resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@expo/config-plugins/node_modules/universalify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
+ "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/@expo/config-types": {
+ "version": "41.0.0",
+ "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-41.0.0.tgz",
+ "integrity": "sha512-Ax0pHuY5OQaSrzplOkT9DdpdmNzaVDnq9VySb4Ujq7UJ4U4jriLy8u93W98zunOXpcu0iiKubPsqD6lCiq0pig==",
+ "license": "MIT"
+ },
+ "node_modules/@expo/json-file": {
+ "version": "8.2.30",
+ "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.2.30.tgz",
+ "integrity": "sha512-vrgGyPEXBoFI5NY70IegusCSoSVIFV3T3ry4tjJg1MFQKTUlR7E0r+8g8XR6qC705rc2PawaZQjqXMAVtV6s2A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "~7.10.4",
+ "fs-extra": "9.0.0",
+ "json5": "^1.0.1",
+ "write-file-atomic": "^2.3.0"
+ }
+ },
+ "node_modules/@expo/json-file/node_modules/@babel/code-frame": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
+ "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/highlight": "^7.10.4"
+ }
+ },
+ "node_modules/@expo/json-file/node_modules/fs-extra": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz",
+ "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==",
+ "license": "MIT",
+ "dependencies": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@expo/json-file/node_modules/json5": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+ "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+ "license": "MIT",
+ "dependencies": {
+ "minimist": "^1.2.0"
+ },
+ "bin": {
+ "json5": "lib/cli.js"
+ }
+ },
+ "node_modules/@expo/json-file/node_modules/jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "license": "MIT",
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/@expo/json-file/node_modules/jsonfile/node_modules/universalify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+ "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/@expo/json-file/node_modules/universalify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
+ "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/@expo/json-file/node_modules/write-file-atomic": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
+ "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==",
+ "license": "ISC",
+ "dependencies": {
+ "graceful-fs": "^4.1.11",
+ "imurmurhash": "^0.1.4",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "node_modules/@expo/plist": {
+ "version": "0.0.13",
+ "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.0.13.tgz",
+ "integrity": "sha512-zGPSq9OrCn7lWvwLLHLpHUUq2E40KptUFXn53xyZXPViI0k9lbApcR9KlonQZ95C+ELsf0BQ3gRficwK92Ivcw==",
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.2.3",
+ "xmlbuilder": "^14.0.0",
+ "xmldom": "~0.5.0"
+ }
+ },
"node_modules/@hapi/hoek": {
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz",
@@ -2173,6 +2524,102 @@
"dev": true,
"license": "BSD-3-Clause"
},
+ "node_modules/@isaacs/cliui": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+ "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^5.1.2",
+ "string-width-cjs": "npm:string-width@^4.2.0",
+ "strip-ansi": "^7.0.1",
+ "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+ "wrap-ansi": "^8.1.0",
+ "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/ansi-regex": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+ "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/ansi-styles": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "license": "MIT"
+ },
+ "node_modules/@isaacs/cliui/node_modules/string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+ "license": "MIT",
+ "dependencies": {
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/wrap-ansi": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
"node_modules/@isaacs/ttlcache": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz",
@@ -2669,6 +3116,57 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@jsamr/counter-style": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@jsamr/counter-style/-/counter-style-2.0.2.tgz",
+ "integrity": "sha512-2mXudGVtSzVxWEA7B9jZLKjoXUeUFYDDtFrQoC0IFX9/Dszz4t1vZOmafi3JSw/FxD+udMQ+4TAFR8Qs0J3URQ==",
+ "license": "MIT"
+ },
+ "node_modules/@jsamr/react-native-li": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/@jsamr/react-native-li/-/react-native-li-2.3.1.tgz",
+ "integrity": "sha512-Qbo4NEj48SQ4k8FZJHFE2fgZDKTWaUGmVxcIQh3msg5JezLdTMMHuRRDYctfdHI6L0FZGObmEv3haWbIvmol8w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@jsamr/counter-style": "^1.0.0 || ^2.0.0",
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/@native-html/css-processor": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@native-html/css-processor/-/css-processor-1.11.0.tgz",
+ "integrity": "sha512-NnhBEbJX5M2gBGltPKOetiLlKhNf3OHdRafc8//e2ZQxXN8JaSW/Hy8cm94pnIckQxwaMKxrtaNT3x4ZcffoNQ==",
+ "license": "MIT",
+ "dependencies": {
+ "css-to-react-native": "^3.0.0",
+ "csstype": "^3.0.8"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-native": "*"
+ }
+ },
+ "node_modules/@native-html/transient-render-engine": {
+ "version": "11.2.3",
+ "resolved": "https://registry.npmjs.org/@native-html/transient-render-engine/-/transient-render-engine-11.2.3.tgz",
+ "integrity": "sha512-zXwgA3gPUEmFs3I3syfnvDvS6WiUHXEE6jY09OBzK+trq7wkweOSFWIoyXiGkbXrozGYG0KY90YgPyr8Tg8Uyg==",
+ "license": "MIT",
+ "dependencies": {
+ "@native-html/css-processor": "1.11.0",
+ "@types/ramda": "^0.27.44",
+ "csstype": "^3.0.9",
+ "domelementtype": "^2.2.0",
+ "domhandler": "^4.2.2",
+ "domutils": "^2.8.0",
+ "htmlparser2": "^7.1.2",
+ "ramda": "^0.27.2"
+ },
+ "peerDependencies": {
+ "@types/react-native": "*",
+ "react-native": "^*"
+ }
+ },
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
"version": "5.1.1-v1",
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
@@ -2717,6 +3215,51 @@
"node": ">= 8"
}
},
+ "node_modules/@pkgjs/parseargs": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@react-native-async-storage/async-storage": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.2.0.tgz",
+ "integrity": "sha512-gvRvjR5JAaUZF8tv2Kcq/Gbt3JHwbKFYfmb445rhOj6NUMx3qPLixmDx5pZAyb9at1bYvJ4/eTUipU5aki45xw==",
+ "license": "MIT",
+ "dependencies": {
+ "merge-options": "^3.0.4"
+ },
+ "peerDependencies": {
+ "react-native": "^0.0.0-0 || >=0.65 <1.0"
+ }
+ },
+ "node_modules/@react-native-clipboard/clipboard": {
+ "version": "1.16.3",
+ "resolved": "https://registry.npmjs.org/@react-native-clipboard/clipboard/-/clipboard-1.16.3.tgz",
+ "integrity": "sha512-cMIcvoZKIrShzJHEaHbTAp458R9WOv0fB6UyC7Ek4Qk561Ow/DrzmmJmH/rAZg21Z6ixJ4YSdFDC14crqIBmCQ==",
+ "license": "MIT",
+ "workspaces": [
+ "example"
+ ],
+ "peerDependencies": {
+ "react": ">= 16.9.0",
+ "react-native": ">= 0.61.5",
+ "react-native-macos": ">= 0.61.0",
+ "react-native-windows": ">= 0.61.0"
+ },
+ "peerDependenciesMeta": {
+ "react-native-macos": {
+ "optional": true
+ },
+ "react-native-windows": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@react-native-community/cli": {
"version": "18.0.0",
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-18.0.0.tgz",
@@ -2950,6 +3493,28 @@
"node": ">=10"
}
},
+ "node_modules/@react-native-community/netinfo": {
+ "version": "11.4.1",
+ "resolved": "https://registry.npmjs.org/@react-native-community/netinfo/-/netinfo-11.4.1.tgz",
+ "integrity": "sha512-B0BYAkghz3Q2V09BF88RA601XursIEA111tnc2JOaN7axJWmNefmfjZqw/KdSxKZp7CZUuPpjBmz/WCR9uaHYg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react-native": ">=0.59"
+ }
+ },
+ "node_modules/@react-native-voice/voice": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@react-native-voice/voice/-/voice-3.2.4.tgz",
+ "integrity": "sha512-4i3IpB/W5VxCI7BQZO5Nr2VB0ecx0SLvkln2Gy29cAQKqgBl+1ZsCwUBChwHlPbmja6vA3tp/+2ADQGwB1OhHg==",
+ "license": "MIT",
+ "dependencies": {
+ "@expo/config-plugins": "^2.0.0",
+ "invariant": "^2.2.4"
+ },
+ "peerDependencies": {
+ "react-native": ">= 0.60.2"
+ }
+ },
"node_modules/@react-native/assets-registry": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.79.0.tgz",
@@ -3284,6 +3849,171 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@react-native/virtualized-lists": {
+ "version": "0.72.8",
+ "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.72.8.tgz",
+ "integrity": "sha512-J3Q4Bkuo99k7mu+jPS9gSUSgq+lLRSI/+ahXNwV92XgJ/8UgOTxu2LPwhJnBk/sQKxq7E8WkZBnBiozukQMqrw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "invariant": "^2.2.4",
+ "nullthrows": "^1.1.1"
+ },
+ "peerDependencies": {
+ "react-native": "*"
+ }
+ },
+ "node_modules/@react-navigation/bottom-tabs": {
+ "version": "7.4.2",
+ "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-7.4.2.tgz",
+ "integrity": "sha512-jyBux5l3qqEucY5M/ZWxVvfA8TQu7DVl2gK+xB6iKqRUfLf7dSumyVxc7HemDwGFoz3Ug8dVZFvSMEs+mfrieQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-navigation/elements": "^2.5.2",
+ "color": "^4.2.3"
+ },
+ "peerDependencies": {
+ "@react-navigation/native": "^7.1.14",
+ "react": ">= 18.2.0",
+ "react-native": "*",
+ "react-native-safe-area-context": ">= 4.0.0",
+ "react-native-screens": ">= 4.0.0"
+ }
+ },
+ "node_modules/@react-navigation/core": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.12.1.tgz",
+ "integrity": "sha512-ir6s25CDkReufi0vQhSIAe+AAHHJN9zTgGlS6iDS1yqbwgl2MiBAZzpaOL1T5llYujie2jF/bODeLz2j4k80zw==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-navigation/routers": "^7.4.1",
+ "escape-string-regexp": "^4.0.0",
+ "nanoid": "^3.3.11",
+ "query-string": "^7.1.3",
+ "react-is": "^19.1.0",
+ "use-latest-callback": "^0.2.4",
+ "use-sync-external-store": "^1.5.0"
+ },
+ "peerDependencies": {
+ "react": ">= 18.2.0"
+ }
+ },
+ "node_modules/@react-navigation/core/node_modules/react-is": {
+ "version": "19.1.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz",
+ "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==",
+ "license": "MIT"
+ },
+ "node_modules/@react-navigation/elements": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.5.2.tgz",
+ "integrity": "sha512-aGC3ukF5+lXuiF5bK7bJyRuWCE+Tk4MZ3GoQpAb7u7+m0KmsquliDhj4UCWEUU5kUoCeoRAUvv+1lKcYKf+WTQ==",
+ "license": "MIT",
+ "dependencies": {
+ "color": "^4.2.3",
+ "use-latest-callback": "^0.2.4",
+ "use-sync-external-store": "^1.5.0"
+ },
+ "peerDependencies": {
+ "@react-native-masked-view/masked-view": ">= 0.2.0",
+ "@react-navigation/native": "^7.1.14",
+ "react": ">= 18.2.0",
+ "react-native": "*",
+ "react-native-safe-area-context": ">= 4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@react-native-masked-view/masked-view": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@react-navigation/native": {
+ "version": "7.1.14",
+ "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.1.14.tgz",
+ "integrity": "sha512-X233/CNx41FpshlWe4uEAUN8CNem3ju4t5pnVKcdhDR0cTQT1rK6P0ZwjSylD9zXdnHvJttFjBhKTot6TcvSqA==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-navigation/core": "^7.12.1",
+ "escape-string-regexp": "^4.0.0",
+ "fast-deep-equal": "^3.1.3",
+ "nanoid": "^3.3.11",
+ "use-latest-callback": "^0.2.4"
+ },
+ "peerDependencies": {
+ "react": ">= 18.2.0",
+ "react-native": "*"
+ }
+ },
+ "node_modules/@react-navigation/native-stack": {
+ "version": "7.3.21",
+ "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-7.3.21.tgz",
+ "integrity": "sha512-oNNZHzkxILEibesamRKLodfXAaDOUvMBITKXLLeblDxnTAyIB/Kf7CmV+8nwkdAgV04kURTxV0SQI+d8gLUm6g==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-navigation/elements": "^2.5.2",
+ "warn-once": "^0.1.1"
+ },
+ "peerDependencies": {
+ "@react-navigation/native": "^7.1.14",
+ "react": ">= 18.2.0",
+ "react-native": "*",
+ "react-native-safe-area-context": ">= 4.0.0",
+ "react-native-screens": ">= 4.0.0"
+ }
+ },
+ "node_modules/@react-navigation/routers": {
+ "version": "7.4.1",
+ "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.4.1.tgz",
+ "integrity": "sha512-42mZrMzQ0LfKxUb5OHIurYrPYyRsXFLolucILrvm21f0O40Sw0Ufh1bnn/jRqnxZZu7wvpUGIGYM8nS9zVE1Aw==",
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.11"
+ }
+ },
+ "node_modules/@react-navigation/stack": {
+ "version": "7.4.2",
+ "resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-7.4.2.tgz",
+ "integrity": "sha512-QlqBxKBfKVx/XRH04pRRGQ92tO1fV0RL7YEw5G4pew6CNY26102dVQl5A39ZztvlvEDQbCQkatyDS7i2xR1QiA==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-navigation/elements": "^2.5.2",
+ "color": "^4.2.3"
+ },
+ "peerDependencies": {
+ "@react-navigation/native": "^7.1.14",
+ "react": ">= 18.2.0",
+ "react-native": "*",
+ "react-native-gesture-handler": ">= 2.0.0",
+ "react-native-safe-area-context": ">= 4.0.0",
+ "react-native-screens": ">= 4.0.0"
+ }
+ },
+ "node_modules/@reduxjs/toolkit": {
+ "version": "2.8.2",
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.8.2.tgz",
+ "integrity": "sha512-MYlOhQ0sLdw4ud48FoC5w0dH9VfWQjtCjreKwYTT3l+r427qYC5Y8PihNutepr8XrNaBUDQo9khWUwQxZaqt5A==",
+ "license": "MIT",
+ "dependencies": {
+ "@standard-schema/spec": "^1.0.0",
+ "@standard-schema/utils": "^0.3.0",
+ "immer": "^10.0.3",
+ "redux": "^5.0.1",
+ "redux-thunk": "^3.1.0",
+ "reselect": "^5.1.0"
+ },
+ "peerDependencies": {
+ "react": "^16.9.0 || ^17.0.0 || ^18 || ^19",
+ "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "react-redux": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@sideway/address": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz",
@@ -3332,6 +4062,18 @@
"@sinonjs/commons": "^3.0.0"
}
},
+ "node_modules/@standard-schema/spec": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
+ "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
+ "license": "MIT"
+ },
+ "node_modules/@standard-schema/utils": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz",
+ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==",
+ "license": "MIT"
+ },
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -3382,6 +4124,12 @@
"@types/node": "*"
}
},
+ "node_modules/@types/hammerjs": {
+ "version": "2.0.46",
+ "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.46.tgz",
+ "integrity": "sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==",
+ "license": "MIT"
+ },
"node_modules/@types/istanbul-lib-coverage": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
@@ -3468,16 +4216,35 @@
"undici-types": "~7.8.0"
}
},
+ "node_modules/@types/ramda": {
+ "version": "0.27.66",
+ "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.27.66.tgz",
+ "integrity": "sha512-i2YW+E2U6NfMt3dp0RxNcejox+bxJUNDjB7BpYuRuoHIzv5juPHkJkNgcUOu+YSQEmaWu8cnAo/8r63C0NnuVA==",
+ "license": "MIT",
+ "dependencies": {
+ "ts-toolbelt": "^6.15.1"
+ }
+ },
"node_modules/@types/react": {
"version": "19.1.8",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz",
"integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==",
- "devOptional": true,
"license": "MIT",
"dependencies": {
"csstype": "^3.0.2"
}
},
+ "node_modules/@types/react-native": {
+ "version": "0.72.8",
+ "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.72.8.tgz",
+ "integrity": "sha512-St6xA7+EoHN5mEYfdWnfYt0e8u6k2FR0P9s2arYgakQGFgU1f9FlPrIEcj0X24pLCF5c5i3WVuLCUdiCYHmOoA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@react-native/virtualized-lists": "^0.72.4",
+ "@types/react": "*"
+ }
+ },
"node_modules/@types/react-test-renderer": {
"version": "19.1.0",
"resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-19.1.0.tgz",
@@ -3501,6 +4268,18 @@
"integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==",
"license": "MIT"
},
+ "node_modules/@types/urijs": {
+ "version": "1.19.25",
+ "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.25.tgz",
+ "integrity": "sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/use-sync-external-store": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
+ "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
+ "license": "MIT"
+ },
"node_modules/@types/yargs": {
"version": "17.0.33",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz",
@@ -3749,6 +4528,15 @@
"devOptional": true,
"license": "MIT"
},
+ "node_modules/@xmldom/xmldom": {
+ "version": "0.8.10",
+ "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
+ "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
"node_modules/abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
@@ -3938,6 +4726,15 @@
"node": ">= 8"
}
},
+ "node_modules/apisauce": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/apisauce/-/apisauce-3.2.0.tgz",
+ "integrity": "sha512-uEvNyBl86g9znFzb5DsBN0kaC9cs9Seo6Ztippf1lJgMEj/mcwE7YMsv4NZeKHjpxGOQ4AHDPItnDRiEgNIdDA==",
+ "license": "MIT",
+ "dependencies": {
+ "axios": "^1.10.0"
+ }
+ },
"node_modules/appdirsjs": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/appdirsjs/-/appdirsjs-1.2.7.tgz",
@@ -4132,6 +4929,21 @@
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
"license": "MIT"
},
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+ "license": "MIT"
+ },
+ "node_modules/at-least-node": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
@@ -4148,6 +4960,17 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/axios": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz",
+ "integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==",
+ "license": "MIT",
+ "dependencies": {
+ "follow-redirects": "^1.15.6",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
"node_modules/babel-jest": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
@@ -4325,6 +5148,11 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT"
},
+ "node_modules/base-64": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz",
+ "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA=="
+ },
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -4345,6 +5173,15 @@
],
"license": "MIT"
},
+ "node_modules/big-integer": {
+ "version": "1.6.52",
+ "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz",
+ "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==",
+ "license": "Unlicense",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
"node_modules/bl": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
@@ -4399,11 +5236,37 @@
"devOptional": true,
"license": "MIT"
},
+ "node_modules/boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+ "license": "ISC"
+ },
+ "node_modules/bplist-creator": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz",
+ "integrity": "sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==",
+ "license": "MIT",
+ "dependencies": {
+ "stream-buffers": "2.2.x"
+ }
+ },
+ "node_modules/bplist-parser": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.1.tgz",
+ "integrity": "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==",
+ "license": "MIT",
+ "dependencies": {
+ "big-integer": "1.6.x"
+ },
+ "engines": {
+ "node": ">= 5.10.0"
+ }
+ },
"node_modules/brace-expansion": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
@@ -4526,7 +5389,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
- "devOptional": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@@ -4605,6 +5467,15 @@
"node": ">=6"
}
},
+ "node_modules/camelize": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
+ "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/caniuse-lite": {
"version": "1.0.30001727",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz",
@@ -4651,6 +5522,26 @@
"node": ">=10"
}
},
+ "node_modules/character-entities-html4": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz",
+ "integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/character-entities-legacy": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
+ "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
"node_modules/chrome-launcher": {
"version": "0.15.2",
"resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz",
@@ -4797,6 +5688,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/color": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
+ "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1",
+ "color-string": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=12.5.0"
+ }
+ },
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -4815,6 +5719,16 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT"
},
+ "node_modules/color-string": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+ "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
"node_modules/colorette": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
@@ -4822,6 +5736,18 @@
"devOptional": true,
"license": "MIT"
},
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "license": "MIT",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/command-exists": {
"version": "1.2.9",
"resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz",
@@ -5007,7 +5933,6 @@
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
- "devOptional": true,
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
@@ -5018,11 +5943,126 @@
"node": ">= 8"
}
},
+ "node_modules/css-color-keywords": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
+ "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/css-select": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
+ "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-what": "^6.1.0",
+ "domhandler": "^5.0.2",
+ "domutils": "^3.0.1",
+ "nth-check": "^2.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/css-select/node_modules/dom-serializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+ "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "entities": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/css-select/node_modules/domhandler": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "domelementtype": "^2.3.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/css-select/node_modules/domutils": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
+ "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "dom-serializer": "^2.0.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
+ "node_modules/css-select/node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/css-to-react-native": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
+ "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==",
+ "license": "MIT",
+ "dependencies": {
+ "camelize": "^1.0.0",
+ "css-color-keywords": "^1.0.0",
+ "postcss-value-parser": "^4.0.2"
+ }
+ },
+ "node_modules/css-tree": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
+ "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
+ "license": "MIT",
+ "dependencies": {
+ "mdn-data": "2.0.14",
+ "source-map": "^0.6.1"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/css-what": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
+ "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">= 6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "devOptional": true,
"license": "MIT"
},
"node_modules/data-view-buffer": {
@@ -5113,6 +6153,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/decode-uri-component": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
+ "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
"node_modules/dedent": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/dedent/-/dedent-1.6.0.tgz",
@@ -5194,6 +6243,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -5259,11 +6317,65 @@
"node": ">=6.0.0"
}
},
+ "node_modules/dom-serializer": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
+ "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.0.1",
+ "domhandler": "^4.2.0",
+ "entities": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/domhandler": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
+ "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "domelementtype": "^2.2.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
+ "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "dom-serializer": "^1.0.1",
+ "domelementtype": "^2.2.0",
+ "domhandler": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
- "devOptional": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
@@ -5274,6 +6386,12 @@
"node": ">= 0.4"
}
},
+ "node_modules/eastasianwidth": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+ "license": "MIT"
+ },
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -5314,6 +6432,15 @@
"node": ">= 0.8"
}
},
+ "node_modules/entities": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+ "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
+ "license": "BSD-2-Clause",
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
"node_modules/env-paths": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
@@ -5442,7 +6569,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
- "devOptional": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -5452,7 +6578,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
- "devOptional": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -5490,7 +6615,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
- "devOptional": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
@@ -5503,7 +6627,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@@ -6225,7 +7348,6 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true,
"license": "MIT"
},
"node_modules/fast-glob": {
@@ -6334,6 +7456,15 @@
"node": ">=8"
}
},
+ "node_modules/filter-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
+ "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/finalhandler": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
@@ -6383,7 +7514,6 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "devOptional": true,
"license": "MIT",
"dependencies": {
"locate-path": "^6.0.0",
@@ -6424,6 +7554,26 @@
"integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==",
"license": "MIT"
},
+ "node_modules/follow-redirects": {
+ "version": "1.15.9",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
+ "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
"node_modules/for-each": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
@@ -6440,6 +7590,50 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/foreground-child": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
+ "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
+ "license": "ISC",
+ "dependencies": {
+ "cross-spawn": "^7.0.6",
+ "signal-exit": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/foreground-child/node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/form-data": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
+ "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
+ "license": "MIT",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "es-set-tostringtag": "^2.1.0",
+ "hasown": "^2.0.2",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
@@ -6488,7 +7682,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
- "devOptional": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -6547,7 +7740,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
- "devOptional": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
@@ -6581,7 +7773,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
- "devOptional": true,
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
@@ -6622,6 +7813,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/getenv": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/getenv/-/getenv-1.0.0.tgz",
+ "integrity": "sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@@ -6736,7 +7936,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
- "devOptional": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -6813,7 +8012,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
- "devOptional": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -6826,7 +8024,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
@@ -6842,7 +8039,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
- "devOptional": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
@@ -6866,6 +8062,21 @@
"hermes-estree": "0.25.1"
}
},
+ "node_modules/hoist-non-react-statics": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "react-is": "^16.7.0"
+ }
+ },
+ "node_modules/hoist-non-react-statics/node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "license": "MIT"
+ },
"node_modules/html-escaper": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
@@ -6873,6 +8084,37 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/htmlparser2": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
+ "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==",
+ "funding": [
+ "https://github.com/fb55/htmlparser2?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.0.1",
+ "domhandler": "^4.2.2",
+ "domutils": "^2.8.0",
+ "entities": "^3.0.1"
+ }
+ },
+ "node_modules/htmlparser2/node_modules/entities": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
+ "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
"node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@@ -6980,6 +8222,16 @@
"node": ">=16.x"
}
},
+ "node_modules/immer": {
+ "version": "10.1.1",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz",
+ "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/immer"
+ }
+ },
"node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@@ -7382,6 +8634,15 @@
"node": ">=8"
}
},
+ "node_modules/is-plain-obj": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/is-regex": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
@@ -7574,7 +8835,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "devOptional": true,
"license": "ISC"
},
"node_modules/istanbul-lib-coverage": {
@@ -7678,6 +8938,21 @@
"node": ">= 0.4"
}
},
+ "node_modules/jackspeak": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+ "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "@isaacs/cliui": "^8.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ },
+ "optionalDependencies": {
+ "@pkgjs/parseargs": "^0.11.0"
+ }
+ },
"node_modules/jest": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz",
@@ -8785,7 +10060,6 @@
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "devOptional": true,
"license": "MIT",
"dependencies": {
"p-locate": "^5.0.0"
@@ -8995,6 +10269,26 @@
"loose-envify": "cli.js"
}
},
+ "node_modules/lottie-react-native": {
+ "version": "7.2.4",
+ "resolved": "https://registry.npmjs.org/lottie-react-native/-/lottie-react-native-7.2.4.tgz",
+ "integrity": "sha512-o1bJ4wiG5bfuaY4YhWNkAfAmL0loPfMtmU/0XyMQoVkEIf0O2CwnO8yi6thldCPkYm6U7ENEhnm9FW3jscBE6w==",
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "@lottiefiles/dotlottie-react": "^0.6.5",
+ "react": "*",
+ "react-native": ">=0.46",
+ "react-native-windows": ">=0.63.x"
+ },
+ "peerDependenciesMeta": {
+ "@lottiefiles/dotlottie-react": {
+ "optional": true
+ },
+ "react-native-windows": {
+ "optional": true
+ }
+ }
+ },
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -9052,12 +10346,17 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
- "devOptional": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
+ "node_modules/mdn-data": {
+ "version": "2.0.14",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
+ "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
+ "license": "CC0-1.0"
+ },
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -9074,6 +10373,18 @@
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==",
"license": "MIT"
},
+ "node_modules/merge-options": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz",
+ "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==",
+ "license": "MIT",
+ "dependencies": {
+ "is-plain-obj": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -9586,7 +10897,6 @@
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
- "dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
@@ -9598,6 +10908,24 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
"node_modules/mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
@@ -9616,6 +10944,24 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
+ "node_modules/nanoid": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
"node_modules/natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
@@ -9691,6 +11037,18 @@
"node": ">=8"
}
},
+ "node_modules/nth-check": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/nth-check?sponsor=1"
+ }
+ },
"node_modules/nullthrows": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz",
@@ -9713,7 +11071,6 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -9941,7 +11298,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "devOptional": true,
"license": "MIT",
"dependencies": {
"yocto-queue": "^0.1.0"
@@ -9957,7 +11313,6 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "devOptional": true,
"license": "MIT",
"dependencies": {
"p-limit": "^3.0.2"
@@ -9978,6 +11333,12 @@
"node": ">=6"
}
},
+ "node_modules/package-json-from-dist": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+ "license": "BlueOak-1.0.0"
+ },
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -10041,7 +11402,6 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -10054,6 +11414,28 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/path-scurry": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "lru-cache": "^10.2.0",
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/path-scurry/node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "license": "ISC"
+ },
"node_modules/path-type": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
@@ -10160,6 +11542,29 @@
"node": ">=8"
}
},
+ "node_modules/plist": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz",
+ "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@xmldom/xmldom": "^0.8.8",
+ "base64-js": "^1.5.1",
+ "xmlbuilder": "^15.1.1"
+ },
+ "engines": {
+ "node": ">=10.4.0"
+ }
+ },
+ "node_modules/plist/node_modules/xmlbuilder": {
+ "version": "15.1.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
+ "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
"node_modules/possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
@@ -10170,6 +11575,12 @@
"node": ">= 0.4"
}
},
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "license": "MIT"
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -10266,7 +11677,6 @@
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"loose-envify": "^1.4.0",
@@ -10278,7 +11688,12 @@
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT"
},
"node_modules/punycode": {
@@ -10324,6 +11739,24 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/query-string": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz",
+ "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==",
+ "license": "MIT",
+ "dependencies": {
+ "decode-uri-component": "^0.2.2",
+ "filter-obj": "^1.1.0",
+ "split-on-first": "^1.0.0",
+ "strict-uri-encode": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/queue": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
@@ -10354,6 +11787,12 @@
],
"license": "MIT"
},
+ "node_modules/ramda": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.2.tgz",
+ "integrity": "sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==",
+ "license": "MIT"
+ },
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@@ -10419,6 +11858,18 @@
}
}
},
+ "node_modules/react-freeze": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.4.tgz",
+ "integrity": "sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "react": ">=17.0.0"
+ }
+ },
"node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -10485,6 +11936,305 @@
}
}
},
+ "node_modules/react-native-blob-util": {
+ "version": "0.22.2",
+ "resolved": "https://registry.npmjs.org/react-native-blob-util/-/react-native-blob-util-0.22.2.tgz",
+ "integrity": "sha512-Czx01QMg7aLsm/4F/7+eqoRAi1q/qjLY2Kao16g+n2SRnTH1+qkD8Qhx2q9okB+VNQvZKB1LbiXhktzYQV52xQ==",
+ "license": "MIT",
+ "dependencies": {
+ "base-64": "0.1.0",
+ "glob": "^10.3.10"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-blob-util/node_modules/glob": {
+ "version": "10.4.5",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+ "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+ "license": "ISC",
+ "dependencies": {
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.4",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^1.11.1"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/react-native-config": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/react-native-config/-/react-native-config-1.5.5.tgz",
+ "integrity": "sha512-dGdLnBU0cd5xL5bF0ROTmHYbsstZnQKOEPfglvZi1vStvAjpld14X25K6mY3KGPTMWAzx6TbjKeq5dR+ILuMMA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react-native-windows": ">=0.61"
+ },
+ "peerDependenciesMeta": {
+ "react-native-windows": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-native-gesture-handler": {
+ "version": "2.27.1",
+ "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.27.1.tgz",
+ "integrity": "sha512-57TUWerhdz589OcDD21e/YlL923Ma4OIpyWsP0hy7gItBCPm5d7qIUW7Yo/cS2wo1qDdOhJaNlvlBD1lDou1fA==",
+ "license": "MIT",
+ "dependencies": {
+ "@egjs/hammerjs": "^2.0.17",
+ "hoist-non-react-statics": "^3.3.0",
+ "invariant": "^2.2.4"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-image-picker": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-7.2.3.tgz",
+ "integrity": "sha512-zKIZUlQNU3EtqizsXSH92zPeve4vpUrsqHu2kkpCxWE9TZhJFZBb+irDsBOY8J21k0+Edgt06TMQGJ+iPUIXyA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-is-edge-to-edge": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.1.7.tgz",
+ "integrity": "sha512-EH6i7E8epJGIcu7KpfXYXiV2JFIYITtq+rVS8uEb+92naMRBdxhTuS8Wn2Q7j9sqyO0B+Xbaaf9VdipIAmGW4w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-linear-gradient": {
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.8.3.tgz",
+ "integrity": "sha512-KflAXZcEg54PXkLyflaSZQ3PJp4uC4whM7nT/Uot9m0e/qxFV3p6uor1983D1YOBJbJN7rrWdqIjq0T42jOJyA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-permissions": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/react-native-permissions/-/react-native-permissions-5.4.1.tgz",
+ "integrity": "sha512-MTou5DVn8IADr7OQjYePJzcxrVNEeODBvSpB8XOt5qBI9ui3HduSBn/KTNZECH/Ph2Y20OnZBMqe6Wp9IryrgQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": ">=18.1.0",
+ "react-native": ">=0.70.0",
+ "react-native-windows": ">=0.70.0"
+ },
+ "peerDependenciesMeta": {
+ "react-native-windows": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-native-raw-bottom-sheet": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/react-native-raw-bottom-sheet/-/react-native-raw-bottom-sheet-3.0.0.tgz",
+ "integrity": "sha512-kHR7j2ExCLqf/AO3MECozMJXi48O1+YxUYSRgRo/5Ftm7mEcrxJEzvjqMmqUbVhhKlfk5hLCGFnEQ5Z9OHCUtg==",
+ "license": "MIT"
+ },
+ "node_modules/react-native-reanimated": {
+ "version": "3.18.0",
+ "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.18.0.tgz",
+ "integrity": "sha512-eVcNcqeOkMW+BUWAHdtvN3FKgC8J8wiEJkX6bNGGQaLS7m7e4amTfjIcqf/Ta+lerZLurmDaQ0lICI1CKPrb1Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/plugin-transform-arrow-functions": "^7.0.0-0",
+ "@babel/plugin-transform-class-properties": "^7.0.0-0",
+ "@babel/plugin-transform-classes": "^7.0.0-0",
+ "@babel/plugin-transform-nullish-coalescing-operator": "^7.0.0-0",
+ "@babel/plugin-transform-optional-chaining": "^7.0.0-0",
+ "@babel/plugin-transform-shorthand-properties": "^7.0.0-0",
+ "@babel/plugin-transform-template-literals": "^7.0.0-0",
+ "@babel/plugin-transform-unicode-regex": "^7.0.0-0",
+ "@babel/preset-typescript": "^7.16.7",
+ "convert-source-map": "^2.0.0",
+ "invariant": "^2.2.4",
+ "react-native-is-edge-to-edge": "1.1.7"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0",
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-render-html": {
+ "version": "6.3.4",
+ "resolved": "https://registry.npmjs.org/react-native-render-html/-/react-native-render-html-6.3.4.tgz",
+ "integrity": "sha512-H2jSMzZjidE+Wo3qCWPUMU1nm98Vs2SGCvQCz/i6xf0P3Y9uVtG/b0sDbG/cYFir2mSYBYCIlS1Dv0WC1LjYig==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@jsamr/counter-style": "^2.0.1",
+ "@jsamr/react-native-li": "^2.3.0",
+ "@native-html/transient-render-engine": "11.2.3",
+ "@types/ramda": "^0.27.40",
+ "@types/urijs": "^1.19.15",
+ "prop-types": "^15.5.7",
+ "ramda": "^0.27.2",
+ "stringify-entities": "^3.1.0",
+ "urijs": "^1.19.6"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-responsive-dimensions": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/react-native-responsive-dimensions/-/react-native-responsive-dimensions-3.1.1.tgz",
+ "integrity": "sha512-Vo2OhWsphq0HgKsmeZOeyW+c+vsFn1ZaCFkGDgdeCEEiLriT76jGA1JlUjtrj27hvyo/xzeTlBZ+vBso1A84fw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react-native": ">=0.44.1"
+ }
+ },
+ "node_modules/react-native-safe-area-context": {
+ "version": "5.5.2",
+ "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.5.2.tgz",
+ "integrity": "sha512-t4YVbHa9uAGf+pHMabGrb0uHrD5ogAusSu842oikJ3YKXcYp6iB4PTGl0EZNkUIR3pCnw/CXKn42OCfhsS0JIw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-screens": {
+ "version": "4.13.1",
+ "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.13.1.tgz",
+ "integrity": "sha512-EESsMAtyzYcL3gpAI2NKKiIo+Ew0fnX4P4b3Zy/+MTc6SJIo3foJbZwdIWd/SUBswOf7IYCvWBppg+D8tbwnsw==",
+ "license": "MIT",
+ "dependencies": {
+ "react-freeze": "^1.0.0",
+ "react-native-is-edge-to-edge": "^1.2.1",
+ "warn-once": "^0.1.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-screens/node_modules/react-native-is-edge-to-edge": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.2.1.tgz",
+ "integrity": "sha512-FLbPWl/MyYQWz+KwqOZsSyj2JmLKglHatd3xLZWskXOpRaio4LfEDEz8E/A6uD8QoTHW6Aobw1jbEwK7KMgR7Q==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-share": {
+ "version": "12.1.0",
+ "resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-12.1.0.tgz",
+ "integrity": "sha512-9OZrrEx9pZfl8Pw8Uh/k5Tc1o6oBaBfctq3z2wxy6eJBY6O/aRhs7/WPrXAoQmh9dCxc5sIClcKN57ef34iORQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/react-native-svg": {
+ "version": "15.12.0",
+ "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.12.0.tgz",
+ "integrity": "sha512-iE25PxIJ6V0C6krReLquVw6R0QTsRTmEQc4K2Co3P6zsimU/jltcDBKYDy1h/5j9S/fqmMeXnpM+9LEWKJKI6A==",
+ "license": "MIT",
+ "dependencies": {
+ "css-select": "^5.1.0",
+ "css-tree": "^1.1.3",
+ "warn-once": "0.1.1"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-toast-message": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/react-native-toast-message/-/react-native-toast-message-2.3.3.tgz",
+ "integrity": "sha512-4IIUHwUPvKHu4gjD0Vj2aGQzqPATiblL1ey8tOqsxOWRPGGu52iIbL8M/mCz4uyqecvPdIcMY38AfwRuUADfQQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-tts": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/react-native-tts/-/react-native-tts-4.1.1.tgz",
+ "integrity": "sha512-VL0TgCwkUWggbbFGIXAPKC3rM1baluAYtgOdgnaTm7UYsWf/y8n5VgmVB0J2Wa8qt1dldZ1cSsdQY9iz3evcAg==",
+ "license": "MIT"
+ },
+ "node_modules/react-native-vector-icons": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-10.2.0.tgz",
+ "integrity": "sha512-n5HGcxUuVaTf9QJPs/W22xQpC2Z9u0nb0KgLPnVltP8vdUvOp6+R26gF55kilP/fV4eL4vsAHUqUjewppJMBOQ==",
+ "license": "MIT",
+ "dependencies": {
+ "prop-types": "^15.7.2",
+ "yargs": "^16.1.1"
+ },
+ "bin": {
+ "fa-upgrade.sh": "bin/fa-upgrade.sh",
+ "fa5-upgrade": "bin/fa5-upgrade.sh",
+ "fa6-upgrade": "bin/fa6-upgrade.sh",
+ "generate-icon": "bin/generate-icon.js"
+ }
+ },
+ "node_modules/react-native-vector-icons/node_modules/cliui": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "node_modules/react-native-vector-icons/node_modules/yargs": {
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/react-native-vector-icons/node_modules/yargs-parser": {
+ "version": "20.2.9",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/react-native/node_modules/@react-native/virtualized-lists": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.79.0.tgz",
@@ -10561,6 +12311,29 @@
"node": ">=10"
}
},
+ "node_modules/react-redux": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
+ "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/use-sync-external-store": "^0.0.6",
+ "use-sync-external-store": "^1.4.0"
+ },
+ "peerDependencies": {
+ "@types/react": "^18.2.25 || ^19",
+ "react": "^18.0 || ^19",
+ "redux": "^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "redux": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-refresh": {
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
@@ -10606,6 +12379,30 @@
"node": ">= 6"
}
},
+ "node_modules/redux": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
+ "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
+ "license": "MIT"
+ },
+ "node_modules/redux-persist": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz",
+ "integrity": "sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "redux": ">4.0.0"
+ }
+ },
+ "node_modules/redux-thunk": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
+ "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "redux": "^5.0.0"
+ }
+ },
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
@@ -10633,14 +12430,12 @@
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
"integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
- "dev": true,
"license": "MIT"
},
"node_modules/regenerate-unicode-properties": {
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz",
"integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"regenerate": "^1.4.2"
@@ -10680,7 +12475,6 @@
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz",
"integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"regenerate": "^1.4.2",
@@ -10698,14 +12492,12 @@
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz",
"integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==",
- "dev": true,
"license": "MIT"
},
"node_modules/regjsparser": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz",
"integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==",
- "dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"jsesc": "~3.0.2"
@@ -10718,7 +12510,6 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
"integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
- "dev": true,
"license": "MIT",
"bin": {
"jsesc": "bin/jsesc"
@@ -10743,6 +12534,12 @@
"devOptional": true,
"license": "ISC"
},
+ "node_modules/reselect": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
+ "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==",
+ "license": "MIT"
+ },
"node_modules/resolve": {
"version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
@@ -10955,6 +12752,12 @@
"devOptional": true,
"license": "MIT"
},
+ "node_modules/sax": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
+ "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
+ "license": "ISC"
+ },
"node_modules/scheduler": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz",
@@ -11129,7 +12932,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "devOptional": true,
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
@@ -11142,7 +12944,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -11242,6 +13043,32 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"license": "ISC"
},
+ "node_modules/simple-plist": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.3.1.tgz",
+ "integrity": "sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==",
+ "license": "MIT",
+ "dependencies": {
+ "bplist-creator": "0.1.0",
+ "bplist-parser": "0.3.1",
+ "plist": "^3.0.5"
+ }
+ },
+ "node_modules/simple-swizzle": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+ "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
+ "node_modules/simple-swizzle/node_modules/is-arrayish": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
+ "license": "MIT"
+ },
"node_modules/sisteransi": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
@@ -11323,6 +13150,15 @@
"source-map": "^0.6.0"
}
},
+ "node_modules/split-on-first": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
+ "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@@ -11400,6 +13236,24 @@
"node": ">= 0.4"
}
},
+ "node_modules/stream-buffers": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz",
+ "integrity": "sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==",
+ "license": "Unlicense",
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/strict-uri-encode": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
+ "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@@ -11445,6 +13299,30 @@
"node": ">=8"
}
},
+ "node_modules/string-width-cjs": {
+ "name": "string-width",
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/string-width/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
@@ -11552,6 +13430,21 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/stringify-entities": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-3.1.0.tgz",
+ "integrity": "sha512-3FP+jGMmMV/ffZs86MoghGqAoqXAdxLrJP4GUdrDN1aIScYih5tuIO3eF4To5AJZ79KDZ8Fpdy7QJnK8SsL1Vg==",
+ "license": "MIT",
+ "dependencies": {
+ "character-entities-html4": "^1.0.0",
+ "character-entities-legacy": "^1.0.0",
+ "xtend": "^4.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
"node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
@@ -11564,6 +13457,19 @@
"node": ">=8"
}
},
+ "node_modules/strip-ansi-cjs": {
+ "name": "strip-ansi",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/strip-bom": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
@@ -11758,6 +13664,12 @@
"typescript": ">=4.2.0"
}
},
+ "node_modules/ts-toolbelt": {
+ "version": "6.15.5",
+ "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz",
+ "integrity": "sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==",
+ "license": "Apache-2.0"
+ },
"node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
@@ -11951,7 +13863,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz",
"integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
@@ -11961,7 +13872,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz",
"integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==",
- "dev": true,
"license": "MIT",
"dependencies": {
"unicode-canonical-property-names-ecmascript": "^2.0.0",
@@ -11975,7 +13885,6 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz",
"integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
@@ -11985,7 +13894,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz",
"integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
@@ -12050,6 +13958,30 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/urijs": {
+ "version": "1.19.11",
+ "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz",
+ "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==",
+ "license": "MIT"
+ },
+ "node_modules/use-latest-callback": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.4.tgz",
+ "integrity": "sha512-LS2s2n1usUUnDq4oVh1ca6JFX9uSqUncTfAm44WMg0v6TxL7POUTk1B044NH8TeLkFbNajIsgDHcgNpNzZucdg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
+ "node_modules/use-sync-external-store": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz",
+ "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -12066,6 +13998,15 @@
"node": ">= 0.4.0"
}
},
+ "node_modules/uuid": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz",
+ "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==",
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
"node_modules/v8-to-istanbul": {
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
@@ -12106,6 +14047,12 @@
"makeerror": "1.0.12"
}
},
+ "node_modules/warn-once": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/warn-once/-/warn-once-0.1.1.tgz",
+ "integrity": "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==",
+ "license": "MIT"
+ },
"node_modules/wcwidth": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
@@ -12126,7 +14073,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "devOptional": true,
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
@@ -12261,6 +14207,24 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
+ "node_modules/wrap-ansi-cjs": {
+ "name": "wrap-ansi",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
@@ -12289,6 +14253,68 @@
"async-limiter": "~1.0.0"
}
},
+ "node_modules/xcode": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/xcode/-/xcode-3.0.1.tgz",
+ "integrity": "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "simple-plist": "^1.1.0",
+ "uuid": "^7.0.3"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/xml2js": {
+ "version": "0.4.23",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
+ "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
+ "license": "MIT",
+ "dependencies": {
+ "sax": ">=0.6.0",
+ "xmlbuilder": "~11.0.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/xml2js/node_modules/xmlbuilder": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/xmlbuilder": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-14.0.0.tgz",
+ "integrity": "sha512-ts+B2rSe4fIckR6iquDjsKbQFK2NlUk6iG5nf14mDEyldgoc2nEKZ3jZWMPTxGQwVgToSjt6VGIho1H8/fNFTg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/xmldom": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.5.0.tgz",
+ "integrity": "sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4"
+ }
+ },
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
@@ -12348,7 +14374,6 @@
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
- "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=10"
diff --git a/package.json b/package.json
index 7548f10..83026a9 100644
--- a/package.json
+++ b/package.json
@@ -10,8 +10,38 @@
"test": "jest"
},
"dependencies": {
+ "@react-native-async-storage/async-storage": "^2.1.0",
+ "@react-native-clipboard/clipboard": "^1.16.1",
+ "@react-native-community/netinfo": "^11.4.1",
+ "@react-native-voice/voice": "^3.2.4",
+ "@react-navigation/bottom-tabs": "^7.2.0",
+ "@react-navigation/native": "^7.0.14",
+ "@react-navigation/native-stack": "^7.2.0",
+ "@react-navigation/stack": "^7.1.1",
+ "@reduxjs/toolkit": "^2.5.1",
+ "apisauce": "^3.1.0",
+ "lottie-react-native": "^7.2.2",
"react": "19.0.0",
- "react-native": "0.79.0"
+ "react-native": "0.79.0",
+ "react-native-blob-util": "^0.22.2",
+ "react-native-config": "^1.5.5",
+ "react-native-gesture-handler": "^2.22.1",
+ "react-native-image-picker": "^7.2.3",
+ "react-native-linear-gradient": "^2.8.3",
+ "react-native-permissions": "^5.2.4",
+ "react-native-raw-bottom-sheet": "^3.0.0",
+ "react-native-reanimated": "^3.18.0",
+ "react-native-render-html": "^6.3.4",
+ "react-native-responsive-dimensions": "^3.1.1",
+ "react-native-safe-area-context": "^5.1.0",
+ "react-native-screens": "^4.5.0",
+ "react-native-share": "^12.0.9",
+ "react-native-svg": "^15.11.1",
+ "react-native-toast-message": "^2.2.1",
+ "react-native-tts": "^4.1.1",
+ "react-native-vector-icons": "^10.2.0",
+ "react-redux": "^9.2.0",
+ "redux-persist": "^6.0.0"
},
"devDependencies": {
"@babel/core": "^7.25.2",
diff --git a/shared/src/components/Button/Button.tsx b/shared/src/components/Button/Button.tsx
new file mode 100644
index 0000000..6da16c1
--- /dev/null
+++ b/shared/src/components/Button/Button.tsx
@@ -0,0 +1,75 @@
+/*
+ * File: Button.tsx
+ * Description: Themed button component using Clinical Blue Interface design system
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { TouchableOpacity, Text, StyleSheet, ViewStyle, TextStyle, GestureResponderEvent } from 'react-native';
+import { Colors, Typography, Spacing, BorderRadius, Shadows } from '../../theme';
+
+// Button props for reusability and type safety
+interface ButtonProps {
+ title: string;
+ onPress: (event: GestureResponderEvent) => void;
+ style?: ViewStyle;
+ textStyle?: TextStyle;
+ disabled?: boolean;
+}
+
+/**
+ * Themed Button component
+ * - Uses Clinical Blue Interface theme
+ * - Supports custom styles and disabled state
+ */
+const Button: React.FC = ({ title, onPress, style, textStyle, disabled }) => {
+ return (
+
+ {title}
+
+ );
+};
+
+// Styles use the theme for consistency
+const styles = StyleSheet.create({
+ button: {
+ backgroundColor: Colors.primary,
+ paddingVertical: Spacing.md,
+ paddingHorizontal: Spacing.xl,
+ borderRadius: BorderRadius.md,
+ alignItems: 'center',
+ justifyContent: 'center',
+ ...Shadows.card,
+ },
+ buttonDisabled: {
+ backgroundColor: Colors.inactiveState,
+ },
+ text: {
+ color: Colors.background,
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.md,
+ fontWeight: Typography.fontWeight.bold as any,
+ letterSpacing: 0.5,
+ },
+ textDisabled: {
+ color: Colors.textMuted,
+ },
+});
+
+export default Button;
+
+/*
+ * End of File: Button.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Button/index.ts b/shared/src/components/Button/index.ts
new file mode 100644
index 0000000..075a01e
--- /dev/null
+++ b/shared/src/components/Button/index.ts
@@ -0,0 +1,14 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Button components
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as Button } from './Button';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Card/Card.styles.ts b/shared/src/components/Card/Card.styles.ts
new file mode 100644
index 0000000..66ead4d
--- /dev/null
+++ b/shared/src/components/Card/Card.styles.ts
@@ -0,0 +1,34 @@
+/*
+ * File: Card.styles.ts
+ * Description: Shared styles for card components
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { StyleSheet } from 'react-native';
+import { Colors, BorderRadius, Spacing, Shadows } from '../../theme';
+
+// Shared card styles
+export const cardStyles = StyleSheet.create({
+ card: {
+ backgroundColor: Colors.cardBackground,
+ borderRadius: BorderRadius.lg,
+ padding: Spacing.lg,
+ marginVertical: Spacing.sm,
+ marginHorizontal: Spacing.md,
+ ...Shadows.card,
+ },
+ infoCard: {
+ backgroundColor: Colors.backgroundAccent,
+ borderRadius: BorderRadius.md,
+ padding: Spacing.md,
+ marginVertical: Spacing.xs,
+ marginHorizontal: Spacing.sm,
+ },
+});
+
+/*
+ * End of File: Card.styles.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Card/Card.tsx b/shared/src/components/Card/Card.tsx
new file mode 100644
index 0000000..0519ecb
--- /dev/null
+++ b/shared/src/components/Card/Card.tsx
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/shared/src/components/Card/Card.types.ts b/shared/src/components/Card/Card.types.ts
new file mode 100644
index 0000000..54b8109
--- /dev/null
+++ b/shared/src/components/Card/Card.types.ts
@@ -0,0 +1,27 @@
+/*
+ * File: Card.types.ts
+ * Description: TypeScript types for card components
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { ReactNode } from 'react';
+import { ViewStyle } from 'react-native';
+
+// Props for Card component
+export interface CardProps {
+ children: ReactNode;
+ style?: ViewStyle;
+}
+
+// Props for InfoCard component
+export interface InfoCardProps {
+ children: ReactNode;
+ style?: ViewStyle;
+}
+
+/*
+ * End of File: Card.types.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Card/InfoCard.tsx b/shared/src/components/Card/InfoCard.tsx
new file mode 100644
index 0000000..606c19e
--- /dev/null
+++ b/shared/src/components/Card/InfoCard.tsx
@@ -0,0 +1,31 @@
+/*
+ * File: InfoCard.tsx
+ * Description: Themed info card using Clinical Blue Interface design system
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React, { ReactNode } from 'react';
+import { View, StyleSheet, ViewStyle } from 'react-native';
+import { cardStyles } from './Card.styles';
+
+interface InfoCardProps {
+ children: ReactNode;
+ style?: ViewStyle;
+}
+
+/**
+ * InfoCard component
+ * - Simple card for displaying information
+ */
+const InfoCard: React.FC = ({ children, style }) => (
+ {children}
+);
+
+export default InfoCard;
+
+/*
+ * End of File: InfoCard.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Card/index.ts b/shared/src/components/Card/index.ts
new file mode 100644
index 0000000..c394be1
--- /dev/null
+++ b/shared/src/components/Card/index.ts
@@ -0,0 +1,14 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Card components
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as Card } from './Card';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Icons/CustomIcon.tsx b/shared/src/components/Icons/CustomIcon.tsx
new file mode 100644
index 0000000..13172bd
--- /dev/null
+++ b/shared/src/components/Icons/CustomIcon.tsx
@@ -0,0 +1,33 @@
+/*
+ * File: CustomIcon.tsx
+ * Description: Themed icon component using Clinical Blue Interface design system
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
+import { Colors } from '../../theme';
+
+interface CustomIconProps {
+ name: string;
+ size?: number;
+ color?: string;
+ style?: any;
+}
+
+/**
+ * CustomIcon component
+ * - Uses MaterialCommunityIcons and theme colors
+ */
+const CustomIcon: React.FC = ({ name, size = 24, color = Colors.primary, style }) => (
+
+);
+
+export default CustomIcon;
+
+/*
+ * End of File: CustomIcon.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Icons/IconButton.tsx b/shared/src/components/Icons/IconButton.tsx
new file mode 100644
index 0000000..7f97b26
--- /dev/null
+++ b/shared/src/components/Icons/IconButton.tsx
@@ -0,0 +1,56 @@
+/*
+ * File: IconButton.tsx
+ * Description: Themed icon button using Clinical Blue Interface design system
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { TouchableOpacity, StyleSheet, ViewStyle, GestureResponderEvent } from 'react-native';
+import CustomIcon from './CustomIcon';
+import { Colors, Spacing, BorderRadius } from '../../theme';
+
+interface IconButtonProps {
+ name: string;
+ size?: number;
+ color?: string;
+ onPress: (event: GestureResponderEvent) => void;
+ style?: ViewStyle;
+ disabled?: boolean;
+}
+
+/**
+ * IconButton component
+ * - Renders a touchable icon with theme styling
+ */
+const IconButton: React.FC = ({ name, size = 24, color = Colors.primary, onPress, style, disabled }) => (
+
+
+
+);
+
+const styles = StyleSheet.create({
+ button: {
+ padding: Spacing.sm,
+ borderRadius: BorderRadius.md,
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: Colors.backgroundAlt,
+ },
+ disabled: {
+ opacity: 0.5,
+ },
+});
+
+export default IconButton;
+
+/*
+ * End of File: IconButton.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Icons/index.ts b/shared/src/components/Icons/index.ts
new file mode 100644
index 0000000..c2ffa86
--- /dev/null
+++ b/shared/src/components/Icons/index.ts
@@ -0,0 +1,15 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Icons components
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as CustomIcon } from './CustomIcon';
+export { default as IconButton } from './IconButton';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Input/Input.styles.ts b/shared/src/components/Input/Input.styles.ts
new file mode 100644
index 0000000..adddcb3
--- /dev/null
+++ b/shared/src/components/Input/Input.styles.ts
@@ -0,0 +1,39 @@
+/*
+ * File: Input.styles.ts
+ * Description: Shared styles for input components
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { StyleSheet } from 'react-native';
+import { Colors, BorderRadius, Spacing, Typography } from '../../theme';
+
+// Shared input styles
+export const inputStyles = StyleSheet.create({
+ textInput: {
+ backgroundColor: Colors.backgroundAlt,
+ borderRadius: BorderRadius.md,
+ color: Colors.textPrimary,
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.md,
+ paddingHorizontal: Spacing.md,
+ paddingVertical: Spacing.sm,
+ marginVertical: Spacing.xs,
+ },
+ searchInput: {
+ backgroundColor: Colors.tertiary,
+ borderRadius: BorderRadius.md,
+ color: Colors.textPrimary,
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.sm,
+ paddingHorizontal: Spacing.md,
+ paddingVertical: Spacing.xs,
+ marginVertical: Spacing.xs,
+ },
+});
+
+/*
+ * End of File: Input.styles.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Input/Input.types.ts b/shared/src/components/Input/Input.types.ts
new file mode 100644
index 0000000..ba6c177
--- /dev/null
+++ b/shared/src/components/Input/Input.types.ts
@@ -0,0 +1,24 @@
+/*
+ * File: Input.types.ts
+ * Description: TypeScript types for input components
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { TextInputProps } from 'react-native';
+
+// Props for Themed TextInput
+export interface ThemedTextInputProps extends TextInputProps {
+ containerStyle?: any;
+}
+
+// Props for SearchInput
+export interface SearchInputProps extends TextInputProps {
+ containerStyle?: any;
+}
+
+/*
+ * End of File: Input.types.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Input/SearchInput.tsx b/shared/src/components/Input/SearchInput.tsx
new file mode 100644
index 0000000..950c68c
--- /dev/null
+++ b/shared/src/components/Input/SearchInput.tsx
@@ -0,0 +1,53 @@
+/*
+ * File: SearchInput.tsx
+ * Description: Themed search input using Clinical Blue Interface design system
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, TextInput as RNTextInput, StyleSheet, TextInputProps } from 'react-native';
+import { inputStyles } from './Input.styles';
+import CustomIcon from '../Icons/CustomIcon';
+import { Colors, Spacing } from '../../theme';
+
+interface SearchInputProps extends TextInputProps {
+ containerStyle?: any;
+}
+
+/**
+ * SearchInput component
+ * - Renders a search bar with icon and themed styles
+ */
+const SearchInput: React.FC = ({ containerStyle, style, ...props }) => (
+
+
+
+
+);
+
+const styles = StyleSheet.create({
+ container: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ backgroundColor: Colors.tertiary,
+ borderRadius: 8,
+ paddingHorizontal: Spacing.sm,
+ marginVertical: Spacing.xs,
+ },
+ icon: {
+ marginRight: Spacing.xs,
+ },
+});
+
+export default SearchInput;
+
+/*
+ * End of File: SearchInput.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Input/TextInput.tsx b/shared/src/components/Input/TextInput.tsx
new file mode 100644
index 0000000..40d8c75
--- /dev/null
+++ b/shared/src/components/Input/TextInput.tsx
@@ -0,0 +1,57 @@
+/*
+ * File: TextInput.tsx
+ * Description: Themed text input component using Clinical Blue Interface design system
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { TextInput as RNTextInput, StyleSheet, TextInputProps, View, ViewStyle } from 'react-native';
+import { Colors, Spacing, BorderRadius, Typography } from '../../theme';
+
+// Props for the themed TextInput
+interface ThemedTextInputProps extends TextInputProps {
+ containerStyle?: ViewStyle;
+}
+
+/**
+ * Themed TextInput component
+ * - Uses Clinical Blue Interface theme
+ * - Supports custom container styles
+ */
+const TextInput: React.FC = ({ containerStyle, style, ...props }) => {
+ return (
+
+
+
+ );
+};
+
+// Styles use the theme for consistency
+const styles = StyleSheet.create({
+ container: {
+ backgroundColor: Colors.backgroundAlt,
+ borderRadius: BorderRadius.md,
+ paddingHorizontal: Spacing.md,
+ paddingVertical: Spacing.sm,
+ marginVertical: Spacing.xs,
+ },
+ input: {
+ color: Colors.textPrimary,
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.md,
+ padding: 0,
+ },
+});
+
+export default TextInput;
+
+/*
+ * End of File: TextInput.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Input/index.ts b/shared/src/components/Input/index.ts
new file mode 100644
index 0000000..d9e8334
--- /dev/null
+++ b/shared/src/components/Input/index.ts
@@ -0,0 +1,15 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Input components
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as TextInput } from './TextInput';
+// Add other input components here as you implement them
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Loading/Loading.styles.ts b/shared/src/components/Loading/Loading.styles.ts
new file mode 100644
index 0000000..8eb314e
--- /dev/null
+++ b/shared/src/components/Loading/Loading.styles.ts
@@ -0,0 +1,28 @@
+/*
+ * File: Loading.styles.ts
+ * Description: Shared styles for loading components
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { StyleSheet } from 'react-native';
+import { Colors, Spacing } from '../../theme';
+
+// Shared loading styles
+export const loadingStyles = StyleSheet.create({
+ overlay: {
+ flex: 1,
+ backgroundColor: Colors.shadow,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ spinner: {
+ padding: Spacing.md,
+ },
+});
+
+/*
+ * End of File: Loading.styles.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Loading/LoadingOverlay.tsx b/shared/src/components/Loading/LoadingOverlay.tsx
new file mode 100644
index 0000000..f8c8fa2
--- /dev/null
+++ b/shared/src/components/Loading/LoadingOverlay.tsx
@@ -0,0 +1,44 @@
+/*
+ * File: LoadingOverlay.tsx
+ * Description: Fullscreen loading overlay using Clinical Blue Interface design system
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { View, StyleSheet, Modal } from 'react-native';
+import Spinner from './Spinner';
+import { Colors } from '../../theme';
+
+interface LoadingOverlayProps {
+ visible: boolean;
+}
+
+/**
+ * LoadingOverlay component
+ * - Shows a fullscreen spinner overlay
+ */
+const LoadingOverlay: React.FC = ({ visible }) => (
+
+
+
+
+
+);
+
+const styles = StyleSheet.create({
+ overlay: {
+ flex: 1,
+ backgroundColor: Colors.shadow,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+});
+
+export default LoadingOverlay;
+
+/*
+ * End of File: LoadingOverlay.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Loading/Spinner.tsx b/shared/src/components/Loading/Spinner.tsx
new file mode 100644
index 0000000..6581078
--- /dev/null
+++ b/shared/src/components/Loading/Spinner.tsx
@@ -0,0 +1,42 @@
+/*
+ * File: Spinner.tsx
+ * Description: Themed loading spinner using Clinical Blue Interface design system
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { ActivityIndicator, View, StyleSheet, ViewStyle } from 'react-native';
+import { Colors, Spacing } from '../../theme';
+
+interface SpinnerProps {
+ size?: 'small' | 'large';
+ style?: ViewStyle;
+}
+
+/**
+ * Themed Spinner component
+ * - Uses Clinical Blue Interface theme
+ * - Supports custom size and style
+ */
+const Spinner: React.FC = ({ size = 'large', style }) => (
+
+
+
+);
+
+const styles = StyleSheet.create({
+ container: {
+ padding: Spacing.md,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+});
+
+export default Spinner;
+
+/*
+ * End of File: Spinner.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Loading/index.ts b/shared/src/components/Loading/index.ts
new file mode 100644
index 0000000..ae3f136
--- /dev/null
+++ b/shared/src/components/Loading/index.ts
@@ -0,0 +1,15 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Loading components
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as Spinner } from './Spinner';
+export { default as LoadingOverlay } from './LoadingOverlay';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Modal/AlertModal.tsx b/shared/src/components/Modal/AlertModal.tsx
new file mode 100644
index 0000000..91219fd
--- /dev/null
+++ b/shared/src/components/Modal/AlertModal.tsx
@@ -0,0 +1,69 @@
+/*
+ * File: AlertModal.tsx
+ * Description: Alert modal using Clinical Blue Interface design system
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { Text, View, StyleSheet } from 'react-native';
+import Modal from './Modal';
+import Button from '../Button/Button';
+import CustomIcon from '../Icons/CustomIcon';
+import { Colors, Typography, Spacing } from '../../theme';
+
+interface AlertModalProps {
+ visible: boolean;
+ title: string;
+ message: string;
+ iconName?: string;
+ iconColor?: string;
+ onDismiss: () => void;
+}
+
+/**
+ * AlertModal component
+ * - Shows an alert dialog with icon, title, message, and dismiss button
+ */
+const AlertModal: React.FC = ({ visible, title, message, iconName = 'alert-circle', iconColor = Colors.warning, onDismiss }) => (
+
+
+
+
+ {title}
+ {message}
+
+
+);
+
+const styles = StyleSheet.create({
+ iconContainer: {
+ alignItems: 'center',
+ marginBottom: Spacing.sm,
+ },
+ title: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.lg,
+ color: Colors.textPrimary,
+ marginBottom: Spacing.xs,
+ textAlign: 'center',
+ },
+ message: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textSecondary,
+ marginBottom: Spacing.lg,
+ textAlign: 'center',
+ },
+ button: {
+ marginTop: Spacing.sm,
+ },
+});
+
+export default AlertModal;
+
+/*
+ * End of File: AlertModal.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Modal/ConfirmModal.tsx b/shared/src/components/Modal/ConfirmModal.tsx
new file mode 100644
index 0000000..baaff27
--- /dev/null
+++ b/shared/src/components/Modal/ConfirmModal.tsx
@@ -0,0 +1,71 @@
+/*
+ * File: ConfirmModal.tsx
+ * Description: Confirmation modal using Clinical Blue Interface design system
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { Text, View, StyleSheet } from 'react-native';
+import Modal from './Modal';
+import Button from '../Button/Button';
+import { Colors, Typography, Spacing } from '../../theme';
+
+interface ConfirmModalProps {
+ visible: boolean;
+ title: string;
+ message: string;
+ onConfirm: () => void;
+ onCancel: () => void;
+}
+
+/**
+ * ConfirmModal component
+ * - Shows a confirmation dialog with two actions
+ */
+const ConfirmModal: React.FC = ({ visible, title, message, onConfirm, onCancel }) => (
+
+ {title}
+ {message}
+
+
+
+
+
+);
+
+const styles = StyleSheet.create({
+ title: {
+ fontFamily: Typography.fontFamily.bold,
+ fontSize: Typography.fontSize.lg,
+ color: Colors.textPrimary,
+ marginBottom: Spacing.sm,
+ textAlign: 'center',
+ },
+ message: {
+ fontFamily: Typography.fontFamily.regular,
+ fontSize: Typography.fontSize.md,
+ color: Colors.textSecondary,
+ marginBottom: Spacing.lg,
+ textAlign: 'center',
+ },
+ actions: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ },
+ button: {
+ flex: 1,
+ marginHorizontal: Spacing.xs,
+ },
+ cancelText: {
+ color: Colors.error,
+ },
+});
+
+export default ConfirmModal;
+
+/*
+ * End of File: ConfirmModal.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Modal/Modal.tsx b/shared/src/components/Modal/Modal.tsx
new file mode 100644
index 0000000..d1ca486
--- /dev/null
+++ b/shared/src/components/Modal/Modal.tsx
@@ -0,0 +1,76 @@
+/*
+ * File: Modal.tsx
+ * Description: Themed modal component using Clinical Blue Interface design system
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React, { ReactNode } from 'react';
+import { Modal as RNModal, View, StyleSheet, TouchableWithoutFeedback } from 'react-native';
+import { Colors, BorderRadius, Spacing } from '../../theme';
+
+interface ModalProps {
+ visible: boolean;
+ onRequestClose: () => void;
+ children: ReactNode;
+}
+
+/**
+ * Themed Modal component
+ * - Uses Clinical Blue Interface theme
+ * - Handles backdrop and content styling
+ */
+const Modal: React.FC = ({ visible, onRequestClose, children }) => {
+ return (
+
+
+
+
+
+ {children}
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ backdrop: {
+ flex: 1,
+ backgroundColor: Colors.shadow,
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ },
+ centeredView: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ modalView: {
+ backgroundColor: Colors.cardBackground,
+ borderRadius: BorderRadius.lg,
+ padding: Spacing.xl,
+ minWidth: 280,
+ maxWidth: '90%',
+ shadowColor: Colors.primary,
+ shadowOffset: { width: 0, height: 2 },
+ shadowOpacity: 0.2,
+ shadowRadius: 8,
+ elevation: 8,
+ },
+});
+
+export default Modal;
+
+/*
+ * End of File: Modal.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/components/Modal/index.ts b/shared/src/components/Modal/index.ts
new file mode 100644
index 0000000..27d9bdd
--- /dev/null
+++ b/shared/src/components/Modal/index.ts
@@ -0,0 +1,16 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Modal components
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as Modal } from './Modal';
+export { default as ConfirmModal } from './ConfirmModal';
+export { default as AlertModal } from './AlertModal';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/theme/animations.ts b/shared/src/theme/animations.ts
new file mode 100644
index 0000000..1874aef
--- /dev/null
+++ b/shared/src/theme/animations.ts
@@ -0,0 +1,29 @@
+/*
+ * File: animations.ts
+ * Description: Animation settings for Clinical Blue Interface theme
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+// Animation durations and easing functions
+export const Animations = {
+ duration: {
+ fast: 150,
+ normal: 300,
+ slow: 600,
+ },
+ easing: {
+ standard: 'ease-in-out',
+ decelerate: 'cubic-bezier(0.0, 0.0, 0.2, 1)',
+ accelerate: 'cubic-bezier(0.4, 0.0, 1, 1)',
+ },
+};
+
+// Usage: import { Animations } from './animations';
+// Example: transitionDuration: Animations.duration.normal
+
+/*
+ * End of File: animations.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/theme/borderRadius.ts b/shared/src/theme/borderRadius.ts
new file mode 100644
index 0000000..4200285
--- /dev/null
+++ b/shared/src/theme/borderRadius.ts
@@ -0,0 +1,23 @@
+/*
+ * File: borderRadius.ts
+ * Description: Border radius values for Clinical Blue Interface theme
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+// Border radius values for rounded corners
+export const BorderRadius = {
+ sm: 4,
+ md: 8,
+ lg: 16,
+ xl: 24,
+};
+
+// Usage: import { BorderRadius } from './borderRadius';
+// Example: style={{ borderRadius: BorderRadius.md }}
+
+/*
+ * End of File: borderRadius.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/theme/colors.ts b/shared/src/theme/colors.ts
new file mode 100644
index 0000000..6554061
--- /dev/null
+++ b/shared/src/theme/colors.ts
@@ -0,0 +1,39 @@
+/*
+ * File: colors.ts
+ * Description: Color palette for Clinical Blue Interface theme
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+// Clinical Blue Interface color palette for the Radiologist App
+export const Colors = {
+ primary: '#5B7CE6', // Blue Purple - selected buttons
+ secondary: '#7B94F0', // Light Blue Purple
+ tertiary: '#E8EFFF', // Very Light Blue
+ quaternary: '#3B5998', // Deep Blue
+ textPrimary: '#1A1D29', // Almost Black
+ textSecondary: '#4A5568', // Medium Gray
+ textMuted: '#9CA3AF', // Light Gray
+ background: '#FFFFFF', // White
+ backgroundAlt: '#F8FAFF', // Very Light Blue Tint
+ backgroundAccent: '#F1F5FF', // Soft Blue
+ cardBackground: '#FFFFFF', // White with shadow
+ success: '#10B981', // Green - security icon
+ warning: '#F59E0B', // Amber
+ error: '#EF4444', // Red
+ info: '#3B82F6', // Blue
+ border: '#E5E7EB', // Light Gray
+ selectedState: '#5B7CE6', // Same as Primary
+ inactiveState: '#F3F4F6', // Light Gray
+ shadow: 'rgba(91, 124, 230, 0.1)', // Blue Shadow
+ gradient: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', // Gradient Background
+};
+
+// Usage: import { Colors } from './colors';
+// Example: style={{ backgroundColor: Colors.primary }}
+
+/*
+ * End of File: colors.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/theme/index.ts b/shared/src/theme/index.ts
new file mode 100644
index 0000000..e91d66d
--- /dev/null
+++ b/shared/src/theme/index.ts
@@ -0,0 +1,20 @@
+/*
+ * File: index.ts
+ * Description: Barrel export for Clinical Blue Interface theme
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+// Export all theme modules for easy import
+export * from './colors';
+export * from './typography';
+export * from './spacing';
+export * from './shadows';
+export * from './borderRadius';
+export * from './animations';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/theme/shadows.ts b/shared/src/theme/shadows.ts
new file mode 100644
index 0000000..e72ccef
--- /dev/null
+++ b/shared/src/theme/shadows.ts
@@ -0,0 +1,26 @@
+/*
+ * File: shadows.ts
+ * Description: Shadow styles for Clinical Blue Interface theme
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+// Shadow styles for card and elevated elements
+export const Shadows = {
+ card: {
+ shadowColor: '#5B7CE6',
+ shadowOffset: { width: 0, height: 2 },
+ shadowOpacity: 0.1,
+ shadowRadius: 8,
+ elevation: 4,
+ },
+};
+
+// Usage: import { Shadows } from './shadows';
+// Example: style={Shadows.card}
+
+/*
+ * End of File: shadows.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/theme/spacing.ts b/shared/src/theme/spacing.ts
new file mode 100644
index 0000000..b1fd245
--- /dev/null
+++ b/shared/src/theme/spacing.ts
@@ -0,0 +1,25 @@
+/*
+ * File: spacing.ts
+ * Description: Spacing scale for Clinical Blue Interface theme
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+// Spacing system for consistent paddings and margins
+export const Spacing = {
+ xs: 4,
+ sm: 8,
+ md: 16,
+ lg: 24,
+ xl: 32,
+ xxl: 40,
+};
+
+// Usage: import { Spacing } from './spacing';
+// Example: style={{ padding: Spacing.md }}
+
+/*
+ * End of File: spacing.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file
diff --git a/shared/src/theme/typography.ts b/shared/src/theme/typography.ts
new file mode 100644
index 0000000..720a427
--- /dev/null
+++ b/shared/src/theme/typography.ts
@@ -0,0 +1,37 @@
+/*
+ * File: typography.ts
+ * Description: Typography settings for Clinical Blue Interface theme
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+// Typography system for the Radiologist App
+export const Typography = {
+ fontFamily: {
+ regular: 'Roboto-Regular',
+ bold: 'Roboto-Bold',
+ },
+ fontSize: {
+ xs: 12,
+ sm: 14,
+ md: 16,
+ lg: 18,
+ xl: 22,
+ xxl: 28,
+ title: 32,
+ },
+ fontWeight: {
+ regular: '400',
+ medium: '500',
+ bold: '700',
+ },
+};
+
+// Usage: import { Typography } from './typography';
+// Example: style={{ fontFamily: Typography.fontFamily.bold, fontSize: Typography.fontSize.lg }}
+
+/*
+ * End of File: typography.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
\ No newline at end of file