akfatimeline 1.0.6 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/CHANGELOG.md +98 -35
  2. package/dist/Timeline.js +4309 -1677
  3. package/dist/components/Timeline/AutocompleteSelect.js +150 -0
  4. package/dist/components/Timeline/ContextMenu.js +149 -0
  5. package/dist/components/Timeline/DailyView.js +255 -0
  6. package/dist/components/Timeline/DatePickerComponent.js +13 -0
  7. package/{public/dist/dist → dist}/components/Timeline/DragAndDropHandler.js +34 -34
  8. package/dist/components/Timeline/EventBadge.js +26 -0
  9. package/dist/components/Timeline/EventDetailModal.js +138 -0
  10. package/dist/components/Timeline/EventIcon.js +47 -0
  11. package/dist/{dist/components → components}/Timeline/EventTooltip.js +206 -206
  12. package/dist/components/Timeline/FilterPanel.js +179 -0
  13. package/dist/{dist/components → components}/Timeline/Indicator.js +26 -26
  14. package/dist/components/Timeline/LoadingSpinner.js +48 -0
  15. package/dist/{dist/components → components}/Timeline/MasterHeader.js +104 -68
  16. package/{public/dist/dist → dist}/components/Timeline/Resources.js +53 -53
  17. package/dist/{dist/components → components}/Timeline/ResourcesHeader.js +14 -14
  18. package/dist/components/Timeline/Timeline.css +2491 -0
  19. package/dist/components/Timeline/Timeline.js +607 -0
  20. package/dist/{dist/components → components}/Timeline/TimelineCell.js +8 -8
  21. package/dist/components/Timeline/TimelineContent.js +838 -0
  22. package/{public/dist/dist → dist}/components/Timeline/TimelineEvents.js +114 -114
  23. package/dist/components/Timeline/TimelineHeader.js +54 -0
  24. package/{public/dist/dist → dist}/components/Timeline/TimelineMonthContainer.js +29 -29
  25. package/{public/dist/dist → dist}/components/Timeline/TimelineResources.js +16 -16
  26. package/{public/dist/dist → dist}/hooks/useDragAndDrop.js +80 -80
  27. package/dist/{dist/hooks → hooks}/useEventDragDrop.js +126 -126
  28. package/dist/hooks/useEventManagement.js +173 -0
  29. package/dist/hooks/useEventSelection.js +82 -0
  30. package/{public/dist/dist → dist}/hooks/useExtendEvent.js +28 -28
  31. package/dist/hooks/useKeyboardShortcuts.js +158 -0
  32. package/dist/hooks/useTouchGestures.js +90 -0
  33. package/dist/utils/conflictUtils.js +105 -0
  34. package/dist/{dist/utils → utils}/dateUtils.js +36 -36
  35. package/dist/{dist/utils → utils}/filterTimelineData.js +20 -20
  36. package/dist/utils/filterUtils.js +106 -0
  37. package/dist/utils/timeUtils.js +179 -0
  38. package/dist/{dist/utils → utils}/timelineUtils.js +39 -39
  39. package/dist/utils/viewModeUtils.js +54 -0
  40. package/package.json +89 -19
  41. package/src/App.js +300 -19
  42. package/src/components/Timeline/AutocompleteSelect.js +150 -0
  43. package/src/components/Timeline/ContextMenu.js +149 -0
  44. package/src/components/Timeline/DailyView.js +255 -0
  45. package/src/components/Timeline/DatePickerComponent.js +13 -17
  46. package/src/components/Timeline/DragAndDropHandler.js +34 -34
  47. package/src/components/Timeline/EventBadge.js +26 -0
  48. package/src/components/Timeline/EventDetailModal.js +138 -0
  49. package/src/components/Timeline/EventIcon.js +47 -0
  50. package/src/components/Timeline/EventTooltip.js +206 -206
  51. package/src/components/Timeline/FilterPanel.js +179 -0
  52. package/src/components/Timeline/Indicator.js +26 -26
  53. package/src/components/Timeline/LoadingSpinner.js +48 -0
  54. package/src/components/Timeline/MasterHeader.js +104 -68
  55. package/src/components/Timeline/Resources.js +53 -53
  56. package/src/components/Timeline/ResourcesHeader.js +14 -14
  57. package/src/components/Timeline/Timeline.css +2491 -616
  58. package/src/components/Timeline/Timeline.js +607 -309
  59. package/src/components/Timeline/TimelineCell.js +8 -8
  60. package/src/components/Timeline/TimelineContent.js +838 -446
  61. package/src/components/Timeline/TimelineEvents.js +114 -114
  62. package/src/components/Timeline/TimelineHeader.js +54 -43
  63. package/src/components/Timeline/TimelineMonthContainer.js +29 -29
  64. package/src/components/Timeline/TimelineResources.js +16 -16
  65. package/src/demo.css +4 -0
  66. package/src/hooks/useDragAndDrop.js +80 -80
  67. package/src/hooks/useEventDragDrop.js +126 -126
  68. package/src/hooks/useEventManagement.js +173 -0
  69. package/src/hooks/useEventSelection.js +82 -0
  70. package/src/hooks/useExtendEvent.js +28 -28
  71. package/src/hooks/useKeyboardShortcuts.js +158 -0
  72. package/src/hooks/useTouchGestures.js +90 -0
  73. package/src/index.js +1 -7
  74. package/src/library.js +26 -0
  75. package/src/utils/conflictUtils.js +105 -0
  76. package/src/utils/dateUtils.js +36 -36
  77. package/src/utils/filterTimelineData.js +20 -20
  78. package/src/utils/filterUtils.js +106 -0
  79. package/src/utils/timeUtils.js +179 -0
  80. package/src/utils/timelineUtils.js +39 -39
  81. package/src/utils/viewModeUtils.js +54 -0
  82. package/.babelrc +0 -6
  83. package/babel.config.json +0 -4
  84. package/dist/dist/components/Timeline/DatePickerComponent.js +0 -17
  85. package/dist/dist/components/Timeline/DragAndDropHandler.js +0 -35
  86. package/dist/dist/components/Timeline/Resources.js +0 -53
  87. package/dist/dist/components/Timeline/Timeline.css +0 -616
  88. package/dist/dist/components/Timeline/Timeline.js +0 -309
  89. package/dist/dist/components/Timeline/TimelineContent.js +0 -446
  90. package/dist/dist/components/Timeline/TimelineEvents.js +0 -114
  91. package/dist/dist/components/Timeline/TimelineHeader.js +0 -43
  92. package/dist/dist/components/Timeline/TimelineMonthContainer.js +0 -29
  93. package/dist/dist/components/Timeline/TimelineResources.js +0 -16
  94. package/dist/dist/hooks/useDragAndDrop.js +0 -80
  95. package/dist/dist/hooks/useExtendEvent.js +0 -28
  96. package/public/dist/Timeline.js +0 -3277
  97. package/public/dist/dist/components/Timeline/DatePickerComponent.js +0 -17
  98. package/public/dist/dist/components/Timeline/EventTooltip.js +0 -206
  99. package/public/dist/dist/components/Timeline/Indicator.js +0 -29
  100. package/public/dist/dist/components/Timeline/MasterHeader.js +0 -68
  101. package/public/dist/dist/components/Timeline/ResourcesHeader.js +0 -14
  102. package/public/dist/dist/components/Timeline/Timeline.css +0 -616
  103. package/public/dist/dist/components/Timeline/Timeline.js +0 -304
  104. package/public/dist/dist/components/Timeline/TimelineCell.js +0 -8
  105. package/public/dist/dist/components/Timeline/TimelineContent.js +0 -447
  106. package/public/dist/dist/components/Timeline/TimelineHeader.js +0 -43
  107. package/public/dist/dist/hooks/useEventDragDrop.js +0 -126
  108. package/public/dist/dist/utils/HorizontalVirtualScroll.js +0 -0
  109. package/public/dist/dist/utils/dateUtils.js +0 -36
  110. package/public/dist/dist/utils/filterTimelineData.js +0 -21
  111. package/public/dist/dist/utils/timelineUtils.js +0 -40
  112. package/public/favicon.ico +0 -0
  113. package/public/index kutuphane /304/261c/304/261n.html" +0 -43
  114. package/public/index tasarim icin.html +0 -20
  115. package/public/index.html +0 -43
  116. package/public/logo192.png +0 -0
  117. package/public/logo512.png +0 -0
  118. package/public/manifest.json +0 -25
  119. package/public/robots.txt +0 -3
  120. package/src/App.css +0 -38
  121. package/src/App.test.js +0 -8
  122. package/src/dist/Timeline.js +0 -277
  123. package/src/index.css +0 -13
  124. package/src/logo.svg +0 -1
  125. package/src/reportWebVitals.js +0 -13
  126. package/src/setupTests.js +0 -5
  127. package/webpack.config.js +0 -49
  128. /package/dist/{dist/utils → utils}/HorizontalVirtualScroll.js +0 -0
