akfatimeline 2.2.2 → 2.2.4

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.
package/dist/Timeline.js CHANGED
@@ -733,6 +733,23 @@ ___CSS_LOADER_EXPORT___.push([module.id, `/* AkfaTimeline - Glassmorphism Theme
733
733
  box-shadow: var(--shadow-md), 0 0 0 3px var(--accent-light);
734
734
  }
735
735
 
736
+ /* Seçili custom button stili - sadece border parlar, arka plan olmaz */
737
+ .master-header-btn-active {
738
+ background: transparent !important;
739
+ backdrop-filter: none !important;
740
+ -webkit-backdrop-filter: none !important;
741
+ border: 2px solid var(--accent-color, #0ea5e9) !important;
742
+ box-shadow: 0 0 10px rgba(14, 165, 233, 0.5), 0 0 20px rgba(14, 165, 233, 0.3) !important;
743
+ color: var(--text-primary) !important;
744
+ }
745
+
746
+ .master-header-btn-active:hover {
747
+ background: transparent !important;
748
+ border-color: var(--accent-color, #0ea5e9) !important;
749
+ box-shadow: 0 0 15px rgba(14, 165, 233, 0.7), 0 0 25px rgba(14, 165, 233, 0.4) !important;
750
+ transform: translateY(-2px);
751
+ }
752
+
736
753
  .master-header-date-picker {
737
754
  background: var(--bg-secondary);
738
755
  backdrop-filter: var(--blur-sm);
@@ -3161,7 +3178,7 @@ const MasterHeader = _ref => {
3161
3178
  onClick: onToday
3162
3179
  }, "Bug\xFCn")), customButtons && customButtons.length > 0 && customButtons.map(button => /*#__PURE__*/external_react_default().createElement("button", {
3163
3180
  key: button.id,
3164
- className: button.className || "master-header-btn",
3181
+ className: button.className ? "master-header-btn ".concat(button.className) : "master-header-btn",
3165
3182
  onClick: button.onClick,
3166
3183
  disabled: button.disabled,
3167
3184
  title: button.tooltip || button.label
@@ -3358,6 +3375,41 @@ const isDateDisabled = (date, disableDates) => {
3358
3375
  }
3359
3376
  return false;
3360
3377
  };
3378
+
3379
+ /**
3380
+ * Bir tarihin hangi açık range'e ait olduğunu bulur (mode: 'include' için)
3381
+ * @param {string | Object | Date} date - Kontrol edilecek tarih
3382
+ * @param {Object} disableDates - { mode: 'include', dates: [], ranges: [] }
3383
+ * @returns {Object | null} - { start: Date, end: Date } veya null
3384
+ */
3385
+ const findEnabledRangeForDate = (date, disableDates) => {
3386
+ if (!disableDates || !disableDates.mode || disableDates.mode !== 'include') {
3387
+ return null; // Sadece 'include' modu için çalışır
3388
+ }
3389
+ const dateObj = parseDate(date);
3390
+ const dateOnly = new Date(dateObj.getFullYear(), dateObj.getMonth(), dateObj.getDate());
3391
+ const {
3392
+ ranges = []
3393
+ } = disableDates;
3394
+
3395
+ // Tarihin hangi range'e ait olduğunu bul
3396
+ for (const range of ranges) {
3397
+ const start = parseDate(range.start);
3398
+ const end = parseDate(range.end);
3399
+ const startOnly = new Date(start.getFullYear(), start.getMonth(), start.getDate());
3400
+ const endOnly = new Date(end.getFullYear(), end.getMonth(), end.getDate());
3401
+ if (dateOnly >= startOnly && dateOnly <= endOnly) {
3402
+ // Bu range'e ait, range'in tamamını döndür
3403
+ return {
3404
+ start: startOnly,
3405
+ end: endOnly
3406
+ };
3407
+ }
3408
+ }
3409
+
3410
+ // Range bulunamadı, null döndür
3411
+ return null;
3412
+ };
3361
3413
  ;// ./src/components/Timeline/TimelineHeader.jsx
3362
3414
 
3363
3415
  // CSS dosyasını import etmeyi unutma
@@ -4082,38 +4134,102 @@ const TimelineContent = _ref => {
4082
4134
  if (e.button === 2 || e.which === 3) {
4083
4135
  return;
4084
4136
  }
4085
- const startDate = parseDate(date.fullDate);
4137
+ const clickedDate = parseDate(date.fullDate);
4086
4138
 
4087
4139
  // Disabled tarih kontrolü - disabled hücrelerde event oluşturmayı engelle
4088
- if (disableDates && isDateDisabled(startDate, disableDates)) {
4140
+ if (disableDates && isDateDisabled(clickedDate, disableDates)) {
4089
4141
  return;
4090
4142
  }
4091
4143
 
4092
4144
  // Geçmiş tarih kontrolü
4093
4145
  if (preventPastEvents && preventPastEventsDate) {
4094
4146
  const preventPastEventsDateObj = parseDate(preventPastEventsDate);
4095
- // Sadece tarih karşılaştırması (saat bilgisi olmadan)
4096
- const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
4147
+ const clickedDateOnly = new Date(clickedDate.getFullYear(), clickedDate.getMonth(), clickedDate.getDate());
4097
4148
  const preventPastEventsDateOnly = new Date(preventPastEventsDateObj.getFullYear(), preventPastEventsDateObj.getMonth(), preventPastEventsDateObj.getDate());
4098
- if (startDateOnly < preventPastEventsDateOnly) {
4149
+ if (clickedDateOnly < preventPastEventsDateOnly) {
4099
4150
  // Geçmiş tarihe tıklama engellendi
4100
4151
  return;
4101
4152
  }
4102
4153
  }
4154
+
4155
+ // Eğer disableDates mode: 'include' ise, tıklanan tarihin range'ini veya date'ini bul
4156
+ let startDate = clickedDate;
4157
+ let endDate = new Date(clickedDate.getTime() + 24 * 60 * 60 * 1000); // Varsayılan: 1 gün
4158
+ let enabledRange = null;
4159
+ if (disableDates && disableDates.mode === 'include') {
4160
+ // Önce ranges'te ara
4161
+ if (disableDates.ranges && disableDates.ranges.length > 0) {
4162
+ enabledRange = findEnabledRangeForDate(clickedDate, disableDates);
4163
+ if (enabledRange) {
4164
+ // Range bulundu, range'in tamamını seç
4165
+ startDate = enabledRange.start;
4166
+ // endDate'i direkt range'in end'i olarak kullan
4167
+ // Range'in end'i zaten son günü temsil ediyor (inclusive)
4168
+ endDate = enabledRange.end;
4169
+ }
4170
+ }
4171
+
4172
+ // Eğer range bulunamadıysa, dates array'inde tek tek tarih var mı kontrol et
4173
+ if (!enabledRange && disableDates.dates && disableDates.dates.length > 0) {
4174
+ const clickedDateOnly = new Date(clickedDate.getFullYear(), clickedDate.getMonth(), clickedDate.getDate());
4175
+ const foundDate = disableDates.dates.find(d => {
4176
+ const dObj = parseDate(d);
4177
+ const dOnly = new Date(dObj.getFullYear(), dObj.getMonth(), dObj.getDate());
4178
+ return dOnly.getTime() === clickedDateOnly.getTime();
4179
+ });
4180
+ if (foundDate) {
4181
+ // Tek bir tarih bulundu, o tarihi seç (1 günlük event)
4182
+ const foundDateObj = parseDate(foundDate);
4183
+ startDate = new Date(foundDateObj.getFullYear(), foundDateObj.getMonth(), foundDateObj.getDate());
4184
+ endDate = new Date(startDate.getTime() + 24 * 60 * 60 * 1000); // 1 gün sonrası
4185
+ enabledRange = {
4186
+ start: startDate,
4187
+ end: startDate
4188
+ }; // Tek gün için range oluştur
4189
+ }
4190
+ }
4191
+ }
4192
+
4193
+ // Event title'ını gün sayısına göre ayarla
4194
+ const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
4195
+ const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
4196
+ // Gün farkını hesapla (gece sayısı = gün farkı)
4197
+ // Örnek: 31 Aralık - 5 Ocak = 5 gece (31-1, 1-2, 2-3, 3-4, 4-5)
4198
+ const daysDiff = Math.round((endDateOnly.getTime() - startDateOnly.getTime()) / (24 * 60 * 60 * 1000));
4199
+ const eventTitle = daysDiff > 0 ? "".concat(daysDiff, " Gece") : "1 Gece";
4200
+
4201
+ // Event'i oluştur - range'in tamamı seçilmiş olacak
4103
4202
  const newEvent = {
4104
4203
  id: Date.now(),
4105
- title: "1 Gece",
4204
+ title: eventTitle,
4106
4205
  startDate,
4107
- endDate: new Date(startDate.getTime() + 24 * 60 * 60 * 1000),
4206
+ endDate,
4108
4207
  resourceId,
4109
- // Mouse başlangıç pozisyonunu kaydet
4208
+ // Mouse başlangıç pozisyonunu kaydet (sürükle-bırak devre dışı olacak)
4110
4209
  startX: (e === null || e === void 0 ? void 0 : e.clientX) || 0,
4111
- startCellIndex: dates.findIndex(d => parseDate(d.fullDate).toDateString() === startDate.toDateString()),
4112
- // color => var(--timeline-new-event-background-color) => => Sonra inline style yerine className
4113
- color: "" // Bunu .css'te "var(--timeline-new-event-background-color)" atayabilirsin
4210
+ startCellIndex: dates.findIndex(d => {
4211
+ const dDate = parseDate(d.fullDate);
4212
+ const dDateOnly = new Date(dDate.getFullYear(), dDate.getMonth(), dDate.getDate());
4213
+ const startDateOnlyCheck = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
4214
+ return dDateOnly.getTime() === startDateOnlyCheck.getTime();
4215
+ }),
4216
+ color: ""
4114
4217
  };
4115
- setTempEvent(newEvent);
4116
- setIsCreating(true);
4218
+
4219
+ // Event'i direkt oluştur (sürükle-bırak olmadan)
4220
+ if (enabledRange) {
4221
+ // Range seçildi, direkt event oluştur (sürükle-bırak devre dışı)
4222
+ setEvents(prev => [...prev, newEvent]);
4223
+
4224
+ // Callback'i çağır
4225
+ if (onCreateEventInfo) {
4226
+ onCreateEventInfo(newEvent);
4227
+ }
4228
+ } else {
4229
+ // Range bulunamadı, eski davranış (sürükle-bırak ile seçim)
4230
+ setTempEvent(newEvent);
4231
+ setIsCreating(true);
4232
+ }
4117
4233
  };
4118
4234
  (0,external_react_.useEffect)(() => {
4119
4235
  if (!createNewEventOn) return;
@@ -66,7 +66,7 @@ const MasterHeader = ({
66
66
  {customButtons && customButtons.length > 0 && customButtons.map((button) => (
67
67
  <button
68
68
  key={button.id}
69
- className={button.className || "master-header-btn"}
69
+ className={button.className ? `master-header-btn ${button.className}` : "master-header-btn"}
70
70
  onClick={button.onClick}
71
71
  disabled={button.disabled}
72
72
  title={button.tooltip || button.label}
@@ -704,6 +704,23 @@
704
704
  box-shadow: var(--shadow-md), 0 0 0 3px var(--accent-light);
705
705
  }
706
706
 
707
+ /* Seçili custom button stili - sadece border parlar, arka plan olmaz */
708
+ .master-header-btn-active {
709
+ background: transparent !important;
710
+ backdrop-filter: none !important;
711
+ -webkit-backdrop-filter: none !important;
712
+ border: 2px solid var(--accent-color, #0ea5e9) !important;
713
+ box-shadow: 0 0 10px rgba(14, 165, 233, 0.5), 0 0 20px rgba(14, 165, 233, 0.3) !important;
714
+ color: var(--text-primary) !important;
715
+ }
716
+
717
+ .master-header-btn-active:hover {
718
+ background: transparent !important;
719
+ border-color: var(--accent-color, #0ea5e9) !important;
720
+ box-shadow: 0 0 15px rgba(14, 165, 233, 0.7), 0 0 25px rgba(14, 165, 233, 0.4) !important;
721
+ transform: translateY(-2px);
722
+ }
723
+
707
724
  .master-header-date-picker {
708
725
  background: var(--bg-secondary);
709
726
  backdrop-filter: var(--blur-sm);
@@ -1,5 +1,5 @@
1
1
  import React, { useState, useRef, useEffect, useCallback } from "react";
2
- import { parseDate, isDateDisabled } from "../../utils/dateUtils";
2
+ import { parseDate, isDateDisabled, findEnabledRangeForDate } from "../../utils/dateUtils";
3
3
  import useDragAndDrop from "../../hooks/useDragAndDrop";
4
4
  import useEventDragDrop from "../../hooks/useEventDragDrop";
5
5
  import Indicator from "./Indicator.jsx";
@@ -202,40 +202,102 @@ const TimelineContent = ({
202
202
  return;
203
203
  }
204
204
 
205
- const startDate = parseDate(date.fullDate);
205
+ const clickedDate = parseDate(date.fullDate);
206
206
 
207
207
  // Disabled tarih kontrolü - disabled hücrelerde event oluşturmayı engelle
208
- if (disableDates && isDateDisabled(startDate, disableDates)) {
208
+ if (disableDates && isDateDisabled(clickedDate, disableDates)) {
209
209
  return;
210
210
  }
211
211
 
212
212
  // Geçmiş tarih kontrolü
213
213
  if (preventPastEvents && preventPastEventsDate) {
214
214
  const preventPastEventsDateObj = parseDate(preventPastEventsDate);
215
- // Sadece tarih karşılaştırması (saat bilgisi olmadan)
216
- const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
215
+ const clickedDateOnly = new Date(clickedDate.getFullYear(), clickedDate.getMonth(), clickedDate.getDate());
217
216
  const preventPastEventsDateOnly = new Date(preventPastEventsDateObj.getFullYear(), preventPastEventsDateObj.getMonth(), preventPastEventsDateObj.getDate());
218
217
 
219
- if (startDateOnly < preventPastEventsDateOnly) {
218
+ if (clickedDateOnly < preventPastEventsDateOnly) {
220
219
  // Geçmiş tarihe tıklama engellendi
221
220
  return;
222
221
  }
223
222
  }
224
223
 
224
+ // Eğer disableDates mode: 'include' ise, tıklanan tarihin range'ini veya date'ini bul
225
+ let startDate = clickedDate;
226
+ let endDate = new Date(clickedDate.getTime() + 24 * 60 * 60 * 1000); // Varsayılan: 1 gün
227
+ let enabledRange = null;
228
+
229
+ if (disableDates && disableDates.mode === 'include') {
230
+ // Önce ranges'te ara
231
+ if (disableDates.ranges && disableDates.ranges.length > 0) {
232
+ enabledRange = findEnabledRangeForDate(clickedDate, disableDates);
233
+ if (enabledRange) {
234
+ // Range bulundu, range'in tamamını seç
235
+ startDate = enabledRange.start;
236
+ // endDate'i direkt range'in end'i olarak kullan
237
+ // Range'in end'i zaten son günü temsil ediyor (inclusive)
238
+ endDate = enabledRange.end;
239
+ }
240
+ }
241
+
242
+ // Eğer range bulunamadıysa, dates array'inde tek tek tarih var mı kontrol et
243
+ if (!enabledRange && disableDates.dates && disableDates.dates.length > 0) {
244
+ const clickedDateOnly = new Date(clickedDate.getFullYear(), clickedDate.getMonth(), clickedDate.getDate());
245
+ const foundDate = disableDates.dates.find((d) => {
246
+ const dObj = parseDate(d);
247
+ const dOnly = new Date(dObj.getFullYear(), dObj.getMonth(), dObj.getDate());
248
+ return dOnly.getTime() === clickedDateOnly.getTime();
249
+ });
250
+
251
+ if (foundDate) {
252
+ // Tek bir tarih bulundu, o tarihi seç (1 günlük event)
253
+ const foundDateObj = parseDate(foundDate);
254
+ startDate = new Date(foundDateObj.getFullYear(), foundDateObj.getMonth(), foundDateObj.getDate());
255
+ endDate = new Date(startDate.getTime() + 24 * 60 * 60 * 1000); // 1 gün sonrası
256
+ enabledRange = { start: startDate, end: startDate }; // Tek gün için range oluştur
257
+ }
258
+ }
259
+ }
260
+
261
+ // Event title'ını gün sayısına göre ayarla
262
+ const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
263
+ const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
264
+ // Gün farkını hesapla (gece sayısı = gün farkı)
265
+ // Örnek: 31 Aralık - 5 Ocak = 5 gece (31-1, 1-2, 2-3, 3-4, 4-5)
266
+ const daysDiff = Math.round((endDateOnly.getTime() - startDateOnly.getTime()) / (24 * 60 * 60 * 1000));
267
+ const eventTitle = daysDiff > 0 ? `${daysDiff} Gece` : "1 Gece";
268
+
269
+ // Event'i oluştur - range'in tamamı seçilmiş olacak
225
270
  const newEvent = {
226
271
  id: Date.now(),
227
- title: "1 Gece",
272
+ title: eventTitle,
228
273
  startDate,
229
- endDate: new Date(startDate.getTime() + 24 * 60 * 60 * 1000),
274
+ endDate,
230
275
  resourceId,
231
- // Mouse başlangıç pozisyonunu kaydet
276
+ // Mouse başlangıç pozisyonunu kaydet (sürükle-bırak devre dışı olacak)
232
277
  startX: e?.clientX || 0,
233
- startCellIndex: dates.findIndex((d) => parseDate(d.fullDate).toDateString() === startDate.toDateString()),
234
- // color => var(--timeline-new-event-background-color) => => Sonra inline style yerine className
235
- color: "", // Bunu .css'te "var(--timeline-new-event-background-color)" atayabilirsin
278
+ startCellIndex: dates.findIndex((d) => {
279
+ const dDate = parseDate(d.fullDate);
280
+ const dDateOnly = new Date(dDate.getFullYear(), dDate.getMonth(), dDate.getDate());
281
+ const startDateOnlyCheck = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
282
+ return dDateOnly.getTime() === startDateOnlyCheck.getTime();
283
+ }),
284
+ color: "",
236
285
  };
237
- setTempEvent(newEvent);
238
- setIsCreating(true);
286
+
287
+ // Event'i direkt oluştur (sürükle-bırak olmadan)
288
+ if (enabledRange) {
289
+ // Range seçildi, direkt event oluştur (sürükle-bırak devre dışı)
290
+ setEvents((prev) => [...prev, newEvent]);
291
+
292
+ // Callback'i çağır
293
+ if (onCreateEventInfo) {
294
+ onCreateEventInfo(newEvent);
295
+ }
296
+ } else {
297
+ // Range bulunamadı, eski davranış (sürükle-bırak ile seçim)
298
+ setTempEvent(newEvent);
299
+ setIsCreating(true);
300
+ }
239
301
  };
240
302
 
241
303
  useEffect(() => {
@@ -95,3 +95,39 @@ export const isDateDisabled = (date, disableDates) => {
95
95
 
96
96
  return false;
97
97
  };
98
+
99
+ /**
100
+ * Bir tarihin hangi açık range'e ait olduğunu bulur (mode: 'include' için)
101
+ * @param {string | Object | Date} date - Kontrol edilecek tarih
102
+ * @param {Object} disableDates - { mode: 'include', dates: [], ranges: [] }
103
+ * @returns {Object | null} - { start: Date, end: Date } veya null
104
+ */
105
+ export const findEnabledRangeForDate = (date, disableDates) => {
106
+ if (!disableDates || !disableDates.mode || disableDates.mode !== 'include') {
107
+ return null; // Sadece 'include' modu için çalışır
108
+ }
109
+
110
+ const dateObj = parseDate(date);
111
+ const dateOnly = new Date(dateObj.getFullYear(), dateObj.getMonth(), dateObj.getDate());
112
+
113
+ const { ranges = [] } = disableDates;
114
+
115
+ // Tarihin hangi range'e ait olduğunu bul
116
+ for (const range of ranges) {
117
+ const start = parseDate(range.start);
118
+ const end = parseDate(range.end);
119
+ const startOnly = new Date(start.getFullYear(), start.getMonth(), start.getDate());
120
+ const endOnly = new Date(end.getFullYear(), end.getMonth(), end.getDate());
121
+
122
+ if (dateOnly >= startOnly && dateOnly <= endOnly) {
123
+ // Bu range'e ait, range'in tamamını döndür
124
+ return {
125
+ start: startOnly,
126
+ end: endOnly,
127
+ };
128
+ }
129
+ }
130
+
131
+ // Range bulunamadı, null döndür
132
+ return null;
133
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akfatimeline",
3
- "version": "2.2.2",
3
+ "version": "2.2.4",
4
4
  "description": "A customizable timeline component for React applications with disableDates, custom header buttons, and past date protection features",
5
5
  "main": "./src/library.js",
6
6
  "module": "./src/library.js",
package/src/App.js CHANGED
@@ -9,10 +9,10 @@ const App = () => {
9
9
  const todayDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());
10
10
 
11
11
  // Timeline'ın gösterileceği tarih state'i
12
+ // Test için 31 Aralık 2025 civarına ayarladık (disable dates testi için)
12
13
  const [programDate, setProgramDate] = useState(() => {
13
- const date = new Date();
14
- date.setDate(date.getDate() - 3); // 3 gün öncesinden başla
15
- return date.toISOString().split('T')[0]; // YYYY-MM-DD formatı
14
+ // Test için 31 Aralık 2025'ten 3 gün öncesinden başla (28 Aralık)
15
+ return '2025-12-28'; // YYYY-MM-DD formatı
16
16
  });
17
17
 
18
18
  // Geçmiş tarih koruması için minimum tarih (programDate ve indicatorDate'ten bağımsız)
@@ -42,8 +42,18 @@ const App = () => {
42
42
  // Loading State
43
43
  const [isLoading, setIsLoading] = useState(false);
44
44
 
45
- // Disable Dates kaldırıldı - Tüm tarihler açık
46
- const disableDates = null;
45
+ // Disable Dates - Test için: 31 Aralık - 5 Ocak arası açık, geri kalan her yer disabled
46
+ // mode: 'include' = belirtilen tarihler ve aralıklar enabled (diğerleri disabled)
47
+ const disableDates = {
48
+ mode: 'include', // Belirtilen tarihler ve aralıklar enabled, diğerleri disabled
49
+ dates: [], // Tekil tarihler (şimdilik boş)
50
+ ranges: [
51
+ {
52
+ start: '2025-12-31', // 31 Aralık 2025
53
+ end: '2026-01-05', // 5 Ocak 2026
54
+ },
55
+ ],
56
+ };
47
57
 
48
58
  // Cell Tooltip için örnek fiyat verisi
49
59
  // Her gün için farklı fiyatlar tanımlanabilir
@@ -66,7 +66,7 @@ const MasterHeader = ({
66
66
  {customButtons && customButtons.length > 0 && customButtons.map((button) => (
67
67
  <button
68
68
  key={button.id}
69
- className={button.className || "master-header-btn"}
69
+ className={button.className ? `master-header-btn ${button.className}` : "master-header-btn"}
70
70
  onClick={button.onClick}
71
71
  disabled={button.disabled}
72
72
  title={button.tooltip || button.label}
@@ -704,6 +704,23 @@
704
704
  box-shadow: var(--shadow-md), 0 0 0 3px var(--accent-light);
705
705
  }
706
706
 
707
+ /* Seçili custom button stili - sadece border parlar, arka plan olmaz */
708
+ .master-header-btn-active {
709
+ background: transparent !important;
710
+ backdrop-filter: none !important;
711
+ -webkit-backdrop-filter: none !important;
712
+ border: 2px solid var(--accent-color, #0ea5e9) !important;
713
+ box-shadow: 0 0 10px rgba(14, 165, 233, 0.5), 0 0 20px rgba(14, 165, 233, 0.3) !important;
714
+ color: var(--text-primary) !important;
715
+ }
716
+
717
+ .master-header-btn-active:hover {
718
+ background: transparent !important;
719
+ border-color: var(--accent-color, #0ea5e9) !important;
720
+ box-shadow: 0 0 15px rgba(14, 165, 233, 0.7), 0 0 25px rgba(14, 165, 233, 0.4) !important;
721
+ transform: translateY(-2px);
722
+ }
723
+
707
724
  .master-header-date-picker {
708
725
  background: var(--bg-secondary);
709
726
  backdrop-filter: var(--blur-sm);
@@ -1,5 +1,5 @@
1
1
  import React, { useState, useRef, useEffect, useCallback } from "react";
2
- import { parseDate, isDateDisabled } from "../../utils/dateUtils";
2
+ import { parseDate, isDateDisabled, findEnabledRangeForDate } from "../../utils/dateUtils";
3
3
  import useDragAndDrop from "../../hooks/useDragAndDrop";
4
4
  import useEventDragDrop from "../../hooks/useEventDragDrop";
5
5
  import Indicator from "./Indicator.jsx";
@@ -202,40 +202,102 @@ const TimelineContent = ({
202
202
  return;
203
203
  }
204
204
 
205
- const startDate = parseDate(date.fullDate);
205
+ const clickedDate = parseDate(date.fullDate);
206
206
 
207
207
  // Disabled tarih kontrolü - disabled hücrelerde event oluşturmayı engelle
208
- if (disableDates && isDateDisabled(startDate, disableDates)) {
208
+ if (disableDates && isDateDisabled(clickedDate, disableDates)) {
209
209
  return;
210
210
  }
211
211
 
212
212
  // Geçmiş tarih kontrolü
213
213
  if (preventPastEvents && preventPastEventsDate) {
214
214
  const preventPastEventsDateObj = parseDate(preventPastEventsDate);
215
- // Sadece tarih karşılaştırması (saat bilgisi olmadan)
216
- const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
215
+ const clickedDateOnly = new Date(clickedDate.getFullYear(), clickedDate.getMonth(), clickedDate.getDate());
217
216
  const preventPastEventsDateOnly = new Date(preventPastEventsDateObj.getFullYear(), preventPastEventsDateObj.getMonth(), preventPastEventsDateObj.getDate());
218
217
 
219
- if (startDateOnly < preventPastEventsDateOnly) {
218
+ if (clickedDateOnly < preventPastEventsDateOnly) {
220
219
  // Geçmiş tarihe tıklama engellendi
221
220
  return;
222
221
  }
223
222
  }
224
223
 
224
+ // Eğer disableDates mode: 'include' ise, tıklanan tarihin range'ini veya date'ini bul
225
+ let startDate = clickedDate;
226
+ let endDate = new Date(clickedDate.getTime() + 24 * 60 * 60 * 1000); // Varsayılan: 1 gün
227
+ let enabledRange = null;
228
+
229
+ if (disableDates && disableDates.mode === 'include') {
230
+ // Önce ranges'te ara
231
+ if (disableDates.ranges && disableDates.ranges.length > 0) {
232
+ enabledRange = findEnabledRangeForDate(clickedDate, disableDates);
233
+ if (enabledRange) {
234
+ // Range bulundu, range'in tamamını seç
235
+ startDate = enabledRange.start;
236
+ // endDate'i direkt range'in end'i olarak kullan
237
+ // Range'in end'i zaten son günü temsil ediyor (inclusive)
238
+ endDate = enabledRange.end;
239
+ }
240
+ }
241
+
242
+ // Eğer range bulunamadıysa, dates array'inde tek tek tarih var mı kontrol et
243
+ if (!enabledRange && disableDates.dates && disableDates.dates.length > 0) {
244
+ const clickedDateOnly = new Date(clickedDate.getFullYear(), clickedDate.getMonth(), clickedDate.getDate());
245
+ const foundDate = disableDates.dates.find((d) => {
246
+ const dObj = parseDate(d);
247
+ const dOnly = new Date(dObj.getFullYear(), dObj.getMonth(), dObj.getDate());
248
+ return dOnly.getTime() === clickedDateOnly.getTime();
249
+ });
250
+
251
+ if (foundDate) {
252
+ // Tek bir tarih bulundu, o tarihi seç (1 günlük event)
253
+ const foundDateObj = parseDate(foundDate);
254
+ startDate = new Date(foundDateObj.getFullYear(), foundDateObj.getMonth(), foundDateObj.getDate());
255
+ endDate = new Date(startDate.getTime() + 24 * 60 * 60 * 1000); // 1 gün sonrası
256
+ enabledRange = { start: startDate, end: startDate }; // Tek gün için range oluştur
257
+ }
258
+ }
259
+ }
260
+
261
+ // Event title'ını gün sayısına göre ayarla
262
+ const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
263
+ const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
264
+ // Gün farkını hesapla (gece sayısı = gün farkı)
265
+ // Örnek: 31 Aralık - 5 Ocak = 5 gece (31-1, 1-2, 2-3, 3-4, 4-5)
266
+ const daysDiff = Math.round((endDateOnly.getTime() - startDateOnly.getTime()) / (24 * 60 * 60 * 1000));
267
+ const eventTitle = daysDiff > 0 ? `${daysDiff} Gece` : "1 Gece";
268
+
269
+ // Event'i oluştur - range'in tamamı seçilmiş olacak
225
270
  const newEvent = {
226
271
  id: Date.now(),
227
- title: "1 Gece",
272
+ title: eventTitle,
228
273
  startDate,
229
- endDate: new Date(startDate.getTime() + 24 * 60 * 60 * 1000),
274
+ endDate,
230
275
  resourceId,
231
- // Mouse başlangıç pozisyonunu kaydet
276
+ // Mouse başlangıç pozisyonunu kaydet (sürükle-bırak devre dışı olacak)
232
277
  startX: e?.clientX || 0,
233
- startCellIndex: dates.findIndex((d) => parseDate(d.fullDate).toDateString() === startDate.toDateString()),
234
- // color => var(--timeline-new-event-background-color) => => Sonra inline style yerine className
235
- color: "", // Bunu .css'te "var(--timeline-new-event-background-color)" atayabilirsin
278
+ startCellIndex: dates.findIndex((d) => {
279
+ const dDate = parseDate(d.fullDate);
280
+ const dDateOnly = new Date(dDate.getFullYear(), dDate.getMonth(), dDate.getDate());
281
+ const startDateOnlyCheck = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
282
+ return dDateOnly.getTime() === startDateOnlyCheck.getTime();
283
+ }),
284
+ color: "",
236
285
  };
237
- setTempEvent(newEvent);
238
- setIsCreating(true);
286
+
287
+ // Event'i direkt oluştur (sürükle-bırak olmadan)
288
+ if (enabledRange) {
289
+ // Range seçildi, direkt event oluştur (sürükle-bırak devre dışı)
290
+ setEvents((prev) => [...prev, newEvent]);
291
+
292
+ // Callback'i çağır
293
+ if (onCreateEventInfo) {
294
+ onCreateEventInfo(newEvent);
295
+ }
296
+ } else {
297
+ // Range bulunamadı, eski davranış (sürükle-bırak ile seçim)
298
+ setTempEvent(newEvent);
299
+ setIsCreating(true);
300
+ }
239
301
  };
240
302
 
241
303
  useEffect(() => {
@@ -95,3 +95,39 @@ export const isDateDisabled = (date, disableDates) => {
95
95
 
96
96
  return false;
97
97
  };
98
+
99
+ /**
100
+ * Bir tarihin hangi açık range'e ait olduğunu bulur (mode: 'include' için)
101
+ * @param {string | Object | Date} date - Kontrol edilecek tarih
102
+ * @param {Object} disableDates - { mode: 'include', dates: [], ranges: [] }
103
+ * @returns {Object | null} - { start: Date, end: Date } veya null
104
+ */
105
+ export const findEnabledRangeForDate = (date, disableDates) => {
106
+ if (!disableDates || !disableDates.mode || disableDates.mode !== 'include') {
107
+ return null; // Sadece 'include' modu için çalışır
108
+ }
109
+
110
+ const dateObj = parseDate(date);
111
+ const dateOnly = new Date(dateObj.getFullYear(), dateObj.getMonth(), dateObj.getDate());
112
+
113
+ const { ranges = [] } = disableDates;
114
+
115
+ // Tarihin hangi range'e ait olduğunu bul
116
+ for (const range of ranges) {
117
+ const start = parseDate(range.start);
118
+ const end = parseDate(range.end);
119
+ const startOnly = new Date(start.getFullYear(), start.getMonth(), start.getDate());
120
+ const endOnly = new Date(end.getFullYear(), end.getMonth(), end.getDate());
121
+
122
+ if (dateOnly >= startOnly && dateOnly <= endOnly) {
123
+ // Bu range'e ait, range'in tamamını döndür
124
+ return {
125
+ start: startOnly,
126
+ end: endOnly,
127
+ };
128
+ }
129
+ }
130
+
131
+ // Range bulunamadı, null döndür
132
+ return null;
133
+ };