Skip to content

Commit

Permalink
Merge pull request #14 from njausteve/add-is-relative-pass-field
Browse files Browse the repository at this point in the history
feat: Add is_relative field to FieldContent struct
  • Loading branch information
njausteve authored Sep 21, 2024
2 parents e412d62 + 2798f58 commit ac25303
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 24 deletions.
32 changes: 19 additions & 13 deletions lib/structs/field_content.ex
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ defmodule ExPass.Structs.FieldContent do
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.
- `is_relative`: A Boolean value that controls whether the date appears as a relative date.
The default value is false, which displays the date as an absolute date.
This key doesn't affect the pass relevance calculation.
"""

use TypedStruct
Expand Down Expand Up @@ -107,13 +111,14 @@ defmodule ExPass.Structs.FieldContent do
field :data_detector_types, data_detector_types(), default: nil
field :date_style, date_style(), default: nil
field :ignores_time_zone, boolean(), default: nil
field :is_relative, 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`, `date_style`, and `ignores_time_zone`.
It validates the `attributed_value`, `change_message`, `currency_code`, `data_detector_types`, `date_style`, `ignores_time_zone`, and `is_relative`.
## Parameters
Expand All @@ -130,22 +135,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, ignores_time_zone: nil}
%FieldContent{attributed_value: "Hello, World!", change_message: nil, currency_code: nil, data_detector_types: nil, date_style: nil, ignores_time_zone: nil, is_relative: nil}
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> FieldContent.new(%{attributed_value: 42, data_detector_types: ["PKDataDetectorTypePhoneNumber"], date_style: "PKDateStyleShort", ignores_time_zone: true, is_relative: false})
%FieldContent{attributed_value: 42, change_message: nil, currency_code: nil, data_detector_types: ["PKDataDetectorTypePhoneNumber"], date_style: "PKDateStyleShort", ignores_time_zone: true, is_relative: false}
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 = FieldContent.new(%{attributed_value: datetime, currency_code: "USD", date_style: "PKDateStyleLong", ignores_time_zone: true, is_relative: true})
iex> %FieldContent{attributed_value: ^datetime, currency_code: "USD", date_style: "PKDateStyleLong", ignores_time_zone: true, is_relative: true} = field_content
iex> field_content.change_message
nil
iex> FieldContent.new(%{attributed_value: "<a href='http://example.com'>Click here</a>", data_detector_types: ["PKDataDetectorTypeLink"], date_style: "PKDateStyleFull"})
%FieldContent{attributed_value: "<a href='http://example.com'>Click here</a>", change_message: nil, currency_code: nil, data_detector_types: ["PKDataDetectorTypeLink"], date_style: "PKDateStyleFull", ignores_time_zone: nil}
iex> FieldContent.new(%{attributed_value: "<a href='http://example.com'>Click here</a>", data_detector_types: ["PKDataDetectorTypeLink"], date_style: "PKDateStyleFull", is_relative: false})
%FieldContent{attributed_value: "<a href='http://example.com'>Click here</a>", change_message: nil, currency_code: nil, data_detector_types: ["PKDataDetectorTypeLink"], date_style: "PKDateStyleFull", ignores_time_zone: nil, is_relative: false}
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}
iex> FieldContent.new(%{attributed_value: "No detectors", data_detector_types: [], change_message: "Updated to %@", ignores_time_zone: true, is_relative: true})
%FieldContent{attributed_value: "No detectors", change_message: "Updated to %@", currency_code: nil, data_detector_types: [], date_style: nil, ignores_time_zone: true, is_relative: true}
"""
@spec new(map()) :: %__MODULE__{}
def new(attrs \\ %{}) do
Expand All @@ -157,7 +162,8 @@ 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)
|> validate(:ignores_time_zone, &Validators.validate_boolean_field(&1, :ignores_time_zone))
|> validate(:is_relative, &Validators.validate_boolean_field(&1, :is_relative))

struct!(__MODULE__, attrs)
end
Expand Down Expand Up @@ -193,8 +199,8 @@ 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)"
key when key in [:ignores_time_zone, :is_relative] ->
"#{key} must be a boolean value (true or false)"

_ ->
""
Expand Down
27 changes: 16 additions & 11 deletions lib/utils/validators.ex
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,14 @@ defmodule ExPass.Utils.Validators do
def validate_date_style(_), do: {:error, "date_style must be a string"}

@doc """
Validates the ignores_time_zone field.
Validates a boolean field.
The ignores_time_zone must be a boolean value.
The field must be a boolean value or nil.
## Parameters
* `value` - The value to validate.
* `field_name` - The name of the field being validated as an atom.
## Returns
Expand All @@ -262,23 +267,23 @@ defmodule ExPass.Utils.Validators do
## Examples
iex> validate_ignores_timezone(true)
iex> validate_boolean_field(true, :ignores_time_zone)
:ok
iex> validate_ignores_timezone(false)
iex> validate_boolean_field(false, :is_relative)
:ok
iex> validate_ignores_timezone(nil)
iex> validate_boolean_field(nil, :ignores_time_zone)
:ok
iex> validate_ignores_timezone("true")
{:error, "ignores_time_zone must be a boolean"}
iex> validate_boolean_field("true", :is_relative)
{:error, "is_relative 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"}
@spec validate_boolean_field(boolean() | nil, atom()) :: :ok | {:error, String.t()}
def validate_boolean_field(nil, _field_name), do: :ok
def validate_boolean_field(value, _field_name) when is_boolean(value), do: :ok
def validate_boolean_field(_, field_name), do: {:error, "#{field_name} must be a boolean"}

defp contains_unsupported_html_tags?(string) do
# Remove all valid anchor tags
Expand Down
29 changes: 29 additions & 0 deletions test/structs/field_content_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -249,4 +249,33 @@ defmodule ExPass.Structs.FieldContentTest do
end
end
end

describe "is_relative" do
test "new/1 creates a valid FieldContent struct with is_relative set to true" do
result = FieldContent.new(%{is_relative: true})

assert %FieldContent{is_relative: true} = result
assert Jason.encode!(result) == ~s({"isRelative":true})
end

test "new/1 creates a valid FieldContent struct with is_relative set to false" do
result = FieldContent.new(%{is_relative: false})

assert %FieldContent{is_relative: false} = result
assert Jason.encode!(result) == ~s({"isRelative":false})
end

test "new/1 defaults to nil when is_relative is not provided" do
result = FieldContent.new(%{})

assert %FieldContent{is_relative: nil} = result
assert Jason.encode!(result) == ~s({})
end

test "new/1 raises ArgumentError when is_relative is not a boolean" do
assert_raise ArgumentError, ~r/is_relative must be a boolean/, fn ->
FieldContent.new(%{is_relative: "true"})
end
end
end
end

0 comments on commit ac25303

Please sign in to comment.