Añádir y Editar completos

This commit is contained in:
Felipe Contreras 2022-11-22 21:26:27 -03:00
parent fe63377c26
commit cff0585bd4
6 changed files with 146 additions and 21 deletions

5
build.rs Normal file
View file

@ -0,0 +1,5 @@
// generated by `sqlx migrate build-script`
fn main() {
// trigger recompilation when a new migration is added
println!("cargo:rerun-if-changed=migrations");
}

View file

@ -0,0 +1 @@
UPDATE places SET longitude=latitude, latitude=longitude;

View file

@ -43,7 +43,7 @@ enum UpsertResponse {
NotFound(NotFound<Json<Place>>), NotFound(NotFound<Json<Place>>),
} }
#[post("/places", format = "json", data = "<place>")] #[put("/places", format = "json", data = "<place>")]
async fn upsert_place(db: Connection<Db>, place: Json<Place>) -> Result<UpsertResponse> { async fn upsert_place(db: Connection<Db>, place: Json<Place>) -> Result<UpsertResponse> {
if place.id.is_some() { if place.id.is_some() {
update_place(db, place).await update_place(db, place).await
@ -79,14 +79,15 @@ async fn insert_place(mut db: Connection<Db>, mut place: Json<Place>) -> Result<
async fn update_place(mut db: Connection<Db>, place: Json<Place>) -> Result<UpsertResponse> { async fn update_place(mut db: Connection<Db>, place: Json<Place>) -> Result<UpsertResponse> {
let result = ::sqlx::query!( let result = ::sqlx::query!(
"UPDATE places SET (name, address, open_hours, icon, description, longitude, latitude) = (?, ?, ?, ?, ?, ?, ?)", "UPDATE places SET (name, address, open_hours, icon, description, longitude, latitude) = (?, ?, ?, ?, ?, ?, ?) WHERE id = ?",
place.name, place.name,
place.address, place.address,
place.open_hours, place.open_hours,
place.icon, place.icon,
place.description, place.description,
place.longitude, place.longitude,
place.latitude place.latitude,
place.id,
) )
.execute(&mut *db) .execute(&mut *db)
.await?; .await?;

View file

@ -52,13 +52,15 @@
} }
#modal-form { #modal-form {
margin: 15vh auto; margin: 15vh auto;
background-color: rgb(245, 245, 245); color: #333;
background-color: white;
padding: 2em; padding: 2em;
border: 1px solid rgb(25, 25, 25); border: 1px solid rgb(25, 25, 25);
width: 80vw; width: 80vw;
border-radius: 12px;
} }
#close { #close {
color: rgb(80, 80, 80); color: #333;
float: right; float: right;
font-size: 28px; font-size: 28px;
font-weight: bold; font-weight: bold;
@ -76,6 +78,7 @@
display: table-row; display: table-row;
} }
label { label {
font-weight: bold;
display: table-cell; display: table-cell;
vertical-align: top; vertical-align: top;
padding-right: 2em; padding-right: 2em;
@ -137,6 +140,9 @@
<textarea id="description" name="description" <textarea id="description" name="description"
cols="30" rows="5"></textarea> cols="30" rows="5"></textarea>
</p> </p>
<p>
<button type="button" id="button">Enviar </button>
</p>
</form> </form>
</div> </div>
</div> </div>

3
ts-client/Makefile Normal file
View file

@ -0,0 +1,3 @@
all: client.ts
tsc
sed -i '1d' build/client.js

View file

@ -1,5 +1,5 @@
import * as L from 'leaflet-contextmenu'; import * as L from 'leaflet-contextmenu';
import { Feature, FeatureCollection, GeoJSON } from 'geojson'; import { Feature, FeatureCollection } from 'geojson';
interface PlaceModel { interface PlaceModel {
id: number | null; id: number | null;
@ -28,12 +28,12 @@ function toFeature(place: PlaceModel): Feature {
}, },
"geometry": { "geometry": {
"type": "Point", "type": "Point",
"coordinates": [place.latitude, place.longitude] "coordinates": [place.longitude, place.latitude]
} }
} }
} }
function toLeafletPlaces(backendPlaces: Array<PlaceModel>): GeoJSON { function toLeafletPlaces(backendPlaces: Array<PlaceModel>): L.GeoJSON {
let result: FeatureCollection = { let result: FeatureCollection = {
type: "FeatureCollection", type: "FeatureCollection",
features: new Array<Feature>(), features: new Array<Feature>(),
@ -45,9 +45,15 @@ function toLeafletPlaces(backendPlaces: Array<PlaceModel>): GeoJSON {
} }
let placesLayer: L.GeoJSON; let placesLayer: L.GeoJSON;
let places = new Map<L.LatLngLiteral, PlaceModel>(); let places = new Map<string, PlaceModel>();
async function createPlace(): Promise<void> { function toStr(latlng: L.LatLngLiteral) {
return latlng.lng + "|" + latlng.lat;
}
function getPlaceFromForm(): PlaceModel {
const idStr = (document.getElementById("id") as HTMLInputElement).value;
const id = idStr == "" ? null : parseInt(idStr);
const name = const name =
(document.getElementById("name") as HTMLInputElement).value; (document.getElementById("name") as HTMLInputElement).value;
const address = const address =
@ -63,8 +69,8 @@ async function createPlace(): Promise<void> {
const longitude = parseFloat( const longitude = parseFloat(
(document.getElementById("long") as HTMLSelectElement).value); (document.getElementById("long") as HTMLSelectElement).value);
const newPlace: PlaceModel = { return {
id: null, id: id,
name: name, name: name,
address: address, address: address,
open_hours: open_hours, open_hours: open_hours,
@ -73,6 +79,37 @@ async function createPlace(): Promise<void> {
latitude: latitude, latitude: latitude,
longitude: longitude, longitude: longitude,
}; };
}
function clearForm(): void {
/* Get the form elements*/
const idInput = (document.getElementById("id") as HTMLInputElement);
const latInput = (document.getElementById("lat") as HTMLInputElement);
const longInput = (document.getElementById("long") as HTMLInputElement);
const nameInput = (document.getElementById("name") as HTMLInputElement);
const addressInput = (document.getElementById("address") as HTMLInputElement);
const openHoursArea = (document.getElementById("open_hours") as HTMLTextAreaElement);
const descriptionArea = (document.getElementById("description") as HTMLTextAreaElement);
/* Clear them */
idInput.value = "";
latInput.value = "";
longInput.value = "";
nameInput.value = "";
addressInput.value = "";
openHoursArea.value = "";
descriptionArea.value = "";
/* Clear the callback */
document.getElementById("button").onclick = null;
/* Now you see it, now you don't*/
document.getElementById("modal").style.display = "none";
}
async function createPlace(): Promise<void> {
const newPlace = getPlaceFromForm();
await fetch('places', { await fetch('places', {
method: 'PUT', method: 'PUT',
@ -84,16 +121,46 @@ async function createPlace(): Promise<void> {
.then((response) => response.json()) .then((response) => response.json())
.then((place: PlaceModel) => { .then((place: PlaceModel) => {
places.set( places.set(
{ lat: place.latitude, lng: place.longitude }, toStr({ lat: place.latitude, lng: place.longitude }),
place place
); );
placesLayer.addData(toFeature(place)); placesLayer.addData(toFeature(place));
clearForm();
alert("Lugar añadido exitosamente");
}) })
.catch((error) => alert(error)); .catch((error) => alert(error));
} }
async function editPlace(): Promise<void> {
const newPlace = getPlaceFromForm();
await fetch('places', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(newPlace),
})
.then((response) => response.json())
.then((place: PlaceModel) => {
places.set(
toStr({ lat: place.latitude, lng: place.longitude }),
place
);
clearForm();
alert("Lugar guardado exitosamente. Para ver los cambios, recargue la página.");
})
.catch((error) => alert(error));
}
const enum Operation {
Create = "create",
Edit = "edit",
}
interface MapEvent { interface MapEvent {
latlng: L.latlng; latlng: L.LatLng;
relatedTarget: L.Marker | L.Path | undefined;
} }
async function setupMap(): Promise<void> { async function setupMap(): Promise<void> {
@ -111,21 +178,62 @@ async function setupMap(): Promise<void> {
} }
} }
function openForm(title: string, lat: number, long: number): void { function openForm(op: Operation, lat: number, long: number): void {
/* Fill the form for us */
const h1 = modal.getElementsByTagName("h1")[0]; const h1 = modal.getElementsByTagName("h1")[0];
h1.innerText = title; if (op == Operation.Create) {
clearForm()
h1.innerText = "Añadir lugar nuevo";
} else {
h1.innerText = "Editar lugar";
}
const latInput = (document.getElementById("lat") as HTMLInputElement); const latInput = (document.getElementById("lat") as HTMLInputElement);
latInput.value = lat.toString();
const longInput = (document.getElementById("long") as HTMLInputElement); const longInput = (document.getElementById("long") as HTMLInputElement);
latInput.value = lat.toString();
longInput.value = long.toString(); longInput.value = long.toString();
if (op == Operation.Edit) {
const place = places.get(toStr({ lat: lat, lng: long }));
console.log(toStr({ lat: lat, lng: long }));
/*Get the form elements*/
const idInput = (document.getElementById("id") as HTMLInputElement);
const nameInput = (document.getElementById("name") as HTMLInputElement);
const addressInput = (document.getElementById("address") as HTMLInputElement);
const openHoursArea = (document.getElementById("open_hours") as HTMLTextAreaElement);
const iconSelect = (document.getElementById("icon") as HTMLSelectElement);
const descriptionArea = (document.getElementById("description") as HTMLTextAreaElement);
/* And set them */
idInput.value = place.id.toString();
nameInput.value = place.name;
addressInput.value = place.address;
openHoursArea.value = place.open_hours;
iconSelect.value = place.icon;
descriptionArea.value = place.description;
}
/* Plug callbacks */
if (op == Operation.Create) {
document.getElementById("button").onclick = createPlace;
} else {
document.getElementById("button").onclick = editPlace;
}
/* Make it appear */
modal.style.display = "block"; modal.style.display = "block";
} }
function openCreateForm(e: MapEvent) { function openCreateForm(e: MapEvent) {
const lat = e.latlng.lat; const lat = e.latlng.lat;
const long = e.latlng.lng; const long = e.latlng.lng;
openForm("Añadir lugar nuevo", lat, long); openForm(Operation.Create, lat, long);
}
function openEditForm(e: MapEvent) {
const marker = (e.relatedTarget as L.Marker);
const lat = marker.getLatLng().lat;
const long = marker.getLatLng().lng;
openForm(Operation.Edit, lat, long);
} }
/* Get places from backend */ /* Get places from backend */
@ -133,13 +241,13 @@ async function setupMap(): Promise<void> {
const leafletPlaces = toLeafletPlaces(backendPlaces); const leafletPlaces = toLeafletPlaces(backendPlaces);
for (const place of backendPlaces) { for (const place of backendPlaces) {
places.set( places.set(
{ lat: place.latitude, lng: place.longitude }, toStr({ lat: place.latitude, lng: place.longitude }),
place place
); );
} }
/* Set up the map*/ /* Set up the map*/
const map = new L.Map('map', { const map = new L.map('map', {
contextmenu: true, contextmenu: true,
contextmenuWidth: 140, contextmenuWidth: 140,
contextmenuItems: [ contextmenuItems: [
@ -181,7 +289,8 @@ async function setupMap(): Promise<void> {
contextmenu: true, contextmenu: true,
contextmenuInheritItems: false, contextmenuInheritItems: false,
contextmenuItems: [{ contextmenuItems: [{
text: 'Marker item' text: 'Editar',
callback: openEditForm,
}] }]
}); });
} }