app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit 6abbc995f801e7a25c881dd4b763e7c72a69c145
parent b66d4f09b693f461d3668921ee14be97b408a812
Author: triesap <137732411+triesap@users.noreply.github.com>
Date:   Sun, 27 Apr 2025 04:55:15 +0000

Add `/farms`, add callback utils, add/edit routes, utils.

Diffstat:
Aapp/src/lib/util/callback.ts | 17+++++++++++++++++
Dapp/src/lib/util/conf.ts | 26--------------------------
Dapp/src/lib/util/err.ts | 6------
Aapp/src/lib/util/lib.ts | 32++++++++++++++++++++++++++++++++
Mapp/src/lib/util/routes.ts | 2++
Mapp/src/routes/(app)/+page.svelte | 44++++++++++++++++++++++----------------------
Aapp/src/routes/(app)/farms/+page.svelte | 29+++++++++++++++++++++++++++++
Mapp/src/routes/(app)/profile/+page.svelte | 259++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mapp/src/routes/(app)/profile/edit/+page.svelte | 96+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mapp/src/routes/(cfg)/init/+page.svelte | 2+-
10 files changed, 275 insertions(+), 238 deletions(-)

diff --git a/app/src/lib/util/callback.ts b/app/src/lib/util/callback.ts @@ -0,0 +1,17 @@ +import { handle_err } from "@radroots/lib-app"; +import type { GeocoderReverseResult, GeolocationPoint } from "@radroots/util"; +import { geoc } from "."; + +export const lc_geocode = async (geoc_p: GeolocationPoint): Promise<GeocoderReverseResult | undefined> => { + try { + await geoc.connect(); + const geoc_res = await geoc.reverse(geoc_p); + if ( + `results` in geoc_res && + geoc_res.results.length > 0 + ) + return geoc_res.results[0]; + } catch (e) { + await handle_err(e, `lc_geocode`); + } +}; diff --git a/app/src/lib/util/conf.ts b/app/src/lib/util/conf.ts @@ -1,26 +0,0 @@ -import { PUBLIC_RADROOTS_RELAY_URL } from "$env/static/public"; -import type { NostrEventTagClient } from "@radroots/nostr-util"; -import { root_symbol } from "@radroots/util"; - -export const radroots_nostr_pubkey = `1f5a37bd7050cffe4dd9c35e029fa1da5c84f429de0818c9e22ecf122815e184` - -export const cfg_delay = { - load: 321, - notify: 123, - mount_el: 500, - nostr_relay_poll_document: 3000, - entry_focus: 2000, - load_notify: 3000, -}; - -export const cfg_nostr = { - relay_url: PUBLIC_RADROOTS_RELAY_URL, - relay_pubkey: radroots_nostr_pubkey, - relay_polling_count_max: 10, -}; - -export const cfg_nostr_client: NostrEventTagClient = { - name: root_symbol, - pubkey: cfg_nostr.relay_pubkey, - relay: cfg_nostr.relay_url -}; diff --git a/app/src/lib/util/err.ts b/app/src/lib/util/err.ts @@ -1,5 +0,0 @@ -export const err = { - nostr: { - no_relays: `error.nostr.no_relays_connected` - } -} -\ No newline at end of file diff --git a/app/src/lib/util/lib.ts b/app/src/lib/util/lib.ts @@ -0,0 +1,32 @@ +import { PUBLIC_RADROOTS_RELAY_URL } from "$env/static/public"; +import type { NostrEventTagClient } from "@radroots/nostr-util"; +import { root_symbol } from "@radroots/util"; + +export const radroots_nostr_pubkey = `1f5a37bd7050cffe4dd9c35e029fa1da5c84f429de0818c9e22ecf122815e184` + +export const err = { + nostr: { + no_relays: `error.nostr.no_relays_connected` + } +}; + +export const cfg_delay = { + load: 321, + notify: 123, + mount_el: 500, + nostr_relay_poll_document: 3000, + entry_focus: 2000, + load_notify: 3000, +}; + +export const cfg_nostr = { + relay_url: PUBLIC_RADROOTS_RELAY_URL, + relay_pubkey: radroots_nostr_pubkey, + relay_polling_count_max: 10, +}; + +export const cfg_nostr_client: NostrEventTagClient = { + name: root_symbol, + pubkey: cfg_nostr.relay_pubkey, + relay: cfg_nostr.relay_url +}; diff --git a/app/src/lib/util/routes.ts b/app/src/lib/util/routes.ts @@ -1,5 +1,6 @@ export type NavigationRoute = | "/" + | "/farm" | "/profile" | "/profile/edit" | "/init"; @@ -7,6 +8,7 @@ export type NavigationRoute = export function parse_route(route: string): NavigationRoute { switch (route) { case "/": + case "/farm": case "/profile": case "/profile/edit": case "/init": diff --git a/app/src/routes/(app)/+page.svelte b/app/src/routes/(app)/+page.svelte @@ -1,27 +1,27 @@ <script lang="ts"> import { ls } from "$lib/locale/i18n"; - import { handle_err, Home, type IHomeViewData } from "@radroots/lib-app"; + import { route } from "$lib/util"; + import { handle_err, Home, type IViewHomeData } from "@radroots/lib-app"; - let data: IHomeViewData | undefined = $state({}); + let data: IViewHomeData | undefined = $state({}); </script> -{#if data} - <Home - {ls} - basis={{ - data, - lc_handle_farms: async () => { - try { - } catch (e) { - await handle_err(e, `lc_handle_farms`); - } - }, - lc_handle_products: async () => { - try { - } catch (e) { - await handle_err(e, `lc_handle_products`); - } - }, - }} - /> -{/if} +<Home + {ls} + basis={{ + data, + lc_handle_farms: async () => { + try { + await route(`/farm`); + } catch (e) { + await handle_err(e, `lc_handle_farms`); + } + }, + lc_handle_products: async () => { + try { + } catch (e) { + await handle_err(e, `lc_handle_products`); + } + }, + }} +/> diff --git a/app/src/routes/(app)/farms/+page.svelte b/app/src/routes/(app)/farms/+page.svelte @@ -0,0 +1,29 @@ +<script lang="ts"> + import { locale, ls } from "$lib/locale/i18n"; + import { lc_geocode } from "$lib/util/callback"; + import { Farms, handle_err, type IViewFarmsData } from "@radroots/lib-app"; + + let data: IViewFarmsData | undefined = $state(undefined); +</script> + +<Farms + {ls} + {locale} + basis={{ + data, + callback_route: { route: `/` }, + lc_geocode, + lc_handle_farm_add: async () => { + try { + } catch (e) { + await handle_err(e, `lc_handle_farm_add`); + } + }, + lc_handle_farm_view: async (farm_id) => { + try { + } catch (e) { + await handle_err(e, `lc_handle_farm_view`); + } + }, + }} +/> diff --git a/app/src/routes/(app)/profile/+page.svelte b/app/src/routes/(app)/profile/+page.svelte @@ -39,142 +39,133 @@ }); </script> -{#if data} - <Profile - bind:photo_path - {ls} - basis={{ - data, - loading_photo_upload, - loading_photo_upload_open, - lc_on_destroy: async () => { - try { - const tb_nostrprofile = await db.nostr_profile_read({ - public_key: $ndk_user?.pubkey, +<Profile + bind:photo_path + {ls} + basis={{ + data, + loading_photo_upload, + loading_photo_upload_open, + lc_on_destroy: async () => { + try { + const tb_nostrprofile = await db.nostr_profile_read({ + public_key: $ndk_user?.pubkey, + }); + if (`err` in tb_nostrprofile) throw_err(tb_nostrprofile); //@todo + await nostr_sync.metadata({ + metadata: tb_nostrprofile.result, + }); // leave off await + } catch (e) { + await handle_err(e, `lc_on_destroy`); + } + }, + lc_handle_back: async ({ is_photo_existing }) => { + try { + const public_key = $ndk_user?.pubkey; + if (!photo_path || !public_key) return void (await route(`/`)); + const keys_nostr_read = await keys.nostr_read(public_key); + if (`err` in keys_nostr_read) throw_err(keys_nostr_read); + if (photo_path) { + const confirm = await gui.confirm({ + message: is_photo_existing + ? `${$ls(`notification.profile.handle_back_with_selected_photo`)}` + : `${$ls(`notification.profile.handle_back_with_selected_photo_no_existing`)}`, + ok: `${$ls(`common.upload_photo`)}`, + cancel: is_photo_existing + ? `${$ls(`common.keep_previous`)}` + : `${$ls(`common.continue`)}`, }); - if (`err` in tb_nostrprofile) throw_err(tb_nostrprofile); //@todo - await nostr_sync.metadata({ - metadata: tb_nostrprofile.result, - }); // leave off await - } catch (e) { - await handle_err(e, `lc_on_destroy`); + if (!confirm) return void (await route(`/`)); } - }, - lc_handle_back: async ({ is_photo_existing }) => { - try { - const public_key = $ndk_user?.pubkey; - if (!photo_path || !public_key) - return void (await route(`/`)); - const keys_nostr_read = await keys.nostr_read(public_key); - if (`err` in keys_nostr_read) throw_err(keys_nostr_read); - if (photo_path) { - const confirm = await gui.confirm({ - message: is_photo_existing - ? `${$ls(`notification.profile.handle_back_with_selected_photo`)}` - : `${$ls(`notification.profile.handle_back_with_selected_photo_no_existing`)}`, - ok: `${$ls(`common.upload_photo`)}`, - cancel: is_photo_existing - ? `${$ls(`common.keep_previous`)}` - : `${$ls(`common.continue`)}`, - }); - if (!confirm) return void (await route(`/`)); - } - loading_photo_upload = true; - let upload_file_path: FilePath | undefined = undefined; - parse_file_path(photo_path); - const tb_media_upload_existing = await db.media_image_read({ - file_path: photo_path, - }); - if (`result` in tb_media_upload_existing) - upload_file_path = parse_file_path( - tb_media_upload_existing.result.file_path, - ); - else upload_file_path = parse_file_path(photo_path); - if (!upload_file_path) - throw_err(`error.util.parse_file_path`); - const file_data = await fs.read_bin( - upload_file_path.file_path, + loading_photo_upload = true; + let upload_file_path: FilePath | undefined = undefined; + parse_file_path(photo_path); + const tb_media_upload_existing = await db.media_image_read({ + file_path: photo_path, + }); + if (`result` in tb_media_upload_existing) + upload_file_path = parse_file_path( + tb_media_upload_existing.result.file_path, ); - const res_fetch_media_image_upload = - await radroots.fetch_media_image_upload({ - file_path: upload_file_path, - file_data, - secret_key: keys_nostr_read.secret_key, - }); - if (`err` in res_fetch_media_image_upload) - throw_err(res_fetch_media_image_upload); - const { - res_base: upload_res_base, - res_path: upload_res_path, - } = res_fetch_media_image_upload; - const tb_media_image_create = await db.media_image_create({ - file_path: upload_file_path.file_path, - res_base: upload_res_base, - res_path: upload_res_path, - mime_type: upload_file_path.mime_type, + else upload_file_path = parse_file_path(photo_path); + if (!upload_file_path) throw_err(`error.util.parse_file_path`); + const file_data = await fs.read_bin(upload_file_path.file_path); + const res_fetch_media_image_upload = + await radroots.fetch_media_image_upload({ + file_path: upload_file_path, + file_data, + secret_key: keys_nostr_read.secret_key, }); - if (`err` in tb_media_image_create) - throw_err(tb_media_image_create); - const tb_nostr_profile_update = - await db.nostr_profile_update({ - filter: { public_key }, - fields: { - picture: `${upload_res_base}/${upload_res_path}.${upload_file_path.mime_type}`, - }, - }); - if (`err` in tb_nostr_profile_update) - throw_err(tb_nostr_profile_update); - await route(`/`); - } catch (e) { - await handle_err(e, `lc_handle_back`); - } finally { - loading_photo_upload = false; - } - }, - lc_handle_edit_profile_field: async ({ field }) => { - try { - if (field === `name`) { - const confirm = await gui.confirm({ - message: `${$ls(`notification.profile.update_name_confirmation`)}. ${$ls(`common.do_you_want_to_continue_q`)}`, - ok: `${$ls(`common.continue`)}`, - cancel: `${$ls(`common.cancel`)}`, - }); - if (!confirm) return; - } - await route(`/profile/edit`, [ - [`key_nostr`, $ndk_user?.pubkey], - [`field`, field], - ]); - } catch (e) { - await handle_err(e, `lc_handle_edit_profile_field`); - } - }, - lc_handle_photo_add: async () => { - try { - loading_photo_upload_open = true; - const photo_paths_open = await gui.open_photos(); - if (!photo_paths_open) return; - const photo_path_add = photo_paths_open.results[0]; - if (photo_path_add) return photo_path_add; - } catch (e) { - await handle_err(e, `lc_handle_photo_add`); - } finally { - loading_photo_upload_open = false; - } - }, - lc_handle_photo_options: async () => { - try { - } catch (e) { - await handle_err(e, `lc_handle_photo_options`); - } - }, - lc_fs_read_bin: async (file_path) => { - try { - return await fs.read_bin(file_path); - } catch (e) { - await handle_err(e, `lc_fs_read_bin`); + if (`err` in res_fetch_media_image_upload) + throw_err(res_fetch_media_image_upload); + const { res_base: upload_res_base, res_path: upload_res_path } = + res_fetch_media_image_upload; + const tb_media_image_create = await db.media_image_create({ + file_path: upload_file_path.file_path, + res_base: upload_res_base, + res_path: upload_res_path, + mime_type: upload_file_path.mime_type, + }); + if (`err` in tb_media_image_create) + throw_err(tb_media_image_create); + const tb_nostr_profile_update = await db.nostr_profile_update({ + filter: { public_key }, + fields: { + picture: `${upload_res_base}/${upload_res_path}.${upload_file_path.mime_type}`, + }, + }); + if (`err` in tb_nostr_profile_update) + throw_err(tb_nostr_profile_update); + await route(`/`); + } catch (e) { + await handle_err(e, `lc_handle_back`); + } finally { + loading_photo_upload = false; + } + }, + lc_handle_edit_profile_field: async ({ field }) => { + try { + if (field === `name`) { + const confirm = await gui.confirm({ + message: `${$ls(`notification.profile.update_name_confirmation`)}. ${$ls(`common.do_you_want_to_continue_q`)}`, + ok: `${$ls(`common.continue`)}`, + cancel: `${$ls(`common.cancel`)}`, + }); + if (!confirm) return; } - }, - }} - /> -{/if} + await route(`/profile/edit`, [ + [`key_nostr`, $ndk_user?.pubkey], + [`field`, field], + ]); + } catch (e) { + await handle_err(e, `lc_handle_edit_profile_field`); + } + }, + lc_handle_photo_add: async () => { + try { + loading_photo_upload_open = true; + const photo_paths_open = await gui.open_photos(); + if (!photo_paths_open) return; + const photo_path_add = photo_paths_open.results[0]; + if (photo_path_add) return photo_path_add; + } catch (e) { + await handle_err(e, `lc_handle_photo_add`); + } finally { + loading_photo_upload_open = false; + } + }, + lc_handle_photo_options: async () => { + try { + } catch (e) { + await handle_err(e, `lc_handle_photo_options`); + } + }, + lc_fs_read_bin: async (file_path) => { + try { + return await fs.read_bin(file_path); + } catch (e) { + await handle_err(e, `lc_fs_read_bin`); + } + }, + }} +/> diff --git a/app/src/routes/(app)/profile/edit/+page.svelte b/app/src/routes/(app)/profile/edit/+page.svelte @@ -46,59 +46,57 @@ return { public_key: tb_nostr_profile.result.public_key, field, - } satisfies IViewProfileEditData; + } satisfies LoadData; } catch (e) { await handle_err(e, `load`); } }; </script> -{#if data} - <ProfileEdit - bind:val_field - {ls} - basis={{ - data, - lc_handle_back: async ({ field, public_key }) => { - try { - if (val_field_init === val_field) - return void (await route(`/profile`)); - const confirm = await gui.confirm({ - message: `${$ls(`notify.profile.name_update`)}. ${$ls(`common.do_you_want_to_continue_q`)}`, - }); - if (!confirm) return; - const nostr_profile_update = await db.nostr_profile_update({ - filter: { - public_key, - }, - fields: { - [field]: val_field, - }, - }); - if (`err` in nostr_profile_update) - throw_err(nostr_profile_update); - const tb_nostr_profile = await db.nostr_profile_read({ +<ProfileEdit + bind:val_field + {ls} + basis={{ + data, + lc_handle_back: async ({ field, public_key }) => { + try { + if (val_field_init === val_field) + return void (await route(`/profile`)); + const confirm = await gui.confirm({ + message: `${$ls(`notify.profile.name_update`)}. ${$ls(`common.do_you_want_to_continue_q`)}`, + }); + if (!confirm) return; + const nostr_profile_update = await db.nostr_profile_update({ + filter: { public_key, - }); - console.log( - JSON.stringify(tb_nostr_profile, null, 4), - `tb_nostr_profile`, - ); - if (`err` in tb_nostr_profile) throw_err(tb_nostr_profile); - nostr_sync.metadata({ - metadata: tb_nostr_profile.result, - }); // leave off await - await route(`/profile`); - } catch (e) { - await handle_err(e, `lc_handle_back`); - } - }, - lc_handle_input: async () => { - try { - } catch (e) { - await handle_err(e, `lc_handle_input`); - } - }, - }} - /> -{/if} + }, + fields: { + [field]: val_field, + }, + }); + if (`err` in nostr_profile_update) + throw_err(nostr_profile_update); + const tb_nostr_profile = await db.nostr_profile_read({ + public_key, + }); + console.log( + JSON.stringify(tb_nostr_profile, null, 4), + `tb_nostr_profile`, + ); + if (`err` in tb_nostr_profile) throw_err(tb_nostr_profile); + nostr_sync.metadata({ + metadata: tb_nostr_profile.result, + }); // leave off await + await route(`/profile`); + } catch (e) { + await handle_err(e, `lc_handle_back`); + } + }, + lc_handle_input: async () => { + try { + } catch (e) { + await handle_err(e, `lc_handle_input`); + } + }, + }} +/> diff --git a/app/src/routes/(cfg)/init/+page.svelte b/app/src/routes/(cfg)/init/+page.svelte @@ -3,7 +3,7 @@ import { PUBLIC_NOSTR_RELAY_DEFAULTS } from "$env/static/public"; import { ls } from "$lib/locale/i18n"; import { datastore, db, gui, keys, radroots, route } from "$lib/util"; - import { cfg_delay } from "$lib/util/conf"; + import { cfg_delay } from "$lib/util/lib"; import { NDKPrivateKeySigner } from "@nostr-dev-kit/ndk"; import { app_lo,