nova_forms/hooks/
use_zip_service.rs1use leptos::*;
2
3use crate::{Datatype, NonEmptyString, PostalCodeCH};
4
5pub fn postal_code_service<S: SignalGet<Value = Option<PostalCodeCH>> + 'static>(postal_code: S) -> Signal<Option<NonEmptyString>> {
8 let zip_service = create_server_action::<PostalCodeServiceServerFn>();
9 create_effect(move |_| {
10 if let Some(postal_code) = postal_code.get() {
11 zip_service.dispatch(PostalCodeServiceServerFn { zip: postal_code.into() });
12 }
13 });
14 let zip_service_value = zip_service.value();
15 let city = create_memo(move |_| {
16 if let Some(Ok(Some(city))) = zip_service_value.get() {
17 NonEmptyString::validate(city).ok()
18 } else {
19 None
20 }
21 });
22 city.into()
23}
24
25#[server]
26async fn postal_code_service_server_fn(zip: String) -> Result<Option<String>, ServerFnError> {
27 use serde::Deserialize;
28
29 #[derive(Deserialize)]
30 struct Response {
31 zips: Vec<ResponseZip>,
32 }
33
34 #[derive(Deserialize)]
35 struct ResponseZip {
36 city18: String,
37 }
38
39 let zips = reqwest::get(format!(
40 "https://service.post.ch/zopa/app/api/addresschecker/v1/zips?limit=2&zip={zip}"
41 ))
42 .await?
43 .json::<Response>()
44 .await?
45 .zips;
46
47 if zips.len() != 1 {
48 return Ok(None);
49 }
50
51 Ok(Some(zips.first().unwrap().city18.to_owned()))
52}
53