feat: use drink api in front and more (#16)
All checks were successful
Build Docker Image Front / run (push) Successful in 28s
Build Docker Image Back / run (push) Successful in 27s

Reviewed-on: #16
Co-authored-by: Clement <c.boesmier@aptatio.com>
Co-committed-by: Clement <c.boesmier@aptatio.com>
This commit is contained in:
2024-06-07 19:09:57 +02:00
committed by Clement
parent 2cb2166093
commit 3cb5a30270
36 changed files with 882 additions and 132 deletions

View File

@ -0,0 +1,89 @@
---
import Layout from 'layouts/PageLayout.astro'
import 'leaflet/dist/leaflet.css'
import 'leaflet-routing-machine/dist/leaflet-routing-machine.css'
import FormContainer from 'components/ui/Form.astro'
import Input from 'components/Input.astro'
import Button from 'components/ui/Button.astro'
const metadata = {
title: 'Maps',
ignoreTitleTemplate: true,
}
---
<Layout metadata={metadata}>
<div class="h-[calc(100vh-16rem)] flex flex-col">
<div class="w-full h-96 grow" id="map" />
<Button id="test-btn">test</Button>
</div>
<!-- TODO: faire en sort que le style soit propre -->
<!-- for remouve footer -->
<!-- <div slot="footer"></div> -->
<!-- penser a rm 11 au rem au dessus pour la taille -->
</Layout>
<script>
import * as L from 'leaflet'
import markerShadow from "leaflet/dist/images/marker-shadow.png"
import markerIcon from "leaflet/dist/images/marker-icon.png"
import 'leaflet-routing-machine/dist/leaflet-routing-machine.js'
import 'leaflet-control-geocoder/dist/Control.Geocoder.js'
const icon = {icon: new L.Icon({iconUrl: markerIcon.src, shadowUrl: markerShadow.src, iconAnchor: [13,41]})}
// declare map
const map = L.map('map', {
center: [51.5, -0.09],
zoom: 13,
preferCanvas: true,
zoomControl: false
})
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map)
// move zoom ctl to bottom
L.control.zoom({
position: 'bottomleft'
}).addTo(map);
const routing = L.Routing.control({
// utile pour afficher des route stocké
// waypoints: [
// L.latLng(46.6705431, -1.4269698),
// L.latLng(47.218536, -1.554075)
// ],
routeWhileDragging: true,
//@ts-ignore
geocoder: L.Control.Geocoder.nominatim(),
//@ts-ignore
position: 'topleft',
showAlternatives: true,
reverseWaypoints: true,
altLineOptions: {
missingRouteTolerance: 50,
extendToWaypoints: true,
styles: [
{color: 'black', opacity: 0.15, weight: 9},
{color: 'white', opacity: 0.2, weight: 6},
{color: 'blue', opacity: 5, weight: 2}
]
}
}).addTo(map).on('routeselected', (e) => {
console.log("iténeraire choisie")
console.log(e)
}).on('routesfound', (e) =>{
console.log("route trouvé")
console.log(e)
})
document.querySelector<HTMLButtonElement>('#test-btn')?.addEventListener('click', () => {
routing.setWaypoints(
[L.latLng(46.6705431, -1.4269698),L.latLng(47.218536, -1.554075)]
)
routing.route();
})
</script>

View File

