commit 41303dbc615f3644d7e405c502be808bdcc8c688
parent 822f98db3858800f0b9e6b43c2fb07bf54bbabc0
Author: triesap <triesap@radroots.dev>
Date: Fri, 21 Nov 2025 02:33:56 +0000
Update `/profile` with new view component integrated from `@radroots/apps-lib-pwa`, upgrade configuration bootstrap to use persisted active key, standardize error guards and farms view typing.
Diffstat:
8 files changed, 181 insertions(+), 12 deletions(-)
diff --git a/app/src/lib/utils/app/handlers.ts b/app/src/lib/utils/app/handlers.ts
@@ -18,13 +18,13 @@ export const lc_gui_confirm: LocalCallbackGuiConfirm = async (opts) => {
export const lc_geocode: LocalCallbackGeocode = async (geoc_p) => {
await geoc.connect();
const geoc_res = await geoc.reverse(geoc_p);
- if (`err` in geoc_res) throw_err(geoc_res);
+ if ("err" in geoc_res) throw_err(geoc_res);
return geoc_res.results[0] || undefined;
};
export const lc_geop_current: LocalCallbackGeocodeCurrent = async () => {
const resolve = await geol.current();
- if (`err` in resolve) throw_err(resolve);
+ if ("err" in resolve) throw_err(resolve);
return resolve;
};
@@ -55,7 +55,7 @@ export const lc_photos_upload: LocalCallbackPhotosUpload = async ({ url, path })
},
data_bin,
});
- if (`err` in res) throw_err(res);
+ if ("err" in res) throw_err(res);
else if (res.data && res.data.res_base && res.data.res_path && res.data.file_ext) {
return {
base_url: res.data.res_base,
diff --git a/app/src/lib/utils/app/routes.ts b/app/src/lib/utils/app/routes.ts
@@ -4,6 +4,8 @@ export type NavigationRoute =
| "/farms/add"
| "/farms/info"
| "/import"
+ | "/profile"
+ | "/profile/edit"
| "/setup"
export function parse_route(route: string): NavigationRoute {
@@ -13,6 +15,8 @@ export function parse_route(route: string): NavigationRoute {
case "/farms/add":
case "/farms/info":
case "/import":
+ case "/profile":
+ case "/profile/edit":
case "/setup":
return route;
default:
diff --git a/app/src/routes/(app)/farms/+page.svelte b/app/src/routes/(app)/farms/+page.svelte
@@ -5,7 +5,7 @@
import type {
FarmExtended,
IViewFarmsData,
- } from "@radroots/apps-lib-pwa/types/views/farm";
+ } from "@radroots/apps-lib-pwa/types/views/farms";
import { onMount } from "svelte";
type LoadData = IViewFarmsData | undefined;
diff --git a/app/src/routes/(app)/farms/add/+page.svelte b/app/src/routes/(app)/farms/add/+page.svelte
@@ -50,7 +50,7 @@
JSON.stringify(farm_location_set, null, 4),
`farm_location_set`,
);
- if (`err` in farm_location_set) throw_err(farm_location_set);
+ if ("err" in farm_location_set) throw_err(farm_location_set);
await route(`/farms`);
} catch (e) {
handle_err(e, `on_submit`);
diff --git a/app/src/routes/(app)/profile/+page.svelte b/app/src/routes/(app)/profile/+page.svelte
@@ -0,0 +1,156 @@
+<script lang="ts">
+ import { db, fs, nostr_keys, notif, radroots, route } from "$lib/utils/app";
+ import { ls } from "$lib/utils/i18n";
+ import { ndk_user, parse_file_path } from "@radroots/apps-lib";
+ import { Profile } from "@radroots/apps-lib-pwa";
+ import type { IViewProfileData } from "@radroots/apps-lib-pwa/types/views/profile";
+ import { handle_err, throw_err, type FilePath } from "@radroots/utils";
+ import { onMount } from "svelte";
+
+ let data: IViewProfileData | undefined = $state(undefined);
+ let loading_photo_upload = $state(false);
+ let loading_photo_upload_open = $state(false);
+ let photo_path = $state(``);
+
+ onMount(async () => {
+ try {
+ data = await load_data();
+ } catch (e) {
+ handle_err(e, `on_mount`);
+ await route(`/`);
+ }
+ });
+
+ const load_data = async (): Promise<IViewProfileData | undefined> => {
+ const nostr_profile = await db.nostr_profile_find_one({
+ on: {
+ public_key: $ndk_user?.pubkey,
+ },
+ });
+ if ("err" in nostr_profile) throw_err(nostr_profile);
+
+ //await nostr_sync.metadata({ metadata: tb_nostr_profile.result }); // no await
+ return { profile: nostr_profile.result };
+ };
+</script>
+
+<Profile
+ bind:photo_path
+ basis={{
+ data,
+ loading_photo_upload,
+ loading_photo_upload_open,
+ on_destroy: async () => {
+ try {
+ const tb_nostrprofile = await db.nostr_profile_find_one({
+ on: {
+ public_key: $ndk_user?.pubkey,
+ },
+ });
+ if ("err" in tb_nostrprofile) throw_err(tb_nostrprofile); //@todo
+ /*await nostr_sync.metadata({
+ metadata: tb_nostrprofile.result,
+ }); // no await */
+ } catch (e) {
+ handle_err(e, `on_destroy`);
+ }
+ },
+ on_handle_back: async ({ is_photo_existing }) => {
+ try {
+ if (!photo_path || !$ndk_user?.pubkey)
+ return void (await route(`/`));
+ const nostr_key = await nostr_keys.read($ndk_user.pubkey);
+ if ("err" in nostr_key) throw_err(nostr_key);
+ if (photo_path) {
+ const confirm = await notif.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 profile_photo_curr = await db.media_image_find_one({
+ on: {
+ file_path: photo_path,
+ },
+ });
+ if ("result" in profile_photo_curr)
+ upload_file_path = parse_file_path(
+ profile_photo_curr.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);
+ if ("err" in file_data) throw_err(file_data);
+ const res_fetch_media_image_upload =
+ await radroots.media_image_upload({
+ file_path: upload_file_path,
+ file_data,
+ secret_key: nostr_key.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,
+ });
+ if ("err" in tb_media_image_create)
+ throw_err(tb_media_image_create);
+ const tb_nostr_profile_update = await db.nostr_profile_update({
+ on: { public_key: $ndk_user.pubkey },
+ 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) {
+ handle_err(e, `on_handle_back`);
+ } finally {
+ loading_photo_upload = false;
+ }
+ },
+ on_handle_edit_profile_field: async ({ field }) => {
+ try {
+ if (field === `name`) {
+ const confirm = await notif.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) {
+ handle_err(e, `on_handle_edit_profile_field`);
+ }
+ },
+ on_handle_photo_options: async () => {
+ try {
+ } catch (e) {
+ handle_err(e, `on_handle_photo_options`);
+ }
+ },
+ }}
+/>
diff --git a/app/src/routes/(app)/profile/edit/+page.svelte b/app/src/routes/(app)/profile/edit/+page.svelte
@@ -0,0 +1,8 @@
+<script lang="ts">
+</script>
+
+<div class={`flex flex-col w-full justify-start items-start`}>
+ <p class={`font-sans font-[400] text-base text-ly0-gl`}>
+ {`profile edit`}
+ </p>
+</div>
diff --git a/app/src/routes/(cfg)/+layout.ts b/app/src/routes/(cfg)/+layout.ts
@@ -1,16 +1,17 @@
import { datastore, nostr_keys, route } from '$lib/utils/app';
+import type { AppData } from '$lib/utils/config';
import { handle_err } from '@radroots/apps-lib';
import type { LayoutLoad, LayoutLoadEvent } from './$types';
export const load: LayoutLoad = async (_: LayoutLoadEvent) => {
try {
await datastore.init();
- const ds_key_nostr = await datastore.get("nostr_key");
- if (`result` in ds_key_nostr) {
- const nostrkey = await nostr_keys.read(ds_key_nostr.result);
- if (`result` in nostrkey) return void await route(`/`);
- await datastore.del("nostr_key");
+ const app_data = await datastore.get_obj<AppData>("app_data");
+ if ("result" in app_data) {
+ const nostr_key = await nostr_keys.read(app_data.result.active_key);
+ if ("result" in nostr_key) return void await route(`/`);
+ // @todo
}
} catch (e) {
handle_err(e, `(cfg)load`)
diff --git a/app/src/routes/(cfg)/setup/+page.svelte b/app/src/routes/(cfg)/setup/+page.svelte
@@ -197,7 +197,7 @@
const create_nostr_key = async (): Promise<void> => {
const keys_nostr_gen = await nostr_keys.generate();
- if (`err` in keys_nostr_gen) return handle_config_err();
+ if ("err" in keys_nostr_gen) return handle_config_err();
await datastore.update_obj<ConfigData>("cfg_data", {
nostr_public_key: keys_nostr_gen.public_key,
});
@@ -286,7 +286,7 @@
tok: accounts_req.result,
secret_key: ks_nostr_key.secret_key,
});
- if (`err` in accounts_create)
+ if ("err" in accounts_create)
return void (await notif.alert(
`${$ls(accounts_create.err, {
default: `${$ls(