app

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

commit 5d9a0e503af7b59455ad6ec572825f72caf1a804
parent 6cd646da1fa977cd989a38bdcafa2f45d9667476
Author: triesap <137732411+triesap@users.noreply.github.com>
Date:   Thu, 14 Nov 2024 19:28:44 +0000

Edit `core` crate add models get method queries, edit sort statements, add SQL alias, update  model table relations SQL, utils. Edit `tauri` crate update model table relation handlers. Edit `/models/` routes. Add logger init/unlisten to root layout. Edit component styles.

Diffstat:
MCargo.lock | 300++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mcrates/core/Cargo.toml | 5+++--
Mcrates/core/src/models/location_gcs.rs | 47++++++++++++++++++++++++-----------------------
Mcrates/core/src/models/nostr_profile.rs | 47++++++++++++++++++++++++-----------------------
Mcrates/core/src/models/nostr_profile_relay.rs | 38++++++++++++++++++++++++++++++--------
Mcrates/core/src/models/nostr_relay.rs | 47++++++++++++++++++++++++-----------------------
Mcrates/core/src/models/trade_product.rs | 43++++++++++++++++++++-----------------------
Mcrates/core/src/models/trade_product_location.rs | 26++++++++++++++++++++++++--
Mcrates/tauri/Cargo.toml | 1+
Mcrates/tauri/migrations/0005_nostr_profile_relay.sql | 10+++++-----
Mcrates/tauri/migrations/0006_trade_product_location.sql | 10+++++-----
Mcrates/tauri/src/lib.rs | 12+++++++++---
Mcrates/tauri/src/models/nostr_profile_relay.rs | 15++++++++++++++-
Mcrates/tauri/src/models/trade_product_location.rs | 15++++++++++++++-
Msrc/lib/components/image_upload_edit_envelope.svelte | 3+--
Msrc/routes/(app)/models/trade-product/+page.svelte | 151+++++++++++++++++++++++++------------------------------------------------------
Msrc/routes/(app)/models/trade-product/add/+page.svelte | 1731+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/routes/(cfg)/cfg/init/+page.svelte | 8--------
Msrc/routes/+layout.svelte | 11++++++++---
19 files changed, 1440 insertions(+), 1080 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -25,6 +25,17 @@ checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.15", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" @@ -72,6 +83,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" [[package]] +name = "android_log-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937" + +[[package]] +name = "android_logger" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b07e8e73d720a1f2e4b6014766e6039fd2e96a4fa44e2a78d0e1fa2ff49826" +dependencies = [ + "android_log-sys", + "env_filter", + "log", +] + +[[package]] name = "android_system_properties" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -136,6 +164,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] name = "ashpd" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -392,6 +426,18 @@ dependencies = [ ] [[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] name = "block" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -429,6 +475,30 @@ dependencies = [ ] [[package]] +name = "borsh" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d4d6dafc1a3bb54687538972158f07b2c948bc57d5890df22c0739098b3028" +dependencies = [ + "borsh-derive", + "cfg_aliases 0.1.1", +] + +[[package]] +name = "borsh-derive" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4918709cc4dd777ad2b6303ed03cb37f3ca0ccede8c1b0d28ac6db8f4710e0" +dependencies = [ + "once_cell", + "proc-macro-crate 2.0.2", + "proc-macro2", + "quote", + "syn 2.0.79", + "syn_derive", +] + +[[package]] name = "brotli" version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -456,6 +526,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] +name = "byte-unit" +version = "5.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cd29c3c585209b0cbc7309bfe3ed7efd8c84c21b7af29c8bfae908f8777174" +dependencies = [ + "rust_decimal", + "serde", + "utf8-width", +] + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] name = "bytemuck" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -587,6 +690,12 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "cfg_aliases" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" @@ -1243,6 +1352,15 @@ dependencies = [ ] [[package]] +name = "fern" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69ff9c9d5fb3e6da8ac2f77ab76fe7e8087d512ce095200f8f29ac5b656cf6dc" +dependencies = [ + "log", +] + +[[package]] name = "field-offset" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1325,6 +1443,12 @@ dependencies = [ ] [[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] name = "futf" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1775,6 +1899,9 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] [[package]] name = "hashbrown" @@ -1782,7 +1909,7 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash", + "ahash 0.8.11", "allocator-api2", ] @@ -2343,6 +2470,9 @@ name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +dependencies = [ + "value-bag", +] [[package]] name = "mac" @@ -2623,6 +2753,15 @@ dependencies = [ ] [[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] name = "objc" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3326,6 +3465,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" [[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] name = "publicsuffix" version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3420,6 +3579,12 @@ dependencies = [ ] [[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] name = "radroots" version = "0.0.1" dependencies = [ @@ -3436,6 +3601,7 @@ dependencies = [ "tauri-plugin-fs", "tauri-plugin-geolocation", "tauri-plugin-http", + "tauri-plugin-log", "tauri-plugin-map-display", "tauri-plugin-notification", "tauri-plugin-os", @@ -3449,6 +3615,7 @@ version = "0.0.1" dependencies = [ "chrono", "futures", + "log", "regex", "serde", "serde_json", @@ -3594,6 +3761,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] name = "reqwest" version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3681,6 +3857,35 @@ dependencies = [ ] [[package]] +name = "rkyv" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] name = "rsa" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3701,6 +3906,22 @@ dependencies = [ ] [[package]] +name = "rust_decimal" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand 0.8.5", + "rkyv", + "serde", + "serde_json", +] + +[[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3829,6 +4050,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] name = "security-framework" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4092,6 +4319,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] name = "siphasher" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4132,7 +4365,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" dependencies = [ "bytemuck", - "cfg_aliases", + "cfg_aliases 0.2.1", "core-graphics", "foreign-types", "js-sys", @@ -4514,6 +4747,18 @@ dependencies = [ ] [[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4616,6 +4861,12 @@ dependencies = [ ] [[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] name = "target-lexicon" version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4830,6 +5081,28 @@ dependencies = [ ] [[package]] +name = "tauri-plugin-log" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8aa13d15daf90230ba26d5a9b4a4612975fa64ce17290cb7f6e0f89bb6997d82" +dependencies = [ + "android_logger", + "byte-unit", + "cocoa", + "fern", + "log", + "objc", + "serde", + "serde_json", + "serde_repr", + "swift-rs", + "tauri", + "tauri-plugin", + "thiserror", + "time", +] + +[[package]] name = "tauri-plugin-map-display" version = "0.1.0" source = "git+https://github.com/inkibra/tauri-plugins?tag=@inkibra/tauri-plugin-map-display@0.2.0#31aa60a18d19f35828649e84c36597d18661b7e9" @@ -5074,7 +5347,9 @@ checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa 1.0.11", + "libc", "num-conv", + "num_threads", "powerfmt", "serde", "time-core", @@ -5440,6 +5715,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] +name = "utf8-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" + +[[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5456,6 +5737,12 @@ dependencies = [ ] [[package]] +name = "value-bag" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" + +[[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6245,6 +6532,15 @@ dependencies = [ ] [[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] name = "x11" version = "2.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml @@ -12,4 +12,5 @@ thiserror = "1.0.64" uuid = { version = "1", features = ["v4"] } chrono = "0.4" regex = "1.11.0" -futures = "0.3.31" -\ No newline at end of file +futures = "0.3.31" +log = "0.4" +\ No newline at end of file diff --git a/crates/core/src/models/location_gcs.rs b/crates/core/src/models/location_gcs.rs @@ -65,8 +65,16 @@ pub enum LocationGcsQueryBindValues { } #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "snake_case")] +pub enum LocationGcsQueryListOf { + All(IModelsQueryBindValue), + OnTradeProduct(IModelsQueryBindValue), + OffTradeProduct(IModelsQueryBindValue), +} + +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct ILocationGcsQueryGetList { - pub of: Vec<String>, + pub of: LocationGcsQueryListOf, pub sort: Option<LocationGcsSort>, } @@ -82,21 +90,6 @@ pub struct ILocationGcsQueryUpdate { pub fields: ILocationGcsFieldsUpdate, } -impl ILocationGcsQueryGet { - pub fn new_on(values: LocationGcsQueryBindValues) -> Self { - ILocationGcsQueryGet { - on: Some(values), - list: None, - } - } - pub fn new_list(list: ILocationGcsQueryGetList) -> Self { - ILocationGcsQueryGet { - on: None, - list: Some(list), - } - } -} - pub type ILocationGcsAdd = ILocationGcsFields; pub type ILocationGcsAddResolve = IModelsId; pub type ILocationGcsGet = ILocationGcsQueryGet; @@ -113,6 +106,19 @@ pub fn location_gcs_query_bind_values(opts: LocationGcsQueryBindValues) -> IMode } } +pub fn location_gcs_query_get_list(opts: ILocationGcsQueryGetList) -> IModelsQueryBindValueTuple { + let query_sort = match opts.sort { + Some(LocationGcsSort::Newest) => " ORDER BY lg.created_at DESC", + Some(LocationGcsSort::Oldest) => " ORDER BY lg.created_at ASC", + None => "", + }; + match opts.of { + LocationGcsQueryListOf::All(_) => (format!("SELECT lg.* FROM location_gcs lg{}", query_sort), "".to_string()), + LocationGcsQueryListOf::OnTradeProduct(id) => (format!("SELECT lg.* FROM location_gcs lg JOIN trade_product_location tp_lg ON lg.id = tp_lg.tb_lg WHERE tp_lg.tb_tp = ?1{}", query_sort), id), + LocationGcsQueryListOf::OffTradeProduct(id) => (format!("SELECT lg.* FROM location_gcs lg WHERE NOT EXISTS (SELECT 1 FROM trade_product_location tp_lg WHERE tp_lg.tb_lg = lg.id AND tp_lg.tb_tp = ?1){}", query_sort), id), + } +} + fn location_gcs_fields_bind_values( opts: ILocationGcsFields, ) -> Result<Vec<IModelsQueryBindValueTuple>, ModelError> { @@ -184,13 +190,8 @@ fn location_gcs_query_get( list: Some(opts_list), .. } => { - let sort = match opts_list.sort { - Some(LocationGcsSort::Newest) => "created_at DESC", - Some(LocationGcsSort::Oldest) => "created_at ASC", - None => "created_at DESC", - }; - let query = format!("SELECT * FROM location_gcs ORDER BY {};", sort); - Ok((query, vec![])) + let (query, bv) = location_gcs_query_get_list(opts_list); + Ok((query, vec![bv])) } ILocationGcsQueryGet { on: Some(opts_on), .. diff --git a/crates/core/src/models/nostr_profile.rs b/crates/core/src/models/nostr_profile.rs @@ -65,8 +65,16 @@ pub enum NostrProfileQueryBindValues { } #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "snake_case")] +pub enum NostrProfileQueryListOf { + All(IModelsQueryBindValue), + OnRelay(IModelsQueryBindValue), + OffRelay(IModelsQueryBindValue), +} + +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct INostrProfileQueryGetList { - pub of: Vec<String>, + pub of: NostrProfileQueryListOf, pub sort: Option<NostrProfileSort>, } @@ -82,21 +90,6 @@ pub struct INostrProfileQueryUpdate { pub fields: INostrProfileFieldsUpdate, } -impl INostrProfileQueryGet { - pub fn new_on(values: NostrProfileQueryBindValues) -> Self { - INostrProfileQueryGet { - on: Some(values), - list: None, - } - } - pub fn new_list(list: INostrProfileQueryGetList) -> Self { - INostrProfileQueryGet { - on: None, - list: Some(list), - } - } -} - pub type INostrProfileAdd = INostrProfileFields; pub type INostrProfileAddResolve = IModelsId; pub type INostrProfileGet = INostrProfileQueryGet; @@ -113,6 +106,19 @@ pub fn nostr_profile_query_bind_values(opts: NostrProfileQueryBindValues) -> IMo } } +pub fn nostr_profile_query_get_list(opts: INostrProfileQueryGetList) -> IModelsQueryBindValueTuple { + let query_sort = match opts.sort { + Some(NostrProfileSort::Newest) => " ORDER BY pr.created_at DESC", + Some(NostrProfileSort::Oldest) => " ORDER BY pr.created_at ASC", + None => "", + }; + match opts.of { + NostrProfileQueryListOf::All(_) => (format!("SELECT pr.* FROM nostr_profile pr{}", query_sort), "".to_string()), + NostrProfileQueryListOf::OnRelay(id) => (format!("SELECT pr.* FROM nostr_profile pr JOIN nostr_profile_relay pr_rl ON pr.id = pr_rl.tb_pr WHERE pr_rl.tb_rl = ?1{}", query_sort), id), + NostrProfileQueryListOf::OffRelay(id) => (format!("SELECT pr.* FROM nostr_profile pr WHERE NOT EXISTS (SELECT 1 FROM nostr_profile_relay pr_rl WHERE pr_rl.tb_pr = pr.id AND pr_rl.tb_rl = ?1){}", query_sort), id), + } +} + fn nostr_profile_fields_bind_values( opts: INostrProfileFields, ) -> Result<Vec<IModelsQueryBindValueTuple>, ModelError> { @@ -184,13 +190,8 @@ fn nostr_profile_query_get( list: Some(opts_list), .. } => { - let sort = match opts_list.sort { - Some(NostrProfileSort::Newest) => "created_at DESC", - Some(NostrProfileSort::Oldest) => "created_at ASC", - None => "created_at DESC", - }; - let query = format!("SELECT * FROM nostr_profile ORDER BY {};", sort); - Ok((query, vec![])) + let (query, bv) = nostr_profile_query_get_list(opts_list); + Ok((query, vec![bv])) } INostrProfileQueryGet { on: Some(opts_on), .. diff --git a/crates/core/src/models/nostr_profile_relay.rs b/crates/core/src/models/nostr_profile_relay.rs @@ -1,10 +1,19 @@ use crate::{ error::ModelError, + types::IModelsResults, models::nostr_profile::{nostr_profile_query_bind_values, NostrProfileQueryBindValues}, models::nostr_relay::{nostr_relay_query_bind_values, NostrRelayQueryBindValues}, }; +use futures::TryStreamExt; + +#[derive(Debug, serde::Serialize, serde::Deserialize, sqlx::FromRow)] +pub struct NostrProfileRelay { + tb_pr: String, + tb_rl: String, +} pub type INostrProfileRelayRelationResolve = bool; +pub type INostrProfileRelayRelationResolveGetAll = IModelsResults<NostrProfileRelay>; #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct INostrProfileRelayRelation { @@ -16,10 +25,10 @@ pub async fn lib_model_nostr_profile_relay_set( db: &sqlx::Pool<sqlx::Sqlite>, opts: INostrProfileRelayRelation, ) -> Result<INostrProfileRelayRelationResolve, ModelError> { - let (bv_np_k, bv_np) = nostr_profile_query_bind_values(opts.nostr_profile); - let (bv_nr_k, bv_nr) = nostr_relay_query_bind_values(opts.nostr_relay); - let query_vals = vec![bv_np, bv_nr]; - let query = format!("INSERT INTO nostr_profile_relay (tb_pr_rl_0, tb_pr_rl_1) VALUES ((SELECT id FROM nostr_profile WHERE {} = ?1), (SELECT id FROM nostr_relay WHERE {} = ?2));", bv_np_k, bv_nr_k); + let (bv_pr_k, bv_pr) = nostr_profile_query_bind_values(opts.nostr_profile); + let (bv_rl_k, bv_rl) = nostr_relay_query_bind_values(opts.nostr_relay); + let query_vals = vec![bv_pr, bv_rl]; + let query = format!("INSERT INTO nostr_profile_relay (tb_pr, tb_rl) VALUES ((SELECT id FROM nostr_profile WHERE {} = ?1), (SELECT id FROM nostr_relay WHERE {} = ?2));", bv_pr_k, bv_rl_k); let mut query_builder = sqlx::query(&query); for value in query_vals.iter() { query_builder = query_builder.bind(value); @@ -35,10 +44,10 @@ pub async fn lib_model_nostr_profile_relay_unset( db: &sqlx::Pool<sqlx::Sqlite>, opts: INostrProfileRelayRelation, ) -> Result<INostrProfileRelayRelationResolve, ModelError> { - let (bv_np_k, bv_np) = nostr_profile_query_bind_values(opts.nostr_profile); - let (bv_nr_k, bv_nr) = nostr_relay_query_bind_values(opts.nostr_relay); - let query_vals = vec![bv_np, bv_nr]; - let query = format!("DELETE FROM nostr_profile_relay WHERE tb_pr_rl_0 = (SELECT id FROM nostr_profile WHERE {} = ?1) AND tb_pr_rl_1 = (SELECT id FROM nostr_relay WHERE {} = ?2);", bv_np_k, bv_nr_k); + let (bv_pr_k, bv_pr) = nostr_profile_query_bind_values(opts.nostr_profile); + let (bv_rl_k, bv_rl) = nostr_relay_query_bind_values(opts.nostr_relay); + let query_vals = vec![bv_pr, bv_rl]; + let query = format!("DELETE FROM nostr_profile_relay WHERE tb_pr = (SELECT id FROM nostr_profile WHERE {} = ?1) AND tb_rl = (SELECT id FROM nostr_relay WHERE {} = ?2);", bv_pr_k, bv_rl_k); let mut query_builder = sqlx::query(&query); for value in query_vals.iter() { query_builder = query_builder.bind(value); @@ -49,3 +58,16 @@ pub async fn lib_model_nostr_profile_relay_unset( .map_err(|e| ModelError::InvalidQuery(e.to_string()))?; Ok(true) } + +pub async fn lib_model_nostr_profile_relay_get_all( + db: &sqlx::Pool<sqlx::Sqlite>, +) -> Result<INostrProfileRelayRelationResolveGetAll, ModelError> { + let query = format!("SELECT * FROM nostr_profile_relay;"); + let query_builder = sqlx::query_as::<_, NostrProfileRelay>(&query); + let results = query_builder + .fetch(db) + .try_collect() + .await + .map_err(|e: sqlx::Error| ModelError::InvalidQuery(e.to_string()))?; + Ok(IModelsResults { results }) +} diff --git a/crates/core/src/models/nostr_relay.rs b/crates/core/src/models/nostr_relay.rs @@ -65,8 +65,16 @@ pub enum NostrRelayQueryBindValues { } #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "snake_case")] +pub enum NostrRelayQueryListOf { + All(IModelsQueryBindValue), + OnProfile(IModelsQueryBindValue), + OffProfile(IModelsQueryBindValue), +} + +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct INostrRelayQueryGetList { - pub of: Vec<String>, + pub of: NostrRelayQueryListOf, pub sort: Option<NostrRelaySort>, } @@ -82,21 +90,6 @@ pub struct INostrRelayQueryUpdate { pub fields: INostrRelayFieldsUpdate, } -impl INostrRelayQueryGet { - pub fn new_on(values: NostrRelayQueryBindValues) -> Self { - INostrRelayQueryGet { - on: Some(values), - list: None, - } - } - pub fn new_list(list: INostrRelayQueryGetList) -> Self { - INostrRelayQueryGet { - on: None, - list: Some(list), - } - } -} - pub type INostrRelayAdd = INostrRelayFields; pub type INostrRelayAddResolve = IModelsId; pub type INostrRelayGet = INostrRelayQueryGet; @@ -113,6 +106,19 @@ pub fn nostr_relay_query_bind_values(opts: NostrRelayQueryBindValues) -> IModels } } +pub fn nostr_relay_query_get_list(opts: INostrRelayQueryGetList) -> IModelsQueryBindValueTuple { + let query_sort = match opts.sort { + Some(NostrRelaySort::Newest) => " ORDER BY rl.created_at DESC", + Some(NostrRelaySort::Oldest) => " ORDER BY rl.created_at ASC", + None => "", + }; + match opts.of { + NostrRelayQueryListOf::All(_) => (format!("SELECT rl.* FROM nostr_relay rl{}", query_sort), "".to_string()), + NostrRelayQueryListOf::OnProfile(public_key) => (format!("SELECT rl.* FROM nostr_relay rl JOIN nostr_profile_relay pr_rl ON rl.id = pr_rl.tb_rl JOIN nostr_profile pr ON pr.id = pr_rl.tb_pr WHERE pr.public_key = ?1{}", query_sort), public_key), + NostrRelayQueryListOf::OffProfile(public_key) => (format!("SELECT rl.* FROM nostr_relay rl LEFT JOIN nostr_profile_relay pr_rl ON rl.id = pr_rl.tb_rl LEFT JOIN nostr_profile pr ON pr.id = pr_rl.tb_pr WHERE pr.public_key <> ?1{}", query_sort), public_key), + } +} + fn nostr_relay_fields_bind_values( opts: INostrRelayFields, ) -> Result<Vec<IModelsQueryBindValueTuple>, ModelError> { @@ -184,13 +190,8 @@ fn nostr_relay_query_get( list: Some(opts_list), .. } => { - let sort = match opts_list.sort { - Some(NostrRelaySort::Newest) => "created_at DESC", - Some(NostrRelaySort::Oldest) => "created_at ASC", - None => "created_at DESC", - }; - let query = format!("SELECT * FROM nostr_relay ORDER BY {};", sort); - Ok((query, vec![])) + let (query, bv) = nostr_relay_query_get_list(opts_list); + Ok((query, vec![bv])) } INostrRelayQueryGet { on: Some(opts_on), .. diff --git a/crates/core/src/models/trade_product.rs b/crates/core/src/models/trade_product.rs @@ -82,8 +82,14 @@ pub enum TradeProductQueryBindValues { } #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "snake_case")] +pub enum TradeProductQueryListOf { + All(IModelsQueryBindValue), +} + +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct ITradeProductQueryGetList { - pub of: Vec<String>, + pub of: TradeProductQueryListOf, pub sort: Option<TradeProductSort>, } @@ -99,21 +105,6 @@ pub struct ITradeProductQueryUpdate { pub fields: ITradeProductFieldsUpdate, } -impl ITradeProductQueryGet { - pub fn new_on(values: TradeProductQueryBindValues) -> Self { - ITradeProductQueryGet { - on: Some(values), - list: None, - } - } - pub fn new_list(list: ITradeProductQueryGetList) -> Self { - ITradeProductQueryGet { - on: None, - list: Some(list), - } - } -} - pub type ITradeProductAdd = ITradeProductFields; pub type ITradeProductAddResolve = IModelsId; pub type ITradeProductGet = ITradeProductQueryGet; @@ -129,6 +120,17 @@ pub fn trade_product_query_bind_values(opts: TradeProductQueryBindValues) -> IMo } } +pub fn trade_product_query_get_list(opts: ITradeProductQueryGetList) -> IModelsQueryBindValueTuple { + let query_sort = match opts.sort { + Some(TradeProductSort::Newest) => " ORDER BY tp.created_at DESC", + Some(TradeProductSort::Oldest) => " ORDER BY tp.created_at ASC", + None => "", + }; + match opts.of { + TradeProductQueryListOf::All(_) => (format!("SELECT tp.* FROM trade_product tp{}", query_sort), "".to_string()), + } +} + fn trade_product_fields_bind_values( opts: ITradeProductFields, ) -> Result<Vec<IModelsQueryBindValueTuple>, ModelError> { @@ -200,13 +202,8 @@ fn trade_product_query_get( list: Some(opts_list), .. } => { - let sort = match opts_list.sort { - Some(TradeProductSort::Newest) => "created_at DESC", - Some(TradeProductSort::Oldest) => "created_at ASC", - None => "created_at DESC", - }; - let query = format!("SELECT * FROM trade_product ORDER BY {};", sort); - Ok((query, vec![])) + let (query, bv) = trade_product_query_get_list(opts_list); + Ok((query, vec![bv])) } ITradeProductQueryGet { on: Some(opts_on), .. diff --git a/crates/core/src/models/trade_product_location.rs b/crates/core/src/models/trade_product_location.rs @@ -1,10 +1,19 @@ use crate::{ error::ModelError, + types::IModelsResults, models::trade_product::{trade_product_query_bind_values, TradeProductQueryBindValues}, models::location_gcs::{location_gcs_query_bind_values, LocationGcsQueryBindValues}, }; +use futures::TryStreamExt; + +#[derive(Debug, serde::Serialize, serde::Deserialize, sqlx::FromRow)] +pub struct TradeProductLocation { + tb_tp: String, + tb_lg: String, +} pub type ITradeProductLocationRelationResolve = bool; +pub type ITradeProductLocationRelationResolveGetAll = IModelsResults<TradeProductLocation>; #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct ITradeProductLocationRelation { @@ -19,7 +28,7 @@ pub async fn lib_model_trade_product_location_set( let (bv_tp_k, bv_tp) = trade_product_query_bind_values(opts.trade_product); let (bv_lg_k, bv_lg) = location_gcs_query_bind_values(opts.location_gcs); let query_vals = vec![bv_tp, bv_lg]; - let query = format!("INSERT INTO trade_product_location (tb_tp_lg_0, tb_tp_lg_1) VALUES ((SELECT id FROM trade_product WHERE {} = ?1), (SELECT id FROM location_gcs WHERE {} = ?2));", bv_tp_k, bv_lg_k); + let query = format!("INSERT INTO trade_product_location (tb_tp, tb_lg) VALUES ((SELECT id FROM trade_product WHERE {} = ?1), (SELECT id FROM location_gcs WHERE {} = ?2));", bv_tp_k, bv_lg_k); let mut query_builder = sqlx::query(&query); for value in query_vals.iter() { query_builder = query_builder.bind(value); @@ -38,7 +47,7 @@ pub async fn lib_model_trade_product_location_unset( let (bv_tp_k, bv_tp) = trade_product_query_bind_values(opts.trade_product); let (bv_lg_k, bv_lg) = location_gcs_query_bind_values(opts.location_gcs); let query_vals = vec![bv_tp, bv_lg]; - let query = format!("DELETE FROM trade_product_location WHERE tb_tp_lg_0 = (SELECT id FROM nostr_profile WHERE {} = ?1) AND tb_tp_lg_1 = (SELECT id FROM nostr_relay WHERE {} = ?2);", bv_tp_k, bv_lg_k); + let query = format!("DELETE FROM trade_product_location WHERE tb_tp = (SELECT id FROM trade_product WHERE {} = ?1) AND tb_lg = (SELECT id FROM location_gcs WHERE {} = ?2);", bv_tp_k, bv_lg_k); let mut query_builder = sqlx::query(&query); for value in query_vals.iter() { query_builder = query_builder.bind(value); @@ -49,3 +58,16 @@ pub async fn lib_model_trade_product_location_unset( .map_err(|e| ModelError::InvalidQuery(e.to_string()))?; Ok(true) } + +pub async fn lib_model_trade_product_location_get_all( + db: &sqlx::Pool<sqlx::Sqlite>, +) -> Result<ITradeProductLocationRelationResolveGetAll, ModelError> { + let query = format!("SELECT * FROM trade_product_location;"); + let query_builder = sqlx::query_as::<_, TradeProductLocation>(&query); + let results = query_builder + .fetch(db) + .try_collect() + .await + .map_err(|e: sqlx::Error| ModelError::InvalidQuery(e.to_string()))?; + Ok(IModelsResults { results }) +} diff --git a/crates/tauri/Cargo.toml b/crates/tauri/Cargo.toml @@ -26,6 +26,7 @@ tauri-plugin-dialog = "2.0.0" tauri-plugin-fs = "2.0.0" tauri-plugin-geolocation = "2.0.0" tauri-plugin-http = "2.0.0" +tauri-plugin-log = "2.0.0" tauri-plugin-map-display = { git = "https://github.com/inkibra/tauri-plugins", tag = "@inkibra/tauri-plugin-map-display@0.2.0", package="tauri-plugin-map-display" } tauri-plugin-notification = "2.0.0" tauri-plugin-os = "2.0.0" diff --git a/crates/tauri/migrations/0005_nostr_profile_relay.sql b/crates/tauri/migrations/0005_nostr_profile_relay.sql @@ -1,7 +1,7 @@ CREATE TABLE IF NOT EXISTS nostr_profile_relay ( - tb_pr_rl_0 CHAR(36), - tb_pr_rl_1 CHAR(36), - FOREIGN KEY (tb_pr_rl_0) REFERENCES nostr_profile(id) ON DELETE CASCADE, - FOREIGN KEY (tb_pr_rl_1) REFERENCES nostr_relay(id) ON DELETE CASCADE, - PRIMARY KEY (tb_pr_rl_0, tb_pr_rl_1) + tb_pr CHAR(36), + tb_rl CHAR(36), + FOREIGN KEY (tb_pr) REFERENCES nostr_profile(id) ON DELETE CASCADE, + FOREIGN KEY (tb_rl) REFERENCES nostr_relay(id) ON DELETE CASCADE, + PRIMARY KEY (tb_pr, tb_rl) ); \ No newline at end of file diff --git a/crates/tauri/migrations/0006_trade_product_location.sql b/crates/tauri/migrations/0006_trade_product_location.sql @@ -1,7 +1,7 @@ CREATE TABLE IF NOT EXISTS trade_product_location ( - tb_tp_lg_0 CHAR(36), - tb_tp_lg_1 CHAR(36), - FOREIGN KEY (tb_tp_lg_0) REFERENCES trade_product(id) ON DELETE CASCADE, - FOREIGN KEY (tb_tp_lg_1) REFERENCES location_gcs(id) ON DELETE CASCADE, - PRIMARY KEY (tb_tp_lg_0, tb_tp_lg_1) + tb_tp CHAR(36), + tb_lg CHAR(36), + FOREIGN KEY (tb_tp) REFERENCES trade_product(id) ON DELETE CASCADE, + FOREIGN KEY (tb_lg) REFERENCES location_gcs(id) ON DELETE CASCADE, + PRIMARY KEY (tb_tp, tb_lg) ); \ No newline at end of file diff --git a/crates/tauri/src/lib.rs b/crates/tauri/src/lib.rs @@ -12,7 +12,10 @@ use models::{ model_nostr_profile_add, model_nostr_profile_delete, model_nostr_profile_get, model_nostr_profile_update, }, - nostr_profile_relay::{model_nostr_profile_relay_set, model_nostr_profile_relay_unset}, + nostr_profile_relay::{ + model_nostr_profile_relay_get_all, model_nostr_profile_relay_set, + model_nostr_profile_relay_unset, + }, nostr_relay::{ model_nostr_relay_add, model_nostr_relay_delete, model_nostr_relay_get, model_nostr_relay_update, @@ -22,7 +25,8 @@ use models::{ model_trade_product_update, }, trade_product_location::{ - model_trade_product_location_set, model_trade_product_location_unset, + model_trade_product_location_get_all, model_trade_product_location_set, + model_trade_product_location_unset, }, }; use radroots::Radroots; @@ -75,8 +79,10 @@ pub fn run() { model_nostr_relay_update, model_nostr_profile_relay_set, model_nostr_profile_relay_unset, + model_nostr_profile_relay_get_all, model_trade_product_location_set, - model_trade_product_location_unset + model_trade_product_location_unset, + model_trade_product_location_get_all ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/crates/tauri/src/models/nostr_profile_relay.rs b/crates/tauri/src/models/nostr_profile_relay.rs @@ -1,6 +1,6 @@ use crate::radroots::Radroots; use radroots_core::{ - models::nostr_profile_relay::{lib_model_nostr_profile_relay_set, lib_model_nostr_profile_relay_unset, INostrProfileRelayRelation, INostrProfileRelayRelationResolve}, + models::nostr_profile_relay::{lib_model_nostr_profile_relay_set, lib_model_nostr_profile_relay_unset, lib_model_nostr_profile_relay_get_all, INostrProfileRelayRelation, INostrProfileRelayRelationResolve, INostrProfileRelayRelationResolveGetAll}, }; #[tauri::command] @@ -30,3 +30,16 @@ pub async fn model_nostr_profile_relay_unset( } } } + +#[tauri::command] +pub async fn model_nostr_profile_relay_get_all( + state: tauri::State<'_, Radroots>, +) -> Result<INostrProfileRelayRelationResolveGetAll, String> { + match lib_model_nostr_profile_relay_get_all(&state.db).await { + Ok(result) => Ok(result), + Err(e) => { + println!("ERROR {}", e); + Err(e.to_string()) + } + } +} diff --git a/crates/tauri/src/models/trade_product_location.rs b/crates/tauri/src/models/trade_product_location.rs @@ -1,6 +1,6 @@ use crate::radroots::Radroots; use radroots_core::{ - models::trade_product_location::{lib_model_trade_product_location_set, lib_model_trade_product_location_unset, ITradeProductLocationRelation, ITradeProductLocationRelationResolve}, + models::trade_product_location::{lib_model_trade_product_location_set, lib_model_trade_product_location_unset, lib_model_trade_product_location_get_all, ITradeProductLocationRelation, ITradeProductLocationRelationResolve, ITradeProductLocationRelationResolveGetAll}, }; #[tauri::command] @@ -30,3 +30,16 @@ pub async fn model_trade_product_location_unset( } } } + +#[tauri::command] +pub async fn model_trade_product_location_get_all( + state: tauri::State<'_, Radroots>, +) -> Result<ITradeProductLocationRelationResolveGetAll, String> { + match lib_model_trade_product_location_get_all(&state.db).await { + Ok(result) => Ok(result), + Err(e) => { + println!("ERROR {}", e); + Err(e.to_string()) + } + } +} diff --git a/src/lib/components/image_upload_edit_envelope.svelte b/src/lib/components/image_upload_edit_envelope.svelte @@ -58,14 +58,13 @@ <EnvelopeLower basis={{ close: async () => { - //await basis.close(); photo_edit = undefined; }, }} > {#if photo_edit} <div - class={`z-50 flex flex-col w-full px-4 gap-4 justify-start items-center`} + class={`flex flex-col w-full px-4 gap-4 justify-start items-center`} > <div class={`flex flex-row w-full justify-center items-center round-44 overflow-hidden`} diff --git a/src/routes/(app)/models/trade-product/+page.svelte b/src/routes/(app)/models/trade-product/+page.svelte @@ -1,20 +1,23 @@ <script lang="ts"> import { db } from "$lib/client"; - import { type TradeProduct } from "@radroots/models"; + import { type LocationGcs, type TradeProduct } from "@radroots/models"; import { + app_layout, app_notify, LayoutTrellis, LayoutView, Nav, route, t, - time_iso, - Trellis, } from "@radroots/svelte-lib"; import { onMount } from "svelte"; + type LoadDataResult = { + trade_product: TradeProduct; + location_gcs?: LocationGcs; + }; type LoadData = { - trade_products: TradeProduct[]; + results: LoadDataResult[]; }; let ld: LoadData | undefined = undefined; @@ -37,115 +40,57 @@ ); return; } + + const results: LoadDataResult[] = []; + for (const trade_product of trade_products.results) { + const location_gcs = await db.location_gcs_get({ + list: [`on_trade_product`, { id: trade_product.id }], + }); + results.push({ + trade_product, + location_gcs: + `results` in location_gcs + ? location_gcs.results[0] + : undefined, + }); + } + const data: LoadData = { - trade_products: trade_products.results, + results, }; return data; } catch (e) { console.log(`(error) load_data `, e); } }; + + $: { + console.log(JSON.stringify(ld, null, 4), `ld`); + } </script> -{#if ld && ld.trade_products.length > 0} +{#if ld && ld.results.length > 0} <LayoutView> <LayoutTrellis> - {#each ld.trade_products as li, li_i} - <Trellis - basis={{ - args: { - layer: 1, - title: - li_i === 0 - ? { - value: `Trade Products`, - } - : undefined, - list: [ - { - hide_active: true, - touch: { - label: { - left: [ - { - value: `Product:`, - classes: `capitalize`, - }, - ], - right: [ - { - value: li.key, - classes: `capitalize`, - }, - ], - }, - callback: async () => {}, - }, - }, - { - hide_active: true, - touch: { - label: { - left: [ - { - value: `Date Created:`, - classes: `capitalize`, - }, - ], - right: [ - { - value: time_iso( - li.created_at, - ), - }, - ], - }, - callback: async () => {}, - }, - }, - { - hide_active: true, - touch: { - label: { - left: [ - { - value: `Lot:`, - classes: `capitalize`, - }, - ], - right: [ - { - value: li.lot || `@todo`, - }, - ], - }, - callback: async () => {}, - }, - }, - { - hide_active: true, - touch: { - label: { - left: [ - { - value: `Process:`, - classes: `capitalize`, - }, - ], - right: [ - { - value: - li.process || `(@todo)`, - }, - ], - }, - callback: async () => {}, - }, - }, - ], - }, - }} - /> + {#each ld.results as li, li_i} + <div + class={`flex flex-col h-[22rem] w-${$app_layout} justify-start items-start bg-layer-1-surface round-44`} + > + <div + class={`flex flex-row h-[11rem] w-${$app_layout} justify-center items-center border-b-line border-b-layer-1-surface-edge`} + > + <p class={`font-sans font-[400] text-layer-0-glyph`}> + photos + </p> + </div> + <div + class={`flex flex-row h-[11rem] w-full justify-center items-center`} + > + <p class={`font-sans font-[400] text-layer-0-glyph`}> + body + </p> + </div> + </div> {/each} </LayoutTrellis> </LayoutView> @@ -162,7 +107,7 @@ }, }, option: - ld && ld?.trade_products?.length > 0 + ld && ld?.results?.length > 0 ? { label: { value: `${$t(`common.add`)}`, diff --git a/src/routes/(app)/models/trade-product/add/+page.svelte b/src/routes/(app)/models/trade-product/add/+page.svelte @@ -8,7 +8,7 @@ import { ascii } from "$lib/conf"; import { el_focus } from "$lib/utils/client"; import { location_gcs_to_geoc } from "$lib/utils/geocode"; - import { kv_init_page } from "$lib/utils/kv"; + import { kv_init_page, kv_sync } from "$lib/utils/kv"; import { model_location_gcs_add_geocode } from "$lib/utils/models"; import { trade_product_fields_validate, @@ -116,6 +116,7 @@ view_effect<View>(view); } + let load_page = false; let load_submit = false; let tradepr_photo_paths: string[] = []; @@ -156,8 +157,10 @@ onMount(async () => { try { await init_page(); + await setup_tests(); } catch (e) { } finally { + load_page = true; } }); @@ -182,6 +185,28 @@ } }; + const setup_tests = async (): Promise<void> => { + try { + tradepr_key_sel = page_param.default.tradepr_key; + tradepr_process_sel = `washed`; + + tradepr_price_amt_val = `1200.07`; + + tradepr_qty_tup_sel.set(`60-kg-bag`); + + await kv_sync([ + [fmt_id(`title`), `Green Coffee Beans`], + [fmt_id(`lot`), `mountain #1`], + [ + fmt_id(`summary`), + `Good coffee, an amazing batch from our secret hillside with world leading terroir and tasting notes of honey.`, + ], + ]); + } catch (e) { + console.log(`(error) setup_tests `, e); + } + }; + let tradepr_cprice_amt: CurrencyPrice | undefined = undefined; $: tradepr_cprice_amt = tradepr_price_amt_val && tradepr_price_curr_sel @@ -418,8 +443,8 @@ fmt_id(`image-upload-control`), async () => await handle_back(2), ); + return; } - return; } let location_gcs_id = ``; const location_gcs_get_i = await db.location_gcs_get_one({ @@ -510,205 +535,325 @@ }; </script> -<LayoutView> - <div - data-view={`c_1`} - class={`flex flex-col h-full w-full justify-start items-center`} - > +{#if load_page} + <LayoutView> <div - data-carousel-container={`c_1`} - class={`carousel-container flex h-full w-full`} + data-view={`c_1`} + class={`flex flex-col h-full w-full justify-start items-center`} > <div - data-carousel-item={`c_1`} - class={`carousel-item flex flex-col w-full justify-start items-center`} + data-carousel-container={`c_1`} + class={`carousel-container flex h-full w-full`} > - <LayoutTrellis> - <ImageUploadControl - bind:photo_paths={tradepr_photo_paths} - bind:photo_edit={tradepr_photo_edit} - basis={{ - id: fmt_id(`image-upload-control`), - }} - /> - <LayoutTrellisLine - basis={{ - label: { - value: `${$t(`icu.listing_*`, { value: `${$t(`common.title`)}` })}`, - }, - }} - > - <EntryLine + <div + data-carousel-item={`c_1`} + class={`carousel-item flex flex-col w-full justify-start items-center`} + > + <LayoutTrellis> + <ImageUploadControl + bind:photo_paths={tradepr_photo_paths} + bind:photo_edit={tradepr_photo_edit} basis={{ - wrap: { - id: fmt_id(`title_wrap`), - layer: 1, - }, - el: { - id: fmt_id(`title`), - layer: 1, - sync: true, - classes: `fade-in-long`, - placeholder: `${$t(`icu.enter_*`, { value: `${$t(`common.title`)}`.toLowerCase() })}`, - field: { - charset: - trade_product_form_fields.title - .charset, - validate: - trade_product_form_fields.title - .validation, - validate_keypress: true, - }, - }, + id: fmt_id(`image-upload-control`), }} /> - </LayoutTrellisLine> - <LayoutTrellisLine - basis={{ - label: { - value: `${$t(`common.product`)}`, - }, - notify: tradepr_key_sel_toggle - ? { - label: { - value: `${$t(`common.close`)}`, - }, - callback: async () => { - await handle_tradepr_key_toggle( - false, - ); - }, - } - : undefined, - }} - > - {#if !tradepr_key_sel_toggle} - <EntrySelect - bind:value={tradepr_key_sel} - basis={{ - wrap: { - id: fmt_id(`key_wrap`), - layer: 1, - }, - el: { - id: fmt_id(`key`), - sync: true, - layer: 1, - options: [ - { - entries: [ - { - value: ``, - label: `${$t(`icu.choose_*`, { value: `${$t(`common.product`)}`.toLowerCase() })}`, - disabled: true, - }, - ...trade_keys.map((i) => ({ - value: i, - label: `${$t(`trade.product.key.${i}.name`)}`, - })), - { - value: ``, - label: `${$t(`common.other`)}`, - }, - ], - }, - ], - callback: async (opt) => { - el_id( - fmt_id(`key_wrap`), - )?.classList.remove( - `entry-layer-1-highlight`, - ); - if (!opt.value) { - await handle_tradepr_key_toggle( - true, - ); - tradepr_key_sel = ``; - tradepr_process_sel = ``; - } else { - tradepr_process_sel = ``; - } - }, - }, - }} - /> - {:else} + <LayoutTrellisLine + basis={{ + label: { + value: `${$t(`icu.listing_*`, { value: `${$t(`common.title`)}` })}`, + }, + }} + > <EntryLine basis={{ wrap: { - id: fmt_id(`key_wrap`), + id: fmt_id(`title_wrap`), layer: 1, }, el: { - id: fmt_id(`key`), + id: fmt_id(`title`), layer: 1, sync: true, classes: `fade-in-long`, - placeholder: `${$t(`icu.enter_the_*`, { value: `${$t(`icu.*_name`, { value: `${$t(`common.product`)}` })}`.toLowerCase() })}`, + placeholder: `${$t(`icu.enter_*`, { value: `${$t(`common.title`)}`.toLowerCase() })}`, field: { charset: - trade_product_form_fields.key + trade_product_form_fields.title .charset, validate: - trade_product_form_fields.key + trade_product_form_fields.title .validation, validate_keypress: true, }, }, }} /> - {/if} - </LayoutTrellisLine> - <LayoutTrellisLine - basis={{ - label: { - value: `${$t(`common.process`)}`, - }, - notify: tradepr_process_sel_toggle - ? { - label: { - value: `${$t(`common.close`)}`, - }, - callback: async () => { - await handle_tradepr_process_toggle( - false, - ); - }, - } - : undefined, - }} - > - {#if !tradepr_process_sel_toggle} + </LayoutTrellisLine> + <LayoutTrellisLine + basis={{ + label: { + value: `${$t(`common.product`)}`, + }, + notify: tradepr_key_sel_toggle + ? { + label: { + value: `${$t(`common.close`)}`, + }, + callback: async () => { + await handle_tradepr_key_toggle( + false, + ); + }, + } + : undefined, + }} + > + {#if !tradepr_key_sel_toggle} + <EntrySelect + bind:value={tradepr_key_sel} + basis={{ + wrap: { + id: fmt_id(`key_wrap`), + layer: 1, + }, + el: { + id: fmt_id(`key`), + sync: true, + layer: 1, + options: [ + { + entries: [ + { + value: ``, + label: `${$t(`icu.choose_*`, { value: `${$t(`common.product`)}`.toLowerCase() })}`, + disabled: true, + }, + ...trade_keys.map( + (i) => ({ + value: i, + label: `${$t(`trade.product.key.${i}.name`)}`, + }), + ), + { + value: ``, + label: `${$t(`common.other`)}`, + }, + ], + }, + ], + callback: async (opt) => { + el_id( + fmt_id(`key_wrap`), + )?.classList.remove( + `entry-layer-1-highlight`, + ); + if (!opt.value) { + await handle_tradepr_key_toggle( + true, + ); + tradepr_key_sel = ``; + tradepr_process_sel = ``; + } else { + tradepr_process_sel = ``; + } + }, + }, + }} + /> + {:else} + <EntryLine + basis={{ + wrap: { + id: fmt_id(`key_wrap`), + layer: 1, + }, + el: { + id: fmt_id(`key`), + layer: 1, + sync: true, + classes: `fade-in-long`, + placeholder: `${$t(`icu.enter_the_*`, { value: `${$t(`icu.*_name`, { value: `${$t(`common.product`)}` })}`.toLowerCase() })}`, + field: { + charset: + trade_product_form_fields + .key.charset, + validate: + trade_product_form_fields + .key.validation, + validate_keypress: true, + }, + }, + }} + /> + {/if} + </LayoutTrellisLine> + <LayoutTrellisLine + basis={{ + label: { + value: `${$t(`common.process`)}`, + }, + notify: tradepr_process_sel_toggle + ? { + label: { + value: `${$t(`common.close`)}`, + }, + callback: async () => { + await handle_tradepr_process_toggle( + false, + ); + }, + } + : undefined, + }} + > + {#if !tradepr_process_sel_toggle} + <EntrySelect + bind:value={tradepr_process_sel} + basis={{ + wrap: { + id: fmt_id(`process_wrap`), + layer: 1, + }, + el: { + id: fmt_id(`process`), + sync: true, + layer: 1, + options: [ + { + entries: + tradepr_process_list.length + ? [ + { + value: ``, + label: `${$t(`icu.choose_*`, { value: `${$t(`common.process`)}`.toLowerCase() })}`, + disabled: true, + }, + ...tradepr_process_list.map( + (i) => ({ + value: i, + label: `${$t(`trade.product.key.${tradepr_key_parsed}.process.${i}`)}`, + }), + ), + { + value: ``, + label: `${$t(`common.other`)}`, + }, + ] + : [ + { + value: ``, + label: `${$t(`icu.choose_*`, { value: `${$t(`common.process`)}`.toLowerCase() })}`, + disabled: true, + }, + + { + value: `*choose-product`, + label: `${$t(`icu.choose_*`, { value: `${$t(`common.product`)}`.toLowerCase() })}`, + }, + ], + }, + ], + callback: async ({ value }) => { + el_id( + fmt_id(`process_wrap`), + )?.classList.remove( + `entry-layer-1-highlight`, + ); + if (!value) { + await handle_tradepr_process_toggle( + true, + ); + } + }, + }, + }} + /> + {:else} + <EntryLine + basis={{ + wrap: { + id: fmt_id(`process_wrap`), + layer: 1, + }, + el: { + id: fmt_id(`process`), + layer: 1, + sync: true, + classes: `fade-in-long`, + placeholder: `${$t(`icu.enter_the_*`, { value: `${$t(`common.process`)}`.toLowerCase() })}`, + field: { + charset: + trade_product_form_fields + .process.charset, + validate: + trade_product_form_fields + .process.validation, + validate_keypress: true, + }, + }, + }} + /> + {/if} + </LayoutTrellisLine> + <LayoutTrellisLine + basis={{ + label: { + value: `${$t(`common.location`)}`, + }, + }} + > <EntrySelect - bind:value={tradepr_process_sel} + bind:value={$tradepr_lgc_sel} basis={{ wrap: { - id: fmt_id(`process_wrap`), + id: fmt_id(`tradepr_location_wrap`), layer: 1, }, el: { - id: fmt_id(`process`), + id: fmt_id(`tradepr_location`), sync: true, layer: 1, options: [ { - entries: [ - { - value: ``, - label: `${$t(`icu.choose_*`, { value: `${$t(`common.process`)}`.toLowerCase() })}`, - disabled: true, - }, - ...tradepr_process_list.map( - (i) => ({ - value: i, - label: `${$t(`trade.product.key.${tradepr_key_parsed}.process.${i}`)}`, - }), - ), - { - value: ``, - label: `${$t(`common.other`)}`, - }, - ], + entries: tradepr_lgc_map_geoc + ? [ + { + value: ``, + label: `${$t(`icu.choose_*`, { value: `${$t(`common.location`)}`.toLowerCase() })}`, + disabled: true, + }, + { + value: `*map`, + label: `${$t(`icu.choose_on_*`, { value: `${$t(`common.map`)}`.toLowerCase() })}`, + }, + { + value: `*geoc`, + label: `${tradepr_lgc_map_geoc.name}, ${tradepr_lgc_map_geoc.admin1_name}, ${tradepr_lgc_map_geoc.country_id}`, + }, + ...tradepr_lgc_list.map( + (i) => ({ + value: i.id, + label: `${i.gc_name}, ${i.gc_admin1_name}, ${i.gc_country_id}`, + }), + ), + ] + : [ + { + value: ``, + label: `${$t(`icu.choose_*`, { value: `${$t(`common.location`)}`.toLowerCase() })}`, + disabled: true, + }, + { + value: `*map`, + label: `${$t(`icu.choose_on_*`, { value: `${$t(`common.map`)}`.toLowerCase() })}`, + }, + ...tradepr_lgc_list.map( + (i) => ({ + value: i.id, + label: `${i.gc_name}, ${i.gc_admin1_name}, ${i.gc_country_id}`, + }), + ), + ], }, ], callback: async ({ value }) => { @@ -717,462 +862,243 @@ )?.classList.remove( `entry-layer-1-highlight`, ); - if (!value) { - await handle_tradepr_process_toggle( - true, - ); + if (value === `*map`) { + await handle_tradepr_lgc_sel_map(); } }, }, }} /> - {:else} - <EntryLine - basis={{ - wrap: { - id: fmt_id(`process_wrap`), - layer: 1, - }, - el: { - id: fmt_id(`process`), - layer: 1, - sync: true, - classes: `fade-in-long`, - placeholder: `${$t(`icu.enter_the_*`, { value: `${$t(`common.process`)}`.toLowerCase() })}`, - field: { - charset: - trade_product_form_fields - .process.charset, - validate: - trade_product_form_fields - .process.validation, - validate_keypress: true, - }, - }, - }} - /> - {/if} - </LayoutTrellisLine> - <LayoutTrellisLine - basis={{ - label: { - value: `${$t(`common.location`)}`, - }, - }} - > - <EntrySelect - bind:value={$tradepr_lgc_sel} - basis={{ - wrap: { - id: fmt_id(`tradepr_location_wrap`), - layer: 1, - }, - el: { - id: fmt_id(`tradepr_location`), - sync: true, - layer: 1, - options: [ - { - entries: tradepr_lgc_map_geoc - ? [ - { - value: ``, - label: `${$t(`icu.choose_*`, { value: `${$t(`common.location`)}`.toLowerCase() })}`, - disabled: true, - }, - { - value: `*map`, - label: `${$t(`icu.choose_on_*`, { value: `${$t(`common.map`)}`.toLowerCase() })}`, - }, - { - value: `*geoc`, - label: `${tradepr_lgc_map_geoc.name}, ${tradepr_lgc_map_geoc.admin1_name}, ${tradepr_lgc_map_geoc.country_id}`, - }, - ...tradepr_lgc_list.map( - (i) => ({ - value: i.id, - label: `${i.gc_name}, ${i.gc_admin1_name}, ${i.gc_country_id}`, - }), - ), - ] - : [ - { - value: ``, - label: `${$t(`icu.choose_*`, { value: `${$t(`common.location`)}`.toLowerCase() })}`, - disabled: true, - }, - { - value: `*map`, - label: `${$t(`icu.choose_on_*`, { value: `${$t(`common.map`)}`.toLowerCase() })}`, - }, - ...tradepr_lgc_list.map( - (i) => ({ - value: i.id, - label: `${i.gc_name}, ${i.gc_admin1_name}, ${i.gc_country_id}`, - }), - ), - ], - }, - ], - callback: async ({ value }) => { - el_id( - fmt_id(`process_wrap`), - )?.classList.remove( - `entry-layer-1-highlight`, - ); - if (value === `*map`) { - await handle_tradepr_lgc_sel_map(); - } - }, - }, - }} - /> - </LayoutTrellisLine> - </LayoutTrellis> - </div> - <div - data-carousel-item={`c_1`} - class={`carousel-item flex flex-col w-full justify-start items-center`} - > - <LayoutTrellis> - <div - class={`flex flex-col w-full justify-center items-center`} - > + </LayoutTrellisLine> + </LayoutTrellis> + </div> + <div + data-carousel-item={`c_1`} + class={`carousel-item flex flex-col w-full justify-start items-center`} + > + <LayoutTrellis> <div - class={`flex flex-col h-[11rem] w-${$app_layout} justify-start items-start bg-layer-1-surface rounded-[2rem] overflow-hidden`} + class={`flex flex-col w-full justify-center items-center`} > <div - class={`flex flex-row h-[2.5rem] w-full justify-center items-center`} + class={`flex flex-col h-[11rem] w-${$app_layout} justify-start items-start bg-layer-1-surface rounded-[2rem] overflow-hidden`} > - <p - class={`font-sans font-[400] text-[1.05rem] text-layer-1-glyph_d`} + <div + class={`flex flex-row h-[2.5rem] w-full justify-center items-center`} > - {`${$t(`common.listing`)}`} - </p> - </div> - <div - class={`flex flex-col h-[8.5rem] w-full px-4 justify-start items-start`} - > + <p + class={`font-sans font-[400] text-[1.05rem] text-layer-1-glyph_d`} + > + {`${$t(`common.listing`)}`} + </p> + </div> <div - class={`flex flex-col h-full w-full gap-[5px] justify-center items-center border-t-line border-layer-0-glyph_d`} + class={`flex flex-col h-[8.5rem] w-full px-4 justify-start items-start`} > - <TradeFieldDisplayKv - basis={{ - visible: $carousel_index === 1, - label: `${$t(`common.title`)}`, - display: { - kv: `title`, - undef: `${$t(`icu.no_*`, { value: `${$t(`common.title`)}`.toLowerCase() })}`, - }, - handle_back: async () => { - await handle_back(1); - }, - }} - /> - <TradeFieldDisplayKv - basis={{ - visible: $carousel_index === 1, - label: `${$t(`common.product`)}`, - display: { - kv: `key`, - undef: `${$t(`icu.no_*`, { value: `${$t(`common.product`)}`.toLowerCase() })}`, - }, - handle_back: async () => { - await handle_back(1); - }, - }} - /> - <TradeFieldDisplayKv - basis={{ - visible: $carousel_index === 1, - label: `${$t(`common.process`)}`, - display: { - kv: `process`, - undef: `${$t(`icu.no_*`, { value: `${$t(`common.process`)}`.toLowerCase() })}`, - }, - handle_back: async () => { - await handle_back(1); - }, - }} - /> - <TradeFieldDisplayKv - basis={{ - visible: $carousel_index === 1, - kv_wrap: `tradepr_location_wrap`, - label: `${$t(`common.location`)}`, - display: { - value: tradepr_lgc_sel_geoc - ? `${tradepr_lgc_sel_geoc.name}, ${tradepr_lgc_sel_geoc.admin1_name}, ${tradepr_lgc_sel_geoc.country_id}` - : ``, - undef: `${$t(`icu.no_*`, { value: `${$t(`common.location`)}`.toLowerCase() })}`, - }, - handle_back: async () => { - await handle_back(1); - }, - }} - /> + <div + class={`flex flex-col h-full w-full gap-[5px] justify-center items-center border-t-line border-layer-0-glyph_d`} + > + <TradeFieldDisplayKv + basis={{ + visible: $carousel_index === 1, + label: `${$t(`common.title`)}`, + display: { + kv: `title`, + undef: `${$t(`icu.no_*`, { value: `${$t(`common.title`)}`.toLowerCase() })}`, + }, + handle_back: async () => { + await handle_back(1); + }, + }} + /> + <TradeFieldDisplayKv + basis={{ + visible: $carousel_index === 1, + label: `${$t(`common.product`)}`, + display: { + kv: `key`, + undef: `${$t(`icu.no_*`, { value: `${$t(`common.product`)}`.toLowerCase() })}`, + }, + handle_back: async () => { + await handle_back(1); + }, + }} + /> + <TradeFieldDisplayKv + basis={{ + visible: $carousel_index === 1, + label: `${$t(`common.process`)}`, + display: { + kv: `process`, + undef: `${$t(`icu.no_*`, { value: `${$t(`common.process`)}`.toLowerCase() })}`, + }, + handle_back: async () => { + await handle_back(1); + }, + }} + /> + <TradeFieldDisplayKv + basis={{ + visible: $carousel_index === 1, + kv_wrap: `tradepr_location_wrap`, + label: `${$t(`common.location`)}`, + display: { + value: tradepr_lgc_sel_geoc + ? `${tradepr_lgc_sel_geoc.name}, ${tradepr_lgc_sel_geoc.admin1_name}, ${tradepr_lgc_sel_geoc.country_id}` + : ``, + undef: `${$t(`icu.no_*`, { value: `${$t(`common.location`)}`.toLowerCase() })}`, + }, + handle_back: async () => { + await handle_back(1); + }, + }} + /> + </div> </div> </div> </div> - </div> - <LayoutTrellisLine - basis={{ - label: { - value: `${$t(`common.lot`)}`, - }, - }} - > - <EntryLine + <LayoutTrellisLine basis={{ - wrap: { - id: fmt_id(`lot_wrap`), - layer: 1, - }, - el: { - id: fmt_id(`lot`), - layer: 1, - sync: true, - placeholder: `${$t(`icu.enter_the_*`, { value: `${$t(`icu.*_name`, { value: `${$t(`common.lot`)}` })}`.toLowerCase() })}`, - field: { - charset: - trade_product_form_fields.lot - .charset, - validate: - trade_product_form_fields.lot - .validation, - validate_keypress: true, - }, + label: { + value: `${$t(`common.lot`)}`, }, }} - /> - </LayoutTrellisLine> - <LayoutTrellisLine - basis={{ - label: { - value: `${$t(`icu.*_price`, { value: `${$t(`common.product`)}` })} (${tradepr_price_curr_sel}/${`${$t(`measurement.mass.unit.${tradepr_price_qty_unit_sel}_ab`)}`})`, - }, - }} - > - <EntryWrap - basis={{ - id: fmt_id(`price_wrap`), - layer: 1, - }} > - <div - class={`flex flex-row justify-start pr-1 items-center`} - > - <SelectElement - bind:value={tradepr_price_curr_sel} - basis={{ - id: fmt_id(`price_currency`), - layer: 1, - sync: true, - classes: `w-fit font-sans font-[400] text-[1.1rem] ${tradepr_price_amt_val ? `text-layer-1-glyph_d` : `text-layer-1-glyph_pl`} el-re`, - options: [ - { - entries: fiat_currencies.map( - (i) => ({ - value: `${i}`, - label: parse_currency_marker( - $locale, - i, - ), - }), - ), - }, - ], - }} - /> - </div> - <InputElement - bind:value={tradepr_price_amt_val} - basis={{ - id: fmt_id(`price_amt`), - layer: 1, - sync: true, - placeholder: `${$t(`icu.enter_the_*`, { value: `${$t(`common.price`)}`.toLowerCase() })}`, - field: { - charset: - trade_product_form_fields.price_amt - .charset, - validate: - trade_product_form_fields.price_amt - .validation, - validate_keypress: true, - }, - callback: async ({ value, pass }) => { - const lastchar = - value[value.length - 1]; - const period_count = - value.split(".").length - 1; - if ( - (pass && - lastchar !== `.` && - period_count < 2) || - value.length < 1 - ) { - el_id( - fmt_id(`price_wrap`), - )?.classList.remove( - `entry-layer-1-highlight`, - ); - } else { - el_id( - fmt_id(`price_wrap`), - )?.classList.add( - `entry-layer-1-highlight`, - ); - } - }, - callback_blur: async ({ el }) => { - if (!el.value) return; - el.value = fmt_price( - tradepr_price_curr_sel, - el.value, - ).slice(1); //@todo fmt handles 'en' only - }, - }} - /> - <div - class={`flex flex-row gap-2 justify-end items-center`} - > - <p - class={`font-sans font-[400] text-[1.05rem] text-layer-1-glyph_d lowercase`} - > - {num_str(1)} - </p> - <SelectElement - bind:value={tradepr_price_qty_unit_sel} - basis={{ - id: fmt_id(`price_qty_unit`), - sync: true, - layer: 1, - classes: `w-fit font-sans font-[400] text-[1.05rem]`, - show_arrows: `r`, - options: [ - { - entries: mass_units.map( - (i) => ({ - value: i, - label: `${$t(`measurement.mass.unit.${i}_ab`)}`.toLowerCase(), - }), - ), - }, - ], - }} - /> - </div> - </EntryWrap> - </LayoutTrellisLine> - <LayoutTrellisLine - basis={{ - label: { - value: `${$t(`icu.*_quantity`, { value: `${$t(`common.order`)}` })}`, - }, - notify: tradepr_qty_tup_sel_toggle - ? { - label: { - value: `${$t(`common.close`)}`, - }, - callback: async () => { - await handle_tradepr_qty_amt_toggle( - false, - ); - }, - } - : undefined, - }} - > - {#if !tradepr_qty_tup_sel_toggle} - <EntrySelect - bind:value={$tradepr_qty_tup_sel} + <EntryLine basis={{ wrap: { - id: fmt_id(`qty_wrap`), + id: fmt_id(`lot_wrap`), layer: 1, }, el: { + id: fmt_id(`lot`), layer: 1, - options: [ - { - entries: [ - { - value: ``, - label: `${$t(`icu.choose_*`, { value: `${$t(`common.quantity`)}`.toLowerCase() })}`, - disabled: true, - }, - ...tradepr_key_quantities_list.map( - (i) => ({ - value: fmt_trade_quantity_tup( - i, - ), - label: `${i.mass} ${$t(`measurement.mass.unit.${i.mass_unit}_ab`)} ${i.label}`, - }), - ), - { - value: ``, - label: `${$t(`common.other`)}`, - }, - ], - }, - ], - callback: async ({ value }) => { - el_id( - fmt_id(`qty_wrap`), - )?.classList.remove( - `entry-layer-1-highlight`, - ); - if (value === ``) { - await handle_tradepr_qty_amt_toggle( - true, - ); - } + sync: true, + placeholder: `${$t(`icu.enter_the_*`, { value: `${$t(`icu.*_name`, { value: `${$t(`common.lot`)}` })}`.toLowerCase() })}`, + field: { + charset: + trade_product_form_fields.lot + .charset, + validate: + trade_product_form_fields.lot + .validation, + validate_keypress: true, }, }, }} /> - {:else} + </LayoutTrellisLine> + <LayoutTrellisLine + basis={{ + label: { + value: `${$t(`icu.*_price`, { value: `${$t(`common.product`)}` })} (${tradepr_price_curr_sel}/${`${$t(`measurement.mass.unit.${tradepr_price_qty_unit_sel}_ab`)}`})`, + }, + }} + > <EntryWrap basis={{ - id: fmt_id(`qty_wrap`), + id: fmt_id(`price_wrap`), layer: 1, }} > + <div + class={`flex flex-row justify-start pr-1 items-center`} + > + <SelectElement + bind:value={tradepr_price_curr_sel} + basis={{ + id: fmt_id(`price_currency`), + layer: 1, + sync: true, + classes: `w-fit font-sans font-[400] text-[1.1rem] ${tradepr_price_amt_val ? `text-layer-1-glyph_d` : `text-layer-1-glyph_pl`} el-re`, + options: [ + { + entries: + fiat_currencies.map( + (i) => ({ + value: `${i}`, + label: parse_currency_marker( + $locale, + i, + ), + }), + ), + }, + ], + }} + /> + </div> <InputElement + bind:value={tradepr_price_amt_val} basis={{ - id: fmt_id(`qty_amt`), - sync: true, + id: fmt_id(`price_amt`), layer: 1, - placeholder: `${$t(`icu.enter_*_per_order`, { value: `${$t(`measurement.mass.unit.${tradepr_qty_unit_sel}_ab`)}`.toLowerCase() })}`, + sync: true, + placeholder: `${$t(`icu.enter_the_*`, { value: `${$t(`common.price`)}`.toLowerCase() })}`, field: { charset: trade_product_form_fields - .qty_amt.charset, + .price_amt.charset, validate: trade_product_form_fields - .qty_amt.validation, + .price_amt.validation, validate_keypress: true, }, + callback: async ({ value, pass }) => { + const lastchar = + value[value.length - 1]; + const period_count = + value.split(".").length - 1; + if ( + (pass && + lastchar !== `.` && + period_count < 2) || + value.length < 1 + ) { + el_id( + fmt_id(`price_wrap`), + )?.classList.remove( + `entry-layer-1-highlight`, + ); + } else { + el_id( + fmt_id(`price_wrap`), + )?.classList.add( + `entry-layer-1-highlight`, + ); + } + }, + callback_blur: async ({ el }) => { + if (!el.value) return; + el.value = fmt_price( + tradepr_price_curr_sel, + el.value, + ).slice(1); //@todo fmt handles 'en' only + }, }} /> <div class={`flex flex-row gap-2 justify-end items-center`} > + <p + class={`font-sans font-[400] text-[1.05rem] text-layer-1-glyph_d lowercase`} + > + {num_str(1)} + </p> <SelectElement - bind:value={tradepr_qty_unit_sel} + bind:value={tradepr_price_qty_unit_sel} basis={{ - id: fmt_id(`qty_unit`), + id: fmt_id(`price_qty_unit`), sync: true, layer: 1, - classes: `w-fit font-sans font-[400] text-[1.05rem] text-layer-1-glyph_d`, + classes: `w-fit font-sans font-[400] text-[1.05rem]`, show_arrows: `r`, options: [ { entries: mass_units.map( (i) => ({ value: i, - label: `${$t(`measurement.mass.unit.${i}_ab`)}`, + label: `${$t(`measurement.mass.unit.${i}_ab`)}`.toLowerCase(), }), ), }, @@ -1181,310 +1107,429 @@ /> </div> </EntryWrap> - {/if} - </LayoutTrellisLine> - <LayoutTrellisLine - basis={{ - label: { - value: `${$t(`common.description`)}`, - }, - }} - > - <EntryMultiline + </LayoutTrellisLine> + <LayoutTrellisLine basis={{ - wrap: { - id: fmt_id(`summary_wrap`), + label: { + value: `${$t(`icu.*_quantity`, { value: `${$t(`common.order`)}` })}`, }, - el: { - classes: `h-[7rem]`, - id: fmt_id(`summary`), - sync: true, - placeholder: `${$t(`icu.enter_the_*`, { value: `${$t(`icu.*_description`, { value: `${$t(`common.listing`)}` })}`.toLowerCase() })}`, - field: { - charset: - trade_product_form_fields.summary - .charset, - validate: - trade_product_form_fields.summary - .validation, - validate_keypress: true, - }, + notify: tradepr_qty_tup_sel_toggle + ? { + label: { + value: `${$t(`common.close`)}`, + }, + callback: async () => { + await handle_tradepr_qty_amt_toggle( + false, + ); + }, + } + : undefined, + }} + > + {#if !tradepr_qty_tup_sel_toggle} + <EntrySelect + bind:value={$tradepr_qty_tup_sel} + basis={{ + wrap: { + id: fmt_id(`qty_wrap`), + layer: 1, + }, + el: { + layer: 1, + options: [ + { + entries: [ + { + value: ``, + label: `${$t(`icu.choose_*`, { value: `${$t(`common.quantity`)}`.toLowerCase() })}`, + disabled: true, + }, + ...tradepr_key_quantities_list.map( + (i) => ({ + value: fmt_trade_quantity_tup( + i, + ), + label: `${i.mass} ${$t(`measurement.mass.unit.${i.mass_unit}_ab`)} ${i.label}`, + }), + ), + { + value: ``, + label: `${$t(`common.other`)}`, + }, + ], + }, + ], + callback: async ({ value }) => { + el_id( + fmt_id(`qty_wrap`), + )?.classList.remove( + `entry-layer-1-highlight`, + ); + if (value === ``) { + await handle_tradepr_qty_amt_toggle( + true, + ); + } + }, + }, + }} + /> + {:else} + <EntryWrap + basis={{ + id: fmt_id(`qty_wrap`), + layer: 1, + }} + > + <InputElement + basis={{ + id: fmt_id(`qty_amt`), + sync: true, + layer: 1, + placeholder: `${$t(`icu.enter_*_per_order`, { value: `${$t(`measurement.mass.unit.${tradepr_qty_unit_sel}_ab`)}`.toLowerCase() })}`, + field: { + charset: + trade_product_form_fields + .qty_amt.charset, + validate: + trade_product_form_fields + .qty_amt.validation, + validate_keypress: true, + }, + }} + /> + <div + class={`flex flex-row gap-2 justify-end items-center`} + > + <SelectElement + bind:value={tradepr_qty_unit_sel} + basis={{ + id: fmt_id(`qty_unit`), + sync: true, + layer: 1, + classes: `w-fit font-sans font-[400] text-[1.05rem] text-layer-1-glyph_d`, + show_arrows: `r`, + options: [ + { + entries: mass_units.map( + (i) => ({ + value: i, + label: `${$t(`measurement.mass.unit.${i}_ab`)}`, + }), + ), + }, + ], + }} + /> + </div> + </EntryWrap> + {/if} + </LayoutTrellisLine> + <LayoutTrellisLine + basis={{ + label: { + value: `${$t(`common.description`)}`, }, }} - /> - </LayoutTrellisLine> - </LayoutTrellis> - </div> - <div - data-carousel-item={`c_1`} - class={`carousel-item flex flex-col w-full justify-start items-center`} - > - <LayoutTrellis> - <div - class={`flex flex-col w-full justify-center items-center`} - > + > + <EntryMultiline + basis={{ + wrap: { + id: fmt_id(`summary_wrap`), + }, + el: { + classes: `h-[7rem]`, + id: fmt_id(`summary`), + sync: true, + placeholder: `${$t(`icu.enter_the_*`, { value: `${$t(`icu.*_description`, { value: `${$t(`common.listing`)}` })}`.toLowerCase() })}`, + field: { + charset: + trade_product_form_fields + .summary.charset, + validate: + trade_product_form_fields + .summary.validation, + validate_keypress: true, + }, + }, + }} + /> + </LayoutTrellisLine> + </LayoutTrellis> + </div> + <div + data-carousel-item={`c_1`} + class={`carousel-item flex flex-col w-full justify-start items-center`} + > + <LayoutTrellis> <div - class={`flex flex-col h-auto w-${$app_layout} justify-start items-start bg-layer-1-surface rounded-[2rem] overflow-hidden`} + class={`flex flex-col w-full justify-center items-center`} > <div - class={`flex flex-row h-[3rem] w-full justify-center items-center`} - > - <p - class={`font-sans font-[400] text-[1.05rem] text-layer-1-glyph_d`} - > - {`${$t(`common.listing`)}`} - </p> - </div> - <div - class={`flex flex-col w-full px-4 justify-start items-center`} + class={`flex flex-col h-auto w-${$app_layout} justify-start items-start bg-layer-1-surface rounded-[2rem] overflow-hidden`} > <div - class={`flex flex-col h-auto w-full py-6 gap-[5px] justify-center items-start border-t-line border-layer-0-glyph_d`} + class={`flex flex-row h-[3rem] w-full justify-center items-center`} > - <TradeFieldDisplayKv - basis={{ - visible: $carousel_index === 2, - label: `${$t(`common.title`)}`, - display: { - kv: `title`, - undef: `${$t(`icu.no_*`, { value: `${$t(`common.title`)}`.toLowerCase() })}`, - }, - handle_back: async () => { - await handle_back(2); - }, - }} - /> - <TradeFieldDisplayKv - basis={{ - visible: $carousel_index === 2, - label: `${$t(`common.product`)}`, - display: { - kv: `key`, - undef: `${$t(`icu.no_*`, { value: `${$t(`common.product`)}`.toLowerCase() })}`, - }, - handle_back: async () => { - await handle_back(2); - }, - }} - /> - <TradeFieldDisplayKv - basis={{ - visible: $carousel_index === 2, - label: `${$t(`common.process`)}`, - display: { - kv: `process`, - undef: `${$t(`icu.no_*`, { value: `${$t(`common.process`)}`.toLowerCase() })}`, - }, - handle_back: async () => { - await handle_back(2); - }, - }} - /> - <TradeFieldDisplayKv - basis={{ - visible: $carousel_index === 2, - kv_wrap: `tradepr_location_wrap`, - label: `${$t(`common.location`)}`, - display: { - value: tradepr_lgc_sel_geoc - ? `${tradepr_lgc_sel_geoc.name}, ${tradepr_lgc_sel_geoc.admin1_name}, ${tradepr_lgc_sel_geoc.country_id}` - : ``, - undef: `${$t(`icu.no_*`, { value: `${$t(`common.location`)}`.toLowerCase() })}`, - }, - handle_back: async () => { - await handle_back(2); - }, - }} - /> - <TradeFieldDisplayKv - basis={{ - visible: $carousel_index === 2, - label: `${$t(`common.lot`)}`, - display: { - kv: `lot`, - undef: `${$t(`icu.no_*`, { value: `${$t(`common.lot`)}`.toLowerCase() })}`, - }, - handle_back: async () => { - await handle_back(1); - }, - }} - /> - <TradeFieldDisplayKv - basis={{ - visible: $carousel_index === 2, - label: `${$t(`common.description`)}`, - display: { - kv: `summary`, - undef: `${$t(`icu.no_*`, { value: `${$t(`common.description`)}`.toLowerCase() })}`, - }, - handle_back: async () => { - await handle_back(1); - }, - }} - /> + <p + class={`font-sans font-[400] text-[1.05rem] text-layer-1-glyph_d`} + > + {`${$t(`common.listing`)}`} + </p> </div> <div - class={`flex flex-col h-auto w-full py-6 gap-[5px] justify-center items-start border-t-line border-layer-0-glyph_d`} + class={`flex flex-col w-full px-4 justify-start items-center`} > - <TradeFieldDisplayKv - basis={{ - visible: $carousel_index === 2, - label: `${$t(`common.price`)}`, - kv_wrap: `price_wrap`, - display: { - value: - tradepr_cprice_amt && - tradepr_price_qty_unit_sel - ? `${fmt_currency_price(tradepr_cprice_amt)} / ${`${$t(`measurement.mass.unit.${tradepr_price_qty_unit_sel}_ab`)}`.toLowerCase()}` + <div + class={`flex flex-col h-auto w-full py-6 gap-[5px] justify-center items-start border-t-line border-layer-0-glyph_d`} + > + <TradeFieldDisplayKv + basis={{ + visible: $carousel_index === 2, + label: `${$t(`common.title`)}`, + display: { + kv: `title`, + undef: `${$t(`icu.no_*`, { value: `${$t(`common.title`)}`.toLowerCase() })}`, + }, + handle_back: async () => { + await handle_back(2); + }, + }} + /> + <TradeFieldDisplayKv + basis={{ + visible: $carousel_index === 2, + label: `${$t(`common.product`)}`, + display: { + kv: `key`, + undef: `${$t(`icu.no_*`, { value: `${$t(`common.product`)}`.toLowerCase() })}`, + }, + handle_back: async () => { + await handle_back(2); + }, + }} + /> + <TradeFieldDisplayKv + basis={{ + visible: $carousel_index === 2, + label: `${$t(`common.process`)}`, + display: { + kv: `process`, + undef: `${$t(`icu.no_*`, { value: `${$t(`common.process`)}`.toLowerCase() })}`, + }, + handle_back: async () => { + await handle_back(2); + }, + }} + /> + <TradeFieldDisplayKv + basis={{ + visible: $carousel_index === 2, + kv_wrap: `tradepr_location_wrap`, + label: `${$t(`common.location`)}`, + display: { + value: tradepr_lgc_sel_geoc + ? `${tradepr_lgc_sel_geoc.name}, ${tradepr_lgc_sel_geoc.admin1_name}, ${tradepr_lgc_sel_geoc.country_id}` : ``, - undef: `${$t(`icu.no_*`, { value: `${$t(`common.price`)}`.toLowerCase() })}`, - nostyle: true, - }, - handle_back: async () => { - await handle_back(1); - }, - }} - /> - <TradeFieldDisplayKv - basis={{ - visible: $carousel_index === 2, - label: `${$t(`icu.*_quantity`, { value: `${$t(`common.order`)}` })}`, - display: { - value: tradepr_parsed_quantity - ? `${tradepr_parsed_quantity.mass} ${`${$t(`measurement.mass.unit.${tradepr_parsed_quantity.mass_unit}_ab`)}`.toLowerCase()} ${tradepr_parsed_quantity.label || `${$t(`common.bag`)}`}` - : ``, - undef: `${$t(`icu.no_*`, { value: `${$t(`icu.*_quantity`, { value: `${$t(`common.order`)}` })}` })}`, - nostyle: - !!tradepr_parsed_quantity, - }, - kv_wrap: `qty_wrap`, - handle_back: async () => { - await handle_back(1); - }, - }} - /> - <TradeFieldDisplayEl - basis={{ - visible: $carousel_index === 2, - label: `${$t(`icu.*_available`, { value: `${$t(`common.quantity`)}` })}${tradepr_parsed_quantity ? ` (${$tradepr_qty_avail})` : ``}`, - display: { - classes: tradepr_parsed_quantity - ? `` - : `pr-4`, - value: tradepr_parsed_quantity - ? ascii.bullet - : ``, - hide: !!tradepr_parsed_quantity, - undef: ascii.dash, - }, - }} + undef: `${$t(`icu.no_*`, { value: `${$t(`common.location`)}`.toLowerCase() })}`, + }, + handle_back: async () => { + await handle_back(2); + }, + }} + /> + <TradeFieldDisplayKv + basis={{ + visible: $carousel_index === 2, + label: `${$t(`common.lot`)}`, + display: { + kv: `lot`, + undef: `${$t(`icu.no_*`, { value: `${$t(`common.lot`)}`.toLowerCase() })}`, + }, + handle_back: async () => { + await handle_back(1); + }, + }} + /> + <TradeFieldDisplayKv + basis={{ + visible: $carousel_index === 2, + label: `${$t(`common.description`)}`, + display: { + kv: `summary`, + undef: `${$t(`icu.no_*`, { value: `${$t(`common.description`)}`.toLowerCase() })}`, + }, + handle_back: async () => { + await handle_back(1); + }, + }} + /> + </div> + <div + class={`flex flex-col h-auto w-full py-6 gap-[5px] justify-center items-start border-t-line border-layer-0-glyph_d`} > - {#if tradepr_parsed_quantity} - <div - class={`flex flex-row gap-2 pl-2 pr-1 justify-center items-center`} - > - <button - class={`group flex flex-row justify-center items-center`} - on:click={async () => { - tradepr_qty_avail.set( - int_step( - $tradepr_qty_avail, - `-`, - 1, - ), - ); - }} + <TradeFieldDisplayKv + basis={{ + visible: $carousel_index === 2, + label: `${$t(`common.price`)}`, + kv_wrap: `price_wrap`, + display: { + value: + tradepr_cprice_amt && + tradepr_price_qty_unit_sel + ? `${fmt_currency_price(tradepr_cprice_amt)} / ${`${$t(`measurement.mass.unit.${tradepr_price_qty_unit_sel}_ab`)}`.toLowerCase()}` + : ``, + undef: `${$t(`icu.no_*`, { value: `${$t(`common.price`)}`.toLowerCase() })}`, + nostyle: true, + }, + handle_back: async () => { + await handle_back(1); + }, + }} + /> + <TradeFieldDisplayKv + basis={{ + visible: $carousel_index === 2, + label: `${$t(`icu.*_quantity`, { value: `${$t(`common.order`)}` })}`, + display: { + value: tradepr_parsed_quantity + ? `${tradepr_parsed_quantity.mass} ${`${$t(`measurement.mass.unit.${tradepr_parsed_quantity.mass_unit}_ab`)}`.toLowerCase()} ${tradepr_parsed_quantity.label || `${$t(`common.bag`)}`}` + : ``, + undef: `${$t(`icu.no_*`, { value: `${$t(`icu.*_quantity`, { value: `${$t(`common.order`)}` })}` })}`, + nostyle: + !!tradepr_parsed_quantity, + }, + kv_wrap: `qty_wrap`, + handle_back: async () => { + await handle_back(1); + }, + }} + /> + <TradeFieldDisplayEl + basis={{ + visible: $carousel_index === 2, + label: `${$t(`icu.*_available`, { value: `${$t(`common.quantity`)}` })}${tradepr_parsed_quantity ? ` (${$tradepr_qty_avail})` : ``}`, + display: { + classes: + tradepr_parsed_quantity + ? `` + : `pr-4`, + value: tradepr_parsed_quantity + ? ascii.bullet + : ``, + hide: !!tradepr_parsed_quantity, + undef: ascii.dash, + }, + }} + > + {#if tradepr_parsed_quantity} + <div + class={`flex flex-row gap-2 pl-2 pr-1 justify-center items-center`} > - <Glyph - basis={{ - key: `arrow-down`, - dim: `xs`, - classes: `h-[1.3rem] w-[1.3rem] text-layer-1-glyph_d bg-layer-2-surface/60 rounded-full el-re`, + <button + class={`group flex flex-row justify-center items-center`} + on:click={async () => { + tradepr_qty_avail.set( + int_step( + $tradepr_qty_avail, + `-`, + 1, + ), + ); }} - /> - </button> - <button - class={`group flex flex-row justify-center items-center`} - on:click={async () => { - tradepr_qty_avail.set( - int_step( - $tradepr_qty_avail, - `+`, - ), - ); - }} - > - <Glyph - basis={{ - key: `arrow-up`, - dim: `xs`, - classes: `h-[1.3rem] w-[1.3rem] text-layer-1-glyph_d bg-layer-2-surface/60 rounded-full el-re`, + > + <Glyph + basis={{ + key: `arrow-down`, + dim: `xs`, + classes: `h-[1.3rem] w-[1.3rem] text-layer-1-glyph_d bg-layer-2-surface/60 rounded-full el-re`, + }} + /> + </button> + <button + class={`group flex flex-row justify-center items-center`} + on:click={async () => { + tradepr_qty_avail.set( + int_step( + $tradepr_qty_avail, + `+`, + ), + ); }} - /> - </button> - </div> - {/if} - </TradeFieldDisplayEl> - <TradeFieldDisplayEl - basis={{ - visible: $carousel_index === 2, - label: `${$t(`icu.*_total`, { value: `${$t(`common.quantity`)}` })}`, - display: { - classes: tradepr_parsed_quantity - ? `pr-2` - : `pr-4`, - value: tradepr_parsed_quantity - ? `${Number( - $tradepr_qty_avail * - tradepr_parsed_quantity.mass, - ).toFixed( - 2, - )} ${`${$t(`measurement.mass.unit.${tradepr_parsed_quantity.mass_unit}_ab`)}`.toLowerCase()}` - : ``, - undef: ascii.dash, - nostyle: true, - }, - }} - /> - </div> - <div - class={`flex flex-col h-auto w-full pb-6 gap-[5px] justify-center items-start`} - > - <TradeFieldDisplayEl - basis={{ - visible: $carousel_index === 2, - label: `${$t(`icu.*_total`, { value: `${$t(`common.order`)}` })}`, - display: { - classes: - tradepr_parsed_quantity && - tradepr_cprice_amt - ? `pr-2` - : `pr-4`, - value: tradepr_cprice_total - ? `${fmt_currency_price(tradepr_cprice_total)}` - : ``, - undef: ascii.dash, - }, - }} - /> + > + <Glyph + basis={{ + key: `arrow-up`, + dim: `xs`, + classes: `h-[1.3rem] w-[1.3rem] text-layer-1-glyph_d bg-layer-2-surface/60 rounded-full el-re`, + }} + /> + </button> + </div> + {/if} + </TradeFieldDisplayEl> + <TradeFieldDisplayEl + basis={{ + visible: $carousel_index === 2, + label: `${$t(`icu.*_total`, { value: `${$t(`common.quantity`)}` })}`, + display: { + classes: + tradepr_parsed_quantity + ? `pr-2` + : `pr-4`, + value: tradepr_parsed_quantity + ? `${Number( + $tradepr_qty_avail * + tradepr_parsed_quantity.mass, + ).toFixed( + 2, + )} ${`${$t(`measurement.mass.unit.${tradepr_parsed_quantity.mass_unit}_ab`)}`.toLowerCase()}` + : ``, + undef: ascii.dash, + nostyle: true, + }, + }} + /> + </div> + <div + class={`flex flex-col h-auto w-full pb-6 gap-[5px] justify-center items-start`} + > + <TradeFieldDisplayEl + basis={{ + visible: $carousel_index === 2, + label: `${$t(`icu.*_total`, { value: `${$t(`common.order`)}` })}`, + display: { + classes: + tradepr_parsed_quantity && + tradepr_cprice_amt + ? `pr-2` + : `pr-4`, + value: tradepr_cprice_total + ? `${fmt_currency_price(tradepr_cprice_total)}` + : ``, + undef: ascii.dash, + }, + }} + /> + </div> </div> </div> </div> - </div> - <button - class={`flex flex-row h-12 w-${$app_layout} justify-center items-center bg-layer-1-glyph-hl active:bg-layer-1-glyph-hl_a round-40 font-sans font-[600] text-[1.1rem] text-white capitalize el-re`} - on:click={async () => { - await submit(); - }} - > - {`${$t(`common.post`)}`} - </button> - </LayoutTrellis> + <button + class={`flex flex-row h-12 w-${$app_layout} justify-center items-center bg-layer-1-glyph-hl active:bg-layer-1-glyph-hl_a round-40 font-sans font-[600] text-[1.1rem] text-white capitalize el-re`} + on:click={async () => { + await submit(); + }} + > + {`${$t(`common.post`)}`} + </button> + </LayoutTrellis> + </div> </div> </div> - </div> -</LayoutView> - + </LayoutView> +{/if} <Nav basis={{ prev: { diff --git a/src/routes/(cfg)/cfg/init/+page.svelte b/src/routes/(cfg)/cfg/init/+page.svelte @@ -89,10 +89,6 @@ const unlisten_1 = await keystore.on_key_change( ks.cfg_init.nostr_secretkey, async (_cfg_init_nostr_secretkey) => { - console.log( - `_cfg_init_nostr_secretkey `, - _cfg_init_nostr_secretkey, - ); if (_cfg_init_nostr_secretkey) { cfg_main_nostr_publickey = nostr.lib.secretkey_to_publickey( @@ -578,10 +574,6 @@ const ks_nostr_secretkey = await keystore.get( ks.cfg_init.nostr_secretkey, ); - console.log( - JSON.stringify(ks_nostr_secretkey, null, 4), - `ks_nostr_secretkey`, - ); if (`err` in ks_nostr_secretkey) { await dialog.alert( `${$t(`error.device.configuration_failure`)}`, diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte @@ -1,7 +1,10 @@ <script lang="ts"> - import { device, dialog, http, os } from "$lib/client"; + import { device, dialog, http, logger, os } from "$lib/client"; import { cfg } from "$lib/conf"; - import type { IClientDeviceMetadata } from "@radroots/client"; + import type { + IClientDeviceMetadata, + IClientUnlisten, + } from "@radroots/client"; import { app_db, app_geoc, @@ -28,7 +31,7 @@ import "../app.css"; let route_render: NavigationRoute | undefined = undefined; - + let log_unlisten: IClientUnlisten | undefined = undefined; onMount(async () => { try { if (`paintWorklet` in CSS) @@ -40,6 +43,7 @@ }; await device.init(metadata); await http.init(metadata); + log_unlisten = await logger.init(); } catch (e) { } finally { } @@ -48,6 +52,7 @@ onDestroy(async () => { try { route_render = undefined; + if (log_unlisten) log_unlisten(); } catch (e) { } finally { }