@ -0,0 +1,281 @@
---
import Layout from 'layouts/PageLayout.astro'
import 'leaflet/dist/leaflet.css'
import 'leaflet-geosearch/dist/geosearch.css'
import CheckBox from 'components/CheckBox.astro'
import Radios from 'components/Radios.astro'
import ListResult, { type RecordModel } from 'pocketbase'
import { Expand, Trash } from 'lucide-astro'
const pb = Astro.locals.pb
const connected = pb.authStore.isValid
const metadata = {
title: 'Maps',
ignoreTitleTemplate: true,
}
let fav = new Array<any>
if(connected){
try {
const request = await pb.collection('user_poi').getList(1,10,{filter:`owner="${pb.authStore.model!.id}"`, expand:"poi_list"})
request.items.forEach(element => {
fav.push(element.expand!.poi_list.Poi)
});
} catch (error) {
console.log(error);
}
}
console.log(fav);
---
<Layout metadata={metadata}>
<div class="h-[calc(100vh-5rem)] flex flex-row">
<div class="w-1/5 flex flex-col">
<p id="message" class="hidden text-center mb-3">pouet</p>
<p class="text-center text-2xl mb-3">Filtre :</p>
<div class="">
<p>note minimal :</p>
<Radios
values={[
{name: "1", label: "1", checked: true},
{name: "2", label: "2"},
{name: "3", label: "3"},
{name: "1h", label: "1h"},
{name: "2h", label: "2h"},
{name: "3h", label: "3h"},
]}
/>
<p class="text-center text-xl mb-3">Type POI :</p>
<CheckBox
label="Bar, Pub, Café,..."
name="filter"
value="drink"
checked
/>
</div>
<div class="mb-3 grow">
<p class="text-center text-xl mb-3">Source :</p>
<CheckBox
label="Open Trip Maps"
name="filter"
value="otm"
checked
/>
</div>
{connected && (
<div class="mb-2">
<p class="text-center text-xl mb-3">Favori :</p>
{fav.map(val =>(
<div class="ml-2 flex flex-row mb-1" id="fav-div">
<p class="grow poi-favori" id={val.id} data-pos={val.geometry.coordinates}>{val.properties.name}</p>
<Trash id={val.id} class="poi-trash"/>
</div>
))}
</div>
)}
</div>
<div class="flex flex-col h-full grow">
<div class="w-full h-full grow" id="map" />
</div>
</div>
<!-- TODO: faire en sort que le style soit propre -->
<!-- for remouve footer -->
<div slot="footer"></div>
<!-- penser a rm 11 au rem au dessus pour la taille -->
</Layout>
<script>
import L, {Popup} from 'leaflet'
import markerShadow from "leaflet/dist/images/marker-shadow.png"
import markerIcon from "leaflet/dist/images/marker-icon.png"
import { OpenStreetMapProvider } from 'leaflet-geosearch'
import { GeoSearchControl } from 'leaflet-geosearch'
const showFav = document.querySelectorAll(".poi-favori")
const trashFav = document.querySelectorAll(".poi-trash")
const favDiv = document.querySelector('#fav-div')
const icon = {icon: new L.Icon({iconUrl: markerIcon.src, shadowUrl: markerShadow.src, iconAnchor: [13,41]})}
// const BACK_URL = "http://localhost:3001/" //XXX : mettre url de prod
const BACK_URL = "https://drink-tweb.cb85.fr/" //XXX : mettre url de prod
// declare map
const map = L.map('map', {
center: [51.5, -0.09],
zoom: 13,
preferCanvas: true,
zoomControl: false
})
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map)
// move zoom ctl to bottom
L.control.zoom({
position: 'bottomleft'
}).addTo(map)
const provider = new OpenStreetMapProvider()
map.addControl(
GeoSearchControl({
notFoundMessage: 'Adresse introuvable !',
provider,
showMarker: false,
style: 'bar',
}),
)
async function saveToFav(element: any, save: boolean){
const url = '/maps/save_poi';
const options = {
method: 'POST',
body: JSON.stringify({Poi : element, save: save})
};
try {
const response = await fetch(url, options);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}
function eventGotoFav(e: Element){
e.addEventListener('click', () =>{
const pose = e.getAttribute('data-pos')?.split(',')
map.panTo(new L.LatLng(parseFloat(pose![1]),parseFloat(pose![0])))
})
}
function eventRemoveFav(e: Element){
e.addEventListener('click', async () => {
await saveToFav({id:e.id, type:"Feature"},false)
document.location.reload()
})
}
showFav.forEach(e => {eventGotoFav(e)})
trashFav.forEach(e => {eventRemoveFav(e)})
let poiMarkers = new Array<L.Marker>
let minimalNote = "1"
let drink = true
let otm = true
// run api search
function searchBox(){
const nordWest = map.getBounds().getNorthWest()
const southEast = map.getBounds().getSouthEast()
const params: URLSearchParams = new URLSearchParams()
params.append("lon1", nordWest.lng.toString())
params.append("lat1", nordWest.lat.toString())
params.append("lon2", southEast.lng.toString())
params.append("lat2", southEast.lat.toString())
params.append("rate", minimalNote)
if(drink && otm){
fetch(`${BACK_URL}otm/box?${params.toString()}`,{method: 'GET',headers: {'Content-Type': 'application/json'}}).then(function (response) {
return response.json()
}).then(function (data) {
poiMarkers.forEach(element => {
element.remove()
})
console.log(data)
data.features.forEach(element => {
const prop = element.properties
const popup: Popup = new Popup()
let tags = new String()
prop.kinds.split(",").forEach(element => {
tags += "- " + element + "<br/>"
})
const poiMarker = L.marker([element.geometry.coordinates[1],element.geometry.coordinates[0]],icon)
.bindPopup(`<b>${prop.name}</b><br/>note : ${prop.rate} <br/>tags:<br/> ${tags} <p>favori : <input type="checkbox" name="like" id=${element.id}/><p>`)
.on("click", () => {
document.querySelectorAll<HTMLInputElement>('input[name="like"]').forEach(e => {
e.addEventListener("click", () => {
console.log(element)
saveToFav(element, e.checked)
document.location.reload()
})
})
})
poiMarker.addTo(map)
poiMarkers.push(poiMarker)
})
}).catch(function (err) {
console.warn('Something went wrong.', err)
})
}
}
// fonciton pour lancer la recherche de box sur l'api
function sender(){
if(map.getZoom() >= 13){
console.log("zoom OKAY")
//TODO: mettre un message de recherche en cour
searchBox()
}else{
console.log("zoom more to see result")
}
}
// envent pour lancer la recherche
const cooldown = 400
sender()
let timeoutHandle = window.setTimeout(sender, cooldown)
window.clearTimeout(timeoutHandle)
map.addEventListener("move",() =>{
window.clearTimeout(timeoutHandle)
timeoutHandle = window.setTimeout(sender, cooldown)
})
map.addEventListener("zoom", () => {
if(map.getZoom() <= 11){
poiMarkers.forEach(element => {
element.remove()
})
}
})
document.querySelectorAll<HTMLInputElement>("input[name='filter']").forEach(e =>{
e.addEventListener("click", () => {
switch (e.value) {
case "drink":
drink = e.checked
break;
case "otm":
otm = e.checked
break;
default:
break;
}
poiMarkers.forEach(element => {
element.remove()
})
searchBox()
})
})
document.querySelectorAll<HTMLInputElement>('input[name="note-min"]').forEach(e => {
e.addEventListener("click", () => {
minimalNote = e.value
searchBox()
})
})
</script>

View File

@ -0,0 +1,47 @@
---
import AstroUtils from "libs/AstroUtils";
import type { RecordModel } from "pocketbase";
const pb = Astro.locals.pb
if(!pb.authStore.isValid){
return Astro.redirect("/account")
}
await AstroUtils.wrap(async () => {
if (Astro.request.method !== 'POST') {
return
}
const poiJson = await Astro.request.json()
const data = {Poi: poiJson.Poi, Poi_id:poiJson.Poi.id}
let record: RecordModel
try {
record = await pb.collection('POI').create(data);
} catch (error) {
try{
record = await pb.collection('POI').getFirstListItem(`Poi_id="${poiJson.Poi.id}"`)
} catch (error2) {
console.log("error 1 :")
console.log(error)
console.log("error 2 :")
console.log(error2)
}
}
try {
if(poiJson.save){
await pb.collection('user_poi').create({owner: pb.authStore.model!.id, poi_list:record!.id})
}else{
record = await pb.collection('user_poi').getFirstListItem(`poi_list="${record!.id}"&&owner="${pb.authStore.model!.id}"`)
await pb.collection('user_poi').delete(record.id)
}
} catch (error) {
console.log(error)
}
})
---