commit 1f9be3fbf83a0f4514c309d8caf05329a6cfe33b
parent 12b5e18a17259322b22e48da2f96f6e202378aa7
Author: triesap <137732411+triesap@users.noreply.github.com>
Date: Thu, 3 Oct 2024 14:11:38 +0000
Add `/map/choose-location` route, remove (map) layout and move map routes into (app), move nostr subscribers from root layout to (app) layout, add nostr ndk configured subscriber, edit trade products add route adding choose from map option for location gcs model
Diffstat:
8 files changed, 397 insertions(+), 234 deletions(-)
diff --git a/src/lib/components/map_control_full.svelte b/src/lib/components/map_control_full.svelte
@@ -1,7 +1,15 @@
<script lang="ts">
- import { Glyph, app_layout, route } from "@radroots/svelte-lib";
+ import {
+ Glyph,
+ app_layout,
+ type CallbackPromise,
+ } from "@radroots/svelte-lib";
let el_zoom: HTMLElement | null;
+
+ export let basis: {
+ callback: CallbackPromise;
+ };
</script>
<div
@@ -11,7 +19,7 @@
<button
class={`flex flex-row h-8 w-8 justify-center items-center rounded-2xl bg-layer-1-surface`}
on:click={async () => {
- await route(`/`);
+ await basis.callback();
}}
>
<Glyph
diff --git a/src/lib/utils/location_gcs.ts b/src/lib/utils/location_gcs.ts
@@ -25,16 +25,13 @@ export const location_gcs_add = async (): Promise<boolean> => {
lat,
lng,
);
- const fields = {
- lat: lat.toString(),
- lng: lng.toString(),
- geohash,
- label: loc_gcs_label,
- };
const exe_res =
- await lc.db.location_gcs_add(
- fields,
- );
+ await lc.db.location_gcs_add({
+ lat: lat.toString(),
+ lng: lng.toString(),
+ geohash,
+ label: loc_gcs_label,
+ });
console.log(`exe_res `, exe_res)
if (
typeof exe_res !== `string` &&
diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte
@@ -1,5 +1,157 @@
<script lang="ts">
- import { LayoutWindow } from "@radroots/svelte-lib";
+ import { lc } from "$lib/client";
+ import { _conf } from "$lib/conf";
+ import { app_nostr_key } from "$lib/stores";
+ import {
+ type NostrRelayFormFields,
+ parse_nostr_relay_form_keys,
+ } from "@radroots/models";
+ import {
+ LayoutWindow,
+ ndk,
+ ndk_init,
+ ndk_user,
+ nostr_ndk_configured,
+ nostr_relays_connected,
+ nostr_relays_poll_documents,
+ nostr_relays_poll_documents_count,
+ } from "@radroots/svelte-lib";
+ import { parse_nostr_relay_information_document_fields } from "@radroots/utils";
+
+ app_nostr_key.subscribe(async (_app_nostr_key) => {
+ try {
+ if (!_app_nostr_key) return;
+ const secret_key = await lc.keystore.get(
+ _conf.kv.nostr_key(_app_nostr_key),
+ );
+ if (!secret_key) {
+ alert(`!secret_key`); //@todo
+ return;
+ }
+ const nostr_relays = await lc.db.nostr_relay_get({
+ list: ["all"],
+ });
+ if (typeof nostr_relays === `string`) {
+ alert(nostr_relays); //@todo
+ return;
+ }
+ for (const { url } of nostr_relays) $ndk.addExplicitRelay(url);
+ await $ndk.connect();
+ const ndk_user = await ndk_init({
+ $ndk,
+ secret_key,
+ });
+ if (!ndk_user) {
+ nostr_ndk_configured.set(false);
+ return;
+ }
+ $ndk_user = ndk_user;
+ $ndk_user.ndk = $ndk;
+ nostr_ndk_configured.set(true);
+ } catch (e) {
+ console.log(`(app_nostr_key) error `, e);
+ }
+ });
+
+ nostr_ndk_configured.subscribe(async (_nostr_ndk_configured) => {
+ try {
+ if (!_nostr_ndk_configured) return;
+ console.log(`(nostr_ndk_configured) success`);
+ nostr_relays_poll_documents.set(true);
+ } catch (e) {
+ console.log(`(error) nostr_ndk_configured`, e);
+ }
+ });
+
+ nostr_relays_poll_documents.subscribe(
+ async (_nostr_relays_poll_documents) => {
+ try {
+ if (!_nostr_relays_poll_documents) return;
+ await fetch_relay_documents();
+ } catch (e) {
+ console.log(`(error) nostr_relays_poll_documents`, e);
+ }
+ },
+ );
+
+ nostr_relays_connected.subscribe(async (_nostr_relays_connected) => {
+ try {
+ if (!_nostr_relays_connected.length) return;
+ else if ($nostr_ndk_configured) {
+ console.log(`nostr sync...`);
+ }
+ } catch (e) {
+ console.log(`(error) nostr_relays_connected `, e);
+ }
+ });
+
+ const fetch_relay_documents = async (): Promise<void> => {
+ try {
+ if (
+ $nostr_relays_poll_documents_count >=
+ _conf.nostr.relay_polling_count_max
+ )
+ return;
+ nostr_relays_poll_documents_count.set(
+ $nostr_relays_poll_documents_count + 1,
+ );
+ const nostr_relays = await lc.db.nostr_relay_get({
+ list: ["on_key", { public_key: $app_nostr_key }],
+ });
+ if (typeof nostr_relays === `string`) throw new Error();
+
+ const unconnected_relays = nostr_relays.filter(
+ (i) => !$nostr_relays_connected.includes(i.id),
+ );
+ if (unconnected_relays.length === 0) {
+ nostr_relays_poll_documents.set(false);
+ return;
+ }
+
+ for (const nostr_relay of unconnected_relays) {
+ const res = await lc.http.fetch({
+ url: nostr_relay.url.replace(`ws://`, `http://`),
+ headers: {
+ Accept: "application/nostr+json",
+ },
+ });
+ if (typeof res === `string`) continue;
+ else if (res.status === 200 && res.data) {
+ const doc = parse_nostr_relay_information_document_fields(
+ res.data,
+ );
+ if (!doc) continue;
+ const fields: Partial<NostrRelayFormFields> = {};
+ for (const [k, v] of Object.entries(doc)) {
+ const field_k = parse_nostr_relay_form_keys(k);
+ if (field_k) fields[field_k] = v;
+ }
+ if (Object.keys(fields).length < 1) continue;
+ await lc.db.nostr_relay_update({
+ on: {
+ url: nostr_relay.url,
+ },
+ fields,
+ });
+ nostr_relays_connected.set(
+ Array.from(
+ new Set([
+ ...$nostr_relays_connected,
+ nostr_relay.id,
+ ]),
+ ),
+ );
+ }
+ }
+
+ setTimeout(
+ fetch_relay_documents,
+ _conf.delay.nostr_relay_poll_document,
+ );
+ } catch (e) {
+ console.log(`(error) fetch_relay_documents `, e);
+ }
+ };
</script>
<LayoutWindow>
diff --git a/src/routes/(app)/map/+page.svelte b/src/routes/(app)/map/+page.svelte
@@ -0,0 +1,94 @@
+<script lang="ts">
+ import { lc } from "$lib/client";
+ import MapControlFull from "$lib/components/map_control_full.svelte";
+ import { _conf } from "$lib/conf";
+ import { app_thc } from "$lib/stores";
+ import { Fill, LoadingView, route, sleep } from "@radroots/svelte-lib";
+ import { MapLibre, Marker, Popup } from "@radroots/svelte-maplibre";
+ import { type NumberTuple } from "@radroots/utils";
+ import { onMount } from "svelte";
+
+ let loading_layout = true;
+ let map_coords: NumberTuple | undefined = undefined;
+
+ onMount(async () => {
+ try {
+ const loc = await lc.geo.current();
+ if (loc && typeof loc !== `string`) {
+ map_coords = [loc.lng, loc.lat];
+ }
+ await sleep(_conf.delay.load);
+ } catch (e) {
+ console.log(`e `, e);
+ } finally {
+ loading_layout = false;
+ }
+ });
+</script>
+
+{#if map_coords}
+ <MapLibre
+ center={map_coords}
+ zoom={10}
+ class={`map-full ${loading_layout ? `hidden` : ``}`}
+ style={_conf.map.styles.base[$app_thc]}
+ >
+ <Marker lngLat={map_coords}>
+ <div class="flex flex-row p-1">
+ <div
+ class={`flex flex-row h-map_circle w-map_circle justify-center items-center bg-white rounded-full shadow-lg`}
+ >
+ <div
+ class={`flex flex-row h-map_circle_inner w-map_circle_inner justify-center items-center bg-blue-400 rounded-full`}
+ >
+ <Fill />
+ </div>
+ </div>
+ </div>
+ <Popup offset={_conf.map.popup.dot.offset}>
+ <button
+ class={`flex flex-row justify-center items-center transition-all`}
+ on:click={async () => {}}
+ >
+ <div
+ class={`flex flex-col w-fit px-2 py-1 gap-2 justify-start items-start`}
+ >
+ <div class={`flex flex-row w-full justify-start items-center`}>
+ <p class={`font-mono font-[400] text-layer-2-glyph`}>
+ {`Marker location:`}
+ </p>
+ </div>
+ <div
+ class={`flex flex-row w-full gap-2 justify-start items-center`}
+ >
+ <p class={`font-mono font-[400] text-layer-2-glyph`}>
+ {map_coords[0]}
+ </p>
+ <p class={`font-mono font-[400] text-layer-2-glyph`}>
+ {map_coords[1]}
+ </p>
+ </div>
+ </div>
+ </button>
+ </Popup>
+ </Marker>
+ </MapLibre>
+{/if}
+{#if loading_layout}
+ <LoadingView />
+{:else}
+ <MapControlFull
+ basis={{
+ callback: async () => {
+ await route(`/`);
+ },
+ }}
+ />
+{/if}
+
+<style>
+ :global(.map-full) {
+ height: 100vh;
+ width: 100vh;
+ }
+</style>
diff --git a/src/routes/(app)/map/choose-location/+page.svelte b/src/routes/(app)/map/choose-location/+page.svelte
@@ -0,0 +1,121 @@
+<script lang="ts">
+ import { lc } from "$lib/client";
+ import MapControlFull from "$lib/components/map_control_full.svelte";
+ import { _conf } from "$lib/conf";
+ import { app_thc } from "$lib/stores";
+ import {
+ Fill,
+ Glyph,
+ LoadingView,
+ route,
+ sleep,
+ } from "@radroots/svelte-lib";
+ import { MapLibre, Marker } from "@radroots/svelte-maplibre";
+ import {
+ location_geohash,
+ type GeolocationCoordinates,
+ } from "@radroots/utils";
+ import { onMount } from "svelte";
+
+ let loading_layout = true;
+ let map_coords: GeolocationCoordinates | undefined = undefined;
+
+ onMount(async () => {
+ try {
+ const loc = await lc.geo.current();
+ if (loc && typeof loc !== `string`) {
+ map_coords = loc;
+ } else {
+ map_coords = {
+ lat: 0,
+ lng: 0,
+ };
+ }
+ await sleep(_conf.delay.load);
+ } catch (e) {
+ console.log(`e `, e);
+ } finally {
+ loading_layout = false;
+ }
+ });
+
+ $: {
+ console.log(`map_coords `, map_coords);
+ }
+</script>
+
+{#if map_coords}
+ <MapLibre
+ center={map_coords}
+ zoom={10}
+ class={`map-full ${loading_layout ? `hidden` : ``}`}
+ style={_conf.map.styles.base[$app_thc]}
+ >
+ <Marker bind:lngLat={map_coords} draggable>
+ <div class="relative flex flex-col w-4 items-center justify-center">
+ <div
+ class={`absolute top-[3px] left-[3px] flex flex-row h-[10px] w-[10px] bg-red-100/30 rounded-full justify-start items-center`}
+ >
+ <Fill />
+ </div>
+ <Glyph
+ basis={{
+ classes: `text-red-700`,
+ key: `map-pin-simple`,
+ weight: `fill`,
+ dim: `xl`,
+ }}
+ />
+ </div>
+ </Marker>
+ </MapLibre>
+{/if}
+{#if loading_layout}
+ <LoadingView />
+{:else}
+ <MapControlFull
+ basis={{
+ callback: async () => {
+ if (!map_coords) return; //@todo
+
+ const location_gcs_label = await lc.dialog.prompt({
+ title: `Geolocation Label`,
+ message: `What is the name of the location.`,
+ input_placeholder: `Enter location name`,
+ });
+ if (location_gcs_label === false) return;
+ else if (!location_gcs_label) {
+ await lc.dialog.alert(`A location name is required.`);
+ return;
+ }
+
+ const { lat, lng } = map_coords;
+ const new_location_gcs = await lc.db.location_gcs_add({
+ label: location_gcs_label,
+ geohash: location_geohash(lat, lng),
+ lat: lat.toString(),
+ lng: lng.toString(),
+ });
+
+ if (typeof new_location_gcs === `string`) {
+ //@todo
+ return;
+ } else if (Array.isArray(new_location_gcs)) {
+ //@todo
+ return;
+ }
+
+ await route(`/models/trade-product/add`, [
+ [`id`, new_location_gcs.id],
+ ]);
+ },
+ }}
+ />
+{/if}
+
+<style>
+ :global(.map-full) {
+ height: 100vh;
+ width: 100vh;
+ }
+</style>
diff --git a/src/routes/(app)/models/trade-product/add/+page.svelte b/src/routes/(app)/models/trade-product/add/+page.svelte
@@ -1,6 +1,7 @@
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<script lang="ts">
+ import { goto } from "$app/navigation";
import { lc } from "$lib/client";
import { location_gcs_add } from "$lib/utils/location_gcs";
import {
@@ -306,6 +307,10 @@
value: `add-new`,
label: `${$t(`common.add_current_location`)}`,
},
+ {
+ value: `add-map`,
+ label: `${$t(`common.add_map_location`)}`,
+ },
]
: [
{
@@ -318,11 +323,19 @@
value: `add-new`,
label: `${$t(`common.add_current_location`)}`,
},
+ {
+ value: `add-map`,
+ label: `${$t(`common.add_map_location`)}`,
+ },
],
callback: async (val) => {
if (val === `add-new`) {
sel_location_gcs_id = ``;
await add_model_location_gcs();
+ } else if (val === `add-map`) {
+ sel_location_gcs_id = ``;
+ console.log(`add map location`);
+ await goto(`/map/choose-location`);
}
},
}}
diff --git a/src/routes/(map)/map/+page.svelte b/src/routes/(map)/map/+page.svelte
@@ -1,88 +0,0 @@
-<script lang="ts">
- import { lc } from "$lib/client";
- import MapControlFull from "$lib/components/map_control_full.svelte";
- import { _conf } from "$lib/conf";
- import { app_thc } from "$lib/stores";
- import { Fill, LoadingView, sleep } from "@radroots/svelte-lib";
- import { MapLibre, Marker, Popup } from "@radroots/svelte-maplibre";
- import { type NumberTuple } from "@radroots/utils";
- import { onMount } from "svelte";
-
- let loading_layout = true;
- let map_coords: NumberTuple | undefined = undefined;
-
- onMount(async () => {
- try {
- const loc = await lc.geo.current();
- if (loc && typeof loc !== `string`) {
- map_coords = [loc.lng, loc.lat];
- }
- await sleep(_conf.delay.load);
- } catch (e) {
- console.log(`e `, e);
- } finally {
- loading_layout = false;
- }
- });
-</script>
-
-{#if map_coords}
- <MapLibre
- center={map_coords}
- zoom={10}
- class={`map-full ${loading_layout ? `hidden` : ``}`}
- style={_conf.map.styles.base[$app_thc]}
- >
- <Marker lngLat={map_coords}>
- <div class="flex flex-row p-1">
- <div
- class={`flex flex-row h-map_circle w-map_circle justify-center items-center bg-white rounded-full shadow-lg`}
- >
- <div
- class={`flex flex-row h-map_circle_inner w-map_circle_inner justify-center items-center bg-blue-400 rounded-full`}
- >
- <Fill />
- </div>
- </div>
- </div>
- <Popup offset={_conf.map.popup.dot.offset}>
- <button
- class={`flex flex-row justify-center items-center transition-all`}
- on:click={async () => {}}
- >
- <div
- class={`flex flex-col w-fit px-2 py-1 gap-2 justify-start items-start`}
- >
- <div class={`flex flex-row w-full justify-start items-center`}>
- <p class={`font-mono font-[400] text-layer-2-glyph`}>
- {`Marker location:`}
- </p>
- </div>
- <div
- class={`flex flex-row w-full gap-2 justify-start items-center`}
- >
- <p class={`font-mono font-[400] text-layer-2-glyph`}>
- {map_coords[0]}
- </p>
- <p class={`font-mono font-[400] text-layer-2-glyph`}>
- {map_coords[1]}
- </p>
- </div>
- </div>
- </button>
- </Popup>
- </Marker>
- </MapLibre>
-{/if}
-{#if loading_layout}
- <LoadingView />
-{:else}
- <MapControlFull />
-{/if}
-
-<style>
- :global(.map-full) {
- height: 100vh;
- width: 100vh;
- }
-</style>
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
@@ -10,28 +10,17 @@
app_thc,
} from "$lib/stores";
import {
- type NostrRelayFormFields,
- parse_nostr_relay_form_keys,
- } from "@radroots/models";
- import {
app_config,
app_notify,
app_render,
AppConfig,
CssStatic,
CssStyles,
- ndk,
- ndk_init,
- ndk_user,
- nostr_relays_connected,
- nostr_relays_poll_documents,
- nostr_relays_poll_documents_count,
route,
sleep,
theme_set,
} from "@radroots/svelte-lib";
import { parse_color_mode, parse_theme_key } from "@radroots/theme";
- import { parse_nostr_relay_information_document_fields } from "@radroots/utils";
import "../app.css";
let render_pwa = browser && lc.platform === `web`;
@@ -119,50 +108,6 @@
}
});
- app_nostr_key.subscribe(async (_app_nostr_key) => {
- try {
- if (!_app_nostr_key) return;
-
- const secret_key = await lc.keystore.get(
- _conf.kv.nostr_key(_app_nostr_key),
- );
- if (!secret_key) {
- alert(`!secret_key`); //@todo
- return;
- }
-
- const nostr_relays = await lc.db.nostr_relay_get({
- list: ["all"],
- });
- if (typeof nostr_relays === `string`) {
- alert(nostr_relays); //@todo
- return;
- }
-
- for (const { url } of nostr_relays) $ndk.addExplicitRelay(url);
-
- await $ndk.connect().then(() => {
- console.log(`(ndk) connected`);
- });
-
- const ndk_user = await ndk_init({
- $ndk,
- secret_key,
- });
- if (!ndk_user) {
- alert(`!ndk_user`); //@todo
- return;
- }
-
- $ndk_user = ndk_user;
- $ndk_user.ndk = $ndk;
- console.log(`(ndk) initialized`);
- nostr_relays_poll_documents.set(true);
- } catch (e) {
- console.log(`(app_nostr_key) error `, e);
- }
- });
-
app_notify.subscribe(async (_app_notify) => {
if (!_app_notify) return;
route(`/`);
@@ -170,85 +115,6 @@
lc.dialog.alert(_app_notify);
app_notify.set(``);
});
-
- nostr_relays_poll_documents.subscribe(
- async (_nostr_relays_poll_documents) => {
- try {
- if (!_nostr_relays_poll_documents) return;
- await fetch_relay_documents();
- } catch (e) {
- console.log(`(error) nostr_relays_poll_documents`, e);
- }
- },
- );
-
- const fetch_relay_documents = async (): Promise<void> => {
- try {
- if (
- $nostr_relays_poll_documents_count >=
- _conf.nostr.relay_polling_count_max
- )
- return;
- nostr_relays_poll_documents_count.set(
- $nostr_relays_poll_documents_count + 1,
- );
- const nostr_relays = await lc.db.nostr_relay_get({
- list: ["on_key", { public_key: $app_nostr_key }],
- });
- if (typeof nostr_relays === `string`) throw new Error();
-
- const unconnected_relays = nostr_relays.filter(
- (i) => !$nostr_relays_connected.includes(i.id),
- );
- if (unconnected_relays.length === 0) {
- nostr_relays_poll_documents.set(false);
- return;
- }
-
- for (const nostr_relay of unconnected_relays) {
- const res = await lc.http.fetch({
- url: nostr_relay.url.replace(`ws://`, `http://`),
- headers: {
- Accept: "application/nostr+json",
- },
- });
- if (typeof res === `string`) continue;
- else if (res.status === 200 && res.data) {
- const doc = parse_nostr_relay_information_document_fields(
- res.data,
- );
- if (!doc) continue;
- const fields: Partial<NostrRelayFormFields> = {};
- for (const [k, v] of Object.entries(doc)) {
- const field_k = parse_nostr_relay_form_keys(k);
- if (field_k) fields[field_k] = v;
- }
- if (Object.keys(fields).length < 1) continue;
- await lc.db.nostr_relay_update({
- on: {
- url: nostr_relay.url,
- },
- fields,
- });
- nostr_relays_connected.set(
- Array.from(
- new Set([
- ...$nostr_relays_connected,
- nostr_relay.id,
- ]),
- ),
- );
- }
- }
-
- setTimeout(
- fetch_relay_documents,
- _conf.delay.nostr_relay_poll_document,
- );
- } catch (e) {
- console.log(`(error) fetch_relay_documents `, e);
- }
- };
</script>
<svelte:head>