perf: optimization phases 3-5

This commit is contained in:
2026-02-26 12:50:12 -05:00
parent 7b3141e5e9
commit 2dd3384882
6 changed files with 41 additions and 4 deletions

View File

@ -7,6 +7,16 @@ const config: CapacitorConfig = {
server: {
androidScheme: 'http',
cleartext: true
},
plugins: {
SplashScreen: {
launchShowDuration: 2000,
launchAutoHide: true,
backgroundColor: "#101820",
androidSplashResourceName: "splash",
androidScaleType: "CENTER_CROP",
showSpinner: false,
}
}
};

View File

@ -9,9 +9,13 @@ export const useBusStopStore = defineStore('busStop', () => {
const busStops = ref<BusStop[]>([])
const isLoading = ref(false)
const error = ref<string | null>(null)
const lastFetched = ref<number>(0)
async function loadBusStops(force = false) {
if (!force && busStops.value.length > 0) {
const CACHE_TIME = 1000 * 60 * 30; // 30 minutos
const now = Date.now();
if (!force && busStops.value.length > 0 && (now - lastFetched.value < CACHE_TIME)) {
return
}
@ -19,6 +23,7 @@ export const useBusStopStore = defineStore('busStop', () => {
error.value = null
try {
busStops.value = await busStopsService.getAllBusStops()
lastFetched.value = now;
} catch (e) {
error.value = e instanceof Error ? e.message : 'Failed to load bus stops'
console.error('Error loading bus stops:', e)

View File

@ -12,11 +12,16 @@ export const useRouteStore = defineStore('route', () => {
const isLoadingRoutes = ref(false)
const isLoadingStops = ref(false)
const error = ref<string | null>(null)
const lastFetched = ref<number>(0) // ⚡ CACHÉ ESTÁTICO
const hasSelectedRoute = computed(() => selectedRouteId.value !== null && selectedRouteName.value !== null)
async function loadRoutes(filters?: { originCity?: string, destinationCity?: string }, force = false) {
if (!force && !filters && allRoutes.value.length > 0) {
const CACHE_TIME = 1000 * 60 * 15; // 15 minutos
const now = Date.now();
// Si no forzamos, no hay filtros raros, ya tenemos rutas y aún no expira el caché, omitir llamada
if (!force && !filters && allRoutes.value.length > 0 && (now - lastFetched.value < CACHE_TIME)) {
return
}
@ -24,6 +29,7 @@ export const useRouteStore = defineStore('route', () => {
error.value = null
try {
allRoutes.value = await routesService.getAllRoutes(filters)
if (!filters) lastFetched.value = now; // Solo actualizar timer si es un request general limio
} catch (e) {
error.value = e instanceof Error ? e.message : 'Failed to load routes'
console.error('Error loading routes:', e)

View File

@ -200,6 +200,7 @@ function resetFilters() {
<div
v-for="biz in filteredBusinesses"
:key="biz.id"
v-memo="[biz.id]"
class="biz-card"
@click="handleExplore(biz)"
>
@ -207,6 +208,8 @@ function resetFilters() {
<img
:src="getImageUrl(biz.image_url, 'business')"
:alt="biz.name"
loading="lazy"
decoding="async"
class="biz-img"
@error="(e) => (e.target as HTMLImageElement).src = getImageUrl(null, 'business')"
/>
@ -271,12 +274,15 @@ function resetFilters() {
<div
v-for="biz in featuredBusinesses"
:key="biz.id"
v-memo="[biz.id]"
class="featured-card"
@click="handleExplore(biz)"
>
<img
:src="getImageUrl(biz.image_url, 'business')"
:alt="biz.name"
loading="lazy"
decoding="async"
class="featured-img"
@error="(e) => (e.target as HTMLImageElement).src = getImageUrl(null, 'business')"
/>
@ -306,6 +312,7 @@ function resetFilters() {
<div
v-for="biz in gridBusinesses"
:key="biz.id"
v-memo="[biz.id]"
class="biz-card"
@click="handleExplore(biz)"
>
@ -313,6 +320,8 @@ function resetFilters() {
<img
:src="getImageUrl(biz.image_url, 'business')"
:alt="biz.name"
loading="lazy"
decoding="async"
class="biz-img"
@error="(e) => (e.target as HTMLImageElement).src = getImageUrl(null, 'business')"
/>

View File

@ -174,6 +174,7 @@ const getStatusClass = (status: string) => {
<div
v-for="route in routeStore.allRoutes"
:key="route.id"
v-memo="[route.id]"
class="bg-slate-50 dark:bg-card-dark p-5 rounded-[2rem] shadow-sm border border-slate-200 dark:border-white/5 flex flex-col gap-4 active:scale-[0.98] transition-all cursor-pointer"
@click="goToSchedules(route)"
>
@ -219,12 +220,13 @@ const getStatusClass = (status: string) => {
<div
v-for="taxi in taxiStore.taxis"
:key="taxi.id"
v-memo="[taxi.id]"
class="bg-slate-50 dark:bg-card-dark p-5 rounded-[2rem] shadow-sm border border-slate-200 dark:border-white/5 flex flex-col gap-4 active:scale-[0.98] transition-all"
>
<div class="flex justify-between items-center">
<div class="flex items-center gap-4">
<div class="size-14 rounded-2xl bg-primary/10 flex items-center justify-center text-primary overflow-hidden">
<img v-if="taxi.image_url" :src="taxi.image_url" class="w-full h-full object-cover">
<img v-if="taxi.image_url" :src="taxi.image_url" loading="lazy" decoding="async" class="w-full h-full object-cover">
<span v-else class="material-icons text-[32px]">local_taxi</span>
</div>
<div>

View File

@ -187,11 +187,13 @@ function getShiftLabel(shift: string) {
</div>
<div v-else class="taxis-grid">
<div v-for="taxi in filteredTaxis" :key="taxi.id" class="taxi-card-new">
<div v-for="taxi in filteredTaxis" :key="taxi.id" v-memo="[taxi.id]" class="taxi-card-new">
<div class="card-top">
<div class="driver-avatar">
<img
:src="getImageUrl(taxi.image_url, 'taxi')"
loading="lazy"
decoding="async"
alt="Driver"
@error="(e) => (e.target as HTMLImageElement).src = getImageUrl(null, 'taxi')"
>
@ -284,6 +286,7 @@ function getShiftLabel(shift: string) {
<div
v-for="shuttle in filteredShuttles"
:key="shuttle.id"
v-memo="[shuttle.id]"
:ref="el => setShuttleRef(el, shuttle.id)"
class="shuttle-card"
:class="{ expanded: expandedShuttleId === shuttle.id }"
@ -296,6 +299,8 @@ function getShiftLabel(shift: string) {
>
<img
:src="getImageUrl(shuttle.image_url, 'shuttle')"
loading="lazy"
decoding="async"
class="shuttle-card-bg"
@error="(e) => (e.target as HTMLImageElement).src = getImageUrl(null, 'shuttle')"
/>