commit
This commit is contained in:
@@ -51,9 +51,9 @@ const ConfirmDialog: React.FC<ConfirmDialogProps> = ({
|
||||
|
||||
{/* Actions */}
|
||||
<View style={styles.actions}>
|
||||
{/* <TouchableOpacity style={styles.cancelBtn} onPress={onClose}>
|
||||
<TouchableOpacity style={styles.cancelBtn} onPress={onClose}>
|
||||
<Text style={styles.cancelText}>{cancelText}</Text>
|
||||
</TouchableOpacity> */}
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.confirmBtn}
|
||||
|
||||
@@ -32,7 +32,6 @@ export default function MainStack() {
|
||||
<Stack.Screen name={NavigationString.Signup} component={Screens.Signup} options={option} />
|
||||
<Stack.Screen name={NavigationString.Onboarding} component={Screens.Onboarding} options={option} />
|
||||
<Stack.Screen name={NavigationString.Login} component={Screens.Login} options={option} />
|
||||
|
||||
<Stack.Screen name={NavigationString.Home} component={BottomTab} options={option} />
|
||||
<Stack.Screen name={NavigationString.PurchaseList} component={Screens.PurchaseList} options={option} />
|
||||
<Stack.Screen name={NavigationString.Emd} component={Screens.Emd} options={option} />
|
||||
@@ -46,7 +45,8 @@ export default function MainStack() {
|
||||
<Stack.Screen name={NavigationString.Registration} component={Screens.Registration} options={option} />
|
||||
<Stack.Screen name={NavigationString.Partnership} component={Screens.Partnership} options={option} />
|
||||
<Stack.Screen name={NavigationString.LiveTenderDetail} component={Screens.LiveTenderDetail} options={option} />
|
||||
<Stack.Screen name={NavigationString.ViewTenderDetail} component={Screens.ViewTenderDetail} options={option} /> <Stack.Screen name={NavigationString.KycWebViewScreen} component={Screens.KycWebViewScreen} options={option} />
|
||||
<Stack.Screen name={NavigationString.ViewTenderDetail} component={Screens.ViewTenderDetail} options={option} />
|
||||
<Stack.Screen name={NavigationString.KycWebViewScreen} component={Screens.KycWebViewScreen} options={option} />
|
||||
</Stack.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useFetchLiveAuction, useFetchPurchaseAuction } from '../../Services/BBP
|
||||
import colors from '../../Constant/Color';
|
||||
import LiveAuction from './LiveAuction';
|
||||
import PurchaseAuction from './PurchaseAuction';
|
||||
import { ShoppingCart } from 'lucide-react-native';
|
||||
import { ShoppingCart, Lock } from 'lucide-react-native';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import NavigationString from '../../Constant/NavigationString';
|
||||
import FontsFamily from '../../Constant/FontsFamily';
|
||||
@@ -21,6 +21,7 @@ const Auction = () => {
|
||||
const { data: liveAuctionData = {} }: any = useFetchLiveAuction();
|
||||
const { data: purchaseAuctionData = {} } = useFetchPurchaseAuction();
|
||||
const SelectedPurchaseList = useSelector((state: any) => state.selectPurchaseAuction);
|
||||
const reduxToken = useSelector((state: any) => state.token?.token);
|
||||
|
||||
const liveCount = Array.isArray(liveAuctionData?.result)
|
||||
? liveAuctionData?.pages?.[0]?.totalCount
|
||||
@@ -31,7 +32,6 @@ const Auction = () => {
|
||||
: 0;
|
||||
|
||||
const [selectedTab, setSelectedTab] = useState<'live' | 'purchase'>('live');
|
||||
|
||||
const translateX = useRef(new Animated.Value(0)).current;
|
||||
|
||||
const TAB_WIDTH = useMemo(() => {
|
||||
@@ -48,10 +48,47 @@ const Auction = () => {
|
||||
}).start();
|
||||
};
|
||||
|
||||
// Check if user is tender type
|
||||
const isTenderUser = reduxToken?.userType?.toLowerCase() === 'tender';
|
||||
|
||||
// Render restricted access message
|
||||
const renderRestrictedAccess = () => (
|
||||
<View style={styles.restrictedContainer}>
|
||||
<View style={styles.restrictedCard}>
|
||||
<View style={styles.iconContainer}>
|
||||
<Lock size={64} color={colors.primary} />
|
||||
</View>
|
||||
|
||||
<Text style={styles.restrictedTitle}>Auction Access Restricted</Text>
|
||||
|
||||
<Text style={styles.restrictedMessage}>
|
||||
You are currently logged in as a Tender user. Auction features are not available for your account type.
|
||||
</Text>
|
||||
|
||||
<Text style={styles.restrictedSubMessage}>
|
||||
To access auction features, please login with an Auction user account.
|
||||
</Text>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.loginButton}
|
||||
onPress={() => Navigation.navigate(NavigationString.Login)}
|
||||
>
|
||||
<Text style={styles.loginButtonText}>Switch to Auction Login</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<InsideHeader title="Auction" showArrow />
|
||||
|
||||
{isTenderUser ? (
|
||||
// Show restricted access message for tender users
|
||||
renderRestrictedAccess()
|
||||
) : (
|
||||
// Show normal auction UI for auction users
|
||||
<>
|
||||
<View style={styles.topRow}>
|
||||
<View
|
||||
style={[
|
||||
@@ -139,6 +176,8 @@ const Auction = () => {
|
||||
</View>
|
||||
|
||||
{selectedTab === 'live' ? <LiveAuction /> : <PurchaseAuction />}
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
@@ -191,4 +230,70 @@ const styles = StyleSheet.create({
|
||||
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,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -86,7 +86,6 @@ const Home = () => {
|
||||
udf2: "77.34",
|
||||
udf3: "string",
|
||||
udf4: "string",
|
||||
responseUrl: "https://dev.procurelinc.in/"
|
||||
};
|
||||
|
||||
console.log("Payload:", payload);
|
||||
|
||||
@@ -52,9 +52,14 @@ import {
|
||||
X,
|
||||
Save,
|
||||
} from 'lucide-react-native';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
|
||||
import { useContractorProfile, useUpdateUserProfile } from '../../Services/BBPS/Hooks';
|
||||
import { useContractorProfile, useUpdateUserProfile, useESetuAdharVarification } from '../../Services/BBPS/Hooks';
|
||||
import colors from '../../Constant/Color';
|
||||
import { useSelector } from 'react-redux';
|
||||
import ConfirmDialog from '../../Constant/Dialog/ConfirmDialog';
|
||||
import { generateTransactionId } from '../../Helper/uniqueId';
|
||||
import NavigationString from '../../Constant/NavigationString';
|
||||
|
||||
const { width } = Dimensions.get('window');
|
||||
|
||||
@@ -102,10 +107,12 @@ interface ContractorData {
|
||||
|
||||
interface ProfileHeaderProps {
|
||||
data: ContractorData;
|
||||
displayName: string;
|
||||
}
|
||||
|
||||
interface QuickStatsProps {
|
||||
data: ContractorData;
|
||||
onAadhaarPress: () => void;
|
||||
}
|
||||
|
||||
interface InfoSectionProps {
|
||||
@@ -129,6 +136,7 @@ interface StatItem {
|
||||
label: string;
|
||||
value: string;
|
||||
color: string;
|
||||
onPress?: () => void;
|
||||
}
|
||||
|
||||
interface UpdateProfilePayload {
|
||||
@@ -150,11 +158,61 @@ const isValidValue = (value: any): boolean => {
|
||||
return true;
|
||||
};
|
||||
|
||||
// Helper function to check if section has any valid data
|
||||
const hasSectionData = (values: any[]): boolean => {
|
||||
return values.some(value => isValidValue(value));
|
||||
};
|
||||
|
||||
// Main Component
|
||||
const ProfileTab: React.FC = () => {
|
||||
const { data, refetch, isLoading, error } = useContractorProfile();
|
||||
console.log("ioioi",data)
|
||||
const user = useSelector((state: any) => state.token?.token);
|
||||
const Navigation: any = useNavigation();
|
||||
const { mutateAsync: eSetuAdharVarification, isPending } = useESetuAdharVarification();
|
||||
|
||||
const [editModalVisible, setEditModalVisible] = useState(false);
|
||||
const [showDialog, setShowDialog] = useState<boolean>(false);
|
||||
const [isNavigating, setIsNavigating] = useState<boolean>(false);
|
||||
|
||||
// Check if user is auction type
|
||||
const isAuctionUser = user?.userType?.toLowerCase() === 'auction';
|
||||
|
||||
// Get display data based on user type
|
||||
const displayName = isAuctionUser ? user?.fullName : data?.fullName;
|
||||
const displayMobile = isAuctionUser ? user?.mobileNo : data?.mobileNo;
|
||||
|
||||
const handleAadhaarPress = () => {
|
||||
if (user?.esetuVerified === 'Not Verified') {
|
||||
setShowDialog(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleProceedVerification = async () => {
|
||||
try {
|
||||
setIsNavigating(true);
|
||||
|
||||
const payload = {
|
||||
contId: user.id,
|
||||
transactionId: generateTransactionId(),
|
||||
udf1: "23.77",
|
||||
udf2: "77.34",
|
||||
udf3: "string",
|
||||
udf4: "string",
|
||||
responseUrl: "https://dev.procurelinc.in/"
|
||||
};
|
||||
|
||||
const res = await eSetuAdharVarification(payload);
|
||||
|
||||
setShowDialog(false);
|
||||
|
||||
Navigation.navigate(NavigationString.KycWebViewScreen, { res });
|
||||
|
||||
} catch (err) {
|
||||
console.log("Verification error:", err);
|
||||
Alert.alert('Error', 'Failed to initiate verification. Please try again.');
|
||||
setIsNavigating(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
@@ -200,30 +258,41 @@ const ProfileTab: React.FC = () => {
|
||||
windowSize={10}
|
||||
>
|
||||
{/* Header with Gradient */}
|
||||
<ProfileHeader data={data} />
|
||||
<ProfileHeader data={data} displayName={displayName || data.fullName} />
|
||||
|
||||
{/* Quick Stats */}
|
||||
<QuickStats data={data} />
|
||||
<QuickStats data={data} onAadhaarPress={handleAadhaarPress} />
|
||||
|
||||
{/* Personal Information */}
|
||||
{/* Personal Information - Always show */}
|
||||
<InfoSection
|
||||
title="Personal Information"
|
||||
IconComponent={UserCircle}
|
||||
delay={0}
|
||||
showEdit={true}
|
||||
showEdit={!isAuctionUser}
|
||||
onEdit={() => setEditModalVisible(true)}
|
||||
>
|
||||
<InfoRow label="Full Name" value={data.firstName+" "+data.middleName+" "+data.lastName} IconComponent={User} />
|
||||
<InfoRow
|
||||
label="Full Name"
|
||||
value={isAuctionUser ? displayName : `${data.firstName} ${data.middleName} ${data.lastName}`.trim()}
|
||||
IconComponent={User}
|
||||
/>
|
||||
<InfoRow label="Email" value={data.emailId} IconComponent={Mail} />
|
||||
<InfoRow
|
||||
label="Mobile"
|
||||
value={`${data.dialCode} ${data.mobileNo}`}
|
||||
value={isAuctionUser ? displayMobile : `${data.dialCode} ${data.mobileNo}`}
|
||||
IconComponent={Phone}
|
||||
/>
|
||||
<InfoRow label="Designation" value={data.designation} IconComponent={Briefcase} />
|
||||
</InfoSection>
|
||||
|
||||
{/* Company Details */}
|
||||
{/* Company Details - Only show if has data */}
|
||||
{hasSectionData([
|
||||
data.company,
|
||||
data.contractorType,
|
||||
data.contOrganization,
|
||||
data.agentWebsite,
|
||||
data.agentRegno
|
||||
]) && (
|
||||
<InfoSection title="Company Details" IconComponent={Building2} delay={0}>
|
||||
<InfoRow label="Company" value={data.company} IconComponent={Building} />
|
||||
<InfoRow label="Type" value={data.contractorType} IconComponent={Tag} />
|
||||
@@ -231,16 +300,31 @@ const ProfileTab: React.FC = () => {
|
||||
<InfoRow label="Website" value={data.agentWebsite} IconComponent={Globe} />
|
||||
<InfoRow label="Registration No" value={data.agentRegno} IconComponent={Award} />
|
||||
</InfoSection>
|
||||
)}
|
||||
|
||||
{/* Address Information */}
|
||||
{/* Address Information - Only show if has data */}
|
||||
{hasSectionData([
|
||||
data.agentAddress,
|
||||
data.agentCity,
|
||||
data.agentState,
|
||||
data.agentPincode
|
||||
]) && (
|
||||
<InfoSection title="Address Information" IconComponent={MapPin} delay={0}>
|
||||
<InfoRow label="Address" value={data.agentAddress} IconComponent={Home} />
|
||||
<InfoRow label="City" value={data.agentCity} IconComponent={Building2} />
|
||||
<InfoRow label="State" value={data.agentState} IconComponent={Map} />
|
||||
<InfoRow label="Pincode" value={data.agentPincode} IconComponent={Mailbox} />
|
||||
</InfoSection>
|
||||
)}
|
||||
|
||||
{/* Tax & Legal */}
|
||||
{/* Tax & Legal - Only show if has data */}
|
||||
{hasSectionData([
|
||||
data.orgPAN,
|
||||
data.orgPANname,
|
||||
data.orgPANdob,
|
||||
data.gistnNo,
|
||||
data.comAadharNo
|
||||
]) && (
|
||||
<InfoSection title="Tax & Legal Information" IconComponent={FileText} delay={0}>
|
||||
<InfoRow label="PAN Number" value={data.orgPAN} IconComponent={CreditCard} />
|
||||
<InfoRow label="PAN Name" value={data.orgPANname} IconComponent={Type} />
|
||||
@@ -248,8 +332,15 @@ const ProfileTab: React.FC = () => {
|
||||
<InfoRow label="GSTIN" value={data.gistnNo} IconComponent={Receipt} />
|
||||
<InfoRow label="Aadhar" value={data.comAadharNo} IconComponent={FileText} />
|
||||
</InfoSection>
|
||||
)}
|
||||
|
||||
{/* Registration Status */}
|
||||
{/* Registration Status - Only show if has data */}
|
||||
{hasSectionData([
|
||||
data.contractorClass,
|
||||
data.socialCategory,
|
||||
data.msmeStatus,
|
||||
data.expiryDate
|
||||
]) && (
|
||||
<InfoSection title="Registration Details" IconComponent={ClipboardCheck} delay={0}>
|
||||
<InfoRow label="Class" value={data.contractorClass} IconComponent={Star} />
|
||||
<InfoRow label="Category" value={data.socialCategory} IconComponent={List} />
|
||||
@@ -261,17 +352,40 @@ const ProfileTab: React.FC = () => {
|
||||
valueColor={colors.warning}
|
||||
/>
|
||||
</InfoSection>
|
||||
)}
|
||||
|
||||
<View style={{ height: 40 }} />
|
||||
</ScrollView>
|
||||
|
||||
{/* Edit Modal */}
|
||||
{/* Edit Modal - Only for tender users */}
|
||||
{!isAuctionUser && (
|
||||
<EditProfileModal
|
||||
visible={editModalVisible}
|
||||
onClose={() => setEditModalVisible(false)}
|
||||
data={data}
|
||||
onSuccess={refetch}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Aadhaar Verification Dialog */}
|
||||
<ConfirmDialog
|
||||
visible={showDialog}
|
||||
title="Aadhaar Verification Required"
|
||||
message="To access all features, please complete your Aadhaar verification."
|
||||
confirmText={isPending || isNavigating ? "Processing..." : "Proceed"}
|
||||
cancelText="Cancel"
|
||||
onConfirm={handleProceedVerification}
|
||||
onClose={() => !isPending && !isNavigating && setShowDialog(false)}
|
||||
loading={isPending || isNavigating}
|
||||
/>
|
||||
|
||||
{/* Navigation Overlay */}
|
||||
{isNavigating && (
|
||||
<View style={styles.navigationOverlay}>
|
||||
<ActivityIndicator size="large" color={colors.primary || '#2563EB'} />
|
||||
<Text style={styles.loadingText}>Loading verification...</Text>
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -303,7 +417,6 @@ const EditProfileModal: React.FC<EditProfileModalProps> = ({
|
||||
|
||||
const updateProfileMutation = useUpdateUserProfile();
|
||||
|
||||
// Reset form when modal opens
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
setFormData({
|
||||
@@ -341,7 +454,6 @@ const EditProfileModal: React.FC<EditProfileModalProps> = ({
|
||||
newErrors.mobileNo = 'Invalid mobile number';
|
||||
}
|
||||
|
||||
// Auto-generate fullname
|
||||
const generatedFullName = `${formData.firstName} ${formData.middleName} ${formData.lastName}`.trim();
|
||||
setFormData(prev => ({ ...prev, fullname: generatedFullName }));
|
||||
|
||||
@@ -376,7 +488,6 @@ const EditProfileModal: React.FC<EditProfileModalProps> = ({
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
>
|
||||
<View style={styles.modalContent}>
|
||||
{/* Header */}
|
||||
<View style={styles.modalHeader}>
|
||||
<Text style={styles.modalTitle}>Edit Personal Information</Text>
|
||||
<TouchableOpacity onPress={onClose} style={styles.closeButton}>
|
||||
@@ -384,9 +495,7 @@ const EditProfileModal: React.FC<EditProfileModalProps> = ({
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Form */}
|
||||
<ScrollView style={styles.formContainer} showsVerticalScrollIndicator={false}>
|
||||
{/* First Name */}
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.inputLabel}>First Name *</Text>
|
||||
<TextInput
|
||||
@@ -401,7 +510,6 @@ const EditProfileModal: React.FC<EditProfileModalProps> = ({
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* Middle Name */}
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.inputLabel}>Middle Name</Text>
|
||||
<TextInput
|
||||
@@ -413,7 +521,6 @@ const EditProfileModal: React.FC<EditProfileModalProps> = ({
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* Last Name */}
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.inputLabel}>Last Name *</Text>
|
||||
<TextInput
|
||||
@@ -428,7 +535,6 @@ const EditProfileModal: React.FC<EditProfileModalProps> = ({
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* Email */}
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.inputLabel}>Email *</Text>
|
||||
<TextInput
|
||||
@@ -445,7 +551,6 @@ const EditProfileModal: React.FC<EditProfileModalProps> = ({
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* Mobile Number */}
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.inputLabel}>Mobile Number *</Text>
|
||||
<TextInput
|
||||
@@ -463,7 +568,6 @@ const EditProfileModal: React.FC<EditProfileModalProps> = ({
|
||||
</View>
|
||||
</ScrollView>
|
||||
|
||||
{/* Footer Buttons */}
|
||||
<View style={styles.modalFooter}>
|
||||
<TouchableOpacity
|
||||
style={[styles.button, styles.cancelButton]}
|
||||
@@ -495,7 +599,7 @@ const EditProfileModal: React.FC<EditProfileModalProps> = ({
|
||||
};
|
||||
|
||||
// Profile Header Component - OPTIMIZED
|
||||
const ProfileHeader: React.FC<ProfileHeaderProps> = React.memo(({ data }) => {
|
||||
const ProfileHeader: React.FC<ProfileHeaderProps> = React.memo(({ data, displayName }) => {
|
||||
const getInitials = (name: string): string => {
|
||||
if (!name || typeof name !== 'string' || name.trim().length === 0) {
|
||||
const fallbackName = `${data.firstName || ''} ${data.lastName || ''}`.trim();
|
||||
@@ -537,7 +641,7 @@ const ProfileHeader: React.FC<ProfileHeaderProps> = React.memo(({ data }) => {
|
||||
>
|
||||
<View style={styles.avatarContainer}>
|
||||
<View style={styles.avatar}>
|
||||
<Text style={styles.avatarText}>{getInitials(data.fullName)}</Text>
|
||||
<Text style={styles.avatarText}>{getInitials(displayName)}</Text>
|
||||
</View>
|
||||
<View style={[styles.statusBadge, { backgroundColor: getStatusColor() }]}>
|
||||
<View style={styles.statusDot} />
|
||||
@@ -545,9 +649,7 @@ const ProfileHeader: React.FC<ProfileHeaderProps> = React.memo(({ data }) => {
|
||||
</View>
|
||||
|
||||
<Text style={styles.headerName}>
|
||||
{data.fullName ||
|
||||
`${data.firstName} ${data.lastName}`.trim() ||
|
||||
'Unknown User'}
|
||||
{displayName || 'Unknown User'}
|
||||
</Text>
|
||||
|
||||
<View style={styles.roleBadge}>
|
||||
@@ -561,15 +663,18 @@ const ProfileHeader: React.FC<ProfileHeaderProps> = React.memo(({ data }) => {
|
||||
|
||||
ProfileHeader.displayName = 'ProfileHeader';
|
||||
|
||||
// Quick Stats Component - OPTIMIZED
|
||||
const QuickStats: React.FC<QuickStatsProps> = React.memo(({ data }) => {
|
||||
// Quick Stats Component - OPTIMIZED WITH TOUCHABLE AADHAAR
|
||||
const QuickStats: React.FC<QuickStatsProps> = React.memo(({ data, onAadhaarPress }) => {
|
||||
const user = useSelector((state: any) => state.token?.token);
|
||||
|
||||
const stats: StatItem[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
Icon: CheckCircle,
|
||||
label: 'Status',
|
||||
value: data.isActive,
|
||||
color: colors.success,
|
||||
label: 'Aadhaar',
|
||||
value: user?.esetuVerified,
|
||||
color: user?.esetuVerified === 'Not Verified' ? colors.error : colors.success,
|
||||
onPress: onAadhaarPress,
|
||||
},
|
||||
{
|
||||
Icon: ShieldCheck,
|
||||
@@ -584,20 +689,37 @@ const QuickStats: React.FC<QuickStatsProps> = React.memo(({ data }) => {
|
||||
color: colors.info,
|
||||
},
|
||||
],
|
||||
[data.isActive, data.twoFactorAuthEnabled, data.registrationStatus]
|
||||
[data.twoFactorAuthEnabled, data.registrationStatus, user?.esetuVerified, onAadhaarPress]
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={styles.statsContainer}>
|
||||
{stats.map((stat) => (
|
||||
<View key={stat.label} style={styles.statCard}>
|
||||
{stats.map((stat) => {
|
||||
const CardContent = (
|
||||
<View style={styles.statCard}>
|
||||
<stat.Icon size={28} color={stat.color} />
|
||||
<Text style={styles.statValue} numberOfLines={2}>
|
||||
{stat.value}
|
||||
</Text>
|
||||
<Text style={styles.statLabel}>{stat.label}</Text>
|
||||
</View>
|
||||
))}
|
||||
);
|
||||
|
||||
if (stat.onPress) {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={stat.label}
|
||||
activeOpacity={0.7}
|
||||
onPress={stat.onPress}
|
||||
style={{ flex: 1 }}
|
||||
>
|
||||
{CardContent}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
|
||||
return <View key={stat.label} style={{ flex: 1 }}>{CardContent}</View>;
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
});
|
||||
@@ -633,7 +755,6 @@ InfoSection.displayName = 'InfoSection';
|
||||
// Info Row Component - OPTIMIZED
|
||||
const InfoRow: React.FC<InfoRowProps> = React.memo(
|
||||
({ label, value, IconComponent, valueColor }) => {
|
||||
// Return null if value is not valid
|
||||
if (!isValidValue(value)) {
|
||||
return null;
|
||||
}
|
||||
@@ -715,6 +836,7 @@ interface Styles {
|
||||
saveButton: ViewStyle;
|
||||
cancelButtonText: TextStyle;
|
||||
saveButtonText: TextStyle;
|
||||
navigationOverlay: ViewStyle;
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create<Styles>({
|
||||
@@ -763,7 +885,6 @@ const styles = StyleSheet.create<Styles>({
|
||||
fontWeight: '600',
|
||||
},
|
||||
|
||||
// Header Styles
|
||||
headerGradient: {
|
||||
paddingTop: Platform.OS === 'ios' ? 60 : 40,
|
||||
paddingBottom: 30,
|
||||
@@ -841,7 +962,6 @@ const styles = StyleSheet.create<Styles>({
|
||||
fontWeight: '600',
|
||||
},
|
||||
|
||||
// Stats Styles
|
||||
statsContainer: {
|
||||
flexDirection: 'row',
|
||||
marginHorizontal: 16,
|
||||
@@ -874,7 +994,6 @@ const styles = StyleSheet.create<Styles>({
|
||||
marginTop: 4,
|
||||
},
|
||||
|
||||
// Section Styles
|
||||
section: {
|
||||
marginHorizontal: 16,
|
||||
marginTop: 24,
|
||||
@@ -925,7 +1044,6 @@ const styles = StyleSheet.create<Styles>({
|
||||
backgroundColor: colors.primaryHighlight,
|
||||
},
|
||||
|
||||
// Info Row Styles
|
||||
infoRow: {
|
||||
borderRadius: 12,
|
||||
overflow: 'hidden',
|
||||
@@ -966,7 +1084,6 @@ const styles = StyleSheet.create<Styles>({
|
||||
lineHeight: 21,
|
||||
},
|
||||
|
||||
// Modal Styles
|
||||
modalOverlay: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||
@@ -1058,6 +1175,17 @@ const styles = StyleSheet.create<Styles>({
|
||||
fontWeight: '600',
|
||||
color: colors.white,
|
||||
},
|
||||
navigationOverlay: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.9)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
zIndex: 999,
|
||||
},
|
||||
});
|
||||
|
||||
export default ProfileTab;
|
||||
|
||||
@@ -12,6 +12,7 @@ const ProceedToBidDetail = () => {
|
||||
const { data, refetch, isRefetching } = useProceedToBid(tenderDataId?.tenderId);
|
||||
const { data: tenderResponse, refetch: tenderRefetch }: any = useFetchTenderById(tenderDataId?.tenderId);
|
||||
const tenderData = tenderResponse?.data;
|
||||
console.log("dataopop",tenderData)
|
||||
const [refreshing, setRefreshing] = React.useState(false);
|
||||
const [loading, setLoading] = React.useState(false);
|
||||
|
||||
@@ -174,8 +175,8 @@ const ProceedToBidDetail = () => {
|
||||
<Text style={styles.sectionTitle}>Envelope Submission Status</Text>
|
||||
<View style={styles.statusGrid}>
|
||||
<StatusIndicator status={tenderData?.envelopeASubmittStatus} label="Envelope A" />
|
||||
<StatusIndicator status={tenderData?.envelopeBSubmittStatus} label="Envelope B" />
|
||||
<StatusIndicator status={tenderData?.envelopeCSubmittStatus} label="Envelope C" />
|
||||
{tenderData?.showEB &&<StatusIndicator status={tenderData?.envelopeBSubmittStatus} label="Envelope B" />}
|
||||
{tenderData?.showEC &&<StatusIndicator status={tenderData?.envelopeCSubmittStatus} label="Envelope C" />}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
useFetchPurchaseTender,
|
||||
} from '../../Services/BBPS/Hooks';
|
||||
import colors from '../../Constant/Color';
|
||||
import { ShoppingCart } from 'lucide-react-native';
|
||||
import { ShoppingCart, Lock } from 'lucide-react-native';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import NavigationString from '../../Constant/NavigationString';
|
||||
import FontsFamily from '../../Constant/FontsFamily';
|
||||
@@ -33,6 +33,7 @@ const Tender = () => {
|
||||
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;
|
||||
@@ -54,10 +55,47 @@ const Tender = () => {
|
||||
}).start();
|
||||
};
|
||||
|
||||
// Check if user is auction type
|
||||
const isAuctionUser = reduxToken?.userType?.toLowerCase() === 'auction';
|
||||
|
||||
// Render restricted access message
|
||||
const renderRestrictedAccess = () => (
|
||||
<View style={styles.restrictedContainer}>
|
||||
<View style={styles.restrictedCard}>
|
||||
<View style={styles.iconContainer}>
|
||||
<Lock size={64} color={colors.primary} />
|
||||
</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
|
||||
style={[
|
||||
@@ -145,6 +183,8 @@ const Tender = () => {
|
||||
</View>
|
||||
|
||||
{selectedTab === 'live' ? <LiveTender /> : <PurchaseTenderAllList />}
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
@@ -197,4 +237,70 @@ const styles = StyleSheet.create({
|
||||
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,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -122,7 +122,7 @@ const ViewTenderDetail = () => {
|
||||
</View>
|
||||
|
||||
{item.fieldValue && (
|
||||
<View style={styles.fieldRow}>
|
||||
<View style={[styles.fieldRow,{backgroundColor:colors.lightGray,borderRadius:20,padding:10}]}>
|
||||
<Type size={16} color={colors.gray} />
|
||||
<Text style={styles.fieldValue}>{item.fieldValue}</Text>
|
||||
</View>
|
||||
@@ -143,14 +143,6 @@ const ViewTenderDetail = () => {
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
||||
<View style={styles.metaInfo}>
|
||||
<Text style={styles.metaText}>
|
||||
Type: {getLabelTypeText(item.labelTypeA || item.labelTypeB)}
|
||||
</Text>
|
||||
{item.docEnvelopeSeqId && (
|
||||
<Text style={styles.metaText}>ID: {item.docEnvelopeSeqId}</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
@@ -515,12 +507,12 @@ const styles = StyleSheet.create({
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 12,
|
||||
marginBottom:8,
|
||||
},
|
||||
labelName: {
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
color: colors.darkText,
|
||||
color: colors.primary,
|
||||
},
|
||||
mandatoryTag: {
|
||||
fontSize: 12,
|
||||
@@ -534,7 +526,7 @@ const styles = StyleSheet.create({
|
||||
fieldRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginTop: 8,
|
||||
marginTop: 4,
|
||||
},
|
||||
fieldValue: {
|
||||
fontSize: 14,
|
||||
|
||||
@@ -42,8 +42,8 @@ const Screens = {
|
||||
Registration,
|
||||
Partnership,
|
||||
LiveTenderDetail,
|
||||
ProfileTab, ,
|
||||
KycWebViewScreen
|
||||
ViewTenderDetail
|
||||
ProfileTab,
|
||||
KycWebViewScreen,
|
||||
ViewTenderDetail,
|
||||
}
|
||||
export default Screens
|
||||
Reference in New Issue
Block a user