Browse Source

processing bookings into 'free time' slots

master
Marek Piasecki 2 years ago
parent
commit
60c27ce919
  1. 10
      src/api/bookings.json
  2. 9
      src/api/bookings_2023_02_01.json
  3. 4
      src/router.imba
  4. 71
      src/ui/choose-slot.imba
  5. 5
      src/ui/date-input.imba
  6. 11
      src/ui/plus-minus.imba
  7. 7
      src/ui/slot-size-input.imba
  8. 2
      src/views/choose-slot.imba

10
src/api/bookings.json

@ -0,0 +1,10 @@
[
{ "id": "8c73d0ca-d999-4081-1558-e5ee6a40fcc2", "start": "2023-01-31T23:00:00.000Z", "end": "2023-02-01T06:00:00.000Z" },
{ "id": "4b24e6ab-bdc6-6b2c-e405-a8e01f0fde84", "start": "2023-02-01T09:00:00.000Z", "end": "2023-02-01T10:00:00.000Z" },
{ "id": "086e3a96-2c74-3d2a-e839-ad10c82626d5", "start": "2023-02-01T10:15:00.000Z", "end": "2023-02-01T10:45:00.000Z" },
{ "id": "087ddebe-dd41-7e39-bda8-f617d8c4385d", "start": "2023-02-01T11:30:00.000Z", "end": "2023-02-01T13:00:00.000Z" },
{ "id": "5117e557-8d86-4180-9326-1ce0cf733982", "start": "2023-02-01T13:00:00.000Z", "end": "2023-02-01T13:10:00.000Z" },
{ "id": "9e323a9e-adf9-605f-9386-c939a9a6af3f", "start": "2023-02-01T13:55:00.000Z", "end": "2023-02-01T14:30:00.000Z" },
{ "id": "bd8fc476-ac50-3327-4ece-d73897796852", "start": "2023-02-01T20:00:00.000Z", "end": "2023-02-01T22:30:00.000Z" },
{ "id": "0510de47-c86e-a64c-bb86-461c039b1012", "start": "2023-02-02T10:00:00.000Z", "end": "2023-02-02T20:00:00.000Z" }
]

9
src/api/bookings_2023_02_01.json

@ -0,0 +1,9 @@
[
{ "id": "8c73d0ca-d999-4081-1558-e5ee6a40fcc2", "start": "2023-01-31T23:00:00.000Z", "end": "2023-02-01T06:00:00.000Z" },
{ "id": "4b24e6ab-bdc6-6b2c-e405-a8e01f0fde84", "start": "2023-02-01T09:00:00.000Z", "end": "2023-02-01T10:00:00.000Z" },
{ "id": "086e3a96-2c74-3d2a-e839-ad10c82626d5", "start": "2023-02-01T10:15:00.000Z", "end": "2023-02-01T10:45:00.000Z" },
{ "id": "087ddebe-dd41-7e39-bda8-f617d8c4385d", "start": "2023-02-01T11:30:00.000Z", "end": "2023-02-01T13:00:00.000Z" },
{ "id": "5117e557-8d86-4180-9326-1ce0cf733982", "start": "2023-02-01T13:00:00.000Z", "end": "2023-02-01T13:10:00.000Z" },
{ "id": "9e323a9e-adf9-605f-9386-c939a9a6af3f", "start": "2023-02-01T13:55:00.000Z", "end": "2023-02-01T14:30:00.000Z" },
{ "id": "bd8fc476-ac50-3327-4ece-d73897796852", "start": "2023-02-01T20:00:00.000Z", "end": "2023-02-01T22:30:00.000Z" }
]

4
src/router.imba

@ -21,8 +21,8 @@ global css
body jc@portrait:flex-end body jc@portrait:flex-end
.active filter:hue-rotate(45deg) bxs:md .active filter:hue-rotate(45deg) bxs:md
.clickable us:none cursor@hover:pointer o@hover:0.7 tween:opacity 300ms .clickable us:none cursor@hover:pointer o@hover:0.7 tween:opacity 300ms
.bordered bd: 2px solid violet5 rd: 10px .bordered bd:2px solid violet5 rd:10px
.bordered-complex > bdr: 2px solid violet5 bdl: 2px solid violet5 .bordered-complex > bd: 2px solid violet5 bdy:none
@first bdt:2px solid violet6 rd:20px 20px 0 0 @first bdt:2px solid violet6 rd:20px 20px 0 0
@last bdb:2px solid violet6 rd:0 0 20px 20px @last bdb:2px solid violet6 rd:0 0 20px 20px

71
src/ui/choose-slot.imba

