{
  "$schema": "https://ai.syncfusion.com/schema/registry-item.json",
  "name": "scheduler-external-drag-and-drop",
  "framework": "react",
  "type": "registry:component",
  "component": "Scheduler",
  "variant": "external-drag-and-drop",
  "dependencies": [
    "@syncfusion/ej2-navigations",
    "@syncfusion/ej2-react-navigations",
    "@syncfusion/ej2-react-schedule"
  ],
  "description": "Scheduler accepts drag-and-drop from an external tree view into its time slots.",
  "meta": {
    "essentialStudioRelease": "2026 Volume 2 (v34.1.29)",
    "license": "commercial-or-community",
    "licenseNote": "The Syncfusion package is licensed. The composition in this file is source you own and edit. See https://ai.syncfusion.com/licensing.md",
    "requiresLicenseKey": true,
    "requiresServerEndpoint": false,
    "platformIndex": "https://ai.syncfusion.com/react/llms.txt",
    "skillPack": "syncfusion/react-ui-components-skills",
    "docs": "https://ai.syncfusion.com/gallery/react/ts/scheduler-external-drag-and-drop.md"
  },
  "files": [
    {
      "target": "src/components/scheduler-external-drag-and-drop/Scheduler.tsx",
      "content": "import { useRef } from 'react';\nimport { ScheduleComponent, type TreeViewArgs, ResourcesDirective, ResourceDirective, ViewsDirective, ViewDirective, type ResourceDetails, Inject, TimelineViews, Resize, DragAndDrop, TimelineMonth, type ActionEventArgs, type CellClickEventArgs } from '@syncfusion/ej2-react-schedule';\nimport { extend, closest, remove, addClass } from '@syncfusion/ej2-base';\nimport { type DragAndDropEventArgs } from '@syncfusion/ej2-navigations';\nimport { TreeViewComponent } from '@syncfusion/ej2-react-navigations';\n\n/**\n * schedule resources group-editing sample\n */\n\nlet waitingList = [\n  { \"Id\": 1, \"Name\": \"Steven\", \"StartTime\": \"2021-09-04T02:00:00.000Z\", \"EndTime\": \"2021-09-04T04:00:00.000Z\", \"Description\": \"Consulting\", \"DepartmentName\": \"GENERAL\" },\n  { \"Id\": 2, \"Name\": \"Milan\", \"StartTime\": \"2021-09-05T03:00:00.000Z\", \"EndTime\": \"2021-09-05T05:00:00.000Z\", \"Description\": \"Bad Breath\", \"DepartmentName\": \"DENTAL\" },\n  { \"Id\": 3, \"Name\": \"Laura\", \"StartTime\": \"2021-09-05T04:00:00.000Z\", \"EndTime\": \"2021-09-05T05:00:00.000Z\", \"Description\": \"Eye Checkup\", \"DepartmentName\": \"GENERAL\" },\n  { \"Id\": 4, \"Name\": \"Janet\", \"StartTime\": \"2021-09-04T05:30:00.000Z\", \"EndTime\": \"2021-09-04T07:00:00.000Z\", \"Description\": \"Gum Disease\", \"DepartmentName\": \"DENTAL\" },\n  { \"Id\": 5, \"Name\": \"Adams\", \"StartTime\": \"2021-09-04T05:30:00.000Z\", \"EndTime\": \"2021-09-04T07:00:00.000Z\", \"Description\": \"Observation\", \"DepartmentName\": \"GENERAL\" },\n  { \"Id\": 6, \"Name\": \"John\", \"StartTime\": \"2021-09-04T05:30:00.000Z\", \"EndTime\": \"2021-09-04T07:00:00.000Z\", \"Description\": \"Mouth Sores\", \"DepartmentName\": \"DENTAL\" }\n];\n\nlet hospitalData = [\n  { \"Id\": 10, \"Name\": \"David\", \"StartTime\": \"2021-08-02T03:30:00.000Z\", \"EndTime\": \"2021-08-02T04:30:00.000Z\", \"Description\": \"Health Checkup\", \"DepartmentID\": 1, \"ConsultantID\": 1, \"DepartmentName\": \"GENERAL\" },\n  { \"Id\": 11, \"Name\": \"John\", \"StartTime\": \"2021-08-02T05:00:00.000Z\", \"EndTime\": \"2021-08-02T06:00:00.000Z\", \"Description\": \"Tooth Erosion\", \"DepartmentID\": 2, \"ConsultantID\": 2, \"DepartmentName\": \"DENTAL\" },\n  { \"Id\": 12, \"Name\": \"Peter\", \"StartTime\": \"2021-08-02T06:30:00.000Z\", \"EndTime\": \"2021-08-02T07:30:00.000Z\", \"Description\": \"Eye and Spectacles Checkup\", \"DepartmentID\": 1, \"ConsultantID\": 3, \"DepartmentName\": \"GENERAL\" },\n  { \"Id\": 13, \"Name\": \"Starc\", \"StartTime\": \"2021-08-02T08:30:00.000Z\", \"EndTime\": \"2021-08-02T09:30:00.000Z\", \"Description\": \"Toothaches\", \"DepartmentID\": 2, \"ConsultantID\": 4, \"DepartmentName\": \"DENTAL\" },\n  { \"Id\": 14, \"Name\": \"James\", \"StartTime\": \"2021-08-02T04:30:00.000Z\", \"EndTime\": \"2021-08-02T05:30:00.000Z\", \"Description\": \"Surgery Appointment\", \"DepartmentID\": 1, \"ConsultantID\": 5, \"DepartmentName\": \"GENERAL\" },\n  { \"Id\": 15, \"Name\": \"Jercy\", \"StartTime\": \"2021-08-02T04:00:00.000Z\", \"EndTime\": \"2021-08-02T05:00:00.000Z\", \"Description\": \"Tooth Sensitivity\", \"DepartmentID\": 2, \"ConsultantID\": 6, \"DepartmentName\": \"DENTAL\" },\n  { \"Id\": 16, \"Name\": \"Albert\", \"StartTime\": \"2021-08-03T04:30:00.000Z\", \"EndTime\": \"2021-08-03T06:00:00.000Z\", \"Description\": \"Skin care treatment\", \"DepartmentID\": 1, \"ConsultantID\": 7, \"DepartmentName\": \"GENERAL\" },\n  { \"Id\": 17, \"Name\": \"Louis\", \"StartTime\": \"2021-08-03T07:00:00.000Z\", \"EndTime\": \"2021-08-03T08:15:00.000Z\", \"Description\": \"General Checkup\", \"DepartmentID\": 1, \"ConsultantID\": 9, \"DepartmentName\": \"GENERAL\" },\n  { \"Id\": 18, \"Name\": \"Williams\", \"StartTime\": \"2021-08-03T06:30:00.000Z\", \"EndTime\": \"2021-08-03T08:30:00.000Z\", \"Description\": \"Mouth Sores\", \"DepartmentID\": 2, \"ConsultantID\": 10, \"DepartmentName\": \"DENTAL\" },\n  { \"Id\": 19, \"Name\": \"David\", \"StartTime\": \"2021-08-03T11:00:00.000Z\", \"EndTime\": \"2021-08-03T12:45:00.000Z\", \"Description\": \"Eye checkup and Treatment\", \"DepartmentID\": 1, \"ConsultantID\": 1, \"DepartmentName\": \"GENERAL\" },\n  { \"Id\": 20, \"Name\": \"John\", \"StartTime\": \"2021-08-03T14:00:00.000Z\", \"EndTime\": \"2021-08-03T16:15:00.000Z\", \"Description\": \"Toothaches\", \"DepartmentID\": 2, \"ConsultantID\": 2, \"DepartmentName\": \"DENTAL\" }\n];\n\nconst ExternalDragDrop = () => {\n  let scheduleObj = useRef<ScheduleComponent>(null);\n  let treeObj = useRef<TreeViewComponent>(null);\n  let isTreeItemDropped: boolean = false;\n  let draggedItemId: string = '';\n  const allowDragAndDrops: boolean = true;\n  const fields: Record<string, any> = { dataSource: waitingList, id: 'Id', text: 'Name' };\n  const data: Record<string, any>[] = extend([], hospitalData, null, true) as Record<string, any>[];\n  const departmentData: Record<string, any>[] = [\n    { Text: 'GENERAL', Id: 1, Color: '#bbdc00' },\n    { Text: 'DENTAL', Id: 2, Color: '#9e5fff' }\n  ];\n  const consultantData: Record<string, any>[] = [\n    { Text: 'Alice', Id: 1, GroupId: 1, Color: '#bbdc00', Designation: 'Cardiologist' },\n    { Text: 'Nancy', Id: 2, GroupId: 2, Color: '#9e5fff', Designation: 'Orthodontist' },\n    { Text: 'Robert', Id: 3, GroupId: 1, Color: '#bbdc00', Designation: 'Optometrist' },\n    { Text: 'Robson', Id: 4, GroupId: 2, Color: '#9e5fff', Designation: 'Periodontist' },\n    { Text: 'Laura', Id: 5, GroupId: 1, Color: '#bbdc00', Designation: 'Orthopedic' },\n    { Text: 'Margaret', Id: 6, GroupId: 2, Color: '#9e5fff', Designation: 'Endodontist' }\n  ];\n\n  const getConsultantName = (value: ResourceDetails | TreeViewArgs): string => {\n    return (value as ResourceDetails).resourceData[(value as ResourceDetails).resource.textField] as string;\n  }\n\n  const getConsultantImage = (value: ResourceDetails): string => {\n    return getConsultantName(value).toLowerCase();\n  }\n\n  const getConsultantDesignation = (value: ResourceDetails): string => {\n    return (value as ResourceDetails).resourceData.Designation as string;\n  }\n\n  const resourceHeaderTemplate = (props: any)  => {\n    return (\n      <div className=\"template-wrap\">\n        <div className=\"specialist-category\">\n          <div className={\"specialist-image \" + getConsultantImage(props)}></div>\n          <div className=\"specialist-name\"> {getConsultantName(props)}</div>\n          <div className=\"specialist-designation\">{getConsultantDesignation(props)}</div>\n        </div>\n      </div>\n    );\n  }\n\n  const treeTemplate = (props: any) => {\n    return (\n      <div id=\"waiting\">\n        <div id=\"waitdetails\">\n          <div id=\"waitlist\">{props.Name}</div>\n          <div id=\"waitcategory\">{props.DepartmentName} - {props.Description}</div>\n        </div>\n      </div>\n    );\n  }\n\n  const onItemSelecting = (args: any): void => {\n    args.cancel = true;\n  }\n\n  const onTreeDrag = (event: any): void => {\n    if (scheduleObj.current.isAdaptive) {\n      let classElement: HTMLElement = scheduleObj.current.element.querySelector('.e-device-hover');\n      if (classElement) {\n        classElement.classList.remove('e-device-hover');\n      }\n      if (event.target.classList.contains('e-work-cells')) {\n        addClass([event.target], 'e-device-hover');\n      }\n    }\n  }\n\n  const onActionBegin = (event: ActionEventArgs): void => {\n    if (event.requestType === 'eventCreate' && isTreeItemDropped) {\n      let treeViewData: Record<string, any>[] = treeObj.current.fields.dataSource as Record<string, any>[];\n      const filteredPeople: Record<string, any>[] = treeViewData.filter((item: any) => item.Id !== parseInt(draggedItemId, 10));\n      treeObj.current.fields.dataSource = filteredPeople;\n      let elements: NodeListOf<HTMLElement> = document.querySelectorAll('.e-drag-item.treeview-external-drag');\n      for (let i: number = 0; i < elements.length; i++) {\n        remove(elements[i]);\n      }\n    }\n  }\n\n  const onTreeDragStop = (event: DragAndDropEventArgs): void => {\n    let treeElement: Element = closest(event.target, '.e-treeview');\n    let classElement: HTMLElement = scheduleObj.current.element.querySelector('.e-device-hover');\n    if (classElement) {\n      classElement.classList.remove('e-device-hover');\n    }\n    if (!treeElement) {\n      event.cancel = true;\n      let scheduleElement: Element = closest(event.target, '.e-content-wrap');\n      if (scheduleElement) {\n        let treeviewData: Record<string, any>[] = treeObj.current.fields.dataSource as Record<string, any>[];\n        if (event.target.classList.contains('e-work-cells')) {\n          const filteredData: Record<string, any>[] = treeviewData.filter((item: any) => item.Id === parseInt(event.draggedNodeData.id as string, 10));\n          let cellData: CellClickEventArgs = scheduleObj.current.getCellDetails(event.target);\n          let resourceDetails: ResourceDetails = scheduleObj.current.getResourcesByIndex(cellData.groupIndex);\n          let eventData: Record<string, any> = {\n            Name: filteredData[0].Name,\n            StartTime: cellData.startTime,\n            EndTime: cellData.endTime,\n            IsAllDay: cellData.isAllDay,\n            Description: filteredData[0].Description,\n            DepartmentID: resourceDetails.resourceData.GroupId,\n            ConsultantID: resourceDetails.resourceData.Id\n          };\n          scheduleObj.current.openEditor(eventData, 'Add', true);\n          isTreeItemDropped = true;\n          draggedItemId = event.draggedNodeData.id as string;\n        }\n      }\n    }\n    document.body.classList.remove('e-disble-not-allowed');\n  }\n\n  const onTreeDragStart = () => {\n    document.body.classList.add('e-disble-not-allowed');\n  }\n\n  return (\n    <div className='schedule-control-section'>\n      <div className='col-lg-12 control-section'>\n        <div className='control-wrapper drag-sample-wrapper'>\n          <div className=\"schedule-container\">\n            <div className=\"title-container\">\n              <h1 className=\"title-text\">Doctor's Appointments</h1>\n            </div>\n            <ScheduleComponent ref={scheduleObj} cssClass='schedule-drag-drop' width='100%' height='650px' selectedDate={new Date(2021, 7, 2)} currentView='TimelineDay' resourceHeaderTemplate={resourceHeaderTemplate} eventSettings={{ dataSource: data, fields: { subject: { title: 'Patient Name', name: 'Name' }, startTime: { title: \"From\", name: \"StartTime\" }, endTime: { title: \"To\", name: \"EndTime\" }, description: { title: 'Reason', name: 'Description' } } }} group={{ enableCompactView: false, resources: ['Departments', 'Consultants'] }} actionBegin={onActionBegin} >\n              <ResourcesDirective>\n                <ResourceDirective field='DepartmentID' title='Department' name='Departments' allowMultiple={false} dataSource={departmentData} textField='Text' idField='Id' colorField='Color' />\n                <ResourceDirective field='ConsultantID' title='Consultant' name='Consultants' allowMultiple={false} dataSource={consultantData} textField='Text' idField='Id' groupIDField=\"GroupId\" colorField='Color' />\n              </ResourcesDirective>\n              <ViewsDirective>\n                <ViewDirective option='TimelineDay' />\n                <ViewDirective option='TimelineMonth' />\n              </ViewsDirective>\n              <Inject services={[TimelineViews, TimelineMonth, Resize, DragAndDrop]} />\n            </ScheduleComponent>\n          </div>\n          <div className=\"treeview-container\">\n            <div className=\"title-container\">\n              <h1 className=\"title-text\">Waiting List</h1>\n            </div>\n            <TreeViewComponent ref={treeObj} cssClass='treeview-external-drag' dragArea=\".drag-sample-wrapper\" nodeTemplate={treeTemplate} fields={fields} nodeDragStop={onTreeDragStop} nodeSelecting={onItemSelecting} nodeDragging={onTreeDrag} nodeDragStart={onTreeDragStart} allowDragAndDrop={allowDragAndDrops} />\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n}\nexport default ExternalDragDrop;"
    }
  ]
}