chore: migrate AdminShuttles and old API endpoints from Axios/Render to Supabase client, remove Axios

This commit is contained in:
2026-02-26 14:51:03 -05:00
parent 30c3f092d8
commit 35a29fbb0f
9 changed files with 69 additions and 175 deletions

View File

@ -1,2 +1,2 @@
VITE_API_URL=http://127.0.0.1:8000
VITE_GOOGLE_MAPS_API_KEY=AIzaSyBKSSmUXBxLbKBqhAtVJ2CljDfkJcWIGzg

View File

@ -1,2 +1,2 @@
VITE_GOOGLE_MAPS_API_KEY=AIzaSyDrKzxJ-9A48cWFRffpOnEdmRR1Ijjj--Y
VITE_API_URL=https://sibu-backend.onrender.com

View File

@ -15,7 +15,6 @@
"@googlemaps/js-api-loader": "^2.0.2",
"@supabase/supabase-js": "^2.97.0",
"@tailwindcss/vite": "^4.2.0",
"axios": "^1.13.2",
"chart.js": "^4.5.1",
"html2canvas": "^1.4.1",
"jspdf": "^4.1.0",
@ -3325,7 +3324,6 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.13.tgz",
"integrity": "sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg==",
"license": "MIT",
"peer": true,
"dependencies": {
"undici-types": "~7.16.0"
}
@ -3865,12 +3863,6 @@
"node": ">= 0.4"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
},
"node_modules/at-least-node": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
@ -3933,17 +3925,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/axios": {
"version": "1.13.5",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz",
"integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.11",
"form-data": "^4.0.5",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/babel-plugin-polyfill-corejs2": {
"version": "0.4.15",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.15.tgz",
@ -4149,6 +4130,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@ -4256,18 +4238,6 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT"
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/commander": {
"version": "12.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
@ -4530,15 +4500,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/detect-libc": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
@ -4562,6 +4523,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
@ -4730,6 +4692,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@ -4739,6 +4702,7 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@ -4748,6 +4712,7 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
@ -4760,6 +4725,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@ -4965,26 +4931,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/follow-redirects": {
"version": "1.15.11",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/for-each": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
@ -5031,22 +4977,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/form-data": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fraction.js": {
"version": "5.3.4",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz",
@ -5093,6 +5023,7 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@ -5153,6 +5084,7 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
@ -5184,6 +5116,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"dev": true,
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
@ -5232,6 +5165,7 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@ -5292,6 +5226,7 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@ -5304,6 +5239,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
@ -5319,6 +5255,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
@ -6305,32 +6242,12 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/minipass": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
@ -6736,12 +6653,6 @@
"node": ">=6"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT"
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",

View File

@ -16,7 +16,6 @@
"@googlemaps/js-api-loader": "^2.0.2",
"@supabase/supabase-js": "^2.97.0",
"@tailwindcss/vite": "^4.2.0",
"axios": "^1.13.2",
"chart.js": "^4.5.1",
"html2canvas": "^1.4.1",
"jspdf": "^4.1.0",

View File

@ -1,10 +1,7 @@
<script setup lang="ts">
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import { SUPABASE_URL } from '@/supabase';
import axios from 'axios';
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000';
import { supabase } from '@/supabase';
const router = useRouter();
const isLoading = ref(false);
@ -53,33 +50,39 @@ async function saveShuttle() {
showMessage.value = { text: '', type: '' };
try {
const token = localStorage.getItem('auth_token');
const formData = new FormData();
// Añadimos campos obligatorios para el backend
formData.append('route_name', `${shuttleForm.value.origin} - ${shuttleForm.value.destination}`);
formData.append('origin', shuttleForm.value.origin);
formData.append('destination', shuttleForm.value.destination);
formData.append('vehicle_type', shuttleForm.value.vehicle_type);
formData.append('company_name', shuttleForm.value.company_name);
formData.append('price_per_person', String(shuttleForm.value.price_per_person));
formData.append('price_private_trip', String(shuttleForm.value.price_private_trip));
formData.append('estimated_duration', shuttleForm.value.estimated_duration);
formData.append('departure_times', shuttleForm.value.departure_times);
formData.append('contact_whatsapp', shuttleForm.value.contact_whatsapp);
formData.append('phone_number', shuttleForm.value.phone_number);
formData.append('english_speaking', String(shuttleForm.value.english_speaking));
let image_url = '';
if (selectedFile.value) {
formData.append('image', selectedFile.value);
const ext = selectedFile.value.name.split('.').pop();
const filename = `shuttles/${Date.now()}.${ext}`;
const { error: upErr } = await supabase.storage.from('uploads').upload(filename, selectedFile.value);
if (upErr) throw upErr;
const { data: urlData } = supabase.storage.from('uploads').getPublicUrl(filename);
image_url = urlData.publicUrl;
}
await axios.post(`${API_URL}/api/shuttles`, formData, {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'multipart/form-data'
}
});
const payload = {
route_name: `${shuttleForm.value.origin} - ${shuttleForm.value.destination}`,
origin: shuttleForm.value.origin,
destination: shuttleForm.value.destination,
vehicle_type: shuttleForm.value.vehicle_type,
company_name: shuttleForm.value.company_name,
price_per_person: shuttleForm.value.price_per_person,
price_private_trip: shuttleForm.value.price_private_trip,
estimated_duration: shuttleForm.value.estimated_duration,
departure_times: shuttleForm.value.departure_times,
contact_whatsapp: shuttleForm.value.contact_whatsapp,
phone_number: shuttleForm.value.phone_number,
english_speaking: shuttleForm.value.english_speaking,
is_active: shuttleForm.value.is_active,
image_url: image_url || shuttleForm.value.image_url
};
const { error: insertError } = await supabase.from('shuttles').insert([payload]);
if (insertError) {
throw insertError;
}
showMessage.value = { text: '¡Viaje Turístico Desplegado!', type: 'success' };
setTimeout(() => router.push('/admin'), 2000);

View File

@ -3,11 +3,9 @@ import { ref, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { businessService } from '@/services/businessService'
import { couponsService } from '@/services/couponsService'
import { SUPABASE_URL } from '@/supabase'
import type { Business, Coupon } from '@/types'
import FavoriteButton from '@/components/FavoriteButton.vue'
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000';
import { getImageUrl as utilGetImageUrl } from '@/utils/imageUrl'
const route = useRoute()
const router = useRouter()
@ -42,9 +40,7 @@ onMounted(async () => {
})
function getImageUrl(path: string | null | undefined) {
if (!path) return '/default-business.jpg'
if (path.startsWith('http')) return path
return `${API_URL}${path.startsWith('/') ? '' : '/'}${path}`
return utilGetImageUrl(path, 'business')
}
const goBack = () => router.back()

View File

@ -2,11 +2,9 @@
import { onMounted, ref, computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useCouponStore } from '@/stores/coupon'
import { SUPABASE_URL } from '@/supabase'
import type { Coupon } from '@/types'
import FavoriteButton from '@/components/FavoriteButton.vue'
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000';
import { getImageUrl as utilGetImageUrl } from '@/utils/imageUrl'
const { t } = useI18n()
const couponStore = useCouponStore()
@ -33,9 +31,7 @@ const filteredCoupons = computed(() => {
})
function getImageUrl(path: string | null | undefined) {
if (!path) return '/default-coupon.png'
if (path.startsWith('http')) return path
return `${API_URL}${path.startsWith('/') ? '' : '/'}${path}`
return utilGetImageUrl(path, 'coupon')
}

View File

@ -3,9 +3,7 @@ import { ref, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { useFavoritesStore } from '@/stores/favorites'
import { SUPABASE_URL } from '@/supabase'
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000';
import { getImageUrl as utilGetImageUrl } from '@/utils/imageUrl'
const { t } = useI18n()
const router = useRouter()
@ -26,9 +24,7 @@ onMounted(async () => {
})
function getImageUrl(path?: string) {
if (!path) return `https://ui-avatars.com/api/?name=Favorito&background=fee715&color=101820&bold=true`
if (path.startsWith('http')) return path
return `${API_URL}${path.startsWith('/') ? '' : '/'}${path}`
return utilGetImageUrl(path, 'business')
}
async function removeFavorite(event: Event, itemType: string, itemId: string) {

View File

@ -5,11 +5,9 @@ import { businessService } from '@/services/businessService'
import { couponsService } from '@/services/couponsService'
import { shuttlesService } from '@/services/shuttlesService'
import { useAuthStore } from '@/stores/auth'
import { SUPABASE_URL } from '@/supabase'
import { SUPABASE_URL, supabase } from '@/supabase'
import type { Coupon, Business, Shuttle } from '@/types'
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000';
const route = useRoute()
const authStore = useAuthStore()
@ -142,14 +140,13 @@ async function loadShuttles() {
// Shuttle Methods
async function toggleShuttleStatus(shuttle: Shuttle) {
try {
const token = localStorage.getItem('auth_token')
const response = await fetch(`${API_URL}/api/shuttles/${shuttle.id}/status?is_active=${!shuttle.is_active}`, {
method: 'PATCH',
headers: { 'Authorization': `Bearer ${token}` }
})
if (response.ok) {
await loadShuttles()
}
const { error } = await supabase
.from('shuttles')
.update({ is_active: !shuttle.is_active })
.eq('id', shuttle.id);
if (error) throw error;
await loadShuttles();
} catch (e) {
alert('Error al actualizar estado del shuttle')
}
@ -158,16 +155,13 @@ async function toggleShuttleStatus(shuttle: Shuttle) {
async function deleteShuttle(id: string) {
if (confirm('¿Estás seguro de eliminar este transporte turístico?')) {
try {
const token = localStorage.getItem('auth_token')
const response = await fetch(`${API_URL}/api/shuttles/${id}`, {
method: 'DELETE',
headers: { 'Authorization': `Bearer ${token}` }
})
if (response.ok) {
await loadShuttles()
} else {
alert('No se pudo eliminar el shuttle')
}
const { error } = await supabase
.from('shuttles')
.delete()
.eq('id', id);
if (error) throw error;
await loadShuttles();
} catch (e) {
alert('Error al eliminar shuttle')
}
@ -289,8 +283,7 @@ function openEditModal(coupon: Coupon) {
function getImageUrl(path: string | null | undefined) {
if (!path) return '/default-coupon.png'
if (path.startsWith('http')) return path
return `${API_URL}${path.startsWith('/') ? '' : '/'}${path}`
return path
}
async function saveCoupon() {