akfatimeline 1.2.0 → 2.0.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 (35) hide show
  1. package/dist/Timeline.js +16 -48
  2. package/{src/components/Timeline/DailyView.js → dist/components/Timeline/DailyView.jsx} +1 -0
  3. package/{src/components/Timeline/EventTooltip.js → dist/components/Timeline/EventTooltip.jsx} +207 -206
  4. package/{src/components/Timeline/Indicator.js → dist/components/Timeline/Indicator.jsx} +27 -26
  5. package/{src/components/Timeline/MasterHeader.js → dist/components/Timeline/MasterHeader.jsx} +105 -104
  6. package/{src/components/Timeline/Resources.js → dist/components/Timeline/Resources.jsx} +54 -53
  7. package/{src/components/Timeline/ResourcesHeader.js → dist/components/Timeline/ResourcesHeader.jsx} +15 -14
  8. package/{src/components/Timeline/Timeline.js → dist/components/Timeline/Timeline.jsx} +572 -607
  9. package/{src/components/Timeline/TimelineContent.js → dist/components/Timeline/TimelineContent.jsx} +837 -838
  10. package/{src/components/Timeline/TimelineHeader.js → dist/components/Timeline/TimelineHeader.jsx} +55 -54
  11. package/dist/components/Timeline/TimelineMonthContainer.js +2 -2
  12. package/package.json +25 -25
  13. package/src/components/Timeline/AutocompleteSelect.jsx +150 -0
  14. package/src/components/Timeline/ContextMenu.jsx +149 -0
  15. package/src/components/Timeline/DailyView.jsx +256 -0
  16. package/src/components/Timeline/EventBadge.jsx +26 -0
  17. package/src/components/Timeline/EventDetailModal.jsx +138 -0
  18. package/src/components/Timeline/EventIcon.jsx +47 -0
  19. package/src/components/Timeline/EventTooltip.jsx +207 -0
  20. package/src/components/Timeline/Indicator.jsx +27 -0
  21. package/src/components/Timeline/LoadingSpinner.jsx +48 -0
  22. package/src/components/Timeline/MasterHeader.jsx +105 -0
  23. package/src/components/Timeline/Resources.jsx +54 -0
  24. package/src/components/Timeline/ResourcesHeader.jsx +15 -0
  25. package/src/components/Timeline/Timeline.jsx +572 -0
  26. package/src/components/Timeline/TimelineContent.jsx +837 -0
  27. package/src/components/Timeline/TimelineHeader.jsx +55 -0
  28. package/src/components/Timeline/TimelineMonthContainer.js +2 -2
  29. package/src/library.js +8 -8
  30. /package/{src/components/Timeline/AutocompleteSelect.js → dist/components/Timeline/AutocompleteSelect.jsx} +0 -0
  31. /package/{src/components/Timeline/ContextMenu.js → dist/components/Timeline/ContextMenu.jsx} +0 -0
  32. /package/{src/components/Timeline/EventBadge.js → dist/components/Timeline/EventBadge.jsx} +0 -0
  33. /package/{src/components/Timeline/EventDetailModal.js → dist/components/Timeline/EventDetailModal.jsx} +0 -0
  34. /package/{src/components/Timeline/EventIcon.js → dist/components/Timeline/EventIcon.jsx} +0 -0
  35. /package/{src/components/Timeline/LoadingSpinner.js → dist/components/Timeline/LoadingSpinner.jsx} +0 -0
