Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions app/frontend/javascript/controllers/datetime_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
connect() {
// Find the form element
const form = this.element.closest("form")
if (!form) return

// Add a submit event listener to combine date and time before submission
form.addEventListener("submit", this.combineDateTime.bind(this))
}

combineDateTime(event) {
// Find all date inputs that have corresponding time inputs
const dateFields = this.element.querySelectorAll('input[data-datetime-part="date"]')

dateFields.forEach(dateInput => {
const fieldName = dateInput.dataset.datetimeField
const timeInput = this.element.querySelector(`input[data-datetime-part="time"][data-datetime-field="${fieldName}"]`)

if (timeInput) {
const dateValue = dateInput.value
const timeValue = timeInput.value

// Only combine if both date and time have values, or if date has a value and field is required
if (dateValue && timeValue) {
// Combine date and time in ISO 8601 format
dateInput.value = `${dateValue}T${timeValue}`
} else if (!dateValue) {
// If date is empty, keep it empty (will trigger validation)
dateInput.value = ""
} else if (dateValue && !timeValue && dateInput.required) {
// If date exists but time is missing and field is required, keep the original date value
// This will allow server-side validation to handle missing time
dateInput.value = dateValue
}
}
})
}
}
68 changes: 50 additions & 18 deletions app/views/events/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,30 @@
<% end %>
</div>

<div class="grid grid-cols-1 md:grid-cols-3 gap-6 my-12">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 my-12" data-controller="datetime">
<div>
<%= f.label :start_date,
"Start time",
required: true,
class: "block font-medium mb-1" %>

<%= f.text_field :start_date,
type: "datetime-local",
class:
"w-full rounded border-gray-300 shadow-sm px-3 py-2 focus:ring-blue-500 focus:border-blue-500",
value: @event.start_date&.strftime("%Y-%m-%dT%H:%M"),
required: true %>
<div class="flex gap-2">
<%= f.text_field :start_date,
type: "date",
class:
"flex-1 rounded border-gray-300 shadow-sm px-3 py-2 focus:ring-blue-500 focus:border-blue-500",
value: @event.start_date&.strftime("%Y-%m-%d"),
required: true,
data: { datetime_part: "date", datetime_field: "start_date" } %>

<%= text_field_tag "start_time",
@event.start_date&.strftime("%H:%M"),
type: "time",
class:
"flex-1 rounded border-gray-300 shadow-sm px-3 py-2 focus:ring-blue-500 focus:border-blue-500",
required: true,
data: { datetime_part: "time", datetime_field: "start_date" } %>
</div>

<% if f.object.errors[:start_date].any? %>
<p class="text-red-500 text-sm mt-1">Start date
Expand All @@ -66,12 +77,23 @@
<div>
<%= f.label :end_date, "End time", required: true, class: "block font-medium mb-1" %>

<%= f.text_field :end_date,
type: "datetime-local",
class:
"w-full rounded border-gray-300 shadow-sm px-3 py-2 focus:ring-blue-500 focus:border-blue-500",
value: @event.end_date&.strftime("%Y-%m-%dT%H:%M"),
required: true %>
<div class="flex gap-2">
<%= f.text_field :end_date,
type: "date",
class:
"flex-1 rounded border-gray-300 shadow-sm px-3 py-2 focus:ring-blue-500 focus:border-blue-500",
value: @event.end_date&.strftime("%Y-%m-%d"),
required: true,
data: { datetime_part: "date", datetime_field: "end_date" } %>

<%= text_field_tag "end_time",
@event.end_date&.strftime("%H:%M"),
type: "time",
class:
"flex-1 rounded border-gray-300 shadow-sm px-3 py-2 focus:ring-blue-500 focus:border-blue-500",
required: true,
data: { datetime_part: "time", datetime_field: "end_date" } %>
</div>

<% if f.object.errors[:end_date].any? %>
<p class="text-red-500 text-sm mt-1">End date
Expand All @@ -84,11 +106,21 @@
"Registration close time",
class: "block font-medium mb-1" %>

<%= f.text_field :registration_close_date,
type: "datetime-local",
class:
"w-full rounded border-gray-300 shadow-sm px-3 py-2 focus:ring-blue-500 focus:border-blue-500",
value: @event.registration_close_date&.strftime("%Y-%m-%dT%H:%M") %>
<div class="flex gap-2">
<%= f.text_field :registration_close_date,
type: "date",
class:
"flex-1 rounded border-gray-300 shadow-sm px-3 py-2 focus:ring-blue-500 focus:border-blue-500",
value: @event.registration_close_date&.strftime("%Y-%m-%d"),
data: { datetime_part: "date", datetime_field: "registration_close_date" } %>

<%= text_field_tag "registration_close_time",
@event.registration_close_date&.strftime("%H:%M"),
type: "time",
class:
"flex-1 rounded border-gray-300 shadow-sm px-3 py-2 focus:ring-blue-500 focus:border-blue-500",
data: { datetime_part: "time", datetime_field: "registration_close_date" } %>
</div>

<% if f.object.errors[:registration_close_date].any? %>
<p class="text-red-500 text-sm mt-1">
Expand Down
9 changes: 6 additions & 3 deletions spec/views/events/_form.html.erb_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@
expect(rendered).to have_selector("form")
expect(rendered).to have_field("event[title]", with: "Original Title")
expect(rendered).to have_selector("#event_rhino_description[type='hidden']", visible: :all)
expect(rendered).to have_selector("input[type='datetime-local'][name='event[start_date]']")
expect(rendered).to have_selector("input[type='datetime-local'][name='event[end_date]']")
expect(rendered).to have_selector("input[type='datetime-local'][name='event[registration_close_date]']")
expect(rendered).to have_selector("input[type='date'][name='event[start_date]']")
expect(rendered).to have_selector("input[type='time'][name='start_time']")
expect(rendered).to have_selector("input[type='date'][name='event[end_date]']")
expect(rendered).to have_selector("input[type='time'][name='end_time']")
expect(rendered).to have_selector("input[type='date'][name='event[registration_close_date]']")
expect(rendered).to have_selector("input[type='time'][name='registration_close_time']")
expect(rendered).to have_selector("input[type='checkbox'][name='event[published]']")
end

Expand Down