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 +130 -14
- package/dist/components/Timeline/MasterHeader.jsx +1 -1
- package/dist/components/Timeline/Timeline.css +17 -0
- package/dist/components/Timeline/TimelineContent.jsx +76 -14
- package/dist/utils/dateUtils.js +36 -0
- package/package.json +1 -1
- package/src/App.js +15 -5
- package/src/components/Timeline/MasterHeader.jsx +1 -1
- package/src/components/Timeline/Timeline.css +17 -0
- package/src/components/Timeline/TimelineContent.jsx +76 -14
- package/src/utils/dateUtils.js +36 -0
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
|
|
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
|
|
4137
|
+
const clickedDate = parseDate(date.fullDate);
|
|
4086
4138
|
|
|
4087
4139
|
// Disabled tarih kontrolü - disabled hücrelerde event oluşturmayı engelle
|
|
4088
|
-
if (disableDates && isDateDisabled(
|
|
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
|
-
|
|
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 (
|
|
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:
|
|
4204
|
+
title: eventTitle,
|
|
4106
4205
|
startDate,
|
|
4107
|
-
endDate
|
|
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 =>
|
|
4112
|
-
|
|
4113
|
-
|
|
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
|
-
|
|
4116
|
-
|
|
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
|
|
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
|
|
205
|
+
const clickedDate = parseDate(date.fullDate);
|
|
206
206
|
|
|
207
207
|
// Disabled tarih kontrolü - disabled hücrelerde event oluşturmayı engelle
|
|
208
|
-
if (disableDates && isDateDisabled(
|
|
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
|
-
|
|
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 (
|
|
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:
|
|
272
|
+
title: eventTitle,
|
|
228
273
|
startDate,
|
|
229
|
-
endDate
|
|
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) =>
|
|
234
|
-
|
|
235
|
-
|
|
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
|
-
|
|
238
|
-
|
|
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(() => {
|
package/dist/utils/dateUtils.js
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
14
|
-
|
|
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
|
|
46
|
-
|
|
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
|
|
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
|
|
205
|
+
const clickedDate = parseDate(date.fullDate);
|
|
206
206
|
|
|
207
207
|
// Disabled tarih kontrolü - disabled hücrelerde event oluşturmayı engelle
|
|
208
|
-
if (disableDates && isDateDisabled(
|
|
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
|
-
|
|
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 (
|
|
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:
|
|
272
|
+
title: eventTitle,
|
|
228
273
|
startDate,
|
|
229
|
-
endDate
|
|
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) =>
|
|
234
|
-
|
|
235
|
-
|
|
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
|
-
|
|
238
|
-
|
|
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(() => {
|
package/src/utils/dateUtils.js
CHANGED
|
@@ -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
|
+
};
|