CSS
<link href="/plugins/slick/slick.css" rel="stylesheet" />
<link href="/plugins/slick/slick-theme.css" rel="stylesheet" />
<style>
@media(max-width: 480px) {
.ui-update .max-scheduler-width {
max-width: 100px;
overflow: hidden;
}
}
.ui-update .th_time {
font-size: 10px;
}
.ui-update .bookedBlock {
width: 60px;
overflow: hidden;
font-size: 9px;
max-height: 24px;
height: 24px;
padding: 0px;
}
.ui-update .timeSlot.notavailable, .ui-update .timeSlot.notavailable:hover {
background-color: #888888;
cursor: not-allowed;
}
::-webkit-scrollbar-thumb {
background-color: rgba(0,0,0,.24);
}
::-webkit-scrollbar {
-webkit-appearance: inherit;
width: 8px;
}
.ui-update .wrapper {
padding-top: 1em;
padding-bottom: 1em;
}
.ui-update .portal-bg {
background-color: #FFF;
}
.ui-update .days,
.ui-update .timeTableWrapper {
position: relative;
width: 100%;
height: 100%;
display: inline-block;
}
.ui-update .input_inline {
display: inline-block;
width: auto;
}
.ui-update .input_inline {
width: 40%;
}
#timeSelect .txt {
margin: 0 8px;
}
#timeSelect h5,
#locationSelect h5 {
display: block;
}
.ui-update .days table {
border-collapse: separate;
border-spacing: 0.5em;
}
.ui-update .days td {
background-color: #fff;
padding: 8px;
cursor: pointer;
padding: 0.5em 1em;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.ui-update .days td * {
display: block;
text-align: center;
}
.ui-update .days td.selected {
box-shadow: 0 0 5px #77A331;
z-index: 5;
}
.ui-update .days td.selected .hdg,
.ui-update .days td.selected .hdg_1,
.ui-update .days td.selected .hdg_6,
.ui-update .days td.selected .txt,
.ui-update .days td.selected .txt_minuscule {
color: #77A331;
}
.ui-update .times,
.ui-update .bookSlot {
display: none;
}
.ui-update .timeTableWrapper table {
float: left;
}
.ui-update th {
padding: 5px;
height: 35px;
}
.ui-update td {
padding: 5px;
margin: 0;
white-space: nowrap;
}
.ui-update .timeTableWrapper .right,
.ui-update .days .scheduleDaysWrapper {
overflow: auto;
}
.ui-update th {
text-align: center;
}
.ui-update .headCol th,
.ui-update .headCol td {
padding-right: 10px;
}
.ui-update .headCol tr {
height: 35px;
border-right: 1px solid #f0f0f0;
border-bottom: 1px solid #f0f0f0;
}
.ui-update .timeSlot {
text-align: center;
border: 1px solid #EEEEEE;
cursor: pointer;
transition: 150ms all ease-in-out;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
white-space: nowrap;
min-width: 75px;
height: 35px;
}
.ui-update .timeSlot:hover {
background-color: #fbfbfb;
}
.ui-update .booked {
background-color: #FEEEEB;
border-color: #FEEEEB;
cursor: not-allowed;
}
.ui-update .booked:hover {
background-color: #FEEEEB;
border-color: #FEEEEB;
cursor: not-allowed;
}
.ui-update .blocked {
background-color: #eefeeb;
border-color: #eefeeb;
cursor: not-allowed;
}
.ui-update .blocked:hover {
background-color: #eefeeb;
border-color: #eefeeb;
cursor: not-allowed;
}
.ui-update .times table .selected {
background-color: #c2d631;
border-color: #c2d631;
}
.ui-update .times table .selected:hover {
background-color: #c2d631;
}
</style>
HTML
(please note this is currently in ASP.NET but you can replace all with HAPI)
<section class="component">
<div class="component-content">
<div class="split split_alignBtm split_collapseOnMobile">
<h2 class="hdg hdg_4">Make a Reservation <%if scheduleItems.Count = 1 %>for <%=scheduleItems.Item(0).schedule_item %><%end if %></h2>
<!--#include file="/include/includeLoginUpdate.aspx"-->
</div>
<%if scheduleItems.Count = 1 Then %>
<%=scheduleItems(0).schedule_item_description %>
<% End if %>
</div>
</section>
<section class="component">
<div class="component-content">
<div class="box mix-box_outlined">
<div class="box-bd box-bd_inflated vr vr_x28">
<asp:PlaceHolder runat="server" ID="pnlSlots" Visible="false">
<h2 class="hdg hdg_6 mix-hdg_dark vr-override_x6">Select a Date</h2>
<ul id="dateSlider" class="scheduleDays">
<% Dim availSlots As Integer = 0 %>
<% for i As Integer = 0 To DateDiff(DateInterval.Day, from_date, to_date) %>
<% availSlots = slots.FindAll(Function(x) x.slot_start >= Convert.ToDateTime(String.Format("{0:d}", from_date.AddDays(i)) & " 12:00 AM") And x.slot_end <= Convert.ToDateTime(String.Format("{0:d}", from_date.AddDays(i)) & " 11:59 PM") And x.isAvailable).Count %>
<li id="<%=String.Format("{0:MMddyyyy}", from_date.AddDays(i)) %>" data-fulldate="<%=String.Format("{0:MMMM dd yyyy}", from_date.AddDays(i)) %>">
<button class="cardBtn">
<span class="cardBtn-bd">
<span class="cardBtn-txt cardBtn-txt_label">
<span><%=from_date.AddDays(i).ToString("dddd") %></span><br />
<span><%=MonthName(Month(from_date.AddDays(i))) %></span>
<span><%=Year(from_date.AddDays(i)) %></span>
</span>
<span class="cardBtn-txt cardBtn-txt_digit"><%=Day(from_date.AddDays(i)) %></span>
</span>
<span class="cardBtn-ft cardBtn-ft_alignRight">
<span class="cardBtn-txt">
<span data-pv-element="total_slots"><%=IIf(availSlots = 0, "No", availSlots) %></span> spot<%=People_Vine___Portal.functions.returnPlural(availSlots) %> available
</span>
</span>
</button>
</li>
<% next %>
</ul>
<div class="times vr vr_x8">
<!-- Populate each day of slots, using the data-for to populate the day so that when you click on a day above, it opens the correct slots-->
<h2 class="hdg hdg_6 mix-hdg_dark vr-override_x3">Make Selection: <em id="selectDate"></em></h2>
<div id="timeTable">
</div>
<% for i As Integer = 0 To DateDiff(DateInterval.Day, from_date, to_date) %>
<% curDate = from_date.AddDays(i) %>
<div data-for="<%=String.Format("{0:MMddyyyy}", curDate) %>" class="slotList" style="display: none;">
<!-- Populates date MMMMddyyyy-->
<div class="timeTableWrapper">
<div class="headCol">
<table>
<thead>
<th class="txt mix-txt_bold">Reserving</th>
</thead>
<tbody>
<!-- Each room gets populated as a separated row to allow the "scroll over" effect-->
<% For each si As People_Vine___Portal.api.scheduler.wi_schedule_item In scheduleItems %>
<tr>
<td class="txt mix-txt_bold max-scheduler-width">
<%=si.schedule_item %>
<%--<% If si.category_no > 0 Then %>
<br /><span class="label label-info"><%=si.category_name %></span>
<% end if %>--%>
</td>
</tr>
<% next %>
</tbody>
</table>
</div>
<div class="right">
<table>
<thead>
<!-- All times in the series get populated here as headers-->
<% tempEarliestTime = earliestTime %>
<% While tempEarliestTime < latestTime %>
<th class="th_time" id="<%=String.Format("{0:t}", tempEarliestTime) %>"><%=String.Format("{0:t}", tempEarliestTime) %></th>
<% tempEarliestTime = tempEarliestTime.AddMinutes(incrementMinutes) %>
<% end while %>
</thead>
<tbody>
<!-- Each room gets it's own row, and if booked, add class 'booked' to it-->
<!-- Start date can be in any format becauase it is not rendered on the page-->
<!-- startTime & endTime need to be in hh:mm because they get updated to the page -->
<% For each sc As People_Vine___Portal.api.scheduler.wi_schedule_item In scheduleItems %>
<tr data-room="<%=sc.schedule_item %>">
<!-- Need to loop through all slots and then if exists put block -->
<% tempEarliestTime = earliestTime %>
<% While tempEarliestTime < latestTime %>
<% curDate = Convert.ToDateTime(String.Format("{0:d}", curDate) & " " & String.Format("{0:t}", tempEarliestTime)) %>
<% slot = slots.Find(Function(x) x.slot_start >= curDate And x.slot_end <= curDate.AddMinutes(sc.block_duration) And x.schedule_item_no = sc.schedule_item_no) %>
<% if slot Is Nothing Then %>
<td class="timeSlot notavailable booked"> </td>
<% else %>
<td data-fee="<%=slot.slot_fee %>" data-room="<%=sc.schedule_item %>" data-starttime="<%=String.Format("{0:t}", slot.slot_start) %>" data-endtime="<%=String.Format("{0:t}", slot.slot_end) %>" data-startdate="<%=String.Format("{0:d}", slot.slot_start) %>" data-duration="<%=sc.block_duration %>" data-roomno="<%=sc.schedule_item_no %>" data-slotno="<%=slot.schedule_slot_no %>" class="timeSlot <%=IIf(slot.isAvailable, IIf(sc.canBook, "", "blocked"), "booked") %>" <%=IIf(Not slot.isAvailable And sc.canBook And sc.visibility <> "public", "title=""" & slot.customer.company_name & " (" & slot.customer.first_name & ")""", "") %>>
<% If Not slot.isAvailable And sc.canBook And sc.visibility <> "public" And slot.customer.customer_no > 0 Then %>
<div class="bookedBlock">
<%=slot.customer.company_name %><br />
<%=slot.customer.first_name %> <%=IIf(slot.customer.last_name.Length > 1, Left(slot.customer.last_name, 1), "") %>
</div>
<% else %>
<% if slot.slot_fee > 0 Then %>
<%=String.Format("{0:c}", slot.slot_fee) %>
<% else %>
<% end if %>
<% end if %>
</td>
<% end if %>
<% tempEarliestTime = tempEarliestTime.AddMinutes(incrementMinutes) %>
<% end while %>
</tr>
<% next %>
</tbody>
</table>
</div>
</div>
</div>
<% Next %>
</div>
<div class="bookSlot" id="bookSlot">
<h1 class="hdg hdg_5">Confirm Selection:</h1>
<h2 class="hdg hdg_6 mix-hdg_dark vr-override_x3"><em><span id="dateSelection">January 1st, 2016</span> <span id="roomName">Example Room</span> <span id="roomStartTime">12:00PM</span> – <span id="roomEndTime">12:30PM</span></em> <span id="roomCost">$0.00</span></h2>
<ul class="split split_alignBtm split_collapseOnMobile split_basisRight">
<li>
<span class="txt txt_feature">Please confirm the date, time and item you are booking is accurate. On the next step, you will be taken to confirm your reservation.</span>
</li>
<li>
<a href="/reservation" class="btn btn_hasIcon" id="bookNowBtn" onclick="myApp.showPleaseWait();">Continue<svg class="icon"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/media/svg/defs.svg#icon_caretRightHeavy"></use></svg>
</a>
</li>
</ul>
</div>
</asp:PlaceHolder>
<asp:PlaceHolder runat="server" ID="pnlNoSlots" Visible="false">
<h2 class="hdg hdg_4">Sorry, we don't currently have any availability at this time.</h2>
</asp:PlaceHolder>
</div>
</div>
</div>
</section>
<section class="component component_loose">
<div class="component-content">
<div class="box mix-box_outlined">
<div class="box-bd box-bd_inflated">
<div class="split split_basisRight split_collapseOnMobile">
<h3 class="hdg hdg_6 mix-hdg_brandCallout">When booking, keep in mind these restrictions:</h3>
<div>
<%if scheduleItems.Count = 1 Then %>
<% if scheduleItems(0).time_between > 0 Or scheduleItems(0).max_blocks > 0 Then %>
<ul class="blocks blocks_4to3to2to1 blocks_equalHeight">
<% if scheduleItems(0).time_between > 0 Then %>
<li>
<a class="cardBtn">
<span class="cardBtn-bd">
<span class="cardBtn-txt cardBtn-txt_label">Time Between<br />
Reservations
</span>
<span class="cardBtn-txt cardBtn-txt_digit"><%=IIf(scheduleItems(0).time_between > 1440, scheduleItems(0).time_between / 1440, IIf(scheduleItems(0).time_between > 60, scheduleItems(0).time_between / 60, scheduleItems(0).time_between)) %></span> <small><%=IIf(scheduleItems(0).time_between > 1440, "days", IIf(scheduleItems(0).time_between > 60, "hours", "minutes")) %></small>
</span>
</a>
</li>
<% End if %>
<% If scheduleItems(0).max_blocks > 0 Then %>
<li>
<a class="cardBtn">
<span class="cardBtn-bd">
<span class="cardBtn-txt cardBtn-txt_label">Max Slots<br />
Per Booking
</span>
<span class="cardBtn-txt cardBtn-txt_digit"><%=scheduleItems(0).max_blocks %></span>
<small><%=IIf(scheduleItems(0).block_duration > 1440, scheduleItems(0).block_duration / 1440, IIf(scheduleItems(0).block_duration > 60, scheduleItems(0).block_duration / 60, scheduleItems(0).block_duration)) %> minutes each</small>
</span>
</a>
</li>
<% end if %>
</ul>
<% else %>
<% End if %>
<% else %>
<ul class="blocks blocks_4to3to2to1 blocks_equalHeight">
<% If maxSlots > 0 Then %>
<li>
<a class="cardBtn">
<span class="cardBtn-bd">
<span class="cardBtn-txt cardBtn-txt_label">Max Slots<br />
Per Booking
</span>
<span class="cardBtn-txt cardBtn-txt_digit"><%=maxSlots %></span>
<small><%=IIf(incrementMinutes > 1440, incrementMinutes / 1440, IIf(incrementMinutes > 60, incrementMinutes / 60, incrementMinutes)) %> minutes each</small>
</span>
</a>
</li>
<% end if %>
</ul>
<% End if %>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="component component_loose">
<div class="component-content">
<div class="box mix-box_outlined">
<div class="box-bd box-bd_inflated vr">
<h2 class="hdg hdg_6 mix-hdg_dark vr-override_x6">Filter</h2>
<ul class="gridList">
<li class="gridList-item gridList-item_7of16 gridList-item_tight" style="<%=iif(request("type") = "calendar", "display:none;", "")%>">
<ul class="gridList-item-subGroup">
<li>
<span class="fieldset">
<label class="fieldset-label fieldset-label_isHidden" for="<%=sfrom_date.ClientID %>">start date</label>
<span class="fieldset-input">
<asp:TextBox runat="server" ID="sfrom_date" placeholder="MM/DD/YYYY" CssClass="js-datepicker" />
</span>
</span>
</li>
<li>
<span class="fieldset">
<label class="fieldset-label fieldset-label_isHidden" for="<%=sto_date.ClientID %>">end date</label>
<span class="fieldset-input">
<asp:TextBox runat="server" ID="sto_date" placeholder="MM/DD/YYYY" CssClass="js-datepicker" />
</span>
</span>
</li>
</ul>
</li>
<li class="gridList-item gridList-item_7of16 gridList-item_tight">
<span class="fieldset">
<label class="fieldset-label" for="<%=schedule_item_no.ClientID %>">or filter</label>
<span class="fieldset-input">
<asp:DropDownList runat="server" ID="schedule_item_no" />
</span>
</span>
</li>
<li class="gridList-item gridList-item_2of16 gridList-item_tight">
<span class="fieldset">
<label class="fieldset-label"> </label>
<asp:Button runat="server" ID="btnsub" Text="Apply" CssClass="btn mix-btn_stretch" OnClick="btnsub_Click" OnClientClick="myApp.showPleaseWait();" />
</span>
</li>
<li class="gridList-item" style="<%=iif(request("type") = "calendar", "display:none;", "")%>">
<asp:RadioButtonList runat="server" ID="filterDate" CssClass="hList tick tick_bubble" RepeatLayout="UnorderedList" AutoPostBack="true" OnSelectedIndexChanged="filterDate_SelectedIndexChanged">
<asp:ListItem Value="today">Today</asp:ListItem>
<asp:ListItem Value="tomorrow">Tomorrow</asp:ListItem>
<asp:ListItem Value="this week">This Week</asp:ListItem>
<asp:ListItem Value="next week">Next Week</asp:ListItem>
</asp:RadioButtonList>
</li>
</ul>
</div>
</div>
</div>
</section>
Javascript
<script>window.jQuery || document.write('<script src="/assets/jQuery/default/jquery.min.js">\x3C/script>')</script>
<script src="/scripts/vendor/fullcalendar/moment.min.js"></script>
<script src="/plugins/slick/slick.min.js"></script>
<script src="/scripts/components/schedulerMulti.js"></script>
<script>
//JS init for slider (init is for reference only - page is not loading Slick Slider plugin: http://kenwheeler.github.io/slick/)
var MAX_SLOTS = 10 //make dynamic based on available schedulers;
var loadSlick = function () {
var selector = '#dateSlider';
var config = {
centerPadding: '60px',
slidesToShow: 7,
arrows: true,
infinite: false,
responsive: [
{
breakpoint: 979,
settings: {
slidesToShow: 7
}
},
{
breakpoint: 767,
settings: {
slidesToShow: 3
}
},
{
breakpoint: 480,
settings: {
slidesToShow: 1
}
}
]
};
$(selector).slick(config);
};
$(document).ready(function () {
//new DatepickerHelper('.js-datepicker', { setDate: new Date(), minDate: new Date(1900, 1, 1) });
var Sch = scheduler(MAX_SLOTS);
Sch.init();
loadSlick();
$("#sfrom_date").datepicker({
defaultDate: "+1d",
changeMonth: false,
numberOfMonths: 3,
minDate: "+0d",
maxDate: "+360d",
onClose: function (selectedDate) {
$("#sto_date.ClientID").datepicker("option", "minDate", selectedDate);
}
});
$("#sto_date").datepicker({
defaultDate: "+3d",
changeMonth: false,
numberOfMonths: 3,
minDate: "+1d",
maxDate: "+360d",
onClose: function (selectedDate) {
$("#sfrom_date").datepicker("option", "maxDate", selectedDate);
}
});
});
</script>