@@ -0,0 +1,150 @@
1
+ import React, { useState, useRef, useEffect } from "react";
2
+ import "./Timeline.css";
3
+
4
+ const AutocompleteSelect = ({
5
+ options = [],
6
+ value = null,
7
+ onChange = () => {},
8
+ placeholder = "Seçiniz...",
9
+ getOptionLabel = (option) => option?.label || option?.name || String(option),
10
+ getOptionValue = (option) => option?.value || option?.id || option,
11
+ filterOptions = (options, inputValue) => {
12
+ if (!inputValue) return options;
13
+ const lowerInput = inputValue.toLowerCase();
14
+ return options.filter((option) => {
15
+ const label = getOptionLabel(option).toLowerCase();
16
+ return label.includes(lowerInput);
17
+ });
18
+ },
19
+ }) => {
20
+ const [isOpen, setIsOpen] = useState(false);
21
+ const [inputValue, setInputValue] = useState("");
22
+ const [filteredOptions, setFilteredOptions] = useState(options);
23
+ const containerRef = useRef(null);
24
+ const inputRef = useRef(null);
25
+
26
+ // Seçili değerin label'ını bul
27
+ const selectedOption = options.find(
28
+ (opt) => getOptionValue(opt) === value
29
+ );
30
+ const displayValue = selectedOption
31
+ ? getOptionLabel(selectedOption)
32
+ : inputValue || placeholder;
33
+
34
+ // Input değiştiğinde filtrele
35
+ useEffect(() => {
36
+ if (isOpen) {
37
+ const filtered = filterOptions(options, inputValue);
38
+ setFilteredOptions(filtered);
39
+ } else {
40
+ setFilteredOptions(options);
41
+ }
42
+ }, [inputValue, isOpen, options, filterOptions]);
43
+
44
+ // Dışarı tıklandığında kapat
45
+ useEffect(() => {
46
+ const handleClickOutside = (event) => {
47
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
48
+ setIsOpen(false);
49
+ setInputValue("");
50
+ }
51
+ };
52
+
53
+ if (isOpen) {
54
+ document.addEventListener("mousedown", handleClickOutside);
55
+ return () => {
56
+ document.removeEventListener("mousedown", handleClickOutside);
57
+ };
58
+ }
59
+ }, [isOpen]);
60
+
61
+ const handleInputChange = (e) => {
62
+ const newValue = e.target.value;
63
+ setInputValue(newValue);
64
+ setIsOpen(true);
65
+ };
66
+
67
+ const handleSelect = (option) => {
68
+ const optionValue = getOptionValue(option);
69
+ onChange(optionValue, option);
70
+ setInputValue("");
71
+ setIsOpen(false);
72
+ };
73
+
74
+ const handleFocus = () => {
75
+ setIsOpen(true);
76
+ if (selectedOption) {
77
+ setInputValue(getOptionLabel(selectedOption));
78
+ }
79
+ };
80
+
81
+ const handleBlur = () => {
82
+ // Input blur olduğunda hemen kapatma, click outside ile kapatılacak
83
+ setTimeout(() => {
84
+ if (!containerRef.current?.contains(document.activeElement)) {
85
+ setIsOpen(false);
86
+ if (selectedOption) {
87
+ setInputValue("");
88
+ }
89
+ }
90
+ }, 200);
91
+ };
92
+
93
+ return (
94
+ <div className="autocomplete-select-container" ref={containerRef}>
95
+ <div
96
+ className={`autocomplete-select-input ${isOpen ? "open" : ""}`}
97
+ onClick={() => {
98
+ setIsOpen(!isOpen);
99
+ inputRef.current?.focus();
100
+ }}
101
+ >
102
+ <input
103
+ ref={inputRef}
104
+ type="text"
105
+ value={isOpen ? inputValue : displayValue}
106
+ onChange={handleInputChange}
107
+ onFocus={handleFocus}
108
+ onBlur={handleBlur}
109
+ placeholder={placeholder}
110
+ className="autocomplete-select-input-field"
111
+ />
112
+ <span className="autocomplete-select-arrow">
113
+ {isOpen ? "▲" : "▼"}
114
+ </span>
115
+ </div>
116
+
117
+ {isOpen && (
118
+ <div className="autocomplete-select-dropdown">
119
+ {filteredOptions.length > 0 ? (
120
+ filteredOptions.map((option, index) => {
121
+ const optionValue = getOptionValue(option);
122
+ const optionLabel = getOptionLabel(option);
123
+ const isSelected = optionValue === value;
124
+
125
+ return (
126
+ <div
127
+ key={index}
128
+ className={`autocomplete-select-option ${
129
+ isSelected ? "selected" : ""
130
+ }`}
131
+ onClick={() => handleSelect(option)}
132
+ onMouseDown={(e) => e.preventDefault()} // Blur'u engelle
133
+ >
134
+ {optionLabel}
135
+ </div>
136
+ );
137
+ })
138
+ ) : (
139
+ <div className="autocomplete-select-no-results">
140
+ Sonuç bulunamadı
141
+ </div>
142
+ )}
143
+ </div>
144
+ )}
145
+ </div>
146
+ );
147
+ };
148
+
149
+ export default AutocompleteSelect;
150
+
@@ -0,0 +1,149 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import './Timeline.css';
3
+
4
+ /**
5
+ * Context Menu Component
6
+ * Sağ tık menüsü için özelleştirilebilir menü bileşeni
7
+ */
8
+ const ContextMenu = ({
9
+ isOpen,
10
+ position,
11
+ onClose,
12
+ menuItems = [],
13
+ resource = null,
14
+ date = null,
15
+ }) => {
16
+ const menuRef = useRef(null);
17
+ const [adjustedPosition, setAdjustedPosition] = useState(position);
18
+
19
+ // Menü pozisyonunu mouse'a yakın tut ve ekran sınırları içinde tut
20
+ useEffect(() => {
21
+ if (!menuRef.current || !position || !isOpen) {
22
+ setAdjustedPosition(position);
23
+ return;
24
+ }
25
+
26
+ // Menü render edildikten sonra pozisyonu ayarla
27
+ const updatePosition = () => {
28
+ const menuRect = menuRef.current.getBoundingClientRect();
29
+ const viewportWidth = window.innerWidth;
30
+ const viewportHeight = window.innerHeight;
31
+
32
+ let adjustedX = position.x;
33
+ let adjustedY = position.y;
34
+
35
+ // Sağa taşma kontrolü
36
+ if (position.x + menuRect.width > viewportWidth) {
37
+ adjustedX = position.x - menuRect.width;
38
+ }
39
+
40
+ // Aşağıya taşma kontrolü
41
+ if (position.y + menuRect.height > viewportHeight) {
42
+ adjustedY = position.y - menuRect.height;
43
+ }
44
+
45
+ // Sola taşma kontrolü
46
+ if (adjustedX < 10) {
47
+ adjustedX = 10;
48
+ }
49
+
50
+ // Yukarıya taşma kontrolü
51
+ if (adjustedY < 10) {
52
+ adjustedY = 10;
53
+ }
54
+
55
+ setAdjustedPosition({ x: adjustedX, y: adjustedY });
56
+ };
57
+
58
+ // Menü render edildikten sonra pozisyonu güncelle
59
+ setTimeout(updatePosition, 0);
60
+ }, [position, isOpen]);
61
+
62
+ // Menü dışına tıklanınca kapat
63
+ useEffect(() => {
64
+ const handleClickOutside = (event) => {
65
+ if (menuRef.current && !menuRef.current.contains(event.target)) {
66
+ onClose();
67
+ }
68
+ };
69
+
70
+ const handleEscape = (event) => {
71
+ if (event.key === 'Escape') {
72
+ onClose();
73
+ }
74
+ };
75
+
76
+ if (isOpen) {
77
+ document.addEventListener('mousedown', handleClickOutside);
78
+ document.addEventListener('keydown', handleEscape);
79
+ // Scroll olduğunda menüyü kapat
80
+ document.addEventListener('scroll', onClose, true);
81
+ }
82
+
83
+ return () => {
84
+ document.removeEventListener('mousedown', handleClickOutside);
85
+ document.removeEventListener('keydown', handleEscape);
86
+ document.removeEventListener('scroll', onClose, true);
87
+ };
88
+ }, [isOpen, onClose]);
89
+
90
+ if (!isOpen || !position) return null;
91
+
92
+ const handleItemClick = (item) => {
93
+ if (item.onClick) {
94
+ item.onClick(resource, date);
95
+ }
96
+ if (item.closeOnClick !== false) {
97
+ onClose();
98
+ }
99
+ };
100
+
101
+ return (
102
+ <div
103
+ ref={menuRef}
104
+ className="context-menu"
105
+ style={{
106
+ position: 'fixed',
107
+ left: `${(adjustedPosition?.x ?? position.x) - 150}px`,
108
+ top: `${(adjustedPosition?.y ?? position.y) - 150}px`,
109
+ zIndex: 10005,
110
+ }}
111
+ >
112
+ <div className="context-menu-content">
113
+ {menuItems.length === 0 ? (
114
+ <div className="context-menu-item context-menu-item-disabled">
115
+ Menü öğesi yok
116
+ </div>
117
+ ) : (
118
+ menuItems.map((item, index) => {
119
+ if (item.separator) {
120
+ return <div key={`separator-${index}`} className="context-menu-separator" />;
121
+ }
122
+
123
+ if (item.hidden) {
124
+ return null;
125
+ }
126
+
127
+ return (
128
+ <div
129
+ key={item.id || index}
130
+ className={`context-menu-item ${item.disabled ? 'context-menu-item-disabled' : ''} ${item.danger ? 'context-menu-item-danger' : ''}`}
131
+ onClick={() => !item.disabled && handleItemClick(item)}
132
+ title={item.tooltip || item.label}
133
+ >
134
+ {item.icon && <span className="context-menu-item-icon">{item.icon}</span>}
135
+ <span className="context-menu-item-label">{item.label}</span>
136
+ {item.shortcut && (
137
+ <span className="context-menu-item-shortcut">{item.shortcut}</span>
138
+ )}
139
+ </div>
140
+ );
141
+ })
142
+ )}
143
+ </div>
144
+ </div>
145
+ );
146
+ };
147
+
148
+ export default ContextMenu;
149
+
@@ -0,0 +1,255 @@
1
+ import React, { useState, useRef, useEffect, useCallback } from 'react';
2
+ import './Timeline.css';
3
+
4
+ /**
5
+ * Daily View Component
6
+ * Seçili resource ve tarih için günlük saat bazlı timeline görünümü
7
+ */
8
+ const DailyView = ({
9
+ isOpen,
10
+ onClose,
11
+ resource,
12
+ date,
13
+ events = [],
14
+ onEventCreate,
15
+ onEventUpdate,
16
+ onEventDelete,
17
+ themeType = 'light',
18
+ }) => {
19
+ const [isCreating, setIsCreating] = useState(false);
20
+ const [tempEvent, setTempEvent] = useState(null);
21
+ const containerRef = useRef(null);
22
+ const timelineRef = useRef(null);
23
+
24
+ // Saatleri oluştur (0-23)
25
+ const hours = Array.from({ length: 24 }, (_, i) => i);
26
+
27
+ // O güne ait event'leri filtrele
28
+ const dayEvents = events.filter(event => {
29
+ if (!event.startDate || !date) return false;
30
+ const eventDate = new Date(event.startDate);
31
+ const selectedDate = new Date(date.fullDate || date);
32
+ return (
33
+ eventDate.getFullYear() === selectedDate.getFullYear() &&
34
+ eventDate.getMonth() === selectedDate.getMonth() &&
35
+ eventDate.getDate() === selectedDate.getDate() &&
36
+ event.resourceId === resource?.id
37
+ );
38
+ });
39
+
40
+ // Saat bazlı event pozisyonu hesapla
41
+ const getEventPosition = (event) => {
42
+ const startDate = new Date(event.startDate);
43
+ const endDate = new Date(event.endDate);
44
+ const startHour = startDate.getHours() + startDate.getMinutes() / 60;
45
+ const endHour = endDate.getHours() + endDate.getMinutes() / 60;
46
+ const duration = endHour - startHour;
47
+
48
+ return {
49
+ top: `${(startHour / 24) * 100}%`,
50
+ height: `${(duration / 24) * 100}%`,
51
+ };
52
+ };
53
+
54
+ // Timeline'a tıklandığında
55
+ const handleTimelineClick = (e) => {
56
+ if (!onEventCreate || !timelineRef.current) return;
57
+
58
+ const rect = timelineRef.current.getBoundingClientRect();
59
+ const clickedY = e.clientY - rect.top;
60
+ const timelineHeight = rect.height;
61
+ const totalMinutes = Math.max(0, Math.min((clickedY / timelineHeight) * (24 * 60), 24 * 60));
62
+
63
+ const startHour = Math.floor(totalMinutes / 60);
64
+ const startMinutes = Math.floor(totalMinutes % 60);
65
+
66
+ const startDate = new Date(date.fullDate || date);
67
+ startDate.setHours(startHour, startMinutes, 0, 0);
68
+
69
+ const endDate = new Date(startDate);
70
+ endDate.setTime(startDate.getTime() + 30 * 60 * 1000); // Varsayılan 30 dakika
71
+
72
+ setIsCreating(true);
73
+ setTempEvent({
74
+ startDate,
75
+ endDate,
76
+ });
77
+ };
78
+
79
+ // Mouse hareketi ile event oluşturma
80
+ const handleMouseMove = useCallback((e) => {
81
+ if (!isCreating || !tempEvent || !timelineRef.current) return;
82
+
83
+ const rect = timelineRef.current.getBoundingClientRect();
84
+ const mouseY = e.clientY - rect.top;
85
+ const timelineHeight = rect.height;
86
+ const totalMinutes = Math.max(0, Math.min((mouseY / timelineHeight) * (24 * 60), 24 * 60));
87
+
88
+ const endHour = Math.floor(totalMinutes / 60);
89
+ const endMinutes = Math.floor(totalMinutes % 60);
90
+
91
+ const newEndDate = new Date(tempEvent.startDate);
92
+ newEndDate.setHours(endHour, endMinutes, 0, 0);
93
+
94
+ // Bitiş saati başlangıçtan önce olamaz
95
+ if (newEndDate <= tempEvent.startDate) {
96
+ newEndDate.setTime(tempEvent.startDate.getTime() + 15 * 60 * 1000); // En az 15 dakika
97
+ }
98
+
99
+ setTempEvent(prev => ({
100
+ ...prev,
101
+ endDate: newEndDate,
102
+ }));
103
+ }, [isCreating, tempEvent]);
104
+
105
+ // Mouse bırakıldığında event oluştur
106
+ const handleMouseUp = useCallback(() => {
107
+ if (!isCreating || !tempEvent || !onEventCreate) return;
108
+
109
+ // Minimum süre kontrolü (en az 15 dakika)
110
+ const duration = tempEvent.endDate.getTime() - tempEvent.startDate.getTime();
111
+ if (duration < 15 * 60 * 1000) {
112
+ setIsCreating(false);
113
+ setTempEvent(null);
114
+ return; // Çok kısa, event oluşturma
115
+ }
116
+
117
+ const newEvent = {
118
+ id: `daily-${Date.now()}`,
119
+ title: 'Yeni Randevu',
120
+ startDate: tempEvent.startDate,
121
+ endDate: tempEvent.endDate,
122
+ resourceId: resource?.id,
123
+ isHourly: true, // Saatlik rezervasyon flag'i
124
+ };
125
+
126
+ onEventCreate(newEvent);
127
+ setIsCreating(false);
128
+ setTempEvent(null);
129
+ }, [isCreating, tempEvent, onEventCreate, resource]);
130
+
131
+ // Global mouse event listener'ları
132
+ useEffect(() => {
133
+ if (!isCreating) return;
134
+
135
+ document.addEventListener('mousemove', handleMouseMove);
136
+ document.addEventListener('mouseup', handleMouseUp);
137
+
138
+ return () => {
139
+ document.removeEventListener('mousemove', handleMouseMove);
140
+ document.removeEventListener('mouseup', handleMouseUp);
141
+ };
142
+ }, [isCreating, handleMouseMove, handleMouseUp]);
143
+
144
+ // Tarih formatı
145
+ const formatDate = (dateObj) => {
146
+ if (!dateObj) return '';
147
+ const d = new Date(dateObj.fullDate || dateObj);
148
+ return d.toLocaleDateString('tr-TR', {
149
+ weekday: 'long',
150
+ year: 'numeric',
151
+ month: 'long',
152
+ day: 'numeric',
153
+ });
154
+ };
155
+
156
+ // Saat formatı
157
+ const formatHour = (hour) => {
158
+ return `${hour.toString().padStart(2, '0')}:00`;
159
+ };
160
+
161
+ if (!isOpen || !resource || !date) return null;
162
+
163
+ return (
164
+ <div
165
+ className={`daily-view-overlay ${themeType === 'dark' ? 'dark-mode' : ''}`}
166
+ onClick={onClose}
167
+ >
168
+ <div
169
+ ref={containerRef}
170
+ className="daily-view-container"
171
+ onClick={(e) => e.stopPropagation()}
172
+ >
173
+ {/* Header */}
174
+ <div className="daily-view-header">
175
+ <div className="daily-view-header-content">
176
+ <h2 className="daily-view-title">{resource.name || resource.id}</h2>
177
+ <p className="daily-view-date">{formatDate(date)}</p>
178
+ </div>
179
+ <button className="daily-view-close" onClick={onClose}>
180
+
181
+ </button>
182
+ </div>
183
+
184
+ {/* Timeline Body */}
185
+ <div className="daily-view-body">
186
+ {/* Saatler (Sol Taraf) */}
187
+ <div className="daily-view-hours">
188
+ {hours.map(hour => (
189
+ <div key={hour} className="daily-view-hour-label">
190
+ {formatHour(hour)}
191
+ </div>
192
+ ))}
193
+ </div>
194
+
195
+ {/* Timeline Content */}
196
+ <div
197
+ ref={timelineRef}
198
+ className="daily-view-timeline"
199
+ onClick={handleTimelineClick}
200
+ >
201
+ {/* Saat hücreleri */}
202
+ {hours.map(hour => (
203
+ <div
204
+ key={hour}
205
+ className="daily-view-hour-cell"
206
+ />
207
+ ))}
208
+
209
+ {/* Event'ler (timeline üzerinde absolute position) */}
210
+ {dayEvents.map(event => {
211
+ const position = getEventPosition(event);
212
+ return (
213
+ <div
214
+ key={event.id}
215
+ className="daily-view-event"
216
+ style={position}
217
+ onClick={(e) => {
218
+ e.stopPropagation();
219
+ // Event detayları göster
220
+ }}
221
+ >
222
+ <span className="daily-view-event-title">{event.title}</span>
223
+ <span className="daily-view-event-time">
224
+ {new Date(event.startDate).toLocaleTimeString('tr-TR', {
225
+ hour: '2-digit',
226
+ minute: '2-digit'
227
+ })} - {new Date(event.endDate).toLocaleTimeString('tr-TR', {
228
+ hour: '2-digit',
229
+ minute: '2-digit'
230
+ })}
231
+ </span>
232
+ </div>
233
+ );
234
+ })}
235
+
236
+ {/* Geçici event (oluşturuluyor) */}
237
+ {isCreating && tempEvent && (
238
+ <div
239
+ className="daily-view-temp-event"
240
+ style={getEventPosition({
241
+ startDate: tempEvent.startDate,
242
+ endDate: tempEvent.endDate,
243
+ })}
244
+ >
245
+ Yeni Randevu
246
+ </div>
247
+ )}
248
+ </div>
249
+ </div>
250
+ </div>
251
+ </div>
252
+ );
253
+ };
254
+
255
+ export default DailyView;
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+
3
+ const DatePickerComponent = ({ onDateSelect }) => {
4
+ return (
5
+ <input
6
+ type="date"
7
+ onChange={(e) => onDateSelect(new Date(e.target.value))}
8
+ className="master-header-date-picker"
9
+ />
10
+ );
11
+ };
12
+
13
+ export default DatePickerComponent;
@@ -1,35 +1,35 @@
1
- /**
2
- * "dd/mm/yyyy" formatındaki bir tarih string'ini Date objesine dönüştürür.
3
- * Eğer dateInput bir string değilse, direkt Date objesini döndürür.
4
- * @param {string | Object | Date} dateInput - "dd/mm/yyyy" formatında tarih stringi veya {fullDate: Date, display: string} objesi veya Date objesi.
5
- * @returns {Date} - Date objesi.
6
- */
7
- export const parseDate = (dateInput) => {
8
- if (dateInput instanceof Date) {
9
- return dateInput;
10
- }
11
- if (typeof dateInput === 'string') {
12
- const [day, month, year] = dateInput.split("/").map(Number);
13
- return new Date(year, month - 1, day);
14
- } else if (typeof dateInput === 'object' && dateInput.fullDate instanceof Date) {
15
- return new Date(dateInput.fullDate);
16
- }
17
- else {
18
- console.error("parseDate received invalid input:", dateInput);
19
- return new Date(); // veya hata fırlat
20
- }
21
- };
22
-
23
- /**
24
- * Bir tarihin belirli bir aralık içinde olup olmadığını kontrol eder.
25
- * @param {string | Object | Date} date - "dd/mm/yyyy" formatında tarih stringi, {fullDate: Date, display: string} objesi veya Date objesi.
26
- * @param {string | Object | Date} startDate - "dd/mm/yyyy" formatında başlangıç tarihi stringi, {fullDate: Date, display: string} objesi veya Date objesi.
27
- * @param {string | Object | Date} endDate - "dd/mm/yyyy" formatında bitiş tarihi stringi, {fullDate: Date, display: string} objesi veya Date objesi.
28
- * @returns {boolean} - Tarih aralık içinde ise true, değilse false.
29
- */
30
- export const isDateInRange = (date, startDate, endDate) => {
31
- const d = parseDate(date);
32
- const start = parseDate(startDate);
33
- const end = parseDate(endDate);
34
- return d >= start && d <= end;
1
+ /**
2
+ * "dd/mm/yyyy" formatındaki bir tarih string'ini Date objesine dönüştürür.
3
+ * Eğer dateInput bir string değilse, direkt Date objesini döndürür.
4
+ * @param {string | Object | Date} dateInput - "dd/mm/yyyy" formatında tarih stringi veya {fullDate: Date, display: string} objesi veya Date objesi.
5
+ * @returns {Date} - Date objesi.
6
+ */
7
+ export const parseDate = (dateInput) => {
8
+ if (dateInput instanceof Date) {
9
+ return dateInput;
10
+ }
11
+ if (typeof dateInput === 'string') {
12
+ const [day, month, year] = dateInput.split("/").map(Number);
13
+ return new Date(year, month - 1, day);
14
+ } else if (typeof dateInput === 'object' && dateInput.fullDate instanceof Date) {
15
+ return new Date(dateInput.fullDate);
16
+ }
17
+ else {
18
+ console.error("parseDate received invalid input:", dateInput);
19
+ return new Date(); // veya hata fırlat
20
+ }
21
+ };
22
+
23
+ /**
24
+ * Bir tarihin belirli bir aralık içinde olup olmadığını kontrol eder.
25
+ * @param {string | Object | Date} date - "dd/mm/yyyy" formatında tarih stringi, {fullDate: Date, display: string} objesi veya Date objesi.
26
+ * @param {string | Object | Date} startDate - "dd/mm/yyyy" formatında başlangıç tarihi stringi, {fullDate: Date, display: string} objesi veya Date objesi.
27
+ * @param {string | Object | Date} endDate - "dd/mm/yyyy" formatında bitiş tarihi stringi, {fullDate: Date, display: string} objesi veya Date objesi.
28
+ * @returns {boolean} - Tarih aralık içinde ise true, değilse false.
29
+ */
30
+ export const isDateInRange = (date, startDate, endDate) => {
31
+ const d = parseDate(date);
32
+ const start = parseDate(startDate);
33
+ const end = parseDate(endDate);
34
+ return d >= start && d <= end;
35
35
  };
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import './Timeline.css';
3
+
4
+ /**
5
+ * Event Badge Component
6
+ * Önemli event'ler için badge gösterir
7
+ */
8
+ const EventBadge = ({
9
+ text,
10
+ type = 'default', // 'default', 'important', 'urgent', 'new', 'custom'
11
+ position = 'top-right', // 'top-right', 'top-left', 'bottom-right', 'bottom-left'
12
+ className = '',
13
+ style = {}
14
+ }) => {
15
+ return (
16
+ <span
17
+ className={`event-badge event-badge-${type} event-badge-${position} ${className}`}
18
+ style={style}
19
+ >
20
+ {text}
21
+ </span>
22
+ );
23
+ };
24
+
25
+ export default EventBadge;
26
+