This commit is contained in:
rohit-kumar-fullstack
2026-01-12 15:41:31 +05:30
parent ceb83782b8
commit 5391040b0b
32 changed files with 1107 additions and 696 deletions
+1 -6
View File
@@ -1,5 +1,4 @@
import axios from 'axios';
import { NavigationString, showErrorAlert, Variable } from '../Constant/AllImports';
import { setToken } from '../Redux/Slices/Token';
import { store } from '../Redux/Store';
@@ -12,24 +11,20 @@ export const apiCall = async <R, D = {}>(
): Promise<R> => {
try {
const token: any = store.getState().token.token;
const response = await axios({
method,
url,
data,
params,
// withCredentials: true,
// baseURL: Variable.Main_Base,
headers: {
Authentication: `Bearer ${token?.token}`,
'Content-Type': contentType || 'application/json',
},
});
return response.data;
} catch (error: any) {
const errorMessage = error?.response?.data?.error;
{ error?.response?.data?.error && showErrorAlert(error?.response?.data?.error || '') }
console.log(errorMessage, '---------------------------api error message');
if (error?.response?.status === 401) {
store.dispatch(setToken({}));
+1 -8
View File
@@ -1,12 +1,5 @@
import React, { FC, useRef, useEffect } from 'react';
import {
StyleSheet,
Text,
View,
TouchableOpacity,
Animated,
Platform,
} from 'react-native';
import { StyleSheet, Text, View, TouchableOpacity, Animated, Platform } from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
import { BlurView } from '@react-native-community/blur';
import colors from '../../Constant/Color';
+2 -2
View File
@@ -7,10 +7,10 @@ import LottieView from 'lottie-react-native';
interface CountdownTimerProps {
endDate: string;
myStyle?: any
size?: number // Expected format: "DD-MM-YYYY HH:mm:ss"
size?: number
}
const CountdownTimer: React.FC<CountdownTimerProps> = React.memo(({ endDate, myStyle = {}, size = 20 }) => {
const CountdownTimer: React.FC<CountdownTimerProps> = React.memo(({ endDate, myStyle = {}, size = 20 }) => {
const calculateTimeLeft = useCallback(() => {
if (!endDate) return null;
+1 -8
View File
@@ -1,12 +1,5 @@
import React, { useState } from 'react';
import {
View,
Text,
TouchableOpacity,
Image,
StyleSheet,
Dimensions,
} from 'react-native';
import { View, Text, TouchableOpacity, Image, StyleSheet, Dimensions } from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { Menu } from 'lucide-react-native';
+2 -9
View File
@@ -1,12 +1,5 @@
import React from 'react';
import {
View,
Text,
TouchableOpacity,
Image,
StyleSheet,
Dimensions,
} from 'react-native';
import { View, Text, TouchableOpacity, Image, StyleSheet, Dimensions } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { ArrowLeft } from 'lucide-react-native';
import colors from '../../Constant/Color';
@@ -23,7 +16,7 @@ interface HeaderProps {
}
const InsideHeader: React.FC<HeaderProps> = ({ title, showArrow = false }) => {
const navigation:any = useNavigation();
const navigation: any = useNavigation();
const insets = useSafeAreaInsets();
return (
@@ -1,10 +1,8 @@
import React from "react";
import { View, Text, StyleSheet, TouchableOpacity, Dimensions } from "react-native";
import { View, Text, StyleSheet, TouchableOpacity } from "react-native";
import LottieView from "lottie-react-native";
import LinearGradient from "react-native-linear-gradient";
const { width } = Dimensions.get("window");
const InternetConnectivity = () => {
return (
<View style={styles.container}>
@@ -1,42 +1,16 @@
import React from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Dimensions,
ScrollView,
StatusBar,
} from 'react-native';
import { View, Text, StyleSheet, TouchableOpacity, Dimensions, ScrollView, StatusBar } from 'react-native';
import LottieView from 'lottie-react-native';
import LinearGradient from 'react-native-linear-gradient';
import {
AlertCircle,
Clock,
Server,
Calendar,
RefreshCw,
MessageCircle,
Twitter,
Activity,
MessageSquare,
Bell,
WifiOff,
} from 'lucide-react-native';
import Colors from '../../Styles/Color';
import { AlertCircle, Clock, RefreshCw, Activity } from 'lucide-react-native';
import colors from '../../Constant/Color';
import FontsFamily from '../../Constant/FontsFamily';
const {width} = Dimensions.get('window');
const ServerDown = () => {
return (
<>
<StatusBar
// translucent={true}
// backgroundColor="transparent"
barStyle="dark-content"
/>
<StatusBar barStyle="dark-content" />
<ScrollView
contentContainerStyle={styles.scrollContainer}
showsVerticalScrollIndicator={false}>
@@ -81,12 +55,12 @@ const ServerDown = () => {
<View style={styles.buttonGroup}>
<TouchableOpacity
activeOpacity={0.7}
onPress={() => {}}
onPress={() => { }}
style={styles.touchable}>
<LinearGradient
colors={[Colors.appColourDark, Colors.appColourDarkDim]}
start={{x: 0, y: 0}}
end={{x: 1, y: 0}}
colors={[colors.primary, colors.primaryLight]}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
style={styles.primaryButton}>
<RefreshCw
size={20}
@@ -140,9 +114,9 @@ const styles = StyleSheet.create({
paddingVertical: 36,
paddingHorizontal: 28,
alignItems: 'center',
shadowColor: Colors.appColourDark,
shadowColor: colors.primary,
shadowOpacity: 0.08,
shadowOffset: {width: 0, height: 12},
shadowOffset: { width: 0, height: 12 },
shadowRadius: 24,
elevation: 10,
borderWidth: 1,
@@ -162,18 +136,18 @@ const styles = StyleSheet.create({
width: 60,
height: 60,
borderRadius: 30,
backgroundColor: Colors.appColourDark,
backgroundColor: colors.primary,
opacity: 0.2,
},
statusDot: {
width: 44,
height: 44,
borderRadius: 22,
backgroundColor: Colors.appColourDarkDim,
backgroundColor: colors.primary,
alignItems: 'center',
justifyContent: 'center',
shadowColor: Colors.appColourDark,
shadowOffset: {width: 0, height: 4},
shadowColor: colors.primary,
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.3,
shadowRadius: 8,
elevation: 6,
@@ -310,7 +284,7 @@ const styles = StyleSheet.create({
touchable: {
width: '100%',
shadowColor: '#FF6B6B',
shadowOffset: {width: 0, height: 4},
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.3,
shadowRadius: 8,
elevation: 6,
+1
View File
@@ -1,5 +1,6 @@
import React from 'react';
import { View, ActivityIndicator } from 'react-native';
interface LoaderType {
size?: 'small' | 'large';
color?: string;
+106
View File
@@ -0,0 +1,106 @@
import { StyleSheet, TextInput, View, TextInputProps, TouchableOpacity } from 'react-native';
import React from 'react';
type MyInputProps = {
icon?: string;
placeholder?: string;
value?: string;
onChangeText?: (text: string) => void;
isVarify?: boolean;
maxlength?: number;
onFocus?: () => void;
onBlur?: () => void;
focused?: boolean;
keyboardType?: TextInputProps['keyboardType'];
editable?: boolean;
autoCapitalize?: TextInputProps['autoCapitalize'];
rightIcon?: string,
rightIconPress?: () => void
} & TextInputProps;
const MyInput: React.FC<MyInputProps> = ({
icon,
placeholder,
value,
onChangeText,
isVarify,
maxlength,
onFocus,
onBlur,
focused,
keyboardType,
editable = true,
autoCapitalize,
rightIcon,
rightIconPress,
...textInputProps
}) => {
return (
<View
style={[
styles.inputWrapper,
focused && styles.inputFocused,
!editable && styles.inputDisabled,
]}
>
{/* <Icon
name={icon}
size={18}
color={focused ? "#0000" : '#aaa'}
style={styles.icon}
/> */}
<TextInput
{...textInputProps}
placeholder={placeholder}
style={[styles.input, !editable && { color: '#999' }]}
placeholderTextColor="#aaa"
value={value}
onChangeText={onChangeText}
maxLength={maxlength}
editable={editable}
onFocus={onFocus}
onBlur={onBlur}
keyboardType={keyboardType}
autoCapitalize={autoCapitalize}
/>
{
rightIcon ?
<TouchableOpacity onPress={rightIconPress}>
</TouchableOpacity>
: null}
</View>
);
};
export default MyInput;
const styles = StyleSheet.create({
inputWrapper: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#fff',
borderRadius: 12,
borderWidth: 1,
borderColor: '#e0e0e0',
paddingHorizontal: 10,
marginVertical: 10,
height: 55,
},
icon: {
marginRight: 10,
},
input: {
flex: 1,
fontSize: 15,
color: '#000',
paddingVertical: 0,
},
inputFocused: {
borderColor: '#007BFF',
},
inputDisabled: {
backgroundColor: '#f2f2f2',
},
});
+3 -15
View File
@@ -1,12 +1,7 @@
import { Filter, Search } from "lucide-react-native";
import React from "react";
import { View, Text, TextInput, StyleSheet, TouchableOpacity, Platform } from "react-native";
import Animated, {
useAnimatedStyle,
useSharedValue,
withTiming,
interpolateColor
} from "react-native-reanimated";
import Animated, { useAnimatedStyle, useSharedValue, withTiming, interpolateColor } from "react-native-reanimated";
import colors from "../../Constant/Color";
export interface SearchType {
@@ -19,21 +14,14 @@ export interface SearchType {
const AnimatedView = Animated.createAnimatedComponent(View);
export const SearchInput: React.FC<SearchType> = ({
placeholder,
onChange,
label,
filter = true,
filterPress
}) => {
export const SearchInput: React.FC<SearchType> = ({ placeholder, onChange, label, filter = true, filterPress }) => {
const isFocused = useSharedValue(0);
// Animate border color and shadow based on focus
const inputContainerStyle = useAnimatedStyle(() => {
const borderColor = interpolateColor(
isFocused.value,
[0, 1],
[colors.grayText + '50', colors.grayText] // Assuming colors.primary exists
[colors.grayText + '50', colors.grayText]
);
return {
-2
View File
@@ -143,8 +143,6 @@ const SideDrawer: React.FC<Props> = ({ visible, onClose }) => {
export default SideDrawer;
/* ================= Styles ================= */
const styles = StyleSheet.create({
modal: {
margin: 0,
-54
View File
@@ -1,54 +0,0 @@
import React, { useEffect, useRef } from 'react';
import { Animated, Text, StyleSheet } from 'react-native';
import colors from '../../Constant/Color';
interface AuctionItemProps {
item: any;
index: number;
}
const AuctionItem: React.FC<AuctionItemProps> = ({ item, index }) => {
const scale = useRef(new Animated.Value(0)).current;
useEffect(() => {
Animated.spring(scale, {
toValue: 1,
friction: 8,
useNativeDriver: true,
delay: index * 50,
}).start();
}, []);
return (
<Animated.View style={[styles.itemCard, { transform: [{ scale }] }]}>
<Text style={styles.itemTitle}>{item.title || `${item.auctionNumber}`}</Text>
<Text style={styles.itemDate}>End Date: {item.purchaseEnd || 'N/A'} </Text>
</Animated.View>
);
};
export default AuctionItem;
const styles = StyleSheet.create({
itemCard: {
backgroundColor: '#fff',
padding: 18,
borderRadius: 16,
marginBottom: 14,
shadowColor: '#000',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.12,
shadowRadius: 8,
elevation: 4,
},
itemTitle: {
fontSize: 16,
fontWeight: '700',
marginBottom: 4,
color: '#020617',
},
itemDate: {
fontSize: 13,
color: '#64748b',
},
});
+4
View File
@@ -34,6 +34,10 @@ const colors = {
Orange: '#F97316',
OrangeLight: '#FDBA74',
OrangeSoft: '#FFF3E8',
darkGray: '#5f6368',
lightestGray: '#f1f3f4',
successLight: '#e6f4ea',
};
export default colors;
+26
View File
@@ -0,0 +1,26 @@
import moment from 'moment';
export const format = {
// Internal helper to safely parse any input
parse: (date: string | Date) => {
if (!date) return null;
let d = date;
if (typeof date === 'string') {
// Replace IST or other known timezone abbreviations with UTC offset
d = date.replace('IST', '+0530');
}
return moment(d);
},
date1: (date: string | Date) => format.parse(date)?.format('DD-MM-YYYY'),
date2: (date: string | Date) => format.parse(date)?.format('YYYY-MM-DD'),
date3: (date: string | Date) => format.parse(date)?.format('MMMM Do, YYYY'),
date4: (date: string | Date) => format.parse(date)?.format('dddd, MMMM Do YYYY'),
date5: (date: string | Date) => format.parse(date)?.format('MM/DD/YYYY'),
date6: (date: string | Date) => format.parse(date)?.format('YYYY/MM/DD HH:mm'),
time1: (date: string | Date) => format.parse(date)?.format('hh:mm A'),
time2: (date: string | Date) => format.parse(date)?.format('HH:mm:ss'),
iso: (date: string | Date) => format.parse(date)?.toISOString(),
fromNow: (date: string | Date) => format.parse(date)?.fromNow(),
custom: (date: string | Date, formatStr: string) => format.parse(date)?.format(formatStr),
};
+3
View File
@@ -12,6 +12,7 @@ import * as LucideIcons from 'lucide-react-native';
import Screens from '../Screens';
import colors from '../Constant/Color';
import NavigationString from '../Constant/NavigationString';
import EditableExcel from '../Screens/Tender/Component/EditableExcel';
const { width } = Dimensions.get('window');
const TAB_BAR_HEIGHT = 60;
@@ -24,6 +25,7 @@ const TabButton = ({ route, isFocused, onPress }: any) => {
Home: { outline: "Home", filled: "Home" },
Auction: { outline: "Gavel", filled: "Gavel" },
Tender: { outline: "FileText", filled: "FileText" },
EditableExcel: { outline: "FileText", filled: "FileText" },
};
const IconName = LucideIcons[isFocused ? icons[route.name].filled : icons[route.name].outline];
const scaleAnim = useRef(new Animated.Value(1)).current;
@@ -146,6 +148,7 @@ export default function BottomTab() {
<Tab.Screen name="Home" component={Screens.Home} />
<Tab.Screen name={NavigationString.Auction} component={Screens.Auction} />
<Tab.Screen name={NavigationString.Tender} component={Screens.Tender} />
<Tab.Screen name={'EditableExcel'} component={EditableExcel} />
</Tab.Navigator>
</View>
);
+27 -27
View File
@@ -1,5 +1,5 @@
import React, { memo, useState } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, ScrollView, Platform, Dimensions } from 'react-native';
import { View, Text, StyleSheet, TouchableOpacity, ScrollView, Platform } from 'react-native';
import Modal from 'react-native-modal';
import { Package, IndianRupee, FileText, Download, ArrowLeft, Info, } from 'lucide-react-native';
import colors from '../../../Constant/Color';
@@ -11,31 +11,30 @@ import { Loader } from '../../../Component/Index';
interface Props { visible: boolean; onClose: () => void; data?: any; }
const Section = ({ title, icon: Icon, children }: any) => (
<View style={styles.sectionCard}>
<View style={styles.sectionHeader}>
<View style={styles.iconCircle}>
<Icon size={18} color={colors.primary} strokeWidth={2.5} />
</View>
<Text style={styles.sectionTitle}>{title}</Text>
</View>
{children}
</View>
);
const PriceTile = ({ label, fig, words, full = false }: any) => (
<View style={[styles.priceTile, full ? { width: '100%' } : { width: '48%' }]}>
<Text style={styles.label}>{label}</Text>
<Text style={styles.priceFig}>₹{Number(fig).toLocaleString('en-IN')}</Text>
<Text style={styles.priceWords}>{words}</Text>
</View>
);
const AuctionItemDetail: React.FC<Props> = ({ visible, onClose, data }) => {
const inset = useSafeAreaInsets()
const [allBoolean, setAllBoolean] = useState({ fileLoading: false });
const { data: itemData } = useAucitonItemDetail({ auctionItemId: data.id });
const Section = ({ title, icon: Icon, children }: any) => (
<View style={styles.sectionCard}>
<View style={styles.sectionHeader}>
<View style={styles.iconCircle}>
<Icon size={18} color={colors.primary} strokeWidth={2.5} />
</View>
<Text style={styles.sectionTitle}>{title}</Text>
</View>
{children}
</View>
);
const PriceTile = ({ label, fig, words, full = false }: any) => (
<View style={[styles.priceTile, full ? { width: '100%' } : { width: '48%' }]}>
<Text style={styles.label}>{label}</Text>
<Text style={styles.priceFig}>₹{Number(fig).toLocaleString('en-IN')}</Text>
<Text style={styles.priceWords}>{words}</Text>
</View>
);
const handleDownload = async (id: number, fileName: string) => {
try {
setAllBoolean((prev: any) => ({ ...prev, fileLoading: true }));
@@ -79,6 +78,7 @@ const AuctionItemDetail: React.FC<Props> = ({ visible, onClose, data }) => {
setAllBoolean((prev: any) => ({ ...prev, fileLoading: false }));
}
};
console.log(data, 'kkkkk---');
return (
<Modal
@@ -133,16 +133,16 @@ const AuctionItemDetail: React.FC<Props> = ({ visible, onClose, data }) => {
<Section title="Reserve & Bid Values" icon={IndianRupee}>
<PriceTile
label="Reserve Price"
fig={data.reservePrice}
words={data.reservePriceInWords}
label="Bidding Price"
fig={data.reservePrice || data.emdAmount}
words={data.reservePriceInWords || data.emdAmountInWords}
full
/>
<View style={styles.hDivider} />
<PriceTile
label="Auction Start Value"
fig={data.reservePrice}
words={data.reservePriceInWords}
fig={data.reservePrice || data.auctionStartValueFigure}
words={data.reservePriceInWords || data.auctionStartValueWords}
full
/>
<View style={styles.hDivider} />
@@ -165,7 +165,7 @@ const AuctionItemDetail: React.FC<Props> = ({ visible, onClose, data }) => {
</View>
{itemData?.map((doc: any, index: any) => (
<TouchableOpacity style={styles.docRow} activeOpacity={0.7} onPress={() => { handleDownload(doc.assetId, doc.fileName) }} key={index}>
<TouchableOpacity style={styles.docRow} activeOpacity={0.7} onPress={() => { handleDownload(doc.assetId, doc.fileName) }} key={doc.assetId}>
<Text style={styles.docIndex}>{index + 1}</Text>
<View style={{ flex: 2 }}>
<Text style={styles.docTitle} numberOfLines={1}>{doc.fileName}</Text>
+3 -24
View File
@@ -1,30 +1,9 @@
import React, { useEffect } from 'react';
import {
View,
Text,
StyleSheet,
Dimensions,
FlatList,
ActivityIndicator,
} from 'react-native';
import Animated, {
useSharedValue,
useAnimatedStyle,
withDelay,
withTiming,
} from 'react-native-reanimated';
import {
Layers,
Clock,
ShoppingCart,
X,
FileText,
} from 'lucide-react-native';
import { View, Text, StyleSheet, Dimensions, FlatList, ActivityIndicator } from 'react-native';
import Animated, { useSharedValue, useAnimatedStyle, withDelay, withTiming } from 'react-native-reanimated';
import { Layers, Clock, ShoppingCart, X, FileText } from 'lucide-react-native';
import { Header } from '../../Component/Index';
import colors from '../../Constant/Color';
import { useWebSocketService } from '../../socket/Socket';
import Variables from '../../Constant/Variable';
import { useFocusEffect } from '@react-navigation/native';
import { useDashboard } from '../../Services/BBPS/Hooks';
const { width } = Dimensions.get('window');
+3 -4
View File
@@ -1,5 +1,5 @@
import React, { useState } from 'react';
import { View, Text, Dimensions, TextInput, TouchableOpacity, StyleSheet, StatusBar, KeyboardAvoidingView, Platform, ScrollView } from 'react-native';
import { View, Text, Dimensions, TextInput, TouchableOpacity, StyleSheet, KeyboardAvoidingView, Platform, ScrollView } from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
import { Formik } from 'formik';
import * as Yup from 'yup';
@@ -31,14 +31,13 @@ const Login = () => {
const Dispatch = useDispatch()
const [passwordVisible, setPasswordVisible] = React.useState(false);
const [loading, setLoading] = useState(false)
const { mutate, isPending } = useLogin()
const { mutate } = useLogin()
const HandleLogin = async (values: any) => {
setLoading(true)
mutate({ password: values.password, emailAdd: values.email }, {
onSuccess: (res) => {
if (res.statusCode == 200) {
console.log("login token : ", res)
Dispatch(setToken({ ...res.data, token: res.token }))
Navigation.dispatch(
CommonActions.reset({
@@ -153,7 +152,7 @@ const Login = () => {
style={styles.button}
>
{
loading ? <Loader color={colors.white} size='small'/> : <>
loading ? <Loader color={colors.white} size='small' /> : <>
<Text style={styles.buttonText}>Sign In</Text>
<ArrowRight size={20} color={colors.white} style={{ marginLeft: 8, marginTop: 5 }} /></>
}
@@ -0,0 +1,187 @@
import React, { useEffect, useState } from 'react';
import {
View,
Text,
TextInput,
ScrollView,
TouchableOpacity,
StyleSheet,
ActivityIndicator,
Alert,
} from 'react-native';
import RNFS from 'react-native-fs';
import * as XLSX from 'xlsx';
import axios from 'axios';
const EXCEL_API_URL = 'https://procurelinc.in/EProcurementSB/eTendering/getEnvelopeCTemplate/tenderId';
const EnvelopeCExcelPreview = () => {
const [data, setData] = useState<any[]>([]);
const [columns, setColumns] = useState<string[]>([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
loadExcelFromApi();
}, []);
// 📥 FETCH EXCEL BLOB + READ
const loadExcelFromApi = async () => {
try {
setLoading(true);
const urlWithParams = `${EXCEL_API_URL}?tenderId=2479`;
// ⬇️ Fetch Excel as blob
const response = await axios.get(urlWithParams, {
responseType: 'arraybuffer',
headers: {
Authorization: `Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJBQklOVE9QUE85NkBHTUFJTC5DT00iLCJpYXQiOjE3Njc5MzgzMDMsImV4cCI6MTc2Nzk3NDMwM30.NiT5iOIdQH0y8TutLfLVp9ApQIAI3NHbkmRjb1fl-JlGxeyX21n3oPGvU6sDw_uU9iTZHI183e2FH_IL2sZYpQ`,
},
});
console.log(response, '--------------------------------------');
// ⬇️ Save file locally
const filePath = `${RNFS.DocumentDirectoryPath}/envelopeC.xlsx`;
const buffer = Buffer.from(response.data, 'binary'); // convert arraybuffer to buffer
await RNFS.writeFile(filePath, buffer.toString('base64'), 'base64');
// 📖 Read Excel
const workbook = XLSX.readFile(filePath);
const sheet = workbook.Sheets[workbook.SheetNames[0]];
const jsonData: any[] = XLSX.utils.sheet_to_json(sheet, { defval: '' });
setData(jsonData);
setColumns(Object.keys(jsonData[0] || {}));
} catch (error: any) {
console.log('Excel load error:', error);
Alert.alert('Error', error.message || 'Unable to load Excel');
} finally {
setLoading(false);
}
};
// ✏️ UPDATE CELL
const updateCell = (rowIndex: number, key: string, value: string) => {
const updated = [...data];
updated[rowIndex][key] = value;
setData(updated);
};
// 💾 SAVE UPDATED EXCEL (LOCAL)
const saveUpdatedExcel = async () => {
try {
setLoading(true);
const worksheet = XLSX.utils.json_to_sheet(data);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
const base64Excel = XLSX.write(workbook, { bookType: 'xlsx', type: 'base64' });
const updatedPath = `${RNFS.DocumentDirectoryPath}/envelopeC_updated.xlsx`;
await RNFS.writeFile(updatedPath, base64Excel, 'base64');
Alert.alert('Success', 'Updated Excel saved successfully');
console.log('Saved at:', updatedPath);
} catch (error) {
console.log('Save error:', error);
Alert.alert('Error', 'Failed to save Excel');
} finally {
setLoading(false);
}
};
if (loading) {
return (
<View style={styles.loader}>
<ActivityIndicator size="large" />
</View>
);
}
return (
<View style={styles.container}>
<Text style={styles.title}>Envelope-C Excel Preview</Text>
<ScrollView horizontal>
<View>
{/* HEADER */}
<View style={styles.row}>
{columns.map(col => (
<Text key={col} style={styles.headerCell}>
{col}
</Text>
))}
</View>
{/* DATA */}
<ScrollView style={{ maxHeight: 420 }}>
{data.map((row, rowIndex) => (
<View key={rowIndex} style={styles.row}>
{columns.map(key => (
<TextInput
key={key}
value={String(row[key])}
style={styles.cell}
onChangeText={text => updateCell(rowIndex, key, text)}
/>
))}
</View>
))}
</ScrollView>
</View>
</ScrollView>
<TouchableOpacity style={styles.button} onPress={saveUpdatedExcel}>
<Text style={styles.buttonText}>Save Updated Excel</Text>
</TouchableOpacity>
</View>
);
};
export default EnvelopeCExcelPreview;
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
backgroundColor: '#fff',
},
loader: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
title: {
fontSize: 18,
fontWeight: '700',
marginBottom: 10,
},
row: {
flexDirection: 'row',
},
headerCell: {
minWidth: 140,
padding: 10,
backgroundColor: '#f1f5f9',
borderWidth: 1,
fontWeight: '700',
},
cell: {
minWidth: 140,
padding: 10,
borderWidth: 1,
borderColor: '#cbd5e1',
},
button: {
marginTop: 15,
backgroundColor: '#2563eb',
padding: 14,
borderRadius: 8,
},
buttonText: {
color: '#fff',
textAlign: 'center',
fontWeight: '600',
},
});
+4 -4
View File
@@ -57,8 +57,8 @@ const LiveTender = () => {
tenderOfWork={item.departmentName}
tenderFees={item.documentFees}
tenderNumber={item.tenderNumber}
// onPurchasePress={() => { Dispatch(togglePurchaseTender(item)) }}
// onDetailsPress={() => navigation.navigate('LiveTenderDetail', {item})}
onPurchasePress={() => { Dispatch(togglePurchaseTender(item)) }}
onDetailsPress={() => navigation.navigate('LiveTenderDetail', { item })}
/>
},
[SelectedPurchaseList]
@@ -104,7 +104,7 @@ const LiveTender = () => {
fontWeight: '500',
}}
>
Refreshing auctions
Refreshing Tender
</Text>
</Animated.View>
)}
@@ -122,7 +122,7 @@ const LiveTender = () => {
<RefreshControl
refreshing={isRefetching}
onRefresh={refetch}
tintColor="transparent" // Set to transparent if you only want your custom banner to show
tintColor="transparent"
colors={[colors.primary]}
/>
}
+150 -423
View File
@@ -1,97 +1,94 @@
import { StyleSheet, Text, View, ScrollView, StatusBar, TouchableOpacity } from 'react-native'
import React from 'react'
import { InsideHeader } from '../../Component/Index'
import colors from '../../Constant/Color'
import { useNavigation, useRoute } from '@react-navigation/native'
import { useProceedToBid } from '../../Services/BBPS/Hooks'
import { StyleSheet, Text, View, ScrollView, TouchableOpacity } from 'react-native';
import React from 'react';
import { InsideHeader } from '../../Component/Index';
import colors from '../../Constant/Color';
import { useNavigation, useRoute } from '@react-navigation/native';
import { useProceedToBid } from '../../Services/BBPS/Hooks';
import { format } from '../../Helper/DateFormat';
import FontsFamily from '../../Constant/FontsFamily';
const ProceedToBidDetail = () => {
// Sample data based on your JSON
const route = useRoute()
const route: any = useRoute();
const tenderData = route.params?.tender;
const {data, refetch} = useProceedToBid(tenderData?.tenderId);
const navigation = useNavigation<any>()
// Format date from array
const navigation = useNavigation<any>();
const { data, refetch } = useProceedToBid(tenderData?.tenderId);
const handleStartBidding = () => {
refetch();
if (data) {
navigation.navigate('TenderBidding', { tenderData: tenderData , bidData: data.data });
navigation.navigate('TenderBidding', { tenderData: tenderData, bidData: data.data });
}
}
const formatDate = (dateArray: any[]) => {
if (!dateArray || dateArray.length < 3) return "N/A";
const [year, month, day, hour = 0, minute = 0] = dateArray;
return `${day.toString().padStart(2, '0')}/${month.toString().padStart(2, '0')}/${year} ${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
};
// Status indicator component
const StatusIndicator = ({ status, label }) => (
const StatusIndicator = ({ status, label }: { status: any, label: string }) => (
<View style={styles.statusContainer}>
<View style={[styles.statusDot, { backgroundColor: status ? colors.success : colors.error }]} />
<Text style={[styles.statusText, { color: status ? colors.success : colors.error }]}>
<Text style={[styles.statusText, { color: status ? colors.success : colors.error, fontFamily: FontsFamily.poppinsSemiBold }]}>
{label}: {status ? "Submitted" : "Not Submitted"}
</Text>
</View>
);
// Envelope log card component
const EnvelopeLogCard = ({ log, title }) => (
<View style={styles.envelopeCard}>
<View style={styles.cardHeader}>
<Text style={styles.cardTitle}>{title}</Text>
<View style={[styles.envelopeBadge, { backgroundColor: colors.primary }]}>
<Text style={styles.envelopeBadgeText}>{log?.envelope}</Text>
const EnvelopeLogCard = ({ log, title }: { log: any, title: string }) => {
return (
<View style={styles.envelopeCard}>
<View style={styles.cardHeader}>
<Text style={[styles.cardTitle, { fontFamily: FontsFamily.poppinsSemiBold }]}>{title}</Text>
<View style={[styles.envelopeBadge, { backgroundColor: colors.primary }]}>
<Text style={[styles.envelopeBadgeText, { fontFamily: FontsFamily.poppinsSemiBold }]}>{log?.envelope}</Text>
</View>
</View>
</View>
<View style={styles.logDetailRow}>
<Text style={styles.label}>Activity:</Text>
<Text style={styles.value}>{log?.activity}</Text>
</View>
<View style={styles.logDetailRow}>
<Text style={styles.label}>Date & Time:</Text>
<Text style={styles.value}>{log?.dateTime}</Text>
</View>
<View style={styles.logDetailRow}>
<Text style={styles.label}>System Info:</Text>
<Text style={styles.value}>{log?.osName} / {log?.browserName}</Text>
</View>
<View style={styles.logDetailRow}>
<Text style={styles.label}>IP Address:</Text>
<Text style={styles.value}>{log?.ipAddress}</Text>
</View>
<View style={styles.logDetailRow}>
<Text style={styles.label}>Status Message:</Text>
<Text style={[styles.value, styles.successText]}>{log?.logMessage}</Text>
</View>
{log?.headingMsg && (
<View style={styles.logDetailRow}>
<Text style={styles.label}>Heading:</Text>
<Text style={styles.value}>{log?.headingMsg}</Text>
<Text style={[styles.label, { fontFamily: FontsFamily.poppinsMedium }]}>Activity:</Text>
<Text style={[styles.value, { fontFamily: FontsFamily.poppinsRegular }]}>{log?.activity}</Text>
</View>
)}
</View>
);
<View style={styles.logDetailRow}>
<Text style={[styles.label, { fontFamily: FontsFamily.poppinsMedium }]}>Date & Time:</Text>
<Text style={[styles.value, { fontFamily: FontsFamily.poppinsRegular }]}>{format.date6(log?.dateTime)}</Text>
</View>
<View style={styles.logDetailRow}>
<Text style={[styles.label, { fontFamily: FontsFamily.poppinsMedium }]}>System Info:</Text>
<Text style={[styles.value, { fontFamily: FontsFamily.poppinsRegular }]}>{log?.osName} / {log?.browserName}</Text>
</View>
<View style={styles.logDetailRow}>
<Text style={[styles.label, { fontFamily: FontsFamily.poppinsMedium }]}>IP Address:</Text>
<Text style={[styles.value, { fontFamily: FontsFamily.poppinsRegular }]}>{log?.ipAddress}</Text>
</View>
<View style={styles.logDetailRow}>
<Text style={[styles.label, { fontFamily: FontsFamily.poppinsMedium }]}>Status Message:</Text>
<Text style={[styles.value, styles.successText, { fontFamily: FontsFamily.poppinsSemiBold }]}>{log?.logMessage}</Text>
</View>
{log?.headingMsg && (
<View style={styles.logDetailRow}>
<Text style={[styles.label, { fontFamily: FontsFamily.poppinsMedium }]}>Heading:</Text>
<Text style={[styles.value, { fontFamily: FontsFamily.poppinsRegular }]}>{log?.headingMsg}</Text>
</View>
)}
</View>
)
}
// Information row component
const InfoRow = ({ label, value, isHighlighted = false }) => (
const InfoRow = ({ label, value, isHighlighted = false }: { label: string, value: string, isHighlighted?: boolean }) => (
<View style={styles.infoRow}>
<Text style={styles.infoLabel}>{label}:</Text>
<Text style={[styles.infoValue, isHighlighted && styles.highlightedValue]}>{value}</Text>
<Text style={[styles.infoLabel, { fontFamily: FontsFamily.poppinsMedium }]}>{label}:</Text>
<Text style={[styles.infoValue, isHighlighted && styles.highlightedValue, { fontFamily: FontsFamily.poppinsSemiBold }]}>{value}</Text>
</View>
);
// Feature chip component
const FeatureChip = ({ label, enabled }) => (
const FeatureChip = ({ label, enabled }: { label: string, enabled: boolean }) => (
<View style={[styles.chip, { backgroundColor: enabled ? colors.successLight : colors.lightGray }]}>
<Text style={[styles.chipText, { color: enabled ? colors.success : colors.darkGray }]}>
<Text style={[styles.chipText, { color: enabled ? colors.success : colors.darkGray, fontFamily: FontsFamily.poppinsSemiBold }]}>
{label} {enabled ? '✓' : '✗'}
</Text>
</View>
@@ -99,42 +96,41 @@ const ProceedToBidDetail = () => {
return (
<View style={{ flex: 1, backgroundColor: colors.white }}>
<StatusBar backgroundColor={colors.primary} barStyle="light-content" />
<InsideHeader title="Tender Detail" showArrow />
<ScrollView style={styles.container} showsVerticalScrollIndicator={false}>
{/* Tender Header Section */}
<ScrollView style={styles.container} showsVerticalScrollIndicator={false} contentContainerStyle={{ paddingBottom: 100 }}>
{/* Tender Header */}
<View style={styles.headerCard}>
<View style={styles.tenderHeader}>
<View>
<Text style={styles.tenderNumber}>{tenderData.tenderNumber}</Text>
<Text style={styles.tenderId}>ID: {tenderData.tenderId}</Text>
<Text style={[styles.tenderNumber, { fontFamily: FontsFamily.poppinsSemiBold }]}>{tenderData.tenderNumber}</Text>
<Text style={[styles.tenderId, { fontFamily: FontsFamily.poppinsRegular }]}>ID: {tenderData.tenderId}</Text>
</View>
<View style={[styles.statusBadge, { backgroundColor: tenderData.biddingStatus ? colors.success : colors.warning }]}>
<Text style={styles.statusBadgeText}>
<Text style={[styles.statusBadgeText, { fontFamily: FontsFamily.poppinsSemiBold }]}>
{tenderData.biddingStatus ? "Active" : "Inactive"}
</Text>
</View>
</View>
<Text style={styles.workDescription}>{tenderData.nameofWork}</Text>
<Text style={[styles.workDescription, { fontFamily: FontsFamily.poppinsRegular }]} numberOfLines={1}>{tenderData.nameofWork}</Text>
<View style={styles.headerInfoRow}>
<View style={styles.headerInfoItem}>
<Text style={styles.headerInfoLabel}>NIT No.</Text>
<Text style={styles.headerInfoValue}>{tenderData.nitNo}</Text>
<Text style={[styles.headerInfoLabel, { fontFamily: FontsFamily.poppinsMedium }]}>NIT No.</Text>
<Text style={[styles.headerInfoValue, { fontFamily: FontsFamily.poppinsSemiBold }]}>{tenderData.nitNo}</Text>
</View>
<View style={styles.separator} />
<View style={styles.headerInfoItem}>
<Text style={styles.headerInfoLabel}>EMD Amount</Text>
<Text style={styles.headerInfoValue}>₹{tenderData.emdInFig}</Text>
<Text style={[styles.headerInfoLabel, { fontFamily: FontsFamily.poppinsMedium }]}>EMD Amount</Text>
<Text style={[styles.headerInfoValue, { fontFamily: FontsFamily.poppinsSemiBold }]}>₹{tenderData.emdInFig}</Text>
</View>
</View>
</View>
{/* Envelope Submission Status */}
{/* Envelope Status */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Envelope Submission Status</Text>
<Text style={[styles.sectionTitle, { color: colors.black }]}>{`Envelope Submission Status`}</Text>
<View style={styles.statusGrid}>
<StatusIndicator status={tenderData.envelopeASubmittStatus} label="Envelope A" />
<StatusIndicator status={tenderData.envelopeBSubmittStatus} label="Envelope B" />
@@ -142,10 +138,10 @@ const ProceedToBidDetail = () => {
</View>
</View>
{/* Envelope Logs */}
{/* Logs */}
{tenderData.envelopeA_Logs && (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Submission Logs</Text>
<Text style={[styles.sectionTitle, { color: colors.black }]}>Submission Logs</Text>
<EnvelopeLogCard log={tenderData.envelopeA_Logs} title="Envelope A Submission" />
<EnvelopeLogCard log={tenderData.envelopeB_Logs} title="Envelope B Submission" />
<EnvelopeLogCard log={tenderData.envelopeC_Logs} title="Envelope C Submission" />
@@ -154,7 +150,7 @@ const ProceedToBidDetail = () => {
{/* Tender Details */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Tender Details</Text>
<Text style={[styles.sectionTitle, { color: colors.black }]}>Tender Details</Text>
<View style={styles.detailsCard}>
<InfoRow label="Envelope Type" value={tenderData.envelopeType} />
<InfoRow label="Tender Stages" value={tenderData.tenderStages} />
@@ -164,24 +160,24 @@ const ProceedToBidDetail = () => {
</View>
</View>
{/* Time Period */}
{/* Submission Time */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Submission Time Period</Text>
<Text style={[styles.sectionTitle, { color: colors.black }]}>Submission Time Period</Text>
<View style={styles.timeCard}>
<View style={styles.timeRow}>
<Text style={styles.timeLabel}>Starts On:</Text>
<Text style={styles.timeValue}>{formatDate(tenderData.submittedStartDate)}</Text>
<Text style={[styles.timeLabel, { fontFamily: FontsFamily.poppinsSemiBold }]}>Starts On:</Text>
<Text style={[styles.timeValue, { fontFamily: FontsFamily.poppinsSemiBold }]}>{format.date6(tenderData.submittedStartDate)}</Text>
</View>
<View style={styles.timeRow}>
<Text style={styles.timeLabel}>Ends On:</Text>
<Text style={styles.timeValue}>{formatDate(tenderData.submittedEndDate)}</Text>
<Text style={[styles.timeLabel, { fontFamily: FontsFamily.poppinsSemiBold }]}>Ends On:</Text>
<Text style={[styles.timeValue, { fontFamily: FontsFamily.poppinsSemiBold }]}>{format.date6(tenderData.submittedEndDate)}</Text>
</View>
</View>
</View>
{/* Feature Flags */}
{/* Feature Chips */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Available Features</Text>
<Text style={[styles.sectionTitle, { color: colors.black }]}>Available Features</Text>
<View style={styles.chipsContainer}>
<FeatureChip label="View Bid" enabled={tenderData.viewBid} />
<FeatureChip label="Proceed to Bid" enabled={tenderData.proceedtoBid} />
@@ -192,362 +188,93 @@ const ProceedToBidDetail = () => {
</View>
</View>
{/* Final Status */}
{/* Overall Status */}
<View style={styles.finalStatusCard}>
<Text style={styles.finalStatusTitle}>Overall Status</Text>
<Text style={[styles.finalStatusTitle, { fontFamily: FontsFamily.poppinsSemiBold }]}>Overall Status</Text>
<View style={styles.finalStatusRow}>
<Text style={styles.finalStatusLabel}>All Envelopes Submitted:</Text>
<Text style={[styles.finalStatusValue,
{
<Text style={[styles.finalStatusLabel, { fontFamily: FontsFamily.poppinsMedium }]}>All Envelopes Submitted:</Text>
<Text style={[styles.finalStatusValue, {
color: tenderData.envelopeASubmittStatus && tenderData.envelopeBSubmittStatus && tenderData.envelopeCSubmittStatus
? colors.success : colors.error
? colors.success : colors.error, fontFamily: FontsFamily.poppinsSemiBold
}]}>
{tenderData.envelopeASubmittStatus && tenderData.envelopeBSubmittStatus && tenderData.envelopeCSubmittStatus
? "COMPLETED" : "PENDING"}
{tenderData.envelopeASubmittStatus && tenderData.envelopeBSubmittStatus && tenderData.envelopeCSubmittStatus ? "COMPLETED" : "PENDING"}
</Text>
</View>
<View style={styles.finalStatusRow}>
<Text style={styles.finalStatusLabel}>Bidding Status:</Text>
<Text style={[styles.finalStatusValue,
{ color: tenderData.biddingStatus ? colors.success : colors.error }]}>
<Text style={[styles.finalStatusLabel, { fontFamily: FontsFamily.poppinsMedium }]}>Bidding Status:</Text>
<Text style={[styles.finalStatusValue, { color: tenderData.biddingStatus ? colors.success : colors.error, fontFamily: FontsFamily.poppinsSemiBold }]}>
{tenderData.biddingStatus ? "ACTIVE" : "CLOSED"}
</Text>
</View>
</View>
<View style={styles.footerSpace} />
</ScrollView>
{/* Footer */}
<View style={styles.footer}>
{
tenderData?.proceedtoBid && !tenderData?.viewBid && tenderData?.biddingStatus && tenderData?.bidWithdrawStatus === false ? (
<TouchableOpacity style={styles.proceedButton} onPress={handleStartBidding}>
<Text style={styles.proceedButtonText}>Start Bidding</Text>
<Text style={[styles.proceedButtonText, { fontFamily: FontsFamily.poppinsSemiBold }]}>Start Bidding</Text>
</TouchableOpacity>
) : <Text style={styles.footerText}>One time bidding is completed</Text>
} </View>
) : <Text style={[styles.footerText, { fontFamily: FontsFamily.poppinsMedium }]}>One time bidding is completed</Text>
}
</View>
</View>
);
};
)
}
export default ProceedToBidDetail
export default ProceedToBidDetail;
// Styles remain mostly unchanged but improved shadows, spacing, and rounded corners
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
marginBottom: 60,
},
headerCard: {
backgroundColor: colors.primaryLight,
borderRadius: 12,
padding: 20,
marginBottom: 20,
borderLeftWidth: 4,
borderLeftColor: colors.primary,
},
tenderHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 12,
},
tenderNumber: {
fontSize: 22,
fontWeight: 'bold',
color: colors.primary,
},
tenderId: {
fontSize: 14,
color: colors.darkGray,
marginTop: 4,
},
statusBadge: {
paddingHorizontal: 12,
paddingVertical: 6,
borderRadius: 20,
},
statusBadgeText: {
color: colors.white,
fontWeight: '600',
fontSize: 12,
},
workDescription: {
fontSize: 16,
color: colors.darkText,
lineHeight: 22,
marginBottom: 16,
},
headerInfoRow: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: colors.white,
borderRadius: 8,
padding: 12,
},
headerInfoItem: {
flex: 1,
alignItems: 'center',
},
headerInfoLabel: {
fontSize: 12,
color: colors.darkGray,
marginBottom: 4,
},
headerInfoValue: {
fontSize: 16,
fontWeight: '600',
color: colors.primary,
},
separator: {
width: 1,
height: 30,
backgroundColor: colors.lightGray,
},
section: {
marginBottom: 20,
},
sectionTitle: {
fontSize: 18,
fontWeight: '600',
color: colors.primary,
marginBottom: 12,
paddingLeft: 4,
},
statusGrid: {
backgroundColor: colors.white,
borderRadius: 12,
padding: 16,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
statusContainer: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 12,
},
statusDot: {
width: 12,
height: 12,
borderRadius: 6,
marginRight: 10,
},
statusText: {
fontSize: 15,
fontWeight: '500',
},
envelopeCard: {
backgroundColor: colors.white,
borderRadius: 12,
padding: 16,
marginBottom: 12,
borderWidth: 1,
borderColor: colors.lightGray,
},
cardHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 12,
},
cardTitle: {
fontSize: 16,
fontWeight: '600',
color: colors.primary,
},
envelopeBadge: {
paddingHorizontal: 10,
paddingVertical: 4,
borderRadius: 12,
},
envelopeBadgeText: {
color: colors.white,
fontWeight: 'bold',
fontSize: 12,
},
logDetailRow: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 8,
},
label: {
fontSize: 14,
color: colors.darkGray,
flex: 1,
},
value: {
fontSize: 14,
color: colors.darkText,
fontWeight: '500',
flex: 2,
textAlign: 'right',
},
successText: {
color: colors.success,
fontWeight: '600',
},
detailsCard: {
backgroundColor: colors.white,
borderRadius: 12,
padding: 16,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
infoRow: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingVertical: 10,
borderBottomWidth: 1,
borderBottomColor: colors.lightestGray,
},
infoLabel: {
fontSize: 14,
color: colors.darkGray,
},
infoValue: {
fontSize: 15,
fontWeight: '500',
color: colors.darkText,
},
highlightedValue: {
color: colors.success,
fontWeight: '600',
},
timeCard: {
backgroundColor: colors.white,
borderRadius: 12,
padding: 16,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
timeRow: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingVertical: 12,
borderBottomWidth: 1,
borderBottomColor: colors.lightestGray,
},
timeLabel: {
fontSize: 15,
color: colors.darkGray,
fontWeight: '500',
},
timeValue: {
fontSize: 15,
color: colors.primary,
fontWeight: '600',
},
chipsContainer: {
flexDirection: 'row',
flexWrap: 'wrap',
gap: 10,
},
chip: {
paddingHorizontal: 16,
paddingVertical: 8,
borderRadius: 20,
marginBottom: 8,
},
chipText: {
fontSize: 14,
fontWeight: '500',
},
finalStatusCard: {
backgroundColor: colors.primaryLight,
borderRadius: 12,
padding: 20,
marginTop: 10,
borderWidth: 2,
borderColor: colors.primary,
},
finalStatusTitle: {
fontSize: 18,
fontWeight: 'bold',
color: colors.primary,
marginBottom: 16,
textAlign: 'center',
},
finalStatusRow: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 12,
paddingVertical: 8,
borderBottomWidth: 1,
borderBottomColor: 'rgba(0, 0, 0, 0.1)',
},
finalStatusLabel: {
fontSize: 16,
color: colors.darkText,
fontWeight: '500',
},
finalStatusValue: {
fontSize: 16,
fontWeight: 'bold',
},
footerSpace: {
height: 30,
},
success: {
color: colors.success,
},
error: {
color: colors.error,
},
primary: {
color: colors.primary,
},
warning: {
color: colors.warning,
},
successLight: {
backgroundColor: colors.successLight,
},
lightGray: {
backgroundColor: colors.lightGray,
},
footer: {
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
backgroundColor: colors.white,
padding: 16,
borderTopWidth: 1,
borderTopColor: colors.lightGray,
elevation: 10,
},
proceedButton: {
backgroundColor: colors.primary,
paddingVertical: 14,
borderRadius: 30,
alignItems: 'center',
},
proceedButtonText: {
color: colors.white,
fontSize: 16,
fontWeight: '600',
},
footerText: {
textAlign: 'center',
color: colors.darkGray,
fontSize: 14,
},
});
container: { flex: 1, padding: 16 },
headerCard: { backgroundColor: colors.white, borderRadius: 14, padding: 20, marginBottom: 20, borderLeftWidth: 4, borderLeftColor: colors.primary, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 5, elevation: 5 },
tenderHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 12 },
tenderNumber: { fontSize: 22, fontWeight: 'bold', color: colors.primary },
tenderId: { fontSize: 14, color: colors.darkGray, marginTop: 4 },
statusBadge: { paddingHorizontal: 12, paddingVertical: 6, borderRadius: 20 },
statusBadgeText: { color: colors.white, fontWeight: '600', fontSize: 12 },
workDescription: { fontSize: 13, color: colors.black, marginBottom: 16, fontFamily: FontsFamily.poppinsMedium },
headerInfoRow: { flexDirection: 'row', alignItems: 'center', backgroundColor: colors.lightestGray, borderRadius: 8, padding: 12 },
headerInfoItem: { flex: 1, alignItems: 'center' },
headerInfoLabel: { fontSize: 12, color: colors.darkGray, marginBottom: 4 },
headerInfoValue: { fontSize: 16, fontWeight: '600', color: colors.primary },
separator: { width: 1, height: 30, backgroundColor: colors.lightGray },
section: { marginBottom: 20 },
sectionTitle: { fontSize: 18, fontWeight: '600', marginBottom: 12, paddingLeft: 4 },
statusGrid: { backgroundColor: colors.white, borderRadius: 14, padding: 16, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 5, elevation: 3 },
statusContainer: { flexDirection: 'row', alignItems: 'center', marginBottom: 12 },
statusDot: { width: 12, height: 12, borderRadius: 6, marginRight: 10 },
statusText: { fontSize: 15, fontWeight: '500' },
envelopeCard: { backgroundColor: colors.white, borderRadius: 14, padding: 16, marginBottom: 12, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.05, shadowRadius: 4, elevation: 2 },
cardHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 },
cardTitle: { fontSize: 16, fontWeight: '600', color: colors.black },
envelopeBadge: { paddingHorizontal: 10, paddingVertical: 4, borderRadius: 12 },
envelopeBadgeText: { color: colors.white, fontWeight: 'bold', fontSize: 12 },
logDetailRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 },
label: { fontSize: 14, color: colors.black, flex: 1, fontFamily: FontsFamily.poppinsSemiBold },
value: { fontSize: 14, color: colors.darkText, flex: 2, textAlign: 'right' },
successText: { color: colors.success, fontWeight: '600' },
detailsCard: { backgroundColor: colors.white, borderRadius: 14, padding: 16, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.05, shadowRadius: 4, elevation: 3 },
infoRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: 10, borderBottomWidth: 1, borderBottomColor: colors.lightestGray },
infoLabel: { fontSize: 14, color: colors.black, fontFamily: FontsFamily.poppinsSemiBold },
infoValue: { fontSize: 15, fontWeight: '500', color: colors.darkText },
highlightedValue: { color: colors.success, fontWeight: '600' },
timeCard: { backgroundColor: colors.white, borderRadius: 14, padding: 16, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.05, shadowRadius: 4, elevation: 3 },
timeRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: 12, borderBottomWidth: 1, borderBottomColor: colors.lightestGray },
timeLabel: { fontSize: 15, color: colors.black, },
timeValue: { fontSize: 15, color: colors.grayText, },
chipsContainer: { flexDirection: 'row', flexWrap: 'wrap', gap: 10 },
chip: { paddingHorizontal: 16, paddingVertical: 8, borderRadius: 20, marginBottom: 8 },
chipText: { fontSize: 14, fontWeight: '500' },
finalStatusCard: { backgroundColor: colors.white, borderRadius: 14, padding: 20, marginTop: 10, borderWidth: 2, borderColor: colors.primary, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 5, elevation: 5 },
finalStatusTitle: { fontSize: 18, fontWeight: 'bold', marginBottom: 16, textAlign: 'center' },
finalStatusRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12, paddingVertical: 8, borderBottomWidth: 1, borderBottomColor: 'rgba(0,0,0,0.1)' },
finalStatusLabel: { fontSize: 14, color: colors.black, fontFamily: FontsFamily.poppinsSemiBold },
finalStatusValue: { fontSize: 13, },
footer: { position: 'absolute', bottom: 0, left: 0, right: 0, backgroundColor: colors.white, padding: 16, borderTopWidth: 1, borderTopColor: colors.lightGray, elevation: 10 },
proceedButton: { backgroundColor: colors.primary, paddingVertical: 14, borderRadius: 30, alignItems: 'center' },
proceedButtonText: { color: colors.white, fontSize: 16, fontWeight: '600' },
footerText: { textAlign: 'center', color: colors.darkGray, fontSize: 14 },
});
+4 -33
View File
@@ -1,29 +1,14 @@
import React, { use, useEffect } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Platform,
Alert,
} from 'react-native';
import Animated, {
FadeInUp,
useAnimatedStyle,
useSharedValue,
withTiming,
} from 'react-native-reanimated';
import { View, Text, StyleSheet, TouchableOpacity, Platform } from 'react-native';
import Animated, { FadeInUp, useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
import moment from 'moment';
import CountdownTimer from '../../Component/Counter/CountdownTimer';
import colors from '../../Constant/Color';
import { useFetchTenderById, useProceedToBid } from '../../Services/BBPS/Hooks';
import { useFetchTenderById } from '../../Services/BBPS/Hooks';
import { useNavigation } from '@react-navigation/native';
import TenderFullDetail from './Modal/TenderFullDetail';
const PurchaseTenderTile = ({
item,
onPressDetails,
}: any) => {
const PurchaseTenderTile = ({ item, onPressDetails }: any) => {
const scale = useSharedValue(1);
const elevation = useSharedValue(8);
const navigation = useNavigation<any>();
@@ -36,15 +21,6 @@ const PurchaseTenderTile = ({
const { data: tenderResponse, }: any = useFetchTenderById(item?.tenderId);
const tender = tenderResponse?.data;
// console.log("item my : ", item)
{
if (item?.nitNumber == 'TN/111') {
console.log("tender item : ", item?.nitNumber)
}
}
const handlePressIn = () => {
scale.value = withTiming(0.97, { duration: 120 });
elevation.value = withTiming(3, { duration: 120 });
@@ -61,11 +37,6 @@ const PurchaseTenderTile = ({
const lightStatusBg = isLive ? '#EFF6FF' : '#F8FAFC';
const [showDetail, setShowDetail] = React.useState(false);
useEffect(() => {
if(item?.tenderNumber == 'TN/210'){
console.log("tender item : ", item)
}
}, [item]);
return (
<Animated.View
+2 -2
View File
@@ -6,8 +6,8 @@ import { apiCall } from "../../Axios/Axios";
export const userLogin = async (payload: { emailAdd: string, password: string }): Promise<any> => {
try {
// const response = await axios.post(LOG_IN_URL, { ...payload, divice: "mobileApp" });
const response = await axios.post(TENDER_LOGIN, { ...payload, device: "mobileApp" });
const response = await axios.post(LOG_IN_URL, { ...payload, divice: "mobileApp" });
// const response = await axios.post(TENDER_LOGIN, { ...payload, device: "mobileApp" });
return response.data;
} catch (error: any) {
throw error.response?.data || error.message;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB