191 lines
4.9 KiB
TypeScript
191 lines
4.9 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 { useChat } from '../composables/useChat';
|
|
import RideCard from '../components/ride/RideCard.vue';
|
|
import RideFilters from '../components/ride/RideFilters.vue';
|
|
import type { Ride, RideSearchFilters, RideType } from '../types';
|
|
import { useUserStore } from 'app/src/store';
|
|
|
|
export default defineComponent({
|
|
name: 'RidesListPage',
|
|
|
|
components: {
|
|
RideCard,
|
|
RideFilters
|
|
},
|
|
|
|
setup() {
|
|
const router = useRouter();
|
|
const $q = useQuasar();
|
|
|
|
const {
|
|
rides,
|
|
loading,
|
|
pagination,
|
|
filters,
|
|
hasMorePages,
|
|
fetchRides,
|
|
searchRides,
|
|
loadMore: loadMoreRides,
|
|
resetFilters
|
|
} = useRides();
|
|
|
|
const { createRequest } = useRideRequests();
|
|
const { getOrCreateDirectChat } = useChat();
|
|
|
|
// State
|
|
const userStore = useUserStore()
|
|
const activeTab = ref<'all' | 'offers' | 'requests'>('all');
|
|
const currentUserId = ref<string>(userStore.my._id);
|
|
|
|
|
|
// Computed
|
|
const filteredRides = computed(() => {
|
|
if (activeTab.value === 'all') return rides.value;
|
|
const type: RideType = activeTab.value === 'offers' ? 'offer' : 'request';
|
|
return rides.value.filter(r => r.type === type);
|
|
});
|
|
|
|
const offersCount = computed(() =>
|
|
rides.value.filter(r => r.type === 'offer').length
|
|
);
|
|
|
|
const requestsCount = computed(() =>
|
|
rides.value.filter(r => r.type === 'request').length
|
|
);
|
|
|
|
const hasActiveFilters = computed(() => {
|
|
return !!(filters.from || filters.to || filters.date || filters.type);
|
|
});
|
|
|
|
// Methods
|
|
const handleSearch = async (searchFilters: RideSearchFilters) => {
|
|
await searchRides(searchFilters);
|
|
};
|
|
|
|
const handleReset = async () => {
|
|
resetFilters();
|
|
await fetchRides({ reset: true });
|
|
};
|
|
|
|
const loadMore = async () => {
|
|
await loadMoreRides();
|
|
};
|
|
|
|
const goToCreate = () => {
|
|
const type = activeTab.value === 'requests' ? 'request' : 'offer';
|
|
router.push({ path: '/viaggi/richiedi', query: { type } });
|
|
};
|
|
|
|
const goToDetail = (rideId: string) => {
|
|
router.push(`/viaggi/ride/${rideId}`);
|
|
};
|
|
|
|
const goToDriverProfile = (userId: string) => {
|
|
router.push(`/viaggi/profilo/${userId}`);
|
|
};
|
|
|
|
const handleBook = async (ride: Ride) => {
|
|
// Apri dialog per prenotazione
|
|
$q.dialog({
|
|
title: 'Richiedi Passaggio',
|
|
message: `Vuoi richiedere un passaggio per il viaggio ${ride.departure.city} → ${ride.destination.city}?`,
|
|
prompt: {
|
|
model: '',
|
|
type: 'textarea',
|
|
label: 'Messaggio (opzionale)',
|
|
placeholder: 'Scrivi un messaggio al conducente...'
|
|
},
|
|
cancel: true,
|
|
persistent: true
|
|
}).onOk(async (message: string) => {
|
|
try {
|
|
$q.loading.show({ message: 'Invio richiesta...' });
|
|
|
|
await createRequest({
|
|
rideId: ride._id,
|
|
message,
|
|
seatsRequested: 1,
|
|
useOriginalRoute: true
|
|
});
|
|
|
|
$q.notify({
|
|
type: 'positive',
|
|
message: 'Richiesta inviata con successo!',
|
|
caption: 'Il conducente riceverà la tua richiesta'
|
|
});
|
|
|
|
} catch (error: any) {
|
|
$q.notify({
|
|
type: 'negative',
|
|
message: 'Errore nell\'invio della richiesta',
|
|
caption: error.data?.message || error.message
|
|
});
|
|
} finally {
|
|
$q.loading.hide();
|
|
}
|
|
});
|
|
};
|
|
|
|
const handleContact = async (ride: Ride) => {
|
|
try {
|
|
const userId = typeof ride.userId === 'string' ? ride.userId : ride.userId._id;
|
|
const response = await getOrCreateDirectChat(userId, ride._id);
|
|
|
|
if (response?.data) {
|
|
router.push(`/viaggi/chat/${response.data._id}`);
|
|
}
|
|
} catch (error: any) {
|
|
$q.notify({
|
|
type: 'negative',
|
|
message: 'Errore nell\'apertura della chat',
|
|
caption: error.data?.message || error.message
|
|
});
|
|
}
|
|
};
|
|
|
|
// Watch tab changes
|
|
watch(activeTab, (newTab) => {
|
|
if (newTab === 'all') {
|
|
filters.type = undefined;
|
|
} else {
|
|
filters.type = newTab === 'offers' ? 'offer' : 'request';
|
|
}
|
|
});
|
|
|
|
// Lifecycle
|
|
onMounted(async () => {
|
|
await fetchRides({ reset: true });
|
|
});
|
|
|
|
return {
|
|
// State
|
|
rides,
|
|
loading,
|
|
filters,
|
|
activeTab,
|
|
currentUserId,
|
|
hasMorePages,
|
|
|
|
// Computed
|
|
filteredRides,
|
|
offersCount,
|
|
requestsCount,
|
|
hasActiveFilters,
|
|
|
|
// Methods
|
|
handleSearch,
|
|
handleReset,
|
|
loadMore,
|
|
goToCreate,
|
|
goToDetail,
|
|
goToDriverProfile,
|
|
handleBook,
|
|
handleContact
|
|
};
|
|
}
|
|
});
|