feat: use drink api in front and more (#16)
Reviewed-on: #16 Co-authored-by: Clement <c.boesmier@aptatio.com> Co-committed-by: Clement <c.boesmier@aptatio.com>
This commit is contained in:
30
front/src/components/CheckBox.astro
Normal file
30
front/src/components/CheckBox.astro
Normal file
@ -0,0 +1,30 @@
|
||||
---
|
||||
import type { Input as Props } from 'types';
|
||||
|
||||
const {value, checked ,name, label, autocomplete, placeholder, divClass, inputClass} = Astro.props;
|
||||
|
||||
---
|
||||
|
||||
<>
|
||||
{
|
||||
name && (
|
||||
<div class={"flex flex-row items-center " + divClass}>
|
||||
<input
|
||||
type="checkbox"
|
||||
name={name}
|
||||
id={name}
|
||||
checked={checked}
|
||||
value={value}
|
||||
autocomplete={autocomplete}
|
||||
placeholder={placeholder}
|
||||
class={"mr-2 size-5 " + inputClass}
|
||||
/>
|
||||
{label && (
|
||||
<label for={name} class="block text-lg font-medium">
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</>
|
28
front/src/components/Input.astro
Normal file
28
front/src/components/Input.astro
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
import type { Input as Props } from 'types';
|
||||
|
||||
const { type, name, label, autocomplete, placeholder, divClass, inputClass} = Astro.props;
|
||||
|
||||
---
|
||||
|
||||
<>
|
||||
{
|
||||
name && (
|
||||
<div class={divClass}>
|
||||
{label && (
|
||||
<label for={name} class="block text-sm font-medium">
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
<input
|
||||
type={type}
|
||||
name={name}
|
||||
id={name}
|
||||
autocomplete={autocomplete}
|
||||
placeholder={placeholder}
|
||||
class={"py-3 px-4 block w-full text-md rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-slate-900" + inputClass}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</>
|
19
front/src/components/Radios.astro
Normal file
19
front/src/components/Radios.astro
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
|
||||
export interface Props {
|
||||
values: Array<{label:String, name:string, checked?:boolean | undefined}>
|
||||
}
|
||||
|
||||
|
||||
const fields = Astro.props.values
|
||||
|
||||
---
|
||||
|
||||
<>
|
||||
<div class="flex, flex-col">
|
||||
{fields.map(value => (
|
||||
<input type="radio" id={value.name} name="note-min" value={value.name} checked={value.checked}>
|
||||
<label for={value.name} class="ml-1">{value.label}</label><br>
|
||||
))}
|
||||
</div>
|
||||
</>
|
@ -26,7 +26,7 @@ export interface Props {
|
||||
const { socialLinks = [], secondaryLinks = [], links = [], footNote = '', theme = 'light' } = Astro.props;
|
||||
---
|
||||
|
||||
<footer class:list={[{ dark: theme === 'dark' }, 'relative border-t border-gray-200 dark:border-slate-800 not-prose, mt-auto']}>
|
||||
<footer class:list={[{ dark: theme === 'dark' }, 'relative border-t border-gray-200 dark:border-slate-800 not-prose, mt-auto, h-{11rem}']}>
|
||||
<div class="dark:bg-dark absolute inset-0 pointer-events-none" aria-hidden="true"></div>
|
||||
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 dark:text-slate-300">
|
||||
<div class="grid grid-cols-12 gap-4 gap-y-8 sm:gap-8 py-8 md:py-12">
|
||||
|
@ -55,7 +55,7 @@ const currentPath = `/${trimSlash(new URL(Astro.url).pathname)}`
|
||||
<header
|
||||
class:list={[
|
||||
{ sticky: isSticky, relative: !isSticky, dark: isDark },
|
||||
'top-0 z-40 flex-none mx-auto w-full border-b border-gray-50/0 transition-[opacity] ease-in-out',
|
||||
'top-0 z-[1001] h-[5rem] bg-page flex-none mx-auto w-full border-b border-gray-50/0 transition-[opacity] ease-in-out',
|
||||
]}
|
||||
{...isSticky ? { 'data-aw-sticky-header': true } : {}}
|
||||
{...id ? { id } : {}}
|
||||
@ -88,7 +88,7 @@ const currentPath = `/${trimSlash(new URL(Astro.url).pathname)}`
|
||||
aria-label="Main navigation"
|
||||
>
|
||||
<ul
|
||||
class="flex flex-col md:flex-row md:self-center w-full md:w-auto text-xl md:text-[0.9375rem] tracking-[0.01rem] font-medium md:justify-center"
|
||||
class="flex flex-col bg-page md:flex-row md:self-center w-full md:w-auto text-xl md:text-[0.9375rem] tracking-[0.01rem] font-medium md:justify-center"
|
||||
>
|
||||
{
|
||||
links.map(({ text, href, links }) => (
|
||||
|
@ -1,6 +1,6 @@
|
||||
site:
|
||||
name: AstroWind
|
||||
site: 'https://astrowind.vercel.app'
|
||||
name: EpicRoadTrip
|
||||
site: 'https://front-tweb.cb85.fr'
|
||||
base: '/'
|
||||
trailingSlash: false
|
||||
|
||||
|
6
front/src/env.d.ts
vendored
6
front/src/env.d.ts
vendored
@ -6,10 +6,10 @@
|
||||
|
||||
import PocketBase from 'pocketbase'
|
||||
export interface ImportMetaEnv {
|
||||
NODE_ENV: string
|
||||
APP_URL: string
|
||||
NODE_ENV: string
|
||||
APP_URL: string
|
||||
|
||||
POCKETBASE_URL: string
|
||||
POCKETBASE_URL: string
|
||||
|
||||
GOOGLE_API_KEY: string
|
||||
}
|
||||
|
@ -80,18 +80,4 @@ const metadata = {
|
||||
]}
|
||||
/>
|
||||
<Oauth/>
|
||||
<form id="account-creation" method="post" enctype="multipart/form-data">
|
||||
<input type="hidden" name="type" value="userPassword">
|
||||
<input required name="name" placeholder="Prénom Nom"/>
|
||||
<input required name="username" placeholder="Pseudo"/>
|
||||
<input required name="email" type="email" placeholder="Renseignez votre email" />
|
||||
<input required name="password" type="password" placeholder="Créez un mot de passe" />
|
||||
<input required name="passwordConfirm" type="password" placeholder="Confirmer votre mot de passe" />
|
||||
<button>Créer un compte</button>
|
||||
</form>
|
||||
|
||||
<button id="OauthDiscord">connexion avec discord</button>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<input type="hidden" name="type" value="discord2FA">
|
||||
</form>
|
||||
</Layout>
|
||||
|
@ -1,31 +0,0 @@
|
||||
---
|
||||
import Layout from 'layouts/PageLayout.astro';
|
||||
import 'leaflet/dist/leaflet.css'
|
||||
|
||||
const metadata = {
|
||||
title: 'Maps',
|
||||
ignoreTitleTemplate: true,
|
||||
};
|
||||
---
|
||||
|
||||
<Layout metadata={metadata}>
|
||||
|
||||
<div class="w-full h-96" id="map" />
|
||||
|
||||
|
||||
</Layout>
|
||||
|
||||
<script>
|
||||
import L from 'leaflet'
|
||||
|
||||
const map = L.map('map', {
|
||||
center: [50,0],
|
||||
zoom: 13,
|
||||
preferCanvas: true
|
||||
})
|
||||
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
}).addTo(map);
|
||||
var marker = L.marker([51.5, -0.09]).addTo(map);
|
||||
</script>
|
89
front/src/pages/maps/find_route.astro
Normal file
89
front/src/pages/maps/find_route.astro
Normal 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: '© <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>
|
281
front/src/pages/maps/index.astro
Normal file
281
front/src/pages/maps/index.astro
Normal 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: '© <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>
|
47
front/src/pages/maps/save_poi.astro
Normal file
47
front/src/pages/maps/save_poi.astro
Normal 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)
|
||||
}
|
||||
|
||||
})
|
||||
---
|
10
front/src/types.d.ts
vendored
10
front/src/types.d.ts
vendored
@ -1,5 +1,5 @@
|
||||
import type { AstroComponentFactory } from 'astro/runtime/server/index.js'
|
||||
import type { HTMLAttributes, ImageMetadata } from 'astro/types'
|
||||
import type { HTMLAttributes, ImageMetadata, HTMLInputTypeAttribute } from 'astro/types'
|
||||
|
||||
export interface Post {
|
||||
/** A unique ID number that identifies a post. */
|
||||
@ -26,7 +26,7 @@ export interface Post {
|
||||
/** */
|
||||
category?: Taxonomy
|
||||
/** */
|
||||
tags?: Taxonomy[]
|
||||
tags?: Array<Taxonomy>
|
||||
/** */
|
||||
author?: string
|
||||
|
||||
@ -162,11 +162,15 @@ export interface Testimonial {
|
||||
}
|
||||
|
||||
export interface Input {
|
||||
type: HTMLInputTypeAttribute
|
||||
type?: HTMLInputTypeAttribute
|
||||
name: string
|
||||
label?: string
|
||||
autocomplete?: string
|
||||
placeholder?: string
|
||||
divClass?: string
|
||||
inputClass?: string
|
||||
checked?: bool
|
||||
value?:string
|
||||
}
|
||||
|
||||
export interface Textarea {
|
||||
|
Reference in New Issue
Block a user