Skip to content

Commit 33b55cd

Browse files
committed
feat: enhance CalendarView with event handling and add button for new events
1 parent 105b096 commit 33b55cd

2 files changed

Lines changed: 133 additions & 25 deletions

File tree

packages/plugin-calendar/src/CalendarView.tsx

Lines changed: 88 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,20 @@
99
"use client"
1010

1111
import * as React from "react"
12-
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react"
13-
import { cn, Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@object-ui/components"
12+
import { ChevronLeftIcon, ChevronRightIcon, CalendarIcon, PlusIcon } from "lucide-react"
13+
import {
14+
cn,
15+
Button,
16+
Select,
17+
SelectContent,
18+
SelectItem,
19+
SelectTrigger,
20+
SelectValue,
21+
Calendar,
22+
Popover,
23+
PopoverContent,
24+
PopoverTrigger
25+
} from "@object-ui/components"
1426

1527
const DEFAULT_EVENT_COLOR = "bg-blue-500 text-white"
1628

@@ -32,6 +44,7 @@ export interface CalendarViewProps {
3244
onDateClick?: (date: Date) => void
3345
onViewChange?: (view: "month" | "week" | "day") => void
3446
onNavigate?: (date: Date) => void
47+
onAddClick?: () => void
3548
className?: string
3649
}
3750

@@ -43,11 +56,21 @@ function CalendarView({
4356
onDateClick,
4457
onViewChange,
4558
onNavigate,
59+
onAddClick,
4660
className,
4761
}: CalendarViewProps) {
4862
const [selectedView, setSelectedView] = React.useState(view)
4963
const [selectedDate, setSelectedDate] = React.useState(currentDate)
5064

65+
// Sync state if props change
66+
React.useEffect(() => {
67+
setSelectedDate(currentDate)
68+
}, [currentDate])
69+
70+
React.useEffect(() => {
71+
setSelectedView(view)
72+
}, [view])
73+
5174
const handlePrevious = () => {
5275
const newDate = new Date(selectedDate)
5376
if (selectedView === "month") {
@@ -113,37 +136,70 @@ function CalendarView({
113136
}
114137
}
115138

139+
const handleDateSelect = (date: Date | undefined) => {
140+
if (date) {
141+
setSelectedDate(date)
142+
onNavigate?.(date)
143+
}
144+
}
145+
116146
return (
117147
<div className={cn("flex flex-col h-full bg-background", className)}>
118148
{/* Header */}
119149
<div className="flex items-center justify-between p-4 border-b">
120-
<div className="flex items-center gap-2">
121-
<Button variant="outline" size="sm" onClick={handleToday}>
122-
Today
123-
</Button>
124-
<div className="flex items-center">
125-
<Button
126-
variant="ghost"
127-
size="icon"
128-
onClick={handlePrevious}
129-
className="h-8 w-8"
130-
>
131-
<ChevronLeftIcon className="h-4 w-4" />
132-
</Button>
133-
<Button
134-
variant="ghost"
135-
size="icon"
136-
onClick={handleNext}
137-
className="h-8 w-8"
138-
>
139-
<ChevronRightIcon className="h-4 w-4" />
140-
</Button>
150+
<div className="flex items-center gap-4">
151+
<div className="flex items-center bg-muted/50 rounded-lg p-1 gap-1">
152+
<Button variant="ghost" size="sm" onClick={handleToday} className="h-8">
153+
Today
154+
</Button>
155+
<div className="h-4 w-px bg-border mx-1" />
156+
<Button
157+
variant="ghost"
158+
size="icon"
159+
onClick={handlePrevious}
160+
className="h-8 w-8"
161+
>
162+
<ChevronLeftIcon className="h-4 w-4" />
163+
</Button>
164+
<Button
165+
variant="ghost"
166+
size="icon"
167+
onClick={handleNext}
168+
className="h-8 w-8"
169+
>
170+
<ChevronRightIcon className="h-4 w-4" />
171+
</Button>
141172
</div>
142-
<h2 className="text-lg font-semibold ml-2">{getDateLabel()}</h2>
173+
174+
<Popover>
175+
<PopoverTrigger asChild>
176+
<Button
177+
variant="ghost"
178+
className={cn(
179+
"text-xl font-semibold h-auto px-3 py-1 hover:bg-muted/50 transition-colors",
180+
"flex items-center gap-2"
181+
)}
182+
>
183+
<CalendarIcon className="h-5 w-5 text-muted-foreground" />
184+
<span>{getDateLabel()}</span>
185+
</Button>
186+
</PopoverTrigger>
187+
<PopoverContent className="w-auto p-0" align="start">
188+
<Calendar
189+
mode="single"
190+
selected={selectedDate}
191+
onSelect={handleDateSelect}
192+
initialFocus
193+
fromYear={2000}
194+
toYear={2050}
195+
/>
196+
</PopoverContent>
197+
</Popover>
143198
</div>
199+
144200
<div className="flex items-center gap-2">
145201
<Select value={selectedView} onValueChange={handleViewChange}>
146-
<SelectTrigger className="w-32">
202+
<SelectTrigger className="w-32 bg-background">
147203
<SelectValue />
148204
</SelectTrigger>
149205
<SelectContent>
@@ -152,6 +208,13 @@ function CalendarView({
152208
<SelectItem value="month">Month</SelectItem>
153209
</SelectContent>
154210
</Select>
211+
212+
{onAddClick && (
213+
<Button onClick={onAddClick} size="sm" className="gap-1">
214+
<PlusIcon className="h-4 w-4" />
215+
New
216+
</Button>
217+
)}
155218
</div>
156219
</div>
157220

packages/plugin-calendar/src/calendar-view-renderer.tsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,51 @@ ComponentRegistry.register('calendar-view',
3030
/** Field name indicating if event is all-day */
3131
const allDayField = schema.allDayField || 'allDay';
3232

33+
return {
34+
id: record._id || record.id || index,
35+
title: record[titleField] || 'Untitled Event',
36+
start: new Date(record[startField]),
37+
end: record[endField] ? new Date(record[endField]) : undefined,
38+
allDay: record[allDayField],
39+
color: record[colorField],
40+
data: record,
41+
};
42+
});
43+
}, [schema.data, schema.titleField, schema.startDateField, schema.endDateField, schema.colorField, schema.allDayField]);
44+
45+
const handleEventClick = (event: CalendarEvent) => {
46+
if (schema.events?.onEventClick) {
47+
// Dispatch configured action
48+
// This would use the action runner in a real implementation
49+
// For now we just call onAction if provided
50+
onAction?.({
51+
type: 'event-click',
52+
payload: event
53+
});
54+
}
55+
};
56+
57+
const handleAddClick = () => {
58+
// Standard "Create" action trigger
59+
onAction?.({
60+
type: 'create',
61+
payload: {}
62+
});
63+
};
64+
65+
return (
66+
<CalendarView
67+
className={className}
68+
events={events}
69+
onEventClick={handleEventClick}
70+
onAddClick={handleAddClick}
71+
// Pass validation or other props
72+
{...props}
73+
/>
74+
);
75+
}
76+
); const allDayField = schema.allDayField || 'allDay';
77+
3378
const title = record[titleField] || 'Untitled';
3479
const start = record[startField] ? new Date(record[startField]) : new Date();
3580
const end = record[endField] ? new Date(record[endField]) : undefined;

0 commit comments

Comments
 (0)