296 lines
8.4 KiB
TypeScript
296 lines
8.4 KiB
TypeScript
import { ref, computed, onMounted, watch, defineComponent } from 'vue';
|
|
import { useRouter } from 'vue-router';
|
|
import { useQuasar } from 'quasar';
|
|
import { useRides } from '../composables/useRides';
|
|
import { useRideRequests } from '../composables/useRideRequests';
|
|
import MyRideCard from '../components/ride/MyRideCard.vue';
|
|
import RequestCard from '../components/ride/RequestCard.vue';
|
|
import type { Ride, RideRequest } from '../types';
|
|
import { useUserStore } from 'app/src/store';
|
|
|
|
export default defineComponent({
|
|
name: 'MyRidesPage',
|
|
|
|
components: {
|
|
MyRideCard,
|
|
RequestCard
|
|
},
|
|
|
|
setup() {
|
|
const router = useRouter();
|
|
const $q = useQuasar();
|
|
|
|
const userStore = useUserStore()
|
|
|
|
const {
|
|
myRides,
|
|
loading,
|
|
fetchMyRides,
|
|
deleteRide,
|
|
completeRideApi,
|
|
} = useRides();
|
|
|
|
const {
|
|
receivedRequests,
|
|
sentRequests,
|
|
loading: loadingRequests,
|
|
requestCounts,
|
|
fetchReceivedRequests,
|
|
fetchSentRequests,
|
|
acceptRequest: acceptRequestApi,
|
|
rejectRequest: rejectRequestApi,
|
|
cancelRequest: cancelRequestApi
|
|
} = useRideRequests();
|
|
|
|
// State
|
|
const activeTab = ref('upcoming');
|
|
const requestsSubTab = ref('received');
|
|
const roleFilter = ref<'all' | 'driver' | 'passenger'>('all');
|
|
const showRequestsDialog = ref(false);
|
|
const selectedRide = ref<Ride | null>(null);
|
|
const selectedRideRequests = ref<RideRequest[]>([]);
|
|
const currentUserId = ref<string>(userStore.my._id);
|
|
|
|
// Filters
|
|
const roleFilters = [
|
|
{ label: 'Tutti', value: 'all' },
|
|
{ label: '🚗 Come conducente', value: 'driver' },
|
|
{ label: '👤 Come passeggero', value: 'passenger' }
|
|
];
|
|
|
|
// Computed
|
|
const upcomingCount = computed(() => myRides.upcoming.length);
|
|
const pendingRequestsCount = computed(() => requestCounts.value.pending);
|
|
|
|
const filteredUpcoming = computed(() => {
|
|
if (roleFilter.value === 'all') return myRides.upcoming;
|
|
if (roleFilter.value === 'driver') {
|
|
return myRides.upcoming.filter(r => isDriver(r));
|
|
}
|
|
return myRides.upcoming.filter(r => !isDriver(r));
|
|
});
|
|
|
|
const filteredPast = computed(() => {
|
|
if (roleFilter.value === 'all') return myRides.past;
|
|
if (roleFilter.value === 'driver') {
|
|
return myRides.past.filter(r => isDriver(r));
|
|
}
|
|
return myRides.past.filter(r => !isDriver(r));
|
|
});
|
|
|
|
// Methods
|
|
const isDriver = (ride: Ride): boolean => {
|
|
const userId = typeof ride.userId === 'string' ? ride.userId : ride.userId._id;
|
|
return userId === currentUserId.value;
|
|
};
|
|
|
|
const getPendingRequests = (rideId: string): number => {
|
|
return receivedRequests.value.filter(r => {
|
|
const reqRideId = typeof r.rideId === 'string' ? r.rideId : r.rideId._id;
|
|
return reqRideId === rideId && r.status === 'pending';
|
|
}).length;
|
|
};
|
|
|
|
const canLeaveFeedback = (ride: Ride): boolean => {
|
|
// TODO: Implement logic to check if user can leave feedback
|
|
return ride.status === 'completed';
|
|
};
|
|
|
|
const goToCreate = () => {
|
|
router.push({ path: '/viaggi/richiedi' });
|
|
};
|
|
|
|
const goToRide = (rideId: string) => {
|
|
router.push(`/viaggi/ride/${rideId}`);
|
|
};
|
|
|
|
const goToProfile = (userId: string) => {
|
|
router.push(`/viaggi/profilo/${userId}`);
|
|
};
|
|
|
|
const editRide = (rideId: string) => {
|
|
router.push(`/viaggi/ride/${rideId}/modifica`);
|
|
};
|
|
|
|
const cancelRide = async (ride: Ride) => {
|
|
$q.dialog({
|
|
title: 'Cancella Viaggio',
|
|
message: 'Sei sicuro di voler cancellare questo viaggio?',
|
|
prompt: {
|
|
model: '',
|
|
type: 'text',
|
|
label: 'Motivo (opzionale)'
|
|
},
|
|
cancel: true
|
|
}).onOk(async (reason: string) => {
|
|
try {
|
|
await deleteRide(ride._id, reason);
|
|
$q.notify({ type: 'positive', message: 'Viaggio cancellato' });
|
|
await fetchMyRides();
|
|
} catch (error: any) {
|
|
$q.notify({ type: 'negative', message: error.data?.message || error.message });
|
|
}
|
|
});
|
|
};
|
|
|
|
const completeRide = async (ride: Ride) => {
|
|
$q.dialog({
|
|
title: 'Completa Viaggio',
|
|
message: 'Confermi che il viaggio è stato completato?',
|
|
cancel: true
|
|
}).onOk(async () => {
|
|
try {
|
|
await completeRideApi(ride._id);
|
|
$q.notify({ type: 'positive', message: 'Viaggio completato!' });
|
|
await fetchMyRides();
|
|
} catch (error: any) {
|
|
$q.notify({ type: 'negative', message: error.data?.message || error.message });
|
|
}
|
|
});
|
|
};
|
|
|
|
const openRequestsDialog = async (ride: Ride) => {
|
|
selectedRide.value = ride;
|
|
selectedRideRequests.value = receivedRequests.value.filter(r => {
|
|
const reqRideId = typeof r.rideId === 'string' ? r.rideId : r.rideId._id;
|
|
return reqRideId === ride._id;
|
|
});
|
|
showRequestsDialog.value = true;
|
|
};
|
|
|
|
const openFeedbackDialog = (ride: Ride) => {
|
|
router.push(`/viaggi/feedback/viaggio/${ride._id}`);
|
|
};
|
|
|
|
const acceptRequest = async (request: RideRequest) => {
|
|
$q.dialog({
|
|
title: 'Accetta Richiesta',
|
|
message: `Vuoi accettare la richiesta di ${getUserName(request.passengerId)}?`,
|
|
prompt: {
|
|
model: '',
|
|
type: 'text',
|
|
label: 'Messaggio (opzionale)'
|
|
},
|
|
cancel: true
|
|
}).onOk(async (message: string) => {
|
|
try {
|
|
await acceptRequestApi(request._id, message);
|
|
$q.notify({ type: 'positive', message: 'Richiesta accettata!' });
|
|
await fetchReceivedRequests();
|
|
await fetchMyRides();
|
|
} catch (error: any) {
|
|
$q.notify({ type: 'negative', message: error.data?.message || error.message });
|
|
}
|
|
});
|
|
};
|
|
|
|
const rejectRequest = async (request: RideRequest) => {
|
|
$q.dialog({
|
|
title: 'Rifiuta Richiesta',
|
|
message: 'Vuoi rifiutare questa richiesta?',
|
|
prompt: {
|
|
model: '',
|
|
type: 'text',
|
|
label: 'Motivo (opzionale)'
|
|
},
|
|
cancel: true
|
|
}).onOk(async (message: string) => {
|
|
try {
|
|
await rejectRequestApi(request._id, message);
|
|
$q.notify({ type: 'info', message: 'Richiesta rifiutata' });
|
|
await fetchReceivedRequests();
|
|
} catch (error: any) {
|
|
$q.notify({ type: 'negative', message: error.data?.message || error.message });
|
|
}
|
|
});
|
|
};
|
|
|
|
const cancelRequest = async (request: RideRequest) => {
|
|
$q.dialog({
|
|
title: 'Annulla Richiesta',
|
|
message: 'Vuoi annullare questa richiesta?',
|
|
cancel: true
|
|
}).onOk(async () => {
|
|
try {
|
|
await cancelRequestApi(request._id);
|
|
$q.notify({ type: 'info', message: 'Richiesta annullata' });
|
|
await fetchSentRequests();
|
|
} catch (error: any) {
|
|
$q.notify({ type: 'negative', message: error.data?.message || error.message });
|
|
}
|
|
});
|
|
};
|
|
|
|
const getUserName = (user: any): string => {
|
|
if (typeof user === 'string') return 'Utente';
|
|
if (user.name) return `${user.name} ${user.surname || ''}`.trim();
|
|
return user.username || 'Utente';
|
|
};
|
|
|
|
// Watch tab changes
|
|
watch(activeTab, async (tab) => {
|
|
if (tab === 'requests') {
|
|
if (requestsSubTab.value === 'received') {
|
|
await fetchReceivedRequests();
|
|
} else {
|
|
await fetchSentRequests();
|
|
}
|
|
}
|
|
});
|
|
|
|
watch(requestsSubTab, async (subTab) => {
|
|
if (subTab === 'received') {
|
|
await fetchReceivedRequests();
|
|
} else {
|
|
await fetchSentRequests();
|
|
}
|
|
});
|
|
|
|
// Lifecycle
|
|
onMounted(async () => {
|
|
await fetchMyRides();
|
|
await fetchReceivedRequests();
|
|
});
|
|
|
|
return {
|
|
// State
|
|
activeTab,
|
|
requestsSubTab,
|
|
roleFilter,
|
|
showRequestsDialog,
|
|
selectedRideRequests,
|
|
loading,
|
|
loadingRequests,
|
|
myRides,
|
|
receivedRequests,
|
|
sentRequests,
|
|
currentUserId,
|
|
|
|
// Filters
|
|
roleFilters,
|
|
|
|
// Computed
|
|
upcomingCount,
|
|
pendingRequestsCount,
|
|
filteredUpcoming,
|
|
filteredPast,
|
|
|
|
// Methods
|
|
isDriver,
|
|
getPendingRequests,
|
|
canLeaveFeedback,
|
|
goToCreate,
|
|
goToRide,
|
|
goToProfile,
|
|
editRide,
|
|
cancelRide,
|
|
completeRide,
|
|
openRequestsDialog,
|
|
openFeedbackDialog,
|
|
acceptRequest,
|
|
rejectRequest,
|
|
cancelRequest
|
|
};
|
|
}
|
|
});
|