@ -0,0 +1,71 @@
import bookings from "../api/bookings_2023_02_01.json" # bookings.where ending_date >= $date and starting_date <= $date sort b sort_by starting_date
# make objects
for booking in bookings
booking.start = new Date(booking.start)
booking.end = new Date(booking.end)
import sh from "../ui/slot-size-input.imba"
let h =
resolution: 15minutes
date: do R.param('alt-day') || R.param('date')
next_day: do
return #next_day if #next_day
let day = new Date(h.date!)
day.setDate(day.getDate! + 1)
#next_day = day
slots: do
#slots ||= h.calculate_slots!
calculate_slots: do
let slots = []
unless bookings.length
slots.push start: h.date!, end: h.next_day!
else
let first = bookings[0]
if first.start > h.date!
slots.push start: h.date!, end: first.start
bookings.forEach do |booking,i|
let next = bookings[i+1]
if next
slots.push start: booking.end, end: next.start
let last = bookings[-1]
if last.end < h.next_day!
slots.push start: last.end, end: h.next_day!
for slot in slots
h.adjust(slot, 'start')
h.adjust(slot, 'end')
slot['duration'] = h.calculate_duration(slot) for slot in slots
slots
adjust: do |slot, param|
let min = Number(slot[param])
let min_mod = min % h.resolution
if min_mod != 0
slot[param] = new Date(min + ( param == 'start' ? h.resolution : 0 ) - min_mod)
calculate_duration: do |slot|
Number(slot.end) - Number(slot.start)
duration: do
h._duration ||= h.calculate_duration end: R.param('size'), start: sh.zero!
tag choose-slot
def render
h._duration = 0 # reset cache
<self>
if h.slots!.length
for d in h.slots!
if d.duration > h.duration!
<p> "{d.end}"
else
<h2> "No slot available this day"
<simple-date-input>

5
src/ui/date-input.imba

@ -44,4 +44,7 @@ tag date-input
<plus-minus value=R.param('date').getFullYear! decr=h.decr_year incr=h.incr_year> <plus-minus value=R.param('date').getFullYear! decr=h.decr_year incr=h.incr_year>
<plus-minus value=R.param('date').getMonth!+1 decorate=h.format decr=h.decr_month incr=h.incr_month> <plus-minus value=R.param('date').getMonth!+1 decorate=h.format decr=h.decr_month incr=h.incr_month>
<plus-minus value=R.param('date').getDate! decorate=h.format decr=h.decr_day incr=h.incr_day> <plus-minus value=R.param('date').getDate! decorate=h.format decr=h.decr_day incr=h.incr_day>
tag simple-date-input
<self>
<plus-minus-v decorate=R.setters.date decr=h.decr_day incr=h.incr_day value=R.param('date')>

11
src/ui/plus-minus.imba

@ -4,7 +4,7 @@ tag plus-minus
prop incr prop incr
prop decr prop decr
css m: 10px css m:10px
> miw:50px h:50px p:19px 5px 0 ta:center fs:180% > miw:50px h:50px p:19px 5px 0 ta:center fs:180%
<self.bordered-complex @wheel=(e.deltaY < 0 ? incr! : decr!)> <self.bordered-complex @wheel=(e.deltaY < 0 ? incr! : decr!)>
@ -19,4 +19,11 @@ tag plus-minus-plus
tag plus-minus-minus tag plus-minus-minus
prop decr prop decr
<self.clickable@click=decr> '-' <self.clickable@click=decr> '-'
tag plus-minus-v < plus-minus
css d:flex fld:row-reverse fs:x-small
> bd:1.8px solid violet5 bdx:none p:25px 7px 0 0
@first bdr:1.8px rd:0 20px 20px 0
@last bdl:1.8px rd:20px 0 0 20px

7
src/ui/slot-size-input.imba

@ -1,11 +1,11 @@
import './plus-minus.imba' import './plus-minus.imba'
let h = let h =
zero: do new Date(0) zero: do new Date("1.01.1970")
max_size: do #ms ||= R.getters.size "3_0_0", 1 # 3 days max_size: do #ms ||= R.getters.size "3_0_0", 1 # 3 days
validate: do |s| validate: do |s|
return R.getters.size("0_0_5", 1) if s < h.zero! return R.getters.size("0_0_5", 1) if s <= h.zero!
return new Date(h.max_size!) if s > h.max_size! return new Date(h.max_size!) if s > h.max_size!
s s
@ -49,4 +49,5 @@ tag slot-size-input
if h.days! > 0 if h.days! > 0
<plus-minus value=h.days! decorate=h.format_d decr=h.decr_day incr=h.incr_day> <plus-minus value=h.days! decorate=h.format_d decr=h.decr_day incr=h.incr_day>
<plus-minus value=R.param('size').getHours!.toString! decorate=h.format_h decr=h.decr_h incr=h.incr_h> <plus-minus value=R.param('size').getHours!.toString! decorate=h.format_h decr=h.decr_h incr=h.incr_h>
<plus-minus value=R.param('size').getMinutes!.toString! decorate=h.format_min decr=h.decr_min incr=h.incr_min> <plus-minus value=R.param('size').getMinutes!.toString! decorate=h.format_min decr=h.decr_min incr=h.incr_min>

2
src/views/choose-slot.imba

@ -1,5 +1,6 @@
import sh from "../ui/slot-size-input.imba" import sh from "../ui/slot-size-input.imba"
import "../ui/action-button.imba" import "../ui/action-button.imba"
import "../ui/choose-slot.imba"
tag view-choose-slot tag view-choose-slot
<self> <self>
@ -10,6 +11,7 @@ tag view-choose-slot
<SizeHint size="10"> <SizeHint size="10">
<SizeHint size="12"> <SizeHint size="12">
<slot-size-input> <slot-size-input>
<choose-slot>
<pro-ref view="booking-confirmation"> <pro-ref view="booking-confirmation">
<action-button[w:230px fs:larger]> "Book slot" <action-button[w:230px fs:larger]> "Book slot"

Loading…
Cancel
Save