Files: e8abaef0cdb1e98c6610e0ff0db2c36145877d4a / views / new.js
4185 bytesRaw
1 | const { h, Value, Struct, Array: MutantArray, when, computed } = require('mutant') |
2 | const Marama = require('marama') |
3 | |
4 | module.exports = function ScryNew (opts) { |
5 | const { |
6 | // i18n |
7 | } = opts |
8 | |
9 | const state = Struct({ |
10 | pristine: true, |
11 | monthIndex: new Date().getMonth(), |
12 | days: MutantArray([]), |
13 | times: MutantArray([]) |
14 | }) |
15 | |
16 | return h('ScryNew', [ |
17 | h('div.cal-picker', [ |
18 | h('div.month-picker', [ |
19 | h('button', { 'ev-click': () => setMonth(-1) }, '<'), |
20 | MonthTitle(state.monthIndex), |
21 | h('button', { 'ev-click': () => setMonth(+1) }, '>') |
22 | ]), |
23 | computed(state, ({ monthIndex, days }) => { |
24 | return Marama({ |
25 | monthIndex, |
26 | events: days, |
27 | onSelect, |
28 | styles: { |
29 | weekFormat: 'rows', |
30 | showNumbers: true, |
31 | tileRadius: 16, |
32 | tileGap: 8 |
33 | } |
34 | }) |
35 | }) |
36 | ]), |
37 | when(state.pristine, |
38 | h('div.time-picker-pristine', [ |
39 | h('label', 'Dates and Times'), |
40 | h('div.instruction', 'Select one or multiple dates') |
41 | ]), |
42 | h('div.time-picker', [ |
43 | h('label', computed(state.days, days => `Same times for all dates (${days.length})`)), |
44 | h('div.picker', [ |
45 | computed(state.times, times => { |
46 | return times |
47 | .map(time => time.date) |
48 | // .sort((a, b) => a - b) |
49 | .map(TimeEntry) |
50 | }), |
51 | NewTimeEntry() |
52 | ]), |
53 | h('div.timezone', [ |
54 | h('label', 'Timezone of your scry is'), |
55 | h('div.zone', [ |
56 | getTimezone(), |
57 | h('span', ['(UTC ', getTimezoneOffset(), ')']) |
58 | ]) |
59 | ]) |
60 | ]) |
61 | ) |
62 | ]) |
63 | |
64 | // functions |
65 | |
66 | function setMonth (d) { |
67 | state.monthIndex.set(state.monthIndex() + d) |
68 | } |
69 | |
70 | function NewTimeEntry () { |
71 | var active = Value(false) |
72 | |
73 | // TODO extract and only run once |
74 | const options = Array(96).fill(0).map((_, i) => { |
75 | var time = new Date () |
76 | time.setHours(0) |
77 | time.setMinutes(15 * i) |
78 | return time |
79 | |
80 | }) |
81 | |
82 | return h('div.new-time-entry', [ |
83 | when(active, |
84 | h('div.dropdown', options.map(time => { |
85 | return h('div', |
86 | { |
87 | 'ev-click': () => { |
88 | state.times.push(Event(time)) |
89 | active.set(false) |
90 | } |
91 | }, |
92 | printTime(time) |
93 | ) |
94 | })) |
95 | ), |
96 | h('div.add', { 'ev-click': () => active.set(true) }, '+ Add more times') |
97 | ]) |
98 | } |
99 | |
100 | function TimeEntry (date) { |
101 | return h('div.time-entry', [ |
102 | h('div.time', printTime(date)), |
103 | h('div.close', { 'ev-click': () => removeTime(date) }, '×') |
104 | // h('i.fa.fa-close') |
105 | ]) |
106 | } |
107 | |
108 | function removeTime (d) { |
109 | var ev = state.times.find(time => time.date === d) |
110 | |
111 | if (ev) state.times.delete(ev) |
112 | } |
113 | |
114 | function MonthTitle (monthIndex) { |
115 | const MONTHS = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ] |
116 | |
117 | return computed(monthIndex, mi => { |
118 | const view = new Date() |
119 | view.setMonth(mi) |
120 | |
121 | return `${MONTHS[view.getMonth()]} ${view.getFullYear()}` |
122 | |
123 | // while (monthIndex < 0) { monthIndex += 12 } |
124 | // return `${MONTHS[(monthIndex) % 12]} ${year}` |
125 | }) |
126 | } |
127 | |
128 | function onSelect ({ gte, lt, events: days }) { |
129 | if (!days.length) addEmptyEvent() |
130 | else clearDay() |
131 | |
132 | state.pristine.set(false) |
133 | |
134 | function addEmptyEvent () { |
135 | state.days.push(Event(gte)) |
136 | } |
137 | function clearDay () { |
138 | const filteredEvents = state.days().filter(e => !days.includes(e)) |
139 | state.days.set(filteredEvents) |
140 | } |
141 | } |
142 | } |
143 | |
144 | function Event (date) { |
145 | return { |
146 | date, |
147 | data: {attending: true} |
148 | } |
149 | } |
150 | |
151 | function getTimezone () { |
152 | try { |
153 | return Intl.DateTimeFormat().resolvedOptions().timeZone |
154 | } catch (e) { |
155 | return '??' |
156 | } |
157 | } |
158 | |
159 | function getTimezoneOffset () { |
160 | return new Date().getTimezoneOffset() / 60 |
161 | } |
162 | |
163 | function printTime (date) { |
164 | var hours = date.getHours().toString() |
165 | while (hours.length < 2) hours = `0${hours}` |
166 | |
167 | var minutes = date.getMinutes().toString() |
168 | while (minutes.length < 2) minutes = `0${minutes}` |
169 | |
170 | return `${hours}:${minutes}` |
171 | } |
172 |
Built with git-ssb-web