 Esta biblioteca de JavaScript para definir la información de Calendario es un clásico y la hemos usado mucho en los desarrollos de PHPRunner.
Esta biblioteca de JavaScript para definir la información de Calendario es un clásico y la hemos usado mucho en los desarrollos de PHPRunner.
En React, está toda ella disponible y sirve todo lo que hemos aprendido de su uso en PHPRunner y es, todavía, más sencillo explotar todas sus funcionalidades desde el entorno de React.
En este artículo facilito 2 ejemplos (de la propia biblioteca), pero adaptados a la última versión de React.
Aunque espero que ya conozcáis cómo se puede saber las librerías instaladas utilizando el fichero «package.json«, voy a explicar qué es lo que he instalado en cada caso.
Objetivo
Comprobar la integración de FullCalendar en el entorno de React.
Demo1: https://fhumanes.com/fullcalendar-react/
Instalaciones:
npm install fullcalendar
npm install @fullcalendar/react
Demo2: https://fhumanes.com/scheduler-react/
Instalaciones:
npm install fullcalendar
npm install @fullcalendar/react
npm install @fullcalendar/resource
npm install @fullcalendar/resource-timeline
npm install @fullcalendar/adptive 
Solución Técnica
Como os he indicado, los ejemplos los he recogido del proyecto que facilitan desde el producto https://github.com/fullcalendar/fullcalendar-examples, lo único que he hecho es ajustarlo a la forma en que construyo TODOS los proyectos de React y actualizar los módulos que utiliza.
En el siguiente artículo que escribiré, utilizaré la misma funcionalidad descrita en el artículo Guía 64 – Utilización de la biblioteca «FullCalendar», pero realizado en React.
Por si queréis consultar el código, os dejo lo más relevante de los ejemplos.
import React, { useState } from 'react'
import { formatDate } from '@fullcalendar/core'
import FullCalendar from '@fullcalendar/react'
import dayGridPlugin from '@fullcalendar/daygrid'
import timeGridPlugin from '@fullcalendar/timegrid'
import interactionPlugin from '@fullcalendar/interaction'
import { INITIAL_EVENTS, createEventId } from './event-utils'
export default function DemoApp() {
  const [weekendsVisible, setWeekendsVisible] = useState(true)
  const [currentEvents, setCurrentEvents] = useState([])
  function handleWeekendsToggle() {
    setWeekendsVisible(!weekendsVisible)
  }
  function handleDateSelect(selectInfo) {
    let title = prompt('Please enter a new title for your event')
    let calendarApi = selectInfo.view.calendar
    calendarApi.unselect() // clear date selection
    if (title) {
      calendarApi.addEvent({
        id: createEventId(),
        title,
        start: selectInfo.startStr,
        end: selectInfo.endStr,
        allDay: selectInfo.allDay
      })
    }
  }
  function handleEventClick(clickInfo) {
   
    if (window.confirm("Are you sure you want to delete the event "+clickInfo.event.title)  ) {
      clickInfo.event.remove()
    }
    console.log("informa del clic en evento: ",clickInfo.event.id);
  }
  function handleEvents(events) {
    setCurrentEvents(events)
  }
  return (
    <div className='demo-app'>
      <Sidebar
        weekendsVisible={weekendsVisible}
        handleWeekendsToggle={handleWeekendsToggle}
        currentEvents={currentEvents}
      />
      <div className='demo-app-main'>
        <FullCalendar
          plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin]}
          headerToolbar={{
            left: 'prev,next today',
            center: 'title',
            right: 'dayGridMonth,timeGridWeek,timeGridDay'
          }}
          initialView='dayGridMonth'
          editable={true}
          selectable={true}
          selectMirror={true}
          dayMaxEvents={true}
          weekends={weekendsVisible}
          initialEvents={INITIAL_EVENTS} // alternatively, use the `events` setting to fetch from a feed
          select={handleDateSelect}
          eventContent={renderEventContent} // custom render function
          eventClick={handleEventClick}
          eventsSet={handleEvents} // called after events are initialized/added/changed/removed
          /* you can update a remote database when these fire:
          eventAdd={function(){}}
          eventChange={function(){}}
          eventRemove={function(){}}
          */
        />
      </div>
    </div>
  )
}
function renderEventContent(eventInfo) {
  return (
    <>
      <b>{eventInfo.timeText}</b>
      <i>{eventInfo.event.title}</i>
    </>
  )
}
function Sidebar({ weekendsVisible, handleWeekendsToggle, currentEvents }) {
  return (
    <div className='demo-app-sidebar'>
      <div className='demo-app-sidebar-section'>
        <h2>Instructions</h2>
        <ul>
          <li>Select dates and you will be prompted to create a new event</li>
          <li>Drag, drop, and resize events</li>
          <li>Click an event to delete it</li>
        </ul>
      </div>
      <div className='demo-app-sidebar-section'>
        <label>
          <input
            type='checkbox'
            checked={weekendsVisible}
            onChange={handleWeekendsToggle}
          ></input>
          toggle weekends
        </label>
      </div>
      <div className='demo-app-sidebar-section'>
        <h2>All Events ({currentEvents.length})</h2>
        <ul>
          {currentEvents.map((event) => (
            <SidebarEvent key={event.id} event={event} />
          ))}
        </ul>
      </div>
    </div>
  )
}
function SidebarEvent({ event }) {
  return (
    <li key={event.id}>
      <b>{formatDate(event.start, {year: 'numeric', month: 'short', day: 'numeric'})}</b>
      <i>{event.title}</i>
    </li>
  )
}
import React from 'react'
import { formatDate } from '@fullcalendar/core'
import FullCalendar from '@fullcalendar/react'
import adaptivePlugin from '@fullcalendar/adaptive'
import dayGridPlugin from '@fullcalendar/daygrid'
import timeGridPlugin from '@fullcalendar/timegrid'
import interactionPlugin from '@fullcalendar/interaction'
import resourceTimelinePlugin from '@fullcalendar/resource-timeline'
import { INITIAL_EVENTS, createEventId } from './event-utils'
const RESOURCES = [
  { id: 'a', title: 'Auditorium A' },
  { id: 'b', title: 'Auditorium B', eventColor: 'green' },
  { id: 'c', title: 'Auditorium C', eventColor: 'orange' },
]
export default class DemoApp extends React.Component {
  state = {
    weekendsVisible: true,
    currentEvents: []
  }
  render() {
    return (
      <div className='demo-app'>
        {this.renderSidebar()}
        <div className='demo-app-main'>
          <FullCalendar
            plugins={[
              adaptivePlugin,
              dayGridPlugin,
              timeGridPlugin,
              interactionPlugin,
              resourceTimelinePlugin,
            ]}
            headerToolbar={{
              left: 'prev,next today',
              center: 'title',
              right: 'dayGridMonth,timeGridWeek,resourceTimelineDay'
            }}
            initialView='resourceTimelineDay'
            editable={true}
            selectable={true}
            selectMirror={true}
            dayMaxEvents={true}
            weekends={this.state.weekendsVisible}
            initialEvents={INITIAL_EVENTS} // alternatively, use the `events` setting to fetch from a feed
            resources={RESOURCES}
            select={this.handleDateSelect}
            eventContent={renderEventContent} // custom render function
            eventClick={this.handleEventClick}
            eventsSet={this.handleEvents} // called after events are initialized/added/changed/removed
            /* you can update a remote database when these fire:
            eventAdd={function(){}}
            eventChange={function(){}}
            eventRemove={function(){}}
            */
          />
        </div>
      </div>
    )
  }
  renderSidebar() {
    return (
      <div className='demo-app-sidebar'>
        <div className='demo-app-sidebar-section'>
          <h2>Instructions</h2>
          <ul>
            <li>Select dates and you will be prompted to create a new event</li>
            <li>Drag, drop, and resize events</li>
            <li>Click an event to delete it</li>
          </ul>
        </div>
        <div className='demo-app-sidebar-section'>
          <label>
            <input
              type='checkbox'
              checked={this.state.weekendsVisible}
              onChange={this.handleWeekendsToggle}
            ></input>
            toggle weekends
          </label>
        </div>
        <div className='demo-app-sidebar-section'>
          <button onClick={this.handlePrint}>Print</button>
        </div>
        <div className='demo-app-sidebar-section'>
          <h2>All Events ({this.state.currentEvents.length})</h2>
          <ul>
            {this.state.currentEvents.map(renderSidebarEvent)}
          </ul>
        </div>
      </div>
    )
  }
  handleWeekendsToggle = () => {
    this.setState({
      weekendsVisible: !this.state.weekendsVisible
    })
  }
  handleDateSelect = (selectInfo) => {
    let title = prompt('Please enter a new title for your event')
    let calendarApi = selectInfo.view.calendar
    calendarApi.unselect() // clear date selection
    if (title) {
      calendarApi.addEvent({
        id: createEventId(),
        title,
        start: selectInfo.startStr,
        end: selectInfo.endStr,
        allDay: selectInfo.allDay
      })
    }
  }
  handleEventClick = (clickInfo) => {
    if (window.confirm(`Are you sure you want to delete the event '${clickInfo.event.title}'`)) {
      clickInfo.event.remove()
    }
  }
  handleEvents = (events) => {
    // Ocultar el LOGO de producto no registrado
      var logo = document.getElementsByClassName('fc-license-message');
      // console.log("Valor de 'logo': ",logo);
      // console.log("Evento : ",events);
      if ( logo.length === 1 ) {
        logo[0].style.visibility = 'hidden'; // Especial Hide logo
      }
    this.setState({
      currentEvents: events
    })
  }
  handlePrint = () => {
    window.print()
  }
}
function renderEventContent(eventInfo) {
  return (
    <>
      <b>{eventInfo.timeText}</b>
      <i>{eventInfo.event.title}</i>
    </>
  )
}
function renderSidebarEvent(event) {
  return (
    <li key={event.id}>
      <b>{formatDate(event.start, {year: 'numeric', month: 'short', day: 'numeric'})}</b>
      <i>{event.title}</i>
    </li>
  )
}
Como siembre, os dejo los fuentes para que los podáis instalar en vuestros equipos.
Adjuntos
| Archivo | Tamaño de archivo | Descargas | 
|---|---|---|
|  fullcalendar-react | 183 KB | 301 | 
|  scheduler-react | 178 KB | 288 | 
