commit 5b5b105959c112b9c0dc5d7b9d420408f03aaa58
parent 7adf36d33c38d5d04e6bdabc19db65a6f3e1463b
Author: triesap <137732411+triesap@users.noreply.github.com>
Date: Sun, 10 Nov 2024 06:58:37 +0000
Edit `models/trade-product/add` add model fields input and select elements, add map location point selection envelope.
Diffstat:
3 files changed, 561 insertions(+), 178 deletions(-)
diff --git a/src/lib/components/map_point_select_envelope.svelte b/src/lib/components/map_point_select_envelope.svelte
@@ -0,0 +1,123 @@
+<script lang="ts">
+ import { geoc } from "$lib/client";
+ import { cfg } from "$lib/conf";
+ import type { GeocoderReverseResult } from "@radroots/geocoder";
+ import {
+ app_thc,
+ envelope_visible,
+ EnvelopeLower,
+ fmt_geol_latitude,
+ fmt_geol_longitude,
+ t,
+ type CallbackPromise,
+ } from "@radroots/svelte-lib";
+ import { MapLibre, Marker } from "@radroots/svelte-maplibre";
+ import type { GeolocationCoordinatesPoint } from "@radroots/utils";
+ import MapMarkerDot from "./map_marker_dot.svelte";
+ import MapPopupPointGeolocation from "./map_popup_point_geolocation.svelte";
+
+ export let map_point_select: GeolocationCoordinatesPoint | undefined;
+ export let map_point_select_geoc: GeocoderReverseResult | undefined =
+ undefined;
+
+ export let basis: {
+ visible: Boolean;
+ close: CallbackPromise;
+ };
+
+ let map_point_center: GeolocationCoordinatesPoint = cfg.map.coords.default;
+
+ $: envelope_visible.set(!!basis.visible);
+
+ $: if (
+ map_point_select &&
+ map_point_center.lat === 0 &&
+ map_point_center.lng === 0
+ ) {
+ map_point_center = {
+ lat: map_point_select.lat,
+ lng: map_point_select.lng - 0.065,
+ };
+ }
+
+ $: {
+ if (
+ map_point_select &&
+ map_point_center &&
+ map_point_center.lat !== 0 &&
+ map_point_center.lng !== 0
+ ) {
+ (async () => {
+ try {
+ const geoc_res = await geoc.reverse({
+ point: map_point_select,
+ });
+ if (`results` in geoc_res && geoc_res.results.length > 0)
+ map_point_select_geoc = geoc_res.results[0];
+ else map_point_select_geoc = undefined;
+ } catch (e) {
+ console.log(`(error) map choose location`, e);
+ }
+ })();
+ }
+ }
+</script>
+
+<EnvelopeLower
+ basis={{
+ full_cover: true,
+ close: async () => {
+ await basis.close();
+ },
+ }}
+>
+ {#if basis.visible && map_point_select}
+ <MapLibre
+ center={map_point_center}
+ zoom={10}
+ class={`h-full w-full`}
+ style={cfg.map.styles.base[$app_thc]}
+ attributionControl={false}
+ >
+ <Marker
+ bind:lngLat={map_point_select}
+ draggable
+ on:dragend={async () => {
+ if (!map_point_select) return;
+ const geoc_res = await geoc.reverse({
+ point: map_point_select,
+ limit: 1,
+ });
+ if (`results` in geoc_res && geoc_res.results.length > 0)
+ map_point_select_geoc = geoc_res.results[0];
+ }}
+ >
+ <button
+ class={`flex flex-row justify-center items-center transform -translate-x-[42%]`}
+ on:click={async () => {}}
+ >
+ <MapPopupPointGeolocation
+ basis={{
+ point: map_point_select,
+ geoc: map_point_select_geoc,
+ }}
+ />
+ </button>
+ <MapMarkerDot />
+ </Marker>
+ </MapLibre>
+ <div
+ class={`absolute top-6 left-4 flex flex-col min-w-[180px] px-4 py-1 justify-start items-start bg-layer-1-surface rounded-xl shadow-md`}
+ >
+ <p class={`font-sans font-[400] text-layer-0-glyph capitalize`}>
+ {`${`${$t(`common.current_location`)}`}:`}
+ </p>
+ <p class={`font-sans font-[400] text-layer-0-glyph`}>
+ {`${fmt_geol_latitude(map_point_select.lat, `dms`)}`}
+ </p>
+ <p class={`font-sans font-[400] text-layer-0-glyph`}>
+ {`${fmt_geol_longitude(map_point_select.lng, `dms`)}`}
+ </p>
+ </div>
+ {/if}
+</EnvelopeLower>
diff --git a/src/lib/components/map_select_point.svelte b/src/lib/components/map_select_point.svelte
@@ -1,105 +0,0 @@
-<script lang="ts">
- import { geoc } from "$lib/client";
- import { cfg } from "$lib/conf";
- import type { GeocoderReverseResult } from "@radroots/geocoder";
- import { app_thc, fmt_cl, sleep } from "@radroots/svelte-lib";
- import { MapLibre, Marker } from "@radroots/svelte-maplibre";
- import type { GeolocationCoordinatesPoint } from "@radroots/utils";
- import { onMount } from "svelte";
- import MapMarkerDot from "./map_marker_dot.svelte";
- import MapPopupPointGeolocation from "./map_popup_point_geolocation.svelte";
-
- export let basis: {
- classes_wrap?: string;
- classes?: string;
- };
- $: basis = basis;
-
- let map_visible = false;
-
- export let map_point_select: GeolocationCoordinatesPoint;
- export let map_point_select_geoc: GeocoderReverseResult | undefined =
- undefined;
-
- let map_point_center: GeolocationCoordinatesPoint = cfg.map.coords.default;
-
- onMount(async () => {
- try {
- await sleep(300);
- } catch (e) {
- } finally {
- map_visible = true;
- }
- });
-
- $: if (!map_visible) {
- map_point_center = {
- lat: map_point_select.lat,
- lng: map_point_select.lng - 0.065,
- };
- }
-
- $: {
- if (
- map_point_center &&
- map_point_center.lat !== 0 &&
- map_point_center.lng !== 0
- ) {
- (async () => {
- try {
- const geoc_res = await geoc.reverse({
- point: map_point_select,
- });
- if (`results` in geoc_res && geoc_res.results.length > 0)
- map_point_select_geoc = geoc_res.results[0];
- else map_point_select_geoc = undefined;
- } catch (e) {
- console.log(`(error) map choose location`, e);
- }
- })();
- }
- }
-</script>
-
-<div
- class={`${fmt_cl(basis.classes_wrap)} flex flex-col justify-start items-center`}
->
- <div
- class={`relative flex flex-col w-full justify-center items-center bg-layer-1-surface overflow-hidden`}
- >
- <MapLibre
- center={map_point_center}
- zoom={10}
- class={`${fmt_cl(basis.classes || `h-full w-full`)} ${map_visible ? `fade-in` : `hidden`}`}
- style={cfg.map.styles.base[$app_thc]}
- attributionControl={false}
- >
- <Marker
- bind:lngLat={map_point_select}
- draggable
- on:dragend={async () => {
- if (!map_point_select) return;
- const geoc_res = await geoc.reverse({
- point: map_point_select,
- limit: 1,
- });
- if (`results` in geoc_res && geoc_res.results.length > 0)
- map_point_select_geoc = geoc_res.results[0];
- }}
- >
- <button
- class={`flex flex-row justify-center items-center transform -translate-x-[42%]`}
- on:click={async () => {}}
- >
- <MapPopupPointGeolocation
- basis={{
- point: map_point_select,
- geoc: map_point_select_geoc,
- }}
- />
- </button>
- <MapMarkerDot />
- </Marker>
- </MapLibre>
- </div>
-</div>
diff --git a/src/routes/(app)/models/trade-product/add/+page.svelte b/src/routes/(app)/models/trade-product/add/+page.svelte
@@ -1,24 +1,37 @@
<script lang="ts">
+ import { dialog, geol } from "$lib/client";
import ImageUploadMulti from "$lib/components/image_upload_multi.svelte";
+ import MapPointSelectEnvelope from "$lib/components/map_point_select_envelope.svelte";
import { tradeproduct_init_kv } from "$lib/utils/trade_product";
+ import type { GeocoderReverseResult } from "@radroots/geocoder";
+ import { trade_product_form_fields } from "@radroots/models";
import {
carousel_index,
carousel_index_max,
carousel_num,
+ el_id,
+ EntryLine,
+ EntrySelect,
fmt_id,
+ kv,
layout_view_cover,
LayoutTrellis,
+ LayoutTrellisLine,
LayoutView,
Nav,
t,
view_effect,
} from "@radroots/svelte-lib";
- import { type TradeKey } from "@radroots/utils";
+ import {
+ parse_trade_key,
+ trade,
+ trade_keys,
+ type GeolocationCoordinatesPoint,
+ type TradeKey,
+ } from "@radroots/utils";
import { onMount } from "svelte";
import { fade } from "svelte/transition";
- const CAROUSEL_INDEX_MAP = 2;
-
type CarouselParam = {
label_prev?: string;
label_next: string;
@@ -71,10 +84,28 @@
let load_submit = false;
+ let tradeproduct_photo_paths: string[] = [];
+
let tradeproduct_key_sel_toggle = false;
let tradeproduct_key_sel = ``;
+ $: tradeproduct_key_parsed = parse_trade_key(tradeproduct_key_sel);
+ $: tradeproduct_key_quantities_list = tradeproduct_key_parsed
+ ? trade.key[tradeproduct_key_parsed].quantity
+ : trade.default.quantity;
- let photo_add_paths: string[] = [];
+ let tradeproduct_process_sel = ``;
+ let tradeproduct_process_sel_toggle = false;
+ $: tradeproduct_process_list = tradeproduct_key_parsed
+ ? trade.key[tradeproduct_key_parsed].process
+ : [];
+
+ let tradeproduct_location_sel = ``;
+ let tradeproduct_location_select_vis = false;
+ let tradeproduct_location_select_point:
+ | GeolocationCoordinatesPoint
+ | undefined = undefined;
+ let tradeproduct_location_select_geoc: GeocoderReverseResult | undefined =
+ undefined;
onMount(async () => {
try {
@@ -90,8 +121,6 @@
const setup_tests = async (): Promise<void> => {
try {
- //const photo1 = `file:///Users/treesap/Library/Developer/CoreSimulator/Devices/04252089-B59A-4955-B1E0-84ECBAC1C28D/data/Containers/Data/Application/73E35A31-5CCD-4C1A-97C3-B5FA617DDB80/Library/Caches/IMG_0111.jpeg`;
- //photo_add_list_paths = [photo1];
} catch (e) {
console.log(`(error) setup_tests `, e);
}
@@ -99,13 +128,6 @@
const handle_view = async (view_new: View): Promise<void> => {
try {
- /*
- const index_max_new = page_param.carousel[view_new].size - 1;
- carousel_index_max.set(index_max_new);
- if (view === `fl_2` && view_new === `fl_1`)
- carousel_index.set(index_max_new);
- else carousel_index.set(0);
- */
carousel_index.set(0);
view = view_new;
} catch (e) {
@@ -113,6 +135,60 @@
}
};
+ const handle_tradeproduct_key_toggle = async (
+ vis_input: boolean,
+ ): Promise<void> => {
+ try {
+ const kv_curr = await kv.get(fmt_id(`key`));
+ if (kv_curr) {
+ const confirm = await dialog.confirm({
+ message: `${$t(`icu.the_current_entry_*_will_be_deleted`, { value: kv_curr })}. ${$t(`common.do_you_want_to_continue_q`)}`,
+ });
+ if (!confirm) return;
+ }
+ tradeproduct_key_sel_toggle = vis_input;
+ if (vis_input) tradeproduct_key_sel = ``;
+ } catch (e) {
+ console.log(`(error) handle_tradeproduct_key_toggle `, e);
+ }
+ };
+
+ const handle_tradeproduct_process_toggle = async (
+ vis_input: boolean,
+ ): Promise<void> => {
+ try {
+ const kv_curr = await kv.get(fmt_id(`process`));
+ if (kv_curr) {
+ const confirm = await dialog.confirm({
+ message: `${$t(`icu.the_current_entry_*_will_be_deleted`, { value: kv_curr })}. ${$t(`common.do_you_want_to_continue_q`)}`,
+ });
+ if (!confirm) return;
+ }
+ tradeproduct_process_sel_toggle = vis_input;
+ if (vis_input) tradeproduct_process_sel = ``;
+ } catch (e) {
+ console.log(`(error) handle_tradeproduct_process_toggle `, e);
+ }
+ };
+
+ const handle_tradeproduct_location_sel_map_select =
+ async (): Promise<void> => {
+ try {
+ const geolc = await geol.current();
+ if (`err` in geolc) return; //@todo
+ tradeproduct_location_select_vis = true;
+ tradeproduct_location_select_point = {
+ lat: geolc.lat,
+ lng: geolc.lng,
+ };
+ } catch (e) {
+ console.log(
+ `(error) handle_tradeproduct_location_sel_map_select `,
+ e,
+ );
+ }
+ };
+
const handle_back = async (): Promise<void> => {
try {
} catch (e) {
@@ -130,11 +206,11 @@
{
console.log(
JSON.stringify(
- photo_add_paths,
+ tradeproduct_photo_paths,
null,
4,
),
- `photo_add_paths`,
+ `tradeproduct_photo_paths`,
);
}
break;
@@ -169,71 +245,360 @@
class={`carousel-item flex flex-col w-full justify-start items-center`}
>
<LayoutTrellis>
- <ImageUploadMulti bind:photo_paths={photo_add_paths} />
+ <ImageUploadMulti
+ bind:photo_paths={tradeproduct_photo_paths}
+ />
+ <LayoutTrellisLine
+ basis={{
+ label: {
+ value: `${$t(`common.product`)}`,
+ },
+ notify: tradeproduct_key_sel_toggle
+ ? {
+ label: {
+ value: `${$t(`common.close`)}`,
+ },
+ callback: async () => {
+ await handle_tradeproduct_key_toggle(
+ false,
+ );
+ },
+ }
+ : undefined,
+ }}
+ >
+ {#if !tradeproduct_key_sel_toggle}
+ <EntrySelect
+ bind:value={tradeproduct_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`, { default: i })}`,
+ })),
+ {
+ 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_tradeproduct_key_toggle(
+ true,
+ );
+ tradeproduct_key_sel = ``;
+ tradeproduct_process_sel = ``;
+ } else {
+ tradeproduct_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.lot`)}`,
+ },
+ }}
+ >
+ <EntryLine
+ basis={{
+ wrap: {
+ id: fmt_id(`lot_wrap`),
+ layer: 1,
+ },
+ el: {
+ id: fmt_id(`lot`),
+ layer: 1,
+ sync: true,
+ classes: `fade-in-long`,
+ 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,
+ },
+ },
+ }}
+ />
+ </LayoutTrellisLine>
+ <LayoutTrellisLine
+ basis={{
+ label: {
+ value: `${$t(`common.process`)}`,
+ },
+ notify: tradeproduct_process_sel_toggle
+ ? {
+ label: {
+ value: `${$t(`common.close`)}`,
+ },
+ callback: async () => {
+ await handle_tradeproduct_process_toggle(
+ false,
+ );
+ },
+ }
+ : undefined,
+ }}
+ >
+ {#if !tradeproduct_process_sel_toggle}
+ <EntrySelect
+ bind:value={tradeproduct_process_sel}
+ basis={{
+ wrap: {
+ id: fmt_id(`process_wrap`),
+ layer: 1,
+ },
+ el: {
+ id: fmt_id(`process`),
+ sync: true,
+ layer: 1,
+ options: [
+ {
+ entries: [
+ {
+ value: ``,
+ label: `${$t(`icu.choose_*`, { value: `${$t(`common.process`)}`.toLowerCase() })}`,
+ disabled: true,
+ },
+ ...tradeproduct_process_list.map(
+ (i) => ({
+ value: i,
+ label: `${$t(`trade.product.key.${tradeproduct_key_parsed}.process.${i}`)}`,
+ }),
+ ),
+ {
+ value: ``,
+ label: `${$t(`common.other`)}`,
+ },
+ ],
+ },
+ ],
+ callback: async ({ value }) => {
+ el_id(
+ fmt_id(`process_wrap`),
+ )?.classList.remove(
+ `entry-layer-1-highlight`,
+ );
+ if (!value) {
+ await handle_tradeproduct_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={tradeproduct_location_sel}
+ basis={{
+ wrap: {
+ id: fmt_id(`tradeproduct_location_wrap`),
+ layer: 1,
+ },
+ el: {
+ id: fmt_id(`tradeproduct_location`),
+ sync: true,
+ layer: 1,
+ options: [
+ {
+ entries:
+ tradeproduct_location_select_geoc
+ ? [
+ {
+ value: `map-select`,
+ label: `${tradeproduct_location_select_geoc.name}, ${tradeproduct_location_select_geoc.admin1_name}, ${tradeproduct_location_select_geoc.country_id}`,
+ },
+ {
+ value: `map-select`,
+ label: `Choose new location`,
+ },
+ ]
+ : [
+ {
+ value: ``,
+ label: `${$t(`icu.choose_*`, { value: `${$t(`common.location`)}`.toLowerCase() })}`,
+ disabled: true,
+ },
+ {
+ value: `map-select`,
+ label: `Choose on map`,
+ },
+ {
+ value: ``,
+ label: `Clear`,
+ },
+ ],
+ },
+ ],
+ callback: async ({ value }) => {
+ el_id(
+ fmt_id(`process_wrap`),
+ )?.classList.remove(
+ `entry-layer-1-highlight`,
+ );
+ if (!value) {
+ //@todo
+ } else if (value === `map-select`) {
+ await handle_tradeproduct_location_sel_map_select();
+ }
+ },
+ },
+ }}
+ />
+ </LayoutTrellisLine>
</LayoutTrellis>
</div>
</div>
</div>
</LayoutView>
-{#if $carousel_index !== CAROUSEL_INDEX_MAP}
- <div
- in:fade={{ delay: 0, duration: 50 }}
- out:fade={{ delay: 50, duration: 200 }}
- class={`flex flex-col w-full justify-start items-center fade-in`}
- >
- <Nav
- basis={{
- prev: {
- label: `${$t(`common.back`)}`,
- route: `/models/trade-product`,
- prevent_route:
- view === `fl_1` && $carousel_index === 0
- ? undefined
- : {
- callback: async () => {
- await handle_back();
- },
- },
- callback: async () => {
- await tradeproduct_init_kv(fmt_id());
- },
- },
- title:
- $carousel_index === CAROUSEL_INDEX_MAP
+<div
+ in:fade={{ delay: 0, duration: 50 }}
+ out:fade={{ delay: 50, duration: 200 }}
+ class={`flex flex-col w-full justify-start items-center fade-in`}
+>
+ <Nav
+ basis={{
+ prev: {
+ label: `${$t(`common.back`)}`,
+ route: `/models/trade-product`,
+ prevent_route:
+ view === `fl_1` && $carousel_index === 0
? undefined
: {
- label: {
- value: `${$t(`icu.new_*`, { value: `${$t(`common.product`)}` })}`,
+ callback: async () => {
+ await handle_back();
},
- callback: async () => {},
},
- option: {
- loading: load_submit,
- label:
- $carousel_index === CAROUSEL_INDEX_MAP
- ? undefined
- : {
- value:
- $carousel_num > 1
- ? `${$t(`common.return`)}`
- : page_param.carousel[view].get(
- $carousel_index,
- )?.label_next || ``,
- glyph:
- $carousel_index > 0
- ? {
- key: `caret-right`,
- classes: `text-layer-1-glyph-hl`,
- }
- : undefined,
- },
- callback: async () => {
- if ($carousel_index === $carousel_index_max)
- await submit();
- else await handle_continue();
- },
+ callback: async () => {
+ await tradeproduct_init_kv(fmt_id());
},
- }}
- />
- </div>
-{/if}
+ },
+ title: {
+ label: {
+ value: `${$t(`icu.new_*`, { value: `${$t(`common.product`)}` })}`,
+ },
+ callback: async () => {},
+ },
+ option: {
+ loading: load_submit,
+ label: {
+ value:
+ $carousel_num > 1
+ ? `${$t(`common.return`)}`
+ : page_param.carousel[view].get($carousel_index)
+ ?.label_next || ``,
+ glyph:
+ $carousel_index > 0
+ ? {
+ key: `caret-right`,
+ classes: `text-layer-1-glyph-hl`,
+ }
+ : undefined,
+ },
+ callback: async () => {
+ if ($carousel_index === $carousel_index_max) await submit();
+ else await handle_continue();
+ },
+ },
+ }}
+ />
+</div>
+<MapPointSelectEnvelope
+ bind:map_point_select={tradeproduct_location_select_point}
+ bind:map_point_select_geoc={tradeproduct_location_select_geoc}
+ basis={{
+ visible: tradeproduct_location_select_vis,
+ close: async () => {
+ tradeproduct_location_select_vis = false;
+ },
+ }}
+/>