Files
ProcureLinc-Mobile-App/src/Component/SideDrawer/SideDrawer.tsx
T
2026-01-15 17:21:34 +05:30

258 lines
6.5 KiB
TypeScript

import React, { useEffect } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, Dimensions, Image } from 'react-native';
import Modal from 'react-native-modal';
import Animated, { useSharedValue, useAnimatedStyle, withTiming, withDelay } from 'react-native-reanimated';
import { Home, Gavel, FileText, User, LogOut, ChevronRight } from 'lucide-react-native';
import { CommonActions, useNavigation } from '@react-navigation/native';
import { useDispatch, useSelector } from 'react-redux';
import { removeToken } from '../../Redux/Slices/Token';
import NavigationString from '../../Constant/NavigationString';
import colors from '../../Constant/Color';
const { width, height } = Dimensions.get('window');
const DRAWER_WIDTH = width * 0.78;
interface Props { visible: boolean; onClose: () => void; }
const SideDrawer: React.FC<Props> = ({ visible, onClose }) => {
const navigation: any = useNavigation();
const dispatch = useDispatch();
const userData = useSelector((state: any) => state.token?.token);
const user = { name: userData?.fullName, role: userData?.role, };
const translateX = useSharedValue(-DRAWER_WIDTH);
useEffect(() => {
translateX.value = visible
? withTiming(0, { duration: 0 })
: withTiming(-DRAWER_WIDTH, { duration: 250 });
}, [visible]);
const drawerStyle = useAnimatedStyle(() => ({
transform: [{ translateX: translateX.value }],
}));
const menuItems = [
{
label: 'Profile',
icon: User,
onPress: () => navigation.navigate(NavigationString.Profile),
},
{
label: 'Home',
icon: Home,
onPress: () => navigation.navigate(NavigationString.Home),
},
{
label: 'Auctions',
icon: Gavel,
onPress: () => navigation.navigate(NavigationString.Auction),
},
{
label: 'Tenders',
icon: FileText,
onPress: () => navigation.navigate(NavigationString.Tender),
},
];
return (
<Modal
isVisible={visible}
onBackdropPress={onClose}
onBackButtonPress={onClose}
backdropOpacity={0.45}
animationIn="fadeIn"
animationOut="fadeOut"
style={styles.modal}
useNativeDriver
coverScreen={false}
propagateSwipe
>
<Animated.View style={[styles.drawer, drawerStyle]}>
{/* ================= Header / Profile ================= */}
<View style={styles.profileHeader}>
{/* <TouchableOpacity style={styles.closeBtn} onPress={() => {
console.log('sdfadsfdsf');
}}>
<X size={20} color="#111827" />
</TouchableOpacity> */}
<View style={styles.avatar}>
<User size={40} color={colors.black} strokeWidth={2} />
</View>
<Text style={styles.userName}>{user.name}</Text>
<Text style={styles.userRole}>{user.role}</Text>
</View>
{/* ================= Menu ================= */}
<View style={styles.menuContainer}>
{menuItems.map((item, index) => {
const Icon = item.icon;
const itemStyle = useAnimatedStyle(() => ({
opacity: withDelay(
index * 80,
withTiming(1, { duration: 300 }),
),
transform: [
{
translateX: withDelay(
index * 80,
withTiming(0, { duration: 300 }),
),
},
],
}));
return (
<Animated.View key={item.label} style={itemStyle}>
<TouchableOpacity
style={styles.menuItem}
activeOpacity={0.7}
onPress={() => {
onClose();
item.onPress();
}}
>
<View style={styles.menuLeft}>
<Icon size={20} color="#1F2937" />
<Text style={styles.menuText}>{item.label}</Text>
</View>
<ChevronRight size={18} color="#9CA3AF" />
</TouchableOpacity>
</Animated.View>
);
})}
</View>
{/* ================= Logout ================= */}
<View style={styles.logoutContainer}>
<TouchableOpacity
style={styles.logoutBtn}
onPress={() => {
dispatch(removeToken());
navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [{ name: NavigationString.Login }],
}),
);
}}
>
<LogOut size={20} color="#EF4444" />
<Text style={styles.logoutText}>Logout</Text>
</TouchableOpacity>
</View>
</Animated.View>
</Modal>
);
};
export default SideDrawer;
const styles = StyleSheet.create({
modal: {
margin: 0,
justifyContent: 'flex-start',
},
drawer: {
width: DRAWER_WIDTH,
height: height - 80,
backgroundColor: '#FFFFFF',
borderTopRightRadius: 24,
borderBottomRightRadius: 24,
elevation: 12,
},
/* -------- Profile -------- */
profileHeader: {
backgroundColor: '#F9FAFB',
paddingTop: 50,
paddingBottom: 24,
alignItems: 'center',
borderTopRightRadius: 24,
},
closeBtn: {
position: 'absolute',
top: 20,
right: 16,
padding: 10,
zIndex: 20
},
avatar: {
justifyContent:'center',
alignItems:'center',
backgroundColor:colors.primary,
padding:25,
borderRadius:60,
marginBottom: 10,
},
userName: {
fontSize: 18,
fontWeight: '700',
color: '#111827',
},
userRole: {
fontSize: 13,
color: '#6B7280',
marginTop: 2,
},
/* -------- Menu -------- */
menuContainer: {
paddingHorizontal: 14,
paddingTop: 20,
},
menuItem: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingVertical: 14,
paddingHorizontal: 12,
borderRadius: 14,
marginBottom: 6,
},
menuLeft: {
flexDirection: 'row',
alignItems: 'center',
gap: 12,
},
menuText: {
fontSize: 16,
fontWeight: '600',
color: '#1F2937',
},
/* -------- Logout -------- */
logoutContainer: {
marginTop: 'auto',
paddingHorizontal: 14,
paddingBottom: 24,
borderTopWidth: 1,
borderTopColor: '#E5E7EB',
},
logoutBtn: {
flexDirection: 'row',
alignItems: 'center',
gap: 12,
paddingVertical: 16,
},
logoutText: {
fontSize: 16,
fontWeight: '600',
color: '#EF4444',
},
});