FullCalendar Calendar Draggable - sydsutton/FS.FluentUI GitHub Wiki
This is a complex, contrived example with lots of printfn
's and unnecessary properties to showcase FullCalendar's
type Event =
| Presenter
| Break
| ``Team Bonding``
module Event =
let getColors = function
| Presenter -> "black", "orange"
| Break -> "white", "green"
| ``Team Bonding`` -> "black", "yellow"
let fromText = function
| Some "Presenter" -> Presenter
| Some "Break" -> Break
| Some "Team Bonding" -> ``Team Bonding``
| _ -> Presenter
open Fable.Core.JsInterop
[<ReactComponent>]
let FullCalendar () =
let isDialogOpen, setIsDialogOpen = React.useState false
let newEventTitle, setNewEventTitle = React.useState ""
let (selectedDate: DateSelectArg option), setSelectedDate = React.useState None
let startTime, setStartTime = React.useState None
let endTime, setEndTime = React.useState None
let (dayEvent: Event), setDayEvent = React.useState Presenter
let allDay, setAllDay = React.useState false
let (calRef: IRefValue<CalendarRoot option>) = React.useRef None
let containerEl = Browser.Dom.document.getElementById "external-events"
let checkboxEl = Browser.Dom.document.getElementById "drop-remove"
if containerEl <> null then
FullCalendar.Draggable (containerEl, [
draggable.itemSelector ".fc-event"
draggable.minDistance 200
draggable.eventData (fun el -> [
event.title el.innerText
event.backgroundColor "green"
]
)
])
let handleDateSelect =
(fun selected ->
let calendarApi = calRef.current.Value.getApi()
let events = calendarApi.getEvents()
printfn "calRef %A" (events |> Array.map (fun t -> t.title))
setSelectedDate (Some selected)
setIsDialogOpen true
setStartTime (Some selected.start)
setEndTime (Some selected.``end``)
)
let handleCloseDialog =
fun _ ->
setIsDialogOpen false
setNewEventTitle ""
setStartTime None
setEndTime None
setDayEvent Presenter
let handleEventClick =
fun (selected: EventClickArg) ->
if Browser.Dom.window.confirm $"Are you sure you want to delete the event {selected.event.title}" then
selected.event.remove ()
let handleAddEvent =
(fun (e: Browser.Types.Event) ->
e.preventDefault ()
match startTime, endTime with
| Some startTime, Some endTime ->
if newEventTitle <> "" && selectedDate.IsSome then
let calendarApi = selectedDate.Value.view.calendar
calendarApi.unselect ()
let (textColor, backgrounColor) = dayEvent |> Event.getColors
let newEvent = [
event.id newEventTitle
event.title newEventTitle
event.start startTime
event.end' endTime
event.allDay allDay
event.backgroundColor backgrounColor
event.textColor textColor
]
let addedEventImpl=
calendarApi.addEvent (!!newEvent |> createObj |> unbox) None
addedEventImpl |> ignore
handleCloseDialog ()
| _, _ -> ()
)
let calendarDialog =
Fui.dialog [
dialog.open' isDialogOpen
dialog.onOpenChange (fun (d: DialogOpenChangeData<Browser.Types.MouseEvent>) ->
d.``open`` |> setIsDialogOpen)
dialog.children [
Fui.dialogSurface [
Fui.dialogContent [
dialogContent.children [
Html.form [
prop.onSubmit handleAddEvent
prop.children [
Fui.stack [
stack.tokens [ stack.tokens.childrenGap 8 ]
stack.horizontal false
stack.children [
Fui.dropdown [
dropdown.value $"{dayEvent}"
dropdown.onOptionSelect (fun (d: OptionOnSelectData) -> d.optionValue |> Event.fromText |> setDayEvent)
dropdown.children [
for event in [ Presenter; Break; ``Team Bonding``] do
Fui.option [
option.value $"{event}"
option.text $"{event}"
option.children [
Fui.text $"{event}"
]
]
]
]
Fui.input [
input.type' "text"
input.placeholder "Event Title"
input.value newEventTitle
input.onChange (fun e -> setNewEventTitle e)
input.required true
]
Fui.timePicker [
timePicker.value ((startTime |> Option.defaultValue DateTime.Today).ToShortTimeString())
timePicker.selectedTime startTime
timePicker.onTimeChange (fun (t: TimeSelectionData) -> setStartTime t.selectedTime)
]
Fui.timePicker [
timePicker.value ((endTime |> Option.defaultValue DateTime.Today).ToShortTimeString())
timePicker.selectedTime endTime
match selectedDate with
| Some sd ->
timePicker.dateAnchor sd.start
timePicker.startHour sd.start.Hour
| None ->
prop.custom ("", "") |> unbox
timePicker.onTimeChange (fun (t: TimeSelectionData) -> setEndTime t.selectedTime)
]
Fui.checkbox [
checkbox.isChecked allDay
checkbox.onCheckedChange (fun c -> setAllDay c)
checkbox.label "All Day Event"
]
Fui.button [
button.type' "submit"
button.text "Add"
]
]
]
]
]
]
]
]
]
]
let draggableEvents =
Html.div [
prop.id "external-events"
prop.children [
for i in [1..5] do
Html.div [
prop.key i
prop.className "fc-event fc-h-event fc-daygrid-event fc-daygrid-block-event"
prop.children [
Html.div [
prop.className "fc-event-main"
prop.children [
Html.text $"My Event {i}"
]
]
]
]
Fui.checkbox [
checkbox.id "drop-remove"
checkbox.label "Remove after drop"
]
]
]
Html.div [
prop.style [ style.width (length.vw 70) ]
prop.children [
draggableEvents
FullCalendar.Calendar [
calendar.plugins [
Plugin.dayGridPlugin
Plugin.timeGridPlugin
Plugin.interactionPlugin
Plugin.bootstrap5Plugin
Plugin.listPlugin
Plugin.multimonthPlugin
]
calendar.ref calRef
calendar.droppable true
calendar.initialView.dayGridMonth
calendar.eventDrop (fun i -> printfn "eventDrop %A" (i.delta.days) )
calendar.eventChange (fun c -> printfn "event %A oldEvent %A" c.event.start c.oldEvent.start)
calendar.editable true
calendar.eventMaxStack 2
calendar.dayMaxEventRows 3
calendar.eventResize (fun info -> Browser.Dom.window.alert (info.event.title + " end is now " + info.event.``end``.ToString()))
calendar.drop (fun (info: DropInfo) ->
if checkboxEl?checked = true then
info.draggedEl.parentNode.removeChild(info.draggedEl) |> ignore
else
()
)
calendar.selectMirror true
calendar.dropAccept (fun el -> printfn "api %A" el.innerText; true)
calendar.nowIndicator true
calendar.unselectAuto true
calendar.unselect (fun unselectArg -> printfn "unselect %A" unselectArg)
calendar.validRange [ range.start (DateTime.Today.AddDays -7); range.end' (DateTime.Today.AddDays 7)]
calendar.selectable true
calendar.select handleDateSelect
calendar.eventClick handleEventClick
calendar.themeSystem.bootstrap5
calendar.dayMaxEvents true
calendar.eventAdd (fun e -> printfn "eventAdd %A" (e.event.title))
calendar.loading (fun b -> printfn "isLoading %A" b)
calendar.buttonIcons [
buttonIcon.prev "chevron-left"
]
calendar.eventsSet (fun (e: CalendarEvent array) -> printfn "eventsSet %A" (e |> Array.map (fun e -> e.title)))
calendar.headerToolbar [
headerToolbar.start "today prev,next"
headerToolbar.center "title"
headerToolbar.end' "myCustomButton, dayGridMonth,timeGridWeek,timeGridDay,list"
]
calendar.dayHeaderFormat [
dateFormat.weekday.short
]
calendar.customButtons [
"myCustomButton",
[
customButton.text "Add event"
customButton.icon "plus-circle"
customButton.click (fun _ _ -> printf "Joke's on you, I don't do anything")
]
]
calendar.events "https://fullcalendar.io/api/demo-feeds/events.json?start=2/23/2025&end=4/5/2025"
]
calendarDialog
]
]