diff --git a/android/app/release/app-release.apk b/android/app/release/app-release.apk
deleted file mode 100644
index 3fa37e6..0000000
Binary files a/android/app/release/app-release.apk and /dev/null differ
diff --git a/android/app/release/baselineProfiles/0/app-release.dm b/android/app/release/baselineProfiles/0/app-release.dm
deleted file mode 100644
index 5b14806..0000000
Binary files a/android/app/release/baselineProfiles/0/app-release.dm and /dev/null differ
diff --git a/android/app/release/baselineProfiles/1/app-release.dm b/android/app/release/baselineProfiles/1/app-release.dm
deleted file mode 100644
index d504419..0000000
Binary files a/android/app/release/baselineProfiles/1/app-release.dm and /dev/null differ
diff --git a/android/app/release/output-metadata.json b/android/app/release/output-metadata.json
deleted file mode 100644
index 8c8d5bf..0000000
--- a/android/app/release/output-metadata.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "version": 3,
- "artifactType": {
- "type": "APK",
- "kind": "Directory"
- },
- "applicationId": "com.procure",
- "variantName": "release",
- "elements": [
- {
- "type": "SINGLE",
- "filters": [],
- "attributes": [],
- "versionCode": 1,
- "versionName": "1.0",
- "outputFile": "app-release.apk"
- }
- ],
- "elementType": "File",
- "baselineProfiles": [
- {
- "minApi": 28,
- "maxApi": 30,
- "baselineProfiles": [
- "baselineProfiles/1/app-release.dm"
- ]
- },
- {
- "minApi": 31,
- "maxApi": 2147483647,
- "baselineProfiles": [
- "baselineProfiles/0/app-release.dm"
- ]
- }
- ],
- "minSdkVersionForDexing": 24
-}
\ No newline at end of file
diff --git a/android/app/src/debug/res/xml/network_security_config.xml b/android/app/src/debug/res/xml/network_security_config.xml
new file mode 100644
index 0000000..ce127bc
--- /dev/null
+++ b/android/app/src/debug/res/xml/network_security_config.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 86fcf14..15c600a 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -16,6 +16,8 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme"
+ android:usesCleartextTraffic="true"
+ android:networkSecurityConfig="@xml/network_security_config"
android:supportsRtl="true">
+
+
+
+
diff --git a/package-lock.json b/package-lock.json
index cc87f4e..33c4651 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,6 +16,7 @@
"@react-navigation/bottom-tabs": "7.9.0",
"@react-navigation/drawer": "^7.8.1",
"@react-navigation/native": "^7.1.28",
+ "@react-navigation/native-stack": "^7.17.3",
"@react-navigation/stack": "7.6.13",
"@reduxjs/toolkit": "2.11.2",
"@stomp/stompjs": "7.2.1",
@@ -3666,12 +3667,12 @@
}
},
"node_modules/@react-navigation/core": {
- "version": "7.17.2",
- "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.17.2.tgz",
- "integrity": "sha512-Rt2OZwcgOmjv401uLGAKaRM6xo0fiBce/A7LfRHI1oe5FV+KooWcgAoZ2XOtgKj6UzVMuQWt3b2e6rxo/mDJRA==",
+ "version": "7.20.0",
+ "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.20.0.tgz",
+ "integrity": "sha512-Lqw5cDQWWxiQnaWv6RhQV95Wr4fh+38/IFVNn1grssyLWV+wXGJjlucXOoU7EVh9jdtcLT8pGyzvsyrvSDywWA==",
"license": "MIT",
"dependencies": {
- "@react-navigation/routers": "^7.5.3",
+ "@react-navigation/routers": "^7.6.0",
"escape-string-regexp": "^4.0.0",
"fast-deep-equal": "^3.1.3",
"nanoid": "^3.3.11",
@@ -3706,9 +3707,9 @@
}
},
"node_modules/@react-navigation/elements": {
- "version": "2.9.15",
- "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.9.15.tgz",
- "integrity": "sha512-cyz/pPiyyC6gaTVLsGFc1g0MYgrmuCFqklAWGXMWPscr5YU3ui94vPI4vnZwcsEy0T758TQWLzmS5XudZeRKcA==",
+ "version": "2.9.23",
+ "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.9.23.tgz",
+ "integrity": "sha512-sp+FgihDyMBoEXoCUsUCT/iibN/sg6LYGq/rciy6NjT8bnfv4Cu3el8SAaJ0bfRG3tdchHy6gweKmcaJs/BAYQ==",
"license": "MIT",
"dependencies": {
"color": "^4.2.3",
@@ -3717,7 +3718,7 @@
},
"peerDependencies": {
"@react-native-masked-view/masked-view": ">= 0.2.0",
- "@react-navigation/native": "^7.2.2",
+ "@react-navigation/native": "^7.3.1",
"react": ">= 18.2.0",
"react-native": "*",
"react-native-safe-area-context": ">= 4.0.0"
@@ -3729,15 +3730,16 @@
}
},
"node_modules/@react-navigation/native": {
- "version": "7.2.2",
- "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.2.2.tgz",
- "integrity": "sha512-kem1Ko2BcbAjmbQIv66dNmr6EtfDut3QU0qjsVhMnLLhktwyXb6FzZYp8gTrUb6AvkAbaJoi+BF5Pl55pAUa5w==",
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.3.1.tgz",
+ "integrity": "sha512-g1o8jBm87WviR0Eq0wT0M43TSi+uBTz4x8YfHh4XRQ+FHqhNr+uGbuxtGu72QhHtOz0LWnb8UWyvd+M6xWkWHQ==",
"license": "MIT",
"dependencies": {
- "@react-navigation/core": "^7.17.2",
+ "@react-navigation/core": "^7.20.0",
"escape-string-regexp": "^4.0.0",
"fast-deep-equal": "^3.1.3",
"nanoid": "^3.3.11",
+ "standard-navigation": "^0.0.7",
"use-latest-callback": "^0.2.4"
},
"peerDependencies": {
@@ -3745,10 +3747,29 @@
"react-native": "*"
}
},
+ "node_modules/@react-navigation/native-stack": {
+ "version": "7.17.3",
+ "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-7.17.3.tgz",
+ "integrity": "sha512-8X9AxW0BACB62eCL+DAL+Nf5lFAxXi3w1qaj2D/i0axYjxUZbI5AwrfuHjRo0B231K5WWa6HKyscF07IDHcKHg==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-navigation/elements": "^2.9.23",
+ "color": "^4.2.3",
+ "sf-symbols-typescript": "^2.1.0",
+ "warn-once": "^0.1.1"
+ },
+ "peerDependencies": {
+ "@react-navigation/native": "^7.3.1",
+ "react": ">= 18.2.0",
+ "react-native": "*",
+ "react-native-safe-area-context": ">= 4.0.0",
+ "react-native-screens": ">= 4.0.0"
+ }
+ },
"node_modules/@react-navigation/routers": {
- "version": "7.5.3",
- "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.5.3.tgz",
- "integrity": "sha512-1tJHg4KKRJuQ1/EvJxatrMef3NZXEPzwUIUZ3n1yJ2t7Q97siwRtbynRpQG9/69ebbtiZ8W3ScOZF/OmhvM4Rg==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.6.0.tgz",
+ "integrity": "sha512-lblhDXfS75jLc7G2K7BZGM+7cjqQXk13X/MA4fq/12r62zM+fBhhreLzYflSitrDDXFRJpSvJXy0ziiGU04Xow==",
"license": "MIT",
"dependencies": {
"nanoid": "^3.3.11"
@@ -14334,6 +14355,12 @@
"node": ">=8"
}
},
+ "node_modules/standard-navigation": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/standard-navigation/-/standard-navigation-0.0.7.tgz",
+ "integrity": "sha512-NCGLCNyuXrFOkGHxdNZFnpsehGtiq1oXbPhKl7ZuxFO5J//H2evqqOchmD4YwEUJnkjO4kH9Xp4hQX6hdAYCKQ==",
+ "license": "MIT"
+ },
"node_modules/statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
diff --git a/package.json b/package.json
index af3a034..e6803ba 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,7 @@
"@react-navigation/bottom-tabs": "7.9.0",
"@react-navigation/drawer": "^7.8.1",
"@react-navigation/native": "^7.1.28",
+ "@react-navigation/native-stack": "^7.17.3",
"@react-navigation/stack": "7.6.13",
"@reduxjs/toolkit": "2.11.2",
"@stomp/stompjs": "7.2.1",
diff --git a/src/Axios/Axios.ts b/src/Axios/Axios.ts
index cd34618..025b23e 100644
--- a/src/Axios/Axios.ts
+++ b/src/Axios/Axios.ts
@@ -5,6 +5,98 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
import { resetAndNavigate } from '../Navigation/NavigationService';
import NavigationString from '../Constant/NavigationString';
+// ============================================================
+// GLOBAL API LOGGER
+// Logs EVERY axios call (apiCall wrapper + direct axios.*),
+// including full URL, method, payload, params, headers,
+// response data and full error response.
+// React-Native friendly (no %c CSS β that doesn't work in Metro/Logcat).
+// ============================================================
+
+// Build the full URL exactly as it goes on the wire: baseURL + url + ?query
+const buildFullUrl = (config: any = {}): string => {
+ const base = config.baseURL || '';
+ const path = config.url || '';
+ let full = base ? `${base.replace(/\/$/, '')}/${path.replace(/^\//, '')}` : path;
+
+ const params = config.params;
+ if (params && typeof params === 'object') {
+ const qs = Object.keys(params)
+ .filter(k => params[k] !== undefined && params[k] !== null)
+ .map(k => `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`)
+ .join('&');
+ if (qs) full += (full.includes('?') ? '&' : '?') + qs;
+ }
+ return full;
+};
+
+// Make any payload safe/readable for logging. console.log already handles
+// nested objects and circular refs, so we only special-case FormData
+// (which otherwise prints as an opaque object).
+const safe = (val: any): any => {
+ if (val == null) return val;
+ if (typeof FormData !== 'undefined' && val instanceof FormData) {
+ const parts = (val as any)?._parts;
+ return Array.isArray(parts)
+ ? `[FormData] ${parts.map((p: any) => p?.[0]).join(', ')}`
+ : '[FormData]';
+ }
+ return val;
+};
+
+// Register interceptors only once (module may be re-imported on fast-refresh)
+const g: any = globalThis as any;
+if (!g.__API_LOGGER_INSTALLED__) {
+ g.__API_LOGGER_INSTALLED__ = true;
+
+ axios.interceptors.request.use(
+ config => {
+ const method = (config.method || 'GET').toUpperCase();
+ const fullUrl = buildFullUrl(config);
+ console.log('\n==================== π API REQUEST ====================');
+ console.log('METHOD β', method);
+ console.log('FULL URL β', fullUrl);
+ console.log('PARAMS β', safe(config.params) ?? {});
+ console.log('PAYLOAD β', safe(config.data) ?? {});
+ console.log('HEADERS β', safe(config.headers) ?? {});
+ console.log('========================================================');
+ return config;
+ },
+ error => {
+ console.log('β REQUEST SETUP ERROR β', error?.message, error);
+ return Promise.reject(error);
+ },
+ );
+
+ axios.interceptors.response.use(
+ response => {
+ const method = (response.config.method || 'GET').toUpperCase();
+ const fullUrl = buildFullUrl(response.config);
+ console.log('\n==================== β
API RESPONSE ====================');
+ console.log('METHOD β', method);
+ console.log('FULL URL β', fullUrl);
+ console.log('STATUS β', response.status);
+ console.log('RESPONSE β', safe(response.data));
+ console.log('=========================================================');
+ return response;
+ },
+ error => {
+ const cfg = error?.config || {};
+ const method = (cfg.method || 'GET').toUpperCase();
+ const fullUrl = buildFullUrl(cfg);
+ console.log('\n==================== β API ERROR ====================');
+ console.log('METHOD β', method);
+ console.log('FULL URL β', fullUrl);
+ console.log('REQ PAYLOADβ', safe(cfg.data) ?? {});
+ console.log('STATUS β', error?.response?.status ?? 'NO RESPONSE / NETWORK');
+ console.log('MESSAGE β', error?.response?.data?.message || error?.message);
+ console.log('ERROR DATA β', safe(error?.response?.data));
+ console.log('FULL ERROR β', error?.toJSON ? error.toJSON() : safe(error));
+ console.log('======================================================');
+ return Promise.reject(error);
+ },
+ );
+}
export const apiCall = async (
method: 'get' | 'post' | 'patch' | 'delete' | 'put',
@@ -15,26 +107,8 @@ export const apiCall = async (
): Promise => {
const token: any = store.getState().token.token;
- // π₯ ONE MAIN GROUP FOR ENTIRE API CALL
- console.group(
- `%cπ API CALL β ${method.toUpperCase()} ${url}`,
- 'color:#0ea5e9;font-weight:bold'
- );
-
- // ===== REQUEST =====
- console.group('π€ REQUEST');
- console.log('%cMETHOD β', 'color:#22c55e;font-weight:bold', method);
- console.log('%cURL β', 'color:#22c55e;font-weight:bold', url);
- console.log('%cPARAMS β', 'color:#f59e0b;font-weight:bold', params);
- console.log('%cPAYLOAD β', 'color:#a855f7;font-weight:bold', data);
- console.log(
- '%cTOKEN β',
- 'color:#ef4444;font-weight:bold',
- token?.token ? 'β PRESENT' : 'β MISSING'
- );
- console.groupEnd();
-
try {
+ // Request/response/error are logged globally by the axios interceptors above.
const response = await axios({
method,
url,
@@ -46,64 +120,18 @@ export const apiCall = async (
},
});
- // ===== RESPONSE =====
- console.group('π₯ RESPONSE');
- console.log(
- '%cSTATUS β',
- 'color:#22c55e;font-weight:bold',
- response.status
- );
- console.log(
- '%cRESPONSE DATA β',
- 'color:#0ea5e9;font-weight:bold',
- response.data
- );
- console.groupEnd();
-
- console.groupEnd(); // π MAIN GROUP
return response.data;
} catch (error: any) {
- // ===== ERROR =====
- console.group('β ERROR');
- console.error(
- '%cSTATUS β',
- 'color:#ef4444;font-weight:bold',
- error?.response?.status
- );
- console.error(
- '%cMESSAGE β',
- 'color:#f97316;font-weight:bold',
- error?.response?.data?.message || error.message
- );
- console.error(
- '%cERROR DATA β',
- 'color:#fb7185;font-weight:bold',
- error?.response?.data
- );
- console.error(
- '%cFULL ERROR β',
- 'color:#7c2d12;font-weight:bold',
- error
- );
- console.groupEnd();
-
// ===== AUTH ERROR =====
if (error?.response?.status === 401) {
- console.warn(
- '%cβ JWT ERROR β Token expired or malformed',
- 'color:#eab308;font-weight:bold'
- );
+ console.warn('β JWT ERROR β Token expired or malformed');
store.dispatch(setToken({}));
- console.groupEnd(); // π MAIN GROUP
return {
success: false,
message: 'JWT Error - Token expired or malformed',
} as R;
}
-
-
- console.groupEnd(); // π MAIN GROUP
return {
success: false,
message:
diff --git a/src/Navigation/Bottom.tsx b/src/Navigation/Bottom.tsx
index ed6114e..20dc7cb 100644
--- a/src/Navigation/Bottom.tsx
+++ b/src/Navigation/Bottom.tsx
@@ -193,6 +193,8 @@ export default function BottomTab() {
screenOptions={{
headerShown: false,
tabBarHideOnKeyboard: true,
+ // Smooth cross-fade when switching tabs instead of an instant cut.
+ animation: 'shift',
}}
>
diff --git a/src/Navigation/MainStack.jsx b/src/Navigation/MainStack.jsx
index 3c4a542..e5c1041 100644
--- a/src/Navigation/MainStack.jsx
+++ b/src/Navigation/MainStack.jsx
@@ -1,42 +1,49 @@
import * as React from 'react';
-import { createStackNavigator } from '@react-navigation/stack';
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
import NavigationString from '../Constant/NavigationString';
import Screens from '../Screens';
import colors from '../Constant/Color';
import BottomTab from './Bottom';
import Login from '../Screens/Login/Login';
+const Stack = createNativeStackNavigator();
+
export default function MainStack() {
- const Stack = createStackNavigator();
- const option = { headerShown: false };
- // ...
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/src/Screens/Login/Login.tsx b/src/Screens/Login/Login.tsx
index 8f8678f..7d98094 100644
--- a/src/Screens/Login/Login.tsx
+++ b/src/Screens/Login/Login.tsx
@@ -1,5 +1,5 @@
import React, { useState, useEffect, useCallback } from 'react';
-import { View, Text, StyleSheet, KeyboardAvoidingView, Platform, ScrollView, TouchableOpacity, Dimensions, StatusBar, TextInput, Image } from 'react-native';
+import { View, Text, StyleSheet, KeyboardAvoidingView, Platform, ScrollView, TouchableOpacity, Dimensions, StatusBar, TextInput, Image, ActivityIndicator, Keyboard } from 'react-native';
import { Formik } from 'formik';
import * as Yup from 'yup';
import { useDispatch } from 'react-redux';
@@ -43,7 +43,7 @@ const Login = () => {
const [passwordVisible, setPasswordVisible] = useState(false);
const [showForm, setShowForm] = useState(false);
const [activeSlide, setActiveSlide] = useState(0);
- const { mutateAsync: registrationStateMutate } = useRagistrationState();
+ const { mutateAsync: registrationStateMutate, isPending: isResolvingRoute } = useRagistrationState();
useEffect(() => {
if (showForm) return;
@@ -211,6 +211,9 @@ const Login = () => {
const handleSuccess = (res: any) => {
dispatch(setToken({ ...res.data, token: res.token, userType: 'tender' }));
console.log('handleSuccess', res)
+ console.log('==================== π AUTH TOKEN ====================');
+ console.log('TOKEN β', res?.token);
+ console.log('=======================================================');
if (res.statusCode === 200) {
handleGetData()
} else {
@@ -219,12 +222,18 @@ const Login = () => {
};
const handleLogin = (values: any) => {
+ if (isLoading) return; // guard against double submit
+ Keyboard.dismiss(); // smooth the navigation transition (no keyboard mid-replace)
const payload = { emailAdd: values.email, password: values.password, device: "mobileApp" };
console.log('payload------------', payload)
loginMutation.mutate(payload);
};
- const isLoading = loginMutation.isPending;
+ // Covers the WHOLE sign-in flow: login request + registration-state resolve
+ // (+ the brief moment before navigation.replace swaps the screen). Without
+ // this, the button reverts to "SIGN IN" between the two requests, which is
+ // the flicker/glitch the user sees.
+ const isLoading = loginMutation.isPending || isResolvingRoute;
// Minimal Input Component (Enhanced for better aesthetics)
const MinimalInput = ({ placeholder, value, onChangeText, onBlur, icon, secureTextEntry, rightIcon, onRightIconPress }: any) => {
@@ -375,7 +384,7 @@ const Login = () => {
- Welcome Back
+ Welcome
Sign in to your account
{
handleSubmit()}
+ disabled={isLoading}
style={styles.loginBtnContainer}
>
-
- {isLoading ? 'Wait...' : 'SIGN IN'}
-
- {!isLoading && }
+ {isLoading ? (
+ <>
+
+
+ SIGNING IN
+
+ >
+ ) : (
+ <>
+ SIGN IN
+
+ >
+ )}
@@ -445,6 +464,17 @@ const Login = () => {
+
+ {/* Full-screen loader β covers the whole loginβresolveβnavigate flow so
+ the user never sees a half-rendered state or the navigation flicker */}
+ {isLoading && (
+
+
+
+ Signing inβ¦
+
+
+ )}
);
};
@@ -688,10 +718,41 @@ const styles = StyleSheet.create({
letterSpacing: 1.5,
textTransform: 'uppercase',
},
+ loginBtnTextLoading: {
+ marginLeft: 12,
+ },
arrowIcon: {
marginLeft: 12,
},
+ // FULL-SCREEN LOADER OVERLAY
+ loaderOverlay: {
+ ...StyleSheet.absoluteFillObject,
+ backgroundColor: 'rgba(0, 0, 0, 0.35)',
+ alignItems: 'center',
+ justifyContent: 'center',
+ zIndex: 999,
+ },
+ loaderCard: {
+ paddingVertical: 24,
+ paddingHorizontal: 32,
+ borderRadius: 20,
+ backgroundColor: 'rgba(255, 255, 255, 0.95)',
+ alignItems: 'center',
+ justifyContent: 'center',
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 8 },
+ shadowOpacity: 0.2,
+ shadowRadius: 16,
+ elevation: 10,
+ },
+ loaderText: {
+ marginTop: 12,
+ fontSize: 15,
+ fontWeight: '600',
+ fontFamily: FontsFamily.poppinsMedium,
+ },
+
// FOOTER
footer: {
flexDirection: 'row',
diff --git a/src/Services/ApiCall/ApiUrls.tsx b/src/Services/ApiCall/ApiUrls.tsx
index e518fa2..d867022 100644
--- a/src/Services/ApiCall/ApiUrls.tsx
+++ b/src/Services/ApiCall/ApiUrls.tsx
@@ -1,5 +1,5 @@
// const BASE_URL = `http://192.168.6.194:8090/`
-const BASE_URL = `http://java-backend-main.lincpay/`
+const BASE_URL = `https://eproc.godemo.in/`
// const BASE_URL = `http://192.168.6.194/AuctionPostgre/api/auction/`
// export const BASE_URL = `https://procurelinc.in/Auction/`
// const BASE_URL = `http://192.168.29.226:8090/`
@@ -25,7 +25,7 @@ const CONTRACTOR_BASIC_PROFILE = `${BASE_URL}contractor/getContractorById?contId
const CONTRACTOR_PROFILE_UPDATE = `${BASE_URL}contractor/updateContBasicDetails?id=`
const GET_REGISTRATION_STATE = `${BASE_URL}contractor/getContractorOrgTypeandStatus`
const GET_MASTER_DATA = `${BASE_URL}contractor/masterdata/all`
-const GET_TENDER_BY_ID = `http://192.168.6.194:8090/eTendering/getTenderById?tenderId=`
+const GET_TENDER_BY_ID = `${BASE_URL}eTendering/getTenderById?tenderId=`
const LOG_IN_URL = `${BASE_URL}auction/loginWithoutDecryption`
const LIVE_TENDER = `${BASE_URL}liveTender/getAllLiveTenders`
const LIVE_AUCTION = `${BASE_URL}api/auction/getLiveAuctionForMobile`