nitro-web 0.0.144 → 0.0.146
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/index.ts +5 -5
- package/components/partials/element/calendar.tsx +63 -40
- package/components/partials/element/filters.tsx +98 -69
- package/components/partials/element/table.tsx +40 -53
- package/components/partials/element/timepicker.tsx +119 -0
- package/components/partials/form/field-color.tsx +27 -19
- package/components/partials/form/field-currency.tsx +108 -102
- package/components/partials/form/field-date.tsx +167 -93
- package/components/partials/form/field.tsx +16 -29
- package/components/partials/styleguide.tsx +94 -40
- package/package.json +3 -4
- package/types/util.d.ts +3 -8
- package/types/util.d.ts.map +1 -1
- package/util.js +9 -24
- package/components/partials/form/field-time.tsx +0 -214
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
Drop, Dropdown, Field, Select, Button as ButtonNitro, Checkbox, GithubLink, Modal, Calendar, injectedConfig,
|
|
3
|
-
Filters, FiltersHandleType, FilterType, Table, TableColumn,
|
|
2
|
+
Drop, Dropdown, Field, Select, Button as ButtonNitro, Checkbox, GithubLink, Modal, Calendar, injectedConfig, TimePicker,
|
|
3
|
+
Filters, FiltersHandleType, FilterType, Table, TableColumn, usePushChangesToPath,
|
|
4
4
|
} from 'nitro-web'
|
|
5
5
|
import { date, getCountryOptions, getCurrencyOptions, onChange, ucFirst } from 'nitro-web/util'
|
|
6
6
|
import { Check, EllipsisVerticalIcon, FileEditIcon } from 'lucide-react'
|
|
@@ -35,6 +35,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
|
|
|
35
35
|
const [, setStore] = useTracked()
|
|
36
36
|
const [customerSearch, setCustomerSearch] = useState('')
|
|
37
37
|
const [showModal1, setShowModal1] = useState(false)
|
|
38
|
+
|
|
38
39
|
// Tip: handy when developing or updating components, you can hide/show the groups you want to see
|
|
39
40
|
const groups = [
|
|
40
41
|
'Links',
|
|
@@ -45,32 +46,65 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
|
|
|
45
46
|
'Selects',
|
|
46
47
|
'Inputs',
|
|
47
48
|
'Date Inputs',
|
|
48
|
-
'File Inputs & Calendar',
|
|
49
|
+
'File Inputs & Calendar & Time',
|
|
49
50
|
'Tables',
|
|
50
51
|
'Modals',
|
|
51
52
|
'Custom Components',
|
|
52
53
|
]
|
|
53
|
-
const [state, setState] = useState(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
54
|
+
const [state, setState] = useState(() => getState())
|
|
55
|
+
|
|
56
|
+
function getState(useOldValues?: boolean) {
|
|
57
|
+
return !useOldValues ? {
|
|
58
|
+
address: '',
|
|
59
|
+
amount: 100,
|
|
60
|
+
brandColor: '#F3CA5F',
|
|
61
|
+
colorsMulti: ['blue', 'green'],
|
|
62
|
+
country: 'nz',
|
|
63
|
+
currency: 'nzd',
|
|
64
|
+
date: Date.now(),
|
|
65
|
+
'date-range': [Date.now(), Date.now() + 1000 * 60 * 60 * 24 * 33],
|
|
66
|
+
'date-multiple': [Date.now(), Date.now() + 1000 * 60 * 60 * 24 * 2],
|
|
67
|
+
'date-time': Date.now(),//////
|
|
68
|
+
time: Date.now(),
|
|
69
|
+
'calendar-single': Date.now(),
|
|
70
|
+
'calendar-range': [Date.now(), Date.now() + 1000 * 60 * 60 * 24 * 8],
|
|
71
|
+
firstName: 'Bruce',
|
|
72
|
+
tableFilter: '',
|
|
73
|
+
errors: [
|
|
74
|
+
{ title: 'address', detail: 'Address is required' },
|
|
75
|
+
],
|
|
76
|
+
} : {
|
|
77
|
+
address: '',
|
|
78
|
+
amount: 200,
|
|
79
|
+
brandColor: '#8656ED',
|
|
80
|
+
colorsMulti: ['blue'],
|
|
81
|
+
country: 'au',
|
|
82
|
+
currency: 'btc',
|
|
83
|
+
date: Date.now() + 1000 * 60 * 60 * 24 * 1.2,
|
|
84
|
+
'date-range': [Date.now(), Date.now() + 1000 * 60 * 60 * 24 * 5.2],
|
|
85
|
+
'date-multiple': [Date.now(), Date.now() + 1000 * 60 * 60 * 24 * 3.2],
|
|
86
|
+
'date-time': Date.now() + 1000 * 60 * 60 * 24 * 2.2,
|
|
87
|
+
time: Date.now() + 1000 * 60 * 60 * 1.2,
|
|
88
|
+
'calendar-single': Date.now(),
|
|
89
|
+
'calendar-range': [Date.now(), Date.now() + 1000 * 60 * 60 * 24 * 3.2],
|
|
90
|
+
firstName: 'John',
|
|
91
|
+
tableFilter: '',
|
|
92
|
+
errors: [
|
|
93
|
+
{ title: 'address', detail: 'Address is required' },
|
|
94
|
+
],
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function indirectlyChangeTheState() {
|
|
99
|
+
// Change the state indirectly to test the inputs reactivity
|
|
100
|
+
setState((s: typeof state) => {
|
|
101
|
+
if (s.firstName == 'Bruce') return getState(true)
|
|
102
|
+
else return getState(false)
|
|
103
|
+
})
|
|
104
|
+
}
|
|
71
105
|
|
|
72
106
|
const [filterState, setFilterState] = useState({})
|
|
73
|
-
const
|
|
107
|
+
const pushChangesToPath = usePushChangesToPath(filterState)
|
|
74
108
|
const filters = useMemo(() => {
|
|
75
109
|
const filters: FilterType[] = [
|
|
76
110
|
{
|
|
@@ -200,7 +234,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
|
|
|
200
234
|
<h1 class="h1">{injectedConfig.isDemo ? 'Design System' : 'Style Guide'}</h1>
|
|
201
235
|
<p class="mb-3">
|
|
202
236
|
Components are styled using
|
|
203
|
-
<a href="https://v3.tailwindcss.com/docs/configuration" class="underline" target="_blank" rel="noreferrer">TailwindCSS</a>.
|
|
237
|
+
<a href="https://v3.tailwindcss.com/docs/configuration" class="underline" target="_blank" rel="noreferrer">TailwindCSS</a>. {injectedConfig.isDemo && <><a href="#" class="underline" onClick={indirectlyChangeTheState}>Click here</a> to indirectly change the state</>}
|
|
204
238
|
</p>
|
|
205
239
|
</div>
|
|
206
240
|
|
|
@@ -248,8 +282,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
|
|
|
248
282
|
<h2 class="h3">Filters</h2>
|
|
249
283
|
<div class="flex flex-wrap gap-x-6 gap-y-4 mb-6">
|
|
250
284
|
{/* Filter dropdown */}
|
|
251
|
-
<Filters
|
|
252
|
-
ref={filtersRef}
|
|
285
|
+
<Filters
|
|
253
286
|
filters={filters}
|
|
254
287
|
state={filterState}
|
|
255
288
|
setState={setFilterState}
|
|
@@ -263,10 +296,10 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
|
|
|
263
296
|
name="search"
|
|
264
297
|
id="search2"
|
|
265
298
|
iconPos="left"
|
|
266
|
-
state={filterState}
|
|
299
|
+
state={filterState}
|
|
267
300
|
onChange={(e) => {
|
|
268
|
-
onChange(e, setFilterState)
|
|
269
|
-
|
|
301
|
+
onChange(e, setFilterState) // update the filter state first
|
|
302
|
+
pushChangesToPath()
|
|
270
303
|
}}
|
|
271
304
|
placeholder="Linked search bar..."
|
|
272
305
|
/>
|
|
@@ -464,7 +497,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
|
|
|
464
497
|
<div>
|
|
465
498
|
<label for="amount">Amount ({state.amount})</label>
|
|
466
499
|
<Field
|
|
467
|
-
name="amount" type="currency" state={state} currency={state.currency || 'nzd'}
|
|
500
|
+
name="amount" type="currency" state={state} currency={state.currency || 'nzd'}
|
|
468
501
|
// Example of using a custom format and currencies, e.g.
|
|
469
502
|
format={'¤#,##0.00'}
|
|
470
503
|
currencies={currencies}
|
|
@@ -480,9 +513,13 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
|
|
|
480
513
|
<div class="grid grid-cols-1 gap-x-6 sm:grid-cols-3">
|
|
481
514
|
<div>
|
|
482
515
|
<label for="date">Date with time</label>
|
|
483
|
-
<Field name="date-time" type="date" mode="single" showTime={true} state={state} onChange={(e) => onChange(e, setState)}
|
|
516
|
+
<Field name="date-time" type="date" mode="single" showTime={true} state={state} onChange={(e) => onChange(e, setState)}
|
|
517
|
+
// Testing timezone support:
|
|
518
|
+
// tz="Pacific/Honolulu"
|
|
519
|
+
// DropdownProps={{ menuIsOpen: true }}
|
|
520
|
+
/>
|
|
484
521
|
</div>
|
|
485
|
-
|
|
522
|
+
<div>
|
|
486
523
|
<label for="date-range">Date range (with prefix & disabled days)</label>
|
|
487
524
|
<Field
|
|
488
525
|
name="date-range"
|
|
@@ -498,32 +535,49 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
|
|
|
498
535
|
</div>
|
|
499
536
|
<div>
|
|
500
537
|
<label for="date">Date multi-select (right aligned)</label>
|
|
501
|
-
<Field name="date" type="date" mode="multiple" state={state} onChange={(e) => onChange(e, setState)} dir="bottom-right" />
|
|
538
|
+
<Field name="date-multiple" type="date" mode="multiple" state={state} onChange={(e) => onChange(e, setState)} dir="bottom-right" />
|
|
502
539
|
</div>
|
|
503
540
|
<div>
|
|
504
541
|
<label for="time">Time</label>
|
|
505
|
-
<Field name="time" type="time" state={state} onChange={(e) => onChange(e, setState)}
|
|
542
|
+
<Field name="time" type="date" mode="time" state={state} onChange={(e) => onChange(e, setState)}
|
|
543
|
+
// Testing timezone support:
|
|
544
|
+
// tz="Pacific/Honolulu"
|
|
545
|
+
/>
|
|
506
546
|
</div>
|
|
507
547
|
</div>
|
|
508
548
|
</div>
|
|
509
549
|
)}
|
|
510
550
|
|
|
511
|
-
{groups.includes('File Inputs & Calendar') && (
|
|
551
|
+
{groups.includes('File Inputs & Calendar & Time') && (
|
|
512
552
|
<div>
|
|
513
|
-
<h2 class="h3">File Inputs & Calendar</h2>
|
|
553
|
+
<h2 class="h3">File Inputs & Calendar & Time</h2>
|
|
514
554
|
<div class="grid grid-cols-3 gap-x-6">
|
|
515
555
|
<div>
|
|
516
556
|
<label for="avatar">Avatar</label>
|
|
517
557
|
<Drop class="is-small" name="avatar" state={state} onChange={(e) => onChange(e, setState)} awsUrl={injectedConfig.awsUrl} />
|
|
518
558
|
</div>
|
|
519
559
|
<div>
|
|
520
|
-
<label for="calendar">
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
560
|
+
<label for="calendar">
|
|
561
|
+
Calendar
|
|
562
|
+
{/* {' ' + new Date(state['calendar-single'] || '')?.toLocaleString('en-US', { timeZone: 'Pacific/Honolulu' })} */}
|
|
563
|
+
</label>
|
|
564
|
+
<Calendar mode="range" value={state['calendar-range']} numberOfMonths={1}
|
|
565
|
+
onChange={(value) => onChange({ target: { name: 'calendar-range', value: value } }, setState)}
|
|
566
|
+
// Testing timezone support:
|
|
567
|
+
// tz="Pacific/Honolulu"
|
|
568
|
+
// preserveTime={true}
|
|
525
569
|
/>
|
|
526
570
|
</div>
|
|
571
|
+
<div>
|
|
572
|
+
<label for="time">TimePicker</label>
|
|
573
|
+
<div className="mt-2.5 mb-6 mt-input-before mb-input-after pt-2">
|
|
574
|
+
<TimePicker value={state.time} className="min-h-[150]"
|
|
575
|
+
onChange={(value) => onChange({ target: { name: 'time', value: value }}, setState)}
|
|
576
|
+
// Testing timezone support:
|
|
577
|
+
// tz="Pacific/Honolulu"
|
|
578
|
+
/>
|
|
579
|
+
</div>
|
|
580
|
+
</div>
|
|
527
581
|
</div>
|
|
528
582
|
</div>
|
|
529
583
|
)}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nitro-web",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.146",
|
|
4
4
|
"repository": "github:boycce/nitro-web",
|
|
5
5
|
"homepage": "https://boycce.github.io/nitro-web/",
|
|
6
6
|
"description": "Nitro is a battle-tested, modular base project to turbocharge your projects, styled using Tailwind 🚀",
|
|
@@ -29,14 +29,14 @@
|
|
|
29
29
|
"types": "tsc util.js ./server/index.js --declaration --declarationMap --allowJs --emitDeclarationOnly --jsx react-jsx --esModuleInterop --skipLibCheck --outDir types && cd ../webpack && npm run types -w . && cd ../core"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
+
"@date-fns/tz": "^1.4.1",
|
|
32
33
|
"@hokify/axios": "^0.19.1",
|
|
33
34
|
"axios": "^1.9.0",
|
|
34
35
|
"axios-retry": "^3.3.1",
|
|
35
36
|
"bcrypt": "^5.0.0",
|
|
36
37
|
"body-parser": "^1.19.0",
|
|
37
38
|
"compression": "^1.7.4",
|
|
38
|
-
"date-fns": "^
|
|
39
|
-
"dateformat": "^5.0.3",
|
|
39
|
+
"date-fns": "^4.1.0",
|
|
40
40
|
"dotenv": "^14.3.2",
|
|
41
41
|
"express": "^4.17.1",
|
|
42
42
|
"express-fileupload": "^1.1.6",
|
|
@@ -53,7 +53,6 @@
|
|
|
53
53
|
"tailwind-merge": "^2.6.0"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@types/dateformat": "^5.0.3",
|
|
57
56
|
"@typescript-eslint/eslint-plugin": "^8.18.1"
|
|
58
57
|
},
|
|
59
58
|
"peerDependencies": {
|
package/types/util.d.ts
CHANGED
|
@@ -111,17 +111,12 @@ export function currency(cents: number, decimals?: number, decimalsMinimum?: num
|
|
|
111
111
|
export function currencyToCents(currency: string): string;
|
|
112
112
|
/**
|
|
113
113
|
* Returns a formatted date string
|
|
114
|
-
* @param {number|Date} [date] -
|
|
115
|
-
* @param {string} [
|
|
114
|
+
* @param {number|Date} [date] - timestamp or date
|
|
115
|
+
* @param {string} [pattern] - e.g. "dd mmmm yy" (https://date-fns.org/v4.1.0/docs/format#)
|
|
116
116
|
* @param {string} [timezone] - convert a UTC date to a particular timezone.
|
|
117
117
|
* @returns {string}
|
|
118
|
-
*
|
|
119
|
-
* Note on the timezone conversion:
|
|
120
|
-
* Timezone conversion relies on parsing the toLocaleString result, e.g. 4/10/2012, 5:10:30 PM.
|
|
121
|
-
* A older browser may not accept en-US formatted date string to its Date constructor, and it may
|
|
122
|
-
* return unexpected result (it may ignore daylight saving).
|
|
123
118
|
*/
|
|
124
|
-
export function date(date?: number | Date,
|
|
119
|
+
export function date(date?: number | Date, pattern?: string, timezone?: string): string;
|
|
125
120
|
/**
|
|
126
121
|
* @template {(...args: any[]) => any} T
|
|
127
122
|
* Creates a debounced function that delays invoking `func` until after `wait`
|
package/types/util.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../util.js"],"names":[],"mappings":"AA2CA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+BC;AAED;;;;;;;;;GASG;AACH,yBARa,sBAAsB,CAoBlC;AAED;;;;;GAKG;AACH,8BAJW,MAAM,cACN;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAC,GACrB,MAAM,CAKlB;AAED;;;;;;GAMG;AACH,+BALW,MAAM,oBACN,OAAO,gBACP,OAAO,GACL,MAAM,CAelB;AAED;;;;;GAKG;AACH,sCAJW,MAAM,wBACN,OAAO,GACL,MAAM,CAMlB;AAED;;;;GAIG;AACH,sCAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;GAIG;AACH,iCAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;GAMG;AACH,gCALW,MAAM,aACN,MAAM,oBACN,MAAM,GACJ,MAAM,CAUlB;AAED;;;;GAIG;AACH,0CAHW,MAAM,GACJ,MAAM,CAMlB;AAED
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../util.js"],"names":[],"mappings":"AA2CA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+BC;AAED;;;;;;;;;GASG;AACH,yBARa,sBAAsB,CAoBlC;AAED;;;;;GAKG;AACH,8BAJW,MAAM,cACN;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAC,GACrB,MAAM,CAKlB;AAED;;;;;;GAMG;AACH,+BALW,MAAM,oBACN,OAAO,gBACP,OAAO,GACL,MAAM,CAelB;AAED;;;;;GAKG;AACH,sCAJW,MAAM,wBACN,OAAO,GACL,MAAM,CAMlB;AAED;;;;GAIG;AACH,sCAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;GAIG;AACH,iCAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;GAMG;AACH,gCALW,MAAM,aACN,MAAM,oBACN,MAAM,GACJ,MAAM,CAUlB;AAED;;;;GAIG;AACH,0CAHW,MAAM,GACJ,MAAM,CAMlB;AAED;;;;;;GAMG;AACH,4BALW,MAAM,GAAC,IAAI,YACX,MAAM,aACN,MAAM,GACJ,MAAM,CAOlB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,yBAnBuC,CAAC,SAA3B,CAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAI,QAI3B,CAAC,SACD,MAAM,YACN;IACN,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GACS,CAAC,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG;IACpD,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,UAAU,CAAC,CAAC,CAAC,CAAA;CAC7B,CAwKH;AAED;;;;;GAKG;AACH,yBAJa,CAAC,OACH,CAAC,GACC,CAAC,CAgBb;AAED;;;;;GAKG;AACH,8BAJW,MAAM,GAAC,GAAG,EAAE,QACZ,MAAM,GACJ,OAAO,CAgBnB;AAED;;;;;;;GAOG;AACH,wBANa,CAAC,OACH,CAAC,QACD,MAAM,SACN,OAAO,WAAS,GACd,CAAC,CAKb;AAED;;;;;;;GAOG;AACH,gCANa,CAAC,QACH,CAAC,QACD,MAAM,SACN,OAAO,WAAS,GACd;IAAE,GAAG,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,CAAC,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAgCpD;AAED;;;;;;GAMG;AACH,0BALW;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAC,GAAC,EAAE,GAAC,IAAI,gCAE5B,MAAM,GACJ,MAAM,GAAC,EAAE,GAAC,IAAI,CAmB1B;AAED;;;;;;;;;GASG;AACH,mCARW,MAAM,GAAC,IAAI,GAAC,IAAI,GAAC,UAAU,CAAC,WAAW,CAAC,YACxC,MAAM,SACN,MAAM,QACN,MAAM,GACJ,IAAI,CA+BhB;AAED;;;;;GAKG;AACH,mCAJW,MAAM,iBACN,OAAO,GACL,MAAM,CAMlB;AAED;;;;GAIG;AACH,mCAHW,MAAM,GACJ,MAAM,CAWlB;AAED;;;;;;;;GAQG;AACH,8BAPW,MAAM,QACN;IAAE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAAE,qBAC5G,QAAQ,cACR,MAAM,GACJ,QAAQ,CAwEpB;AAED;;;;GAIG;AACH,iCAHW;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,GACnC,MAAM,CAIlB;AAED;;;;GAIG;AACH,sCAHW,MAAM,GACJ,MAAM,EAAE,CASpB;AAED;;;;GAIG;AACH,6CAHW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACjC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAS5D;AAED;;;;GAIG;AACH,+CAHW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACjC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAS9C;AAED;;;;;GAKG;AACH,yCAJW;IAAE,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,GAAC,SAAS,QAC1D,MAAM,GAAC,MAAM,GACX;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAC,SAAS,CAQvD;AAED;;;;;GAKG;AACH,uCAJW,MAAM,iBACN,MAAM,GACJ,MAAM,CAYlB;AAED;;;;;GAKG;AACH,qCAJW;IAAE,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,MAAM,CAAA;CAAE,QACvC,MAAM,GACJ,MAAM,CAYlB;AAED;;;;GAIG;AACH,6DAHW,MAAM,GACJ,OAAO,CAAC,OAAO,mBAAmB,EAAE,MAAM,GAAC,IAAI,CAAC,CAI5D;AAED;;;;;;GAMG;AACH,wCAHW,aAAa,GACX,UAAU,EAAE,CAgCxB;AAED;;;;GAIG;AACH,4CAHW,UAAU,EAAE,GAAC,SAAS,GACpB,MAAM,CAMlB;AAED;;;;;;GAMG;AACH,+BALW,GAAG,EAAE,UACL,OAAO,QACP,MAAM,GACJ,OAAO,CAcnB;AAED;;;;GAIG;AACH,kCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,iCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,oCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,+BAHW,MAAM,GACJ,OAAO,CAMnB;AAED;;;;;GAKG;AACH,8BAJW;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAC,GAAC,IAAI,qBAC7B,OAAO,GACL,OAAO,CASnB;AAED;;;;GAIG;AACH,qCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,+BAHW,OAAO,GACL,OAAO,CAmBnB;AAED;;;;GAIG;AACH,mCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,mCAHW,OAAO,GACL,OAAO,CAKnB;AAED;;;;GAIG;AACH,kCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,mCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,gCAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;GAMG;AACH,kCALW,MAAM,QACN,MAAM,iBACN,OAAO,GACL,MAAM,CAalB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qCAxBW,MAAM,mBACN,KAAK,GAAC,GAAG,aACT,KAAK,GACH,CAAC,KAAK,EAAE,KAAK,CAAC,GAAC,IAAI,CAuC/B;AAED;;;;;;;;;GASG;AACH,qDARW;IACN,IAAI,CAAC,EAAE;QAAC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAC,CAAA;IACjE,QAAQ,CAAC,EAAE;QAAC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAC,CAAA;CAC3C,MACO,MAAM,UACN,MAAM,OA+ChB;AAED;;;;;GAKG;AACH,6CAJW,MAAM,EAAE,UACR,MAAM,EAAE,GACP,MAAM,CAgBjB;AAED;;;;GAIG;AACH,kCAHW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,MACtB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,KAAK,GAAG;;EAS1C;AAED;;;;;GAKG;AACH,0BAJW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,UAC1B,MAAM,EAAE,GACN;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAStC;AAED;;GAEG;AAEH;;;;;;;;;;;;;GAaG;AACH,yBAXa,CAAC,oBACH,gBAAgB,YAChB,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,mBACvC,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,8BAEzB,OAAO,CAAC,CAAC,CAAC,CA+CtB;AAED;;;;;;GAMG;AACH,0BALW,MAAM,YACN,MAAM,eACN,MAAM,GACJ,MAAM,CAUlB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,oCAvCW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,UAY1B;IACV,CAAK,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAC,QAAQ,GAAC,SAAS,GAAC,QAAQ,GAAC,WAAW,GAAC,SAAS,GAAC;QAAE,IAAI,EAAE,KAAK,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAA;CAC5G;;iBA6BmD,MAAM;;eAAY,MAAM;cAAQ,MAAM;eAAS,MAAM;cAAQ,MAAM;;aAC1G,QAAQ,EAAE;;EA+EzB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wCAhBW;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,GAAG,GAAC,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,SAMnD;IAAE,eAAe,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,UACzC,MAAM,YACN,OAAO;;;;;;EAgCjB;AAED;;;;GAIG;AACH,0BAHW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,QACtB,MAAM,GAAC,MAAM,GAAC,MAAM,EAAE,GAAC,MAAM,EAAE;;EAiBzC;AAED;;;;;;;;;;;;GAYG;AACH,0CAVW,MAAM,YAEd;IAA0B,iBAAiB,GAAnC,OAAO;IACW,mBAAmB,GAArC,OAAO;IACW,iBAAiB,GAAnC,OAAO;CAEf,GAAU;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAC,IAAI,GAAC,CAAC,MAAM,GAAC,IAAI,CAAC,EAAE,CAAA;CAAC,CAyCxD;AAED;;;;GAIG;AACH,yCAHW,MAAM,GACJ,MAAM,EAAE,CAOpB;AAED;;;;;;;;;GASG;AACH,iCARW;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAC,UACxB,MAAM,YACN;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAC,YAE/B;IAA0B,iBAAiB,GAAnC,OAAO;CAEf,GAAU,MAAM,CAkBlB;AAED;;;;;;;;;;;;GAYG;AACH,+BAXW,MAAM,SACN;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,UACtB;IAAC,cAAc,CAAC,WAAU;CAAC,cAC3B,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,aACnC,QAAQ,GACN,OAAO,CAAC,GAAG,CAAC,CAyDxB;AAED;;;;GAIG;AACH,0CAHW,EAAE,GAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAC,GACrB,EAAE,GAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAC,CAcnC;AAED;;;;;;;;GAQG;AACH,gCANW,MAAM,gBACN,KAAK,EAAE,GAAC,KAAK,SACb,MAAM,MACN,MAAM,GACJ,MAAM,CAclB;AAED;;;;GAIG;AACH,qCAHW,MAAM,GACJ,MAAM,CAMlB;AAED;;;;;;;;GAQG;AACH,yCAPW,MAAM,gBACN,MAAM,wBAEN,MAAM,aADN,MAAM,GAEJ,MAAM,CA8ClB;AAED;;;;;GAKG;AACH,uCAJW,MAAM,cACN,OAAO,GACL,MAAM,CAelB;AAED;;;;;GAKG;AACH,gEAHW,MAAM,GACJ,OAAO,CAAC,IAAI,CAAC,CAMzB;AAED;;;;GAIG;AACH,oDAFW,aAAa,QAKvB;AAED;;;;;GAKG;AACH,sCAJW;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAC,EAAE,OACtB,MAAM,GACJ,MAAM,EAAE,CAQpB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,yBAhBuC,CAAC,SAA3B,CAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAI,QAG3B,CAAC,SACD,MAAM,YACN;IACL,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACrB,GACS,CAAC,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG;IACpD,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,UAAU,CAAC,CAAC,CAAC,CAAA;CAC7B,CAmBH;AAED;;;;;GAKG;AACH,wBAJa,CAAC,YACH,CAAC,GAAG,SAAS,GACX,CAAC,CAAC,SAAS,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CASvC;AAED;;;;GAIG;AACH,6BAHW,MAAM,GACJ,MAAM,CAKlB;AA4DD;;;;GAIG;AACH,iCAHW,CAAC,MAAM,GAAC,IAAI,GAAC,SAAS,GAAC,KAAK,GAAC,CAAC,GAAC,EAAE,CAAC,EAAE,GAClC,MAAM,CAuElB;AAED;;;;GAIG;AACH,gCAHW,MAAM,GACJ,MAAM,CAKlB;;;;4BAnpCY,KAAK,GAAC,UAAU,EAAE,GAAC,UAAU,GAAC,eAAe,GAAC,MAAM,GAAC,GAAG;;;;oBA+NxD,CAAC,MAAM,EAAE,MAAM,CAAC;;;;kBAChB;IAAC,UAAU,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,KAAK,CAAA;CAAC;+BA0JpC,CAAC;IAAC,MAAM,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAC,CAAA;CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;;;;oBAic9D;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAC;uBA5jD7D,OAAO,OAAO,EAAE,QAAQ,CAAC,OAAO,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;;;;4BAI9D,OAAO,OAAO,EAAE,aAAa;;;;iCAC7B,OAAO,OAAO,EAAE,kBAAkB;;;;4BAClC,OAAO,OAAO,EAAE,aAAa;;;;wCAC7B,OAAO,aAAa,EAAE,yBAAyB;;;;0CAG/C,kBAAkB,GAAG;IAAE,aAAa,CAAC,EAAE,yBAAyB,CAAA;CAAE;;;;qCAGlE,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,GAAG;IACrC,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,aAAa,EAAE,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,2BAA2B,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;CACzG;uBAGW,MAAM;sBACN,CAAC,KAAK,EAAE,MAAM,KAAK,QAAQ;;;;wBAC3B,CAAC,MAAM,GAAC,MAAM,GAAC,OAAO,CAAC,EAAE;yBACzB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;yBACjC;IAAE,MAAM,EAAE,MAAM;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE;8BACrC;IAAE,QAAQ,EAAE;QAAE,IAAI,EAAE;YAAE,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAA;CAAE"}
|
package/util.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _axios from 'axios'
|
|
2
2
|
import axiosRetry from 'axios-retry'
|
|
3
|
-
import
|
|
3
|
+
import { format } from 'date-fns'
|
|
4
4
|
import { loadStripe } from '@stripe/stripe-js/pure.js' // pure removes ping
|
|
5
5
|
import { twMerge as _twMerge, twJoin, createTailwindMerge, getDefaultConfig } from 'tailwind-merge'
|
|
6
6
|
|
|
@@ -194,31 +194,16 @@ export function currencyToCents (currency) {
|
|
|
194
194
|
|
|
195
195
|
/**
|
|
196
196
|
* Returns a formatted date string
|
|
197
|
-
* @param {number|Date} [date] -
|
|
198
|
-
* @param {string} [
|
|
197
|
+
* @param {number|Date} [date] - timestamp or date
|
|
198
|
+
* @param {string} [pattern] - e.g. "dd mmmm yy" (https://date-fns.org/v4.1.0/docs/format#)
|
|
199
199
|
* @param {string} [timezone] - convert a UTC date to a particular timezone.
|
|
200
200
|
* @returns {string}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
export function date (date, format, timezone) {
|
|
208
|
-
if (!date) return 'Date?'
|
|
209
|
-
|
|
210
|
-
// Get the milliseconds
|
|
211
|
-
let milliseconds = 0
|
|
212
|
-
if (typeof date === 'number') {
|
|
213
|
-
if (date < 9999999999) milliseconds = date * 1000
|
|
214
|
-
else milliseconds = date
|
|
215
|
-
} else if (isDate(date)) {
|
|
216
|
-
milliseconds = date.getTime()
|
|
217
|
-
}
|
|
218
|
-
if (timezone) {
|
|
219
|
-
milliseconds = new Date(new Date(milliseconds).toLocaleString('en-US', { timeZone: timezone })).getTime()
|
|
220
|
-
}
|
|
221
|
-
return dateformat(milliseconds, format || 'dS mmmm')
|
|
201
|
+
*/
|
|
202
|
+
export function date (date, pattern, timezone) {
|
|
203
|
+
if (!date) return ''
|
|
204
|
+
const timestamp = typeof date === 'number' ? date : isDate(date) ? date?.getTime() : 0
|
|
205
|
+
const timestampInTz = timezone ? new Date(new Date(timestamp).toLocaleString('en-US', { timeZone: timezone })).getTime() : timestamp
|
|
206
|
+
return format(timestampInTz, pattern ?? 'do MMMM')
|
|
222
207
|
}
|
|
223
208
|
|
|
224
209
|
/**
|
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
import { format, parse } from 'date-fns'
|
|
2
|
-
import { Button, Dropdown } from 'nitro-web'
|
|
3
|
-
import { dayButtonClassName } from '../element/calendar'
|
|
4
|
-
|
|
5
|
-
type Timestamp = number // timestamp on epoch day
|
|
6
|
-
type DropdownRef = {
|
|
7
|
-
setIsActive: (value: boolean) => void
|
|
8
|
-
}
|
|
9
|
-
export type FieldTimeProps = React.InputHTMLAttributes<HTMLInputElement> & {
|
|
10
|
-
name: string
|
|
11
|
-
id?: string
|
|
12
|
-
onChange?: (e: { target: { name: string, value: null|number } }) => void
|
|
13
|
-
value?: string | Timestamp;
|
|
14
|
-
Icon?: React.ReactNode
|
|
15
|
-
dir?: 'bottom-left'|'bottom-right'|'top-left'|'top-right'
|
|
16
|
-
// tz?: string
|
|
17
|
-
}
|
|
18
|
-
type TimePickerProps = {
|
|
19
|
-
date?: Date
|
|
20
|
-
onChange: (value: Timestamp) => void
|
|
21
|
-
// tz?: string
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function FieldTime({ onChange, value, Icon, dir = 'bottom-left', ...props }: FieldTimeProps) {
|
|
25
|
-
// time is viewed and set in local timezone, and saved as timestamp on epoch day.
|
|
26
|
-
// Note: timestamp is better than saving seconds so we can easily view this in a particular timezone
|
|
27
|
-
const localePattern = 'hh:mmaa'
|
|
28
|
-
const dropdownRef = useRef<DropdownRef>(null)
|
|
29
|
-
const id = props.id || props.name
|
|
30
|
-
|
|
31
|
-
// Convert the value to a valid time value
|
|
32
|
-
const validValue = useMemo(() => {
|
|
33
|
-
const num = typeof value === 'string' ? parseInt(value) : value
|
|
34
|
-
return typeof num === 'number' && !isNaN(num) ? num : new Date(0).getTime()
|
|
35
|
-
}, [value])
|
|
36
|
-
|
|
37
|
-
// Hold the input value in state
|
|
38
|
-
const [inputValue, setInputValue] = useState(() => getInputValue(validValue))
|
|
39
|
-
|
|
40
|
-
function onTimePickerChange(value: Timestamp) {
|
|
41
|
-
setInputValue(getInputValue(value))
|
|
42
|
-
if (onChange) onChange({ target: { name: props.name, value: value }})
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function getInputValue(timestamp: Timestamp) {
|
|
46
|
-
// Get the input-value in local timezone
|
|
47
|
-
return typeof timestamp === 'number' ? format(new Date(timestamp), localePattern) : ''
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function onInputChange(e: React.ChangeEvent<HTMLInputElement>) {
|
|
51
|
-
// Assume the string is in local timezone, and calls onChange with "raw" values (should update state, thus updating the value).
|
|
52
|
-
setInputValue(e.target.value) // keep the input value in sync
|
|
53
|
-
const [, _hour, _minute, _second, _period] = e.target.value.match(/(\d{1,2}):(\d{2})(:\d{2})?\s*(am|pm)/i) || []
|
|
54
|
-
if (!_hour || !_minute) return
|
|
55
|
-
const hour24 = parseInt(_hour) < 12 && _period.match(/pm/i) ? parseInt(_hour) + 12 : parseInt(_hour)
|
|
56
|
-
const minute = parseInt(_minute)
|
|
57
|
-
|
|
58
|
-
// Assume the time string is in the local timezone, and convert to UTC date from epoch
|
|
59
|
-
const localDate = new Date(0)
|
|
60
|
-
localDate.setHours(hour24, minute, _second ? parseInt(_second) : 0, 0)
|
|
61
|
-
const value = localDate.getTime()
|
|
62
|
-
if (onChange) onChange({ target: { name: props.name, value: value }})
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function onNowClick() {
|
|
66
|
-
const epochDay = new Date(0)
|
|
67
|
-
const now = new Date()
|
|
68
|
-
// now set hours, minutes, seconds to now but on epoch day
|
|
69
|
-
epochDay.setHours(now.getHours(), now.getMinutes(), now.getSeconds(), 0)
|
|
70
|
-
onTimePickerChange(epochDay.getTime())
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return (
|
|
74
|
-
<Dropdown
|
|
75
|
-
ref={dropdownRef}
|
|
76
|
-
menuToggles={false}
|
|
77
|
-
// animate={false}
|
|
78
|
-
// menuIsOpen={true}
|
|
79
|
-
minWidth={0}
|
|
80
|
-
dir={dir}
|
|
81
|
-
menuContent={
|
|
82
|
-
<div>
|
|
83
|
-
<div className="flex justify-center h-[250px]">
|
|
84
|
-
<TimePicker date={new Date(validValue)} onChange={onTimePickerChange} />
|
|
85
|
-
</div>
|
|
86
|
-
<div className="flex justify-between p-2 border-t border-gray-100">
|
|
87
|
-
<Button color="secondary" size="xs" onClick={() => onNowClick()}>Now</Button>
|
|
88
|
-
<Button color="primary" size="xs" onClick={() => dropdownRef.current?.setIsActive(false)}>Done</Button>
|
|
89
|
-
</div>
|
|
90
|
-
</div>
|
|
91
|
-
}
|
|
92
|
-
>
|
|
93
|
-
<div className="grid grid-cols-1">
|
|
94
|
-
{Icon}
|
|
95
|
-
<input
|
|
96
|
-
{...props}
|
|
97
|
-
id={id}
|
|
98
|
-
autoComplete="off"
|
|
99
|
-
className={(props.className||'')}// + props.className?.includes('is-invalid') ? ' is-invalid' : ''}
|
|
100
|
-
value={inputValue}
|
|
101
|
-
onChange={onInputChange}
|
|
102
|
-
onBlur={() => setInputValue(getInputValue(validValue))} // onChange should of updated the value -> validValue by this point
|
|
103
|
-
type="text"
|
|
104
|
-
/>
|
|
105
|
-
</div>
|
|
106
|
-
</Dropdown>
|
|
107
|
-
)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export function TimePicker({ date, onChange }: TimePickerProps) {
|
|
111
|
-
const refs = {
|
|
112
|
-
hour: useRef<HTMLDivElement>(null),
|
|
113
|
-
minute: useRef<HTMLDivElement>(null),
|
|
114
|
-
period: useRef<HTMLDivElement>(null),
|
|
115
|
-
}
|
|
116
|
-
const lists = [
|
|
117
|
-
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], // hours
|
|
118
|
-
[
|
|
119
|
-
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
|
|
120
|
-
27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
|
|
121
|
-
51, 52, 53, 54, 55, 56, 57, 58, 59,
|
|
122
|
-
], // minutes
|
|
123
|
-
['AM', 'PM'], // AM/PM
|
|
124
|
-
]
|
|
125
|
-
|
|
126
|
-
// Get current values from date or use defaults
|
|
127
|
-
const hour = date ? parseInt(format(date, 'h')) : undefined
|
|
128
|
-
const minute = date ? parseInt(format(date, 'm')) : undefined
|
|
129
|
-
const period = date ? format(date, 'a') : undefined
|
|
130
|
-
|
|
131
|
-
// Scroll into view when the date changes
|
|
132
|
-
useEffect(() => {
|
|
133
|
-
if (hour !== undefined) scrollIntoView('hour', hour)
|
|
134
|
-
if (minute !== undefined) scrollIntoView('minute', minute)
|
|
135
|
-
if (period) scrollIntoView('period', period)
|
|
136
|
-
}, [date])
|
|
137
|
-
|
|
138
|
-
const handleTimeChange = (type: 'hour' | 'minute' | 'period', value: string | number) => {
|
|
139
|
-
// Creates a new date object in the local timezone, and calls onChange with the timestamp
|
|
140
|
-
const newDate = new Date(date || new Date())
|
|
141
|
-
|
|
142
|
-
if (type === 'hour') {
|
|
143
|
-
// Parse the time with the new hour value
|
|
144
|
-
const timeString = `${value}:${format(newDate, 'mm')} ${format(newDate, 'a')}`
|
|
145
|
-
const updatedDate = parse(timeString, 'h:mm a', newDate)
|
|
146
|
-
newDate.setHours(updatedDate.getHours(), updatedDate.getMinutes())
|
|
147
|
-
} else if (type === 'minute') {
|
|
148
|
-
// Parse the time with the new minute value
|
|
149
|
-
const timeString = `${format(newDate, 'h')}:${value} ${format(newDate, 'a')}`
|
|
150
|
-
const updatedDate = parse(timeString, 'h:mm a', newDate)
|
|
151
|
-
newDate.setMinutes(updatedDate.getMinutes())
|
|
152
|
-
} else if (type === 'period') {
|
|
153
|
-
// Parse the time with the new period value
|
|
154
|
-
const timeString = `${format(newDate, 'h')}:${format(newDate, 'mm')} ${value}`
|
|
155
|
-
const updatedDate = parse(timeString, 'h:mm a', newDate)
|
|
156
|
-
newDate.setHours(updatedDate.getHours())
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
onChange(newDate.getTime())
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function scrollIntoView (type: 'hour' | 'minute' | 'period', value: string | number) {
|
|
163
|
-
const container = refs[type].current
|
|
164
|
-
if (!container) return
|
|
165
|
-
const element = container.querySelector(`[data-val="${value}"]`) as HTMLElement
|
|
166
|
-
if (!element) return
|
|
167
|
-
|
|
168
|
-
const target =
|
|
169
|
-
element.offsetTop
|
|
170
|
-
- (container.clientHeight / 2)
|
|
171
|
-
+ (element.clientHeight / 2)
|
|
172
|
-
|
|
173
|
-
container.scrollTo({ top: target, behavior: 'smooth' })
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return (
|
|
177
|
-
lists.map((list, i) => {
|
|
178
|
-
const type = i === 0 ? 'hour' : i === 1 ? 'minute' : 'period'
|
|
179
|
-
const currentValue = i === 0 ? hour : i === 1 ? minute : period
|
|
180
|
-
|
|
181
|
-
return (
|
|
182
|
-
<div
|
|
183
|
-
key={i}
|
|
184
|
-
ref={refs[type]}
|
|
185
|
-
className="w-[60px] relative overflow-hidden hover:overflow-y-auto border-l border-gray-100 sm-scrollbar first:border-l-0"
|
|
186
|
-
>
|
|
187
|
-
<div className="w-[60px] absolute flex flex-col items-center py-2">
|
|
188
|
-
{/* using absolute since the scrollbar takes up space */}
|
|
189
|
-
{list.map(item => (
|
|
190
|
-
<div
|
|
191
|
-
className="py-[1px] flex group cursor-pointer"
|
|
192
|
-
data-val={item}
|
|
193
|
-
key={item}
|
|
194
|
-
onClick={(_e) => {
|
|
195
|
-
handleTimeChange(type, item)
|
|
196
|
-
}}
|
|
197
|
-
>
|
|
198
|
-
<button
|
|
199
|
-
key={item}
|
|
200
|
-
className={
|
|
201
|
-
`${dayButtonClassName} rounded-full flex justify-center items-center group-hover:bg-gray-100 `
|
|
202
|
-
+ (item === currentValue ? '!bg-input-border-focus text-white' : '')
|
|
203
|
-
}
|
|
204
|
-
>
|
|
205
|
-
{item.toString().padStart(2, '0').toLowerCase()}
|
|
206
|
-
</button>
|
|
207
|
-
</div>
|
|
208
|
-
))}
|
|
209
|
-
</div>
|
|
210
|
-
</div>
|
|
211
|
-
)
|
|
212
|
-
})
|
|
213
|
-
)
|
|
214
|
-
}
|