Added customer composite key
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
<div id="<%= dom_id customer %>">
|
||||
<p class="my-5">
|
||||
<strong class="block font-medium mb-1">Name:</strong>
|
||||
<%= customer.name %>
|
||||
<strong class="block font-medium mb-1">First Name:</strong>
|
||||
<%= customer.first_name %>
|
||||
</p>
|
||||
|
||||
<p class="my-5">
|
||||
<strong class="block font-medium mb-1">Surname:</strong>
|
||||
<%= customer.surname %>
|
||||
</p>
|
||||
|
||||
<p class="my-5">
|
||||
|
||||
@@ -12,8 +12,13 @@
|
||||
<% end %>
|
||||
|
||||
<div class="my-5">
|
||||
<%= form.label :name %>
|
||||
<%= form.text_field :name, class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %>
|
||||
<%= form.label :first_name %>
|
||||
<%= form.text_field :first_name, class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %>
|
||||
</div>
|
||||
|
||||
<div class="my-5">
|
||||
<%= form.label :surname %>
|
||||
<%= form.text_field :surname, class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %>
|
||||
</div>
|
||||
|
||||
<div class="my-5">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<% @customers.each do |customer| %>
|
||||
<%= render customer %>
|
||||
<p>
|
||||
<%= link_to "Show this customer", customer, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
|
||||
<%= link_to "Show this customer", customer_path(customer), class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
|
||||
</p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
|
||||
|
||||
<%= javascript_importmap_tags %>
|
||||
<link href="https://cdn.jsdelivr.net/npm/tom-select@2.2.2/dist/css/tom-select.css" rel="stylesheet">
|
||||
<script src="https://cdn.jsdelivr.net/npm/tom-select@2.2.2/dist/js/tom-select.complete.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -12,10 +12,49 @@
|
||||
<%= stylesheet_link_tag "calendar.tailwind", "data-turbo-track": "reload" %>
|
||||
|
||||
<%= javascript_importmap_tags %>
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
overflow: hidden;
|
||||
}
|
||||
body.calendar {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
overflow: hidden;
|
||||
}
|
||||
body.calendar main {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.w-full, .min-w-full, div[data-controller="main-calendar"] {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#main-calendar {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
}
|
||||
.flex.justify-between.items-center {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 1000;
|
||||
background: rgba(255,255,255,0.8);
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="calendar">
|
||||
<main style="height: 100vw;">
|
||||
<main>
|
||||
<%= yield %>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
@@ -1,38 +1,115 @@
|
||||
<%= form_with(model: reservation, class: "contents") do |form| %>
|
||||
<% if reservation.errors.any? %>
|
||||
<div id="error_explanation" class="bg-red-50 text-red-500 px-3 py-2 font-medium rounded-lg mt-3">
|
||||
<h2><%= pluralize(reservation.errors.count, "error") %> prohibited this reservation from being saved:</h2>
|
||||
<%= form_with(model: reservation, class: "contents", data: { controller: "customer-search" }) do |form| %>
|
||||
<% if reservation.errors.any? %>
|
||||
<div id="error_explanation" class="bg-red-50 text-red-500 px-3 py-2 font-medium rounded-lg mt-3">
|
||||
<h2><%= pluralize(reservation.errors.count, "error") %> prohibited this reservation from being saved:</h2>
|
||||
|
||||
<ul>
|
||||
<% reservation.errors.each do |error| %>
|
||||
<li><%= error.full_message %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<ul>
|
||||
<% reservation.errors.each do |error| %>
|
||||
<li><%= error.full_message %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="my-5">
|
||||
<%= form.label :customer %>
|
||||
<%= form.select :customer_id,
|
||||
[], # Start with empty options
|
||||
{ prompt: "Type to search customers..." },
|
||||
{
|
||||
class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full",
|
||||
data: { customer_search_target: "select" }
|
||||
} %>
|
||||
</div>
|
||||
|
||||
<div class="my-5">
|
||||
<%= form.label :phone_number %>
|
||||
<%= form.telephone_field :customer_original_phone,
|
||||
class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full",
|
||||
data: { customer_search_target: "phoneField" } %>
|
||||
</div>
|
||||
|
||||
<div data-customer-search-target="newCustomerFields" class="hidden">
|
||||
<div class="my-5">
|
||||
<%= form.label :first_name %>
|
||||
<%= form.text_field :customer_first_name,
|
||||
class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full",
|
||||
data: { customer_search_target: "firstNameField" } %>
|
||||
</div>
|
||||
|
||||
<div class="my-5">
|
||||
<%= form.label :surname %>
|
||||
<%= form.text_field :customer_surname,
|
||||
class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full",
|
||||
data: { customer_search_target: "surnameField" } %>
|
||||
</div>
|
||||
|
||||
<div class="my-5">
|
||||
<%= form.label :birth_year %>
|
||||
<%= form.number_field :customer_birth_year,
|
||||
class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full",
|
||||
data: { customer_search_target: "birthYearField" } %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="my-5">
|
||||
<%= form.label :team_id %>
|
||||
<%= form.collection_select :team_id,
|
||||
@company.teams,
|
||||
:id,
|
||||
:name,
|
||||
{ prompt: "Select a team" },
|
||||
class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %>
|
||||
</div>
|
||||
|
||||
<div class="my-5">
|
||||
<%= form.label :start_time %>
|
||||
<%= form.datetime_field :start_time,
|
||||
class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full",
|
||||
id: "start_time_field" %>
|
||||
</div>
|
||||
|
||||
<div class="my-5">
|
||||
<%= form.label :end_time %>
|
||||
<%= form.datetime_field :end_time,
|
||||
class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full",
|
||||
id: "end_time_field" %>
|
||||
</div>
|
||||
|
||||
<div class="inline">
|
||||
<%= form.submit class: "rounded-lg py-3 px-5 bg-blue-600 text-white inline-block font-medium cursor-pointer" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="my-5">
|
||||
<%= form.label :customer_id %>
|
||||
<%= form.collection_select :customer_id, @company.customers, :id, :name, class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %>
|
||||
</div>
|
||||
|
||||
<div class="my-5">
|
||||
<%= form.label :team_id %>
|
||||
<%= form.collection_select :team_id, @company.teams, :id, :name, prompt: "Select a Team", class:"block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="my-5">
|
||||
<%= form.label :start_time %>`
|
||||
<%= form.datetime_field :start_time, class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %>
|
||||
</div>
|
||||
|
||||
<div class="my-5">
|
||||
<%= form.label :end_time %>
|
||||
<%= form.datetime_field :end_time, class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %>
|
||||
</div>
|
||||
|
||||
<div class="inline">
|
||||
<%= form.submit class: "rounded-lg py-3 px-5 bg-blue-600 text-white inline-block font-medium cursor-pointer" %>
|
||||
</div>
|
||||
<% end %>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
// Only set default times for new records (not when editing)
|
||||
<% unless reservation.persisted? %>
|
||||
// Get current date and time
|
||||
const now = new Date();
|
||||
|
||||
// Get local components
|
||||
const year = now.getFullYear();
|
||||
const month = String(now.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed
|
||||
const day = String(now.getDate()).padStart(2, '0');
|
||||
const hours = String(now.getHours()).padStart(2, '0');
|
||||
const minutes = String(now.getMinutes()).padStart(2, '0');
|
||||
|
||||
// Format for datetime-local input (YYYY-MM-DDThh:mm)
|
||||
const localStartTime = `${year}-${month}-${day}T${hours}:${minutes}`;
|
||||
document.getElementById('start_time_field').value = localStartTime;
|
||||
|
||||
// Add 30 minutes for end time
|
||||
const endDate = new Date(now.getTime() + 30 * 60000);
|
||||
const endHours = String(endDate.getHours()).padStart(2, '0');
|
||||
const endMinutes = String(endDate.getMinutes()).padStart(2, '0');
|
||||
const localEndTime = `${year}-${month}-${day}T${endHours}:${endMinutes}`;
|
||||
document.getElementById('end_time_field').value = localEndTime;
|
||||
|
||||
// For debugging - add this to see actual values
|
||||
console.log("Start time set to: " + localStartTime);
|
||||
console.log("End time set to: " + localEndTime);
|
||||
console.log("Current browser time: " + now.toString());
|
||||
<% end %>
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
|
||||
<p class="my-5">
|
||||
<strong class="block font-medium mb-1">Customer:</strong>
|
||||
<%= reservation.customer_id %>
|
||||
<%= reservation.customer.try(:full_name) || "N/A" %>
|
||||
(<%= reservation.customer.try(:birthyear) %>)
|
||||
</p>
|
||||
|
||||
<p class="my-5">
|
||||
|
||||
@@ -1,16 +1,37 @@
|
||||
<div class="w-full" style="height: 100%">
|
||||
<% if notice.present? %>
|
||||
<p class="py-2 px-3 bg-green-50 mb-5 text-green-500 font-medium rounded-lg inline-block" id="notice"><%= notice %></p>
|
||||
<% end %>
|
||||
<!-- Separate the page into two distinct parts -->
|
||||
<div class="reservation-page" data-controller="main-calendar" style="display: block; width: 100%; height: 100vh; overflow: hidden;">
|
||||
<!-- Fixed height header -->
|
||||
<header style="height: 80px; padding: 15px; background-color: white; box-shadow: 0 2px 4px rgba(0,0,0,0.1); position: relative; z-index: 100;">
|
||||
<% if notice.present? %>
|
||||
<p class="py-2 px-3 bg-green-50 text-green-500 font-medium rounded-lg inline-block" id="notice"><%= notice %></p>
|
||||
<% end %>
|
||||
|
||||
<% content_for :title, "Reservations" %>
|
||||
<% content_for :title, "Reservations" %>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<h1 class="font-bold text-4xl">Reservations</h1>
|
||||
<%= link_to "New reservation", new_reservation_path, class: "rounded-lg py-3 px-5 bg-blue-600 text-white block font-medium" %>
|
||||
<div class="flex justify-between items-center-calendar">
|
||||
<div class="flex items-center space-x-4">
|
||||
<h1 class="font-bold text-4xl px-5">Reservations</h1>
|
||||
<div class="flex items-center space-x-2 ml-6" data-main-calendar-target="navigation">
|
||||
<button data-action="main-calendar#prev" class="px-3 py-1 bg-gray-100 rounded-md hover:bg-gray-200">
|
||||
« Prev
|
||||
</button>
|
||||
<button data-action="main-calendar#today" class="px-3 py-1 bg-gray-100 rounded-md hover:bg-gray-200">
|
||||
Today
|
||||
</button>
|
||||
<button data-action="main-calendar#next" class="px-3 py-1 bg-gray-100 rounded-md hover:bg-gray-200">
|
||||
Next »
|
||||
</button>
|
||||
<span data-main-calendar-target="dateDisplay" class="ml-3 font-medium"></span>
|
||||
</div>
|
||||
</div>
|
||||
<%= link_to "New reservation", new_reservation_path, class: "rounded-lg py-3 px-5 bg-blue-600 text-white block font-medium ml-auto" %>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Calendar container - with fixed top position and precise height calculation -->
|
||||
<div class="calendar-container" style="height: calc(100vh - 80px); width: 100%; position: relative; top: 0; left: 0;">
|
||||
<div style="height: 100%; width: 100%;">
|
||||
<%= tag.div nil, data: {reservations: @reservations.to_json}, id: "main-calendar", style: "height: 100%; width: 100%;" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div data-controller="main-calendar" class="min-w-full" style="height: 90vh;" >
|
||||
<%= tag.div nil, data: {reservations: @reservations.to_json}, id: "main-calendar"%>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user