diff --git a/android/app/build.gradle b/android/app/build.gradle
index af82bf6..c44818d 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -1,6 +1,7 @@
apply plugin: "com.android.application"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"
+apply plugin: 'com.google.gms.google-services'
apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
@@ -81,14 +82,14 @@ android {
buildToolsVersion rootProject.ext.buildToolsVersion
compileSdk rootProject.ext.compileSdkVersion
- namespace "com.convex_crm"
+ namespace "app.convexsol.convexsolcrm"
defaultConfig {
- applicationId "com.convex_crm"
+ applicationId "app.convexsol.convexsolcrm"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
- resValue "string", "build_config_package", "com.convex_crm"
+ resValue "string", "build_config_package", "app.convexsol.convexsolcrm"
}
signingConfigs {
debug {
diff --git a/android/app/google-services.json b/android/app/google-services.json
new file mode 100644
index 0000000..8cb0fa6
--- /dev/null
+++ b/android/app/google-services.json
@@ -0,0 +1,29 @@
+{
+ "project_info": {
+ "project_number": "712641953559",
+ "project_id": "convex-crm-cdb42",
+ "storage_bucket": "convex-crm-cdb42.firebasestorage.app"
+ },
+ "client": [
+ {
+ "client_info": {
+ "mobilesdk_app_id": "1:712641953559:android:85a912a03f43148f5d0152",
+ "android_client_info": {
+ "package_name": "app.convexsol.convexsolcrm"
+ }
+ },
+ "oauth_client": [],
+ "api_key": [
+ {
+ "current_key": "AIzaSyBFeKwZ8CBf3x62U6qHTv-T_ufp4qTHDrA"
+ }
+ ],
+ "services": {
+ "appinvite_service": {
+ "other_platform_oauth_client": []
+ }
+ }
+ }
+ ],
+ "configuration_version": "1"
+}
\ No newline at end of file
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index fb78f39..f4bacd8 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,27 +1,28 @@
+
+
-
-
-
+
-
-
-
-
-
-
-
+ android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
+ android:launchMode="singleTask"
+ android:windowSoftInputMode="adjustResize"
+ android:exported="true"
+ android:theme="@style/BootTheme">
+
+
+
+
+
+
diff --git a/android/app/src/main/java/com/convex_crm/MainActivity.kt b/android/app/src/main/java/com/convex_crm/MainActivity.kt
index feaa95d..f5e509b 100644
--- a/android/app/src/main/java/com/convex_crm/MainActivity.kt
+++ b/android/app/src/main/java/com/convex_crm/MainActivity.kt
@@ -1,12 +1,19 @@
-package com.convex_crm
+package app.convexsol.convexsolcrm
+import android.os.Bundle
import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
import com.facebook.react.defaults.DefaultReactActivityDelegate
+import com.zoontek.rnbootsplash.RNBootSplash
class MainActivity : ReactActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ RNBootSplash.init(this, R.style.BootTheme)
+ super.onCreate(savedInstanceState)
+ }
+
/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
diff --git a/android/app/src/main/java/com/convex_crm/MainApplication.kt b/android/app/src/main/java/com/convex_crm/MainApplication.kt
index 0e80b2c..14c3552 100644
--- a/android/app/src/main/java/com/convex_crm/MainApplication.kt
+++ b/android/app/src/main/java/com/convex_crm/MainApplication.kt
@@ -1,4 +1,4 @@
-package com.convex_crm
+package app.convexsol.convexsolcrm
import android.app.Application
import com.facebook.react.PackageList
diff --git a/android/app/src/main/res/drawable-hdpi/bootsplash_logo.png b/android/app/src/main/res/drawable-hdpi/bootsplash_logo.png
new file mode 100644
index 0000000..1c10762
Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/bootsplash_logo.png differ
diff --git a/android/app/src/main/res/drawable-mdpi/bootsplash_logo.png b/android/app/src/main/res/drawable-mdpi/bootsplash_logo.png
new file mode 100644
index 0000000..68d08e8
Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/bootsplash_logo.png differ
diff --git a/android/app/src/main/res/drawable-xhdpi/bootsplash_logo.png b/android/app/src/main/res/drawable-xhdpi/bootsplash_logo.png
new file mode 100644
index 0000000..d6ae84f
Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/bootsplash_logo.png differ
diff --git a/android/app/src/main/res/drawable-xxhdpi/bootsplash_logo.png b/android/app/src/main/res/drawable-xxhdpi/bootsplash_logo.png
new file mode 100644
index 0000000..713b027
Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/bootsplash_logo.png differ
diff --git a/android/app/src/main/res/drawable-xxxhdpi/bootsplash_logo.png b/android/app/src/main/res/drawable-xxxhdpi/bootsplash_logo.png
new file mode 100644
index 0000000..7d9ff5d
Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/bootsplash_logo.png differ
diff --git a/android/app/src/main/res/drawable/ic_launcher_background.xml b/android/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..ca3826a
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
index a2f5908..b55a4dd 100644
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..b305806
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
index 1b52399..84b8a0b 100644
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
index ff10afd..ce1e92b 100644
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..c258c2d
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
index 115a4c7..03ad41d 100644
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
index dcd3cd8..b4fc194 100644
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..4f1fec5
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
index 459ca60..bcc3731 100644
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/drawable/ic_launcher_background.xml b/android/app/src/main/res/mipmap-xxhdpi/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..ca3826a
--- /dev/null
+++ b/android/app/src/main/res/mipmap-xxhdpi/drawable/ic_launcher_background.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
index 8ca12fe..c9f4b83 100644
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..45d5602
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
index 8e19b41..09da6de 100644
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index b824ebd..6070f9d 100644
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..6992c1d
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
index 4c19a13..fa13b3b 100644
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/playstore-icon.png b/android/app/src/main/res/playstore-icon.png
new file mode 100644
index 0000000..e16cf8c
Binary files /dev/null and b/android/app/src/main/res/playstore-icon.png differ
diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..d4aaff4
--- /dev/null
+++ b/android/app/src/main/res/values/colors.xml
@@ -0,0 +1,3 @@
+
+ #ffffff
+
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
index 7ba83a2..4b89c01 100644
--- a/android/app/src/main/res/values/styles.xml
+++ b/android/app/src/main/res/values/styles.xml
@@ -1,9 +1,12 @@
-
-
+
diff --git a/android/build.gradle b/android/build.gradle
index dad99b0..441fc30 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -15,6 +15,7 @@ buildscript {
classpath("com.android.tools.build:gradle")
classpath("com.facebook.react:react-native-gradle-plugin")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
+ classpath ("com.google.gms:google-services:4.3.15")
}
}
diff --git a/app/App.tsx b/app/App.tsx
index 6628476..2501891 100644
--- a/app/App.tsx
+++ b/app/App.tsx
@@ -1,11 +1,13 @@
import React, { useEffect } from 'react';
-import { StyleSheet, StatusBar } from 'react-native';
+import { StatusBar } from 'react-native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { RootNavigator } from './navigation/rootNavigator';
import { ThemeProvider, useTheme } from './theme';
import { Provider } from 'react-redux';
-import { store, persistor } from '@store';
+import { store, persistor, useAppDispatch, useAppSelector, getStatusList, getSourceList, getCountryList } from '@store';
import { PersistGate } from 'redux-persist/integration/react';
+import { NotificationService } from '@services';
+import BootSplash from 'react-native-bootsplash';
const ThemedStatusBar = () => {
const { theme: colors, isDark } = useTheme();
@@ -23,13 +25,61 @@ const ThemedStatusBar = () => {
);
};
+/** Dispatches startup data fetches once the Redux store is ready. */
+const AppInit = () => {
+ const dispatch = useAppDispatch();
+ const token = useAppSelector(state => state.auth.token);
+
+ useEffect(() => {
+ if (token) {
+ dispatch(getStatusList());
+ dispatch(getSourceList());
+ dispatch(getCountryList());
+ }
+ }, [dispatch, token]);
+
+ return null;
+};
+
const App = () => {
+ useEffect(() => {
+ let cleanup: (() => void) | undefined;
+
+ const initApp = async () => {
+ try {
+ const cleanupFn = await NotificationService.initialize({
+ onNotificationOpen: data => {
+ // TODO: Use data (e.g. { screen, id }) to deep-navigate once
+ console.log('[App] Notification opened with data:', data);
+ },
+ onTokenRefreshed: token => {
+ // TODO: Send the refreshed token to your backend so the server
+ // always has the latest FCM token for this device.
+ console.log('[App] FCM token refreshed — sync to server:', token);
+ },
+ });
+ cleanup = cleanupFn;
+ } catch (err) {
+ console.error('[App] NotificationService.initialize error:', err);
+ } finally {
+ await BootSplash.hide({ fade: true });
+ }
+ };
+
+ initApp();
+
+ return () => {
+ cleanup?.();
+ };
+ }, []);
+
return (
+
diff --git a/app/api/index.ts b/app/api/index.ts
index a1272e1..9ef0b73 100644
--- a/app/api/index.ts
+++ b/app/api/index.ts
@@ -1,3 +1,4 @@
export * from './authApi';
export * from './leadsApi';
export * from './leadDetailsApi';
+export * from './listApi';
diff --git a/app/api/leadsApi.ts b/app/api/leadsApi.ts
index 3926dbd..2fd506d 100644
--- a/app/api/leadsApi.ts
+++ b/app/api/leadsApi.ts
@@ -1,4 +1,4 @@
-import { LeadItem } from '@interfaces';
+import { LeadItem, LeadCountItem } from '@interfaces';
import { api } from '@utils';
export const getLeadsApi = async (
@@ -8,3 +8,10 @@ export const getLeadsApi = async (
const url = `/api/leads/${leadId}/${staffId}`;
return await api.get(url);
};
+
+export const getLeadCountListApi = async (
+ staffId: string,
+): Promise => {
+ const url = `/api/leadcountlist/${staffId}`;
+ return await api.get(url);
+};
diff --git a/app/api/listApi.ts b/app/api/listApi.ts
new file mode 100644
index 0000000..10c6720
--- /dev/null
+++ b/app/api/listApi.ts
@@ -0,0 +1,17 @@
+import { StatusListItem, SourceListItem, CountryListItem } from '@interfaces';
+import { api } from '@utils';
+
+export const getStatusListApi = async (): Promise => {
+ const url = 'api/statuslist';
+ return await api.get(url);
+};
+
+export const getSourceListApi = async (): Promise => {
+ const url = 'api/sourcelist';
+ return await api.get(url);
+};
+
+export const getCountryListApi = async (): Promise => {
+ const url = 'api/countrylist';
+ return await api.get(url);
+};
diff --git a/app/components/actionCard/actionCard.styles.ts b/app/components/actionCard/actionCard.styles.ts
index 8954a99..4451e56 100644
--- a/app/components/actionCard/actionCard.styles.ts
+++ b/app/components/actionCard/actionCard.styles.ts
@@ -5,20 +5,22 @@ export const getStyles = (colors: ThemeColors) =>
StyleSheet.create({
card: {
backgroundColor: colors.card,
- borderRadius: 12,
+ borderRadius: 18,
padding: 16,
- marginBottom: 12,
- shadowColor: '#000',
- shadowOffset: { width: 0, height: 2 },
- shadowOpacity: 0.05,
- shadowRadius: 4,
- elevation: 2,
+ marginBottom: 14,
+ borderWidth: 1,
+ borderColor: colors.border,
+ shadowColor: '#5B4CF5',
+ shadowOffset: { width: 0, height: 4 },
+ shadowOpacity: 0.06,
+ shadowRadius: 12,
+ elevation: 3,
},
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
- marginBottom: 12,
+ marginBottom: 14,
},
leftSection: {
flexDirection: 'row',
@@ -26,19 +28,21 @@ export const getStyles = (colors: ThemeColors) =>
flex: 1,
},
iconContainer: {
- width: 40,
- height: 40,
- borderRadius: 20,
+ width: 42,
+ height: 42,
+ borderRadius: 12,
backgroundColor: colors.surface,
justifyContent: 'center',
alignItems: 'center',
marginRight: 12,
+ borderWidth: 1,
+ borderColor: colors.border,
},
titleSection: {
flex: 1,
},
title: {
- fontSize: 16,
+ fontSize: 15,
fontWeight: '700',
color: colors.text,
},
@@ -49,31 +53,31 @@ export const getStyles = (colors: ThemeColors) =>
},
actionsRow: {
flexDirection: 'row',
- gap: 8,
+ gap: 10,
},
- actionButton: {
+ actionBtn: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
+ gap: 6,
paddingVertical: 10,
- paddingHorizontal: 16,
- borderRadius: 8,
+ paddingHorizontal: 14,
+ borderRadius: 12,
backgroundColor: colors.surface,
borderWidth: 1,
borderColor: colors.border,
},
- addButton: {
+ addBtn: {
backgroundColor: colors.icon,
borderColor: colors.icon,
},
- actionButtonText: {
- fontSize: 14,
+ actionText: {
+ fontSize: 13,
fontWeight: '600',
color: colors.text,
- marginLeft: 6,
},
- addButtonText: {
+ addText: {
color: '#FFFFFF',
},
});
diff --git a/app/components/actionCard/actionCard.tsx b/app/components/actionCard/actionCard.tsx
index 89b9a46..5f8f02e 100644
--- a/app/components/actionCard/actionCard.tsx
+++ b/app/components/actionCard/actionCard.tsx
@@ -17,11 +17,10 @@ export const ActionCard: React.FC = ({
return (
- {/* Header with Icon and Title */}
-
+
{title}
@@ -34,24 +33,21 @@ export const ActionCard: React.FC = ({
- {/* Action Buttons */}
-
-
- Add
-
+ activeOpacity={0.75}>
+
+ Add
-
- View All
+ activeOpacity={0.75}>
+
+ View All
diff --git a/app/components/formInput/formInput.props.ts b/app/components/formInput/formInput.props.ts
index 7068b9f..8266252 100644
--- a/app/components/formInput/formInput.props.ts
+++ b/app/components/formInput/formInput.props.ts
@@ -1,10 +1,15 @@
-import { TextInputProps } from 'react-native';
+import { TextInputProps, StyleProp, ViewStyle, TextStyle } from 'react-native';
export interface FormInputProps extends Omit {
- label: string;
+ label?: string;
value: string;
onChangeText: (text: string) => void;
placeholder?: string;
required?: boolean;
multiline?: boolean;
+ leftIcon?: React.ReactNode;
+ rightIcon?: React.ReactNode;
+ containerStyle?: StyleProp;
+ inputContainerStyle?: StyleProp;
+ inputStyle?: StyleProp;
}
diff --git a/app/components/formInput/formInput.styles.ts b/app/components/formInput/formInput.styles.ts
index d0f78a9..7522372 100644
--- a/app/components/formInput/formInput.styles.ts
+++ b/app/components/formInput/formInput.styles.ts
@@ -7,21 +7,38 @@ export const getStyles = (colors: ThemeColors) =>
marginBottom: 16,
},
label: {
- fontSize: 14,
+ fontSize: 13,
fontWeight: '600',
- color: colors.text,
+ color: colors.textSecondary,
marginBottom: 8,
+ textTransform: 'uppercase',
+ letterSpacing: 0.5,
},
required: {
color: '#EF4444',
marginLeft: 2,
},
- input: {
+ inputWrapper: {
+ flexDirection: 'row',
+ alignItems: 'center',
backgroundColor: colors.surface,
borderWidth: 1,
borderColor: colors.border,
- borderRadius: 10,
- paddingHorizontal: 16,
+ borderRadius: 12,
+ paddingHorizontal: 12,
+ },
+ leftIconWrapper: {
+ marginRight: 8,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ rightIconWrapper: {
+ marginLeft: 8,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ input: {
+ flex: 1,
paddingVertical: 12,
fontSize: 15,
color: colors.text,
diff --git a/app/components/formInput/formInput.tsx b/app/components/formInput/formInput.tsx
index 100ba53..9d87ba8 100644
--- a/app/components/formInput/formInput.tsx
+++ b/app/components/formInput/formInput.tsx
@@ -12,28 +12,39 @@ export const FormInput: React.FC = ({
required = false,
multiline = false,
keyboardType = 'default',
+ leftIcon,
+ rightIcon,
+ containerStyle,
+ inputContainerStyle,
+ inputStyle,
...rest
}) => {
const { theme: colors } = useTheme();
const styles = getStyles(colors);
return (
-
-
- {label}
- {required && *}
-
-
+
+ {label ? (
+
+ {label}
+ {required && *}
+
+ ) : null}
+
+ {leftIcon ? {leftIcon} : null}
+
+ {rightIcon ? {rightIcon} : null}
+
);
};
diff --git a/app/components/index.ts b/app/components/index.ts
index fa09fb6..ef4d718 100644
--- a/app/components/index.ts
+++ b/app/components/index.ts
@@ -8,3 +8,4 @@ export * from './formPicker';
export * from './addItemButton';
export * from './actionButton';
export * from './checkboxWithLabel';
+export * from './statCard';
diff --git a/app/components/leadDetailHeader/leadDetailHeader.styles.ts b/app/components/leadDetailHeader/leadDetailHeader.styles.ts
index 7362bf7..eaf24e5 100644
--- a/app/components/leadDetailHeader/leadDetailHeader.styles.ts
+++ b/app/components/leadDetailHeader/leadDetailHeader.styles.ts
@@ -3,77 +3,98 @@ import { ThemeColors } from '../../theme';
export const getStyles = (colors: ThemeColors) =>
StyleSheet.create({
- container: {
- alignItems: 'center',
- paddingVertical: 24,
- paddingHorizontal: 16,
- borderBottomWidth: 1,
- borderBottomColor: colors.border,
+ card: {
backgroundColor: colors.card,
- },
- avatar: {
- width: 80,
- height: 80,
- borderRadius: 40,
- justifyContent: 'center',
+ borderRadius: 20,
+ padding: 20,
alignItems: 'center',
marginBottom: 16,
+ borderWidth: 1,
+ borderColor: colors.border,
+ shadowColor: '#5B4CF5',
+ shadowOffset: { width: 0, height: 6 },
+ shadowOpacity: 0.08,
+ shadowRadius: 16,
+ elevation: 4,
+ },
+ avatar: {
+ width: 76,
+ height: 76,
+ borderRadius: 38,
+ justifyContent: 'center',
+ alignItems: 'center',
+ marginBottom: 14,
},
avatarText: {
- fontSize: 32,
- fontWeight: '700',
+ fontSize: 26,
+ fontWeight: '800',
color: '#FFFFFF',
+ letterSpacing: 0.5,
},
- nameRow: {
+ name: {
+ fontSize: 20,
+ fontWeight: '700',
+ color: colors.text,
+ textAlign: 'center',
+ marginBottom: 4,
+ },
+ companyRow: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
+ gap: 6,
marginBottom: 12,
- flexWrap: 'wrap',
- paddingHorizontal: 16,
- },
- name: {
- fontSize: 24,
- fontWeight: '700',
- color: colors.text,
- marginRight: 8,
- },
- statusBadge: {
- paddingHorizontal: 12,
- paddingVertical: 6,
- borderRadius: 16,
- },
- statusText: {
- fontSize: 13,
- fontWeight: '600',
- textTransform: 'capitalize',
},
company: {
- fontSize: 16,
+ fontSize: 13,
color: colors.textSecondary,
- marginBottom: 12,
- textAlign: 'center',
+ fontWeight: '500',
},
- contactRow: {
+ statusBadge: {
flexDirection: 'row',
alignItems: 'center',
- marginBottom: 8,
- paddingHorizontal: 16,
+ gap: 6,
+ paddingHorizontal: 12,
+ paddingVertical: 5,
+ borderRadius: 20,
+ marginBottom: 16,
},
- contactLabel: {
- fontSize: 14,
+ statusDot: {
+ width: 6,
+ height: 6,
+ borderRadius: 3,
+ },
+ statusText: {
+ fontSize: 11,
+ fontWeight: '700',
+ textTransform: 'uppercase',
+ letterSpacing: 0.5,
+ },
+ quickActions: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ gap: 12,
+ width: '100%',
+ paddingTop: 14,
+ borderTopWidth: StyleSheet.hairlineWidth,
+ borderTopColor: colors.border,
+ },
+ actionBtn: {
+ flex: 1,
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ gap: 6,
+ paddingVertical: 10,
+ borderRadius: 12,
+ borderWidth: 1,
+ borderColor: colors.border,
+ backgroundColor: colors.surface,
+ },
+ actionBtnText: {
+ fontSize: 12,
fontWeight: '600',
color: colors.text,
- marginRight: 8,
- minWidth: 50,
- },
- contactText: {
- fontSize: 14,
- color: colors.textSecondary,
- flex: 1,
- },
- iconButton: {
- marginLeft: 8,
- padding: 4,
},
});
diff --git a/app/components/leadDetailHeader/leadDetailHeader.tsx b/app/components/leadDetailHeader/leadDetailHeader.tsx
index 099a513..67cb38b 100644
--- a/app/components/leadDetailHeader/leadDetailHeader.tsx
+++ b/app/components/leadDetailHeader/leadDetailHeader.tsx
@@ -4,6 +4,7 @@ import Icon from 'react-native-vector-icons/Ionicons';
import { useTheme } from '@theme';
import { getStyles } from './leadDetailHeader.styles';
import { LeadDetailHeaderProps } from './leadDetailHeader.props';
+import { getInitials, toRgba } from '@utils';
export const LeadDetailHeader: React.FC = ({
name,
@@ -17,87 +18,62 @@ export const LeadDetailHeader: React.FC = ({
onEmailPress,
onPhonePress,
}) => {
- const { theme: colors } = useTheme();
+ const { theme: colors, isDark } = useTheme();
const styles = getStyles(colors);
- // Get initials from name
- const getInitials = (name: string): string => {
- if (!name) return '?';
- const nameParts = name.trim().split(' ');
- if (nameParts.length >= 2) {
- return (nameParts[0][0] + nameParts[1][0]).toUpperCase();
- }
- return name.substring(0, 2).toUpperCase();
- };
+ const accent = statusColor || avatarColor || '#5B4CF5';
+ const badgeBg = toRgba(accent, isDark ? 0.20 : 0.12);
return (
-
- {/* Avatar */}
-
+
+
{getInitials(name)}
- {/* Name and Status Row */}
-
- {name || 'No Name'}
-
-
-
- {statusName || 'No Status'}
-
-
-
+
+ {name || 'No Name'}
+
+
+ {company && (
+
+
+ {company}
+
+ )}
+
+
+
+
+
+ {statusName || 'No Status'}
+
+
+
+
+
+ {email && (
+
+
+ Email
+
+ )}
+
+ {phonenumber && (
+
+
+ Call
+
+ )}
-
- {/* Company */}
- {company && {company}}
-
- {/* Email Row */}
- {email && (
-
- Email:
- {email}
- {onEmailPress && (
-
-
-
- )}
-
- )}
-
- {/* Phone Row */}
- {phonenumber && (
-
- Phone:
- {phonenumber}
- {onPhonePress && (
-
-
-
- )}
-
- )}
);
};
diff --git a/app/components/leadItemCard/leadItemCard.styles.ts b/app/components/leadItemCard/leadItemCard.styles.ts
index 14b9c69..f427deb 100644
--- a/app/components/leadItemCard/leadItemCard.styles.ts
+++ b/app/components/leadItemCard/leadItemCard.styles.ts
@@ -3,72 +3,174 @@ import { ThemeColors } from '../../theme';
export const getStyles = (colors: ThemeColors) =>
StyleSheet.create({
+ cardWrapper: {
+ marginBottom: 16,
+ borderRadius: 20,
+ shadowColor: '#5B4CF5',
+ shadowOffset: { width: 0, height: 6 },
+ shadowOpacity: 0.10,
+ shadowRadius: 18,
+ elevation: 6,
+ },
card: {
backgroundColor: colors.card,
- borderRadius: 12,
- padding: 16,
- marginBottom: 12,
+ borderRadius: 20,
flexDirection: 'row',
- alignItems: 'center',
- shadowColor: '#000',
- shadowOffset: { width: 0, height: 2 },
- shadowOpacity: 0.05,
- shadowRadius: 4,
- elevation: 2,
+ overflow: 'hidden',
+ borderWidth: 1,
+ borderColor: colors.border,
},
- avatarContainer: {
- width: 56,
- height: 56,
- borderRadius: 28,
+ leftStrip: {
+ width: 4,
+ borderTopLeftRadius: 20,
+ borderBottomLeftRadius: 20,
+ },
+ cardInner: {
+ flex: 1,
+ padding: 15,
+ paddingLeft: 14,
+ },
+ topSection: {
+ flexDirection: 'row',
+ alignItems: 'flex-start',
+ marginBottom: 12,
+ },
+ avatar: {
+ width: 48,
+ height: 48,
+ borderRadius: 24,
justifyContent: 'center',
alignItems: 'center',
marginRight: 12,
},
avatarText: {
- fontSize: 20,
- fontWeight: '700',
+ fontSize: 16,
+ fontWeight: '800',
color: '#FFFFFF',
+ letterSpacing: 0.5,
},
- contentContainer: {
+ meta: {
flex: 1,
- },
- headerRow: {
- flexDirection: 'row',
- justifyContent: 'space-between',
- alignItems: 'center',
- marginBottom: 8,
+ minWidth: 0,
},
name: {
- fontSize: 16,
+ fontSize: 15,
fontWeight: '700',
color: colors.text,
- flex: 1,
- marginRight: 8,
+ marginBottom: 3,
+ letterSpacing: 0.05,
+ },
+ companyRow: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ marginBottom: 8,
+ gap: 5,
+ flexWrap: 'wrap',
+ },
+ companyText: {
+ fontSize: 12,
+ color: colors.textSecondary,
+ fontWeight: '500',
+ flexShrink: 1,
+ },
+ titleText: {
+ fontSize: 11,
+ color: colors.textMuted,
+ flexShrink: 1,
+ },
+ dot: {
+ width: 3,
+ height: 3,
+ borderRadius: 2,
+ backgroundColor: colors.textMuted,
+ opacity: 0.6,
},
statusBadge: {
+ alignSelf: 'flex-start',
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: 5,
paddingHorizontal: 10,
paddingVertical: 4,
- borderRadius: 12,
- flexShrink: 0,
+ borderRadius: 20,
+ },
+ statusDot: {
+ width: 5,
+ height: 5,
+ borderRadius: 3,
},
statusText: {
- fontSize: 11,
- fontWeight: '600',
- textTransform: 'capitalize',
+ fontSize: 10,
+ fontWeight: '700',
+ textTransform: 'uppercase',
+ letterSpacing: 0.7,
+ },
+ separator: {
+ height: StyleSheet.hairlineWidth,
+ backgroundColor: colors.border,
+ marginVertical: 11,
+ },
+ contacts: {
+ gap: 8,
},
contactRow: {
flexDirection: 'row',
alignItems: 'center',
- justifyContent: 'space-between',
- marginBottom: 6,
+ gap: 9,
+ },
+ iconWrap: {
+ width: 28,
+ height: 28,
+ borderRadius: 9,
+ justifyContent: 'center',
+ alignItems: 'center',
},
contactText: {
- fontSize: 13,
+ fontSize: 12,
color: colors.textSecondary,
flex: 1,
- marginRight: 8,
},
- contactIconButton: {
- padding: 4,
+ actionBtn: {
+ width: 28,
+ height: 28,
+ borderRadius: 9,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ footer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ marginTop: 12,
+ paddingTop: 10,
+ borderTopWidth: StyleSheet.hairlineWidth,
+ borderTopColor: colors.border,
+ },
+ sourcePill: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ backgroundColor: colors.surface,
+ borderRadius: 20,
+ paddingHorizontal: 9,
+ paddingVertical: 4,
+ gap: 5,
+ borderWidth: 1,
+ borderColor: colors.border,
+ },
+ sourceText: {
+ fontSize: 10,
+ color: colors.textMuted,
+ fontWeight: '600',
+ textTransform: 'uppercase',
+ letterSpacing: 0.5,
+ },
+ dateRow: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: 4,
+ },
+ dateText: {
+ fontSize: 10,
+ color: colors.textMuted,
},
});
diff --git a/app/components/leadItemCard/leadItemCard.tsx b/app/components/leadItemCard/leadItemCard.tsx
index 9f76af7..2bcb78f 100644
--- a/app/components/leadItemCard/leadItemCard.tsx
+++ b/app/components/leadItemCard/leadItemCard.tsx
@@ -1,83 +1,111 @@
import React from 'react';
-import {
- View,
- Text,
- TouchableOpacity,
-} from 'react-native';
+import { View, Text, TouchableOpacity } from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';
import { useTheme } from '@theme';
import { getStyles } from './leadItemCard.styles';
import { LeadItemCardProps } from './leadItemCard.props';
-import { getInitials, handleEmailPress, handlePhonePress } from '@utils';
+import { getInitials, handleEmailPress, handlePhonePress, toRgba, formatDate } from '@utils';
-export const LeadItemCard: React.FC = ({
- item,
- onPress,
-}) => {
- const { theme: colors } = useTheme();
+export const LeadItemCard: React.FC = ({ item, onPress }) => {
+ const { theme: colors, isDark } = useTheme();
const styles = getStyles(colors);
- return (
-
- {/* Left side - Avatar/Initials */}
-
- {getInitials(item.name)}
-
+ const accent = item.color?.startsWith('#') ? item.color : '#5B4CF5';
+ const tint = (a: number) => toRgba(accent, isDark ? a + 0.08 : a);
- {/* Right side - Content */}
-
- {/* Name and Status Row */}
-
-
- {item.name || 'No Name'}
-
-
-
- {item.status_name || item.status || 'No Status'}
-
+ return (
+
+
+
+
+
+
+
+ {getInitials(item.name)}
+
+
+
+
+ {item.name || 'No Name'}
+
+
+ {(item.company || item.title) && (
+
+ {item.company && (
+ <>
+
+ {item.company}
+ >
+ )}
+ {item.company && item.title && }
+ {item.title && (
+ {item.title}
+ )}
+
+ )}
+
+
+
+
+ {item.status_name || item.status || 'No Status'}
+
+
+
+
+
+ {(item.email || item.phonenumber) && (
+ <>
+
+
+ {item.email && (
+
+
+
+
+ {item.email}
+ handleEmailPress(item.email)}
+ hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
+
+
+
+ )}
+
+ {item.phonenumber && (
+
+
+
+
+ {item.phonenumber}
+ handlePhonePress(item.phonenumber)}
+ hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
+
+
+
+ )}
+
+ >
+ )}
+
+
+ {(item.source_name || item.source) ? (
+
+
+ {item.source_name || item.source}
+
+ ) : }
+
+ {item.dateadded && (
+
+
+ {formatDate(item.dateadded)}
+
+ )}
-
- {/* Email Row */}
- {item.email ? (
-
-
- {item.email}
-
- handleEmailPress(item.email)}
- hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}>
-
-
-
- ) : null}
-
- {/* Phone Row */}
- {item.phonenumber ? (
-
-
- {item.phonenumber}
-
- handlePhonePress(item.phonenumber)}
- hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}>
-
-
-
- ) : null}
);
diff --git a/app/components/searchInput/searchInput.styles.ts b/app/components/searchInput/searchInput.styles.ts
index 4f3cffc..c97e8ea 100644
--- a/app/components/searchInput/searchInput.styles.ts
+++ b/app/components/searchInput/searchInput.styles.ts
@@ -9,18 +9,25 @@ export const getStyles = (colors: ThemeColors) =>
backgroundColor: colors.surface,
borderWidth: 1,
borderColor: colors.border,
- borderRadius: 12,
- paddingHorizontal: 12,
+ borderRadius: 14,
+ paddingHorizontal: 14,
height: 48,
+ // Branded shadow — subtle indigo glow
+ shadowColor: '#5B4CF5',
+ shadowOffset: { width: 0, height: 3 },
+ shadowOpacity: 0.07,
+ shadowRadius: 8,
+ elevation: 2,
},
searchIcon: {
- marginRight: 8,
+ marginRight: 9,
},
input: {
flex: 1,
- fontSize: 15,
+ fontSize: 14,
color: colors.text,
paddingVertical: 0,
+ letterSpacing: 0.1,
},
clearButton: {
marginLeft: 8,
diff --git a/app/components/statCard/index.ts b/app/components/statCard/index.ts
new file mode 100644
index 0000000..23a9f95
--- /dev/null
+++ b/app/components/statCard/index.ts
@@ -0,0 +1,2 @@
+export * from './statCard';
+export * from './statCard.props';
diff --git a/app/components/statCard/statCard.props.ts b/app/components/statCard/statCard.props.ts
new file mode 100644
index 0000000..807615a
--- /dev/null
+++ b/app/components/statCard/statCard.props.ts
@@ -0,0 +1,7 @@
+export interface StatCardProps {
+ label: string;
+ count: number;
+ color: string;
+ isSelected?: boolean;
+ onPress?: () => void;
+}
diff --git a/app/components/statCard/statCard.styles.ts b/app/components/statCard/statCard.styles.ts
new file mode 100644
index 0000000..281e77c
--- /dev/null
+++ b/app/components/statCard/statCard.styles.ts
@@ -0,0 +1,60 @@
+import { StyleSheet } from 'react-native';
+import { ThemeColors } from '../../theme';
+
+export const getStyles = (colors: ThemeColors) =>
+ StyleSheet.create({
+ card: {
+ minWidth: 105,
+ height: 84,
+ borderRadius: 16,
+ backgroundColor: colors.card,
+ borderWidth: 1.5,
+ borderColor: colors.border,
+ paddingHorizontal: 8,
+ paddingVertical: 10,
+ alignItems: 'center',
+ justifyContent: 'center',
+ shadowColor: '#5B4CF5',
+ shadowOffset: { width: 0, height: 2 },
+ shadowOpacity: 0.05,
+ shadowRadius: 6,
+ elevation: 2,
+ },
+ cardSelected: {
+ borderWidth: 2,
+ shadowOpacity: 0.12,
+ shadowRadius: 8,
+ elevation: 3,
+ },
+ pillTag: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ paddingHorizontal: 9,
+ paddingVertical: 4,
+ borderRadius: 10,
+ gap: 5,
+ maxWidth: '100%',
+ },
+ pillTagInactive: {
+ backgroundColor: colors.surface,
+ },
+ statusDot: {
+ width: 6,
+ height: 6,
+ borderRadius: 3,
+ },
+ labelText: {
+ fontSize: 11,
+ fontWeight: '700',
+ },
+ countText: {
+ fontSize: 24,
+ fontWeight: '900',
+ color: colors.text,
+ textAlign: 'center',
+ marginTop: 6,
+ lineHeight: 28,
+ includeFontPadding: false,
+ letterSpacing: -0.5,
+ },
+ });
diff --git a/app/components/statCard/statCard.tsx b/app/components/statCard/statCard.tsx
new file mode 100644
index 0000000..0900e5c
--- /dev/null
+++ b/app/components/statCard/statCard.tsx
@@ -0,0 +1,67 @@
+import React from 'react';
+import { View, Text, TouchableOpacity } from 'react-native';
+import { useTheme } from '../../theme';
+import { getStyles } from './statCard.styles';
+import { StatCardProps } from './statCard.props';
+
+export const StatCard: React.FC = ({
+ label,
+ count,
+ color,
+ isSelected = false,
+ onPress,
+}) => {
+ const { theme: colors } = useTheme();
+ const styles = getStyles(colors);
+
+ const themeColor = color || colors.icon;
+ const borderColor = isSelected ? themeColor : colors.border;
+
+ return (
+
+ {/* Top Status Pill Tag */}
+
+
+
+ {label}
+
+
+
+ {/* Large Metric Count */}
+
+ {count}
+
+
+ );
+};
diff --git a/app/features/leadDetails/leadDetails.screen.tsx b/app/features/leadDetails/leadDetails.screen.tsx
index 306aaca..b386c39 100644
--- a/app/features/leadDetails/leadDetails.screen.tsx
+++ b/app/features/leadDetails/leadDetails.screen.tsx
@@ -1,11 +1,6 @@
import React, { useEffect } from 'react';
-import {
- View,
- Text,
- ScrollView,
- Linking,
- Platform,
-} from 'react-native';
+import { View, Text, ScrollView, TouchableOpacity } from 'react-native';
+import Icon from 'react-native-vector-icons/Ionicons';
import { RouteProp, useRoute, useNavigation } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { useTheme } from '@theme';
@@ -14,14 +9,10 @@ import { getLeadDetails } from './thunk';
import { getStyles } from './leadDetails.styles';
import { LeadsStackParamList } from '../../navigation/leadsStack';
import { Loader, LeadDetailHeader, ActionCard } from '@components';
-import { handleEmailPress, handlePhonePress } from '@utils';
-import { route as routes } from '@utils';
+import { handleEmailPress, handlePhonePress, handleWebsitePress, formatDate, route as routes } from '@utils';
type LeadDetailsRouteProp = RouteProp;
-type LeadDetailsNavigationProp = NativeStackNavigationProp<
- LeadsStackParamList,
- 'leadDetails'
->;
+type LeadDetailsNavigationProp = NativeStackNavigationProp;
export const LeadDetailsScreen = () => {
const route = useRoute();
@@ -30,35 +21,23 @@ export const LeadDetailsScreen = () => {
const { theme: colors } = useTheme();
const styles = getStyles(colors);
- // Get lead ID from route params
const leadId = route.params?.lead?.id;
-
- // Get data from Redux store
- const { item: lead, loading, error } = useAppSelector(
- (state: RootState) => state.leadDetails,
- );
+ const { item: lead, loading, error } = useAppSelector((state: RootState) => state.leadDetails);
const user_data = useAppSelector((state: RootState) => state.auth.user_data);
- // Fetch lead details on mount
useEffect(() => {
if (leadId && user_data?.staffid) {
dispatch(getLeadDetails({ leadId, staffid: user_data.staffid }));
}
}, [dispatch, leadId, user_data]);
- // Show loader while loading
- if (loading) {
- return ;
- }
+ if (loading) return ;
- // Show error if any
if (error) {
return (
-
-
- {error}
-
+
+ {error}
);
@@ -67,50 +46,19 @@ export const LeadDetailsScreen = () => {
if (!lead) {
return (
- No lead data available
+
+ No lead data available
+
);
}
- // Handle status press (for future status change functionality)
- const handleStatusPress = () => {
- // TODO: Show status list modal/picker
- console.log('Status pressed - show status list');
- };
-
- // Proposals handlers
- const handleAddProposal = () => {
- // TODO: Navigate to add proposal screen
- navigation.navigate(routes.leadProposals, { leadId: lead.id });
- };
-
- const handleViewAllProposals = () => {
- console.log('view Proposal pressed');
- };
-
- // Tasks handlers
- const handleAddTask = () => {
- // TODO: Navigate to add task screen
- navigation.navigate(routes.leadTasks, { leadId: lead.id });
- };
-
- const handleViewAllTasks = () => {
- console.log('view Add Task pressed');
- };
-
- // Notes handlers
- const handleAddNote = () => {
- // TODO: Navigate to add note screen
- navigation.navigate(routes.leadNotes, { leadId: lead.id });
- };
-
- const handleViewAllNotes = () => {
- console.log('view Add Note pressed');
- };
+ const addressString = [lead.address, lead.city, lead.state, lead.country]
+ .filter(Boolean)
+ .join(', ');
return (
- {/* Header with Avatar */}
{
phonenumber={lead.phonenumber}
statusName={lead.status_name || lead.status}
statusColor={lead.color}
- onStatusPress={handleStatusPress}
onEmailPress={() => handleEmailPress(lead.email)}
onPhonePress={() => handlePhonePress(lead.phonenumber)}
/>
- {/* Action Cards Section */}
+
+
+ Lead Value
+
+ {lead.lead_value ? `$${lead.lead_value}` : 'N/A'}
+
+
+
+ Source
+
+ {lead.source_name || lead.source || 'Direct'}
+
+
+
+ Created
+
+ {formatDate(lead.dateadded) || 'N/A'}
+
+
+
+
+ Lead Information
+
+ {lead.email ? (
+ <>
+ handleEmailPress(lead.email)}
+ activeOpacity={0.7}>
+
+
+
+
+ Email
+ {lead.email}
+
+
+
+ >
+ ) : null}
+
+ {lead.phonenumber ? (
+ <>
+ handlePhonePress(lead.phonenumber)}
+ activeOpacity={0.7}>
+
+
+
+
+ Phone
+ {lead.phonenumber}
+
+
+
+ >
+ ) : null}
+
+ {lead.website ? (
+ <>
+ handleWebsitePress(lead.website)}
+ activeOpacity={0.7}>
+
+
+
+
+ Website
+ {lead.website}
+
+
+
+ >
+ ) : null}
+
+ {addressString ? (
+ <>
+
+
+
+
+
+ Address
+ {addressString}
+
+
+
+ >
+ ) : null}
+
+ {lead.assigned ? (
+
+
+
+
+
+ Assigned Staff
+ {lead.assigned}
+
+
+ ) : null}
+
+
+ Activity & Management
navigation.navigate(routes.leadProposals, { leadId: lead.id })}
+ onViewAllPress={() => navigation.navigate(routes.leadProposals, { leadId: lead.id })}
/>
navigation.navigate(routes.leadTasks, { leadId: lead.id })}
+ onViewAllPress={() => navigation.navigate(routes.leadTasks, { leadId: lead.id })}
/>
navigation.navigate(routes.leadNotes, { leadId: lead.id })}
+ onViewAllPress={() => navigation.navigate(routes.leadNotes, { leadId: lead.id })}
/>
diff --git a/app/features/leadDetails/leadDetails.styles.ts b/app/features/leadDetails/leadDetails.styles.ts
index 70ad542..745060f 100644
--- a/app/features/leadDetails/leadDetails.styles.ts
+++ b/app/features/leadDetails/leadDetails.styles.ts
@@ -9,114 +9,102 @@ export const getStyles = (colors: ThemeColors) =>
},
scrollContent: {
padding: 16,
- },
- cardsContainer: {
- marginTop: 16,
- },
- header: {
- alignItems: 'center',
- paddingVertical: 24,
- borderBottomWidth: 1,
- borderBottomColor: colors.border,
- marginBottom: 16,
- },
- avatar: {
- width: 80,
- height: 80,
- borderRadius: 40,
- justifyContent: 'center',
- alignItems: 'center',
- marginBottom: 12,
- },
- avatarText: {
- fontSize: 32,
- fontWeight: '700',
- color: '#FFFFFF',
- },
- name: {
- fontSize: 24,
- fontWeight: '700',
- color: colors.text,
- marginBottom: 4,
- },
- company: {
- fontSize: 16,
- color: colors.textSecondary,
- marginBottom: 8,
- },
- statusBadge: {
- paddingHorizontal: 16,
- paddingVertical: 6,
- borderRadius: 16,
- },
- statusText: {
- fontSize: 13,
- fontWeight: '600',
- textTransform: 'capitalize',
- },
- section: {
- backgroundColor: colors.card,
- borderRadius: 12,
- padding: 16,
- marginBottom: 16,
- shadowColor: '#000',
- shadowOffset: { width: 0, height: 2 },
- shadowOpacity: 0.05,
- shadowRadius: 4,
- elevation: 2,
+ paddingBottom: 32,
},
sectionTitle: {
- fontSize: 16,
+ fontSize: 15,
fontWeight: '700',
color: colors.text,
marginBottom: 12,
+ letterSpacing: 0.1,
+ },
+ statsRow: {
+ flexDirection: 'row',
+ gap: 10,
+ marginBottom: 16,
+ },
+ statCard: {
+ flex: 1,
+ backgroundColor: colors.card,
+ borderRadius: 16,
+ padding: 14,
+ borderWidth: 1,
+ borderColor: colors.border,
+ shadowColor: '#5B4CF5',
+ shadowOffset: { width: 0, height: 4 },
+ shadowOpacity: 0.05,
+ shadowRadius: 10,
+ elevation: 2,
+ },
+ statLabel: {
+ fontSize: 11,
+ color: colors.textMuted,
+ marginBottom: 4,
+ fontWeight: '500',
+ },
+ statValue: {
+ fontSize: 15,
+ fontWeight: '700',
+ color: colors.text,
+ },
+ infoCard: {
+ backgroundColor: colors.card,
+ borderRadius: 18,
+ padding: 16,
+ marginBottom: 16,
+ borderWidth: 1,
+ borderColor: colors.border,
+ shadowColor: '#5B4CF5',
+ shadowOffset: { width: 0, height: 4 },
+ shadowOpacity: 0.05,
+ shadowRadius: 10,
+ elevation: 2,
},
infoRow: {
flexDirection: 'row',
alignItems: 'center',
- marginBottom: 12,
+ paddingVertical: 9,
+ gap: 12,
},
- infoIcon: {
- width: 40,
- height: 40,
- borderRadius: 20,
+ infoIconWrap: {
+ width: 32,
+ height: 32,
+ borderRadius: 10,
backgroundColor: colors.surface,
justifyContent: 'center',
alignItems: 'center',
- marginRight: 12,
+ borderWidth: 1,
+ borderColor: colors.border,
},
- infoContent: {
+ infoMeta: {
flex: 1,
},
infoLabel: {
- fontSize: 12,
+ fontSize: 11,
color: colors.textMuted,
marginBottom: 2,
},
infoValue: {
- fontSize: 14,
- color: colors.text,
- fontWeight: '500',
- },
- actionButton: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'center',
- backgroundColor: colors.icon,
- paddingVertical: 14,
- paddingHorizontal: 20,
- borderRadius: 12,
- marginBottom: 12,
- },
- actionButtonText: {
- fontSize: 15,
+ fontSize: 13,
fontWeight: '600',
- color: '#FFFFFF',
- marginLeft: 8,
+ color: colors.text,
},
- noteText: {
+ divider: {
+ height: StyleSheet.hairlineWidth,
+ backgroundColor: colors.border,
+ },
+ cardsContainer: {
+ marginTop: 4,
+ },
+ errorContainer: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ padding: 32,
+ },
+ errorText: {
+ color: '#EF4444',
fontSize: 14,
- color: colors.textSecondary,
- lineHeight: 20,
+ textAlign: 'center',
},
});
diff --git a/app/features/leads/leads.screen.tsx b/app/features/leads/leads.screen.tsx
index d6ef546..3dab9a3 100644
--- a/app/features/leads/leads.screen.tsx
+++ b/app/features/leads/leads.screen.tsx
@@ -3,7 +3,9 @@ import {
Text,
View,
FlatList,
+ ScrollView,
TouchableOpacity,
+ ActivityIndicator,
} from 'react-native';
import { useNavigation } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
@@ -11,9 +13,9 @@ import Icon from 'react-native-vector-icons/Ionicons';
import { getStyles } from './leads.styles';
import { useTheme } from '@theme';
import { useAppDispatch, useAppSelector, RootState } from '@store';
-import { getLeads } from './thunk';
+import { getLeads, getLeadCountList } from './thunk';
import { LeadItem } from '@interfaces';
-import { LeadItemCard, SearchInput, Loader } from '@components';
+import { LeadItemCard, SearchInput, Loader, StatCard } from '@components';
import { LeadsStackParamList } from '../../navigation/leadsStack';
import { route } from '@utils';
@@ -28,8 +30,9 @@ export const LeadsScreen = () => {
const { theme: colors } = useTheme();
const styles = getStyles(colors);
const [searchTerm, setSearchTerm] = useState('');
+ const [selectedStatusId, setSelectedStatusId] = useState(null);
- const { items, loading, error } = useAppSelector(
+ const { items, loading, error, counts, countsLoading } = useAppSelector(
(state: RootState) => state.leads,
);
const user_data = useAppSelector((state: RootState) => state.auth.user_data);
@@ -37,20 +40,30 @@ export const LeadsScreen = () => {
useEffect(() => {
if (user_data?.staffid) {
dispatch(getLeads({ leadId: null, staffid: user_data.staffid }));
+ dispatch(getLeadCountList(user_data.staffid));
}
}, [dispatch, user_data]);
- const filteredLeads = searchTerm
- ? items.filter(
- lead =>
- lead.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
- lead.company.toLowerCase().includes(searchTerm.toLowerCase()) ||
- lead.email.toLowerCase().includes(searchTerm.toLowerCase()),
- )
- : items;
+ const filteredLeads = items.filter(lead => {
+ const matchesSearch = searchTerm
+ ? lead.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
+ lead.company.toLowerCase().includes(searchTerm.toLowerCase()) ||
+ lead.email.toLowerCase().includes(searchTerm.toLowerCase())
+ : true;
+
+ const matchesStatus =
+ !selectedStatusId || selectedStatusId === '0'
+ ? true
+ : lead.status === selectedStatusId;
+
+ return matchesSearch && matchesStatus;
+ });
+
+ const handleStatusPress = (id: string) => {
+ setSelectedStatusId(prev => (prev === id ? null : id));
+ };
const handleLeadPress = (lead: LeadItem) => {
- // Navigate to lead details screen
navigation.navigate(route.leadDetails, { lead });
};
@@ -60,6 +73,7 @@ export const LeadsScreen = () => {
return (
+ {/* Search + Filter Header (Fixed at top) */}
{
+ {/* Status count cards */}
+ {countsLoading ? (
+
+
+
+ ) : counts.length > 0 ? (
+
+ {counts.map(item => (
+ handleStatusPress(item.id)}
+ />
+ ))}
+
+ ) : null}
+
+ {/* Lead list */}
{loading ? (
) : error ? (
@@ -82,11 +122,20 @@ export const LeadsScreen = () => {
item.id}
+ style={{ flex: 1 }}
contentContainerStyle={styles.listContent}
renderItem={renderLead}
ListEmptyComponent={() => (
- No leads available.
+
+
+
+ No Leads Found
+
+ {searchTerm
+ ? `No leads match "${searchTerm}". Try a different search.`
+ : 'You have no leads yet. New leads will appear here.'}
+
)}
/>
diff --git a/app/features/leads/leads.styles.ts b/app/features/leads/leads.styles.ts
index faef590..b425082 100644
--- a/app/features/leads/leads.styles.ts
+++ b/app/features/leads/leads.styles.ts
@@ -7,9 +7,22 @@ export const getStyles = (colors: ThemeColors) =>
flex: 1,
backgroundColor: colors.background,
},
+ countsLoading: {
+ height: 82,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ countsScroll: {
+ paddingHorizontal: 16,
+ paddingTop: 4,
+ paddingBottom: 10,
+ gap: 10,
+ },
header: {
flexDirection: 'row',
- padding: 16,
+ paddingHorizontal: 16,
+ paddingTop: 12,
+ paddingBottom: 10,
alignItems: 'center',
gap: 10,
},
@@ -22,13 +35,20 @@ export const getStyles = (colors: ThemeColors) =>
backgroundColor: colors.surface,
borderWidth: 1,
borderColor: colors.border,
- borderRadius: 12,
+ borderRadius: 14,
justifyContent: 'center',
alignItems: 'center',
+ // Branded indigo shadow
+ shadowColor: '#5B4CF5',
+ shadowOffset: { width: 0, height: 3 },
+ shadowOpacity: 0.12,
+ shadowRadius: 6,
+ elevation: 3,
},
listContent: {
- padding: 16,
- paddingTop: 0,
+ paddingHorizontal: 16,
+ paddingTop: 6,
+ paddingBottom: 40,
},
errorContainer: {
flex: 1,
@@ -42,14 +62,40 @@ export const getStyles = (colors: ThemeColors) =>
textAlign: 'center',
},
emptyContainer: {
- flex: 1,
+ alignItems: 'center',
+ paddingTop: 80,
+ padding: 32,
+ gap: 10,
+ },
+ emptyIconWrap: {
+ width: 76,
+ height: 76,
+ borderRadius: 38,
+ backgroundColor: colors.surface,
justifyContent: 'center',
alignItems: 'center',
- padding: 32,
+ marginBottom: 10,
+ borderWidth: 1,
+ borderColor: colors.border,
+ // Subtle shadow
+ shadowColor: '#5B4CF5',
+ shadowOffset: { width: 0, height: 4 },
+ shadowOpacity: 0.10,
+ shadowRadius: 10,
+ elevation: 3,
+ },
+ emptyTitle: {
+ color: colors.text,
+ fontSize: 17,
+ fontWeight: '700',
+ textAlign: 'center',
+ letterSpacing: 0.1,
},
emptyText: {
color: colors.textSecondary,
- fontSize: 14,
+ fontSize: 13,
textAlign: 'center',
+ lineHeight: 20,
+ maxWidth: 280,
},
});
diff --git a/app/features/leads/reducers.ts b/app/features/leads/reducers.ts
index 4d84599..7372e1d 100644
--- a/app/features/leads/reducers.ts
+++ b/app/features/leads/reducers.ts
@@ -1,17 +1,23 @@
import { createReducer } from '@reduxjs/toolkit';
-import { getLeads } from './thunk';
-import { LeadItem } from '@interfaces';
+import { getLeads, getLeadCountList } from './thunk';
+import { LeadItem, LeadCountItem } from '@interfaces';
export interface LeadsState {
items: LeadItem[];
loading: boolean;
error: string | null;
+ counts: LeadCountItem[];
+ countsLoading: boolean;
+ countsError: string | null;
}
const initialState: LeadsState = {
items: [],
loading: false,
error: null,
+ counts: [],
+ countsLoading: false,
+ countsError: null,
};
export const reducers = createReducer(initialState, builder => {
@@ -31,6 +37,22 @@ export const reducers = createReducer(initialState, builder => {
(action.payload as string) ??
action.error.message ??
'Failed to load leads';
+ })
+ .addCase(getLeadCountList.pending, acc => {
+ acc.countsLoading = true;
+ acc.countsError = null;
+ })
+ .addCase(getLeadCountList.fulfilled, (acc, action) => {
+ acc.countsLoading = false;
+ acc.counts = action.payload;
+ acc.countsError = null;
+ })
+ .addCase(getLeadCountList.rejected, (acc, action) => {
+ acc.countsLoading = false;
+ acc.countsError =
+ (action.payload as string) ??
+ action.error.message ??
+ 'Failed to load lead counts';
});
});
diff --git a/app/features/leads/thunk.ts b/app/features/leads/thunk.ts
index ddf9711..bb019e0 100644
--- a/app/features/leads/thunk.ts
+++ b/app/features/leads/thunk.ts
@@ -1,6 +1,6 @@
import { createAsyncThunk } from '@reduxjs/toolkit';
-import { getLeadsApi } from '@api';
-import { LeadItem } from '@interfaces';
+import { getLeadsApi, getLeadCountListApi } from '@api';
+import { LeadItem, LeadCountItem } from '@interfaces';
export const getLeads = createAsyncThunk<
LeadItem[],
@@ -12,3 +12,14 @@ export const getLeads = createAsyncThunk<
return rejectWithValue(error.message || 'Failed to load leads');
}
});
+
+export const getLeadCountList = createAsyncThunk<
+ LeadCountItem[],
+ string
+>('leads/getLeadCountList', async (staffid, { rejectWithValue }) => {
+ try {
+ return await getLeadCountListApi(staffid);
+ } catch (error: any) {
+ return rejectWithValue(error.message || 'Failed to load lead counts');
+ }
+});
diff --git a/app/features/login/login.screen.tsx b/app/features/login/login.screen.tsx
index 5e57691..1d05db0 100644
--- a/app/features/login/login.screen.tsx
+++ b/app/features/login/login.screen.tsx
@@ -2,29 +2,37 @@ import React, { useState, useEffect } from 'react';
import {
Text,
View,
- TextInput,
TouchableOpacity,
KeyboardAvoidingView,
Platform,
ScrollView,
+ ImageBackground,
+ ActivityIndicator,
+ StatusBar,
} from 'react-native';
import { useNavigation } from '@react-navigation/native';
import Icon from 'react-native-vector-icons/Ionicons';
import { getStyles } from './login.styles';
-import { useTheme } from '../../theme';
-import { useAppDispatch, useAppSelector } from '../../store/store';
-import { login } from '../../store/commonReducers/auth/thunk';
+import { useTheme } from '@theme';
+import { useAppDispatch, useAppSelector, RootState, login } from '@store';
import { LoginRequest } from '@interfaces';
-import { RootState } from '../../store/rootReducer';
+import { NotificationService } from '@services';
+import { backGroundImage } from '@utils';
+import { FormInput } from '@components';
+import config from 'react-native-config';
+import AsyncStorage from '@react-native-async-storage/async-storage';
export const LoginScreen = () => {
const dispatch = useAppDispatch();
const navigation = useNavigation();
- const { theme: colors } = useTheme();
- const styles = getStyles(colors);
+ const { theme: colors, isDark } = useTheme();
+ const styles = getStyles(colors, isDark);
+
const [tenancy, setTenancy] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
+ const [showPassword, setShowPassword] = useState(false);
+ const [focusedField, setFocusedField] = useState(null);
const [localError, setLocalError] = useState('');
const { loginLoading, loginError, loginSuccess, token, user_data } =
@@ -40,20 +48,69 @@ export const LoginScreen = () => {
setLocalError('Email address is required');
return;
}
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+ if (!emailRegex.test(email.trim())) {
+ setLocalError('Please enter a valid email address');
+ return;
+ }
if (!password.trim()) {
setLocalError('Password is required');
return;
}
+ const deviceToken = await NotificationService.getFCMToken();
+ console.log('deviceToken-', deviceToken)
+
const payload: LoginRequest = {
email,
password,
- device_token: '',
+ device_token: deviceToken ?? '',
};
-
- await dispatch(login(payload));
+ console.log('payload-', payload)
+ console.log('tenancy-', config.BASE_URL)
+ if (tenancy == config.BASE_URL) {
+ try {
+ await AsyncStorage.setItem('base_url', tenancy);
+ await AsyncStorage.setItem('email', email);
+ await AsyncStorage.setItem('password', password);
+ } catch (e) {
+ console.error('Failed to save login credentials to AsyncStorage', e);
+ }
+ await dispatch(login(payload));
+ } else {
+ setLocalError('Invalid tenancy name');
+ }
};
+ useEffect(() => {
+ const loadCredentials = async () => {
+ try {
+ const savedBaseUrl = await AsyncStorage.getItem('base_url');
+ const savedEmail = await AsyncStorage.getItem('email');
+ const savedPassword = await AsyncStorage.getItem('password');
+
+ if (savedBaseUrl) setTenancy(savedBaseUrl);
+ if (savedEmail) setEmail(savedEmail);
+ if (savedPassword) setPassword(savedPassword);
+ } catch (e) {
+ console.error('Failed to load login credentials from AsyncStorage', e);
+ }
+ };
+ loadCredentials();
+ }, []);
+
+ useEffect(() => {
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+ if (
+ tenancy.trim() &&
+ email.trim() &&
+ emailRegex.test(email.trim()) &&
+ password.trim()
+ ) {
+ setLocalError('');
+ }
+ }, [tenancy, email, password]);
+
useEffect(() => {
if (loginSuccess && token && user_data) {
navigation.reset({
@@ -64,117 +121,164 @@ export const LoginScreen = () => {
}, [loginSuccess, token, user_data, navigation]);
return (
-
-
-
-
-
-
- Convex CRM
-
- Enter details to access your workspace
-
-
+
+
+
+
+ {/* Top Area Spacer displaying background illustration */}
+
-
- {localError || loginError ? (
-
-
- {localError || loginError}
-
- ) : null}
+ {/* Bottom Sheet Form Card */}
+
+
- {/* Tenancy Field */}
-
- Tenancy Name
-
-
-
+ Sign In
+
+ Enter your credentials to continue
+
+
+
+ {localError || loginError ? (
+
+
+ {localError || loginError}
+
+ ) : null}
+
+ {/* Tenancy Field */}
+ setFocusedField('tenancy')}
+ onBlur={() => setFocusedField(null)}
+ leftIcon={
+
+ }
/>
-
-
- {/* Email Field */}
-
- Email Address
-
-
- setFocusedField('email')}
+ onBlur={() => setFocusedField(null)}
+ leftIcon={
+
+ }
/>
-
-
- {/* Password Field */}
-
- Password
-
-
- setFocusedField('password')}
+ onBlur={() => setFocusedField(null)}
+ leftIcon={
+
+ }
+ rightIcon={
+ setShowPassword(!showPassword)}
+ style={styles.eyeIconButton}
+ activeOpacity={0.7}
+ >
+
+
+ }
/>
+
+ {/* Sign In Button */}
+
+ {loginLoading ? (
+
+ ) : (
+ Sign In
+ )}
+
-
-
- {/* Sign In Button */}
-
-
- {loginLoading ? 'Signing In...' : 'Sign In'}
-
-
-
-
-
- Secure SSL encrypted workspace
-
-
-
+
+
+
+
);
};
diff --git a/app/features/login/login.styles.ts b/app/features/login/login.styles.ts
index 7490beb..f512eb9 100644
--- a/app/features/login/login.styles.ts
+++ b/app/features/login/login.styles.ts
@@ -1,128 +1,129 @@
-import { StyleSheet } from 'react-native';
+import { StyleSheet, Platform } from 'react-native';
import { ThemeColors } from '../../theme';
-export const getStyles = (colors: ThemeColors) =>
+export const getStyles = (colors: ThemeColors, isDark: boolean) =>
StyleSheet.create({
container: {
flex: 1,
- backgroundColor: colors.background,
+ },
+ backgroundImage: {
+ flex: 1,
+ width: '100%',
+ height: '100%',
+ },
+ overlay: {
+ flex: 1,
+ backgroundColor: isDark
+ ? 'rgba(10, 12, 26, 0.75)'
+ : 'rgba(235, 242, 250, 0.35)',
},
scrollContainer: {
flexGrow: 1,
- justifyContent: 'center',
- padding: 24,
+ justifyContent: 'space-between',
},
- headerContainer: {
- alignItems: 'center',
- marginBottom: 32,
+ topSpacer: {
+ flex: 1,
+ minHeight: 120,
},
- logoCircle: {
- width: 80,
- height: 80,
- borderRadius: 40,
- backgroundColor: colors.border,
- justifyContent: 'center',
- alignItems: 'center',
+ bottomSheetCard: {
+ backgroundColor: isDark
+ ? 'rgba(26, 29, 58, 0.96)'
+ : 'rgba(255, 255, 255, 0.98)',
+ borderTopLeftRadius: 32,
+ borderTopRightRadius: 32,
+ borderBottomLeftRadius: 0,
+ borderBottomRightRadius: 0,
+ paddingHorizontal: 24,
+ paddingTop: 14,
+ paddingBottom: Platform.OS === 'ios' ? 36 : 24,
+ borderWidth: 1,
+ borderBottomWidth: 0,
+ borderColor: isDark
+ ? 'rgba(255, 255, 255, 0.1)'
+ : 'rgba(228, 232, 245, 0.9)',
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: -8 },
+ shadowOpacity: isDark ? 0.4 : 0.12,
+ shadowRadius: 20,
+ elevation: 16,
+ },
+ sheetHandle: {
+ width: 36,
+ height: 4,
+ borderRadius: 2,
+ backgroundColor: isDark ? 'rgba(255, 255, 255, 0.2)' : '#CBD5E1',
+ alignSelf: 'center',
marginBottom: 16,
- shadowColor: colors.icon,
- shadowOffset: { width: 0, height: 4 },
- shadowOpacity: 0.3,
- shadowRadius: 10,
- elevation: 8,
},
- title: {
- fontSize: 28,
+ cardHeader: {
+ marginBottom: 18,
+ },
+ welcomeTitle: {
+ fontSize: 22,
fontWeight: '800',
color: colors.text,
- letterSpacing: 0.5,
+ letterSpacing: 0.2,
},
- subtitle: {
- fontSize: 14,
+ welcomeSubtitle: {
+ fontSize: 13,
color: colors.textSecondary,
- marginTop: 8,
- textAlign: 'center',
- },
- formCard: {
- backgroundColor: colors.card,
- borderRadius: 16,
- padding: 24,
- shadowColor: '#000',
- shadowOffset: { width: 0, height: 10 },
- shadowOpacity: 0.25,
- shadowRadius: 15,
- elevation: 10,
+ marginTop: 4,
+ fontWeight: '400',
},
errorBanner: {
flexDirection: 'row',
alignItems: 'center',
- backgroundColor: '#451A1A',
- borderRadius: 8,
+ backgroundColor: isDark ? 'rgba(239, 68, 68, 0.15)' : '#FEF2F2',
+ borderRadius: 12,
padding: 12,
marginBottom: 16,
borderWidth: 1,
- borderColor: '#7F1D1D',
+ borderColor: isDark ? 'rgba(239, 68, 68, 0.3)' : '#FCA5A5',
},
errorText: {
- color: '#FCA5A5',
+ color: '#EF4444',
fontSize: 13,
- marginLeft: 8,
+ fontWeight: '500',
+ marginLeft: 10,
flex: 1,
},
- inputContainer: {
- marginBottom: 20,
- },
- label: {
- fontSize: 13,
- fontWeight: '600',
- color: colors.textSecondary,
- marginBottom: 8,
- textTransform: 'uppercase',
- letterSpacing: 0.5,
+ fieldContainer: {
+ marginBottom: 14,
},
inputWrapper: {
- flexDirection: 'row',
- alignItems: 'center',
- backgroundColor: colors.background,
- borderRadius: 10,
- borderWidth: 1,
- borderBottomColor: colors.border,
+ backgroundColor: isDark ? 'rgba(15, 16, 34, 0.6)' : '#F8FAFC',
+ borderRadius: 14,
+ borderWidth: 1.5,
borderColor: colors.border,
- paddingHorizontal: 12,
+ height: 50,
},
- inputIcon: {
- marginRight: 10,
+ inputWrapperFocused: {
+ borderColor: colors.icon,
+ backgroundColor: isDark ? 'rgba(15, 16, 34, 0.85)' : '#FFFFFF',
},
- input: {
- flex: 1,
- height: 48,
- color: colors.text,
- fontSize: 15,
+ eyeIconButton: {
+ padding: 6,
},
button: {
backgroundColor: colors.icon,
- borderRadius: 10,
- height: 50,
+ borderRadius: 14,
+ height: 52,
justifyContent: 'center',
alignItems: 'center',
- marginTop: 8,
+ marginTop: 10,
shadowColor: colors.icon,
- shadowOffset: { width: 0, height: 4 },
- shadowOpacity: 0.4,
- shadowRadius: 6,
- elevation: 5,
+ shadowOffset: { width: 0, height: 6 },
+ shadowOpacity: 0.35,
+ shadowRadius: 12,
+ elevation: 6,
+ },
+ buttonDisabled: {
+ opacity: 0.7,
},
buttonText: {
color: '#FFFFFF',
fontSize: 16,
fontWeight: '700',
- letterSpacing: 0.5,
- },
- footer: {
- alignItems: 'center',
- marginTop: 32,
- },
- footerText: {
- fontSize: 12,
- color: colors.textMuted,
+ letterSpacing: 0.4,
},
});
diff --git a/app/features/profile/profile.screen.tsx b/app/features/profile/profile.screen.tsx
index 32bb906..ee063fa 100644
--- a/app/features/profile/profile.screen.tsx
+++ b/app/features/profile/profile.screen.tsx
@@ -1,20 +1,21 @@
import React from 'react';
import { Text, View, TouchableOpacity, ScrollView, Switch } from 'react-native';
-import AsyncStorage from '@react-native-async-storage/async-storage';
import { useNavigation } from '@react-navigation/native';
import Icon from 'react-native-vector-icons/Ionicons';
import { getStyles } from './profile.styles';
import { useTheme } from '../../theme';
+import { useAppDispatch, logout } from '@store';
+
export const ProfileScreen = () => {
const navigation = useNavigation();
const { theme: colors, isDark, toggleTheme } = useTheme();
const styles = getStyles(colors);
+ const dispatch = useAppDispatch();
const handleLogout = async () => {
try {
- await AsyncStorage.removeItem('userToken');
- await AsyncStorage.removeItem('tenancyName');
+ dispatch(logout());
} catch (e) {
console.error(e);
}
diff --git a/app/interfaces/index.ts b/app/interfaces/index.ts
index c6ee8be..9392ca8 100644
--- a/app/interfaces/index.ts
+++ b/app/interfaces/index.ts
@@ -2,3 +2,4 @@ export * from './drawerItem';
export * from './auth';
export * from './leads';
export * from './leadDetails';
+export * from './list';
diff --git a/app/interfaces/leads.ts b/app/interfaces/leads.ts
index 410141f..e5dfaae 100644
--- a/app/interfaces/leads.ts
+++ b/app/interfaces/leads.ts
@@ -46,3 +46,12 @@ export interface LeadItem {
status_name: string;
source_name: string;
}
+
+export interface LeadCountItem {
+ id: string;
+ name: string;
+ statusorder: string | number;
+ color: string;
+ isdefault: string | number;
+ count: number;
+}
diff --git a/app/interfaces/list.ts b/app/interfaces/list.ts
new file mode 100644
index 0000000..d2c0759
--- /dev/null
+++ b/app/interfaces/list.ts
@@ -0,0 +1,25 @@
+export interface StatusListItem {
+ id: string;
+ name: string;
+ statusorder: string;
+ color: string;
+ isdefault: string;
+}
+
+export interface SourceListItem {
+ id: string;
+ name: string;
+}
+
+export interface CountryListItem {
+ country_id: string;
+ iso2: string;
+ short_name: string;
+ long_name: string;
+ iso3: string;
+ numcode: string;
+ un_member: string;
+ calling_code: string;
+ cctld: string;
+}
+
diff --git a/app/navigation/customDrawerContent.tsx b/app/navigation/customDrawerContent.tsx
index 16505b3..90cc851 100644
--- a/app/navigation/customDrawerContent.tsx
+++ b/app/navigation/customDrawerContent.tsx
@@ -1,13 +1,14 @@
import React from 'react';
import { Text, View, TouchableOpacity, ScrollView } from 'react-native';
import { DrawerContentComponentProps } from '@react-navigation/drawer';
-import AsyncStorage from '@react-native-async-storage/async-storage';
import Icon from 'react-native-vector-icons/Ionicons';
import { menuItems } from '@mock-data';
import { useTheme } from '@theme';
import { DrawerItemProps } from '@interfaces';
import { getStyles } from './customDrawerContent.style';
+import { useAppDispatch, logout } from '@store';
+
const DrawerItem = ({ label, iconName, focused, onPress }: DrawerItemProps) => {
const { theme: colors } = useTheme();
const styles = getStyles(colors);
@@ -35,11 +36,11 @@ export const CustomDrawerContent = (props: DrawerContentComponentProps) => {
const { state, navigation } = props;
const { theme: colors } = useTheme();
const styles = getStyles(colors);
+ const dispatch = useAppDispatch();
const handleLogout = async () => {
try {
- await AsyncStorage.removeItem('userToken');
- await AsyncStorage.removeItem('tenancyName');
+ dispatch(logout());
} catch (e) {
console.error(e);
}
diff --git a/app/navigation/drawerStack.tsx b/app/navigation/drawerStack.tsx
index f84729c..134ef5c 100644
--- a/app/navigation/drawerStack.tsx
+++ b/app/navigation/drawerStack.tsx
@@ -29,6 +29,7 @@ const Drawer = createDrawerNavigator();
export const DrawerStack = () => {
const { theme: colors } = useTheme();
+
return (
{
swipeEnabled: false,
headerStyle: {
backgroundColor: colors.header,
- elevation: 0,
- shadowOpacity: 0,
},
headerTitleStyle: {
- fontSize: 16,
+ fontSize: 17,
fontWeight: '700',
color: colors.text,
+ letterSpacing: 0.2,
},
headerTitleAlign: 'center',
headerTintColor: colors.text,
- }}
- >
- {/* Tab Navigator has its own headers per tab, so hide Drawer header for home */}
+ headerShadowVisible: false,
+ }}>
{
backgroundColor: colors.header,
},
headerTitleStyle: {
- fontSize: 16,
+ fontSize: 17,
fontWeight: '700',
color: colors.text,
},
headerTitleAlign: 'center',
headerTintColor: colors.text,
+ headerShadowVisible: false,
}}>
();
export const RootNavigator = () => {
const { token } = useAppSelector((state: RootState) => state.auth);
- console.log('RootNavigator token:', token); // Debugging line to check the token value
const initialRouteName = token ? 'DrawerStack' : 'AuthStack';
return (
diff --git a/app/navigation/tabStack.styles.ts b/app/navigation/tabStack.styles.ts
index 14ee377..7fda12f 100644
--- a/app/navigation/tabStack.styles.ts
+++ b/app/navigation/tabStack.styles.ts
@@ -1,4 +1,4 @@
-import { StyleSheet } from 'react-native';
+import { StyleSheet, Platform } from 'react-native';
import { ThemeColors } from '@theme';
export const getStyles = (colors: ThemeColors) =>
@@ -7,30 +7,45 @@ export const getStyles = (colors: ThemeColors) =>
backgroundColor: colors.tabBar,
borderTopWidth: 1,
borderTopColor: colors.border,
- height: 60,
- paddingBottom: 8,
- paddingTop: 8,
+ height: Platform.OS === 'ios' ? 84 : 64,
+ paddingBottom: Platform.OS === 'ios' ? 24 : 10,
+ // paddingTop: 8,
+ shadowColor: '#5B4CF5',
+ shadowOffset: { width: 0, height: -4 },
+ shadowOpacity: 0.06,
+ shadowRadius: 12,
+ elevation: 8,
},
tabBarLabel: {
- fontSize: 11,
+ fontSize: 12,
fontWeight: '600',
+ letterSpacing: 0.2,
},
header: {
backgroundColor: colors.header,
borderBottomWidth: 1,
borderBottomColor: colors.border,
- elevation: 0,
- shadowOpacity: 0,
+ shadowColor: '#5B4CF5',
+ shadowOffset: { width: 0, height: 2 },
+ shadowOpacity: 0.04,
+ shadowRadius: 6,
+ elevation: 2,
},
headerTitle: {
fontSize: 17,
- fontWeight: '800',
+ fontWeight: '700',
color: colors.text,
+ letterSpacing: 0.2,
},
drawerButton: {
- paddingHorizontal: 16,
- height: '100%',
+ width: 38,
+ height: 38,
+ borderRadius: 12,
justifyContent: 'center',
alignItems: 'center',
+ marginLeft: 14,
+ backgroundColor: colors.surface,
+ borderWidth: 1,
+ borderColor: colors.border,
},
});
diff --git a/app/navigation/tabStack.tsx b/app/navigation/tabStack.tsx
index dc623a9..a8f3ec2 100644
--- a/app/navigation/tabStack.tsx
+++ b/app/navigation/tabStack.tsx
@@ -37,11 +37,11 @@ export const TabStack = () => {
} else if (tabRoute.name === route.addLead) {
iconName = focused ? 'add-circle' : 'add-circle-outline';
} else if (tabRoute.name === route.customers) {
- iconName = focused ? 'business' : 'business-outline';
+ iconName = focused ? 'people' : 'people-outline';
} else if (tabRoute.name === route.profile) {
iconName = focused ? 'person' : 'person-outline';
}
- return ;
+ return ;
},
tabBarActiveTintColor: colors.icon,
tabBarInactiveTintColor: colors.textMuted,
@@ -50,28 +50,26 @@ export const TabStack = () => {
headerStyle: styles.header,
headerTitleStyle: styles.headerTitle,
headerTitleAlign: 'center',
- })}
- >
+ })}>
({
+ tabBarLabel: 'Dashboard',
headerTitle: 'Convex CRM',
headerLeft: () => (
{
- const parentNav =
- navigation.getParent>();
+ const parentNav = navigation.getParent>();
if (parentNav) {
parentNav.openDrawer();
} else {
(navigation as any).openDrawer?.();
}
- }}
- >
-
+ }}>
+
),
})}
@@ -79,11 +77,35 @@ export const TabStack = () => {
+
+
+
-
-
-
);
};
diff --git a/app/services/index.ts b/app/services/index.ts
new file mode 100644
index 0000000..9ea5ce7
--- /dev/null
+++ b/app/services/index.ts
@@ -0,0 +1 @@
+export * from './notifications';
diff --git a/app/services/notifications.ts b/app/services/notifications.ts
new file mode 100644
index 0000000..fd19f65
--- /dev/null
+++ b/app/services/notifications.ts
@@ -0,0 +1,310 @@
+import messaging, {
+ FirebaseMessagingTypes,
+} from '@react-native-firebase/messaging';
+import notifee, {
+ AndroidImportance,
+ AndroidVisibility,
+ AuthorizationStatus,
+ EventType,
+} from '@notifee/react-native';
+import { Platform } from 'react-native';
+
+const CHANNEL_ID = 'convex_crm_default';
+const CHANNEL_NAME = 'Convex CRM Notifications';
+const CHANNEL_DESCRIPTION = 'General push notifications for Convex CRM';
+
+export interface NotificationData {
+ [key: string]: string;
+}
+
+export type MessageHandler = (
+ message: FirebaseMessagingTypes.RemoteMessage,
+) => void;
+
+export type NotificationOpenHandler = (data: NotificationData) => void;
+
+export async function requestPermission(): Promise {
+ try {
+ const settings = await notifee.requestPermission();
+ const granted =
+ settings.authorizationStatus === AuthorizationStatus.AUTHORIZED ||
+ settings.authorizationStatus === AuthorizationStatus.PROVISIONAL;
+ console.log('[NotificationService] Permission granted:', granted);
+ return granted;
+ } catch (error) {
+ console.error('[NotificationService] requestPermission error:', error);
+ return false;
+ }
+}
+
+export async function createDefaultChannel(): Promise {
+ if (Platform.OS !== 'android') {
+ return;
+ }
+ try {
+ await notifee.createChannel({
+ id: CHANNEL_ID,
+ name: CHANNEL_NAME,
+ description: CHANNEL_DESCRIPTION,
+ importance: AndroidImportance.HIGH,
+ visibility: AndroidVisibility.PUBLIC,
+ sound: 'default',
+ vibration: true,
+ vibrationPattern: [300, 500],
+ lights: true,
+ lightColor: '#4F46E5', // indigo accent
+ });
+ console.log('[NotificationService] Default Android channel created:', CHANNEL_ID);
+ } catch (error) {
+ console.error('[NotificationService] createDefaultChannel error:', error);
+ }
+}
+
+export async function getFCMToken(): Promise {
+ try {
+ // Ensure FCM is registered to receive messages
+ if (!messaging().isDeviceRegisteredForRemoteMessages) {
+ await messaging().registerDeviceForRemoteMessages();
+ }
+ const token = await messaging().getToken();
+ console.log('[NotificationService] FCM Token:', token);
+ return token;
+ } catch (error) {
+ console.error('[NotificationService] getFCMToken error:', error);
+ return null;
+ }
+}
+
+/**
+ * Subscribe to token-refresh events.
+ * Call this once; the returned function unsubscribes when invoked.
+ */
+export function onTokenRefresh(
+ callback: (token: string) => void,
+): () => void {
+ const unsubscribe = messaging().onTokenRefresh(newToken => {
+ console.log('[NotificationService] FCM token refreshed:', newToken);
+ callback(newToken);
+ });
+ return unsubscribe;
+}
+
+export async function displayNotification(
+ title: string,
+ body: string,
+ data: NotificationData = {},
+): Promise {
+ try {
+ await notifee.displayNotification({
+ title,
+ body,
+ data,
+ android: {
+ channelId: CHANNEL_ID,
+ importance: AndroidImportance.HIGH,
+ smallIcon: 'ic_notification', // must exist in android/app/src/main/res/drawable
+ pressAction: { id: 'default' },
+ color: '#4F46E5',
+ },
+ ios: {
+ sound: 'default',
+ foregroundPresentationOptions: {
+ alert: true,
+ badge: true,
+ sound: true,
+ },
+ },
+ });
+ } catch (error) {
+ console.error('[NotificationService] displayNotification error:', error);
+ }
+}
+
+export function onForegroundMessage(
+ onOpen?: NotificationOpenHandler,
+): () => void {
+ // FCM foreground listener
+ const unsubscribeFCM = messaging().onMessage(
+ async (remoteMessage: FirebaseMessagingTypes.RemoteMessage) => {
+ console.log('[NotificationService] Foreground FCM message:', remoteMessage);
+
+ const title =
+ remoteMessage.notification?.title ?? 'Convex CRM';
+ const body =
+ remoteMessage.notification?.body ?? 'You have a new notification';
+ const data = (remoteMessage.data ?? {}) as NotificationData;
+
+ await displayNotification(title, body, data);
+ },
+ );
+
+ // Notifee foreground event listener (handles taps on Notifee notifications)
+ const unsubscribeNotifee = notifee.onForegroundEvent(({ type, detail }) => {
+ if (type === EventType.PRESS && detail.notification?.data) {
+ console.log(
+ '[NotificationService] Notifee notification pressed (foreground):',
+ detail.notification.data,
+ );
+ onOpen?.(detail.notification.data as NotificationData);
+ }
+ });
+
+ return () => {
+ unsubscribeFCM();
+ unsubscribeNotifee();
+ };
+}
+
+export function registerBackgroundHandler(): void {
+ messaging().setBackgroundMessageHandler(
+ async (remoteMessage: FirebaseMessagingTypes.RemoteMessage) => {
+ console.log(
+ '[NotificationService] Background FCM message:',
+ remoteMessage,
+ );
+ // FCM data-only messages in the background need manual display
+ if (remoteMessage.data && !remoteMessage.notification) {
+ const title =
+ (remoteMessage.data.title as string) ?? 'Convex CRM';
+ const body =
+ (remoteMessage.data.body as string) ?? 'You have a new notification';
+ await displayNotification(title, body, remoteMessage.data as NotificationData);
+ }
+ },
+ );
+
+ // Notifee background event (handles taps on notifications from background)
+ notifee.onBackgroundEvent(async ({ type, detail }) => {
+ if (type === EventType.PRESS) {
+ console.log(
+ '[NotificationService] Notifee notification pressed (background):',
+ detail.notification?.data,
+ );
+ }
+ if (type === EventType.DISMISSED) {
+ console.log(
+ '[NotificationService] Notification dismissed (background)',
+ );
+ }
+ });
+}
+
+/**
+ * Subscribe to FCM notification taps when the app is in the background
+ * (but not fully quit). Returns an unsubscribe function.
+ */
+export function onNotificationOpenedApp(
+ callback: NotificationOpenHandler,
+): () => void {
+ const unsubscribe = messaging().onNotificationOpenedApp(remoteMessage => {
+ console.log(
+ '[NotificationService] App opened from background notification:',
+ remoteMessage,
+ );
+ callback((remoteMessage.data ?? {}) as NotificationData);
+ });
+ return unsubscribe;
+}
+
+/**
+ * Check whether the app was launched by tapping a notification
+ * while it was fully quit. Call once on app startup.
+ */
+export async function getInitialNotification(
+ callback: NotificationOpenHandler,
+): Promise {
+ try {
+ const remoteMessage = await messaging().getInitialNotification();
+ if (remoteMessage) {
+ console.log(
+ '[NotificationService] App launched from quit-state notification:',
+ remoteMessage,
+ );
+ callback((remoteMessage.data ?? {}) as NotificationData);
+ }
+ } catch (error) {
+ console.error('[NotificationService] getInitialNotification error:', error);
+ }
+}
+
+/**
+ * Set the app icon badge count (iOS only; no-op on Android).
+ */
+export async function setBadgeCount(count: number): Promise {
+ try {
+ await notifee.setBadgeCount(count);
+ } catch (error) {
+ console.error('[NotificationService] setBadgeCount error:', error);
+ }
+}
+
+/**
+ * Clear the app icon badge (iOS only; no-op on Android).
+ */
+export async function clearBadge(): Promise {
+ try {
+ await notifee.setBadgeCount(0);
+ } catch (error) {
+ console.error('[NotificationService] clearBadge error:', error);
+ }
+}
+
+export interface InitializeOptions {
+ onNotificationOpen?: NotificationOpenHandler;
+ onTokenRefreshed?: (token: string) => void;
+}
+
+export async function initialize(
+ options: InitializeOptions = {},
+): Promise<() => void> {
+ const { onNotificationOpen, onTokenRefreshed } = options;
+
+ // 1. Permission
+ await requestPermission();
+
+ // 2. Android channel
+ await createDefaultChannel();
+
+ // 3. FCM token
+ await getFCMToken();
+
+ // 4. Token refresh
+ const unsubscribeTokenRefresh = onTokenRefresh(token => {
+ onTokenRefreshed?.(token);
+ });
+
+ // 5. Foreground messages
+ const unsubscribeForeground = onForegroundMessage(onNotificationOpen);
+
+ // 6. Background tap
+ const unsubscribeBackgroundOpen = onNotificationOpenedApp(data => {
+ onNotificationOpen?.(data);
+ });
+
+ // 7. Quit-state launch
+ await getInitialNotification(data => {
+ onNotificationOpen?.(data);
+ });
+
+ // Return aggregate cleanup
+ return () => {
+ unsubscribeTokenRefresh();
+ unsubscribeForeground();
+ unsubscribeBackgroundOpen();
+ };
+}
+
+export const NotificationService = {
+ requestPermission,
+ createDefaultChannel,
+ getFCMToken,
+ onTokenRefresh,
+ displayNotification,
+ onForegroundMessage,
+ registerBackgroundHandler,
+ onNotificationOpenedApp,
+ getInitialNotification,
+ setBadgeCount,
+ clearBadge,
+ initialize,
+};
diff --git a/app/store/commonReducers/auth/reducers.ts b/app/store/commonReducers/auth/reducers.ts
index 96a3dc0..2b6bc86 100644
--- a/app/store/commonReducers/auth/reducers.ts
+++ b/app/store/commonReducers/auth/reducers.ts
@@ -24,7 +24,7 @@ const initialState: LoginState = {
loginMessage: null,
};
-export const reducers = createReducer(initialState, builder => {
+export const authReducer = createReducer(initialState, builder => {
builder
.addCase(login.pending, acc => {
acc.loginLoading = true;
@@ -49,4 +49,4 @@ export const reducers = createReducer(initialState, builder => {
});
});
-export default reducers;
+export default authReducer;
diff --git a/app/store/commonReducers/auth/thunk.ts b/app/store/commonReducers/auth/thunk.ts
index 24f5f88..89b6e7e 100644
--- a/app/store/commonReducers/auth/thunk.ts
+++ b/app/store/commonReducers/auth/thunk.ts
@@ -1,4 +1,4 @@
-import { createAsyncThunk } from '@reduxjs/toolkit';
+import { createAction, createAsyncThunk } from '@reduxjs/toolkit';
import { LoginRequest, LoginResponse } from '@interfaces';
import { loginApi } from '@api';
@@ -12,3 +12,5 @@ export const login = createAsyncThunk(
}
},
);
+
+export const logout = createAction('USER_LOGOUT');
diff --git a/app/store/commonReducers/countrylist/index.ts b/app/store/commonReducers/countrylist/index.ts
new file mode 100644
index 0000000..40a5b4c
--- /dev/null
+++ b/app/store/commonReducers/countrylist/index.ts
@@ -0,0 +1,2 @@
+export * from './thunk';
+export * from './reducers';
diff --git a/app/store/commonReducers/countrylist/reducers.ts b/app/store/commonReducers/countrylist/reducers.ts
new file mode 100644
index 0000000..502145b
--- /dev/null
+++ b/app/store/commonReducers/countrylist/reducers.ts
@@ -0,0 +1,37 @@
+import { createReducer } from '@reduxjs/toolkit';
+import { getCountryList } from './thunk';
+import { CountryListItem } from '@interfaces';
+
+export interface CountryListState {
+ items: CountryListItem[];
+ loading: boolean;
+ error: string | null;
+}
+
+const initialState: CountryListState = {
+ items: [],
+ loading: false,
+ error: null,
+};
+
+export const countryListReducer = createReducer(initialState, builder => {
+ builder
+ .addCase(getCountryList.pending, acc => {
+ acc.loading = true;
+ acc.error = null;
+ })
+ .addCase(getCountryList.fulfilled, (acc, action) => {
+ acc.loading = false;
+ acc.items = action.payload;
+ acc.error = null;
+ })
+ .addCase(getCountryList.rejected, (acc, action) => {
+ acc.loading = false;
+ acc.error =
+ (action.payload as string) ??
+ action.error.message ??
+ 'Failed to fetch country list';
+ });
+});
+
+export default countryListReducer;
diff --git a/app/store/commonReducers/countrylist/thunk.ts b/app/store/commonReducers/countrylist/thunk.ts
new file mode 100644
index 0000000..5526817
--- /dev/null
+++ b/app/store/commonReducers/countrylist/thunk.ts
@@ -0,0 +1,14 @@
+import { createAsyncThunk } from '@reduxjs/toolkit';
+import { getCountryListApi } from '@api';
+import { CountryListItem } from '@interfaces';
+
+export const getCountryList = createAsyncThunk(
+ 'countrylist/getCountryList',
+ async (_, { rejectWithValue }) => {
+ try {
+ return await getCountryListApi();
+ } catch (error: any) {
+ return rejectWithValue(error.message || 'Failed to fetch country list');
+ }
+ },
+);
diff --git a/app/store/commonReducers/index.ts b/app/store/commonReducers/index.ts
index 269586e..badd083 100644
--- a/app/store/commonReducers/index.ts
+++ b/app/store/commonReducers/index.ts
@@ -1 +1,4 @@
export * from './auth';
+export * from './statuslist';
+export * from './sourcelist';
+export * from './countrylist';
diff --git a/app/store/commonReducers/sourcelist/index.ts b/app/store/commonReducers/sourcelist/index.ts
new file mode 100644
index 0000000..40a5b4c
--- /dev/null
+++ b/app/store/commonReducers/sourcelist/index.ts
@@ -0,0 +1,2 @@
+export * from './thunk';
+export * from './reducers';
diff --git a/app/store/commonReducers/sourcelist/reducers.ts b/app/store/commonReducers/sourcelist/reducers.ts
new file mode 100644
index 0000000..1e09d61
--- /dev/null
+++ b/app/store/commonReducers/sourcelist/reducers.ts
@@ -0,0 +1,37 @@
+import { createReducer } from '@reduxjs/toolkit';
+import { getSourceList } from './thunk';
+import { SourceListItem } from '@interfaces';
+
+export interface SourceListState {
+ items: SourceListItem[];
+ loading: boolean;
+ error: string | null;
+}
+
+const initialState: SourceListState = {
+ items: [],
+ loading: false,
+ error: null,
+};
+
+export const sourceListReducer = createReducer(initialState, builder => {
+ builder
+ .addCase(getSourceList.pending, acc => {
+ acc.loading = true;
+ acc.error = null;
+ })
+ .addCase(getSourceList.fulfilled, (acc, action) => {
+ acc.loading = false;
+ acc.items = action.payload;
+ acc.error = null;
+ })
+ .addCase(getSourceList.rejected, (acc, action) => {
+ acc.loading = false;
+ acc.error =
+ (action.payload as string) ??
+ action.error.message ??
+ 'Failed to fetch source list';
+ });
+});
+
+export default sourceListReducer;
diff --git a/app/store/commonReducers/sourcelist/thunk.ts b/app/store/commonReducers/sourcelist/thunk.ts
new file mode 100644
index 0000000..06af097
--- /dev/null
+++ b/app/store/commonReducers/sourcelist/thunk.ts
@@ -0,0 +1,14 @@
+import { createAsyncThunk } from '@reduxjs/toolkit';
+import { getSourceListApi } from '@api';
+import { SourceListItem } from '@interfaces';
+
+export const getSourceList = createAsyncThunk(
+ 'sourcelist/getSourceList',
+ async (_, { rejectWithValue }) => {
+ try {
+ return await getSourceListApi();
+ } catch (error: any) {
+ return rejectWithValue(error.message || 'Failed to fetch source list');
+ }
+ },
+);
diff --git a/app/store/commonReducers/statuslist/index.ts b/app/store/commonReducers/statuslist/index.ts
new file mode 100644
index 0000000..40a5b4c
--- /dev/null
+++ b/app/store/commonReducers/statuslist/index.ts
@@ -0,0 +1,2 @@
+export * from './thunk';
+export * from './reducers';
diff --git a/app/store/commonReducers/statuslist/reducers.ts b/app/store/commonReducers/statuslist/reducers.ts
new file mode 100644
index 0000000..8857243
--- /dev/null
+++ b/app/store/commonReducers/statuslist/reducers.ts
@@ -0,0 +1,37 @@
+import { createReducer } from '@reduxjs/toolkit';
+import { getStatusList } from './thunk';
+import { StatusListItem } from '@interfaces';
+
+export interface StatusListState {
+ items: StatusListItem[];
+ loading: boolean;
+ error: string | null;
+}
+
+const initialState: StatusListState = {
+ items: [],
+ loading: false,
+ error: null,
+};
+
+export const statusListReducer = createReducer(initialState, builder => {
+ builder
+ .addCase(getStatusList.pending, acc => {
+ acc.loading = true;
+ acc.error = null;
+ })
+ .addCase(getStatusList.fulfilled, (acc, action) => {
+ acc.loading = false;
+ acc.items = action.payload;
+ acc.error = null;
+ })
+ .addCase(getStatusList.rejected, (acc, action) => {
+ acc.loading = false;
+ acc.error =
+ (action.payload as string) ??
+ action.error.message ??
+ 'Failed to fetch status list';
+ });
+});
+
+export default statusListReducer;
diff --git a/app/store/commonReducers/statuslist/thunk.ts b/app/store/commonReducers/statuslist/thunk.ts
new file mode 100644
index 0000000..41502a5
--- /dev/null
+++ b/app/store/commonReducers/statuslist/thunk.ts
@@ -0,0 +1,14 @@
+import { createAsyncThunk } from '@reduxjs/toolkit';
+import { getStatusListApi } from '@api';
+import { StatusListItem } from '@interfaces';
+
+export const getStatusList = createAsyncThunk(
+ 'statuslist/getStatusList',
+ async (_, { rejectWithValue }) => {
+ try {
+ return await getStatusListApi();
+ } catch (error: any) {
+ return rejectWithValue(error.message || 'Failed to fetch status list');
+ }
+ },
+);
diff --git a/app/store/rootReducer.ts b/app/store/rootReducer.ts
index 34e510f..61b77c6 100644
--- a/app/store/rootReducer.ts
+++ b/app/store/rootReducer.ts
@@ -1,13 +1,26 @@
import { combineReducers } from '@reduxjs/toolkit';
import authReducer from './commonReducers/auth/reducers';
+import statusListReducer from './commonReducers/statuslist/reducers';
+import sourceListReducer from './commonReducers/sourcelist/reducers';
+import countryListReducer from './commonReducers/countrylist/reducers';
import leadsReducer from '../features/leads/reducers';
import leadDetailsReducer from '../features/leadDetails/reducers';
-const rootReducer = combineReducers({
+const appReducer = combineReducers({
auth: authReducer,
+ statusList: statusListReducer,
+ sourceList: sourceListReducer,
+ countryList: countryListReducer,
leads: leadsReducer,
leadDetails: leadDetailsReducer,
});
-export type RootState = ReturnType;
+const rootReducer = (state: any, action: any) => {
+ if (action.type === 'USER_LOGOUT') {
+ state = undefined;
+ }
+ return appReducer(state, action);
+};
+
+export type RootState = ReturnType;
export default rootReducer;
diff --git a/app/theme/colors.ts b/app/theme/colors.ts
index 4e502d8..8b9e738 100644
--- a/app/theme/colors.ts
+++ b/app/theme/colors.ts
@@ -1,39 +1,44 @@
-// Palette derived from the app background (blue/navy/cyan)
+// ─────────────────────────────────────────────────────────────────────────────
+// Design System Palette — Modern CRM (Indigo-Violet base)
+// Light: Clean whites with indigo accents, warm card surfaces
+// Dark: Rich deep slate/charcoal with electric indigo/violet accents
+// ─────────────────────────────────────────────────────────────────────────────
export const colors = {
- // Brand
- primary: '#1565C0', // deep blue (dark bg accent / light primary)
- primaryLight: '#1E90FF', // bright sky blue
- accent: '#4FC3F7', // cyan highlight
+ // ── Brand tokens ────────────────────────────────────────────────────────────
+ primary: '#5B4CF5', // electric indigo — primary actions
+ primaryLight: '#7C6FF7', // lighter indigo for hover / tint
+ accent: '#8B5CF6', // violet — gradient end, highlights
+ accentAlt: '#06B6D4', // cyan — contrast accent (badges, chips)
- // Light theme
+ // ── Light theme ─────────────────────────────────────────────────────────────
light: {
- background: '#F0F6FF',
- surface: '#FFFFFF',
- border: '#BBDEFB',
- text: '#0A1A6B',
- textSecondary: '#1E3A8A',
- textMuted: '#5C7BA8',
- icon: '#1565C0',
+ background: '#F4F6FB', // soft cool white-grey — avoids pure white glare
+ surface: '#FFFFFF', // pure white surfaces (search, buttons)
+ card: '#FFFFFF', // card bg — clean white with shadow
+ border: '#E4E8F5', // subtle lavender-grey border
+ text: '#1A1D3A', // near-black with slight blue tint — excellent contrast
+ textSecondary: '#4B5280', // medium slate — readable secondary text
+ textMuted: '#9399BB', // muted lavender — placeholders, dates
+ icon: '#5B4CF5', // brand indigo icons
tabBar: '#FFFFFF',
header: '#FFFFFF',
drawerBg: '#FFFFFF',
- drawerHeader: '#0A237A',
- card: '#FFFFFF',
+ drawerHeader: '#1A1D3A',
},
- // Dark theme
+ // ── Dark theme ──────────────────────────────────────────────────────────────
dark: {
- background: '#07112A',
- surface: '#0D1F4A',
- border: '#1A3575',
- text: '#E3F0FF',
- textSecondary: '#A8C8F5',
- textMuted: '#5C7BA8',
- icon: '#4FC3F7',
- tabBar: '#0D1F4A',
- header: '#0D1F4A',
- drawerBg: '#0A1A6B',
- drawerHeader: '#07112A',
- card: '#0D1F4A',
+ background: '#0F1022', // very deep blue-black — premium feel
+ surface: '#1A1D3A', // dark navy-indigo — elevated surfaces
+ card: '#1E2140', // slightly lighter than surface for cards
+ border: '#2D3260', // muted indigo border — visible but subtle
+ text: '#EEF0FF', // near-white with slight violet tint
+ textSecondary: '#A5AACF', // soft lavender — readable secondary
+ textMuted: '#5C6290', // deep muted indigo — placeholders, dates
+ icon: '#7C6FF7', // light indigo icons
+ tabBar: '#1A1D3A',
+ header: '#1A1D3A',
+ drawerBg: '#141630',
+ drawerHeader: '#0F1022',
},
} as const;
diff --git a/app/utils/assets/index.ts b/app/utils/assets/index.ts
index 94b51e5..8067875 100644
--- a/app/utils/assets/index.ts
+++ b/app/utils/assets/index.ts
@@ -1,2 +1,3 @@
export const backGroundImage = require('./background.png')
+export const logo = require('./logo.png')
diff --git a/app/utils/assets/logo.png b/app/utils/assets/logo.png
new file mode 100644
index 0000000..6992c1d
Binary files /dev/null and b/app/utils/assets/logo.png differ
diff --git a/app/utils/helper.ts b/app/utils/helper.ts
index 19bc377..c6a1684 100644
--- a/app/utils/helper.ts
+++ b/app/utils/helper.ts
@@ -51,3 +51,19 @@ export const getInitials = (name?: string | null): string => {
return name.substring(0, 2).toUpperCase();
};
+
+export const toRgba = (hex: string, alpha: number): string => {
+ const h = hex.replace('#', '');
+ const r = parseInt(h.slice(0, 2), 16);
+ const g = parseInt(h.slice(2, 4), 16);
+ const b = parseInt(h.slice(4, 6), 16);
+ return `rgba(${r},${g},${b},${alpha})`;
+};
+
+export const formatDate = (raw: string): string => {
+ if (!raw) return '';
+ const d = new Date(raw);
+ return isNaN(d.getTime())
+ ? raw
+ : d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
+};
diff --git a/assets/bootsplash/logo.png b/assets/bootsplash/logo.png
new file mode 100644
index 0000000..0496418
Binary files /dev/null and b/assets/bootsplash/logo.png differ
diff --git a/assets/bootsplash/logo@1,5x.png b/assets/bootsplash/logo@1,5x.png
new file mode 100644
index 0000000..460e2ee
Binary files /dev/null and b/assets/bootsplash/logo@1,5x.png differ
diff --git a/assets/bootsplash/logo@2x.png b/assets/bootsplash/logo@2x.png
new file mode 100644
index 0000000..cde3fef
Binary files /dev/null and b/assets/bootsplash/logo@2x.png differ
diff --git a/assets/bootsplash/logo@3x.png b/assets/bootsplash/logo@3x.png
new file mode 100644
index 0000000..c1a644a
Binary files /dev/null and b/assets/bootsplash/logo@3x.png differ
diff --git a/assets/bootsplash/logo@4x.png b/assets/bootsplash/logo@4x.png
new file mode 100644
index 0000000..b3e4adb
Binary files /dev/null and b/assets/bootsplash/logo@4x.png differ
diff --git a/assets/bootsplash/manifest.json b/assets/bootsplash/manifest.json
new file mode 100644
index 0000000..db974f3
--- /dev/null
+++ b/assets/bootsplash/manifest.json
@@ -0,0 +1,7 @@
+{
+ "background": "#ffffff",
+ "logo": {
+ "width": 100,
+ "height": 100
+ }
+}
diff --git a/assets/logo.png b/assets/logo.png
new file mode 100644
index 0000000..6992c1d
Binary files /dev/null and b/assets/logo.png differ
diff --git a/index.js b/index.js
index 06002ff..3619874 100644
--- a/index.js
+++ b/index.js
@@ -1,9 +1,12 @@
import { AppRegistry } from 'react-native';
import App from './app/App';
import { name as appName } from './app.json';
+import { NotificationService } from '@services';
if (__DEV__) {
require('./ReactotronConfig');
}
+NotificationService.registerBackgroundHandler();
+
AppRegistry.registerComponent(appName, () => App);
diff --git a/ios/convex_CRM.xcodeproj/project.pbxproj b/ios/convex_CRM.xcodeproj/project.pbxproj
index 97aa070..e95405c 100644
--- a/ios/convex_CRM.xcodeproj/project.pbxproj
+++ b/ios/convex_CRM.xcodeproj/project.pbxproj
@@ -11,6 +11,8 @@
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
+ 79E049D907A74F1AB0714099 /* BootSplash.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 688D1DB853AD445C91817BC9 /* BootSplash.storyboard */; };
+ 1E6477E483F84C6495D52EC7 /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A57FEAAA1E5B410F8EEA9BA8 /* Colors.xcassets */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -24,6 +26,8 @@
761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = convex_CRM/AppDelegate.swift; sourceTree = ""; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = convex_CRM/LaunchScreen.storyboard; sourceTree = ""; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
+ 688D1DB853AD445C91817BC9 /* BootSplash.storyboard */ = {isa = PBXFileReference; name = "BootSplash.storyboard"; path = "convex_CRM/BootSplash.storyboard"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
+ A57FEAAA1E5B410F8EEA9BA8 /* Colors.xcassets */ = {isa = PBXFileReference; name = "Colors.xcassets"; path = "convex_CRM/Colors.xcassets"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = folder.assetcatalog; explicitFileType = undefined; includeInIndex = 0; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -46,6 +50,8 @@
13B07FB61A68108700A75B9A /* Info.plist */,
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,
13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */,
+ 688D1DB853AD445C91817BC9 /* BootSplash.storyboard */,
+ A57FEAAA1E5B410F8EEA9BA8 /* Colors.xcassets */,
);
name = convex_CRM;
sourceTree = "";
@@ -159,6 +165,8 @@
files = (
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
+ 79E049D907A74F1AB0714099 /* BootSplash.storyboard in Resources */,
+ 1E6477E483F84C6495D52EC7 /* Colors.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/ios/convex_CRM/BootSplash.storyboard b/ios/convex_CRM/BootSplash.storyboard
new file mode 100644
index 0000000..fb5bc6d
--- /dev/null
+++ b/ios/convex_CRM/BootSplash.storyboard
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/convex_CRM/Colors.xcassets/BootSplashBackground-15a9bf.colorset/Contents.json b/ios/convex_CRM/Colors.xcassets/BootSplashBackground-15a9bf.colorset/Contents.json
new file mode 100644
index 0000000..f13e571
--- /dev/null
+++ b/ios/convex_CRM/Colors.xcassets/BootSplashBackground-15a9bf.colorset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "colors": [
+ {
+ "idiom": "universal",
+ "color": {
+ "color-space": "srgb",
+ "components": {
+ "blue": "1.00000000000000",
+ "green": "1.00000000000000",
+ "red": "1.00000000000000",
+ "alpha": "1.000"
+ }
+ }
+ }
+ ],
+ "info": {
+ "author": "xcode",
+ "version": 1
+ }
+}
diff --git a/ios/convex_CRM/Images.xcassets/BootSplashLogo-15a9bf.imageset/Contents.json b/ios/convex_CRM/Images.xcassets/BootSplashLogo-15a9bf.imageset/Contents.json
new file mode 100644
index 0000000..24e6206
--- /dev/null
+++ b/ios/convex_CRM/Images.xcassets/BootSplashLogo-15a9bf.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images": [
+ {
+ "idiom": "universal",
+ "filename": "logo-15a9bf.png",
+ "scale": "1x"
+ },
+ {
+ "idiom": "universal",
+ "filename": "logo-15a9bf@2x.png",
+ "scale": "2x"
+ },
+ {
+ "idiom": "universal",
+ "filename": "logo-15a9bf@3x.png",
+ "scale": "3x"
+ }
+ ],
+ "info": {
+ "author": "xcode",
+ "version": 1
+ }
+}
diff --git a/ios/convex_CRM/Images.xcassets/BootSplashLogo-15a9bf.imageset/logo-15a9bf.png b/ios/convex_CRM/Images.xcassets/BootSplashLogo-15a9bf.imageset/logo-15a9bf.png
new file mode 100644
index 0000000..0496418
Binary files /dev/null and b/ios/convex_CRM/Images.xcassets/BootSplashLogo-15a9bf.imageset/logo-15a9bf.png differ
diff --git a/ios/convex_CRM/Images.xcassets/BootSplashLogo-15a9bf.imageset/logo-15a9bf@2x.png b/ios/convex_CRM/Images.xcassets/BootSplashLogo-15a9bf.imageset/logo-15a9bf@2x.png
new file mode 100644
index 0000000..cde3fef
Binary files /dev/null and b/ios/convex_CRM/Images.xcassets/BootSplashLogo-15a9bf.imageset/logo-15a9bf@2x.png differ
diff --git a/ios/convex_CRM/Images.xcassets/BootSplashLogo-15a9bf.imageset/logo-15a9bf@3x.png b/ios/convex_CRM/Images.xcassets/BootSplashLogo-15a9bf.imageset/logo-15a9bf@3x.png
new file mode 100644
index 0000000..c1a644a
Binary files /dev/null and b/ios/convex_CRM/Images.xcassets/BootSplashLogo-15a9bf.imageset/logo-15a9bf@3x.png differ
diff --git a/ios/convex_CRM/Info.plist b/ios/convex_CRM/Info.plist
index 7aa4fe5..8ec5dc3 100644
--- a/ios/convex_CRM/Info.plist
+++ b/ios/convex_CRM/Info.plist
@@ -28,7 +28,6 @@
NSAppTransportSecurity
-
NSAllowsArbitraryLoads
NSAllowsLocalNetworking
@@ -37,7 +36,7 @@
NSLocationWhenInUseUsageDescription
UILaunchStoryboardName
- LaunchScreen
+ BootSplash
UIRequiredDeviceCapabilities
arm64
diff --git a/package.json b/package.json
index bbbb537..d8f420e 100644
--- a/package.json
+++ b/package.json
@@ -10,7 +10,10 @@
"test": "jest"
},
"dependencies": {
+ "@notifee/react-native": "^9.1.8",
"@react-native-async-storage/async-storage": "^3.1.1",
+ "@react-native-firebase/app": "^25.1.0",
+ "@react-native-firebase/messaging": "^25.1.0",
"@react-navigation/bottom-tabs": "^7.18.8",
"@react-navigation/drawer": "^7.12.8",
"@react-navigation/native": "^7.3.8",
@@ -20,6 +23,7 @@
"axios": "^1.18.1",
"react": "19.2.3",
"react-native": "0.86.0",
+ "react-native-bootsplash": "^7.3.2",
"react-native-config": "^1.6.1",
"react-native-gesture-handler": "^2.32.0",
"react-native-reanimated": "^4.5.0",
diff --git a/yarn.lock b/yarn.lock
index 8852342..6fd09c9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,7 +2,7 @@
# yarn lockfile v1
-"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.29.0", "@babel/code-frame@^7.29.7":
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.20.0", "@babel/code-frame@^7.29.0", "@babel/code-frame@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.29.7.tgz#f2fbbfea87c44a21590ec515b778b2c26d8866e7"
integrity sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==
@@ -1033,6 +1033,13 @@
dependencies:
"@types/hammerjs" "^2.0.36"
+"@emnapi/runtime@^1.11.1":
+ version "1.11.2"
+ resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.11.2.tgz#eb22f04d76febfdf4f87fdaff54c8a53f6bf0dbd"
+ integrity sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==
+ dependencies:
+ tslib "^2.4.0"
+
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.9.1":
version "4.9.1"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz#4e90af67bc51ddee6cdef5284edf572ec376b595"
@@ -1065,6 +1072,473 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2"
integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==
+"@expo/config-plugins@*":
+ version "57.0.5"
+ resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-57.0.5.tgz#6bbaeaef5d60218bee7afa9d05cc9427d29dfe8c"
+ integrity sha512-xhUGgzpFWRghDUH98+Wl4RDakYhTsbyMg6aOYiBjRzPO/THH8tKMw3vlksgFYlU2PkiAdABJN3tNPf5qmvOQhA==
+ dependencies:
+ "@expo/config-types" "^57.0.2"
+ "@expo/json-file" "~11.0.1"
+ "@expo/plist" "^0.8.1"
+ "@expo/require-utils" "^57.0.3"
+ "@expo/sdk-runtime-versions" "^1.0.0"
+ chalk "^4.1.2"
+ debug "^4.3.5"
+ getenv "^2.0.0"
+ glob "^13.0.0"
+ semver "^7.5.4"
+ slugify "^1.6.6"
+ xcode "^3.0.1"
+ xml2js "0.6.0"
+
+"@expo/config-types@^57.0.2":
+ version "57.0.2"
+ resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-57.0.2.tgz#127da99326399e014b63cf23d71220719f1336a1"
+ integrity sha512-ewW08OonrcRIsRKIlFvvcmmafE5zemb1ocu3HkNwtVPyRtj2w42pZCAkMIROYpcVBaPnc3mDT9UZDzwXWC3i6g==
+
+"@expo/json-file@~11.0.1":
+ version "11.0.1"
+ resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-11.0.1.tgz#dab8f6e5ff78e7c33a8e49a48722ce972306036c"
+ integrity sha512-zxHWj4MKKMAL29ZQSY/Fssx4Thluk40JmuGNaeS078wy/NhlFhnVi+rHHunulE3xJAJ0CM73m8VK2+GkF9eRwQ==
+ dependencies:
+ "@babel/code-frame" "^7.20.0"
+ json5 "^2.2.3"
+
+"@expo/plist@^0.8.1":
+ version "0.8.1"
+ resolved "https://registry.yarnpkg.com/@expo/plist/-/plist-0.8.1.tgz#8f024f23d7b9cf45cfff4a6f8871d1c107a8833c"
+ integrity sha512-3gTReGIUm0oRaMClsAJYxBnVPCl6fVpsl8HS+DTVxDhW4GyVyxg9E/Znm3BvcHtUJ51RJJI14pC1wvrNilCRHw==
+ dependencies:
+ "@xmldom/xmldom" "^0.8.8"
+ base64-js "^1.5.1"
+ xmlbuilder "^15.1.1"
+
+"@expo/require-utils@^57.0.3":
+ version "57.0.3"
+ resolved "https://registry.yarnpkg.com/@expo/require-utils/-/require-utils-57.0.3.tgz#b2bcac04f0f227aad8412ac3a78a6a3b5c26093f"
+ integrity sha512-ns05X1K8tM+Qtzp6dNloUFOopSdh3J+HC61BtOR8WHhgtPFyX8TKuO2diqZUqVg9K8yfkWug7g8tBS0qRniSTA==
+ dependencies:
+ "@babel/code-frame" "^7.20.0"
+ "@babel/core" "^7.25.2"
+ "@babel/plugin-transform-modules-commonjs" "^7.24.8"
+
+"@expo/sdk-runtime-versions@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@expo/sdk-runtime-versions/-/sdk-runtime-versions-1.0.0.tgz#d7ebd21b19f1c6b0395e50d78da4416941c57f7c"
+ integrity sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ==
+
+"@firebase/ai@2.13.1":
+ version "2.13.1"
+ resolved "https://registry.yarnpkg.com/@firebase/ai/-/ai-2.13.1.tgz#15dc946a793bc8ea35e1aba03ec3cf50c9443ba9"
+ integrity sha512-RhT/VViTPBSplhQSuEp62HhLvfsV+LowMh8ZUo5MMRDzG7oFtSget4Kmg5oHP50hDVyWQuQj6to9iPFEZk08Tw==
+ dependencies:
+ "@firebase/app-check-interop-types" "0.3.4"
+ "@firebase/component" "0.7.3"
+ "@firebase/logger" "0.5.1"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/analytics-compat@0.2.28":
+ version "0.2.28"
+ resolved "https://registry.yarnpkg.com/@firebase/analytics-compat/-/analytics-compat-0.2.28.tgz#fb8f18e40a019dd9ea005859fe71ccf3d0867ee9"
+ integrity sha512-lIAlqUUbBu93FJMlQfslryQtBwwzdzvp23ePC6FNgymXk6Ook5v4Uvc0vdutvoIeqmyA3LfP0ZeRFK8+11kOOQ==
+ dependencies:
+ "@firebase/analytics" "0.10.22"
+ "@firebase/analytics-types" "0.8.4"
+ "@firebase/component" "0.7.3"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/analytics-types@0.8.4":
+ version "0.8.4"
+ resolved "https://registry.yarnpkg.com/@firebase/analytics-types/-/analytics-types-0.8.4.tgz#194ee289e7293e47b1bd6221147f0dcc02f92e3d"
+ integrity sha512-zQ+XTgkwH6CY/eUSHJRP7e4LxM30RCxlCmob5sy2axs25GE3Ny0XdgpDscMTHHQIGqWkxPXad4w2Mw9sCgT8zQ==
+
+"@firebase/analytics@0.10.22":
+ version "0.10.22"
+ resolved "https://registry.yarnpkg.com/@firebase/analytics/-/analytics-0.10.22.tgz#20f3a6431ed51c4590cf898455de7fd40b2163f0"
+ integrity sha512-8BSaq/QRGU1+xyi8L2PTLTJU7MH9aMA72RQdIxrbhWFauOZY9OXo8f2YDN/972xA8d588tlnNVEQ2Mo69pT9Ow==
+ dependencies:
+ "@firebase/component" "0.7.3"
+ "@firebase/installations" "0.6.22"
+ "@firebase/logger" "0.5.1"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/app-check-compat@0.4.5":
+ version "0.4.5"
+ resolved "https://registry.yarnpkg.com/@firebase/app-check-compat/-/app-check-compat-0.4.5.tgz#f136a07e5bcdef81aaad1b82b49557d5d1329ee8"
+ integrity sha512-JI17mVcZs34zO6ZeSCrw4U2iohqy+n6GIzkbmsA+TbVjmvFLkUKt3bs5M+qRBteQm/0IWzqSHYFzEQLzDTQebg==
+ dependencies:
+ "@firebase/app-check" "0.12.0"
+ "@firebase/app-check-types" "0.5.4"
+ "@firebase/component" "0.7.3"
+ "@firebase/logger" "0.5.1"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/app-check-interop-types@0.3.4":
+ version "0.3.4"
+ resolved "https://registry.yarnpkg.com/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.4.tgz#747bf9fe8e9db11f6a44b695f20754f2a20208a4"
+ integrity sha512-zz3i6e13B8BfWiLy8MABtTh8aGIACgKbf9UVnyHcWs+yQzJXgQcl8A46b0zfaiJHdQ+niF0ouAfcpuf+3LMPQg==
+
+"@firebase/app-check-types@0.5.4":
+ version "0.5.4"
+ resolved "https://registry.yarnpkg.com/@firebase/app-check-types/-/app-check-types-0.5.4.tgz#8001732e81332dd77d898d82fe773761cf2f023b"
+ integrity sha512-xV7JsIyzVr15aA7f3Pi0rB9gdBuVubs89FGA8VkRYA4g0l78poADgdfrScgf7NndSg9mm7cR7PJyY0+t22KaGw==
+
+"@firebase/app-check@0.12.0":
+ version "0.12.0"
+ resolved "https://registry.yarnpkg.com/@firebase/app-check/-/app-check-0.12.0.tgz#8fb9bdfa426b110169efc7446f84a9c54ef5bdd0"
+ integrity sha512-wMeT6HLWRAuW7Cp/5UjWBGKgjPNxWNOoNf4PRIv0weljoGMZVeqbUY7wNBWTI2/31cX1NlXx8gQruDLsUShB3Q==
+ dependencies:
+ "@firebase/component" "0.7.3"
+ "@firebase/logger" "0.5.1"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/app-compat@0.5.14":
+ version "0.5.14"
+ resolved "https://registry.yarnpkg.com/@firebase/app-compat/-/app-compat-0.5.14.tgz#8645e416e74aa8c559cff4c699bd37c1280b539e"
+ integrity sha512-rgFmiofYsdS9ZG/Bht3OBxJtPD3zWE1cffShWubEm+4+qZeyzCbmtb1q6jOEjN9fB7uufe4rQmWOPXouR3758Q==
+ dependencies:
+ "@firebase/app" "0.15.0"
+ "@firebase/component" "0.7.3"
+ "@firebase/logger" "0.5.1"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/app-types@0.9.5":
+ version "0.9.5"
+ resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.9.5.tgz#4c59391fd2559530d709a614d49f62af4ad8766b"
+ integrity sha512-YevqTjvo7Iujsa9Dwowmd6dSoElhzmD63ZSrq6bzjvQ6POjYgNjOFHLmNIgJs48eNO093NCERibuFnxbfOvU7A==
+ dependencies:
+ "@firebase/logger" "0.5.1"
+
+"@firebase/app@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.15.0.tgz#5fbb1ed3e0f9d29f678b06ac12e3c1d5baff119b"
+ integrity sha512-soIskolmGgbpi0K/MfrjtdpO1220qRCbXA4Z8Qx3lM+fVwA3q40m+OM+7zBHd2nuQCrLXb33L6Oc1aBH3Y26AQ==
+ dependencies:
+ "@firebase/component" "0.7.3"
+ "@firebase/logger" "0.5.1"
+ "@firebase/util" "1.15.1"
+ idb "7.1.1"
+ tslib "^2.1.0"
+
+"@firebase/auth-compat@0.6.8":
+ version "0.6.8"
+ resolved "https://registry.yarnpkg.com/@firebase/auth-compat/-/auth-compat-0.6.8.tgz#09d828421a9ec1edcde60cd86785a29cad9b5720"
+ integrity sha512-llcBREUC4iSNKZ6rvwud7Oz9Q7aAWU6KuQLa6pdu7Q+QAQsy4JLw6yFgxwtmzabsgznHmmcsX2UjHLLzqUxi3Q==
+ dependencies:
+ "@firebase/auth" "1.13.3"
+ "@firebase/auth-types" "0.13.1"
+ "@firebase/component" "0.7.3"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/auth-interop-types@0.2.5":
+ version "0.2.5"
+ resolved "https://registry.yarnpkg.com/@firebase/auth-interop-types/-/auth-interop-types-0.2.5.tgz#828e2e160cff40fa78ecb4b6e3187c88158eb2e9"
+ integrity sha512-1Li/YuBDBAXcKv7BzY4U28gontUmAaw53sYiqbaVOMCFb2lFKK/c3CGMUWqtwe7+TXrl3poWnTCL5umYBg85Eg==
+
+"@firebase/auth-types@0.13.1":
+ version "0.13.1"
+ resolved "https://registry.yarnpkg.com/@firebase/auth-types/-/auth-types-0.13.1.tgz#eb5abafdaa40dd3b6badfab111dd94f7e196ea66"
+ integrity sha512-0c1Mnid0uMDfGJHeUS4zfvBa4/CedJXotGy/n/NZJnBjwiJawt0ZYU+wH2VAVLiRCEfG2ncCkAX3yd1/2nrB7g==
+
+"@firebase/auth@1.13.3":
+ version "1.13.3"
+ resolved "https://registry.yarnpkg.com/@firebase/auth/-/auth-1.13.3.tgz#5cad74ce656c9b4f8ffb2a026fab98d4b40c4a96"
+ integrity sha512-bqiq4uubDN2YyQkdvSWPQeJyXAv2O76ImF41En9b6UhV5JuBVYDoHYrrrE3NzIuGkpFMKagfhMRP4Vz6t+yQSQ==
+ dependencies:
+ "@firebase/component" "0.7.3"
+ "@firebase/logger" "0.5.1"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/component@0.7.3":
+ version "0.7.3"
+ resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.7.3.tgz#900c9720f7e5abb2a23975f90f96366d62d085b9"
+ integrity sha512-wFofIaa2879ogD/WvkjYXJxRmfnL0scen6ORgaC3na1FNOR9ASIUANQdhqQcmWu/h77/pVHY7ch5flewa5Bcew==
+ dependencies:
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/data-connect@0.7.1":
+ version "0.7.1"
+ resolved "https://registry.yarnpkg.com/@firebase/data-connect/-/data-connect-0.7.1.tgz#3ae9235525b5b0438968c4bf1ea1afc8816944b3"
+ integrity sha512-2LbUU8mmSA63HknxQMmWHjpzuNLBKflvVwQc2tpoVKg0biWleNEJX031ELks0vzFs+dDjOUkCJR72RP6mQHFOg==
+ dependencies:
+ "@firebase/auth-interop-types" "0.2.5"
+ "@firebase/component" "0.7.3"
+ "@firebase/logger" "0.5.1"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/database-compat@2.1.4":
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/@firebase/database-compat/-/database-compat-2.1.4.tgz#8ea753bef91d2dfbd81853479799f3ab17ddbbbe"
+ integrity sha512-3pK35F1MAgmqFJQlf2nhQl44vtAXQO1uaCaQOEUI9kCRtLFqi7N+QRKR7lFZPg+xIZIyubgxQaxY69YgfZRZWg==
+ dependencies:
+ "@firebase/component" "0.7.3"
+ "@firebase/database" "1.1.3"
+ "@firebase/database-types" "1.0.20"
+ "@firebase/logger" "0.5.1"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/database-types@1.0.20":
+ version "1.0.20"
+ resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-1.0.20.tgz#2050c3c13a4b71d92797e1475a297c0b5e0c9f5d"
+ integrity sha512-kegbOk/w8iU64pr0q6k2ItyNGjnQBMHFhwS7ohdWI4W+pc0/zhhdGXTdFj6X1oxItRjPoYOsSQmERgBkn/ihxw==
+ dependencies:
+ "@firebase/app-types" "0.9.5"
+ "@firebase/util" "1.15.1"
+
+"@firebase/database@1.1.3":
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/@firebase/database/-/database-1.1.3.tgz#ae3b1c906c45d70381359e61b4add6fc4beaa51e"
+ integrity sha512-XwWCa+E4TvNGpGwXrycLRNfdogADwFcvuhyow6wDWma9W54roaQIhe+4PM0KiLsIftBdSCGI7OKCXrdSRHbIhw==
+ dependencies:
+ "@firebase/app-check-interop-types" "0.3.4"
+ "@firebase/auth-interop-types" "0.2.5"
+ "@firebase/component" "0.7.3"
+ "@firebase/logger" "0.5.1"
+ "@firebase/util" "1.15.1"
+ faye-websocket "0.11.4"
+ tslib "^2.1.0"
+
+"@firebase/firestore-compat@0.4.11":
+ version "0.4.11"
+ resolved "https://registry.yarnpkg.com/@firebase/firestore-compat/-/firestore-compat-0.4.11.tgz#f382491377bad53e0aec888c62dfe400865266b5"
+ integrity sha512-W7o1WdwWq5aABK5Up2ncSvTQs/QGLR/fy7cVpFBNqhsXtxoMtflHf2xBIG6+aoptcuGAobddq4g2Sq27wqHaYw==
+ dependencies:
+ "@firebase/component" "0.7.3"
+ "@firebase/firestore" "4.16.0"
+ "@firebase/firestore-types" "3.0.4"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/firestore-types@3.0.4":
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/@firebase/firestore-types/-/firestore-types-3.0.4.tgz#a7205638195de1d356fbd39a620fd2d93c11d792"
+ integrity sha512-jGn+JSS4X9zZsrfu7Yw66v5YRdOLD1oyQh4USR0xWl4CUqV/DA6bNIXRPpxH/cUl3iVTNiP6MN7g+EL42A4qfA==
+
+"@firebase/firestore@4.16.0":
+ version "4.16.0"
+ resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-4.16.0.tgz#502b35d7ed4cdc61d62a02311a67145192c804f6"
+ integrity sha512-qdHMHMvMr0nRMuZyWNR/ArWa0YlPE3C4eAbmxTASJMYXAesKPL0Y54p70moggrNPzaK7MSIIq5RDJJyntQyIYA==
+ dependencies:
+ "@firebase/component" "0.7.3"
+ "@firebase/logger" "0.5.1"
+ "@firebase/util" "1.15.1"
+ "@firebase/webchannel-wrapper" "1.0.6"
+ "@grpc/grpc-js" "~1.9.0"
+ "@grpc/proto-loader" "^0.7.8"
+ re2js "^0.4.2"
+ tslib "^2.1.0"
+
+"@firebase/functions-compat@0.4.5":
+ version "0.4.5"
+ resolved "https://registry.yarnpkg.com/@firebase/functions-compat/-/functions-compat-0.4.5.tgz#5e22c71c5b11c7d49177fd7b0ff62d8583567604"
+ integrity sha512-10qlUXGY25G5/1g9UihqksPp2po+ZqSE7LEizsrdUP7vrTmkysXxGSZCDyojSEp6mQe/ecRDdDDI+z4XRdb4wQ==
+ dependencies:
+ "@firebase/component" "0.7.3"
+ "@firebase/functions" "0.13.5"
+ "@firebase/functions-types" "0.6.4"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/functions-types@0.6.4":
+ version "0.6.4"
+ resolved "https://registry.yarnpkg.com/@firebase/functions-types/-/functions-types-0.6.4.tgz#bb73ed93aa396419f907967202572ea55a605a40"
+ integrity sha512-zV6kgqtduR4rUAdC/ilS7kmb93XD7bEZoJDlVBZqlOw2uGGGCNBQBuleww2rr0Ulr3L9o2TDjumEt68/l1f9DQ==
+
+"@firebase/functions@0.13.5":
+ version "0.13.5"
+ resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.13.5.tgz#a4e099c072d7eac32b0f835438c45fa29a531e93"
+ integrity sha512-bWCx713f4kE/uFV7gdFOLBS7lDoiZj48MRkbAqe35gkXcCeWF4QjRNO07Jhmve7EJIoQOBczL29y2r8VRuN1kw==
+ dependencies:
+ "@firebase/app-check-interop-types" "0.3.4"
+ "@firebase/auth-interop-types" "0.2.5"
+ "@firebase/component" "0.7.3"
+ "@firebase/messaging-interop-types" "0.2.5"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/installations-compat@0.2.22":
+ version "0.2.22"
+ resolved "https://registry.yarnpkg.com/@firebase/installations-compat/-/installations-compat-0.2.22.tgz#d8287cef67879b3d3e796fc7e81256e1b75c8c8a"
+ integrity sha512-C/zpAuTP5S9OgKSPvXRupw3hoY/JZSlA1wFjD/Sb7LIQE0FNbcMdO8Y4KXVEkjVzma/DDDDIAzxEXqKMAzc88w==
+ dependencies:
+ "@firebase/component" "0.7.3"
+ "@firebase/installations" "0.6.22"
+ "@firebase/installations-types" "0.5.4"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/installations-types@0.5.4":
+ version "0.5.4"
+ resolved "https://registry.yarnpkg.com/@firebase/installations-types/-/installations-types-0.5.4.tgz#3b1e41ae7d1b89eb3b4a1c9cc583a12bed83aa27"
+ integrity sha512-U2eFapdHwjb43Vx9o+Pmj4dFfvcHEK1IirEFLqMtWrTHvmdrS3gBpBD1kmJk/9HjsOtoHZxJ2Paoe79e+L1ZPg==
+
+"@firebase/installations@0.6.22":
+ version "0.6.22"
+ resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.6.22.tgz#f5e7d2f51e58d22f8fd5c44901e56e3555d58837"
+ integrity sha512-ef6nn3GGQTdReCfotRMG77PJZu8CqEbiK5pEoBnM0gTu/Z9v0i/az2p3HABsa/1beQmmyh1OsOjf7P5+pgwdZw==
+ dependencies:
+ "@firebase/component" "0.7.3"
+ "@firebase/util" "1.15.1"
+ idb "7.1.1"
+ tslib "^2.1.0"
+
+"@firebase/logger@0.5.1":
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.5.1.tgz#da1eb266b3fa8d1375617cb64c36c9a5cb63d8e1"
+ integrity sha512-vZKLsqE1ABOy8OjQiE7cUTFn4gvaqlk88yp8N94Pk/sDpq61YqZGqmVFZTvOyflTwuYFcWirBdYGoJgbDaXKYQ==
+ dependencies:
+ tslib "^2.1.0"
+
+"@firebase/messaging-compat@0.2.27":
+ version "0.2.27"
+ resolved "https://registry.yarnpkg.com/@firebase/messaging-compat/-/messaging-compat-0.2.27.tgz#55a5d0754f54ecf9befac7c0574a2c8f6899b208"
+ integrity sha512-JNOiu1PPgdHzEPEtoFiNxQuu0x9bm4bfETSQCpGfcTlgWkhlSK7uh7nlsjC10TQLUNgYetLmuutaYTh8aeYLVA==
+ dependencies:
+ "@firebase/component" "0.7.3"
+ "@firebase/messaging" "0.13.0"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/messaging-interop-types@0.2.5":
+ version "0.2.5"
+ resolved "https://registry.yarnpkg.com/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.5.tgz#078657f9be789bfaa31156a969630ecc4c0d5e16"
+ integrity sha512-tUEKnaAP2Y/MNIqgnriPpV6e5l13Vs/+p2yrd6NGlncPJT9O3a8muYZtdnWe+IJ4fgKLHJVC79n/asxk/N5Msw==
+
+"@firebase/messaging@0.13.0":
+ version "0.13.0"
+ resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.13.0.tgz#40b0c9a564759c963527c8aef9038c438397c3c7"
+ integrity sha512-GZoo0uGRvEbszo83xcgbjJp4FpkmBEr4l8Z4hi8gl+P1Spn/MTK3HapanMzSX4yUHuTEiF5hasWRxOaz+o5sxQ==
+ dependencies:
+ "@firebase/component" "0.7.3"
+ "@firebase/installations" "0.6.22"
+ "@firebase/messaging-interop-types" "0.2.5"
+ "@firebase/util" "1.15.1"
+ idb "7.1.1"
+ tslib "^2.1.0"
+
+"@firebase/performance-compat@0.2.25":
+ version "0.2.25"
+ resolved "https://registry.yarnpkg.com/@firebase/performance-compat/-/performance-compat-0.2.25.tgz#2c23654e67d974b0679b39a18a7672bf886d0bb5"
+ integrity sha512-q6NjTXpIPoFuUmCmMN/maCdTgzT6aExs9xZo+PxfVLj6uLVGvpyAD6XWjmcrb7jChsFBYbq7E5dyNDF7Zhy9kA==
+ dependencies:
+ "@firebase/component" "0.7.3"
+ "@firebase/logger" "0.5.1"
+ "@firebase/performance" "0.7.12"
+ "@firebase/performance-types" "0.2.4"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/performance-types@0.2.4":
+ version "0.2.4"
+ resolved "https://registry.yarnpkg.com/@firebase/performance-types/-/performance-types-0.2.4.tgz#9aa9e531f974f4b5e5a09bffff12406e0dc11e1f"
+ integrity sha512-kJSEk7b0uhpcPRyL4SQ/GPujLqk52XNKcXlnsKDbWGAb9vugcLvOU3u6zfEdwd+d8hWJb5S5ZizV1JFFI0nkKg==
+
+"@firebase/performance@0.7.12":
+ version "0.7.12"
+ resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.7.12.tgz#7d46c91f4942df365669dbb32492c100d069bad6"
+ integrity sha512-fe7nV8teUU3OBHlMUZ9Lw4gLhCW2k4m5Uc3pfWGV+fl8uwJQBGp9Q3lqsJ+HSrFu3Q2pJyLAgrClPGSKyDeYgQ==
+ dependencies:
+ "@firebase/component" "0.7.3"
+ "@firebase/installations" "0.6.22"
+ "@firebase/logger" "0.5.1"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+ web-vitals "^4.2.4"
+
+"@firebase/remote-config-compat@0.2.26":
+ version "0.2.26"
+ resolved "https://registry.yarnpkg.com/@firebase/remote-config-compat/-/remote-config-compat-0.2.26.tgz#2c862af744f596ea4ae6e1abbbba2d9607572afb"
+ integrity sha512-uC57Tc7GYYOCnMgLkGIVf999XlaYaPDONoa54c93YTKDctlvCZI89z0zQ2RbhGR8Zf+QuCbQHs/99vqoE84a7g==
+ dependencies:
+ "@firebase/component" "0.7.3"
+ "@firebase/logger" "0.5.1"
+ "@firebase/remote-config" "0.8.5"
+ "@firebase/remote-config-types" "0.5.1"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/remote-config-types@0.5.1":
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/@firebase/remote-config-types/-/remote-config-types-0.5.1.tgz#2bc52831f8b52aff2b1b434158b4f7803e05f86e"
+ integrity sha512-cX/1LT6KQwkXzck2eSzeKnuvXZCyr8qaPpDcikoJs7jmI+oBOXixpDLeDtWj1U6GNMkIoXrEDNoyT2Ypcyp5/A==
+
+"@firebase/remote-config@0.8.5":
+ version "0.8.5"
+ resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.8.5.tgz#273ba61e07a365172abee03a6cf9c0e0ac676aa6"
+ integrity sha512-zb+7CDGFP2wYVF1LXQoYIFdoESIQM3p0+uiW1welw8+zvDxAL50K75PKTXXtunJADUrksTVpV7mD0pn54vzJRA==
+ dependencies:
+ "@firebase/component" "0.7.3"
+ "@firebase/installations" "0.6.22"
+ "@firebase/logger" "0.5.1"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/storage-compat@0.4.3":
+ version "0.4.3"
+ resolved "https://registry.yarnpkg.com/@firebase/storage-compat/-/storage-compat-0.4.3.tgz#85a01de8fbd0ef4cad261d39beea5e6391e5a051"
+ integrity sha512-gruVqjtUGX8tEoeNbaWXZm0Zfcfcb7fvmDmBxV8yPAbWvExRnZYLO2+qw9idxNE7BvPXt5csyjSYHy//dAizxw==
+ dependencies:
+ "@firebase/component" "0.7.3"
+ "@firebase/storage" "0.14.3"
+ "@firebase/storage-types" "0.8.4"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/storage-types@0.8.4":
+ version "0.8.4"
+ resolved "https://registry.yarnpkg.com/@firebase/storage-types/-/storage-types-0.8.4.tgz#88d72c80eb9a1167da33e8c551fd3b703c2422ec"
+ integrity sha512-BT7cwxJOx8SWwlQfrlC+bD/Sk3Cw+1odCi8UZNFNWTVZoPsBnA5W+mqtZzVnvsdJpXCFGSGQ7R7vOR6dtM/BRA==
+
+"@firebase/storage@0.14.3":
+ version "0.14.3"
+ resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.14.3.tgz#df93f895ff6f296e9305933cfe6c387d19fa4f93"
+ integrity sha512-YX4/YL6P6/fufSSeGnVhjWddcIXbFq2cWIhMKFTZo1E/Rtcl2mJj/BYUQTwJfcE1Tl8un1FOya4L05jcSLN/Eg==
+ dependencies:
+ "@firebase/component" "0.7.3"
+ "@firebase/util" "1.15.1"
+ tslib "^2.1.0"
+
+"@firebase/util@1.15.1":
+ version "1.15.1"
+ resolved "https://registry.yarnpkg.com/@firebase/util/-/util-1.15.1.tgz#7efaf8903f50b601c06afbaffbeb48ed2ba7aab8"
+ integrity sha512-LUdM4Wg7YM9Pq/49nGYySJA0CSQEKnGffFzWV8+6gXN7mGxn+FL1IqvFbuZUtAQcfZgHYDwCE1wwlK7rB7gl2g==
+ dependencies:
+ tslib "^2.1.0"
+
+"@firebase/webchannel-wrapper@1.0.6":
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.6.tgz#4be6a62b8c27a6bad8cc8da41f9a12de901e965d"
+ integrity sha512-Vr/Mqu79dMwGRAyGbJ4uN4+BtXB3/mRTdzetD1daWNeG8QaWuzhhbG77GltO5c0yYmYls8i250iX73624GJd7Q==
+
+"@grpc/grpc-js@~1.9.0":
+ version "1.9.16"
+ resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.9.16.tgz#614f85036ac8e3c957374c1bd1ebb05934a79a1c"
+ integrity sha512-wE4Ut/olIzfKqp631XrG+wbF0v1vWFN4YL9FyXC2LJiG33DsV7PLzURjrCvY/6je2ntdRkeLpPDluzSRGaVltQ==
+ dependencies:
+ "@grpc/proto-loader" "^0.7.8"
+ "@types/node" ">=12.12.47"
+
+"@grpc/proto-loader@^0.7.8":
+ version "0.7.15"
+ resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.15.tgz#4cdfbf35a35461fc843abe8b9e2c0770b5095e60"
+ integrity sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==
+ dependencies:
+ lodash.camelcase "^4.3.0"
+ long "^5.0.0"
+ protobufjs "^7.2.5"
+ yargs "^17.7.2"
+
"@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0":
version "9.3.0"
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb"
@@ -1096,6 +1570,167 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3"
integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==
+"@img/colour@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@img/colour/-/colour-1.1.0.tgz#b0c2c2fa661adf75effd6b4964497cd80010bb9d"
+ integrity sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==
+
+"@img/sharp-darwin-arm64@0.35.3":
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz#8b2740884bc58b127fc3020479a01294fa1095cb"
+ integrity sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==
+ optionalDependencies:
+ "@img/sharp-libvips-darwin-arm64" "1.3.2"
+
+"@img/sharp-darwin-x64@0.35.3":
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz#92df91320faf57cc54b331185770d5a93d510049"
+ integrity sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==
+ optionalDependencies:
+ "@img/sharp-libvips-darwin-x64" "1.3.2"
+
+"@img/sharp-freebsd-wasm32@0.35.3":
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz#48018c1379a8f507d681d6cd8dbe43d9795dc809"
+ integrity sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==
+ dependencies:
+ "@img/sharp-wasm32" "0.35.3"
+
+"@img/sharp-libvips-darwin-arm64@1.3.2":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz#227b41ffc6c99612bceaba56f994a1933d779573"
+ integrity sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==
+
+"@img/sharp-libvips-darwin-x64@1.3.2":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz#694903ec410c00945ce5b0c26dac83d7184c8b86"
+ integrity sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==
+
+"@img/sharp-libvips-linux-arm64@1.3.2":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz#49ddf156728666a21deed0716f3bb72bb351179e"
+ integrity sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==
+
+"@img/sharp-libvips-linux-arm@1.3.2":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz#e60e088c806bde1ac28be648b60c3465f41c18a7"
+ integrity sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==
+
+"@img/sharp-libvips-linux-ppc64@1.3.2":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz#be3161aafd659417b3e26374dfbbcd2da2bfb62c"
+ integrity sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==
+
+"@img/sharp-libvips-linux-riscv64@1.3.2":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz#bf008a6779d9be2b56a4df67b753941f767c957d"
+ integrity sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==
+
+"@img/sharp-libvips-linux-s390x@1.3.2":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz#9583814b8db58889c85bad9e5e0b7825257ff394"
+ integrity sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==
+
+"@img/sharp-libvips-linux-x64@1.3.2":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.2.tgz#abc9a3114495b705ba20b7c1568b9eecd62aebbb"
+ integrity sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==
+
+"@img/sharp-libvips-linuxmusl-arm64@1.3.2":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.2.tgz#e58fb14a7879f15d9e70a982870f384f39a832a2"
+ integrity sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==
+
+"@img/sharp-libvips-linuxmusl-x64@1.3.2":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.2.tgz#5611480fcb7465dd5316044db53ad7a843ed4af8"
+ integrity sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==
+
+"@img/sharp-linux-arm64@0.35.3":
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.3.tgz#44b65823ecc977d4585b308070fff3947256de04"
+ integrity sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==
+ optionalDependencies:
+ "@img/sharp-libvips-linux-arm64" "1.3.2"
+
+"@img/sharp-linux-arm@0.35.3":
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.3.tgz#c8da500c4016893a89d46e9832d08a06eef77f27"
+ integrity sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==
+ optionalDependencies:
+ "@img/sharp-libvips-linux-arm" "1.3.2"
+
+"@img/sharp-linux-ppc64@0.35.3":
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.3.tgz#ea1d7db818f52af1e1e057e82d55f23b2de3864c"
+ integrity sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==
+ optionalDependencies:
+ "@img/sharp-libvips-linux-ppc64" "1.3.2"
+
+"@img/sharp-linux-riscv64@0.35.3":
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.3.tgz#722bd7994658791b02d1037ea09ca5cb78030d8d"
+ integrity sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==
+ optionalDependencies:
+ "@img/sharp-libvips-linux-riscv64" "1.3.2"
+
+"@img/sharp-linux-s390x@0.35.3":
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.3.tgz#e8294817d7da495541a4a870f56e6b5d0f8643cd"
+ integrity sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==
+ optionalDependencies:
+ "@img/sharp-libvips-linux-s390x" "1.3.2"
+
+"@img/sharp-linux-x64@0.35.3":
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.3.tgz#9843c32f39aeac4b60dd60f9e3416520a4e4de46"
+ integrity sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==
+ optionalDependencies:
+ "@img/sharp-libvips-linux-x64" "1.3.2"
+
+"@img/sharp-linuxmusl-arm64@0.35.3":
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.3.tgz#9cfee4ecc3d41ab9a274e019dfe7b4062840510c"
+ integrity sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==
+ optionalDependencies:
+ "@img/sharp-libvips-linuxmusl-arm64" "1.3.2"
+
+"@img/sharp-linuxmusl-x64@0.35.3":
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.3.tgz#204d0678c8c3b15300d9a26ecb9c0dcda11ca5de"
+ integrity sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==
+ optionalDependencies:
+ "@img/sharp-libvips-linuxmusl-x64" "1.3.2"
+
+"@img/sharp-wasm32@0.35.3":
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz#42f8979bdbe1a541a2e9b99d3b5be07e6b71c7c0"
+ integrity sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==
+ dependencies:
+ "@emnapi/runtime" "^1.11.1"
+
+"@img/sharp-webcontainers-wasm32@0.35.3":
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.3.tgz#823aaa93d14db84999d5b5dc967ff56cf1966d9f"
+ integrity sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==
+ dependencies:
+ "@img/sharp-wasm32" "0.35.3"
+
+"@img/sharp-win32-arm64@0.35.3":
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.3.tgz#f3554d45cbe24532a0adea736ec57658f74a2911"
+ integrity sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==
+
+"@img/sharp-win32-ia32@0.35.3":
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.3.tgz#0942b2643bcb57e48419fe4119de84078ae0ac74"
+ integrity sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==
+
+"@img/sharp-win32-x64@0.35.3":
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.3.tgz#8a25cacdc75a8c26077c07fba51e8056aae474f1"
+ integrity sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==
+
"@isaacs/ttlcache@^1.4.1":
version "1.4.1"
resolved "https://registry.yarnpkg.com/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz#21fb23db34e9b6220c6ba023a0118a2dd3461ea2"
@@ -1379,6 +2014,58 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
+"@notifee/react-native@^9.1.8":
+ version "9.1.8"
+ resolved "https://registry.yarnpkg.com/@notifee/react-native/-/react-native-9.1.8.tgz#3d55cb3fbcc21f9e35931e366afdf64b294da891"
+ integrity sha512-Az/dueoPerJsbbjRxu8a558wKY+gONUrfoy3Hs++5OqbeMsR0dYe6P+4oN6twrLFyzAhEA1tEoZRvQTFDRmvQg==
+
+"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
+ integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==
+
+"@protobufjs/base64@^1.1.2":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735"
+ integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==
+
+"@protobufjs/codegen@^2.0.5":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.5.tgz#d9315ad7cf3f30aac70bda3c068443dc6f143659"
+ integrity sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==
+
+"@protobufjs/eventemitter@^1.1.1":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz#d512cb26c0ae026091ee2c1167f1be6faf5c842a"
+ integrity sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==
+
+"@protobufjs/fetch@^1.1.1":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.1.tgz#4d6fc00c8fb64016a5c81b469d549046350f1065"
+ integrity sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==
+ dependencies:
+ "@protobufjs/aspromise" "^1.1.1"
+
+"@protobufjs/float@^1.0.2":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
+ integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==
+
+"@protobufjs/path@^1.1.2":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
+ integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==
+
+"@protobufjs/pool@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
+ integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==
+
+"@protobufjs/utf8@^1.1.1":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.2.tgz#78d476333d85d5b1c792e257bca74ba080da49a4"
+ integrity sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==
+
"@react-native-async-storage/async-storage@^3.1.1":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@react-native-async-storage/async-storage/-/async-storage-3.1.1.tgz#051caeb93919260041e53165f1b6c8a975b15105"
@@ -1538,6 +2225,18 @@
prompts "^2.4.2"
semver "^7.5.2"
+"@react-native-firebase/app@^25.1.0":
+ version "25.1.0"
+ resolved "https://registry.yarnpkg.com/@react-native-firebase/app/-/app-25.1.0.tgz#7260d6f8b48078b9f651ca07804b140e9787397a"
+ integrity sha512-IRBM0Uwrs1O+SkUF8D9g7FgC8WI5b/3xEbt3JzFTTsHWvQyXxvTflKd4rNFNegV+2mFrM53XC9cS1BNVjWSSSg==
+ dependencies:
+ firebase "12.15.0"
+
+"@react-native-firebase/messaging@^25.1.0":
+ version "25.1.0"
+ resolved "https://registry.yarnpkg.com/@react-native-firebase/messaging/-/messaging-25.1.0.tgz#21d46ba446a728c44e7c5bc3622099ba355f915c"
+ integrity sha512-YVhGWr6uthySTNHqnXsDh6DX4WtK4AittU9oDeKaBSjN4uoMDOe2X74TYnBFEUdcCQxOAsUavFNAexQx/o8dsw==
+
"@react-native/assets-registry@0.86.0":
version "0.86.0"
resolved "https://registry.yarnpkg.com/@react-native/assets-registry/-/assets-registry-0.86.0.tgz#560e78135969d1198aabfdc4ae74faae336463d0"
@@ -1929,7 +2628,7 @@
expect "^29.0.0"
pretty-format "^29.0.0"
-"@types/node@*":
+"@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0":
version "26.1.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-26.1.1.tgz#bad758d601e97d6cf457d204ee76a35fce7bd119"
integrity sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==
@@ -2078,6 +2777,16 @@
resolved "https://registry.yarnpkg.com/@vscode/sudo-prompt/-/sudo-prompt-9.3.2.tgz#692ba38df40bd3502ccc4e9f099fbbaedbd5f04e"
integrity sha512-gcXoCN00METUNFeQOFJ+C9xUI0DKB+0EGMVg7wbVYRHBw2Eq3fKisDZOkRdOz3kqXRKOENMfShPOmypw1/8nOw==
+"@xmldom/xmldom@^0.8.8":
+ version "0.8.13"
+ resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.13.tgz#00d1dd940b218dff2e49309d410d8bb212159225"
+ integrity sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==
+
+"@xmldom/xmldom@^0.9.10":
+ version "0.9.10"
+ resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.9.10.tgz#a0ad5a26fe8aa996310870726e1704977f769dee"
+ integrity sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==
+
abort-controller@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
@@ -2468,6 +3177,11 @@ baseline-browser-mapping@^2.10.42:
resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.43.tgz#7b5d11590ce5acdbe4859443e3c940e81ce8c02d"
integrity sha512-AjYpR78kDWAY3Efj+cDTFH9t9SCoL7OoTp1BOb0mQV7S+6CiLwnWM3FyxhJtdPufDFKzmCSFoUncKjWgJEZTCQ==
+big-integer@1.6.x:
+ version "1.6.52"
+ resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85"
+ integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==
+
bl@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
@@ -2495,6 +3209,25 @@ body-parser@^1.20.3:
type-is "~1.6.18"
unpipe "~1.0.0"
+boolbase@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
+ integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
+
+bplist-creator@0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/bplist-creator/-/bplist-creator-0.1.0.tgz#018a2d1b587f769e379ef5519103730f8963ba1e"
+ integrity sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==
+ dependencies:
+ stream-buffers "2.2.x"
+
+bplist-parser@0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.3.1.tgz#e1c90b2ca2a9f9474cc72f6862bbf3fee8341fd1"
+ integrity sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==
+ dependencies:
+ big-integer "1.6.x"
+
brace-expansion@^1.1.7:
version "1.1.16"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.16.tgz#723d3a30c0558c225abc9fc479a73e14e26c3c2f"
@@ -2606,7 +3339,7 @@ caniuse-lite@^1.0.30001803:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz#1bc8e502b723fa393455dfbedd5ccec0c29bb74e"
integrity sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==
-chalk@^4.0.0, chalk@^4.1.0:
+chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@@ -2771,6 +3504,11 @@ commander@^12.0.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3"
integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==
+commander@^14.0.3:
+ version "14.0.3"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.3.tgz#425d79b48f9af82fcd9e4fc1ea8af6c5ec07bbc2"
+ integrity sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==
+
commander@^2.20.0:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
@@ -2865,6 +3603,22 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3, cross-spawn@^7.0.6:
shebang-command "^2.0.0"
which "^2.0.1"
+css-select@^5.1.0:
+ version "5.2.2"
+ resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.2.2.tgz#01b6e8d163637bb2dd6c982ca4ed65863682786e"
+ integrity sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==
+ dependencies:
+ boolbase "^1.0.0"
+ css-what "^6.1.0"
+ domhandler "^5.0.2"
+ domutils "^3.0.1"
+ nth-check "^2.0.1"
+
+css-what@^6.1.0:
+ version "6.2.2"
+ resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.2.2.tgz#cdcc8f9b6977719fdfbd1de7aec24abf756b9dea"
+ integrity sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==
+
csstype@^3.2.2:
version "3.2.3"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a"
@@ -2909,7 +3663,7 @@ debug@2.6.9, debug@^2.6.9:
dependencies:
ms "2.0.0"
-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, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.5, debug@^4.4.0, debug@^4.4.3:
version "4.4.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a"
integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==
@@ -2981,6 +3735,16 @@ destroy@1.2.0, destroy@~1.2.0:
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
+detect-indent@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6"
+ integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==
+
+detect-libc@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.1.2.tgz#689c5dcdc1900ef5583a4cb9f6d7b473742074ad"
+ integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==
+
detect-newline@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
@@ -3005,6 +3769,36 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"
+dom-serializer@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53"
+ integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==
+ dependencies:
+ domelementtype "^2.3.0"
+ domhandler "^5.0.2"
+ entities "^4.2.0"
+
+domelementtype@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
+ integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
+
+domhandler@^5.0.2, domhandler@^5.0.3:
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31"
+ integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==
+ dependencies:
+ domelementtype "^2.3.0"
+
+domutils@^3.0.1:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.2.2.tgz#edbfe2b668b0c1d97c24baf0f1062b132221bc78"
+ integrity sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==
+ dependencies:
+ dom-serializer "^2.0.0"
+ domelementtype "^2.3.0"
+ domhandler "^5.0.3"
+
dunder-proto@^1.0.0, dunder-proto@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a"
@@ -3044,6 +3838,11 @@ encodeurl@~2.0.0:
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58"
integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==
+entities@^4.2.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
+ integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
+
env-paths@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2"
@@ -3483,7 +4282,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
-fast-glob@^3.3.2:
+fast-glob@^3.3.2, fast-glob@^3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818"
integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==
@@ -3518,6 +4317,13 @@ fastq@^1.6.0:
dependencies:
reusify "^1.0.4"
+faye-websocket@0.11.4:
+ version "0.11.4"
+ resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da"
+ integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==
+ dependencies:
+ websocket-driver ">=0.5.1"
+
fb-dotslash@0.5.8:
version "0.5.8"
resolved "https://registry.yarnpkg.com/fb-dotslash/-/fb-dotslash-0.5.8.tgz#c5ef3dacd75e1ddb2197c367052464ddde0115f5"
@@ -3597,6 +4403,40 @@ find-up@^5.0.0:
locate-path "^6.0.0"
path-exists "^4.0.0"
+firebase@12.15.0:
+ version "12.15.0"
+ resolved "https://registry.yarnpkg.com/firebase/-/firebase-12.15.0.tgz#30efa309ebcac219f43adf0de462351185cb76e0"
+ integrity sha512-p0YTLcRSTiBXMx9sGr4ZNSfLjc/RVBEw4C/TXjVMtw65+6E1Pbm47UY3F4/AqRoDobEcNX3gsbPGy7jPjxbgSQ==
+ dependencies:
+ "@firebase/ai" "2.13.1"
+ "@firebase/analytics" "0.10.22"
+ "@firebase/analytics-compat" "0.2.28"
+ "@firebase/app" "0.15.0"
+ "@firebase/app-check" "0.12.0"
+ "@firebase/app-check-compat" "0.4.5"
+ "@firebase/app-compat" "0.5.14"
+ "@firebase/app-types" "0.9.5"
+ "@firebase/auth" "1.13.3"
+ "@firebase/auth-compat" "0.6.8"
+ "@firebase/data-connect" "0.7.1"
+ "@firebase/database" "1.1.3"
+ "@firebase/database-compat" "2.1.4"
+ "@firebase/firestore" "4.16.0"
+ "@firebase/firestore-compat" "0.4.11"
+ "@firebase/functions" "0.13.5"
+ "@firebase/functions-compat" "0.4.5"
+ "@firebase/installations" "0.6.22"
+ "@firebase/installations-compat" "0.2.22"
+ "@firebase/messaging" "0.13.0"
+ "@firebase/messaging-compat" "0.2.27"
+ "@firebase/performance" "0.7.12"
+ "@firebase/performance-compat" "0.2.25"
+ "@firebase/remote-config" "0.8.5"
+ "@firebase/remote-config-compat" "0.2.26"
+ "@firebase/storage" "0.14.3"
+ "@firebase/storage-compat" "0.4.3"
+ "@firebase/util" "1.15.1"
+
flat-cache@^3.0.4:
version "3.2.0"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee"
@@ -3746,6 +4586,11 @@ get-symbol-description@^1.1.0:
es-errors "^1.3.0"
get-intrinsic "^1.2.6"
+getenv@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/getenv/-/getenv-2.0.0.tgz#b1698c7b0f29588f4577d06c42c73a5b475c69e0"
+ integrity sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==
+
glob-parent@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
@@ -3760,6 +4605,15 @@ glob-parent@^6.0.2:
dependencies:
is-glob "^4.0.3"
+glob@^13.0.0:
+ 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.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
@@ -3855,6 +4709,11 @@ hasown@^2.0.2, hasown@^2.0.3, hasown@^2.0.4:
dependencies:
function-bind "^1.1.2"
+he@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
+ integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+
hermes-compiler@250829098.0.14:
version "250829098.0.14"
resolved "https://registry.yarnpkg.com/hermes-compiler/-/hermes-compiler-250829098.0.14.tgz#4fbe8c18d277d5b766c4650c7bc4b3dddd6fd9c1"
@@ -3919,6 +4778,11 @@ http-errors@~2.0.1:
statuses "~2.0.2"
toidentifier "~1.0.1"
+http-parser-js@>=0.5.1:
+ version "0.5.10"
+ resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.10.tgz#b3277bd6d7ed5588e20ea73bf724fcbe44609075"
+ integrity sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==
+
https-proxy-agent@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
@@ -3947,6 +4811,11 @@ iconv-lite@~0.4.24:
dependencies:
safer-buffer ">= 2.1.2 < 3"
+idb@7.1.1:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b"
+ integrity sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==
+
idb@8.0.3:
version "8.0.3"
resolved "https://registry.yarnpkg.com/idb/-/idb-8.0.3.tgz#c91e558f15a8d53f1d7f53a094d226fc3ad71fd9"
@@ -4865,6 +5734,11 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"
+lodash.camelcase@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
+ integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
+
lodash.debounce@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
@@ -4902,6 +5776,11 @@ logkitty@^0.7.1:
dayjs "^1.8.15"
yargs "^15.1.0"
+long@^5.0.0, long@^5.3.2:
+ version "5.3.2"
+ resolved "https://registry.yarnpkg.com/long/-/long-5.3.2.tgz#1d84463095999262d7d7b7f8bfd4a8cc55167f83"
+ integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==
+
loose-envify@^1.0.0, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
@@ -4914,6 +5793,11 @@ lru-cache@^10.2.0:
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119"
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.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
@@ -5230,7 +6114,7 @@ minipass@^4.2.4:
resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a"
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.yarnpkg.com/minipass/-/minipass-7.1.3.tgz#79389b4eb1bb2d003a9bba87d492f2bd37bdc65b"
integrity sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==
@@ -5295,6 +6179,14 @@ node-exports-info@^1.6.0:
object.entries "^1.1.9"
semver "^6.3.1"
+node-html-parser@^7.1.0:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-7.1.0.tgz#48e83bd705dd8b89415c00bf670aebfe267312d7"
+ integrity sha512-iJo8b2uYGT40Y8BTyy5ufL6IVbN8rbm/1QK2xffXU/1a/v3AAa0d1YAoqBNYqaS4R/HajkWIpIfdE6KcyFh1AQ==
+ dependencies:
+ css-select "^5.1.0"
+ he "1.2.0"
+
node-int64@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
@@ -5322,6 +6214,13 @@ npm-run-path@^4.0.1:
dependencies:
path-key "^3.0.0"
+nth-check@^2.0.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
+ integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==
+ dependencies:
+ boolbase "^1.0.0"
+
nullthrows@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1"
@@ -5570,6 +6469,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.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
@@ -5604,6 +6511,15 @@ pkg-up@^3.1.0:
dependencies:
find-up "^3.0.0"
+plist@^3.0.5:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/plist/-/plist-3.1.1.tgz#fa6099e1e3cf6ea180258ebe6378ea3878c2c841"
+ integrity sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA==
+ dependencies:
+ "@xmldom/xmldom" "^0.9.10"
+ base64-js "^1.5.1"
+ xmlbuilder "^15.1.1"
+
possible-typed-array-names@^1.0.0, possible-typed-array-names@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae"
@@ -5619,6 +6535,11 @@ prettier@2.8.8:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
+prettier@^3.8.1:
+ version "3.9.6"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.9.6.tgz#b3ea5146515d40fc53f18aa63f74dfab1e10dbf6"
+ integrity sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==
+
pretty-format@^29.0.0, pretty-format@^29.7.0:
version "29.7.0"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812"
@@ -5652,6 +6573,23 @@ prop-types@^15.7.2, prop-types@^15.8.1:
object-assign "^4.1.1"
react-is "^16.13.1"
+protobufjs@^7.2.5:
+ version "7.6.5"
+ resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.6.5.tgz#7b9250cdaf4a06139a9f0fe468a40d7d4febca71"
+ integrity sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==
+ dependencies:
+ "@protobufjs/aspromise" "^1.1.2"
+ "@protobufjs/base64" "^1.1.2"
+ "@protobufjs/codegen" "^2.0.5"
+ "@protobufjs/eventemitter" "^1.1.1"
+ "@protobufjs/fetch" "^1.1.1"
+ "@protobufjs/float" "^1.0.2"
+ "@protobufjs/path" "^1.1.2"
+ "@protobufjs/pool" "^1.1.0"
+ "@protobufjs/utf8" "^1.1.1"
+ "@types/node" ">=13.7.0"
+ long "^5.3.2"
+
proxy-from-env@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-2.1.0.tgz#a7487568adad577cfaaa7e88c49cab3ab3081aba"
@@ -5712,6 +6650,11 @@ raw-body@~2.5.3:
iconv-lite "~0.4.24"
unpipe "~1.0.0"
+re2js@^0.4.2:
+ version "0.4.3"
+ resolved "https://registry.yarnpkg.com/re2js/-/re2js-0.4.3.tgz#1318cd0c12aa6ed3ba56d5e012311ffbfb2aef35"
+ integrity sha512-EuNmh7jurhHEE8Ge/lBo9JuMLb3qf866Xjjfyovw3wPc7+hlqDkZq4LwhrCQMEI+ARWfrKrHozEndzlpNT0WDg==
+
react-devtools-core@^6.1.5:
version "6.1.5"
resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-6.1.5.tgz#c5eca79209dab853a03b2158c034c5166975feee"
@@ -5740,6 +6683,23 @@ react-is@^19.1.0, react-is@^19.2.3:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.2.7.tgz#57668ee86a78574a542b0a539455212b2c086df2"
integrity sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==
+react-native-bootsplash@^7.3.2:
+ version "7.3.2"
+ resolved "https://registry.yarnpkg.com/react-native-bootsplash/-/react-native-bootsplash-7.3.2.tgz#d235f8de54a3f6f38b9cf7cde0d2199433815416"
+ integrity sha512-tPOmyufxKUin+1cDjsJqz1dLBDBV1O7kO+5uZgATih73eDkYgyDerXwjtorwrE0U6ILvTvOJ7rA4PiW1t7PTxQ==
+ dependencies:
+ "@expo/config-plugins" "*"
+ commander "^14.0.3"
+ detect-indent "^6.1.0"
+ fast-glob "^3.3.3"
+ node-html-parser "^7.1.0"
+ picocolors "^1.1.1"
+ prettier "^3.8.1"
+ react-native-is-edge-to-edge "^1.3.1"
+ sharp "^0.35.2"
+ ts-dedent "^2.2.0"
+ xml-formatter "^3.7.0"
+
react-native-config@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/react-native-config/-/react-native-config-1.6.1.tgz#f8428829fda74384484d773fe36820159c559159"
@@ -6093,7 +7053,7 @@ safe-array-concat@^1.1.3:
has-symbols "^1.1.0"
isarray "^2.0.5"
-safe-buffer@5.2.1, safe-buffer@~5.2.0:
+safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
@@ -6120,6 +7080,11 @@ safe-regex-test@^1.1.0:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+sax@>=0.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/sax/-/sax-1.6.0.tgz#da59637629307b97e7c4cb28e080a7bc38560d5b"
+ integrity sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==
+
scheduler@0.27.0, scheduler@^0.27.0:
version "0.27.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.27.0.tgz#0c4ef82d67d1e5c1e359e8fc76d3a87f045fe5bd"
@@ -6130,7 +7095,7 @@ semver@^6.3.0, semver@^6.3.1:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
-semver@^7.1.3, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.7.3, 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, semver@^7.8.5:
version "7.8.5"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.8.5.tgz#39b646037dd50c14fb451e7e4cac58ed8b863f69"
integrity sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==
@@ -6215,6 +7180,41 @@ sf-symbols-typescript@^2.1.0:
resolved "https://registry.yarnpkg.com/sf-symbols-typescript/-/sf-symbols-typescript-2.2.0.tgz#926d6e0715e3d8784cadf7658431e36581254208"
integrity sha512-TPbeg0b7ylrswdGCji8FRGFAKuqbpQlLbL8SOle3j1iHSs5Ob5mhvMAxWN2UItOjgALAB5Zp3fmMfj8mbWvXKw==
+sharp@^0.35.2:
+ version "0.35.3"
+ resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.35.3.tgz#41ed21a46406be163eacd0be7b364b42fcf2885f"
+ integrity sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==
+ dependencies:
+ "@img/colour" "^1.1.0"
+ detect-libc "^2.1.2"
+ semver "^7.8.5"
+ optionalDependencies:
+ "@img/sharp-darwin-arm64" "0.35.3"
+ "@img/sharp-darwin-x64" "0.35.3"
+ "@img/sharp-freebsd-wasm32" "0.35.3"
+ "@img/sharp-libvips-darwin-arm64" "1.3.2"
+ "@img/sharp-libvips-darwin-x64" "1.3.2"
+ "@img/sharp-libvips-linux-arm" "1.3.2"
+ "@img/sharp-libvips-linux-arm64" "1.3.2"
+ "@img/sharp-libvips-linux-ppc64" "1.3.2"
+ "@img/sharp-libvips-linux-riscv64" "1.3.2"
+ "@img/sharp-libvips-linux-s390x" "1.3.2"
+ "@img/sharp-libvips-linux-x64" "1.3.2"
+ "@img/sharp-libvips-linuxmusl-arm64" "1.3.2"
+ "@img/sharp-libvips-linuxmusl-x64" "1.3.2"
+ "@img/sharp-linux-arm" "0.35.3"
+ "@img/sharp-linux-arm64" "0.35.3"
+ "@img/sharp-linux-ppc64" "0.35.3"
+ "@img/sharp-linux-riscv64" "0.35.3"
+ "@img/sharp-linux-s390x" "0.35.3"
+ "@img/sharp-linux-x64" "0.35.3"
+ "@img/sharp-linuxmusl-arm64" "0.35.3"
+ "@img/sharp-linuxmusl-x64" "0.35.3"
+ "@img/sharp-webcontainers-wasm32" "0.35.3"
+ "@img/sharp-win32-arm64" "0.35.3"
+ "@img/sharp-win32-ia32" "0.35.3"
+ "@img/sharp-win32-x64" "0.35.3"
+
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
@@ -6277,6 +7277,15 @@ signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
+simple-plist@^1.1.0:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/simple-plist/-/simple-plist-1.3.1.tgz#16e1d8f62c6c9b691b8383127663d834112fb017"
+ integrity sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==
+ dependencies:
+ bplist-creator "0.1.0"
+ bplist-parser "0.3.1"
+ plist "^3.0.5"
+
simple-swizzle@^0.2.2:
version "0.2.4"
resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.4.tgz#a8d11a45a11600d6a1ecdff6363329e3648c3667"
@@ -6303,6 +7312,11 @@ slice-ansi@^2.0.0:
astral-regex "^1.0.0"
is-fullwidth-code-point "^2.0.0"
+slugify@^1.6.6:
+ version "1.6.9"
+ resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.6.9.tgz#610957dea21e56b65e3a153215ef7b265715c8e8"
+ integrity sha512-vZ7rfeehZui7wQs438JXBckYLkIIdfHOXsaVEUMyS5fHo1483l1bMdo0EDSWYclY0yZKFOipDy4KHuKs6ssvdg==
+
source-map-support@0.5.13:
version "0.5.13"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932"
@@ -6381,6 +7395,11 @@ stop-iteration-iterator@^1.1.0:
es-errors "^1.3.0"
internal-slot "^1.1.0"
+stream-buffers@2.2.x:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4"
+ integrity sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==
+
strict-uri-encode@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
@@ -6587,6 +7606,16 @@ ts-api-utils@^2.5.0:
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.5.0.tgz#4acd4a155e22734990a5ed1fe9e97f113bcb37c1"
integrity sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==
+ts-dedent@^2.2.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.3.0.tgz#8fac36c7902b541c154ac13a27ac467997af11f8"
+ integrity sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==
+
+tslib@^2.1.0, tslib@^2.4.0:
+ version "2.8.1"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
+ integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
+
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
@@ -6755,6 +7784,11 @@ utils-merge@1.0.1:
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
+uuid@^7.0.3:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b"
+ integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==
+
v8-to-istanbul@^9.0.1:
version "9.3.0"
resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175"
@@ -6793,6 +7827,25 @@ wcwidth@^1.0.1:
dependencies:
defaults "^1.0.3"
+web-vitals@^4.2.4:
+ version "4.2.4"
+ resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-4.2.4.tgz#1d20bc8590a37769bd0902b289550936069184b7"
+ integrity sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==
+
+websocket-driver@>=0.5.1:
+ version "0.7.5"
+ resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.5.tgz#569d22764ab21f2de20af0e74b411e8ae5a0fa46"
+ integrity sha512-ZL2+3c7kMBdIRCMz6l8jQMHyGVxj+UL+xVk74Ombiciboca8rHa15L86B19E5oh1pL9Ii/uj54gtsIrZGMo6zA==
+ dependencies:
+ http-parser-js ">=0.5.1"
+ safe-buffer ">=5.1.0"
+ websocket-extensions ">=0.1.1"
+
+websocket-extensions@>=0.1.1:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42"
+ integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==
+
whatwg-fetch@^3.0.0:
version "3.6.20"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz#580ce6d791facec91d37c72890995a0b48d31c70"
@@ -6911,6 +7964,44 @@ ws@^7, ws@^7.5.10:
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.12.tgz#4ca2c04966db4dcd2f9bc4d1419d23cd1e4a18db"
integrity sha512-1xGnbYN3zbog9CwuNDQULNRrTCLIn46/WmpR1f0w6PsCYQHkylZr5vkd6kfMZYV6pRnQkcPNRyiA8LsrNKyhpg==
+xcode@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/xcode/-/xcode-3.0.1.tgz#3efb62aac641ab2c702458f9a0302696146aa53c"
+ integrity sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==
+ dependencies:
+ simple-plist "^1.1.0"
+ uuid "^7.0.3"
+
+xml-formatter@^3.7.0:
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/xml-formatter/-/xml-formatter-3.7.0.tgz#ac6f8c02e2388759652e9d0c8a4b5b3dfc0694e5"
+ integrity sha512-+8qTc3zv2UcJ1v9IsSIce37Dl4MQG14Cp7tWrwmy202UaI1wqRukw5QMX1JHsV+DX64yw77EgGsj2s5wGvuMbQ==
+ dependencies:
+ xml-parser-xo "^4.1.5"
+
+xml-parser-xo@^4.1.5:
+ version "4.1.6"
+ resolved "https://registry.yarnpkg.com/xml-parser-xo/-/xml-parser-xo-4.1.6.tgz#22bb2d0e1f651f92de04c7b79433a9df6f1490f2"
+ integrity sha512-mXbSNSM+rIwndoxSwmFa83bOdeP8G/cOGr7XvxA67X7ebCzoAuVez9JYDCDub3zRDNBZxIbfjuXLSsamr7NfwQ==
+
+xml2js@0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.0.tgz#07afc447a97d2bd6507a1f76eeadddb09f7a8282"
+ integrity sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==
+ dependencies:
+ sax ">=0.6.0"
+ xmlbuilder "~11.0.0"
+
+xmlbuilder@^15.1.1:
+ version "15.1.1"
+ resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5"
+ integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==
+
+xmlbuilder@~11.0.0:
+ version "11.0.1"
+ resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3"
+ integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==
+
y18n@^4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"
@@ -6979,7 +8070,7 @@ yargs@^16.1.1:
y18n "^5.0.5"
yargs-parser "^20.2.2"
-yargs@^17.3.1, yargs@^17.6.2:
+yargs@^17.3.1, yargs@^17.6.2, yargs@^17.7.2:
version "17.7.3"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.3.tgz#779dffe6bcafec596a7172e983289a588647faaa"
integrity sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==