feat: implement KYC document viewing screen and foundational utility services

This commit is contained in:
Tamojit Biswas 2026-07-21 13:04:40 +05:30
parent 3e18e618d1
commit d9766b842c
13 changed files with 985 additions and 243 deletions

View File

@ -77,7 +77,7 @@ export const CompleteProfileScreen: React.FC = () => {
)
.unwrap()
.then(() => {
navigation.navigate(RouteNames.Kyc);
navigation.replace(RouteNames.Kyc);
})
.catch(error => {
Alert.alert('Error', error.message);

View File

@ -1,6 +1,8 @@
import { StyleSheet } from 'react-native';
import { StyleSheet, Dimensions } from 'react-native';
import { typography, spacing, borderRadius, shadow } from '@theme';
const { width, height } = Dimensions.get('window');
export const getStyles = (colors: any) =>
StyleSheet.create({
container: {
@ -9,35 +11,81 @@ export const getStyles = (colors: any) =>
},
scrollContainer: {
paddingHorizontal: spacing.lg,
paddingTop: spacing.md,
paddingBottom: spacing.xxl,
},
docCard: {
summaryCard: {
backgroundColor: colors.primaryLight,
borderRadius: borderRadius.lg,
padding: spacing.lg,
marginBottom: spacing.lg,
borderWidth: 1,
borderColor: colors.border,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
summaryLeft: {
flex: 1,
},
summaryTitle: {
fontSize: typography.fontSize.lg,
fontWeight: typography.fontWeight.bold,
color: colors.primaryDark || colors.primary,
marginBottom: spacing.xs,
},
summarySub: {
fontSize: typography.fontSize.sm,
color: colors.textSecondary,
},
summaryBadge: {
backgroundColor: colors.primary,
paddingHorizontal: spacing.md,
paddingVertical: spacing.xs,
borderRadius: borderRadius.full,
},
summaryBadgeText: {
fontSize: typography.fontSize.xs,
fontWeight: typography.fontWeight.bold,
color: colors.white,
},
sectionTitle: {
fontSize: typography.fontSize.md,
fontWeight: typography.fontWeight.bold,
color: colors.text,
marginBottom: spacing.md,
},
docCard: {
backgroundColor: colors.cardBg,
borderRadius: borderRadius.md,
padding: spacing.md,
marginBottom: spacing.sm,
borderRadius: borderRadius.lg,
padding: spacing.lg,
marginBottom: spacing.md,
borderWidth: 1,
borderColor: colors.border,
...shadow.sm,
},
docLeft: {
cardHeader: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: spacing.md,
},
cardHeaderLeft: {
flexDirection: 'row',
alignItems: 'center',
flex: 1,
marginRight: spacing.sm,
},
iconContainer: {
width: 40,
height: 40,
borderRadius: borderRadius.full,
width: 44,
height: 44,
borderRadius: borderRadius.md,
backgroundColor: colors.primaryLight,
justifyContent: 'center',
alignItems: 'center',
marginRight: spacing.md,
},
docInfo: {
docTypeContainer: {
flex: 1,
},
docTitle: {
@ -46,22 +94,161 @@ export const getStyles = (colors: any) =>
color: colors.text,
marginBottom: 2,
},
docSub: {
docNumber: {
fontSize: typography.fontSize.xs,
color: colors.textSecondary,
},
statusContainer: {
flexDirection: 'row',
alignItems: 'center',
fontWeight: typography.fontWeight.medium,
},
statusBadge: {
paddingHorizontal: spacing.sm,
paddingVertical: 4,
borderRadius: borderRadius.sm,
marginRight: spacing.sm,
alignSelf: 'flex-start',
},
statusText: {
fontSize: 10,
fontWeight: 'bold',
fontSize: typography.fontSize.xs - 2,
fontWeight: typography.fontWeight.bold,
letterSpacing: 0.5,
},
divider: {
height: 1,
backgroundColor: colors.divider,
marginVertical: spacing.md,
},
detailsRow: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: spacing.md,
},
detailItem: {
flex: 1,
},
detailLabel: {
fontSize: typography.fontSize.xs - 1,
color: colors.textSecondary,
marginBottom: 2,
},
detailValue: {
fontSize: typography.fontSize.xs,
color: colors.text,
fontWeight: typography.fontWeight.semibold,
},
viewButton: {
backgroundColor: colors.inputBg,
borderWidth: 1,
borderColor: colors.border,
borderRadius: borderRadius.md,
paddingVertical: spacing.sm,
paddingHorizontal: spacing.md,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
viewButtonText: {
fontSize: typography.fontSize.sm,
fontWeight: typography.fontWeight.semibold,
color: colors.primary,
marginRight: spacing.xs,
},
filePill: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: colors.inputBg,
paddingHorizontal: spacing.md,
paddingVertical: spacing.xs + 2,
borderRadius: borderRadius.sm,
maxWidth: '70%',
},
fileNameText: {
fontSize: typography.fontSize.xs,
color: colors.textSecondary,
marginLeft: spacing.xs,
},
// Full Screen Modal Styles
modalContainer: {
flex: 1,
backgroundColor: colors.background,
},
modalHeader: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: spacing.lg,
paddingTop: spacing.xl,
paddingBottom: spacing.md,
backgroundColor: colors.cardBg,
borderBottomWidth: 1,
borderBottomColor: colors.border,
...shadow.sm,
},
modalHeaderInfo: {
flex: 1,
marginRight: spacing.md,
},
modalTitle: {
fontSize: typography.fontSize.lg,
fontWeight: typography.fontWeight.bold,
color: colors.text,
},
modalSubtitle: {
fontSize: typography.fontSize.xs,
color: colors.textSecondary,
marginTop: 2,
},
closeButton: {
width: 38,
height: 38,
borderRadius: borderRadius.full,
backgroundColor: colors.inputBg,
justifyContent: 'center',
alignItems: 'center',
},
viewerContainer: {
flex: 1,
backgroundColor: '#121212',
justifyContent: 'center',
alignItems: 'center',
},
pdfViewer: {
flex: 1,
width: width,
height: height,
backgroundColor: '#121212',
},
imageViewer: {
width: '100%',
height: '100%',
},
loadingContainer: {
position: 'absolute',
zIndex: 10,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(0,0,0,0.4)',
padding: spacing.xl,
borderRadius: borderRadius.lg,
},
loadingText: {
color: colors.white,
marginTop: spacing.md,
fontSize: typography.fontSize.sm,
fontWeight: typography.fontWeight.medium,
},
emptyContainer: {
alignItems: 'center',
justifyContent: 'center',
paddingVertical: spacing.huge,
},
emptyTitle: {
fontSize: typography.fontSize.lg,
fontWeight: typography.fontWeight.bold,
color: colors.text,
marginTop: spacing.md,
},
emptySub: {
fontSize: typography.fontSize.sm,
color: colors.textSecondary,
marginTop: spacing.xs,
},
});

View File

@ -1,87 +1,266 @@
import React from 'react';
import { View, Text, ScrollView, TouchableOpacity, Alert } from 'react-native';
import React, { useEffect, useState } from 'react';
import {
View,
Text,
ScrollView,
TouchableOpacity,
Modal,
Image,
ActivityIndicator,
SafeAreaView,
} from 'react-native';
import Pdf from 'react-native-pdf';
import { useAppTheme } from '@theme';
import { ScreenHeader } from '@components';
import { ClipboardIcon, ChevronRightIcon } from '@icons';
import { ClipboardIcon, CloseIcon, ChevronRightIcon } from '@icons';
import { useNavigation } from '@react-navigation/native';
import { getFullUrl, isPdf } from '@utils/helper';
import { getStyles } from './documentsScreen.styles';
import { KycDocUploadResponseDocument } from '@interfaces';
import { formatDate } from '@utils/formatters';
import { useAppDispatch, useAppSelector } from '@store';
import { fetchMyKyc } from '../kycScreen';
export const DocumentsScreen: React.FC = () => {
const { colors } = useAppTheme();
const styles = getStyles(colors);
const navigation = useNavigation();
const dispatch = useAppDispatch();
const documentsList = [
{ id: 'dl', title: 'Driving License', sub: 'Verified', status: 'verified' },
{ id: 'aadhaar', title: 'Aadhaar Card', sub: 'Verified', status: 'verified' },
{ id: 'rc', title: 'Vehicle RC', sub: 'Verified', status: 'verified' },
{ id: 'insurance', title: 'Insurance', sub: 'Expires on 12 May 2026', status: 'expiring' },
{ id: 'vehicle_photo', title: 'Vehicle Photo', sub: 'Verified', status: 'verified' },
{ id: 'profile_photo', title: 'Profile Photo', sub: 'Verified', status: 'verified' },
];
const [selectedDoc, setSelectedDoc] =
useState<KycDocUploadResponseDocument | null>(null);
const [isModalLoading, setIsModalLoading] = useState<boolean>(true);
const { myKycResponse } = useAppSelector(state => state.kyc);
const handleDocClick = (title: string) => {
Alert.alert('Document Preview', `Opening document view for ${title}...`);
useEffect(() => {
dispatch(fetchMyKyc());
}, []);
const getStatusBadgeConfig = (status: string) => {
switch (status?.toUpperCase()) {
case 'APPROVED':
case 'VERIFIED':
return {
bg: colors.successLight,
text: colors.success,
label: 'APPROVED',
};
case 'PENDING':
return {
bg: colors.warningLight,
text: colors.warning,
label: 'PENDING',
};
case 'REJECTED':
return {
bg: colors.errorLight,
text: colors.error,
label: 'REJECTED',
};
default:
return {
bg: colors.primaryLight,
text: colors.primary,
label: status?.toUpperCase() || 'ACTIVE',
};
}
};
const handleOpenDocModal = (doc: KycDocUploadResponseDocument) => {
setIsModalLoading(true);
setSelectedDoc(doc);
};
const approvedCount = myKycResponse?.documents?.filter(
d => d.status === 'APPROVED',
).length;
return (
<View style={styles.container}>
{/* Navigation Screen Header */}
{/* Screen Header */}
<ScreenHeader
title="Documents"
title="My Documents"
showBack={true}
onBack={() => navigation.goBack()}
/>
<ScrollView contentContainerStyle={styles.scrollContainer} showsVerticalScrollIndicator={false}>
{documentsList.map((doc) => (
<TouchableOpacity
key={doc.id}
style={styles.docCard}
activeOpacity={0.7}
onPress={() => handleDocClick(doc.title)}
>
<View style={styles.docLeft}>
<View style={styles.iconContainer}>
<ClipboardIcon size={20} color={colors.primary} />
</View>
<View style={styles.docInfo}>
<Text style={styles.docTitle} numberOfLines={1}>{doc.title}</Text>
<Text style={styles.docSub}>{doc.sub}</Text>
</View>
<ScrollView
contentContainerStyle={styles.scrollContainer}
showsVerticalScrollIndicator={false}
>
{/* Document Status Overview Banner */}
<View style={styles.summaryCard}>
<View style={styles.summaryLeft}>
<Text style={styles.summaryTitle}>Document Verification</Text>
<Text style={styles.summarySub}>
{approvedCount} of {myKycResponse?.documents?.length} Documents
Verified
</Text>
</View>
<View style={styles.summaryBadge}>
<Text style={styles.summaryBadgeText}>
{approvedCount === myKycResponse?.documents?.length
? 'VERIFIED'
: 'PENDING'}
</Text>
</View>
</View>
<Text style={styles.sectionTitle}>Uploaded Documents</Text>
{myKycResponse?.documents?.length === 0 ? (
<View style={styles.emptyContainer}>
<ClipboardIcon size={48} color={colors.placeholder} />
<Text style={styles.emptyTitle}>No Documents Found</Text>
<Text style={styles.emptySub}>
Your uploaded documents will appear here.
</Text>
</View>
) : (
myKycResponse?.documents?.map(doc => {
const statusConfig = getStatusBadgeConfig(doc.status);
const formattedDocName =
doc.documentType === 'Pan' ? 'PAN Card' : doc.documentType;
return (
<TouchableOpacity
key={doc.id}
style={styles.docCard}
activeOpacity={0.7}
onPress={() => handleOpenDocModal(doc)}
>
{/* Header Row */}
<View style={styles.cardHeader}>
<View style={styles.cardHeaderLeft}>
<View style={styles.iconContainer}>
<ClipboardIcon size={22} color={colors.primary} />
</View>
<View style={styles.docTypeContainer}>
<Text style={styles.docTitle} numberOfLines={1}>
{formattedDocName}
</Text>
<Text style={styles.docNumber}>
Doc #: {doc.documentNumber}
</Text>
</View>
</View>
<View
style={[
styles.statusBadge,
{ backgroundColor: statusConfig.bg },
]}
>
<Text
style={[styles.statusText, { color: statusConfig.text }]}
>
{statusConfig.label}
</Text>
</View>
</View>
{/* Details Section */}
<View style={styles.detailsRow}>
<View style={styles.detailItem}>
<Text style={styles.detailLabel}>Uploaded On</Text>
<Text style={styles.detailValue}>
{formatDate(doc.createdAt)}
</Text>
</View>
{doc.verifiedAt && (
<View style={styles.detailItem}>
<Text style={styles.detailLabel}>Verified On</Text>
<Text style={styles.detailValue}>
{formatDate(doc.verifiedAt)}
</Text>
</View>
)}
</View>
<View style={styles.divider} />
{/* View Button Footer */}
<View style={styles.viewButton}>
<Text style={styles.viewButtonText}>View Document</Text>
<ChevronRightIcon size={16} color={colors.primary} />
</View>
</TouchableOpacity>
);
})
)}
</ScrollView>
{/* Full Screen View Modal */}
<Modal
visible={!!selectedDoc}
animationType="slide"
statusBarTranslucent
onRequestClose={() => setSelectedDoc(null)}
>
<SafeAreaView style={styles.modalContainer}>
{/* Modal Header */}
<View style={styles.modalHeader}>
<View style={styles.modalHeaderInfo}>
<Text style={styles.modalTitle} numberOfLines={1}>
{selectedDoc?.documentType === 'Pan'
? 'PAN Card'
: selectedDoc?.documentType}{' '}
Preview
</Text>
<Text style={styles.modalSubtitle} numberOfLines={1}>
{selectedDoc?.fileName}
</Text>
</View>
<View style={styles.statusContainer}>
<View
style={[
styles.statusBadge,
{
backgroundColor:
doc.status === 'verified'
? colors.primaryLight
: colors.warningLight,
},
]}
>
<Text
style={[
styles.statusText,
{
color:
doc.status === 'verified'
? colors.primary
: colors.warning,
},
]}
>
{doc.status === 'verified' ? 'VERIFIED' : 'ACTIVE'}
</Text>
<TouchableOpacity
style={styles.closeButton}
activeOpacity={0.7}
onPress={() => setSelectedDoc(null)}
>
<CloseIcon size={20} color={colors.text} />
</TouchableOpacity>
</View>
{/* Modal Body / Viewer */}
<View style={styles.viewerContainer}>
{isModalLoading && (
<View style={styles.loadingContainer}>
<ActivityIndicator size="large" color={colors.primary} />
<Text style={styles.loadingText}>Loading file preview...</Text>
</View>
<ChevronRightIcon size={20} color={colors.textSecondary} />
</View>
</TouchableOpacity>
))}
</ScrollView>
)}
{selectedDoc &&
isPdf(selectedDoc.fileName || selectedDoc.fileUrl) ? (
<Pdf
trustAllCerts={false}
source={{
uri: getFullUrl(selectedDoc.fileUrl),
cache: true,
}}
onLoadComplete={() => setIsModalLoading(false)}
onError={error => {
setIsModalLoading(false);
console.log('PDF Load Error:', error);
}}
style={styles.pdfViewer}
/>
) : (
selectedDoc && (
<Image
source={{ uri: getFullUrl(selectedDoc.fileUrl) }}
style={styles.imageViewer}
resizeMode="contain"
onLoadStart={() => setIsModalLoading(true)}
onLoadEnd={() => setIsModalLoading(false)}
onError={() => setIsModalLoading(false)}
/>
)
)}
</View>
</SafeAreaView>
</Modal>
</View>
);
};

View File

@ -54,7 +54,7 @@ export const ProfileScreen: React.FC = () => {
const handleMenuPress = (item: any) => {
if (item.route) {
navigation.navigate(item.route);
navigation.navigate(RouteNames.Documents);
} else {
Alert.alert('Menu Option', `Viewing ${item.title} section...`);
}

View File

@ -15,7 +15,7 @@ const STORAGE_KEYS = {
} as const;
// ─── Config ──────────────────────────────────────────────────────────────────
const BASE_URL = 'https://53a9-202-8-116-13.ngrok-free.app'; // TODO: replace with your actual base URL
const BASE_URL = 'https://sg-delivery-api.convexsol.co'; // TODO: replace with your actual base URL
// ─── Token Helpers ───────────────────────────────────────────────────────────
export const tokenManager = {

View File

@ -6,7 +6,7 @@ import { setDeliveryOffer } from '@store/commonReducers/delivery';
import { RouteNames } from '@utils/constants';
// Must match the REST API base URL (without trailing slash)
const BASE_URL = 'https://53a9-202-8-116-13.ngrok-free.app';
const BASE_URL = 'https://sg-delivery-api.convexsol.co';
type Callback = (data: any) => void;

View File

@ -47,7 +47,7 @@ export enum SocketEvents {
NewJob = 'new_job',
DeliveryOffer = 'delivery_offer',
JobCancelled = 'job_cancelled',
LocationUpdate = 'location_update',
LocationUpdate = 'driver_location_update',
GoOnline = 'go_online',
GoOffline = 'go_offline',
}

11
app/utils/helper.ts Normal file
View File

@ -0,0 +1,11 @@
export const getFullUrl = (url?: string) => {
const BASE_URL = 'https://sg-delivery-api.convexsol.co';
if (!url) return '';
return url.startsWith('/') ? `${BASE_URL}${url}` : url;
};
export const isPdf = (fileNameOrUrl?: string) => {
if (!fileNameOrUrl) return false;
const clean = fileNameOrUrl.toLowerCase().split('?')[0];
return clean.endsWith('.pdf');
};

4
app/utils/index.ts Normal file
View File

@ -0,0 +1,4 @@
export * from './validators';
export * from './helper';
export * from './constants';
export * from './formatters';

View File

@ -0,0 +1,233 @@
# Delivery Socket Integration — Implementation Plan
## Overview
This plan covers the end-to-end integration of the real-time delivery dispatch flow, as described in `mobile_delivery_app_integration.md`. The work involves:
1. **Interfaces** — Add typed contracts for the `delivery_offer` socket event and the REST respond endpoint.
2. **API Layer** — Implement `deliveryApi.ts` with `respondToOffer` and `getPendingOffer` calls.
3. **Redux (delivery slice)** — Wire thunks + reducer in `app/store/commonReducers/delivery/` for the respond flow.
4. **SocketService** — Implement real socket.io connection in `socketService.ts` (replacing the empty file), initialized globally.
5. **Global socket bootstrap** — Initialise/teardown the socket in `App.tsx` (or root navigator) so every screen benefits.
6. **NewJobRequestScreen** — Connect to Redux delivery state, replace current `job.newJobOffer` source with socket-driven data, and enhance UI.
7. **DashboardScreen** — Remove the mock 12-s timer and wire real socket online/offline control.
---
## User Review Required
> [!IMPORTANT]
> The integration guide specifies the socket event name as `delivery_offer` and the action values `"ACCEPT"` / `"REJECT"`. The existing `SocketEvents` enum uses `new_job`. The plan aligns with the integration guide naming while keeping the old mock service unchanged.
> [!WARNING]
> `socket.io-client` must already be installed. If not, run: `npm install socket.io-client`. Please confirm before executing.
> [!IMPORTANT]
> The base URL for the socket is the same as the REST API (`https://8415-202-8-116-13.ngrok-free.app`). Confirm this is correct for the socket server too.
---
## Open Questions
> [!NOTE]
> 1. **Timer duration** — The integration guide shows 15 s timer on the screen. The `newJobRequestScreen` already uses 15 s. Keep it or change to 30 s (constant `JOB_ACCEPT_TIMEOUT_SECONDS`)?
> 2. **Pending offer on app start** — Should `checkPendingOffers()` run every time the app launches (even before going online), or only after the auth/onboarding flow completes?
> 3. **NewJobRequestScreen UI** — User says "you can enhance it". Plan is to add an animated circular progress timer ring instead of plain text countdown, and a subtle pulsing accept button. Agree?
---
## Proposed Changes
### 1 — Interfaces
#### [MODIFY] [delivery.ts](file:///d:/SG-Delivery/sg-delivery-partner/app/interfaces/delivery.ts)
Add typed contracts that mirror the integration guide's socket offer payload and REST respond endpoint.
```typescript
// Socket offer payload (delivery_offer event)
export interface DeliveryOffer {
deliveryId: string;
orderId: string;
pickupAddress: { label: string; lat: number; lng: number };
dropAddress: { label: string; lat: number; lng: number };
totalAmount: number;
distanceKm: number;
}
// REST: POST /delivery-partners/deliveries/{id}/respond
export type DeliveryAction = 'ACCEPT' | 'REJECT';
export interface RespondToOfferPayload {
action: DeliveryAction;
}
export interface RespondToOfferResponse {
success: boolean;
message: string;
deliveryId?: string;
}
// REST: GET /delivery-partners/deliveries/pending-offer
export interface PendingOfferResponse {
offer: DeliveryOffer | null;
}
```
---
### 2 — API Layer
#### [MODIFY] [deliveryApi.ts](file:///d:/SG-Delivery/sg-delivery-partner/app/api/deliveryApi.ts)
Implement two API calls matching the integration guide:
- `respondToOffer(deliveryId, action)` → `POST /delivery-partners/deliveries/{id}/respond`
- `getPendingOffer()` → `GET /delivery-partners/deliveries/pending-offer`
---
### 3 — Redux Delivery Slice
#### [MODIFY] [thunk.ts](file:///d:/SG-Delivery/sg-delivery-partner/app/store/commonReducers/delivery/thunk.ts)
Two async thunks:
- `respondToOfferThunk(deliveryId, action)` — calls `deliveryApi.respondToOffer`
- `checkPendingOfferThunk()` — calls `deliveryApi.getPendingOffer`
#### [MODIFY] [reducer.ts](file:///d:/SG-Delivery/sg-delivery-partner/app/store/commonReducers/delivery/reducer.ts)
`DeliveryState`:
```typescript
interface DeliveryState {
currentOffer: DeliveryOffer | null; // live socket offer
respondLoading: boolean;
respondError: string | null;
pendingOfferLoading: boolean;
}
```
Actions:
- `setDeliveryOffer(offer)` — dispatched by socketService on `delivery_offer`
- `clearDeliveryOffer()` — dispatched after accept/reject
Thunk cases: pending/fulfilled/rejected for both thunks.
#### [MODIFY] [index.ts](file:///d:/SG-Delivery/sg-delivery-partner/app/store/commonReducers/delivery/index.ts)
Export reducer, thunks, and actions.
#### [MODIFY] [commonReducers/index.ts](file:///d:/SG-Delivery/sg-delivery-partner/app/store/commonReducers/index.ts)
Add `export * from './delivery'`.
#### [MODIFY] [rootReducer.ts](file:///d:/SG-Delivery/sg-delivery-partner/app/store/rootReducer.ts)
Import and register `deliveryReducer` under key `delivery`.
---
### 4 — SocketService
#### [MODIFY] [socketService.ts](file:///d:/SG-Delivery/sg-delivery-partner/app/services/socketService.ts)
Real `socket.io-client` implementation with the following contract:
```typescript
class SocketService {
connect(token: string): void // init socket with JWT auth
disconnect(): void
goOnline(): void // emit partner going online
goOffline(): void // emit partner going offline
updateLocation(coords): void // emit location update
on(event, callback): void
off(event, callback?): void
isConnected(): boolean
}
export const socketService = new SocketService();
```
Key behaviors:
- Connects to `BASE_URL` with `auth: { token }` — same URL as axiosInstance
- Listens for `delivery_offer` → dispatches `setDeliveryOffer` + navigates to `NewJobRequest` screen (store reference injected)
- Handles reconnection automatically (socket.io built-in)
- On `connect_error` logs the error
> [!NOTE]
> The socketService needs a reference to the Redux store and the navigation ref to dispatch and navigate globally. We will use a `bootstrapSocketService(store, navRef)` function called once in `App.tsx`.
---
### 5 — Global Bootstrap in App.tsx
#### [MODIFY] [App.tsx](file:///d:/SG-Delivery/sg-delivery-partner/app/App.tsx)
- Create a `navigationRef` using `createNavigationContainerRef`.
- After `PersistGate` hydrates, run `useEffect` that: reads `accessToken` from store → if present, calls `socketService.connect(token)`.
- Pass `navigationRef` to `NavigationContainer`.
- On token change (logout), call `socketService.disconnect()`.
- Also call `checkPendingOfferThunk()` on app start when token exists.
---
### 6 — NewJobRequestScreen Enhancement
#### [MODIFY] [newJobRequestScreen.tsx](file:///d:/SG-Delivery/sg-delivery-partner/app/features/screens/newJobRequestScreen/newJobRequestScreen.tsx)
**Data source change**: Read from `state.delivery.currentOffer` (the real socket offer) instead of `state.job.newJobOffer`. Map `DeliveryOffer` fields to UI fields.
**UI enhancements**:
- Animated circular countdown ring (using `Animated` API — no extra deps needed) instead of the plain text timer box.
- Pulsing green ring on the Accept button when < 5 s remain.
- Order amount shown prominently with a gradient badge.
- Accept/Reject dispatch `respondToOfferThunk` + `clearDeliveryOffer`.
#### [MODIFY] [newJobRequestScreen.styles.ts](file:///d:/SG-Delivery/sg-delivery-partner/app/features/screens/newJobRequestScreen/newJobRequestScreen.styles.ts)
Add styles for the circular timer, pulse ring, earnings badge.
---
### 7 — DashboardScreen Cleanup
#### [MODIFY] [dashboardScreen.tsx](file:///d:/SG-Delivery/sg-delivery-partner/app/features/screens/dashboardScreen/dashboardScreen.tsx)
- Remove the mock 12-s `setTimeout` that simulates a job offer.
- When going online → call `socketService.goOnline()`.
- When going offline → call `socketService.goOffline()`.
---
## File Change Summary
| File | Action | Purpose |
|---|---|---|
| `app/interfaces/delivery.ts` | MODIFY | DeliveryOffer, RespondToOfferPayload, PendingOfferResponse types |
| `app/api/deliveryApi.ts` | MODIFY | respondToOffer, getPendingOffer API calls |
| `app/store/commonReducers/delivery/thunk.ts` | MODIFY | respondToOfferThunk, checkPendingOfferThunk |
| `app/store/commonReducers/delivery/reducer.ts` | MODIFY | DeliveryState, setDeliveryOffer, clearDeliveryOffer |
| `app/store/commonReducers/delivery/index.ts` | MODIFY | barrel export |
| `app/store/commonReducers/index.ts` | MODIFY | add delivery export |
| `app/store/rootReducer.ts` | MODIFY | register deliveryReducer |
| `app/services/socketService.ts` | MODIFY | real socket.io-client implementation |
| `app/App.tsx` | MODIFY | global socket bootstrap + navigationRef |
| `app/features/screens/newJobRequestScreen/newJobRequestScreen.tsx` | MODIFY | socket-driven data + enhanced UI |
| `app/features/screens/newJobRequestScreen/newJobRequestScreen.styles.ts` | MODIFY | timer ring + pulse styles |
| `app/features/screens/dashboardScreen/dashboardScreen.tsx` | MODIFY | remove mock timer, add socket calls |
---
## Verification Plan
### Automated Checks
- TypeScript compilation: `npx tsc --noEmit` — must pass with 0 errors.
### Manual Verification
- App launches → socket connects (check logs: `[Socket] Connected`).
- Go online → `goOnline()` called.
- Backend dispatches `delivery_offer` → `NewJobRequestScreen` pops up from any screen.
- Accept → REST `POST /respond` with `ACCEPT` fires → screen navigates to `OrderAccepted`.
- Reject / timeout → REST `POST /respond` with `REJECT` fires → back to Dashboard.
- Kill app → relaunch → `checkPendingOfferThunk` fires → pending offer screen shown if offer exists.
- Go offline → socket `goOffline()` event sent.

View File

@ -0,0 +1,110 @@
# Mobile App Integration Guide (Delivery Partner)
This developer guide details how to implement the real-time delivery dispatch flow in the Delivery Partner mobile application (e.g. React Native, Flutter, or Native iOS/Android).
---
### Step 1: Establish Socket Connection (on Login / Going Online)
Initialize the socket connection and pass the JWT token in the handshake authentication options.
```javascript
import { io } from "socket.io-client";
// Replace with your backend server URL
const socket = io("http://YOUR_BACKEND_IP:8000", {
auth: {
token: DRIVER_JWT_TOKEN // Pass the verified driver token here
}
});
socket.on("connect", () => {
console.log("Connected to dispatch server!");
});
```
---
### Step 2: Listen for Incoming Offers (`delivery_offer`)
When the socket receives the `delivery_offer` event, display a modal or popup banner in your UI with the order details and Accept/Reject buttons.
```javascript
socket.on("delivery_offer", (offer) => {
console.log("New offer received:", offer);
// Example UI action: Open the screen showing details
showNewOfferModal({
deliveryId: offer.deliveryId,
orderId: offer.orderId,
pickupAddress: offer.pickupAddress.label,
dropAddress: offer.dropAddress.label,
amount: offer.totalAmount,
distance: offer.distanceKm
});
});
```
---
### Step 3: Respond to the Offer (Accept / Reject)
When the driver clicks Accept or Reject, hit the existing REST endpoint `POST /delivery-partners/deliveries/{id}/respond`.
```javascript
async function respondToOffer(deliveryId, isAccepted) {
const action = isAccepted ? "ACCEPT" : "REJECT";
try {
const response = await fetch(`http://YOUR_BACKEND_IP:8000/delivery-partners/deliveries/${deliveryId}/respond`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${DRIVER_JWT_TOKEN}`
},
body: JSON.stringify({ action })
});
const result = await response.json();
if (response.ok) {
console.log(`Successfully responded with action: ${action}`);
// Close the modal or update app state
} else {
console.error(result.message);
}
} catch (error) {
console.error("Network error: ", error);
}
}
```
---
### Step 4: Handle App Restarts / Notification Clicks
If the app was closed when the offer was dispatched or opened via a push notification:
1. On app launch, call `GET /delivery-partners/deliveries/pending-offer`.
2. If the offer is not `null`, load the accept/reject screen immediately.
```javascript
async function checkPendingOffers() {
const response = await fetch("http://YOUR_BACKEND_IP:8000/delivery-partners/deliveries/pending-offer", {
headers: { 'Authorization': `Bearer ${DRIVER_JWT_TOKEN}` }
});
const data = await response.json();
if (data.offer) {
showNewOfferModal(data.offer); // Load the screen if there's a pending offer
}
}
```
---
### App State Lifecycle & Flow Handling
Depending on the operational state of the delivery partner's mobile application, the offer is received and presented to the rider in different ways:
| App State | Delivery Offer Trigger Mechanism | What Happens |
| :--- | :--- | :--- |
| **Foreground (Open & Active)** | **WebSocket Listener** | The `delivery_offer` WebSocket event fires instantly (handled in **Step 2**). The modal or bottom sheet overlay pops up immediately in front of the rider. |
| **Background (Open but Minimized)** | **Push Notification (FCM / APNs)** | Mobile OSs sleep WebSocket connections when minimized. The backend dispatches a push notification. Tapping the notification brings the app to the foreground and calls `checkPendingOffers()` (handled in **Step 4**) to display the offer. |
| **Closed / Killed (Not Running)** | **Push Notification (FCM / APNs)** | The backend dispatches a push notification. Tapping it starts up the app, which then runs `checkPendingOffers()` on load to retrieve the pending offer. |

View File

@ -22,9 +22,11 @@
"axios": "^1.18.1",
"react": "19.2.3",
"react-native": "0.86.0",
"react-native-blob-util": "^0.24.10",
"react-native-geolocation-service": "^5.3.1",
"react-native-gesture-handler": "^2.32.0",
"react-native-maps": "^1.29.0",
"react-native-pdf": "^7.0.4",
"react-native-reanimated": "^4.5.0",
"react-native-safe-area-context": "^5.8.0",
"react-native-screens": "^4.25.2",

334
yarn.lock
View File

@ -16,7 +16,7 @@
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz"
integrity sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==
"@babel/core@*", "@babel/core@^7.0.0", "@babel/core@^7.0.0 || ^8.0.0-0", "@babel/core@^7.0.0-0", "@babel/core@^7.0.0-0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.11.0", "@babel/core@^7.11.6", "@babel/core@^7.12.0", "@babel/core@^7.12.3", "@babel/core@^7.13.0", "@babel/core@^7.23.9", "@babel/core@^7.24.4", "@babel/core@^7.25.2", "@babel/core@^7.4.0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.8.0":
"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9", "@babel/core@^7.24.4", "@babel/core@^7.25.2":
version "7.29.7"
resolved "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz"
integrity sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==
@ -37,7 +37,7 @@
json5 "^2.2.3"
semver "^6.3.1"
"@babel/eslint-parser@^7.12.0", "@babel/eslint-parser@^7.25.1":
"@babel/eslint-parser@^7.25.1":
version "7.29.7"
resolved "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.29.7.tgz"
integrity sha512-zxt+UJTOMKvUt3yOg+D58MLuz334pHp93qifMFcjIIO+9hN6t+ufw2gi7vDPMpxvfnHRR+3VVXvIjineCcgyXw==
@ -1366,7 +1366,7 @@
"@nodelib/fs.stat" "2.0.5"
run-parallel "^1.1.9"
"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
version "2.0.5"
resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
@ -1522,7 +1522,7 @@
dependencies:
joi "^17.2.1"
"@react-native-community/cli@*", "@react-native-community/cli@20.1.0":
"@react-native-community/cli@20.1.0":
version "20.1.0"
resolved "https://registry.npmjs.org/@react-native-community/cli/-/cli-20.1.0.tgz"
integrity sha512-441WsVtRe4nGJ9OzA+QMU1+22lA6Q2hRWqqIMKD0wjEMLqcSfOZyu2UL9a/yRpL/dRpyUsU4n7AxqKfTKO/Csg==
@ -1701,7 +1701,7 @@
hermes-parser "0.36.0"
nullthrows "^1.1.1"
"@react-native/metro-config@*", "@react-native/metro-config@0.86.0":
"@react-native/metro-config@0.86.0":
version "0.86.0"
resolved "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.86.0.tgz"
integrity sha512-7v+xbTeEci9ZcQ/Z1OqI4RXcqN69wSMDYL5BAMvOReZ7U04+aDQ0/SQhClYPn6x2/RxM4WzMKSAuNyLKqvYVtw==
@ -1716,6 +1716,11 @@
resolved "https://registry.npmjs.org/@react-native/new-app-screen/-/new-app-screen-0.86.0.tgz"
integrity sha512-hgZYg2I6gk+U0PWpV/JWg02KaS+FYYQ7OpFPVyG5RbFRAKNJw38mp8up3JqWFCMHeUH/kjWLEbJsCA0O5Qx2MA==
"@react-native/normalize-color@*":
version "2.1.0"
resolved "https://registry.yarnpkg.com/@react-native/normalize-color/-/normalize-color-2.1.0.tgz#939b87a9849e81687d3640c5efa2a486ac266f91"
integrity sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA==
"@react-native/normalize-colors@0.86.0":
version "0.86.0"
resolved "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.86.0.tgz"
@ -1776,7 +1781,7 @@
sf-symbols-typescript "^2.1.0"
warn-once "^0.1.1"
"@react-navigation/native@^7.3.4", "@react-navigation/native@^7.3.5":
"@react-navigation/native@^7.3.4":
version "7.3.5"
resolved "https://registry.npmjs.org/@react-navigation/native/-/native-7.3.5.tgz"
integrity sha512-lzcRpMoLCIypXXKm8KhpyZ81XpQBO/i8Oy1due4kUR97kG8kBlJxKUeP8yNnT5Fcl85rNdLXWbpwEr+9HPu4Ig==
@ -1958,7 +1963,7 @@
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^18.2.25 || ^19", "@types/react@^19.1.0", "@types/react@^19.1.1", "@types/react@^19.2.0":
"@types/react@*", "@types/react@^19.2.0":
version "19.2.17"
resolved "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz"
integrity sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==
@ -1987,7 +1992,7 @@
dependencies:
"@types/yargs-parser" "*"
"@typescript-eslint/eslint-plugin@^8.0.0", "@typescript-eslint/eslint-plugin@^8.36.0":
"@typescript-eslint/eslint-plugin@^8.36.0":
version "8.62.1"
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.62.1.tgz"
integrity sha512-4EQM77WgVNxj7OkL/5b/D/xZsw00G577+UriYTC7JF5opcF3T2AuoeY7ueLaZgSVjSgCS6yOAJB5bRGLPSJUzA==
@ -2001,7 +2006,7 @@
natural-compare "^1.4.0"
ts-api-utils "^2.5.0"
"@typescript-eslint/parser@^8.36.0", "@typescript-eslint/parser@^8.62.1":
"@typescript-eslint/parser@^8.36.0":
version "8.62.1"
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.62.1.tgz"
integrity sha512-sPhE4iHuJDSvoAiec+Ro8JyXw8f0ql13HFR82P99nCm9GwTEKG0KYLvDe6REk8BCXuit6vJAv/Yxg5ABaNS2rA==
@ -2029,7 +2034,7 @@
"@typescript-eslint/types" "8.62.1"
"@typescript-eslint/visitor-keys" "8.62.1"
"@typescript-eslint/tsconfig-utils@^8.62.1", "@typescript-eslint/tsconfig-utils@8.62.1":
"@typescript-eslint/tsconfig-utils@8.62.1", "@typescript-eslint/tsconfig-utils@^8.62.1":
version "8.62.1"
resolved "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.1.tgz"
integrity sha512-xadytJqX9vJVQ2fdQjkcIVigwaOJNWkpjdLt6cEQ+xPnrI1fkp+/jZE/I97k9KUjqtpd25i0HeyZf3T6dutv2g==
@ -2045,7 +2050,7 @@
debug "^4.4.3"
ts-api-utils "^2.5.0"
"@typescript-eslint/types@^8.62.1", "@typescript-eslint/types@8.62.1":
"@typescript-eslint/types@8.62.1", "@typescript-eslint/types@^8.62.1":
version "8.62.1"
resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.1.tgz"
integrity sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q==
@ -2065,7 +2070,7 @@
tinyglobby "^0.2.15"
ts-api-utils "^2.5.0"
"@typescript-eslint/utils@^8.0.0", "@typescript-eslint/utils@8.62.1":
"@typescript-eslint/utils@8.62.1", "@typescript-eslint/utils@^8.0.0":
version "8.62.1"
resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.62.1.tgz"
integrity sha512-sHtbPfuKNZCG+ih8SyjjucqRntSVmp8XgL5u6o9mAhiSn8ds5o/M/XdM0abweme2Tln3szOstOrZ9OXitvPh0g==
@ -2121,16 +2126,11 @@ acorn-jsx@^5.3.2:
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.15.0, acorn@^8.9.0:
acorn@^8.15.0, acorn@^8.9.0:
version "8.17.0"
resolved "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz"
integrity sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==
agent-base@^7.1.2:
version "7.1.4"
resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz"
integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==
agent-base@6:
version "6.0.2"
resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz"
@ -2138,6 +2138,11 @@ agent-base@6:
dependencies:
debug "4"
agent-base@^7.1.2:
version "7.1.4"
resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz"
integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==
ajv@^6.12.4:
version "6.15.0"
resolved "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz"
@ -2473,6 +2478,11 @@ balanced-match@^4.0.2:
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz"
integrity sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==
base-64@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/base-64/-/base-64-1.0.0.tgz#09d0f2084e32a3fd08c2475b973788eee6ae8f4a"
integrity sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==
base64-js@^1.3.1, base64-js@^1.5.1:
version "1.5.1"
resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz"
@ -2544,7 +2554,7 @@ braces@^3.0.3:
dependencies:
fill-range "^7.1.1"
browserslist@^4.24.0, browserslist@^4.28.1, "browserslist@>= 4.21.0":
browserslist@^4.24.0, browserslist@^4.28.1:
version "4.28.4"
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.28.4.tgz"
integrity sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==
@ -2575,7 +2585,7 @@ buffer@^5.5.0:
base64-js "^1.3.1"
ieee754 "^1.1.13"
bytes@~3.1.2, bytes@3.1.2:
bytes@3.1.2, bytes@~3.1.2:
version "3.1.2"
resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz"
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
@ -2734,16 +2744,16 @@ color-convert@^2.0.1:
dependencies:
color-name "~1.1.4"
color-name@^1.0.0, color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
color-name@^1.0.0, color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
color-string@^1.9.0:
version "1.9.1"
resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz"
@ -2876,6 +2886,11 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3, cross-spawn@^7.0.6:
shebang-command "^2.0.0"
which "^2.0.1"
crypto-js@4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==
css-select@^5.1.0:
version "5.2.2"
resolved "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz"
@ -2937,27 +2952,20 @@ dayjs@^1.8.15:
resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz"
integrity sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==
debug@^2.6.9:
debug@2.6.9, debug@^2.6.9:
version "2.6.9"
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
dependencies:
ms "2.0.0"
debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.4.0, debug@^4.4.3, debug@~4.4.1, debug@4:
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.4.0, debug@^4.4.3, debug@~4.4.1:
version "4.4.3"
resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz"
integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==
dependencies:
ms "^2.1.3"
debug@2.6.9:
version "2.6.9"
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
dependencies:
ms "2.0.0"
decamelize@^1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz"
@ -3013,12 +3021,21 @@ delayed-stream@~1.0.0:
resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
depd@~2.0.0, depd@2.0.0:
depd@2.0.0, depd@~2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz"
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
destroy@~1.2.0, destroy@1.2.0:
deprecated-react-native-prop-types@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-2.3.0.tgz#c10c6ee75ff2b6de94bb127f142b814e6e08d9ab"
integrity sha512-pWD0voFtNYxrVqvBMYf5gq3NA2GCpfodS1yNynTPc93AYA/KEMGeWDqqeUB6R2Z9ZofVhks2aeJXiuQqKNpesA==
dependencies:
"@react-native/normalize-color" "*"
invariant "*"
prop-types "*"
destroy@1.2.0, destroy@~1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz"
integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
@ -3407,14 +3424,6 @@ eslint-plugin-react@^7.37.5:
string.prototype.matchall "^4.0.12"
string.prototype.repeat "^1.0.0"
eslint-scope@^7.2.2:
version "7.2.2"
resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz"
integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==
dependencies:
esrecurse "^4.3.0"
estraverse "^5.2.0"
eslint-scope@5.1.1:
version "5.1.1"
resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz"
@ -3423,6 +3432,14 @@ eslint-scope@5.1.1:
esrecurse "^4.3.0"
estraverse "^4.1.1"
eslint-scope@^7.2.2:
version "7.2.2"
resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz"
integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==
dependencies:
esrecurse "^4.3.0"
estraverse "^5.2.0"
eslint-visitor-keys@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz"
@ -3438,7 +3455,7 @@ eslint-visitor-keys@^5.0.0:
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz"
integrity sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==
"eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7", "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0", "eslint@^3.17.0 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.5.0 || ^8.0.0 || ^9.0.0", "eslint@^8.0.0 || ^9.0.0", eslint@^8.1.0, eslint@^8.19.0, "eslint@^8.57.0 || ^9.0.0 || ^10.0.0", eslint@>=4.19.1, eslint@>=7.0.0:
eslint@^8.19.0:
version "8.57.1"
resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz"
integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==
@ -3751,6 +3768,11 @@ fs.realpath@^1.0.0:
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
fsevents@^2.3.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
function-bind@^1.1.2:
version "1.1.2"
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
@ -3848,6 +3870,15 @@ glob-parent@^6.0.2:
dependencies:
is-glob "^4.0.3"
glob@13.0.6:
version "13.0.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-13.0.6.tgz#078666566a425147ccacfbd2e332deb66a2be71d"
integrity sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==
dependencies:
minimatch "^10.2.2"
minipass "^7.1.3"
path-scurry "^2.0.2"
glob@^7.1.3, glob@^7.1.4:
version "7.2.3"
resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz"
@ -3963,13 +3994,6 @@ hermes-estree@0.36.0:
resolved "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.36.0.tgz"
integrity sha512-A1+8zn5oss2CFP7pKsOaxorQG6FNIz1WU1VDqruLPPZl3LVgeE2C5xfFg8Ow6/Ow4mSslLLtYP1J3n38eKyW9w==
hermes-parser@^0.25.1:
version "0.25.1"
resolved "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz"
integrity sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==
dependencies:
hermes-estree "0.25.1"
hermes-parser@0.35.0:
version "0.35.0"
resolved "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.35.0.tgz"
@ -3984,6 +4008,13 @@ hermes-parser@0.36.0:
dependencies:
hermes-estree "0.36.0"
hermes-parser@^0.25.1:
version "0.25.1"
resolved "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz"
integrity sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==
dependencies:
hermes-estree "0.25.1"
hoist-non-react-statics@^3.3.0:
version "3.3.2"
resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz"
@ -4096,7 +4127,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@~2.0.4, inherits@2:
inherits@2, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@~2.0.4:
version "2.0.4"
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@ -4110,7 +4141,7 @@ internal-slot@^1.1.0:
hasown "^2.0.2"
side-channel "^1.1.0"
invariant@^2.2.4:
invariant@*, invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
@ -4648,7 +4679,7 @@ jest-resolve-dependencies@^29.7.0:
jest-regex-util "^29.6.3"
jest-snapshot "^29.7.0"
jest-resolve@*, jest-resolve@^29.7.0:
jest-resolve@^29.7.0:
version "29.7.0"
resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz"
integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==
@ -4792,7 +4823,7 @@ jest-worker@^29.7.0:
merge-stream "^2.0.0"
supports-color "^8.0.0"
jest@*, jest@^29.6.3:
jest@^29.6.3:
version "29.7.0"
resolved "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz"
integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==
@ -5002,6 +5033,11 @@ lru-cache@^10.2.0:
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz"
integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==
lru-cache@^11.0.0:
version "11.5.2"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.5.2.tgz#00e16665c90c620fba14a3c368732a976493f760"
integrity sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==
lru-cache@^5.1.1:
version "5.1.1"
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz"
@ -5086,7 +5122,7 @@ metro-cache@0.84.4:
https-proxy-agent "^7.0.5"
metro-core "0.84.4"
metro-config@^0.84.3, metro-config@0.84.4:
metro-config@0.84.4, metro-config@^0.84.3:
version "0.84.4"
resolved "https://registry.npmjs.org/metro-config/-/metro-config-0.84.4.tgz"
integrity sha512-PMotGDjXcXLWo2TMRH+VR99phFNgYTwqh4OoieIKK3yTJa1Jmkl+fZJxDO0jfBvNF+WESHciHvpNuBtXaF3B0Q==
@ -5100,7 +5136,7 @@ metro-config@^0.84.3, metro-config@0.84.4:
metro-runtime "0.84.4"
yaml "^2.6.1"
metro-core@^0.84.3, metro-core@0.84.4:
metro-core@0.84.4, metro-core@^0.84.3:
version "0.84.4"
resolved "https://registry.npmjs.org/metro-core/-/metro-core-0.84.4.tgz"
integrity sha512-HONpWC5LGXZn3ffkd4Hu6AIrfE7j4Z0g0wMo/goV24WOB3lhuFZ40KgvaDiSw8iyQHloMYay5N/wPX+z8oN/PQ==
@ -5139,7 +5175,7 @@ metro-resolver@0.84.4:
dependencies:
flow-enums-runtime "^0.0.6"
metro-runtime@^0.84.3, metro-runtime@0.84.4:
metro-runtime@0.84.4, metro-runtime@^0.84.3:
version "0.84.4"
resolved "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.84.4.tgz"
integrity sha512-Jibypds4g7AhzdRKY+kDoj51s5EXMwgyp5ddtlreDAsWefMdOx+agWqgm0H2XSZ/ueanHHVM89fnf5OJnlxa8Q==
@ -5147,7 +5183,7 @@ metro-runtime@^0.84.3, metro-runtime@0.84.4:
"@babel/runtime" "^7.25.0"
flow-enums-runtime "^0.0.6"
metro-source-map@^0.84.3, metro-source-map@0.84.4:
metro-source-map@0.84.4, metro-source-map@^0.84.3:
version "0.84.4"
resolved "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.84.4.tgz"
integrity sha512-jbWkPxIesVuo1IWkvezmMJld6iu8nD62GsrZiV6jP37AOdbo4OBq1FJ+qkOg8sV05wAHB//jAbziuW0SlJfW4g==
@ -5205,7 +5241,7 @@ metro-transform-worker@0.84.4:
metro-transform-plugins "0.84.4"
nullthrows "^1.1.1"
metro@^0.84.3, metro@0.84.4:
metro@0.84.4, metro@^0.84.3:
version "0.84.4"
resolved "https://registry.npmjs.org/metro/-/metro-0.84.4.tgz"
integrity sha512-8ETTubqfD6ornDy2zYDvRcKnVDOXdFJsjetYDBsY4oAsb6NJkiwFR+FaMESyGppFmQUyBQA4H4sFGxzcQSGtFA==
@ -5258,16 +5294,16 @@ micromatch@^4.0.4, micromatch@^4.0.8:
braces "^3.0.3"
picomatch "^2.3.1"
mime-db@^1.54.0, "mime-db@>= 1.43.0 < 2":
version "1.54.0"
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz"
integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
"mime-db@>= 1.43.0 < 2", mime-db@^1.54.0:
version "1.54.0"
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz"
integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
mime-types@^2.1.35, mime-types@~2.1.24, mime-types@~2.1.34:
version "2.1.35"
resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz"
@ -5275,30 +5311,23 @@ mime-types@^2.1.35, mime-types@~2.1.24, mime-types@~2.1.34:
dependencies:
mime-db "1.52.0"
mime-types@^3.0.0:
mime-types@^3.0.0, mime-types@^3.0.1:
version "3.0.2"
resolved "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz"
integrity sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==
dependencies:
mime-db "^1.54.0"
mime-types@^3.0.1:
version "3.0.2"
resolved "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz"
integrity sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==
dependencies:
mime-db "^1.54.0"
mime@^2.4.1:
version "2.6.0"
resolved "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz"
integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==
mime@1.6.0:
version "1.6.0"
resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
mime@^2.4.1:
version "2.6.0"
resolved "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz"
integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==
mimic-fn@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz"
@ -5330,7 +5359,7 @@ minipass@^4.2.4:
resolved "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz"
integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==
"minipass@^5.0.0 || ^6.0.2 || ^7.0.0":
"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2, minipass@^7.1.3:
version "7.1.3"
resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz"
integrity sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==
@ -5345,16 +5374,16 @@ mkdirp@^1.0.4:
resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
ms@^2.1.3, ms@2.1.3:
version "2.1.3"
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
ms@2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
ms@2.1.3, ms@^2.1.3:
version "2.1.3"
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
nanoid@^3.3.11:
version "3.3.15"
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz"
@ -5365,6 +5394,11 @@ natural-compare@^1.4.0:
resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz"
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
negotiator@0.6.3:
version "0.6.3"
resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz"
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
negotiator@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz"
@ -5375,11 +5409,6 @@ negotiator@~0.6.4:
resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz"
integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==
negotiator@0.6.3:
version "0.6.3"
resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz"
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
nocache@^3.0.1:
version "3.0.4"
resolved "https://registry.npmjs.org/nocache/-/nocache-3.0.4.tgz"
@ -5582,14 +5611,7 @@ own-keys@^1.0.1:
object-keys "^1.1.1"
safe-push-apply "^1.0.0"
p-limit@^2.0.0:
version "2.3.0"
resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz"
integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
dependencies:
p-try "^2.0.0"
p-limit@^2.2.0:
p-limit@^2.0.0, p-limit@^2.2.0:
version "2.3.0"
resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz"
integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
@ -5684,6 +5706,14 @@ path-scurry@^1.6.1:
lru-cache "^10.2.0"
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
path-scurry@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.2.tgz#6be0d0ee02a10d9e0de7a98bae65e182c9061f85"
integrity sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==
dependencies:
lru-cache "^11.0.0"
minipass "^7.1.2"
picocolors@^1.1.1:
version "1.1.1"
resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz"
@ -5694,7 +5724,7 @@ picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1:
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz"
integrity sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==
"picomatch@^3 || ^4", picomatch@^4.0.4:
picomatch@^4.0.4:
version "4.0.4"
resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz"
integrity sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==
@ -5728,7 +5758,7 @@ prelude-ls@^1.2.1:
resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
prettier@>=2, prettier@2.8.8:
prettier@2.8.8:
version "2.8.8"
resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz"
integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
@ -5757,7 +5787,7 @@ prompts@^2.0.1, prompts@^2.4.2:
kleur "^3.0.3"
sisteransi "^1.0.5"
prop-types@^15.8.1:
prop-types@*, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@ -5839,12 +5869,7 @@ react-freeze@^1.0.0:
resolved "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.4.tgz"
integrity sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==
react-is@^16.13.1:
version "16.13.1"
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-is@^16.7.0:
react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@ -5859,12 +5884,20 @@ react-is@^19.1.0, react-is@^19.2.3:
resolved "https://registry.npmjs.org/react-is/-/react-is-19.2.7.tgz"
integrity sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==
react-native-blob-util@^0.24.10:
version "0.24.10"
resolved "https://registry.yarnpkg.com/react-native-blob-util/-/react-native-blob-util-0.24.10.tgz#f213e3efd5ee42037d9d39efb1fe23926ef5304e"
integrity sha512-4yazgoCstXgt2/CRURtowGP3furAzbWdfMQ4jyUPDo5xtLx7KE2F/xMz3oU3shLwfL4id0iEKsBywoxvJSHPzQ==
dependencies:
base-64 "1.0.0"
glob "13.0.6"
react-native-geolocation-service@^5.3.1:
version "5.3.1"
resolved "https://registry.npmjs.org/react-native-geolocation-service/-/react-native-geolocation-service-5.3.1.tgz"
integrity sha512-LTXPtPNmrdhx+yeWG47sAaCgQc3nG1z+HLLHlhK/5YfOgfLcAb9HAkhREPjQKPZOUx8pKZMIpdGFUGfJYtimXQ==
react-native-gesture-handler@^2.32.0, "react-native-gesture-handler@>= 2.0.0":
react-native-gesture-handler@^2.32.0:
version "2.32.0"
resolved "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.32.0.tgz"
integrity sha512-uYIMOKlKENORq2SABE+jIjbPU+h5I/sQKcq2v16zRq848nwEp1fWRVwML4QWqijc8UcXJC25o54S8GQd4Mf2OA==
@ -5886,6 +5919,14 @@ react-native-maps@^1.29.0:
dependencies:
"@types/geojson" "^7946.0.13"
react-native-pdf@^7.0.4:
version "7.0.4"
resolved "https://registry.yarnpkg.com/react-native-pdf/-/react-native-pdf-7.0.4.tgz#f48d485d32cef24f41511ba2072bc99ba94b13c9"
integrity sha512-Uhxn5SSguMKvbwD50iIZfYPmYeKcX+9I3tc4J3HCbRExAN0uqXTAKx2pvbR2Y62umAj0JS274FcbSldQfoQfyg==
dependencies:
crypto-js "4.2.0"
deprecated-react-native-prop-types "^2.3.0"
react-native-reanimated@^4.5.0:
version "4.5.1"
resolved "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.5.1.tgz"
@ -5894,12 +5935,12 @@ react-native-reanimated@^4.5.0:
react-native-is-edge-to-edge "^1.3.1"
semver "^7.7.3"
react-native-safe-area-context@^5.8.0, "react-native-safe-area-context@>= 4.0.0":
react-native-safe-area-context@^5.8.0:
version "5.8.0"
resolved "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.8.0.tgz"
integrity sha512-t+ZsAVzY/wWzzx34vqGbo3/as9EEESJdbyZNL7Yg5EYX+toYMtMqFoDDCvqZUi35eeGVsXc6pAaEk4edMwbuCQ==
react-native-screens@^4.25.2, "react-native-screens@>= 4.0.0":
react-native-screens@^4.25.2:
version "4.25.2"
resolved "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.25.2.tgz"
integrity sha512-1Nj1fusFd+rIMKU/qC9yGKVG+3ofh11d3OdBQKL1iVvQfKvcB8vhvTGQf2TkfxW3bamxN+hCZIXmNuU0mRkyDg==
@ -5920,7 +5961,7 @@ react-native-uuid@^2.0.4:
resolved "https://registry.npmjs.org/react-native-uuid/-/react-native-uuid-2.0.4.tgz"
integrity sha512-LSJNeh559qC17fgVPBsWuTSW/OygFp2dwTcf94IQBLYft5FzIQS9pCsuT36OPvyvDOMb6yiGr6TafaJDnz9PPQ==
react-native-worklets@^0.10.0, react-native-worklets@0.10.x:
react-native-worklets@^0.10.0:
version "0.10.2"
resolved "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.10.2.tgz"
integrity sha512-LX27ejYI8veeDp59Z3rjo2pYyPa9euzSH8GUlem7cnNqfsDtGum8PQpkbzrqhLsWH0CjdeHR7p3sncCyYbwaVw==
@ -5938,7 +5979,7 @@ react-native-worklets@^0.10.0, react-native-worklets@0.10.x:
convert-source-map "^2.0.0"
semver "^7.7.4"
react-native@*, "react-native@>= 0.62", "react-native@>= 0.76.0", react-native@>=0.40.0, react-native@>=0.79.0, react-native@>=0.82.0, "react-native@0.83 - 0.86", react-native@0.86.0:
react-native@0.86.0:
version "0.86.0"
resolved "https://registry.npmjs.org/react-native/-/react-native-0.86.0.tgz"
integrity sha512-17ALh/dd6AO4pgOVmOO5Axll5PbErEo3XFyLokyzW6usyi+OShIEPwUW26wLPlhVifgSOIfECCH0WN+0IqtJ1w==
@ -5976,7 +6017,7 @@ react-native@*, "react-native@>= 0.62", "react-native@>= 0.76.0", react-native@>
ws "^7.5.10"
yargs "^17.6.2"
"react-redux@^7.2.1 || ^8.1.3 || ^9.0.0", react-redux@^9.3.0:
react-redux@^9.3.0:
version "9.3.0"
resolved "https://registry.npmjs.org/react-redux/-/react-redux-9.3.0.tgz"
integrity sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==
@ -5997,7 +6038,7 @@ react-test-renderer@19.2.3:
react-is "^19.2.3"
scheduler "^0.27.0"
react@*, "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.9.0 || ^17.0.0 || ^18 || ^19", "react@^18.0 || ^19", react@^19.2.3, "react@>= 18.2.0", "react@>= 18.3.1", react@>=16.8, react@>=17.0.0, react@19.2.3:
react@19.2.3:
version "19.2.3"
resolved "https://registry.npmjs.org/react/-/react-19.2.3.tgz"
integrity sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==
@ -6042,7 +6083,7 @@ redux-thunk@^3.1.0:
resolved "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz"
integrity sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==
redux@^5.0.0, redux@^5.0.1, redux@>4.0.0:
redux@^5.0.1:
version "5.0.1"
resolved "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz"
integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==
@ -6216,7 +6257,7 @@ safe-array-concat@^1.1.3:
has-symbols "^1.1.0"
isarray "^2.0.5"
safe-buffer@~5.2.0, safe-buffer@5.2.1:
safe-buffer@5.2.1, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
@ -6243,7 +6284,7 @@ safe-regex-test@^1.1.0:
resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
scheduler@^0.27.0, scheduler@0.27.0:
scheduler@0.27.0, scheduler@^0.27.0:
version "0.27.0"
resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz"
integrity sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==
@ -6253,32 +6294,7 @@ semver@^6.3.0, semver@^6.3.1:
resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
semver@^7.1.3:
version "7.8.5"
resolved "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz"
integrity sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==
semver@^7.5.2:
version "7.8.5"
resolved "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz"
integrity sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==
semver@^7.5.3:
version "7.8.5"
resolved "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz"
integrity sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==
semver@^7.5.4:
version "7.8.5"
resolved "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz"
integrity sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==
semver@^7.7.3:
version "7.8.5"
resolved "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz"
integrity sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==
semver@^7.7.4:
semver@^7.1.3, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.7.3, semver@^7.7.4:
version "7.8.5"
resolved "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz"
integrity sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==
@ -6469,14 +6485,6 @@ socket.io-parser@~4.2.4:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.4.1"
source-map-support@~0.5.20:
version "0.5.21"
resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz"
integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map-support@0.5.13:
version "0.5.13"
resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz"
@ -6485,6 +6493,14 @@ source-map-support@0.5.13:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map-support@~0.5.20:
version "0.5.21"
resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz"
integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map@^0.5.6:
version "0.5.7"
resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz"
@ -6552,13 +6568,6 @@ strict-uri-encode@^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==
string_decoder@^1.1.1:
version "1.3.0"
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz"
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
dependencies:
safe-buffer "~5.2.0"
string-length@^4.0.1:
version "4.0.2"
resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz"
@ -6641,6 +6650,13 @@ string.prototype.trimstart@^1.0.8:
define-properties "^1.2.1"
es-object-atoms "^1.0.0"
string_decoder@^1.1.1:
version "1.3.0"
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz"
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
dependencies:
safe-buffer "~5.2.0"
strip-ansi@^5.0.0:
version "5.2.0"
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz"
@ -6833,7 +6849,7 @@ typed-array-length@^1.0.7:
possible-typed-array-names "^1.1.0"
reflect.getprototypeof "^1.0.10"
typescript@^5.8.3, typescript@>=4.8.4, "typescript@>=4.8.4 <6.1.0", "typescript@>=4.8.4 <7.0.0", typescript@>=4.9.5:
typescript@^5.8.3:
version "5.9.3"
resolved "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz"
integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==