Add optional URL field #14
6 changed files with 44 additions and 15 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -654,7 +654,7 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
|||
|
||||
[[package]]
|
||||
name = "huellas"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
dependencies = [
|
||||
"rocket",
|
||||
"rocket_db_pools",
|
||||
|
|
|
|||
1
migrations/20230315004723_add_url.sql
Normal file
1
migrations/20230315004723_add_url.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE places ADD url VARCHAR DEFAULT null;
|
||||
|
|
@ -11,4 +11,5 @@ pub struct Place {
|
|||
pub description: String,
|
||||
pub longitude: f64,
|
||||
pub latitude: f64,
|
||||
pub url: Option<String>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ struct Db(rocket_db_pools::sqlx::SqlitePool);
|
|||
#[get("/places")]
|
||||
async fn get_places(mut db: Connection<Db>) -> Result<Json<Vec<Place>>> {
|
||||
let places = rocket_db_pools::sqlx::query!(
|
||||
"SELECT id, name, address, open_hours, icon, description," +
|
||||
"SELECT id, name, address, open_hours, icon, description, url," +
|
||||
r#"longitude as "longitude: f64", latitude as "latitude: f64" FROM places WHERE active = TRUE"#
|
||||
)
|
||||
.fetch(&mut *db)
|
||||
|
|
@ -29,6 +29,7 @@ async fn get_places(mut db: Connection<Db>) -> Result<Json<Vec<Place>>> {
|
|||
description: p.description,
|
||||
latitude: p.latitude,
|
||||
longitude: p.longitude,
|
||||
url: p.url,
|
||||
})
|
||||
.try_collect::<Vec<_>>()
|
||||
.await?;
|
||||
|
|
@ -59,8 +60,8 @@ struct Id {
|
|||
async fn insert_place(mut db: Connection<Db>, mut place: Json<Place>) -> Result<UpsertResponse> {
|
||||
let i = ::sqlx::query_as!(
|
||||
Id,
|
||||
"INSERT INTO places (name, address, open_hours, icon, description, longitude, latitude)\
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)\
|
||||
"INSERT INTO places (name, address, open_hours, icon, description, longitude, latitude, url)\
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)\
|
||||
RETURNING id",
|
||||
place.name,
|
||||
place.address,
|
||||
|
|
@ -68,7 +69,8 @@ async fn insert_place(mut db: Connection<Db>, mut place: Json<Place>) -> Result<
|
|||
place.icon,
|
||||
place.description,
|
||||
place.longitude,
|
||||
place.latitude
|
||||
place.latitude,
|
||||
place.url
|
||||
)
|
||||
.fetch_one(&mut *db)
|
||||
.await?;
|
||||
|
|
@ -79,7 +81,7 @@ 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> {
|
||||
let result = ::sqlx::query!(
|
||||
"UPDATE places SET (name, address, open_hours, icon, description, longitude, latitude) = (?, ?, ?, ?, ?, ?, ?) WHERE id = ?",
|
||||
"UPDATE places SET (name, address, open_hours, icon, description, longitude, latitude, url) = (?, ?, ?, ?, ?, ?, ?, ?) WHERE id = ?",
|
||||
place.name,
|
||||
place.address,
|
||||
place.open_hours,
|
||||
|
|
@ -87,6 +89,7 @@ async fn update_place(mut db: Connection<Db>, place: Json<Place>) -> Result<Upse
|
|||
place.description,
|
||||
place.longitude,
|
||||
place.latitude,
|
||||
place.url,
|
||||
place.id,
|
||||
)
|
||||
.execute(&mut *db)
|
||||
|
|
@ -105,7 +108,7 @@ async fn delete_place(mut db: Connection<Db>, id: i64) -> Result<Option<()>> {
|
|||
.execute(&mut *db)
|
||||
.await?;
|
||||
|
||||
Ok((result.rows_affected() == 1).then(|| ()))
|
||||
Ok((result.rows_affected() == 1).then_some(()))
|
||||
}
|
||||
|
||||
async fn run_migrations(rocket: Rocket<Build>) -> fairing::Result {
|
||||
|
|
|
|||
|
|
@ -136,6 +136,10 @@
|
|||
<option value="shop">Tienda</option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="url"> URL:</label>
|
||||
<input type="text" id="url" name="url" size="30">
|
||||
</p>
|
||||
<p>
|
||||
<label for="description"> Descripción:</label>
|
||||
<textarea id="description" name="description"
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ interface PlaceModel {
|
|||
description: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
url: string | null;
|
||||
}
|
||||
|
||||
async function loadPlaces(): Promise<Array<PlaceModel>> {
|
||||
|
|
@ -24,7 +25,8 @@ function toFeature(place: PlaceModel): Feature {
|
|||
"address": place.address,
|
||||
"open_hours": place.open_hours,
|
||||
"icon": place.icon,
|
||||
"description": place.description
|
||||
"description": place.description,
|
||||
"url": place.url,
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
|
|
@ -68,6 +70,8 @@ function getPlaceFromForm(): PlaceModel {
|
|||
(document.getElementById("lat") as HTMLInputElement).value);
|
||||
const longitude = parseFloat(
|
||||
(document.getElementById("long") as HTMLSelectElement).value);
|
||||
const url =
|
||||
(document.getElementById("url") as HTMLInputElement).value;
|
||||
|
||||
return {
|
||||
id: id,
|
||||
|
|
@ -78,6 +82,7 @@ function getPlaceFromForm(): PlaceModel {
|
|||
description: description,
|
||||
latitude: latitude,
|
||||
longitude: longitude,
|
||||
url: url,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -88,6 +93,7 @@ function clearForm(): void {
|
|||
const longInput = (document.getElementById("long") as HTMLInputElement);
|
||||
const nameInput = (document.getElementById("name") as HTMLInputElement);
|
||||
const addressInput = (document.getElementById("address") as HTMLInputElement);
|
||||
const urlInput = (document.getElementById("url") as HTMLInputElement);
|
||||
const openHoursArea = (document.getElementById("open_hours") as HTMLTextAreaElement);
|
||||
const descriptionArea = (document.getElementById("description") as HTMLTextAreaElement);
|
||||
|
||||
|
|
@ -97,6 +103,7 @@ function clearForm(): void {
|
|||
longInput.value = "";
|
||||
nameInput.value = "";
|
||||
addressInput.value = "";
|
||||
urlInput.value = "";
|
||||
openHoursArea.value = "";
|
||||
descriptionArea.value = "";
|
||||
|
||||
|
|
@ -168,6 +175,14 @@ async function getAddressReverse(lat: number, long: number): Promise<string> {
|
|||
return `${address.road} ${address.house_number}, ${address.city}`;
|
||||
}
|
||||
|
||||
function toLink(url: string): string {
|
||||
let content = url;
|
||||
const m = url.match("https://instagram.com/(.*)");
|
||||
if (m) {
|
||||
content = `@${m[1]}`;
|
||||
}
|
||||
return `<a href="${url}" target="_blank">${content}</a>`
|
||||
}
|
||||
async function setupMap(): Promise<void> {
|
||||
/* Create/Edit form */
|
||||
const modal = document.getElementById("modal");
|
||||
|
|
@ -204,6 +219,7 @@ async function setupMap(): Promise<void> {
|
|||
/*Get the form elements*/
|
||||
const idInput = (document.getElementById("id") as HTMLInputElement);
|
||||
const nameInput = (document.getElementById("name") as HTMLInputElement);
|
||||
const urlInput = (document.getElementById("url") as HTMLInputElement);
|
||||
const openHoursArea = (document.getElementById("open_hours") as HTMLTextAreaElement);
|
||||
const iconSelect = (document.getElementById("icon") as HTMLSelectElement);
|
||||
const descriptionArea = (document.getElementById("description") as HTMLTextAreaElement);
|
||||
|
|
@ -212,6 +228,7 @@ async function setupMap(): Promise<void> {
|
|||
idInput.value = place.id.toString();
|
||||
nameInput.value = place.name;
|
||||
addressInput.value = place.address;
|
||||
urlInput.value = place.url;
|
||||
openHoursArea.value = place.open_hours;
|
||||
iconSelect.value = place.icon;
|
||||
descriptionArea.value = place.description;
|
||||
|
|
@ -287,19 +304,22 @@ async function setupMap(): Promise<void> {
|
|||
|
||||
function onEachFeature(feature: Feature, layer: L.Layer) {
|
||||
if (feature.properties) {
|
||||
let popupStr = "<h3>" + feature.properties.name + "</h3>";
|
||||
let popupStr = `<h3>${feature.properties.name}</h3>`;
|
||||
popupStr += "<ul>"
|
||||
if (feature.properties.address)
|
||||
popupStr += "<li><b>Dirección:</b> " + feature.properties.address + "</li>";
|
||||
popupStr += `<li><b>Dirección:</b>${feature.properties.address}</li>`;
|
||||
if (feature.properties.open_hours)
|
||||
popupStr += "<li><b>Horario:</b> " + feature.properties.open_hours + "</li>";
|
||||
popupStr += `<li><b>Horario:</b>${feature.properties.open_hours}</li>`;
|
||||
if (feature.properties.description)
|
||||
popupStr += "<li>" + feature.properties.description + "</li>";
|
||||
popupStr += `<li>${feature.properties.description}</li>`;
|
||||
if (feature.properties.url)
|
||||
popupStr += `<li>${toLink(feature.properties.url)}</li>`;
|
||||
|
||||
const lnglat = (feature.geometry as Point).coordinates;
|
||||
popupStr += "<a href=\"https://www.google.com/maps/dir//" +
|
||||
lnglat[1] + "," + lnglat[0] + "/@" + lnglat[1] + "," + lnglat[0] +
|
||||
",15z\" target=\"_blank\">GMaps</a>"
|
||||
const lng = lnglat[0];
|
||||
const lat = lnglat[0];
|
||||
popupStr += `<a href="https://www.google.com/maps/dir//` +
|
||||
`${lat},${lng}/@${lat},${lng},15z" target="_blank">GMaps</a>`
|
||||
popupStr += "</ul>";
|
||||
|
||||
layer.bindPopup(popupStr);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue