Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions admin-dashboard/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Flux Admin Dashboard</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
</head>
<body>
<div id="root"></div>
Expand Down
9 changes: 9 additions & 0 deletions admin-dashboard/public/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 10 additions & 6 deletions mobile/FluxRider/src/components/PopupNotifications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import {X, Bell, CheckCircle, AlertCircle} from 'lucide-react-native';
import {useNotification} from '../context/NotificationContext';
import {colors} from '../theme';
import CardGradient from './CardGradient';

const NotificationItem: React.FC<{
id: string;
Expand Down Expand Up @@ -68,7 +69,7 @@ const NotificationItem: React.FC<{
};

const getBgColor = () => {
return colors.surface;
return colors.surfaceAlt;
};

const getBorderColor = () => {
Expand All @@ -89,12 +90,15 @@ const NotificationItem: React.FC<{
style={[
styles.container,
{
backgroundColor: getBgColor(),
backgroundColor: colors.bg,
borderColor: getBorderColor(),
transform: [{translateY}],
opacity,
},
]}>
<View style={StyleSheet.absoluteFill}>
<CardGradient radius={16} />
</View>
<TouchableOpacity
style={styles.tapArea}
activeOpacity={0.85}
Expand Down Expand Up @@ -161,11 +165,11 @@ const styles = StyleSheet.create({
overflow: 'hidden',
borderRadius: 16,
borderWidth: 1,
shadowColor: '#000',
shadowColor: colors.accent,
shadowOffset: {width: 0, height: 4},
shadowOpacity: 0.4,
shadowRadius: 8,
elevation: 6,
shadowOpacity: 0.8,
shadowRadius: 16,
elevation: 10,
marginBottom: 10,
},
tapArea: {
Expand Down
13 changes: 7 additions & 6 deletions mobile/FluxRider/src/context/NotificationContext.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {createContext, useContext, useState, useCallback} from 'react';
import React, {createContext, useContext, useState, useCallback, useRef} from 'react';

export interface Notification {
id: string;
Expand All @@ -22,6 +22,7 @@ const NotificationContext = createContext<NotificationContextType | undefined>(
export const NotificationProvider: React.FC<{children: React.ReactNode}> = ({
children,
}) => {
const seenIds = useRef<Set<string>>(new Set());
const [notifications, setNotifications] = useState<Notification[]>([]);

const hideNotification = useCallback((id: string) => {
Expand All @@ -32,12 +33,12 @@ export const NotificationProvider: React.FC<{children: React.ReactNode}> = ({
(notification: Notification | Omit<Notification, 'id'>) => {
const id = 'id' in notification && notification.id ? notification.id : Math.random().toString(36).substring(7);

if (seenIds.current.has(id)) {
return; // Ignore if we've already shown this
}
seenIds.current.add(id);

setNotifications(prev => {
// Deduplicate: if a notification with this ID already exists, don't add it again
if (prev.some(n => n.id === id)) {
return prev;
}

// Auto hide after 5 seconds for new notifications
setTimeout(() => {
hideNotification(id);
Expand Down
17 changes: 12 additions & 5 deletions mobile/FluxRider/src/screens/AvailableBookingsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ const AvailableBookingsScreen = ({navigation}: any) => {
return Number.isFinite(num) && Math.abs(num) <= 180;
};


useEffect(() => {
if (availableBookings.length > 0 && currentIndex >= availableBookings.length) {
setCurrentIndex(availableBookings.length - 1);
} else if (availableBookings.length === 0 && currentIndex !== 0) {
setCurrentIndex(0);
}
}, [availableBookings.length, currentIndex]);

const fetchAvailableBookings = useCallback(
async (lat?: number, lng?: number) => {
const latitude = lat || currentLocation?.latitude || 28.6139;
Expand Down Expand Up @@ -125,7 +134,6 @@ const AvailableBookingsScreen = ({navigation}: any) => {
.filter(Boolean);

dispatch(setAvailableBookings(bookings));
setCurrentIndex(0);
} catch (error: any) {
console.log('Error fetching bookings:', error);
Alert.alert(
Expand Down Expand Up @@ -231,7 +239,6 @@ const AvailableBookingsScreen = ({navigation}: any) => {
dispatch(addBid(response.data));
Alert.alert('Success', 'Bid placed successfully!');
setBidAmount('');
handleNext();
} catch (error: any) {
Alert.alert(
'Error',
Expand All @@ -249,7 +256,7 @@ const AvailableBookingsScreen = ({navigation}: any) => {
const response = await api.post(`/bookings/${currentBooking.id}/accept-user-price`);
Alert.alert('Success', 'You have accepted this ride!');
dispatch(setAvailableBookings([]));
navigation.navigate('ActiveBooking');
(navigation as any).replace('RideTracking', { bookingId: currentBooking.id });
} catch (error: any) {
Alert.alert(
'Error',
Expand Down Expand Up @@ -655,10 +662,10 @@ const styles = StyleSheet.create({
elevation: 10,
},
cardScroll: {
maxHeight: 404,
maxHeight: 600,
},
cardScrollContent: {
paddingBottom: 6,
paddingBottom: 24,
},
bidInputContainer: {
flex: 1,
Expand Down
9 changes: 8 additions & 1 deletion mobile/FluxRider/src/screens/RideTrackingScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,14 @@ const RideTrackingScreen = () => {
try {
const response = await api.get(`/bookings/${resolvedBookingId}`);
setBooking(response.data);
const nextStatus = String(response.data?.status || 'ACCEPTED') as
const status = response.data?.status;
if (status === 'CANCELLED_BY_USER' || status === 'CANCELLED') {
Alert.alert('Ride Cancelled', 'The user has cancelled the ride.');
(navigation as any).replace('Home');
return;
}

const nextStatus = String(status || 'ACCEPTED') as
| 'ACCEPTED'
| 'RIDER_EN_ROUTE'
| 'RIDER_ARRIVED'
Expand Down
3 changes: 2 additions & 1 deletion mobile/FluxRider/src/store/slices/riderSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ const riderSlice = createSlice({
state.currentLocation = action.payload;
},
setAvailableBookings: (state, action: PayloadAction<Booking[]>) => {
state.availableBookings = action.payload;
const biddedIds = new Set(state.myBids.map(bid => bid.bookingId));
state.availableBookings = action.payload.filter(b => !biddedIds.has(b.id));
},
addAvailableBooking: (state, action: PayloadAction<Booking>) => {
const exists = state.availableBookings.find(
Expand Down
16 changes: 10 additions & 6 deletions mobile/FluxUser/src/components/PopupNotifications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import {X, Bell, CheckCircle, AlertCircle} from 'lucide-react-native';
import {useNotification} from '../context/NotificationContext';
import {colors} from '../theme';
import CardGradient from './CardGradient';

const NotificationItem: React.FC<{
id: string;
Expand Down Expand Up @@ -69,7 +70,7 @@ const NotificationItem: React.FC<{
};

const getBgColor = () => {
return colors.surface;
return colors.surfaceAlt;
};

const getBorderColor = () => {
Expand All @@ -90,12 +91,15 @@ const NotificationItem: React.FC<{
style={[
styles.container,
{
backgroundColor: getBgColor(),
backgroundColor: colors.bg,
borderColor: getBorderColor(),
transform: [{translateY}],
opacity,
},
]}>
<View style={StyleSheet.absoluteFill}>
<CardGradient radius={16} />
</View>
<TouchableOpacity
style={styles.tapArea}
activeOpacity={0.85}
Expand Down Expand Up @@ -162,11 +166,11 @@ const styles = StyleSheet.create({
overflow: 'hidden',
borderRadius: 16,
borderWidth: 1,
shadowColor: '#000',
shadowColor: colors.accent,
shadowOffset: {width: 0, height: 4},
shadowOpacity: 0.4,
shadowRadius: 8,
elevation: 6,
shadowOpacity: 0.8,
shadowRadius: 16,
elevation: 10,
marginBottom: 10,
},
tapArea: {
Expand Down
13 changes: 7 additions & 6 deletions mobile/FluxUser/src/context/NotificationContext.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {createContext, useContext, useState, useCallback} from 'react';
import React, {createContext, useContext, useState, useCallback, useRef} from 'react';

export interface Notification {
id: string;
Expand All @@ -22,6 +22,7 @@ const NotificationContext = createContext<NotificationContextType | undefined>(
export const NotificationProvider: React.FC<{children: React.ReactNode}> = ({
children,
}) => {
const seenIds = useRef<Set<string>>(new Set());
const [notifications, setNotifications] = useState<Notification[]>([]);

const hideNotification = useCallback((id: string) => {
Expand All @@ -32,12 +33,12 @@ export const NotificationProvider: React.FC<{children: React.ReactNode}> = ({
(notification: Notification | Omit<Notification, 'id'>) => {
const id = 'id' in notification && notification.id ? notification.id : Math.random().toString(36).substring(7);

if (seenIds.current.has(id)) {
return; // Ignore if we've already shown this
}
seenIds.current.add(id);

setNotifications(prev => {
// Deduplicate: if a notification with this ID already exists, don't add it again
if (prev.some(n => n.id === id)) {
return prev;
}

// Auto hide after 5 seconds for new notifications
setTimeout(() => {
hideNotification(id);
Expand Down
12 changes: 1 addition & 11 deletions mobile/FluxUser/src/screens/ActiveBookingScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,17 +164,7 @@ const ActiveBookingScreen = () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
Alert.alert(
'Rider Cancelled',
'The rider has cancelled. Finding another rider for you...',
[
{
text: 'OK',
onPress: () =>
(navigation as any).replace('BidSelection', {bookingId}),
},
],
);
(navigation as any).replace('BidSelection', {bookingId});
}
} catch (error) {
console.log('Error fetching booking:', error);
Expand Down
14 changes: 9 additions & 5 deletions mobile/FluxUser/src/screens/RatingScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
TextInput,
Alert,
SafeAreaView,
KeyboardAvoidingView,
Platform,
ScrollView,
Animated,
ActivityIndicator,
Expand Down Expand Up @@ -137,8 +139,9 @@ const RatingScreen = ({navigation, route}: any) => {

return (
<SafeAreaView className="flex-1" style={{backgroundColor: colors.bg}}>
<ScrollView className="flex-1" showsVerticalScrollIndicator={false}>
<View className="px-6 pt-4 pb-10">
<KeyboardAvoidingView behavior={Platform.OS === "ios" ? "padding" : undefined} className="flex-1">
<View className="flex-1 justify-between px-6 pt-4 pb-6">
<View className="flex-1">
<TouchableOpacity
onPress={() => navigation.goBack()}
className="p-2.5 rounded-xl border self-start mb-10"
Expand All @@ -149,7 +152,7 @@ const RatingScreen = ({navigation, route}: any) => {
<ArrowLeft size={24} color={colors.text} strokeWidth={2.5} />
</TouchableOpacity>

<View className="items-center mb-12">
<View className="items-center">
<View
className="p-6 rounded-[40px] shadow-2xl mb-8"
style={{backgroundColor: colors.accent}}>
Expand All @@ -166,7 +169,7 @@ const RatingScreen = ({navigation, route}: any) => {
</View>

<View
className="rounded-[40px] p-8 border mb-8"
className="rounded-[40px] p-8 border mb-4"
style={{
backgroundColor: colors.surface,
borderColor: colors.border,
Expand Down Expand Up @@ -286,7 +289,8 @@ const RatingScreen = ({navigation, route}: any) => {
)}
</TouchableOpacity>
</View>
</ScrollView>
</View>
</KeyboardAvoidingView>
</SafeAreaView>
);
};
Expand Down
Loading