style: format recurrence helpers
This commit is contained in:
@@ -15,11 +15,11 @@ import {
|
||||
getRecurrencePreview,
|
||||
getWeekdayOptions,
|
||||
parseRecurrenceRule,
|
||||
type RecurrenceFormValue,
|
||||
recurrenceFrequencyLabels,
|
||||
type SupportedRecurrenceFrequency,
|
||||
serializeRecurrenceRule,
|
||||
validateRecurrence,
|
||||
type RecurrenceFormValue,
|
||||
type SupportedRecurrenceFrequency,
|
||||
type Weekday,
|
||||
} from "@/lib/recurrence";
|
||||
|
||||
@@ -39,10 +39,7 @@ const getStartWeekday = (start?: string): Weekday => {
|
||||
return weekdays[jsDay] ?? "MO";
|
||||
};
|
||||
|
||||
const updateWeekdays = (
|
||||
current: Weekday[],
|
||||
day: Weekday,
|
||||
): Weekday[] => {
|
||||
const updateWeekdays = (current: Weekday[], day: Weekday): Weekday[] => {
|
||||
return current.includes(day)
|
||||
? current.filter((existingDay) => existingDay !== day)
|
||||
: [...current, day];
|
||||
@@ -95,11 +92,13 @@ export function RecurrencePicker({ value, start, onChange }: Props) {
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{Object.entries(recurrenceFrequencyLabels).map(([optionValue, label]) => (
|
||||
<SelectItem key={optionValue} value={optionValue}>
|
||||
{label}
|
||||
</SelectItem>
|
||||
))}
|
||||
{Object.entries(recurrenceFrequencyLabels).map(
|
||||
([optionValue, label]) => (
|
||||
<SelectItem key={optionValue} value={optionValue}>
|
||||
{label}
|
||||
</SelectItem>
|
||||
),
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
@@ -108,7 +107,12 @@ export function RecurrencePicker({ value, start, onChange }: Props) {
|
||||
<>
|
||||
<div>
|
||||
<Label htmlFor="interval" className="text-xs text-muted-foreground">
|
||||
Interval (every {recurrence.interval} {recurrence.freq === "DAILY" ? "day" : recurrence.freq === "WEEKLY" ? "week" : "month"}
|
||||
Interval (every {recurrence.interval}{" "}
|
||||
{recurrence.freq === "DAILY"
|
||||
? "day"
|
||||
: recurrence.freq === "WEEKLY"
|
||||
? "week"
|
||||
: "month"}
|
||||
{recurrence.interval > 1 ? "s" : ""})
|
||||
</Label>
|
||||
<Input
|
||||
@@ -117,7 +121,9 @@ export function RecurrencePicker({ value, start, onChange }: Props) {
|
||||
min={1}
|
||||
value={recurrence.interval}
|
||||
onChange={(event) =>
|
||||
update({ interval: Number.parseInt(event.target.value, 10) || 1 })
|
||||
update({
|
||||
interval: Number.parseInt(event.target.value, 10) || 1,
|
||||
})
|
||||
}
|
||||
className="mt-1.5 w-24"
|
||||
/>
|
||||
@@ -125,7 +131,9 @@ export function RecurrencePicker({ value, start, onChange }: Props) {
|
||||
|
||||
{recurrence.freq === "WEEKLY" && (
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">Days of the week</Label>
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
Days of the week
|
||||
</Label>
|
||||
<div className="mt-1.5 flex flex-wrap gap-3">
|
||||
{weekdayOptions.map(({ value: day, label }) => (
|
||||
<div key={day} className="flex items-center gap-1.5">
|
||||
@@ -136,7 +144,10 @@ export function RecurrencePicker({ value, start, onChange }: Props) {
|
||||
update({ byDay: updateWeekdays(recurrence.byDay, day) })
|
||||
}
|
||||
/>
|
||||
<Label htmlFor={day} className="cursor-pointer text-xs font-normal">
|
||||
<Label
|
||||
htmlFor={day}
|
||||
className="cursor-pointer text-xs font-normal"
|
||||
>
|
||||
{label}
|
||||
</Label>
|
||||
</div>
|
||||
@@ -186,10 +197,14 @@ export function RecurrencePicker({ value, start, onChange }: Props) {
|
||||
</div>
|
||||
|
||||
{validation.errors.count && (
|
||||
<p className="text-xs text-destructive">{validation.errors.count}</p>
|
||||
<p className="text-xs text-destructive">
|
||||
{validation.errors.count}
|
||||
</p>
|
||||
)}
|
||||
{validation.errors.until && (
|
||||
<p className="text-xs text-destructive">{validation.errors.until}</p>
|
||||
<p className="text-xs text-destructive">
|
||||
{validation.errors.until}
|
||||
</p>
|
||||
)}
|
||||
{validation.errors.rule && (
|
||||
<p className="text-xs text-destructive">{validation.errors.rule}</p>
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { format, parseISO } from "date-fns";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { formatRecurrenceText, getRecurrencePreview, parseRecurrenceRule } from "@/lib/recurrence";
|
||||
import {
|
||||
formatRecurrenceText,
|
||||
getRecurrencePreview,
|
||||
parseRecurrenceRule,
|
||||
} from "@/lib/recurrence";
|
||||
|
||||
interface RRuleDisplayProps {
|
||||
rrule?: string;
|
||||
@@ -12,17 +16,25 @@ export function RRuleDisplay({ rrule, className, start }: RRuleDisplayProps) {
|
||||
if (!rrule) return null;
|
||||
|
||||
const humanText = formatRecurrenceText(rrule);
|
||||
const preview = start ? getRecurrencePreview(parseRecurrenceRule(rrule), start, 3) : [];
|
||||
const preview = start
|
||||
? getRecurrencePreview(parseRecurrenceRule(rrule), start, 3)
|
||||
: [];
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<div className="flex flex-wrap items-center gap-1.5">
|
||||
<Badge variant="secondary" className="h-5 text-[10px] font-normal capitalize">
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="h-5 text-[10px] font-normal capitalize"
|
||||
>
|
||||
{humanText ?? rrule}
|
||||
</Badge>
|
||||
{preview.length > 0 && (
|
||||
<Badge variant="outline" className="h-5 text-[10px] font-normal">
|
||||
Next: {preview.map((value) => format(parseISO(value), "MMM d")).join(", ")}
|
||||
Next:{" "}
|
||||
{preview
|
||||
.map((value) => format(parseISO(value), "MMM d"))
|
||||
.join(", ")}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user