Converts tasks to lightbox form params and validates submitted params.
The lightbox uses plain HTML inputs, so dates travel as "YYYY-MM-DD"
(or "YYYY-MM-DDTHH:MM" when the duration unit is smaller than a day) and
progress as a percentage.
iex> task = GanttEx.Task.new!(id: 1, text: "Design", start_date: ~D[2025-01-06], duration: 3, progress: 0.4)
iex> GanttEx.TaskForm.params(task, :day)
%{"text" => "Design", "type" => "task", "start_date" => "2025-01-06", "duration" => "3", "progress" => "40", "parent" => "", "constraint_type" => "", "constraint_date" => "", "planned_start" => "", "planned_end" => "", "deadline" => ""}
iex> GanttEx.TaskForm.cast(%{"text" => " Build ", "type" => "task", "start_date" => "2025-01-08", "duration" => "2", "progress" => "25"}, :day)
{:ok, %{text: "Build", type: :task, start_date: ~N[2025-01-08 00:00:00], duration: 2, progress: 0.25}}
iex> GanttEx.TaskForm.cast(%{"text" => "", "start_date" => "nope", "duration" => "-1"}, :day)
{:error, [text: :required, start_date: :invalid_date, duration: :invalid_number]}
Summary
Functions
Validates submitted params.
Returns the HTML input type used for dates with the given duration unit.
Returns the end date to display.
Like display_end/2 for any end date (such as :planned_end).
Formats a datetime for a date input.
Returns the form params for a task.
Converts a displayed (inclusive) end date back to the exclusive end date.
The inverse of display_end/2.
Functions
@spec cast(map(), GanttEx.Dates.unit(), GanttEx.Store.t() | nil) :: {:ok, map()} | {:error, keyword(atom())}
Validates submitted params.
Returns {:ok, attrs} with the attributes to apply to the task, or
{:error, errors} where errors is a keyword list of field: reason. Reasons
are keys of GanttEx.I18n.labels/1 (:required, :invalid_date,
:invalid_number, :invalid_progress).
A "parent" param is resolved to a task id when a store is given (an empty
value means "top level").
@spec date_input_type(GanttEx.Dates.unit()) :: String.t()
Returns the HTML input type used for dates with the given duration unit.
iex> GanttEx.TaskForm.date_input_type(:day)
"date"
iex> GanttEx.TaskForm.date_input_type(:hour)
"datetime-local"
@spec display_end(GanttEx.Task.t(), GanttEx.Dates.unit()) :: NaiveDateTime.t() | nil
Returns the end date to display.
End dates are exclusive internally (a one-day task on January 6th ends on January 7th at midnight), but people expect to read the last day of work. For day-based units, an end date at midnight is shown as the previous day.
iex> task = GanttEx.Task.new!(id: 1, start_date: ~D[2025-01-06], end_date: ~D[2025-01-07])
iex> GanttEx.TaskForm.display_end(task, :day)
~N[2025-01-06 00:00:00]
iex> task = GanttEx.Task.new!(id: 1, start_date: ~N[2025-01-06 09:00:00], end_date: ~N[2025-01-06 17:00:00])
iex> GanttEx.TaskForm.display_end(task, :hour)
~N[2025-01-06 17:00:00]
@spec inclusive_end( NaiveDateTime.t() | nil, NaiveDateTime.t() | nil, GanttEx.Dates.unit() ) :: NaiveDateTime.t() | nil
Like display_end/2 for any end date (such as :planned_end).
iex> GanttEx.TaskForm.inclusive_end(~N[2025-01-08 00:00:00], ~N[2025-01-06 00:00:00], :day)
~N[2025-01-07 00:00:00]
iex> GanttEx.TaskForm.inclusive_end(nil, nil, :day)
nil
@spec input_date(NaiveDateTime.t() | nil, GanttEx.Dates.unit()) :: String.t()
Formats a datetime for a date input.
iex> GanttEx.TaskForm.input_date(~N[2025-01-06 09:30:00], :hour)
"2025-01-06T09:30"
@spec params(GanttEx.Task.t(), GanttEx.Dates.unit()) :: %{ required(String.t()) => String.t() }
Returns the form params for a task.
@spec parse_end(NaiveDateTime.t(), GanttEx.Dates.unit()) :: NaiveDateTime.t()
Converts a displayed (inclusive) end date back to the exclusive end date.
The inverse of display_end/2.
iex> GanttEx.TaskForm.parse_end(~N[2025-01-06 00:00:00], :day)
~N[2025-01-07 00:00:00]
iex> GanttEx.TaskForm.parse_end(~N[2025-01-06 17:00:00], :hour)
~N[2025-01-06 17:00:00]