sanity-plugin-recurring-dates 1.3.2 → 1.4.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sanity-plugin-recurring-dates",
3
- "version": "1.3.2",
3
+ "version": "1.4.0",
4
4
  "description": "Add a custom input component to your Sanity Studio to manage recurring dates (e.g. for events)",
5
5
  "keywords": [
6
6
  "sanity",
@@ -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: string | undefined
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((date: string | null) => {
80
- if (date) {
81
- setUntil(toDate(`${date}T23:59:59`))
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>) => {
@@ -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>
@@ -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
- if (dateOnly === true) {
95
- if (startDateMember?.kind == 'field') {
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
- } else {
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
- if (endDateMember?.kind == 'field') {
109
- endDateMember.field.schemaType.name = 'datetime'
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
- // Add custom validation to the start and end date fields
114
- if (validation?.startDate && startDateMember?.kind == 'field') {
115
- startDateMember.field.schemaType.validation = (CustomValidation) =>
116
- validation?.startDate?.(CustomValidation) as Rule
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
- if (validation?.endDate && endDateMember?.kind == 'field') {
120
- endDateMember.field.schemaType.validation = (CustomValidation) =>
121
- validation?.endDate?.(CustomValidation) as Rule
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 & {