{
  "id": "fx_root",
  "type": "module",
  "version": "1.1",
  "context": {
    "title": "Currency Rates",
    "icon": "💱",
    "fxReady": "{{ ${ratesBase} == ${base} && notEmpty(${rates}) }}"
  },
  "state": {
    "base": "USD",
    "baseOption": "USD · US Dollar",
    "rates": {},
    "ratesBase": "",
    "updatedAt": 0,
    "status": "idle",
    "error": "",
    "currencies": [
      {
        "code": "USD",
        "name": "US Dollar",
        "flag": "🇺🇸"
      },
      {
        "code": "EUR",
        "name": "Euro",
        "flag": "🇪🇺"
      },
      {
        "code": "GBP",
        "name": "British Pound",
        "flag": "🇬🇧"
      },
      {
        "code": "UAH",
        "name": "Ukrainian Hryvnia",
        "flag": "🇺🇦"
      },
      {
        "code": "PLN",
        "name": "Polish Zloty",
        "flag": "🇵🇱"
      },
      {
        "code": "CHF",
        "name": "Swiss Franc",
        "flag": "🇨🇭"
      },
      {
        "code": "JPY",
        "name": "Japanese Yen",
        "flag": "🇯🇵"
      },
      {
        "code": "CNY",
        "name": "Chinese Yuan",
        "flag": "🇨🇳"
      },
      {
        "code": "CAD",
        "name": "Canadian Dollar",
        "flag": "🇨🇦"
      },
      {
        "code": "AUD",
        "name": "Australian Dollar",
        "flag": "🇦🇺"
      }
    ]
  },
  "dependencies": [
    {
      "repository": {
        "remote": {
          "id": "fx_api",
          "config": {
            "endPoint": "https://open.er-api.com/v6/latest"
          }
        }
      }
    },
    {
      "repository": {
        "local": {
          "id": "fx_store",
          "config": {}
        }
      }
    },
    {
      "service": {
        "audio": {
          "id": "fx_audio"
        }
      }
    },
    {
      "action": {
        "repo": {
          "id": "fx_call",
          "input": {
            "repositoryId": "fx_api",
            "operation": "read",
            "params": {
              "subUrl": "{{ '/' + ${base} }}"
            }
          },
          "debounce": 0.3,
          "output": {
            "success": [
              {
                "state": {
                  "id": "fx_apply",
                  "input": {
                    "rates": "{{ @{fx_call.result} == 'success' && @{fx_call.base_code} == ${base} ? @{fx_call.rates} : ${rates} }}",
                    "ratesBase": "{{ @{fx_call.result} == 'success' && @{fx_call.base_code} == ${base} ? @{fx_call.base_code} : ${ratesBase} }}",
                    "updatedAt": "{{ @{fx_call.result} == 'success' && @{fx_call.base_code} == ${base} ? @{fx_call.time_last_update_unix} : ${updatedAt} }}",
                    "status": "{{ switch(@{fx_call.result} == 'success' && @{fx_call.base_code} != ${base}, ${status}, @{fx_call.result} == 'success', 'ready', 'error') }}",
                    "error": "{{ @{fx_call.result} == 'success' ? '' : 'Rates for ' + ${base} + ' are unavailable right now. Try again in a moment.' }}"
                  }
                }
              }
            ],
            "failure": [
              {
                "state": {
                  "id": "fx_fail",
                  "input": {
                    "status": "error",
                    "error": "{{ 'Could not load rates' + (notEmpty(@{fx_call.message}) ? ': ' + @{fx_call.message} : '. Check your connection and try again.') }}"
                  }
                }
              },
              {
                "service": {
                  "id": "fx_fail_haptic",
                  "input": {
                    "serviceId": "fx_audio",
                    "params": {
                      "haptic": "warning"
                    }
                  }
                }
              }
            ]
          }
        }
      }
    }
  ],
  "events": {
    "onAppear": [
      {
        "repo": {
          "id": "fx_load_prefs",
          "input": {
            "repositoryId": "fx_store",
            "operation": "read",
            "params": {
              "collection": "settings",
              "documentId": "prefs"
            }
          },
          "output": {
            "success": [
              {
                "state": {
                  "id": "fx_restore_base",
                  "input": {
                    "baseOption": "{{ notEmpty(@{fx_load_prefs.baseOption}) ? @{fx_load_prefs.baseOption} : notEmpty(${currencies[code == #{currency}]}) ? ${currencies[code == #{currency}][0].code} + ' · ' + ${currencies[code == #{currency}][0].name} : 'USD · US Dollar' }}",
                    "base": "{{ notEmpty(@{fx_load_prefs.baseOption}) ? prefix(@{fx_load_prefs.baseOption}, 3) : notEmpty(${currencies[code == #{currency}]}) ? ${currencies[code == #{currency}][0].code} : 'USD' }}",
                    "status": "idle"
                  },
                  "output": {
                    "success": [
                      {
                        "template": {
                          "id": "fx_run_restored",
                          "input": "fx_call"
                        }
                      }
                    ]
                  }
                }
              }
            ],
            "failure": [
              {
                "state": {
                  "id": "fx_default_base",
                  "input": {
                    "baseOption": "{{ notEmpty(${currencies[code == #{currency}]}) ? ${currencies[code == #{currency}][0].code} + ' · ' + ${currencies[code == #{currency}][0].name} : 'USD · US Dollar' }}",
                    "base": "{{ notEmpty(${currencies[code == #{currency}]}) ? ${currencies[code == #{currency}][0].code} : 'USD' }}",
                    "status": "idle"
                  },
                  "output": {
                    "success": [
                      {
                        "template": {
                          "id": "fx_run_default",
                          "input": "fx_call"
                        }
                      }
                    ]
                  }
                }
              }
            ]
          }
        }
      }
    ]
  },
  "children": [
    {
      "id": "fx_scroll",
      "type": "scroll",
      "events": {
        "onRefresh": [
          {
            "state": {
              "id": "fx_refresh_mark",
              "input": {
                "status": "idle"
              },
              "output": {
                "success": [
                  {
                    "template": {
                      "id": "fx_run_refresh",
                      "input": "fx_call"
                    }
                  }
                ]
              }
            }
          },
          {
            "service": {
              "id": "fx_refresh_haptic",
              "input": {
                "serviceId": "fx_audio",
                "params": {
                  "haptic": "light"
                }
              }
            }
          }
        ]
      },
      "children": [
        {
          "id": "fx_content",
          "type": "vstack",
          "context": {
            "_spacing": 20,
            "_alignment": "leading"
          },
          "style": {
            "layout": {
              "padding": {
                "horizontal": 16,
                "top": 8,
                "bottom": 28
              },
              "maxWidth": "infinity"
            }
          },
          "children": [
            {
              "id": "fx_hero_card",
              "type": "vstack",
              "context": {
                "_spacing": 8,
                "_alignment": "leading",
                "heroCode": "${currencies[code != ${base}][0].code}",
                "heroName": "${currencies[code != ${base}][0].name}",
                "heroFlag": "${currencies[code != ${base}][0].flag}",
                "heroValue": "{{ 1 / ${rates[@{heroCode}]} }}"
              },
              "style": {
                "common": {
                  "background": {
                    "gradient": {
                      "linear": {
                        "colors": [
                          "#0E7C66",
                          "#1D4ED8"
                        ],
                        "startPoint": "leading",
                        "endPoint": "trailing"
                      }
                    }
                  },
                  "cornerRadius": 22
                },
                "layout": {
                  "padding": 20,
                  "maxWidth": "infinity"
                },
                "shadow": {
                  "color": {
                    "color": "black",
                    "opacity": 0.18
                  },
                  "radius": 16,
                  "y": 8
                }
              },
              "children": [
                {
                  "id": "fx_hero_top",
                  "type": "hstack",
                  "context": {
                    "_spacing": 10,
                    "_alignment": "center"
                  },
                  "children": [
                    {
                      "id": "fx_hero_flag",
                      "type": "text",
                      "context": {
                        "_text": "@{heroFlag}"
                      },
                      "style": {
                        "common": {
                          "font": "largeTitle",
                          "foreground": "#f1eeee"
                        }
                      }
                    },
                    {
                      "id": "fx_hero_names",
                      "type": "vstack",
                      "context": {
                        "_spacing": 2,
                        "_alignment": "leading"
                      },
                      "children": [
                        {
                          "id": "fx_hero_name",
                          "type": "text",
                          "context": {
                            "_text": "@{heroName}"
                          },
                          "style": {
                            "common": {
                              "font": {
                                "kind": "headline",
                                "weight": "semibold"
                              },
                              "foreground": "white"
                            }
                          }
                        },
                        {
                          "id": "fx_hero_unit",
                          "type": "text",
                          "context": {
                            "_text": "{{ 'For 1 ' + @{heroCode} }}"
                          },
                          "style": {
                            "common": {
                              "font": "subheadline",
                              "foreground": {
                                "color": "white",
                                "opacity": 0.8
                              }
                            }
                          }
                        }
                      ]
                    },
                    {
                      "id": "fx_hero_spacer",
                      "type": "spacer"
                    }
                  ]
                },
                {
                  "id": "fx_hero_value_switch",
                  "type": "conditional",
                  "context": {
                    "_condition": "@{fxReady}",
                    "_trueComponent": {
                      "id": "fx_hero_value",
                      "type": "text",
                      "context": {
                        "_text": "@{heroValue}",
                        "_format": {
                          "number": {
                            "style": "currency",
                            "currencyCode": "${base}",
                            "maximumFractionDigits": "{{ @{heroValue} < 1 ? 4 : 2 }}"
                          }
                        }
                      },
                      "style": {
                        "common": {
                          "font": {
                            "kind": "largeTitle",
                            "weight": "bold"
                          },
                          "foreground": "white"
                        },
                        "animation": {
                          "kind": "spring",
                          "value": "${updatedAt}",
                          "duration": 0.5,
                          "bounce": 0.25
                        }
                      }
                    },
                    "_falseComponent": {
                      "id": "fx_hero_waiting",
                      "type": "text",
                      "context": {
                        "_text": "{{ ${status} == 'error' ? 'Rates unavailable' : 'Loading rates…' }}"
                      },
                      "style": {
                        "common": {
                          "font": {
                            "kind": "title2",
                            "weight": "semibold"
                          },
                          "foreground": {
                            "color": "white",
                            "opacity": 0.85
                          }
                        }
                      }
                    }
                  }
                }
              ]
            },
            {
              "id": "fx_base_card",
              "type": "hstack",
              "context": {
                "_spacing": 12,
                "_alignment": "center"
              },
              "style": {
                "common": {
                  "background": "surface",
                  "cornerRadius": 18
                },
                "layout": {
                  "padding": {
                    "vertical": 12,
                    "horizontal": 16
                  },
                  "maxWidth": "infinity",
                  "minHeight": 56
                },
                "shadow": {
                  "color": {
                    "color": "black",
                    "opacity": 0.06
                  },
                  "radius": 10,
                  "y": 4
                }
              },
              "children": [
                {
                  "id": "fx_base_icon",
                  "type": "image",
                  "context": {
                    "_source": "sf://arrow.left.arrow.right.circle.fill"
                  },
                  "style": {
                    "common": {
                      "foreground": "accentcolor"
                    },
                    "layout": {
                      "width": 26,
                      "height": 26
                    }
                  }
                },
                {
                  "id": "fx_base_texts",
                  "type": "vstack",
                  "context": {
                    "_spacing": 2,
                    "_alignment": "leading"
                  },
                  "children": [
                    {
                      "id": "fx_base_title",
                      "type": "text",
                      "context": {
                        "_text": "Show rates in"
                      },
                      "style": {
                        "common": {
                          "font": "headline",
                          "foreground": "onsurface"
                        }
                      }
                    },
                    {
                      "id": "fx_base_hint",
                      "type": "text",
                      "context": {
                        "_text": "Starts with your device currency"
                      },
                      "style": {
                        "common": {
                          "font": "caption",
                          "foreground": "onsurfacevariant"
                        }
                      }
                    }
                  ]
                },
                {
                  "id": "fx_base_spacer",
                  "type": "spacer"
                },
                {
                  "id": "fx_base_picker",
                  "type": "picker",
                  "context": {
                    "_label": "Currency",
                    "_selection": "${baseOption}",
                    "_options": "{{ map(${currencies}, @{item.code} + ' · ' + @{item.name}) }}"
                  },
                  "style": {
                    "picker": "menu",
                    "common": {
                      "tint": "accentcolor"
                    }
                  },
                  "events": {
                    "onChange": {
                      "observed": "baseOption",
                      "actions": [
                        {
                          "state": {
                            "id": "fx_switch_base",
                            "input": {
                              "base": "{{ prefix(${baseOption}, 3) }}",
                              "status": "idle",
                              "error": ""
                            },
                            "output": {
                              "success": [
                                {
                                  "template": {
                                    "id": "fx_run_switch",
                                    "input": "fx_call"
                                  }
                                }
                              ]
                            }
                          }
                        },
                        {
                          "repo": {
                            "id": "fx_save_prefs",
                            "input": {
                              "repositoryId": "fx_store",
                              "operation": "create",
                              "params": {
                                "collection": "settings",
                                "documentId": "prefs",
                                "rewrite": true,
                                "body": {
                                  "baseOption": "${baseOption}"
                                }
                              }
                            }
                          }
                        }
                      ]
                    }
                  }
                }
              ]
            },
            {
              "id": "fx_rates_card",
              "type": "vstack",
              "context": {
                "_spacing": 6,
                "_alignment": "leading"
              },
              "style": {
                "common": {
                  "background": "surface",
                  "cornerRadius": 18
                },
                "layout": {
                  "padding": 16,
                  "maxWidth": "infinity"
                },
                "shadow": {
                  "color": {
                    "color": "black",
                    "opacity": 0.06
                  },
                  "radius": 10,
                  "y": 4
                }
              },
              "children": [
                {
                  "id": "fx_rates_header",
                  "type": "hstack",
                  "context": {
                    "_spacing": 8,
                    "_alignment": "center"
                  },
                  "children": [
                    {
                      "id": "fx_rates_title",
                      "type": "text",
                      "context": {
                        "_text": "Other currencies"
                      },
                      "style": {
                        "common": {
                          "font": "headline",
                          "foreground": "onsurface"
                        }
                      }
                    },
                    {
                      "id": "fx_rates_header_spacer",
                      "type": "spacer"
                    },
                    {
                      "id": "fx_rates_unit",
                      "type": "text",
                      "context": {
                        "_text": "{{ 'Price of 1 unit in ' + ${base} }}"
                      },
                      "style": {
                        "common": {
                          "font": "caption",
                          "foreground": "onsurfacevariant"
                        }
                      }
                    }
                  ]
                },
                {
                  "id": "fx_stale_banner",
                  "type": "conditional",
                  "context": {
                    "_condition": "{{ @{fxReady} && ${status} == 'error' }}",
                    "_trueComponent": {
                      "id": "fx_stale_label",
                      "type": "label",
                      "context": {
                        "_title": "{{ 'Showing earlier rates. ' + ${error} }}",
                        "_image": "sf://exclamationmark.triangle.fill"
                      },
                      "style": {
                        "common": {
                          "font": "caption",
                          "foreground": "error"
                        },
                        "layout": {
                          "padding": {
                            "vertical": 4
                          }
                        }
                      }
                    }
                  }
                },
                {
                  "id": "fx_rows_switch",
                  "type": "conditional",
                  "context": {
                    "_condition": "@{fxReady}",
                    "_trueComponent": {
                      "id": "fx_rows",
                      "type": "dynamic",
                      "context": {
                        "_data": "{{ removeAt(${currencies[code != ${base}]}, 0) }}"
                      },
                      "prototype": {
                        "id": "fx_row",
                        "type": "hstack",
                        "context": {
                          "_spacing": 12,
                          "_alignment": "center",
                          "rowValue": "{{ 1 / ${rates[@{item.code}]} }}"
                        },
                        "style": {
                          "layout": {
                            "padding": {
                              "vertical": 10
                            },
                            "maxWidth": "infinity"
                          }
                        },
                        "children": [
                          {
                            "id": "fx_row_flag",
                            "type": "text",
                            "context": {
                              "_text": "@{item.flag}"
                            },
                            "style": {
                              "common": {
                                "font": "title2",
                                "foreground": "onsurface"
                              }
                            }
                          },
                          {
                            "id": "fx_row_names",
                            "type": "vstack",
                            "context": {
                              "_spacing": 2,
                              "_alignment": "leading"
                            },
                            "children": [
                              {
                                "id": "fx_row_code",
                                "type": "text",
                                "context": {
                                  "_text": "@{item.code}"
                                },
                                "style": {
                                  "common": {
                                    "font": {
                                      "kind": "body",
                                      "weight": "semibold"
                                    },
                                    "foreground": "onsurface"
                                  }
                                }
                              },
                              {
                                "id": "fx_row_name",
                                "type": "text",
                                "context": {
                                  "_text": "@{item.name}"
                                },
                                "style": {
                                  "common": {
                                    "font": "caption",
                                    "foreground": "onsurfacevariant"
                                  }
                                }
                              }
                            ]
                          },
                          {
                            "id": "fx_row_spacer",
                            "type": "spacer"
                          },
                          {
                            "id": "fx_row_value",
                            "type": "text",
                            "context": {
                              "_text": "@{rowValue}",
                              "_format": {
                                "number": {
                                  "style": "currency",
                                  "currencyCode": "${base}",
                                  "maximumFractionDigits": "{{ @{rowValue} < 1 ? 4 : 2 }}"
                                }
                              }
                            },
                            "style": {
                              "common": {
                                "font": {
                                  "kind": "body",
                                  "weight": "semibold"
                                },
                                "foreground": "onsurface"
                              },
                              "animation": {
                                "kind": "spring",
                                "value": "${updatedAt}",
                                "duration": 0.45,
                                "bounce": 0.2
                              }
                            }
                          }
                        ]
                      }
                    },
                    "_falseComponent": {
                      "id": "fx_rows_pending",
                      "type": "conditional",
                      "context": {
                        "_condition": "{{ ${status} == 'error' }}",
                        "_trueComponent": {
                          "id": "fx_error_view",
                          "type": "vstack",
                          "context": {
                            "_spacing": 12,
                            "_alignment": "center"
                          },
                          "style": {
                            "layout": {
                              "padding": {
                                "vertical": 20
                              },
                              "maxWidth": "infinity"
                            }
                          },
                          "children": [
                            {
                              "id": "fx_error_icon",
                              "type": "image",
                              "context": {
                                "_source": "sf://wifi.exclamationmark"
                              },
                              "style": {
                                "common": {
                                  "foreground": "error"
                                },
                                "layout": {
                                  "width": 34,
                                  "height": 34
                                }
                              }
                            },
                            {
                              "id": "fx_error_text",
                              "type": "text",
                              "context": {
                                "_text": "${error}"
                              },
                              "style": {
                                "common": {
                                  "font": "body",
                                  "foreground": "onsurface"
                                },
                                "text": {
                                  "multilineTextAlignment": "center"
                                }
                              }
                            },
                            {
                              "id": "fx_retry_btn",
                              "type": "button",
                              "context": {
                                "_label": "Try again",
                                "_image": "sf://arrow.clockwise"
                              },
                              "style": {
                                "button": {
                                  "standard": {
                                    "type": "borderedProminent",
                                    "shape": "capsule"
                                  }
                                },
                                "layout": {
                                  "minHeight": 44
                                }
                              },
                              "events": {
                                "onTap": [
                                  {
                                    "state": {
                                      "id": "fx_retry_mark",
                                      "input": {
                                        "status": "idle",
                                        "error": ""
                                      },
                                      "output": {
                                        "success": [
                                          {
                                            "template": {
                                              "id": "fx_run_retry",
                                              "input": "fx_call"
                                            }
                                          }
                                        ]
                                      }
                                    }
                                  }
                                ]
                              }
                            }
                          ]
                        },
                        "_falseComponent": {
                          "id": "fx_rows_loading",
                          "type": "dynamic",
                          "context": {
                            "_data": "{{ removeAt(${currencies[code != ${base}]}, 0) }}",
                            "_isLoading": true,
                            "_skeletonRows": 8
                          },
                          "prototype": {
                            "id": "fx_skel_row",
                            "type": "hstack",
                            "context": {
                              "_spacing": 12,
                              "_alignment": "center"
                            },
                            "style": {
                              "layout": {
                                "padding": {
                                  "vertical": 10
                                },
                                "maxWidth": "infinity"
                              }
                            },
                            "children": [
                              {
                                "id": "fx_skel_flag",
                                "type": "text",
                                "context": {
                                  "_text": "@{item.flag}"
                                },
                                "style": {
                                  "common": {
                                    "font": "title2",
                                    "foreground": "onsurface"
                                  }
                                }
                              },
                              {
                                "id": "fx_skel_code",
                                "type": "text",
                                "context": {
                                  "_text": "@{item.code}"
                                },
                                "style": {
                                  "common": {
                                    "font": {
                                      "kind": "body",
                                      "weight": "semibold"
                                    },
                                    "foreground": "onsurface"
                                  }
                                }
                              },
                              {
                                "id": "fx_skel_spacer",
                                "type": "spacer"
                              },
                              {
                                "id": "fx_skel_value",
                                "type": "text",
                                "context": {
                                  "_text": "0.00"
                                },
                                "style": {
                                  "common": {
                                    "font": "body",
                                    "foreground": "onsurfacevariant"
                                  }
                                }
                              }
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              ]
            },
            {
              "id": "fx_footer",
              "type": "vstack",
              "context": {
                "_spacing": 4,
                "_alignment": "leading"
              },
              "style": {
                "layout": {
                  "padding": {
                    "horizontal": 4
                  }
                }
              },
              "children": [
                {
                  "id": "fx_updated_switch",
                  "type": "conditional",
                  "context": {
                    "_condition": "@{fxReady}",
                    "_trueComponent": {
                      "id": "fx_updated_row",
                      "type": "hstack",
                      "context": {
                        "_spacing": 4,
                        "_alignment": "center"
                      },
                      "children": [
                        {
                          "id": "fx_updated_label",
                          "type": "text",
                          "context": {
                            "_text": "Updated"
                          },
                          "style": {
                            "common": {
                              "font": "caption",
                              "foreground": "secondary"
                            }
                          }
                        },
                        {
                          "id": "fx_updated_time",
                          "type": "text",
                          "context": {
                            "_text": "${updatedAt}",
                            "_format": {
                              "date": "datetime"
                            }
                          },
                          "style": {
                            "common": {
                              "font": "caption",
                              "foreground": "secondary"
                            }
                          }
                        }
                      ]
                    }
                  }
                },
                {
                  "id": "fx_source_note",
                  "type": "text",
                  "context": {
                    "_text": "Rates by ExchangeRate-API, refreshed once a day. Pull down to refresh."
                  },
                  "style": {
                    "common": {
                      "font": "caption2",
                      "foreground": "secondary"
                    }
                  }
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}