diff --git a/lib/structs/field_content.ex b/lib/structs/field_content.ex index ca7fb89..61e16c1 100644 --- a/lib/structs/field_content.ex +++ b/lib/structs/field_content.ex @@ -35,6 +35,11 @@ defmodule ExPass.Structs.FieldContent do * "PKDateStyleMedium" * "PKDateStyleLong" * "PKDateStyleFull" + + - `ignores_time_zone`: A Boolean value that controls the time zone for the time and date to display in the field. + The default value is false, which displays the time and date using the current device's time zone. + If set to true, the time and date appear in the time zone associated with the date and time of value. + This key doesn't affect the pass relevance calculation. """ use TypedStruct @@ -101,13 +106,14 @@ defmodule ExPass.Structs.FieldContent do field :currency_code, String.t(), default: nil field :data_detector_types, data_detector_types(), default: nil field :date_style, date_style(), default: nil + field :ignores_time_zone, boolean(), default: nil end @doc """ Creates a new FieldContent struct. This function initializes a new FieldContent struct with the given attributes. - It validates the `attributed_value`, `change_message`, `currency_code`, `data_detector_types`, and `date_style`. + It validates the `attributed_value`, `change_message`, `currency_code`, `data_detector_types`, `date_style`, and `ignores_time_zone`. ## Parameters @@ -124,22 +130,22 @@ defmodule ExPass.Structs.FieldContent do ## Examples iex> FieldContent.new(%{attributed_value: "Hello, World!"}) - %FieldContent{attributed_value: "Hello, World!", change_message: nil, currency_code: nil, data_detector_types: nil, date_style: nil} + %FieldContent{attributed_value: "Hello, World!", change_message: nil, currency_code: nil, data_detector_types: nil, date_style: nil, ignores_time_zone: nil} - iex> FieldContent.new(%{attributed_value: 42, data_detector_types: ["PKDataDetectorTypePhoneNumber"], date_style: "PKDateStyleShort"}) - %FieldContent{attributed_value: 42, change_message: nil, currency_code: nil, data_detector_types: ["PKDataDetectorTypePhoneNumber"], date_style: "PKDateStyleShort"} + iex> FieldContent.new(%{attributed_value: 42, data_detector_types: ["PKDataDetectorTypePhoneNumber"], date_style: "PKDateStyleShort", ignores_time_zone: true}) + %FieldContent{attributed_value: 42, change_message: nil, currency_code: nil, data_detector_types: ["PKDataDetectorTypePhoneNumber"], date_style: "PKDateStyleShort", ignores_time_zone: true} - iex> datetime = DateTime.utc_now() - iex> field_content = FieldContent.new(%{attributed_value: datetime, currency_code: "USD", date_style: "PKDateStyleLong"}) - iex> %FieldContent{attributed_value: ^datetime, currency_code: "USD", date_style: "PKDateStyleLong"} = field_content + iex> datetime = ~U[2023-04-15 14:30:00Z] + iex> field_content = FieldContent.new(%{attributed_value: datetime, currency_code: "USD", date_style: "PKDateStyleLong", ignores_time_zone: true}) + iex> %FieldContent{attributed_value: ^datetime, currency_code: "USD", date_style: "PKDateStyleLong", ignores_time_zone: true} = field_content iex> field_content.change_message nil iex> FieldContent.new(%{attributed_value: "Click here", data_detector_types: ["PKDataDetectorTypeLink"], date_style: "PKDateStyleFull"}) - %FieldContent{attributed_value: "Click here", change_message: nil, currency_code: nil, data_detector_types: ["PKDataDetectorTypeLink"], date_style: "PKDateStyleFull"} + %FieldContent{attributed_value: "Click here", change_message: nil, currency_code: nil, data_detector_types: ["PKDataDetectorTypeLink"], date_style: "PKDateStyleFull", ignores_time_zone: nil} - iex> FieldContent.new(%{attributed_value: "No detectors", data_detector_types: []}) - %FieldContent{attributed_value: "No detectors", change_message: nil, currency_code: nil, data_detector_types: [], date_style: nil} + iex> FieldContent.new(%{attributed_value: "No detectors", data_detector_types: [], change_message: "Updated to %@", ignores_time_zone: true}) + %FieldContent{attributed_value: "No detectors", change_message: "Updated to %@", currency_code: nil, data_detector_types: [], date_style: nil, ignores_time_zone: true} """ @spec new(map()) :: %__MODULE__{} def new(attrs \\ %{}) do @@ -151,6 +157,7 @@ defmodule ExPass.Structs.FieldContent do |> validate(:currency_code, &Validators.validate_currency_code/1) |> validate(:data_detector_types, &Validators.validate_data_detector_types/1) |> validate(:date_style, &Validators.validate_date_style/1) + |> validate(:ignores_time_zone, &Validators.validate_ignores_timezone/1) struct!(__MODULE__, attrs) end @@ -186,6 +193,9 @@ defmodule ExPass.Structs.FieldContent do :date_style -> "Supported values are: PKDateStyleNone, PKDateStyleShort, PKDateStyleMedium, PKDateStyleLong, PKDateStyleFull" + :ignores_time_zone -> + "ignores_time_zone must be a boolean value (true or false)" + _ -> "" end diff --git a/lib/utils/validators.ex b/lib/utils/validators.ex index 6e8dec7..d047f55 100644 --- a/lib/utils/validators.ex +++ b/lib/utils/validators.ex @@ -250,6 +250,36 @@ defmodule ExPass.Utils.Validators do def validate_date_style(_), do: {:error, "date_style must be a string"} + @doc """ + Validates the ignores_time_zone field. + + The ignores_time_zone must be a boolean value. + + ## Returns + + * `:ok` if the value is a valid boolean or nil. + * `{:error, reason}` if the value is not valid, where reason is a string explaining the error. + + ## Examples + + iex> validate_ignores_timezone(true) + :ok + + iex> validate_ignores_timezone(false) + :ok + + iex> validate_ignores_timezone(nil) + :ok + + iex> validate_ignores_timezone("true") + {:error, "ignores_time_zone must be a boolean"} + + """ + @spec validate_ignores_timezone(boolean() | nil) :: :ok | {:error, String.t()} + def validate_ignores_timezone(nil), do: :ok + def validate_ignores_timezone(value) when is_boolean(value), do: :ok + def validate_ignores_timezone(_), do: {:error, "ignores_time_zone must be a boolean"} + defp contains_unsupported_html_tags?(string) do # Remove all valid anchor tags string_without_anchors = String.replace(string, ~r{]*>.*?|]*/>}, "") diff --git a/test/structs/field_content_test.exs b/test/structs/field_content_test.exs index d9baa56..aaeb132 100644 --- a/test/structs/field_content_test.exs +++ b/test/structs/field_content_test.exs @@ -220,4 +220,33 @@ defmodule ExPass.Structs.FieldContentTest do end end end + + describe "ignores_time_zone" do + test "new/1 creates a valid FieldContent struct with ignores_time_zone set to true" do + result = FieldContent.new(%{ignores_time_zone: true}) + + assert %FieldContent{ignores_time_zone: true} = result + assert Jason.encode!(result) == ~s({"ignoresTimeZone":true}) + end + + test "new/1 creates a valid FieldContent struct with ignores_time_zone set to false" do + result = FieldContent.new(%{ignores_time_zone: false}) + + assert %FieldContent{ignores_time_zone: false} = result + assert Jason.encode!(result) == ~s({"ignoresTimeZone":false}) + end + + test "new/1 defaults to nil when ignores_time_zone is not provided" do + result = FieldContent.new(%{}) + + assert %FieldContent{ignores_time_zone: nil} = result + assert Jason.encode!(result) == ~s({}) + end + + test "new/1 raises ArgumentError when ignores_time_zone is not a boolean" do + assert_raise ArgumentError, ~r/ignores_time_zone must be a boolean/, fn -> + FieldContent.new(%{ignores_time_zone: "true"}) + end + end + end end