387 lines
9.6 KiB
TypeScript
387 lines
9.6 KiB
TypeScript
import { ref, computed } from 'vue';
|
|
import { Api } from '@api';
|
|
import type {
|
|
DriverProfile,
|
|
Vehicle,
|
|
UserPreferences,
|
|
DriverPublicProfile
|
|
} from '../types/viaggi.types';
|
|
|
|
// ============================================================
|
|
// STATE
|
|
// ============================================================
|
|
|
|
const driverProfile = ref<DriverPublicProfile | null>(null);
|
|
const myDriverProfile = ref<DriverProfile | null>(null);
|
|
const myVehicles = ref<Vehicle[]>([]);
|
|
const myPreferences = ref<UserPreferences | null>(null);
|
|
|
|
const loading = ref(false);
|
|
const error = ref<string | null>(null);
|
|
|
|
// ============================================================
|
|
// COMPOSABLE
|
|
// ============================================================
|
|
|
|
export function useDriverProfile() {
|
|
|
|
// ------------------------------------------------------------
|
|
// COMPUTED
|
|
// ------------------------------------------------------------
|
|
|
|
const isDriver = computed(() => myDriverProfile.value?.isDriver ?? false);
|
|
const hasVehicles = computed(() => myVehicles.value.length > 0);
|
|
const defaultVehicle = computed(() =>
|
|
myVehicles.value.find(v => v.isDefault) || myVehicles.value[0]
|
|
);
|
|
const averageRating = computed(() => myDriverProfile.value?.averageRating ?? 0);
|
|
const totalRides = computed(() =>
|
|
(myDriverProfile.value?.ridesCompletedAsDriver ?? 0) +
|
|
(myDriverProfile.value?.ridesCompletedAsPassenger ?? 0)
|
|
);
|
|
|
|
// ------------------------------------------------------------
|
|
// API CALLS
|
|
// ------------------------------------------------------------
|
|
|
|
/**
|
|
* Ottieni profilo pubblico di un conducente
|
|
*/
|
|
const fetchDriverProfile = async (userId: string) => {
|
|
try {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
const response = await Api.SendReqWithData(
|
|
`/api/viaggi/driver/user/${userId}`,
|
|
'GET'
|
|
);
|
|
|
|
if (response.success && response.data) {
|
|
driverProfile.value = response.data;
|
|
}
|
|
|
|
return response;
|
|
} catch (err: any) {
|
|
error.value = err.message || 'Errore nel recupero del profilo';
|
|
throw err;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Aggiorna il mio profilo conducente e/o preferenze
|
|
*/
|
|
const updateDriverProfile = async (data: {
|
|
driverProfile?: Partial<DriverProfile>;
|
|
preferences?: Partial<UserPreferences>;
|
|
}) => {
|
|
try {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
const response = await Api.SendReqWithData(
|
|
'/api/viaggi/driver/profile',
|
|
'PUT',
|
|
{
|
|
...data
|
|
}
|
|
);
|
|
|
|
if (response.success && response.data) {
|
|
// Il backend ritorna user.profile che contiene driverProfile e preferences
|
|
if (response.data.driverProfile) {
|
|
myDriverProfile.value = response.data.driverProfile;
|
|
}
|
|
if (response.data.preferences) {
|
|
myPreferences.value = response.data.preferences;
|
|
}
|
|
}
|
|
|
|
return response;
|
|
} catch (err: any) {
|
|
error.value = err.message || 'Errore nell\'aggiornamento del profilo';
|
|
throw err;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Aggiorna solo le preferenze
|
|
*/
|
|
const updatePreferences = async (preferences: Partial<UserPreferences>) => {
|
|
return await updateDriverProfile({ preferences });
|
|
};
|
|
|
|
/**
|
|
* Aggiungi veicolo
|
|
*/
|
|
const addVehicle = async (vehicleData: Omit<Vehicle, '_id'>) => {
|
|
try {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
const response = await Api.SendReqWithData(
|
|
'/api/viaggi/driver/vehicles',
|
|
'POST',
|
|
{ vehicle: vehicleData }
|
|
);
|
|
|
|
if (response.success && response.data) {
|
|
myVehicles.value = response.data;
|
|
}
|
|
|
|
return response;
|
|
} catch (err: any) {
|
|
error.value = err.message || 'Errore nell\'aggiunta del veicolo';
|
|
throw err;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Aggiorna veicolo
|
|
*/
|
|
const updateVehicle = async (vehicleId: string, vehicleData: Partial<Vehicle>) => {
|
|
try {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
const response = await Api.SendReqWithData(
|
|
`/api/viaggi/driver/vehicles/${vehicleId}`,
|
|
'PUT',
|
|
{ vehicle: vehicleData }
|
|
);
|
|
|
|
if (response.success && response.data) {
|
|
myVehicles.value = response.data;
|
|
}
|
|
|
|
return response;
|
|
} catch (err: any) {
|
|
error.value = err.message || 'Errore nell\'aggiornamento del veicolo';
|
|
throw err;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Rimuovi veicolo
|
|
*/
|
|
const removeVehicle = async (vehicleId: string) => {
|
|
try {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
const response = await Api.SendReqWithData(
|
|
`/api/viaggi/driver/vehicles/${vehicleId}`,
|
|
'DELETE'
|
|
);
|
|
|
|
if (response.success) {
|
|
myVehicles.value = myVehicles.value.filter(v => v._id !== vehicleId);
|
|
}
|
|
|
|
return response;
|
|
} catch (err: any) {
|
|
error.value = err.message || 'Errore nella rimozione del veicolo';
|
|
throw err;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Imposta veicolo predefinito
|
|
*/
|
|
const setDefaultVehicle = async (vehicleId: string) => {
|
|
try {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
const response = await Api.SendReqWithData(
|
|
`/api/viaggi/driver/vehicles/${vehicleId}/default`,
|
|
'POST'
|
|
);
|
|
|
|
if (response.success) {
|
|
// Aggiorna localmente
|
|
myVehicles.value = myVehicles.value.map(v => ({
|
|
...v,
|
|
isDefault: v._id === vehicleId
|
|
}));
|
|
}
|
|
|
|
return response;
|
|
} catch (err: any) {
|
|
error.value = err.message || 'Errore nell\'impostazione del veicolo predefinito';
|
|
throw err;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
// ------------------------------------------------------------
|
|
// UTILITIES
|
|
// ------------------------------------------------------------
|
|
|
|
/**
|
|
* Formatta tipo veicolo
|
|
*/
|
|
const formatVehicleType = (type: string): string => {
|
|
const types: Record<string, string> = {
|
|
auto: '🚗 Auto',
|
|
moto: '🏍️ Moto',
|
|
furgone: '🚐 Furgone',
|
|
minibus: '🚌 Minibus',
|
|
altro: '🚙 Altro'
|
|
};
|
|
return types[type] || type;
|
|
};
|
|
|
|
/**
|
|
* Formatta veicolo completo
|
|
*/
|
|
const formatVehicle = (vehicle: Vehicle): string => {
|
|
const parts = [];
|
|
if (vehicle.brand) parts.push(vehicle.brand);
|
|
if (vehicle.model) parts.push(vehicle.model);
|
|
if (vehicle.color) parts.push(`(${vehicle.color})`);
|
|
return parts.join(' ') || 'Veicolo';
|
|
};
|
|
|
|
/**
|
|
* Formatta response time
|
|
*/
|
|
const formatResponseTime = (time?: string): string => {
|
|
const times: Record<string, string> = {
|
|
within_hour: 'Entro un\'ora',
|
|
within_day: 'Entro un giorno',
|
|
within_days: 'Entro qualche giorno'
|
|
};
|
|
return times[time || 'within_day'] || 'N/D';
|
|
};
|
|
|
|
/**
|
|
* Formatta member since
|
|
*/
|
|
const formatMemberSince = (date?: Date | string): string => {
|
|
if (!date) return 'N/D';
|
|
const d = new Date(date);
|
|
return d.toLocaleDateString('it-IT', { month: 'long', year: 'numeric' });
|
|
};
|
|
|
|
/**
|
|
* Calcola livello utente
|
|
*/
|
|
const calculateLevel = (points: number): { level: number; progress: number; nextLevel: number } => {
|
|
const levels = [0, 100, 300, 600, 1000, 1500, 2500, 4000, 6000, 10000];
|
|
let level = 1;
|
|
|
|
for (let i = 1; i < levels.length; i++) {
|
|
if (points >= levels[i]) {
|
|
level = i + 1;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
const currentLevelPoints = levels[level - 1] || 0;
|
|
const nextLevelPoints = levels[level] || levels[levels.length - 1];
|
|
const progress = ((points - currentLevelPoints) / (nextLevelPoints - currentLevelPoints)) * 100;
|
|
|
|
return {
|
|
level,
|
|
progress: Math.min(100, Math.max(0, progress)),
|
|
nextLevel: nextLevelPoints
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Ottieni badge icon
|
|
*/
|
|
const getBadgeIcon = (badgeName: string): string => {
|
|
const badges: Record<string, string> = {
|
|
first_ride: '🎉',
|
|
five_rides: '🚗',
|
|
ten_rides: '🏆',
|
|
fifty_rides: '⭐',
|
|
hundred_rides: '👑',
|
|
eco_warrior: '🌱',
|
|
super_driver: '🦸',
|
|
top_rated: '💯',
|
|
fast_responder: '⚡',
|
|
friendly: '😊'
|
|
};
|
|
return badges[badgeName] || '🏅';
|
|
};
|
|
|
|
/**
|
|
* Inizializza profilo dal user corrente (userStore)
|
|
*/
|
|
const initFromUser = (user: any) => {
|
|
if (user?.profile?.driverProfile) {
|
|
myDriverProfile.value = user.profile.driverProfile;
|
|
myVehicles.value = user.profile.driverProfile.vehicles || [];
|
|
}
|
|
if (user?.profile?.preferences) {
|
|
myPreferences.value = user.profile.preferences;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Pulisci stato
|
|
*/
|
|
const clearState = () => {
|
|
driverProfile.value = null;
|
|
myDriverProfile.value = null;
|
|
myVehicles.value = [];
|
|
myPreferences.value = null;
|
|
error.value = null;
|
|
};
|
|
|
|
// ------------------------------------------------------------
|
|
// RETURN
|
|
// ------------------------------------------------------------
|
|
|
|
return {
|
|
// State
|
|
driverProfile,
|
|
myDriverProfile,
|
|
myVehicles,
|
|
myPreferences,
|
|
loading,
|
|
error,
|
|
|
|
// Computed
|
|
isDriver,
|
|
hasVehicles,
|
|
defaultVehicle,
|
|
averageRating,
|
|
totalRides,
|
|
|
|
// API Methods
|
|
fetchDriverProfile,
|
|
updateDriverProfile,
|
|
updatePreferences,
|
|
addVehicle,
|
|
updateVehicle,
|
|
removeVehicle,
|
|
setDefaultVehicle,
|
|
|
|
// Utilities
|
|
formatVehicleType,
|
|
formatVehicle,
|
|
formatResponseTime,
|
|
formatMemberSince,
|
|
calculateLevel,
|
|
getBadgeIcon,
|
|
initFromUser,
|
|
clearState
|
|
};
|
|
}
|