farms-add.svelte (7676B)
1 <script lang="ts"> 2 import ButtonLayoutBottom from "$lib/components/button/button-layout-bottom.svelte"; 3 import ButtonLayoutPair from "$lib/components/button/button-layout-pair.svelte"; 4 import FarmsAddDetails from "$lib/components/farm/farms-add-detail.svelte"; 5 import FarmsAddMap from "$lib/components/farm/farms-add-map.svelte"; 6 import LayoutView from "$lib/components/layout/layout-view.svelte"; 7 import CarouselContainer from "$lib/components/lib/carousel-container.svelte"; 8 import CarouselItem from "$lib/components/lib/carousel-item.svelte"; 9 import PageToolbar from "$lib/components/navigation/page-toolbar.svelte"; 10 import { app_platform } from "$lib/stores/app"; 11 import type { LibContext } from "$lib/types/context"; 12 import type { IViewFarmsAddSubmission } from "$lib/types/views/farms"; 13 import { schema_view_farms_add_submission } from "$lib/utils/farm/schema"; 14 import { focus_map_marker } from "$lib/utils/map"; 15 import { 16 carousel_create, 17 carousel_dec, 18 carousel_inc, 19 el_id, 20 fmt_id, 21 geop_init, 22 geop_is_valid, 23 get_context, 24 type CallbackRoute, 25 } from "@radroots/apps-lib"; 26 import { 27 geol_lat_fmt, 28 geol_lng_fmt, 29 parse_geocode_address, 30 type GeocoderReverseResult, 31 type GeolocationAddress, 32 type GeolocationPoint, 33 } from "@radroots/geo"; 34 import { type CallbackPromiseGeneric } from "@radroots/utils"; 35 36 const { ls, locale, lc_gui_alert, lc_geop_current, lc_geocode } = 37 get_context<LibContext>(`lib`); 38 39 let { 40 basis, 41 }: { 42 basis: { 43 callback_route?: CallbackRoute<string>; 44 on_submit: CallbackPromiseGeneric<{ 45 payload: IViewFarmsAddSubmission; 46 }>; 47 }; 48 } = $props(); 49 50 let map_geop: GeolocationPoint = $state(geop_init()); 51 let map_geoc: GeocoderReverseResult | undefined = $state(undefined); 52 53 let val_farmname = $state(``); 54 let val_farmaddress = $state(``); 55 let val_farmabout = $state(``); 56 let val_farmwebsite = $state(``); 57 58 const carousel_farms_add = carousel_create({ 59 view: "farms_add", 60 max_index: 1, 61 }); 62 63 const carousel_farms_add_index = carousel_farms_add.index; 64 65 const disabled_submit = $derived( 66 $carousel_farms_add_index === 1 && !val_farmname, 67 ); 68 69 const farm_geop_lat = $derived( 70 geop_is_valid(map_geop) 71 ? geol_lat_fmt(map_geop.lat, `dms`, $locale, 3) 72 : ``, 73 ); 74 75 const farm_geop_lng = $derived( 76 geop_is_valid(map_geop) 77 ? geol_lng_fmt(map_geop.lng, `dms`, $locale, 3) 78 : ``, 79 ); 80 81 const farm_geolocation_address: GeolocationAddress | undefined = $derived( 82 parse_geocode_address(map_geoc), 83 ); 84 85 $effect(() => { 86 if (farm_geolocation_address) 87 val_farmaddress = `${farm_geolocation_address.primary}, ${farm_geolocation_address.admin}, ${farm_geolocation_address.country}`; 88 }); 89 90 const handle_enter_location = async (): Promise<void> => { 91 map_geoc = undefined; 92 map_geop = geop_init(); 93 val_farmaddress = ``; 94 await handle_continue(); 95 el_id(fmt_id(`farm_location`))?.focus(); 96 }; 97 98 const handle_continue_1 = async (): Promise<void> => { 99 const geolocation_point = geop_is_valid(map_geop) 100 ? map_geop 101 : undefined; 102 const geocode_result = map_geoc; 103 const farms_add_submission = schema_view_farms_add_submission.safeParse( 104 { 105 farm_name: val_farmname, 106 farm_about: val_farmabout ? val_farmabout : undefined, 107 farm_website: val_farmwebsite ? val_farmwebsite : undefined, 108 farm_location_label: val_farmaddress ? val_farmaddress : undefined, 109 geolocation_point, 110 geocode_result, 111 } satisfies IViewFarmsAddSubmission, 112 ); 113 114 if (!farms_add_submission.success) { 115 return void lc_gui_alert( 116 `Request invalid: ${farms_add_submission.error}`, 117 ); // @todo 118 } 119 await basis.on_submit({ payload: farms_add_submission.data }); 120 }; 121 122 const handle_continue = async (): Promise<void> => { 123 switch ($carousel_farms_add_index) { 124 case 1: 125 return await handle_continue_1(); 126 default: 127 await carousel_inc(carousel_farms_add); 128 } 129 }; 130 131 const handle_back = async (): Promise<void> => { 132 switch ($carousel_farms_add_index) { 133 case 1: { 134 if (!geop_is_valid(map_geop)) { 135 const geop_cur = await lc_geop_current(); 136 if (geop_cur) { 137 map_geop = geop_cur; 138 const geoc_cur = await lc_geocode(geop_cur); 139 if (geoc_cur) map_geoc = geoc_cur; 140 focus_map_marker(); 141 } 142 } 143 } 144 default: 145 return await carousel_dec(carousel_farms_add); 146 } 147 }; 148 </script> 149 150 <LayoutView> 151 <PageToolbar 152 basis={{ 153 header: { 154 label: `${$ls(`common.farms`)} / ${`${$ls(`common.add`)}`}`, 155 callback_route: basis.callback_route, 156 }, 157 }} 158 > 159 {#snippet header_option()} 160 <!-- {#if $casl_i === 0} 161 <button 162 class={`flex flex-row justify-center items-center`} 163 onclick={async () => { 164 await handle_enter_location(); 165 }} 166 > 167 <p 168 class={`font-sans font-[600] text-[18px] text-ly0-gl-hl`} 169 > 170 {`${$ls(`common.enter_location`)}`} 171 </p> 172 <Glyph 173 basis={{ 174 classes: `text-ly0-gl-hl`, 175 dim: `md`, 176 key: `caret-right`, 177 }} 178 /> 179 </button> 180 {/if}--> 181 {/snippet} 182 </PageToolbar> 183 <CarouselContainer 184 basis={{ 185 carousel: carousel_farms_add, 186 }} 187 > 188 <CarouselItem 189 basis={{ 190 classes: `justify-start items-center`, 191 }} 192 > 193 <FarmsAddMap 194 bind:map_geop 195 bind:map_geoc 196 {farm_geop_lat} 197 {farm_geop_lng} 198 /> 199 </CarouselItem> 200 <CarouselItem 201 basis={{ 202 classes: `justify-start items-center`, 203 }} 204 > 205 <FarmsAddDetails 206 bind:val_farmname 207 bind:val_farmaddress 208 bind:val_farmabout 209 bind:val_farmwebsite 210 {farm_geop_lat} 211 {farm_geop_lng} 212 /> 213 </CarouselItem> 214 </CarouselContainer> 215 </LayoutView> 216 {#if $app_platform?.browser !== `safari`} 217 <ButtonLayoutBottom> 218 <ButtonLayoutPair 219 basis={{ 220 continue: { 221 label: `${$ls(`common.continue`)}`, 222 disabled: disabled_submit, 223 callback: handle_continue, 224 }, 225 back: { 226 label: `${$ls(`common.back`)}`, 227 visible: $carousel_farms_add_index > 0, 228 callback: handle_back, 229 }, 230 }} 231 /> 232 </ButtonLayoutBottom> 233 {/if}