Skip to content

Commit

Permalink
Feat/validation (#21)
Browse files Browse the repository at this point in the history
* chore(deps): update non-major

* chore: linting

* chore: update deps

* chore: ts fixes

* feat: add custom validation for start and end dates

* chore: tidy code

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
  • Loading branch information
thebiggianthead and renovate[bot] authored Sep 5, 2024
1 parent b7c7d89 commit cb7a960
Show file tree
Hide file tree
Showing 20 changed files with 5,591 additions and 3,836 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ defineField({

// Changes the date picker to date only, no time
dateOnly: true, // defaults to false

// override the default validation
validation: {
startDate: (Rule) => Rule.required() // defaults to (Rule) => Rule.required()
endDate: (Rule) => Rule.min(Rule.valueOfField('startDate')) // defaults to (Rule) => Rule.min(Rule.valueOfField('startDate'))
}
},
})
```
Expand Down
9,003 changes: 5,361 additions & 3,642 deletions package-lock.json

Large diffs are not rendered by default.

51 changes: 26 additions & 25 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,39 +53,40 @@
"sanity-plugin-utils": "^1.6.2"
},
"devDependencies": {
"@commitlint/cli": "^18.4.4",
"@commitlint/config-conventional": "^18.4.4",
"@sanity/pkg-utils": "^3.3.7",
"@sanity/plugin-kit": "^3.1.10",
"@sanity/semantic-release-preset": "^4.1.6",
"@types/react": "^18.2.47",
"@typescript-eslint/eslint-plugin": "^6.18.1",
"@typescript-eslint/parser": "^6.18.1",
"eslint": "^8.56.0",
"@commitlint/cli": "^18.6.1",
"@commitlint/config-conventional": "^18.6.3",
"@sanity/pkg-utils": "^3.3.8",
"@sanity/plugin-kit": "^3.1.12",
"@sanity/semantic-release-preset": "^4.1.8",
"@types/react": "^18.3.5",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-config-sanity": "^7.0.1",
"eslint-plugin-prettier": "^5.1.2",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-config-sanity": "^7.1.2",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.35.2",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-simple-import-sort": "^10.0.0",
"husky": "^8.0.3",
"lint-staged": "^15.2.0",
"npm-run-all": "^4.1.5",
"prettier": "^3.1.1",
"prettier-plugin-packagejson": "^2.4.9",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-is": "^18.2.0",
"npm-run-all2": "^5.0.0",
"prettier": "^3.3.3",
"prettier-plugin-packagejson": "^2.5.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-is": "^18.3.1",
"rimraf": "^5.0.1",
"sanity": "^3.23.4",
"styled-components": "^6.1.8",
"typescript": "^5.3.3"
"sanity": "^3.57.0",
"styled-components": "^6.1.13",
"typescript": "^5.5.4"
},
"peerDependencies": {
"react": "^18",
"sanity": "^3",
"@sanity/icons": ">= 2",
"@sanity/ui": "^1 || ^2.0.0-beta",
"@sanity/icons": ">= 2"
"@sanity/util": "^3.57.0",
"react": "^18",
"sanity": "^3"
},
"engines": {
"node": ">=14"
Expand Down
207 changes: 100 additions & 107 deletions src/components/CustomRule/CustomRule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function CustomRule({
initialValue: string
startDate: string | undefined
dateTimeOptions: PluginConfig['dateTimeOptions']
}) {
}): React.JSX.Element {
const initialRule = useMemo(() => {
return initialValue ? rrulestr(initialValue) : new RRule()
}, [initialValue])
Expand All @@ -48,8 +48,6 @@ export function CustomRule({
setFrequency(Number(value))
} else if (name === 'interval') {
setInterval(Number(value))
} else if (name === 'interval') {
setCount(Number(value))
} else if (name === 'count') {
setCount(Number(value))
}
Expand Down Expand Up @@ -113,118 +111,113 @@ export function CustomRule({
onChange(set(newRule.toString(), ['rrule']))
}, [byweekday, count, frequency, interval, onChange, onClose, until])

return (
open && (
<Dialog
header="Custom recurrence"
id="dialog-example"
onClose={onClose}
zOffset={1000}
width={1}
>
<Flex direction="column">
<Box flex={1} overflow="auto" padding={4}>
<Stack space={4}>
return open ? (
<Dialog
header="Custom recurrence"
id="dialog-example"
onClose={onClose}
zOffset={1000}
width={1}
>
<Flex direction="column">
<Box flex={1} overflow="auto" padding={4}>
<Stack space={4}>
<Flex gap={2} align="center">
<Text style={{whiteSpace: 'nowrap'}}>Repeat every</Text>
<Box style={{width: '75px'}}>
<TextInput name="interval" type="number" value={interval} onChange={handleChange} />
</Box>
<Box>
<Select name="freq" value={frequency} onChange={handleChange}>
<option value={RRule.YEARLY}>years</option>
<option value={RRule.MONTHLY}>months</option>
<option value={RRule.WEEKLY}>weeks</option>
<option value={RRule.DAILY}>days</option>
</Select>
</Box>
</Flex>

{frequency === RRule.MONTHLY && (
<Monthly byweekday={byweekday as Weekday} setByweekday={setByweekday} />
)}

{frequency === RRule.WEEKLY && (
<Weekly byweekday={byweekday as Weekday} setByweekday={setByweekday} />
)}

<Stack space={2}>
<Text>Ends</Text>
<Flex gap={2} paddingY={2} align="center">
<Radio
checked={!count && !until}
name="ends"
onChange={handleEndChange}
value=""
id="ends-never"
/>
<Text htmlFor="ends-never" as="label">
Never
</Text>
</Flex>
<Flex gap={2} align="center">
<Text style={{whiteSpace: 'nowrap'}}>Repeat every</Text>
<Radio
checked={!!until}
name="ends"
onChange={handleEndChange}
value="until"
id="ends-until"
/>
<Text htmlFor="ends-until" as="label" style={{width: '75px'}}>
On
</Text>
<Box style={{width: '200px'}}>
<DateInput
id="until"
onChange={handleUntilChange}
type={{
name: 'until',
title: 'Date',
options: dateTimeOptions,
}}
value={until ? new Date(until) : getUntilDate()}
disabled={!until}
/>
</Box>
</Flex>
<Flex gap={2} align="center">
<Radio
checked={!!count}
name="ends"
onChange={handleEndChange}
value="count"
id="ends-count"
/>
<Text htmlFor="ends-count" as="label" style={{width: '75px'}}>
After
</Text>
<Box style={{width: '75px'}}>
<TextInput
name="interval"
name="count"
type="number"
value={interval}
value={count || DEFAULT_COUNTS[frequency]}
onChange={handleChange}
disabled={!count}
/>
</Box>
<Box>
<Select name="freq" value={frequency} onChange={handleChange}>
<option value={RRule.YEARLY}>years</option>
<option value={RRule.MONTHLY}>months</option>
<option value={RRule.WEEKLY}>weeks</option>
<option value={RRule.DAILY}>days</option>
</Select>
</Box>
<Text style={{whiteSpace: 'nowrap'}}>occurrences</Text>
</Flex>

{frequency === RRule.MONTHLY && (
<Monthly byweekday={byweekday as Weekday} setByweekday={setByweekday} />
)}

{frequency === RRule.WEEKLY && (
<Weekly byweekday={byweekday as Weekday} setByweekday={setByweekday} />
)}

<Stack space={2}>
<Text>Ends</Text>
<Flex gap={2} paddingY={2} align="center">
<Radio
checked={!count && !until}
name="ends"
onChange={handleEndChange}
value=""
id="ends-never"
/>
<Text htmlFor="ends-never" as="label">
Never
</Text>
</Flex>
<Flex gap={2} align="center">
<Radio
checked={!!until}
name="ends"
onChange={handleEndChange}
value="until"
id="ends-until"
/>
<Text htmlFor="ends-until" as="label" style={{width: '75px'}}>
On
</Text>
<Box style={{width: '200px'}}>
<DateInput
id="until"
onChange={handleUntilChange}
type={{
name: 'until',
title: 'Date',
options: dateTimeOptions,
}}
value={until ? new Date(until) : getUntilDate()}
disabled={!until}
/>
</Box>
</Flex>
<Flex gap={2} align="center">
<Radio
checked={!!count}
name="ends"
onChange={handleEndChange}
value="count"
id="ends-count"
/>
<Text htmlFor="ends-count" as="label" style={{width: '75px'}}>
After
</Text>
<Box style={{width: '75px'}}>
<TextInput
name="count"
type="number"
value={count || DEFAULT_COUNTS[frequency]}
onChange={handleChange}
disabled={!count}
/>
</Box>
<Text style={{whiteSpace: 'nowrap'}}>occurrences</Text>
</Flex>
</Stack>
</Stack>
</Box>
<Box paddingX={4} paddingY={3} style={{borderTop: '1px solid var(--card-border-color)'}}>
<Flex gap={2} justify="flex-end">
<Button text="Cancel" mode="ghost" onClick={onClose} />
<Button text="Done" tone="positive" onClick={handleConfirm} />
</Flex>
</Box>
</Flex>
</Dialog>
)
</Stack>
</Box>
<Box paddingX={4} paddingY={3} style={{borderTop: '1px solid var(--card-border-color)'}}>
<Flex gap={2} justify="flex-end">
<Button text="Cancel" mode="ghost" onClick={onClose} />
<Button text="Done" tone="positive" onClick={handleConfirm} />
</Flex>
</Box>
</Flex>
</Dialog>
) : (
<></>
)
}
2 changes: 1 addition & 1 deletion src/components/CustomRule/Monthly.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface MonthlyProps {
setByweekday: (value: Options['byweekday']) => void
}

export function Monthly(props: MonthlyProps) {
export function Monthly(props: MonthlyProps): React.JSX.Element {
const {byweekday, setByweekday} = props

const {weekday: dayNo, n: weekNo} =
Expand Down
2 changes: 1 addition & 1 deletion src/components/CustomRule/Weekly.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface WeeklyProps {
setByweekday: (value: Options['byweekday']) => void
}

export function Weekly(props: WeeklyProps) {
export function Weekly(props: WeeklyProps): React.JSX.Element {
const {byweekday, setByweekday} = props

const currentWeekdays: number[] = useMemo(() => {
Expand Down
9 changes: 5 additions & 4 deletions src/components/DateInputs/CommonDateTimeInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const CommonDateTimeInput = React.forwardRef(function CommonDateTimeInput
}, [value])

const handleDatePickerInputChange = React.useCallback(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(event: any) => {
const nextInputValue = event.currentTarget.value
const result = nextInputValue === '' ? null : parseInputValue(nextInputValue)
Expand Down Expand Up @@ -81,14 +82,14 @@ export const CommonDateTimeInput = React.forwardRef(function CommonDateTimeInput
const parseResult = localValue
? parseInputValue(localValue)
: value
? deserialize(value as string)
: null
? deserialize(value as string)
: null

const inputValue = localValue
? localValue
: parseResult?.isValid
? formatInputValue(parseResult.date)
: (value as string)
? formatInputValue(parseResult.date)
: (value as string)

return readOnly ? (
<TextInput value={inputValue} readOnly disabled={readOnly} />
Expand Down
2 changes: 1 addition & 1 deletion src/components/DateInputs/DateInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const serialize = (date: Date) => format(date, VALUE_FORMAT)
/**
* @hidden
* @beta */
export function DateInput(props: DateInputProps) {
export function DateInput(props: DateInputProps): React.JSX.Element {
const {id, onChange, type, value, disabled, ...rest} = props

const {dateFormat} = parseOptions(type.options)
Expand Down
2 changes: 1 addition & 1 deletion src/components/DateInputs/DateTimeInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ function enforceTimeStep(dateString: string, timeStep: number) {
/**
* @hidden
* @beta */
export function DateTimeInput(props: DateTimeInputProps) {
export function DateTimeInput(props: DateTimeInputProps): React.JSX.Element {
const {id, onChange, type, value, disabled, ...rest} = props

const {dateFormat, timeFormat, timeStep} = parseOptions(type.options)
Expand Down
Loading

0 comments on commit cb7a960

Please sign in to comment.