updated code with dsc and device binding

This commit is contained in:
Abin Toppo
2026-05-08 13:39:41 +05:30
parent c1ecc97e29
commit 66461370a2
120 changed files with 11910 additions and 8347 deletions
+281 -240
View File
@@ -1,7 +1,6 @@
import React, { useState, useRef, useMemo } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Animated,
@@ -12,40 +11,39 @@ import {
useFetchLiveTender,
useFetchPurchaseTender,
} from '../../Services/ApiCall/Hooks';
import colors from '../../Constant/Color';
import { ShoppingCart, Lock } from 'lucide-react-native';
import { ShoppingCart, Lock, Radio, Package } from 'lucide-react-native';
import { useNavigation } from '@react-navigation/native';
import NavigationString from '../../Constant/NavigationString';
import FontsFamily from '../../Constant/FontsFamily';
import { useSelector } from 'react-redux';
import LiveTender from './LiveTender';
import PurchaseTenderAllList from './PurchaseTenderAllList';
import { useTheme } from '../../Hooks/useTheme';
import AppText from '../../components/AppText';
const { width: SCREEN_WIDTH } = Dimensions.get('window');
const TAB_HEIGHT = 44;
const TAB_HEIGHT = 48;
const HORIZONTAL_PADDING = 32;
const SWITCH_INSETS = 2;
const SWITCH_INSETS = 3;
const Tender = () => {
const { colors, spacing, shadows } = useTheme();
const Navigation = useNavigation() as any;
const { data: liveTenderData }: any = useFetchLiveTender();
const { data: purchaseTenderData }: any = useFetchPurchaseTender();
const SelectedPurchaseList = useSelector(
(state: any) => state?.selectPurchaseTender,
);
const SelectedPurchaseList = useSelector((state: any) => state?.selectPurchaseTender);
const reduxToken = useSelector((state: any) => state.token?.token);
const liveCount = liveTenderData?.pages?.[0]?.totalCount || 0;
const purchaseCount = purchaseTenderData?.pages?.[0]?.totalCount || 0;
const [selectedTab, setSelectedTab] = useState<'live' | 'purchase'>('live');
const translateX = useRef(new Animated.Value(0)).current;
const TAB_WIDTH = useMemo(() => {
const availableWidth = SCREEN_WIDTH - HORIZONTAL_PADDING - SWITCH_INSETS * 2;
return availableWidth / 2.4;
return availableWidth / 2;
}, []);
const [selectedTab, setSelectedTab] = useState<'live' | 'purchase'>('purchase');
const translateX = useRef(new Animated.Value(TAB_WIDTH)).current;
const onTabPress = (tab: 'live' | 'purchase', index: number) => {
setSelectedTab(tab);
Animated.spring(translateX, {
@@ -55,252 +53,295 @@ const Tender = () => {
}).start();
};
// Check if user is auction type
const isAuctionUser = reduxToken?.userType?.toLowerCase() === 'auction';
const cartCount = SelectedPurchaseList.length;
// Render restricted access message
const renderRestrictedAccess = () => (
<View style={styles.restrictedContainer}>
<View style={styles.restrictedCard}>
<View style={styles.iconContainer}>
<Lock size={64} color={colors.primary} />
const styles = makeStyles(colors, spacing, shadows, TAB_WIDTH, TAB_HEIGHT);
if (isAuctionUser) {
return (
<View style={styles.container}>
<InsideHeader title="Tender" showArrow />
<View style={styles.restrictedContainer}>
<View style={styles.restrictedCard}>
{/* Double-ring Lock Icon */}
<View style={styles.lockRing}>
<View style={styles.lockInner}>
<Lock size={40} color={colors.primary} strokeWidth={1.8} />
</View>
</View>
<AppText variant="h2" centered color={colors.text} style={styles.restrictedTitle as any}>
Access Restricted
</AppText>
<AppText variant="body" centered color={colors.textSecondary} style={styles.restrictedMessage as any}>
You're logged in as an{' '}
<AppText variant="body" color={colors.primary} style={{ fontWeight: '700' } as any}>
Auction user
</AppText>
{'. '}Tender features are not available for your account type.
</AppText>
<View style={styles.hintBox}>
<AppText variant="bodySmall" centered color={colors.textSecondary}>
Switch to a Tender account to access live & purchase tender features.
</AppText>
</View>
<TouchableOpacity
style={styles.loginButton}
activeOpacity={0.85}
onPress={() => Navigation.navigate(NavigationString.Login)}
>
<AppText variant="button" color={colors.buttonText} style={styles.loginBtnText as any}>
Switch to Tender Login
</AppText>
</TouchableOpacity>
</View>
</View>
<Text style={styles.restrictedTitle}>Tender Access Restricted</Text>
<Text style={styles.restrictedMessage}>
You are currently logged in as an Auction user. Tender features are not available for your account type.
</Text>
<Text style={styles.restrictedSubMessage}>
To access tender features, please login with a Tender user account.
</Text>
<TouchableOpacity
style={styles.loginButton}
onPress={() => Navigation.navigate(NavigationString.Login)}
>
<Text style={styles.loginButtonText}>Switch to Tender Login</Text>
</TouchableOpacity>
</View>
</View>
);
);
}
return (
<View style={styles.container}>
<InsideHeader title="Tender" showArrow />
{isAuctionUser ? (
// Show restricted access message for auction users
renderRestrictedAccess()
) : (
// Show normal tender UI for tender users
<>
<View style={styles.topRow}>
<View
{/* Tab Row */}
<View style={styles.topRow}>
{/* Segmented Control */}
<View
style={[
styles.switchWrapper,
{ width: TAB_WIDTH * 2 + SWITCH_INSETS * 2 },
]}
>
{/* Sliding pill */}
<Animated.View
pointerEvents="none"
style={[
styles.activeTab,
{ width: TAB_WIDTH, transform: [{ translateX }] },
]}
/>
{/* Live Tab */}
<TouchableOpacity
style={[styles.tab, { width: TAB_WIDTH }]}
activeOpacity={0.8}
onPress={() => onTabPress('live', 0)}
>
<Radio
size={13}
color={selectedTab === 'live' ? colors.primary : colors.textSecondary}
strokeWidth={2}
/>
<AppText
variant="caption"
color={selectedTab === 'live' ? colors.primary : colors.textSecondary}
style={[
styles.switchWrapper,
{
width: TAB_WIDTH * 2 + SWITCH_INSETS * 2,
},
styles.tabText,
selectedTab === 'live' && (styles.activeTabText as any),
]}
>
<Animated.View
pointerEvents="none"
style={[
styles.activeTab,
{
width: TAB_WIDTH,
transform: [{ translateX }],
},
]}
/>
Live {liveCount ? `(${liveCount})` : ''}
</AppText>
</TouchableOpacity>
<TouchableOpacity
style={[styles.tab, { width: TAB_WIDTH }]}
activeOpacity={0.8}
onPress={() => onTabPress('live', 0)}
>
<Text
style={[
styles.tabText,
selectedTab === 'live' && styles.activeText,
]}
>
Live ({liveCount})
</Text>
</TouchableOpacity>
{/* Purchase Tab */}
<TouchableOpacity
style={[styles.tab, { width: TAB_WIDTH }]}
activeOpacity={0.8}
onPress={() => onTabPress('purchase', 1)}
>
<Package
size={13}
color={selectedTab === 'purchase' ? colors.primary : colors.textSecondary}
strokeWidth={2}
/>
<AppText
variant="caption"
color={selectedTab === 'purchase' ? colors.primary : colors.textSecondary}
style={[
styles.tabText,
selectedTab === 'purchase' && (styles.activeTabText as any),
]}
>
Purchased {purchaseCount ? `(${purchaseCount})` : ''}
</AppText>
</TouchableOpacity>
</View>
</View>
<TouchableOpacity
style={[styles.tab, { width: TAB_WIDTH }]}
activeOpacity={0.8}
onPress={() => onTabPress('purchase', 1)}
>
<Text
style={[
styles.tabText,
selectedTab === 'purchase' && styles.activeText,
]}
>
Purchased ({purchaseCount})
</Text>
</TouchableOpacity>
</View>
{/* Content */}
{selectedTab === 'live' ? <LiveTender /> : <PurchaseTenderAllList />}
<View>
{SelectedPurchaseList.length ? (
<View
style={{
borderWidth: 2,
borderColor: colors.white,
backgroundColor: colors.primaryLight,
position: 'absolute',
borderRadius: 50,
zIndex: 20,
right: 0,
top: -10,
paddingHorizontal: 2,
}}
>
<Text style={{ fontSize: 12, color: colors.black }}>
{SelectedPurchaseList.length}
</Text>
</View>
) : null}
<TouchableOpacity
style={{
padding: 10,
backgroundColor: colors.primaryLight,
borderRadius: 20,
}}
onPress={() => {
Navigation.navigate(NavigationString.PurchaseTenderList);
}}
>
<ShoppingCart size={22} color={colors.black} strokeWidth={2} />
</TouchableOpacity>
</View>
{/* Cart Floating Button */}
<TouchableOpacity
style={styles.cartFloatingButton}
activeOpacity={0.9}
onPress={() => Navigation.navigate(NavigationString.PurchaseTenderList)}
>
<ShoppingCart size={24} color={colors.buttonText} strokeWidth={2} />
{cartCount > 0 && (
<View style={styles.cartBadge}>
<AppText variant="caption" color={colors.primary} style={styles.cartBadgeText as any}>
{cartCount}
</AppText>
</View>
{selectedTab === 'live' ? <LiveTender /> : <PurchaseTenderAllList />}
</>
)}
)}
</TouchableOpacity>
</View>
);
};
export default Tender;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.white,
},
topRow: {
flexDirection: 'row',
justifyContent: 'space-around',
alignItems: 'center',
paddingHorizontal: 16,
},
switchWrapper: {
flexDirection: 'row',
marginVertical: 14,
backgroundColor: '#f1f5f9',
borderRadius: 18,
padding: 2,
height: TAB_HEIGHT,
},
tab: {
height: TAB_HEIGHT - 4,
alignItems: 'center',
justifyContent: 'center',
zIndex: 2,
},
tabText: {
fontSize: 14,
color: '#64748b',
lineHeight: 18,
fontFamily: FontsFamily.poppinsSemiBold,
},
activeText: {
color: colors.primary,
},
activeTab: {
position: 'absolute',
top: 2,
left: 2,
height: TAB_HEIGHT - 4,
backgroundColor: '#fff',
borderRadius: 16,
shadowColor: '#000',
shadowOpacity: 0.1,
shadowRadius: 6,
elevation: 3,
},
restrictedContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 24,
backgroundColor: colors.lightGray,
},
restrictedCard: {
backgroundColor: colors.white,
borderRadius: 24,
padding: 32,
alignItems: 'center',
maxWidth: 400,
width: '100%',
},
iconContainer: {
width: 120,
height: 120,
borderRadius: 60,
backgroundColor: colors.primaryHighlight,
justifyContent: 'center',
alignItems: 'center',
marginBottom: 24,
},
restrictedTitle: {
fontSize: 24,
fontWeight: '700',
color: colors.darkText,
textAlign: 'center',
marginBottom: 16,
fontFamily: FontsFamily.poppinsBold,
},
restrictedMessage: {
fontSize: 16,
color: colors.grayText,
textAlign: 'center',
lineHeight: 24,
marginBottom: 12,
fontFamily: FontsFamily.poppinsRegular,
},
restrictedSubMessage: {
fontSize: 14,
color: colors.grayText,
textAlign: 'center',
lineHeight: 22,
marginBottom: 32,
fontFamily: FontsFamily.poppinsRegular,
},
loginButton: {
backgroundColor: colors.primary,
paddingHorizontal: 32,
paddingVertical: 14,
borderRadius: 12,
shadowColor: colors.primary,
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.3,
shadowRadius: 8,
elevation: 4,
},
loginButtonText: {
color: colors.white,
fontSize: 16,
fontWeight: '600',
fontFamily: FontsFamily.poppinsSemiBold,
},
});
/* ─── Styles factory ─── */
const makeStyles = (colors: any, spacing: any, shadows: any, TAB_WIDTH: number, TAB_HEIGHT: number) =>
StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.background,
},
/* ── Tab Row ── */
topRow: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: spacing.m,
paddingVertical: spacing.s + 2,
},
switchWrapper: {
flexDirection: 'row',
backgroundColor: colors.surface,
borderRadius: 16,
padding: SWITCH_INSETS,
height: TAB_HEIGHT,
...shadows.light,
},
tab: {
height: TAB_HEIGHT - SWITCH_INSETS * 2,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
gap: 5,
zIndex: 2,
},
tabText: {
fontWeight: '600',
letterSpacing: 0.3,
} as any,
activeTabText: {
fontWeight: '700',
} as any,
activeTab: {
position: 'absolute',
top: SWITCH_INSETS,
left: SWITCH_INSETS,
height: TAB_HEIGHT - SWITCH_INSETS * 2,
backgroundColor: colors.background,
borderRadius: 13,
...shadows.medium,
},
/* ── Cart Floating Button ── */
cartFloatingButton: {
position: 'absolute',
bottom: spacing.xl + 80,
right: spacing.l,
width: 56,
height: 56,
borderRadius: 28,
backgroundColor: colors.primary,
alignItems: 'center',
justifyContent: 'center',
...shadows.strong,
zIndex: 999,
},
cartBadge: {
position: 'absolute',
top: 0,
right: 0,
minWidth: 20,
height: 20,
borderRadius: 10,
backgroundColor: colors.background,
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: 4,
borderWidth: 1.5,
borderColor: colors.primary,
},
cartBadgeText: {
fontSize: 10,
fontWeight: '800',
lineHeight: 13,
} as any,
/* ── Restricted Access ── */
restrictedContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: spacing.l,
backgroundColor: colors.background,
},
restrictedCard: {
backgroundColor: colors.surface,
borderRadius: 28,
padding: spacing.l,
alignItems: 'center',
width: '100%',
maxWidth: 400,
...shadows.strong,
},
lockRing: {
width: 100,
height: 100,
borderRadius: 50,
backgroundColor: `${colors.primary}12`,
alignItems: 'center',
justifyContent: 'center',
marginBottom: spacing.l,
borderWidth: 1.5,
borderColor: `${colors.primary}25`,
},
lockInner: {
width: 72,
height: 72,
borderRadius: 36,
backgroundColor: `${colors.primary}18`,
alignItems: 'center',
justifyContent: 'center',
},
restrictedTitle: {
marginBottom: spacing.s + 4,
} as any,
restrictedMessage: {
marginBottom: spacing.s,
lineHeight: 24,
} as any,
hintBox: {
backgroundColor: colors.overlay,
borderRadius: 14,
paddingHorizontal: spacing.m,
paddingVertical: spacing.s + 2,
marginBottom: spacing.l,
width: '100%',
},
loginButton: {
backgroundColor: colors.buttonPrimary,
paddingHorizontal: spacing.l,
paddingVertical: 14,
borderRadius: 16,
width: '100%',
alignItems: 'center',
...shadows.medium,
},
loginBtnText: {
letterSpacing: 1.2,
} as any,
});