@@ -0,0 +1,256 @@
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;
256
+
@@ -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
+
@@ -0,0 +1,138 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import './Timeline.css';
3
+
4
+ const EventDetailModal = ({
5
+ event,
6
+ isOpen,
7
+ onClose,
8
+ onSave,
9
+ onDelete,
10
+ resources = [],
11
+ }) => {
12
+ const [formData, setFormData] = useState({
13
+ title: '',
14
+ startDate: '',
15
+ endDate: '',
16
+ resourceId: '',
17
+ ...event,
18
+ });
19
+
20
+ useEffect(() => {
21
+ if (event) {
22
+ setFormData({
23
+ title: event.title || '',
24
+ startDate: event.startDate
25
+ ? new Date(event.startDate).toISOString().split('T')[0]
26
+ : '',
27
+ endDate: event.endDate
28
+ ? new Date(event.endDate).toISOString().split('T')[0]
29
+ : '',
30
+ resourceId: event.resourceId || '',
31
+ ...event,
32
+ });
33
+ }
34
+ }, [event]);
35
+
36
+ if (!isOpen || !event) return null;
37
+
38
+ const handleSubmit = (e) => {
39
+ e.preventDefault();
40
+ if (onSave) {
41
+ const updatedEvent = {
42
+ ...event,
43
+ ...formData,
44
+ startDate: new Date(formData.startDate),
45
+ endDate: new Date(formData.endDate),
46
+ };
47
+ onSave(updatedEvent);
48
+ }
49
+ onClose();
50
+ };
51
+
52
+ const handleDelete = () => {
53
+ if (onDelete && window.confirm('Bu event\'i silmek istediğinize emin misiniz?')) {
54
+ onDelete(event.id);
55
+ onClose();
56
+ }
57
+ };
58
+
59
+ return (
60
+ <div className="modal-overlay" onClick={onClose}>
61
+ <div className="modal-content" onClick={(e) => e.stopPropagation()}>
62
+ <div className="modal-header">
63
+ <h2>Event Düzenle</h2>
64
+ <button className="modal-close-btn" onClick={onClose}>
65
+ ×
66
+ </button>
67
+ </div>
68
+
69
+ <form onSubmit={handleSubmit} className="modal-form">
70
+ <div className="form-group">
71
+ <label>Başlık</label>
72
+ <input
73
+ type="text"
74
+ value={formData.title}
75
+ onChange={(e) => setFormData({ ...formData, title: e.target.value })}
76
+ required
77
+ />
78
+ </div>
79
+
80
+ <div className="form-group">
81
+ <label>Resource</label>
82
+ <select
83
+ value={formData.resourceId}
84
+ onChange={(e) => setFormData({ ...formData, resourceId: e.target.value })}
85
+ required
86
+ >
87
+ <option value="">Seçiniz...</option>
88
+ {resources.map((resource) => (
89
+ <option key={resource.id} value={resource.id}>
90
+ {resource.name}
91
+ </option>
92
+ ))}
93
+ </select>
94
+ </div>
95
+
96
+ <div className="form-row">
97
+ <div className="form-group">
98
+ <label>Başlangıç Tarihi</label>
99
+ <input
100
+ type="date"
101
+ value={formData.startDate}
102
+ onChange={(e) => setFormData({ ...formData, startDate: e.target.value })}
103
+ required
104
+ />
105
+ </div>
106
+
107
+ <div className="form-group">
108
+ <label>Bitiş Tarihi</label>
109
+ <input
110
+ type="date"
111
+ value={formData.endDate}
112
+ onChange={(e) => setFormData({ ...formData, endDate: e.target.value })}
113
+ required
114
+ />
115
+ </div>
116
+ </div>
117
+
118
+ <div className="modal-actions">
119
+ <button type="button" className="btn-delete" onClick={handleDelete}>
120
+ Sil
121
+ </button>
122
+ <div>
123
+ <button type="button" className="btn-cancel" onClick={onClose}>
124
+ İptal
125
+ </button>
126
+ <button type="submit" className="btn-save">
127
+ Kaydet
128
+ </button>
129
+ </div>
130
+ </div>
131
+ </form>
132
+ </div>
133
+ </div>
134
+ );
135
+ };
136
+
137
+ export default EventDetailModal;
138
+
@@ -0,0 +1,47 @@
1
+ import React from 'react';
2
+ import './Timeline.css';
3
+
4
+ /**
5
+ * Event Icon Component
6
+ * Event'lerde gösterilecek ikonları render eder
7
+ */
8
+ const EventIcon = ({ type, className = '' }) => {
9
+ const getIconContent = () => {
10
+ switch (type) {
11
+ case 'balance-warning':
12
+ return '⚠️'; // Bakiye uyarısı
13
+ case 'important-note':
14
+ return '📝'; // Önemli not
15
+ case 'payment-pending':
16
+ return '💳'; // Ödeme bekliyor
17
+ case 'confirmed':
18
+ return '✅'; // Onaylandı
19
+ case 'cancelled':
20
+ return '❌'; // İptal edildi
21
+ case 'pending':
22
+ return '⏳'; // Beklemede
23
+ case 'completed':
24
+ return '✓'; // Tamamlandı
25
+ case 'in-progress':
26
+ return '▶️'; // Devam ediyor
27
+ case 'alert':
28
+ return '🔔'; // Uyarı
29
+ case 'info':
30
+ return 'ℹ️'; // Bilgi
31
+ default:
32
+ return null;
33
+ }
34
+ };
35
+
36
+ const iconContent = getIconContent();
37
+ if (!iconContent) return null;
38
+
39
+ return (
40
+ <span className={`event-icon event-icon-${type} ${className}`}>
41
+ {iconContent}
42
+ </span>
43
+ );
44
+ };
45
+
46
+ export default EventIcon;
47
+
@@ -0,0 +1,207 @@
1
+ // src/components/Timeline/EventTooltip.jsx
2
+ import React from "react";
3
+
4
+ const EventTooltip = ({ event, position = { top: 0, left: 0 }, onClose, onEdit, onDelete }) => {
5
+ if (!event) return null;
6
+
7
+ const { top, left } = position;
8
+
9
+ // Rezervasyon durumuna göre renk belirleme
10
+ const getStatusColor = (status) => {
11
+ switch (status) {
12
+ case "Confirmed":
13
+ return "#4caf50"; // Yeşil
14
+ case "Pending":
15
+ return "#ff9800"; // Turuncu
16
+ case "Cancelled":
17
+ return "#f44336"; // Kırmızı
18
+ case "Completed":
19
+ return "#2196f3"; // Mavi
20
+ default:
21
+ return "#9e9e9e"; // Gri
22
+ }
23
+ };
24
+
25
+ const statusColor = getStatusColor(event.status);
26
+
27
+ return (
28
+ <div
29
+ style={{
30
+ position: "absolute",
31
+ top: top - 200, // Tooltip'in biraz yukarıda görünmesi için
32
+ left: left + 70,
33
+ transform: "translateX(-50%)",
34
+ backgroundColor: "#ffffff",
35
+ color: "#333333",
36
+ borderRadius: "10px",
37
+ boxShadow: "0 8px 16px rgba(0, 0, 0, 0.2)",
38
+ fontSize: "16px",
39
+ zIndex: 1000,
40
+ pointerEvents: "auto", // Tooltip'in tıklanabilir olmasını sağlar
41
+ whiteSpace: "normal",
42
+ maxWidth: "400px",
43
+ width: "100%",
44
+ transition: "opacity 0.3s ease, transform 0.3s ease",
45
+ }}
46
+ >
47
+ {/* Kapatma Butonu */}
48
+ {onClose && (
49
+ <button
50
+ onClick={onClose}
51
+ style={{
52
+ position: "absolute",
53
+ top: "10px",
54
+ right: "15px",
55
+ background: "transparent",
56
+ border: "none",
57
+ color: "#aaa",
58
+ fontSize: "24px",
59
+ cursor: "pointer",
60
+ transition: "color 0.2s",
61
+ }}
62
+ aria-label="Kapat"
63
+ onMouseOver={(e) => (e.target.style.color = "#000")}
64
+ onMouseOut={(e) => (e.target.style.color = "#aaa")}
65
+ >
66
+ &times;
67
+ </button>
68
+ )}
69
+
70
+ {/* Header */}
71
+ <div
72
+ style={{
73
+ backgroundColor: statusColor,
74
+ color: "#ffffff",
75
+ padding: "15px 20px",
76
+ borderTopLeftRadius: "10px",
77
+ borderTopRightRadius: "10px",
78
+ display: "flex",
79
+ flexDirection: "column",
80
+ gap: "5px",
81
+ }}
82
+ >
83
+ <div style={{ fontWeight: "bold", fontSize: "18px" }}>{event.title}</div>
84
+ <div style={{ fontSize: "14px" }}>Rezervasyon ID: {event.reservationId}</div>
85
+ </div>
86
+
87
+ {/* İçerik */}
88
+ <div style={{ padding: "20px", display: "flex", flexDirection: "column", gap: "15px" }}>
89
+ {/* Misafirler */}
90
+ {Array.isArray(event.guestNames) && (
91
+ <div>
92
+ <strong>Misafirler:</strong> {event.guestNames.join(", ")}
93
+ </div>
94
+ )}
95
+
96
+ {/* Giriş ve Çıkış Tarihleri */}
97
+ <div style={{ display: "flex", justifyContent: "space-between", marginBottom: "10px" }}>
98
+ <div>
99
+ <strong>Giriş:</strong> {new Date(event.startDate).toLocaleDateString()}
100
+ </div>
101
+ <div>
102
+ <strong>Çıkış:</strong> {new Date(event.endDate).toLocaleDateString()}
103
+ </div>
104
+ </div>
105
+
106
+ {/* Ödeme Bilgileri */}
107
+ {(event.totalAmount !== undefined || event.amountPaid !== undefined) && (
108
+ <div style={{ display: "flex", justifyContent: "space-between", marginBottom: "10px" }}>
109
+ {event.amountPaid !== undefined && (
110
+ <div>
111
+ <strong>Ödenen Miktar:</strong> ${event.amountPaid.toFixed(2)}
112
+ </div>
113
+ )}
114
+ {event.totalAmount !== undefined && (
115
+ <div>
116
+ <strong>Toplam Borç:</strong> ${event.totalAmount.toFixed(2)}
117
+ </div>
118
+ )}
119
+ </div>
120
+ )}
121
+
122
+ {/* Rezervasyon Durumu */}
123
+ {event.status && (
124
+ <div>
125
+ <strong>Durum:</strong> {event.status}
126
+ </div>
127
+ )}
128
+
129
+ {/* Rezervasyon Notu */}
130
+ {event.note && (
131
+ <div>
132
+ <strong>Not:</strong> {event.note}
133
+ </div>
134
+ )}
135
+ </div>
136
+
137
+
138
+ {/* Footer */}
139
+ <div
140
+ style={{
141
+ padding: "15px 20px",
142
+ borderTop: "1px solid #ddd",
143
+ display: "flex",
144
+ justifyContent: "flex-end",
145
+ gap: "10px",
146
+ borderBottomLeftRadius: "10px",
147
+ borderBottomRightRadius: "10px",
148
+ }}
149
+ >
150
+ {/* Düzenle Butonu */}
151
+ {onEdit && (
152
+ <button
153
+ onClick={() => onEdit(event)}
154
+ style={{
155
+ padding: "8px 16px",
156
+ backgroundColor: "#2196f3",
157
+ color: "#ffffff",
158
+ border: "none",
159
+ borderRadius: "4px",
160
+ cursor: "pointer",
161
+ fontSize: "14px",
162
+ display: "flex",
163
+ alignItems: "center",
164
+ gap: "5px",
165
+ transition: "background-color 0.2s",
166
+ }}
167
+ onMouseOver={(e) => (e.target.style.backgroundColor = "#1976d2")}
168
+ onMouseOut={(e) => (e.target.style.backgroundColor = "#2196f3")}
169
+ >
170
+ {/* Düzenle İkonu */}
171
+ <span role="img" aria-label="Düzenle">✏️</span>
172
+ Düzenle
173
+ </button>
174
+ )}
175
+
176
+ {/* Sil Butonu */}
177
+ {onDelete && (
178
+ <button
179
+ onClick={() => onDelete(event.id)}
180
+ style={{
181
+ padding: "8px 16px",
182
+ backgroundColor: "#f44336",
183
+ color: "#ffffff",
184
+ border: "none",
185
+ borderRadius: "4px",
186
+ cursor: "pointer",
187
+ fontSize: "14px",
188
+ display: "flex",
189
+ alignItems: "center",
190
+ gap: "5px",
191
+ transition: "background-color 0.2s",
192
+ }}
193
+ onMouseOver={(e) => (e.target.style.backgroundColor = "#d32f2f")}
194
+ onMouseOut={(e) => (e.target.style.backgroundColor = "#f44336")}
195
+ >
196
+ {/* Sil İkonu */}
197
+ <span role="img" aria-label="Sil">🗑️</span>
198
+ Sil
199
+ </button>
200
+ )}
201
+ </div>
202
+ </div>
203
+ );
204
+ };
205
+
206
+ export default EventTooltip;
207
+
@@ -0,0 +1,27 @@
1
+ import React from "react";
2
+
3
+ const Indicator = ({ todayIndex, totalDays }) => {
4
+ if (todayIndex < 0 || todayIndex >= totalDays) {
5
+ return null; // Bugün timeline dışında ise çizgiyi gösterme
6
+ }
7
+
8
+ return (
9
+ <div
10
+ style={{
11
+ position: "absolute",
12
+ top: 0,
13
+ left: `calc(${(todayIndex + 0.5) / totalDays} * 100%)`, // Günün ortasına yerleştirmek için +0.5
14
+ width: "2px",
15
+ height: "100%",
16
+ backgroundColor: "transparent",
17
+ zIndex: 5,
18
+ borderStyle: "dashed", // Kesikli çizgi için
19
+ borderWidth: "0 0 0 2px", // Sadece sol tarafa kesikli çizgi
20
+ borderColor: "red",
21
+ }}
22
+ ></div>
23
+ );
24
+ };
25
+
26
+ export default Indicator;
27
+