Fix favorites system, add support for bus stops and tourist trips, and improve UI consistency

This commit is contained in:
2026-02-24 21:55:52 -05:00
parent 973483fa35
commit 4bf75d3302
7 changed files with 114 additions and 65 deletions

View File

@ -12,10 +12,11 @@ const selectedFilter = ref('all')
const filters = [
{ key: 'all', label: 'Todos', icon: 'star' },
{ key: 'routes', label: 'Rutas', icon: 'directions_bus' },
{ key: 'routes', label: 'Buses', icon: 'directions_bus' },
{ key: 'taxis', label: 'Taxis', icon: 'local_taxi' },
{ key: 'businesses',label: 'Negocios', icon: 'store' },
{ key: 'coupons', label: 'Eventos', icon: 'confirmation_number' },
{ key: 'businesses',label: 'Comercios', icon: 'store' },
{ key: 'coupons', label: 'Ofertas', icon: 'confirmation_number' },
{ key: 'stops', label: 'Paradas', icon: 'location_on' },
]
onMounted(async () => {
@ -34,9 +35,11 @@ async function removeFavorite(event: Event, itemType: string, itemId: string) {
}
function navigateToItem(item: any) {
if (item.item_type === 'route') router.push('/schedules')
if (item.item_type === 'route') router.push({ path: '/schedules', query: { routeId: item.item_id } })
else if (item.item_type === 'taxi') router.push('/taxi')
else if (item.item_type === 'business') router.push('/business/' + item.item_id)
else if (item.item_type === 'coupon') router.push('/coupons')
else if (item.item_type === 'stop') router.push({ path: '/map', query: { stopId: item.item_id } })
}
const visibleRoutes = computed(() =>
@ -51,11 +54,15 @@ const visibleBusinesses = computed(() =>
const visibleCoupons = computed(() =>
(selectedFilter.value === 'all' || selectedFilter.value === 'coupons') ? favoritesStore.coupons : []
)
const visibleStops = computed(() =>
(selectedFilter.value === 'all' || selectedFilter.value === 'stops') ? favoritesStore.stops : []
)
const totalFavorites = computed(() => favoritesStore.favorites.length)
const hasVisibleItems = computed(() =>
visibleRoutes.value.length + visibleTaxis.value.length +
visibleBusinesses.value.length + visibleCoupons.value.length > 0
visibleBusinesses.value.length + visibleCoupons.value.length +
visibleStops.value.length > 0
)
</script>
@ -206,20 +213,22 @@ const hasVisibleItems = computed(() =>
<section v-if="visibleCoupons.length > 0" class="fav-section">
<div class="section-label">
<span class="material-icons">confirmation_number</span>
<span>Eventos</span>
<span>Ofertas y Viajes</span>
</div>
<div class="card-list">
<div
v-for="item in visibleCoupons"
:key="item.id"
class="card card--row"
@click="navigateToItem(item)"
>
<div class="card-thumb card-thumb--event">
<span class="material-icons">local_activity</span>
<img v-if="item.item_image" :src="getImageUrl(item.item_image)" class="thumb-img" />
<span v-else class="material-icons">local_activity</span>
</div>
<div class="card-info">
<p class="card-name">{{ item.item_name }}</p>
<span class="badge-avail">Disponible</span>
<span class="badge-avail">Cupón</span>
</div>
<button class="heart-btn heart-btn--active" @click.stop="removeFavorite($event, item.item_type, item.item_id)" title="Quitar de favoritos">
<span class="material-icons">favorite</span>
@ -228,6 +237,33 @@ const hasVisibleItems = computed(() =>
</div>
</section>
<!-- PARADAS -->
<section v-if="visibleStops.length > 0" class="fav-section">
<div class="section-label">
<span class="material-icons">location_on</span>
<span>Paradas</span>
</div>
<div class="card-list">
<div
v-for="item in visibleStops"
:key="item.id"
class="card card--row"
@click="navigateToItem(item)"
>
<div class="card-thumb card-thumb--blue">
<span class="material-icons">location_on</span>
</div>
<div class="card-info">
<p class="card-name">{{ item.item_name }}</p>
<span class="badge-avail">Favorito</span>
</div>
<button class="heart-btn heart-btn--active" @click.stop="removeFavorite($event, item.item_type, item.item_id)">
<span class="material-icons">favorite</span>
</button>
</div>
</div>
</section>
</div>
</template>
</div>

View File

@ -12,6 +12,7 @@ import { telemetryService } from "@/services/telemetryService";
import { analyticsService } from "@/services/analyticsService";
import BusStopInfoModal from "@/components/BusStopInfoModal.vue";
import FavoriteButton from "@/components/FavoriteButton.vue";
import type { BusStop } from '@/types'
const router = useRouter();
@ -231,6 +232,19 @@ onMounted(async () => {
}
}
// Handle stopId if present
const queryStopId = router.currentRoute.value.query.stopId as string;
if (queryStopId) {
await busStopStore.loadBusStops();
const foundStop = busStopStore.busStops.find(s => s.id === queryStopId);
if (foundStop) {
selectedBusStop.value = foundStop;
showBusStopModal.value = true;
setCenter(foundStop.latitude, foundStop.longitude);
setZoom(17);
}
}
// Wait for Google Maps to load
if (isLoaded.value) {
await initializeMap();
@ -1141,6 +1155,14 @@ function clearNavigation() {
<span v-if="currentPromo.discount_percentage" class="sheet-discount">
-{{ currentPromo.discount_percentage }}%
</span>
<div class="sheet-fav-pos" @click.stop>
<FavoriteButton
item-type="coupon"
:item-id="currentPromo.id"
:item-name="currentPromo.title"
:item-image="currentPromo.image_url || undefined"
/>
</div>
</div>
<!-- Info -->
@ -1192,6 +1214,14 @@ function clearNavigation() {
<div class="promo-header-modal">
<img :src="getImageUrl(selectedPromo.image_url)" class="promo-img-modal" />
<div class="promo-badge-modal">PROMO</div>
<div class="promo-modal-fav">
<FavoriteButton
item-type="coupon"
:item-id="selectedPromo.id"
:item-name="selectedPromo.title"
:item-image="selectedPromo.image_url || undefined"
/>
</div>
</div>
<div class="promo-body-modal">
<h2 class="promo-title-modal">{{ selectedPromo.title }}</h2>
@ -2155,4 +2185,17 @@ function clearNavigation() {
.nav-destination { color: #e8eaed; }
.nav-btn-close { background: #3c4043; color: #bdc1c6; }
}
.sheet-fav-pos {
position: absolute;
top: 6px;
right: 6px;
z-index: 10;
}
.promo-modal-fav {
position: absolute;
top: 15px;
left: 15px;
z-index: 10;
}
</style>

View File

@ -237,8 +237,14 @@ const getStatusClass = (status: string) => {
</p>
</div>
</div>
<div class="text-right">
<div class="text-right flex flex-col items-end gap-2">
<p class="font-black text-xl text-primary">{{ taxi.shift }}</p>
<FavoriteButton
item-type="taxi"
:item-id="taxi.id"
:item-name="taxi.owner_name"
:item-image="taxi.image_url || undefined"
/>
</div>
</div>
<div class="flex items-center justify-between">

View File

@ -308,6 +308,14 @@ function getShiftLabel(shift: string) {
<span class="amount">{{ shuttle.price_per_person }}</span>
<span class="price-pill-label">/p</span>
</div>
<div class="shuttle-fav-wrap" @click.stop>
<FavoriteButton
item-type="route"
:item-id="shuttle.id"
:item-name="shuttle.route_name"
:item-image="shuttle.image_url || undefined"
/>
</div>
</div>
<div class="shuttle-route-compact" v-if="shuttle.origin && shuttle.destination">