enhance repeat section with week patterns and day occurrence options
This commit is contained in:
@@ -62,6 +62,51 @@ const DAYS = [
|
||||
'saturday',
|
||||
'sunday',
|
||||
]
|
||||
|
||||
const WEEK_PATTERNS = {
|
||||
every_week: 'Every week',
|
||||
nth_day_of_month: 'Specific occurrences in the month',
|
||||
}
|
||||
|
||||
const DAY_OCCURRENCE_OPTIONS = [
|
||||
{ value: 1, label: '1st occurrence' },
|
||||
{ value: 2, label: '2nd occurrence' },
|
||||
{ value: 3, label: '3rd occurrence' },
|
||||
{ value: 4, label: '4th occurrence' },
|
||||
{ value: -1, label: 'Last occurrence' },
|
||||
]
|
||||
// Helper function to generate schedule preview text
|
||||
const generateSchedulePreview = metadata => {
|
||||
if (!metadata?.days?.length) return ''
|
||||
|
||||
const dayNames = metadata.days
|
||||
.map(day => day.charAt(0).toUpperCase() + day.slice(1, 3))
|
||||
.join(', ')
|
||||
|
||||
const timeStr = metadata.time
|
||||
? moment(metadata.time).format('h:mm A')
|
||||
: '6:00 PM'
|
||||
|
||||
if (metadata.weekPattern === 'every_week' || !metadata.weekPattern) {
|
||||
return `Every ${dayNames} at ${timeStr}`
|
||||
}
|
||||
|
||||
if (
|
||||
metadata.weekPattern === 'nth_day_of_month' &&
|
||||
metadata.dayOccurrences?.length
|
||||
) {
|
||||
const occurrenceStr = metadata.dayOccurrences
|
||||
.map(w => {
|
||||
if (w === -1) return 'last'
|
||||
return `${w}${w === 1 ? 'st' : w === 2 ? 'nd' : w === 3 ? 'rd' : 'th'}`
|
||||
})
|
||||
.join(', ')
|
||||
return `Every ${occurrenceStr} ${dayNames} of the month at ${timeStr}`
|
||||
}
|
||||
|
||||
return `Every ${dayNames} at ${timeStr}`
|
||||
}
|
||||
|
||||
const RepeatOnSections = ({
|
||||
frequencyType,
|
||||
frequency,
|
||||
@@ -77,13 +122,30 @@ const RepeatOnSections = ({
|
||||
moment(new Date()).format('YYYY-MM-DD') + 'T' + '18:00',
|
||||
).format()
|
||||
}
|
||||
}, [frequencyMetadata])
|
||||
// Initialize weekPattern if not set
|
||||
if (!frequencyMetadata?.weekPattern) {
|
||||
onFrequencyMetadataUpdate({
|
||||
...frequencyMetadata,
|
||||
weekPattern: 'every_week',
|
||||
dayOccurrences: [],
|
||||
})
|
||||
}
|
||||
}, [frequencyMetadata, onFrequencyMetadataUpdate])
|
||||
|
||||
const timePickerComponent = (
|
||||
<Grid item sm={12} sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Typography level='h5'>At: </Typography>
|
||||
<Grid
|
||||
item
|
||||
sm={12}
|
||||
sx={{
|
||||
display: 'flex',
|
||||
direction: 'column',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<Typography level='h5'>Time of day: </Typography>
|
||||
<Input
|
||||
type='time'
|
||||
sx={{ width: '150px' }}
|
||||
defaultValue={moment(frequencyMetadata?.time).format('HH:mm')}
|
||||
onChange={e => {
|
||||
onFrequencyMetadataUpdate({
|
||||
@@ -192,6 +254,8 @@ const RepeatOnSections = ({
|
||||
onFrequencyMetadataUpdate({
|
||||
...frequencyMetadata,
|
||||
days: [],
|
||||
weekPattern: 'every_week',
|
||||
dayOccurrences: [],
|
||||
})
|
||||
} else {
|
||||
onFrequencyMetadataUpdate({
|
||||
@@ -209,6 +273,140 @@ const RepeatOnSections = ({
|
||||
</Button>
|
||||
</Card>
|
||||
</Grid>
|
||||
|
||||
<Grid item sm={12} sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Box>
|
||||
<RadioGroup
|
||||
value={frequencyMetadata?.weekPattern || 'every_week'}
|
||||
onChange={event => {
|
||||
const newPattern = event.target.value
|
||||
onFrequencyMetadataUpdate({
|
||||
...frequencyMetadata,
|
||||
weekPattern: newPattern,
|
||||
dayOccurrences:
|
||||
newPattern === 'every_week'
|
||||
? []
|
||||
: frequencyMetadata?.dayOccurrences || [],
|
||||
})
|
||||
}}
|
||||
sx={{ gap: 1, '& > div': { p: 1 } }}
|
||||
>
|
||||
{Object.entries(WEEK_PATTERNS).map(([value, label]) => (
|
||||
<FormControl key={value}>
|
||||
<Radio value={value} label={label} variant='soft' />
|
||||
{value === 'every_week' && (
|
||||
<FormHelperText>
|
||||
Task repeats every week on selected days
|
||||
</FormHelperText>
|
||||
)}
|
||||
{value === 'nth_day_of_month' && (
|
||||
<FormHelperText>
|
||||
Task repeats on specific day occurrences each month
|
||||
(e.g., 1st Monday, 3rd Friday)
|
||||
</FormHelperText>
|
||||
)}
|
||||
</FormControl>
|
||||
))}
|
||||
</RadioGroup>
|
||||
|
||||
{frequencyMetadata?.weekPattern === 'nth_day_of_month' && (
|
||||
<Box mt={2}>
|
||||
<Typography level='body-sm' mb={1}>
|
||||
Select which occurrences of the selected days:
|
||||
</Typography>
|
||||
<Typography level='body-xs' color='neutral' mb={2}>
|
||||
Example: "1st Monday" means the first Monday of each month
|
||||
</Typography>
|
||||
<Card>
|
||||
<List
|
||||
orientation='horizontal'
|
||||
wrap
|
||||
sx={{
|
||||
'--List-gap': '8px',
|
||||
'--ListItem-radius': '20px',
|
||||
}}
|
||||
>
|
||||
{DAY_OCCURRENCE_OPTIONS.map(option => (
|
||||
<ListItem key={option.value}>
|
||||
<Checkbox
|
||||
checked={
|
||||
frequencyMetadata?.dayOccurrences?.includes(
|
||||
option.value,
|
||||
) || false
|
||||
}
|
||||
onChange={() => {
|
||||
const currentOccurrences =
|
||||
frequencyMetadata?.dayOccurrences || []
|
||||
const newOccurrences =
|
||||
currentOccurrences.includes(option.value)
|
||||
? currentOccurrences.filter(
|
||||
w => w !== option.value,
|
||||
)
|
||||
: [...currentOccurrences, option.value]
|
||||
onFrequencyMetadataUpdate({
|
||||
...frequencyMetadata,
|
||||
dayOccurrences: newOccurrences.sort((a, b) => {
|
||||
if (a === -1) return 1 // Last occurrence goes to end
|
||||
if (b === -1) return -1
|
||||
return a - b
|
||||
}),
|
||||
})
|
||||
}}
|
||||
overlay
|
||||
disableIcon
|
||||
variant='soft'
|
||||
label={option.label}
|
||||
/>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
<Button
|
||||
size='sm'
|
||||
variant='soft'
|
||||
color='neutral'
|
||||
onClick={() => {
|
||||
if (
|
||||
frequencyMetadata?.dayOccurrences?.length ===
|
||||
DAY_OCCURRENCE_OPTIONS.length
|
||||
) {
|
||||
onFrequencyMetadataUpdate({
|
||||
...frequencyMetadata,
|
||||
dayOccurrences: [],
|
||||
})
|
||||
} else {
|
||||
onFrequencyMetadataUpdate({
|
||||
...frequencyMetadata,
|
||||
dayOccurrences: DAY_OCCURRENCE_OPTIONS.map(
|
||||
option => option.value,
|
||||
),
|
||||
})
|
||||
}
|
||||
}}
|
||||
overlay
|
||||
disableIcon
|
||||
>
|
||||
{frequencyMetadata?.dayOccurrences?.length ===
|
||||
DAY_OCCURRENCE_OPTIONS.length
|
||||
? 'Unselect All'
|
||||
: 'Select All'}
|
||||
</Button>
|
||||
</Card>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Quarter week pattern removed - doesn't make sense with Nth day approach */}
|
||||
|
||||
{/* Live Preview */}
|
||||
{frequencyMetadata?.days?.length > 0 && (
|
||||
<Card mt={2} p={2}>
|
||||
<Typography level='body-sm' color='primary'>
|
||||
{generateSchedulePreview(frequencyMetadata)}
|
||||
</Typography>
|
||||
</Card>
|
||||
)}
|
||||
</Box>
|
||||
</Grid>
|
||||
|
||||
{timePickerComponent}
|
||||
</>
|
||||
)
|
||||
@@ -461,6 +659,8 @@ const RepeatSection = ({
|
||||
onFrequencyMetadataUpdate({
|
||||
...frequencyMetadata,
|
||||
days: [],
|
||||
weekPattern: 'every_week',
|
||||
weekNumbers: [],
|
||||
})
|
||||
} else if (item === 'day_of_the_month') {
|
||||
onFrequencyMetadataUpdate({
|
||||
|
||||
Reference in New Issue
Block a user