sanity-plugin-recurring-dates 1.3.2 → 1.4.1
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/LICENSE +1 -1
- package/README.md +22 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.esm.js +60 -24
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +60 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/CustomRule/CustomRule.tsx +32 -8
- package/src/components/CustomRule/Monthly.tsx +7 -1
- package/src/components/RecurringDate.tsx +47 -23
- package/src/schema/recurringDates.tsx +5 -3
- package/src/types.ts +8 -0
package/package.json
CHANGED
|
@@ -3,6 +3,7 @@ import {format, toDate} from 'date-fns-tz'
|
|
|
3
3
|
import React, {useCallback, useMemo, useState} from 'react'
|
|
4
4
|
import {Options, RRule, rrulestr, Weekday} from 'rrule'
|
|
5
5
|
import {type ObjectInputProps, set} from 'sanity'
|
|
6
|
+
import {Feedback} from 'sanity-plugin-utils'
|
|
6
7
|
|
|
7
8
|
import {DEFAULT_COUNTS} from '../../constants'
|
|
8
9
|
import {PluginConfig} from '../../types'
|
|
@@ -16,13 +17,15 @@ export function CustomRule({
|
|
|
16
17
|
onChange,
|
|
17
18
|
initialValue,
|
|
18
19
|
startDate,
|
|
20
|
+
endDate,
|
|
19
21
|
dateTimeOptions,
|
|
20
22
|
}: {
|
|
21
23
|
open: boolean
|
|
22
24
|
onClose: () => void
|
|
23
25
|
onChange: ObjectInputProps['onChange']
|
|
24
26
|
initialValue: string
|
|
25
|
-
startDate
|
|
27
|
+
startDate?: string
|
|
28
|
+
endDate?: string
|
|
26
29
|
dateTimeOptions: PluginConfig['dateTimeOptions']
|
|
27
30
|
}): React.JSX.Element {
|
|
28
31
|
const initialRule = useMemo(() => {
|
|
@@ -43,6 +46,8 @@ export function CustomRule({
|
|
|
43
46
|
initialRule.origOptions.byweekday || null,
|
|
44
47
|
)
|
|
45
48
|
|
|
49
|
+
const [untilValid, setUntilValid] = useState<boolean>(true)
|
|
50
|
+
|
|
46
51
|
const handleChange = useCallback(
|
|
47
52
|
(event: React.FormEvent<HTMLInputElement> | React.FormEvent<HTMLSelectElement>) => {
|
|
48
53
|
const {name, value} = event.currentTarget
|
|
@@ -76,11 +81,25 @@ export function CustomRule({
|
|
|
76
81
|
return fromDate
|
|
77
82
|
}, [frequency, startDate])
|
|
78
83
|
|
|
79
|
-
const handleUntilChange = useCallback(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
const handleUntilChange = useCallback(
|
|
85
|
+
(date: string | null) => {
|
|
86
|
+
if (date) {
|
|
87
|
+
const untilDate = toDate(`${date}T23:59:59`)
|
|
88
|
+
|
|
89
|
+
if (
|
|
90
|
+
(endDate && untilDate < toDate(endDate)) ||
|
|
91
|
+
(startDate && untilDate < toDate(startDate))
|
|
92
|
+
) {
|
|
93
|
+
setUntilValid(false)
|
|
94
|
+
} else {
|
|
95
|
+
setUntilValid(true)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
setUntil(untilDate)
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
[endDate, startDate],
|
|
102
|
+
)
|
|
84
103
|
|
|
85
104
|
const handleEndChange = useCallback(
|
|
86
105
|
(event: React.FormEvent<HTMLInputElement>) => {
|
|
@@ -107,7 +126,7 @@ export function CustomRule({
|
|
|
107
126
|
interval,
|
|
108
127
|
count: count || null,
|
|
109
128
|
until: until ? (until as Date) : null,
|
|
110
|
-
byweekday,
|
|
129
|
+
byweekday: frequency === RRule.WEEKLY || frequency === RRule.MONTHLY ? byweekday : null,
|
|
111
130
|
}
|
|
112
131
|
|
|
113
132
|
const newRule = new RRule(newOptions)
|
|
@@ -198,6 +217,11 @@ export function CustomRule({
|
|
|
198
217
|
readOnly={!until}
|
|
199
218
|
/>
|
|
200
219
|
</Box>
|
|
220
|
+
{!untilValid && (
|
|
221
|
+
<Feedback tone="critical">
|
|
222
|
+
<Text size={1}>Until date must be after event ends</Text>
|
|
223
|
+
</Feedback>
|
|
224
|
+
)}
|
|
201
225
|
</Flex>
|
|
202
226
|
<Flex gap={2} align="center">
|
|
203
227
|
<Radio
|
|
@@ -227,7 +251,7 @@ export function CustomRule({
|
|
|
227
251
|
<Box paddingX={4} paddingY={3} style={{borderTop: '1px solid var(--card-border-color)'}}>
|
|
228
252
|
<Flex gap={2} justify="flex-end">
|
|
229
253
|
<Button text="Cancel" mode="ghost" onClick={onClose} />
|
|
230
|
-
<Button text="Done" tone="positive" onClick={handleConfirm} />
|
|
254
|
+
<Button text="Done" tone="positive" onClick={handleConfirm} disabled={!untilValid} />
|
|
231
255
|
</Flex>
|
|
232
256
|
</Box>
|
|
233
257
|
</Flex>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {Box, Flex, Select, Text} from '@sanity/ui'
|
|
2
|
-
import React, {useCallback} from 'react'
|
|
2
|
+
import React, {useCallback, useEffect} from 'react'
|
|
3
3
|
import {Options, Weekday} from 'rrule'
|
|
4
4
|
|
|
5
5
|
import {DAYS} from '../../constants'
|
|
@@ -34,6 +34,12 @@ export function Monthly(props: MonthlyProps): React.JSX.Element {
|
|
|
34
34
|
[dayNo, setByweekday, weekNo],
|
|
35
35
|
)
|
|
36
36
|
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (!weekNo) {
|
|
39
|
+
setByweekday(null)
|
|
40
|
+
}
|
|
41
|
+
}, [])
|
|
42
|
+
|
|
37
43
|
return (
|
|
38
44
|
<Flex gap={2} align="center">
|
|
39
45
|
<Text style={{whiteSpace: 'nowrap'}}>On the</Text>
|
|
@@ -82,6 +82,31 @@ export function RecurringDates(props: RecurringDatesProps): React.JSX.Element {
|
|
|
82
82
|
...startDateMember?.field?.schemaType.options,
|
|
83
83
|
...dateTimeOptions,
|
|
84
84
|
}
|
|
85
|
+
|
|
86
|
+
// Ensure the right schemaType is set
|
|
87
|
+
if (dateOnly === true) {
|
|
88
|
+
startDateMember.field.schemaType.name = 'date'
|
|
89
|
+
} else {
|
|
90
|
+
startDateMember.field.schemaType.name = 'datetime'
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Add custom validation to the start date field
|
|
94
|
+
if (validation?.startDate) {
|
|
95
|
+
startDateMember.field.schemaType.validation = (CustomValidation) =>
|
|
96
|
+
validation?.startDate?.(CustomValidation) as Rule
|
|
97
|
+
} else {
|
|
98
|
+
startDateMember.field.schemaType.validation = (DefaultRule) => DefaultRule.required() as Rule
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Add custom title to the start date field
|
|
102
|
+
if (options?.fieldTitles?.startDate) {
|
|
103
|
+
startDateMember.field.schemaType.title = options.fieldTitles.startDate
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Add custom description to the start date field
|
|
107
|
+
if (options?.fieldDescriptions?.startDate) {
|
|
108
|
+
startDateMember.field.schemaType.description = options.fieldDescriptions.startDate
|
|
109
|
+
}
|
|
85
110
|
}
|
|
86
111
|
|
|
87
112
|
if (endDateMember?.kind == 'field') {
|
|
@@ -89,36 +114,32 @@ export function RecurringDates(props: RecurringDatesProps): React.JSX.Element {
|
|
|
89
114
|
...endDateMember?.field?.schemaType.options,
|
|
90
115
|
...dateTimeOptions,
|
|
91
116
|
}
|
|
92
|
-
}
|
|
93
117
|
|
|
94
|
-
|
|
95
|
-
if (
|
|
96
|
-
startDateMember.field.schemaType.name = 'date'
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (endDateMember?.kind == 'field') {
|
|
118
|
+
// Ensure the right schemaType is set
|
|
119
|
+
if (dateOnly === true) {
|
|
100
120
|
endDateMember.field.schemaType.name = 'date'
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// we need to explicitly set the schemaType to datetime
|
|
104
|
-
if (startDateMember?.kind == 'field') {
|
|
105
|
-
startDateMember.field.schemaType.name = 'datetime'
|
|
121
|
+
} else {
|
|
122
|
+
endDateMember.field.schemaType.name = 'datetime'
|
|
106
123
|
}
|
|
107
124
|
|
|
108
|
-
|
|
109
|
-
|
|
125
|
+
// Add custom validation to the end date field
|
|
126
|
+
if (validation?.endDate) {
|
|
127
|
+
endDateMember.field.schemaType.validation = (CustomValidation) =>
|
|
128
|
+
validation?.endDate?.(CustomValidation) as Rule
|
|
129
|
+
} else {
|
|
130
|
+
endDateMember.field.schemaType.validation = (DefaultRule) =>
|
|
131
|
+
DefaultRule.min(DefaultRule.valueOfField('startDate')) as Rule
|
|
110
132
|
}
|
|
111
|
-
}
|
|
112
133
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
134
|
+
// Add custom title to the end date field
|
|
135
|
+
if (options?.fieldTitles?.endDate) {
|
|
136
|
+
endDateMember.field.schemaType.title = options.fieldTitles.endDate
|
|
137
|
+
}
|
|
118
138
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
139
|
+
// Add custom description to the end date field
|
|
140
|
+
if (options?.fieldDescriptions?.endDate) {
|
|
141
|
+
endDateMember.field.schemaType.description = options.fieldDescriptions.endDate
|
|
142
|
+
}
|
|
122
143
|
}
|
|
123
144
|
|
|
124
145
|
// Do we have an end date set for this field?
|
|
@@ -186,6 +207,9 @@ export function RecurringDates(props: RecurringDatesProps): React.JSX.Element {
|
|
|
186
207
|
startDate={
|
|
187
208
|
startDateMember?.kind == 'field' ? (startDateMember?.field?.value as string) : undefined
|
|
188
209
|
}
|
|
210
|
+
endDate={
|
|
211
|
+
endDateMember?.kind == 'field' ? (endDateMember?.field?.value as string) : undefined
|
|
212
|
+
}
|
|
189
213
|
dateTimeOptions={dateTimeOptions}
|
|
190
214
|
/>
|
|
191
215
|
</Stack>
|
|
@@ -8,7 +8,7 @@ import {PluginConfig, WithRequiredProperty} from '../types'
|
|
|
8
8
|
export default (
|
|
9
9
|
config: WithRequiredProperty<PluginConfig, 'defaultRecurrences'>,
|
|
10
10
|
): SchemaTypeDefinition => {
|
|
11
|
-
const {dateTimeOptions, dateOnly, validation} = config
|
|
11
|
+
const {dateTimeOptions, dateOnly, validation, fieldTitles, fieldDescriptions} = config
|
|
12
12
|
|
|
13
13
|
return defineField({
|
|
14
14
|
name: 'recurringDates',
|
|
@@ -17,7 +17,8 @@ export default (
|
|
|
17
17
|
icon: CalendarIcon,
|
|
18
18
|
fields: [
|
|
19
19
|
defineField({
|
|
20
|
-
title: 'Start Date',
|
|
20
|
+
title: fieldTitles?.startDate || 'Start Date',
|
|
21
|
+
description: fieldDescriptions?.startDate || '',
|
|
21
22
|
name: 'startDate',
|
|
22
23
|
type: dateOnly ? 'date' : 'datetime',
|
|
23
24
|
options: dateTimeOptions,
|
|
@@ -25,7 +26,8 @@ export default (
|
|
|
25
26
|
validation?.startDate ? validation.startDate(Rule) : Rule.required(),
|
|
26
27
|
}),
|
|
27
28
|
defineField({
|
|
28
|
-
title: 'End Date',
|
|
29
|
+
title: fieldTitles?.endDate || 'End Date',
|
|
30
|
+
description: fieldDescriptions?.endDate || '',
|
|
29
31
|
name: 'endDate',
|
|
30
32
|
type: dateOnly ? 'date' : 'datetime',
|
|
31
33
|
options: dateTimeOptions,
|
package/src/types.ts
CHANGED
|
@@ -10,6 +10,14 @@ export interface PluginConfig {
|
|
|
10
10
|
startDate?: (Rule: DateRule) => DateRule
|
|
11
11
|
endDate?: (Rule: DateRule) => DateRule
|
|
12
12
|
}
|
|
13
|
+
fieldTitles?: {
|
|
14
|
+
startDate?: string
|
|
15
|
+
endDate?: string
|
|
16
|
+
}
|
|
17
|
+
fieldDescriptions?: {
|
|
18
|
+
startDate?: string
|
|
19
|
+
endDate?: string
|
|
20
|
+
}
|
|
13
21
|
}
|
|
14
22
|
|
|
15
23
|
export type WithRequiredProperty<Type, Key extends keyof Type> = Type & {
|