avance editar paraderos desde mapa

master/frontend-google-map
Francisco Sandoval 2023-08-07 20:30:52 -04:00
parent 169c0766de
commit d440df819f
4 changed files with 184 additions and 12 deletions

View File

@ -1,14 +1,16 @@
<script> <script>
import { onMount } from 'svelte' import { onMount, createEventDispatcher } from 'svelte'
const dispatch = createEventDispatcher();
export let google_api_key = null; export let google_api_key = null;
export let center = null; export let center = null;
export let zoom = 4; export let zoom = 4;
export let marks = []; export let marks = [];
let mapEl = null; let mapEl = null;
let infoWindow;
onMount(() => { onMount(() => {
console.log('onMount')
if (!globalThis.google) { if (!globalThis.google) {
const el = document.createElement('script') const el = document.createElement('script')
el.src = "https://maps.googleapis.com/maps/api/js?key=" + google_api_key + "&callback=initMap&v=weekly" el.src = "https://maps.googleapis.com/maps/api/js?key=" + google_api_key + "&callback=initMap&v=weekly"
@ -25,21 +27,21 @@
if (!google || !mapEl) return; if (!google || !mapEl) return;
const map = new google.maps.Map(mapEl, { zoom, center }); const map = new google.maps.Map(mapEl, { zoom, center });
const infoWindow = new google.maps.InfoWindow(); infoWindow = new google.maps.InfoWindow();
for (const mark of marks) { for (const mark of marks) {
const { position, title, location } = mark; const { position, title, location, url_image, id_paradero } = mark;
const marker = new google.maps.Marker({ const marker = new google.maps.Marker({ position, map, title });
position,
map,
title,
});
marker.addListener("click", () => { marker.addListener("click", () => {
infoWindow.close(); infoWindow.close();
const imagen = url_image ? `<img alt="Imagen" src="${url_image}" width="200">` : ''
const html = ` const html = `
<h1>${title}</h1> <h1>${title}</h1>
<p>${location}</p> <p>${location}</p>
<button class="btn btn-primary" onclick="onEdita(${id_paradero})">Editar</button>
<hr>
${imagen}
` `
infoWindow.setContent(html); infoWindow.setContent(html);
infoWindow.open(marker.getMap(), marker); infoWindow.open(marker.getMap(), marker);
@ -49,6 +51,11 @@
console.log({ zoom: map.zoom }); console.log({ zoom: map.zoom });
}); });
}; };
globalThis.onEdita = function(id_paradero) {
infoWindow.close();
dispatch('edita', id_paradero)
}
</script> </script>
<div bind:this={mapEl} style="height: 800px; max-height: 90vh;">Cargando...</div> <div bind:this={mapEl} style="height: 800px; max-height: 90vh;">Cargando...</div>

View File

@ -0,0 +1,92 @@
<script>
import Modal from "$/components/Modal.svelte";
import { getParadero, getUrlImagen, createParadero, updateParadero, deleteParadero, saveImageParadero } from "$/services/paraderos";
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
export let paradero = { id_paradero: null };
let form = {};
let inputfile = null;
let imagenEl = null;
$: infoParadero(paradero)
async function infoParadero({ id_paradero }) {
try {
if (!id_paradero) return;
form = await getParadero(id_paradero)
} catch (error) {
alert(error)
}
}
async function onSaveParadero() {
try {
form = form.id_paradero ? await updateParadero(form) : await createParadero(form)
alert('Información guardada')
} catch (error) {
alert(error)
}
}
async function onDeleteParadero() {
try {
await deleteParadero(form.id_paradero)
alert('Paradero eliminado')
dispatch('delete', form)
dispatch('close')
} catch (error) {
alert(error)
}
}
async function onChangeImage() {
try {
const { url_image } = await saveImageParadero(paradero.id_paradero, inputfile.files[0])
imagenEl.src = url_image + '?nocache=' + (new Date()).valueOf()
alert('Imagen cambiada')
} catch (error) {
alert(error)
}
}
</script>
<form on:submit|preventDefault={onSaveParadero}>
<Modal size="lg"
title={'Paradero #' + paradero.id_paradero}
on:close={() => dispatch('close')}>
<div class="input-group mb-3">
<div class="input-group-text">Dirección</div>
<input type="text" bind:value={form.stop_name} class="form-control">
</div>
<div class="input-group mb-3">
<div class="input-group-text">Latitud</div>
<input type="number" step="any" bind:value={form.stop_lat} class="form-control">
</div>
<div class="input-group mb-3">
<div class="input-group-text">Longitud</div>
<input type="number" step="any" bind:value={form.stop_lon} class="form-control">
</div>
{#if form.id_paradero}
<div class="input-group mb-3">
<div class="input-group-text"><i class="bi bi-image"></i></div>
<div class="form-control"><input type="file" bind:this={inputfile}></div>
<button class="btn btn-primary" on:click|preventDefault={onChangeImage}>Cambiar Imagen</button>
</div>
<img alt="Imagen Paradero" class="img-fluid" bind:this={imagenEl} src={getUrlImagen(form.id_paradero)}>
{/if}
<svelte:fragment slot="buttons">
<button type="submit" class="btn btn-primary me-2">
<i class="bi bi-save"></i> Guardar
</button>
<button class="btn btn-danger me-2" on:click|preventDefault={onDeleteParadero}>
<i class="bi bi-trash"></i> Eliminar
</button>
</svelte:fragment>
</Modal>
</form>

View File

@ -4,12 +4,12 @@
import { storeParaderos } from "$/stores/global"; import { storeParaderos } from "$/stores/global";
import GoogleMap from '$/components/GoogleMap.svelte' import GoogleMap from '$/components/GoogleMap.svelte'
import IconLoading from "$/components/IconLoading.svelte"; import IconLoading from "$/components/IconLoading.svelte";
import ModalParadero from "./ModalParadero.svelte";
let my_map = null;
let data_map = null let data_map = null
let paradero = null
$: init_google_map($storeParaderos) $: init_google_map($storeParaderos)
$: console.log({ data_map })
async function init_google_map(data_inicial) { async function init_google_map(data_inicial) {
const paraderos = data_inicial || await getMarcasParaderos() const paraderos = data_inicial || await getMarcasParaderos()
@ -17,7 +17,9 @@
data_map = paraderos; data_map = paraderos;
} }
function onEdita(id_paradero) {
paradero = { id_paradero }
}
</script> </script>
<PageTitle>Paraderos</PageTitle> <PageTitle>Paraderos</PageTitle>
@ -33,9 +35,15 @@
center={data_map.center} center={data_map.center}
zoom={data_map.zoom} zoom={data_map.zoom}
marks={data_map.marks} marks={data_map.marks}
on:edita={ev => onEdita(ev.detail)}
/> />
{:else} {:else}
<IconLoading /> <IconLoading />
{/if} {/if}
</div> </div>
</div> </div>
{#if paradero}
<ModalParadero {paradero} on:close={() => paradero = null} />
{/if}

View File

@ -0,0 +1,65 @@
import { base, getToken } from './_config'
export function getUrlImagen(id_paradero) {
return `${base}/paraderos/image/${id_paradero}`
}
export async function getParaderos(params) {
const query = !params ? '' : '?' + (new URLSearchParams(params).toString());
const res = await fetch(`${base}/paraderos/${query}`, {
headers: { "Authorization": `Bearer ${getToken()}`, "Content-Type": "application/json" }
})
if (!res.ok) throw await res.text()
return res.json()
}
export async function getParadero(rut) {
const res = await fetch(`${base}/paraderos/${rut}/`, {
headers: { "Authorization": `Bearer ${getToken()}`, "Content-Type": "application/json" }
})
if (!res.ok) throw await res.text()
return res.json()
}
export async function createParadero(data) {
const res = await fetch(`${base}/paraderos/`, {
method: 'POST',
body: JSON.stringify(data),
headers: { "Authorization": `Bearer ${getToken()}`, "Content-Type": "application/json" }
})
if (!res.ok) throw await res.text()
return res.json()
}
export async function updateParadero({ id_paradero: id = null, ...data }) {
const res = await fetch(`${base}/paraderos/${id}/`, {
method: 'PATCH',
body: JSON.stringify(data),
headers: { "Authorization": `Bearer ${getToken()}`, "Content-Type": "application/json" }
})
if (!res.ok) throw await res.text()
return res.json()
}
export async function deleteParadero(id) {
const res = await fetch(`${base}/paraderos/${id}/`, {
method: 'DELETE',
headers: { "Authorization": `Bearer ${getToken()}`, "Content-Type": "application/json" }
})
if (!res.ok) throw await res.text()
return res.json()
}
export async function saveImageParadero(id = null, file) {
const form = new FormData()
form.append('imagen', file)
const res = await fetch(`${base}/paraderos/image/${id}/`, {
method: 'POST',
body: form,
headers: { "Authorization": `Bearer ${getToken()}` }
})
if (!res.ok) throw await res.text()
return res.json()
}