akfatimeline 2.2.2 → 2.2.3
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 +107 -14
- package/dist/components/Timeline/MasterHeader.jsx +1 -1
- package/dist/components/Timeline/Timeline.css +17 -0
- package/dist/components/Timeline/TimelineContent.jsx +55 -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 +55 -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,79 @@ 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 ve ranges varsa, tıklanan tarihin range'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' && disableDates.ranges && disableDates.ranges.length > 0) {
|
|
4160
|
+
enabledRange = findEnabledRangeForDate(clickedDate, disableDates);
|
|
4161
|
+
if (enabledRange) {
|
|
4162
|
+
// Range bulundu, range'in tamamını seç
|
|
4163
|
+
startDate = enabledRange.start;
|
|
4164
|
+
// endDate'i direkt range'in end'i olarak kullan
|
|
4165
|
+
// Range'in end'i zaten son günü temsil ediyor (inclusive)
|
|
4166
|
+
endDate = enabledRange.end;
|
|
4167
|
+
}
|
|
4168
|
+
}
|
|
4169
|
+
|
|
4170
|
+
// Event title'ını gün sayısına göre ayarla
|
|
4171
|
+
const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
|
|
4172
|
+
const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
|
|
4173
|
+
// Gün farkını hesapla (gece sayısı = gün farkı)
|
|
4174
|
+
// Örnek: 31 Aralık - 5 Ocak = 5 gece (31-1, 1-2, 2-3, 3-4, 4-5)
|
|
4175
|
+
const daysDiff = Math.round((endDateOnly.getTime() - startDateOnly.getTime()) / (24 * 60 * 60 * 1000));
|
|
4176
|
+
const eventTitle = daysDiff > 0 ? "".concat(daysDiff, " Gece") : "1 Gece";
|
|
4177
|
+
|
|
4178
|
+
// Event'i oluştur - range'in tamamı seçilmiş olacak
|
|
4103
4179
|
const newEvent = {
|
|
4104
4180
|
id: Date.now(),
|
|
4105
|
-
title:
|
|
4181
|
+
title: eventTitle,
|
|
4106
4182
|
startDate,
|
|
4107
|
-
endDate
|
|
4183
|
+
endDate,
|
|
4108
4184
|
resourceId,
|
|
4109
|
-
// Mouse başlangıç pozisyonunu kaydet
|
|
4185
|
+
// Mouse başlangıç pozisyonunu kaydet (sürükle-bırak devre dışı olacak)
|
|
4110
4186
|
startX: (e === null || e === void 0 ? void 0 : e.clientX) || 0,
|
|
4111
|
-
startCellIndex: dates.findIndex(d =>
|
|
4112
|
-
|
|
4113
|
-
|
|
4187
|
+
startCellIndex: dates.findIndex(d => {
|
|
4188
|
+
const dDate = parseDate(d.fullDate);
|
|
4189
|
+
const dDateOnly = new Date(dDate.getFullYear(), dDate.getMonth(), dDate.getDate());
|
|
4190
|
+
const startDateOnlyCheck = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
|
|
4191
|
+
return dDateOnly.getTime() === startDateOnlyCheck.getTime();
|
|
4192
|
+
}),
|
|
4193
|
+
color: ""
|
|
4114
4194
|
};
|
|
4115
|
-
|
|
4116
|
-
|
|
4195
|
+
|
|
4196
|
+
// Event'i direkt oluştur (sürükle-bırak olmadan)
|
|
4197
|
+
if (enabledRange) {
|
|
4198
|
+
// Range seçildi, direkt event oluştur (sürükle-bırak devre dışı)
|
|
4199
|
+
setEvents(prev => [...prev, newEvent]);
|
|
4200
|
+
|
|
4201
|
+
// Callback'i çağır
|
|
4202
|
+
if (onCreateEventInfo) {
|
|
4203
|
+
onCreateEventInfo(newEvent);
|
|
4204
|
+
}
|
|
4205
|
+
} else {
|
|
4206
|
+
// Range bulunamadı, eski davranış (sürükle-bırak ile seçim)
|
|
4207
|
+
setTempEvent(newEvent);
|
|
4208
|
+
setIsCreating(true);
|
|
4209
|
+
}
|
|
4117
4210
|
};
|
|
4118
4211
|
(0,external_react_.useEffect)(() => {
|
|
4119
4212
|
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,81 @@ 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 ve ranges varsa, tıklanan tarihin range'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' && disableDates.ranges && disableDates.ranges.length > 0) {
|
|
230
|
+
enabledRange = findEnabledRangeForDate(clickedDate, disableDates);
|
|
231
|
+
if (enabledRange) {
|
|
232
|
+
// Range bulundu, range'in tamamını seç
|
|
233
|
+
startDate = enabledRange.start;
|
|
234
|
+
// endDate'i direkt range'in end'i olarak kullan
|
|
235
|
+
// Range'in end'i zaten son günü temsil ediyor (inclusive)
|
|
236
|
+
endDate = enabledRange.end;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Event title'ını gün sayısına göre ayarla
|
|
241
|
+
const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
|
|
242
|
+
const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
|
|
243
|
+
// Gün farkını hesapla (gece sayısı = gün farkı)
|
|
244
|
+
// Örnek: 31 Aralık - 5 Ocak = 5 gece (31-1, 1-2, 2-3, 3-4, 4-5)
|
|
245
|
+
const daysDiff = Math.round((endDateOnly.getTime() - startDateOnly.getTime()) / (24 * 60 * 60 * 1000));
|
|
246
|
+
const eventTitle = daysDiff > 0 ? `${daysDiff} Gece` : "1 Gece";
|
|
247
|
+
|
|
248
|
+
// Event'i oluştur - range'in tamamı seçilmiş olacak
|
|
225
249
|
const newEvent = {
|
|
226
250
|
id: Date.now(),
|
|
227
|
-
title:
|
|
251
|
+
title: eventTitle,
|
|
228
252
|
startDate,
|
|
229
|
-
endDate
|
|
253
|
+
endDate,
|
|
230
254
|
resourceId,
|
|
231
|
-
// Mouse başlangıç pozisyonunu kaydet
|
|
255
|
+
// Mouse başlangıç pozisyonunu kaydet (sürükle-bırak devre dışı olacak)
|
|
232
256
|
startX: e?.clientX || 0,
|
|
233
|
-
startCellIndex: dates.findIndex((d) =>
|
|
234
|
-
|
|
235
|
-
|
|
257
|
+
startCellIndex: dates.findIndex((d) => {
|
|
258
|
+
const dDate = parseDate(d.fullDate);
|
|
259
|
+
const dDateOnly = new Date(dDate.getFullYear(), dDate.getMonth(), dDate.getDate());
|
|
260
|
+
const startDateOnlyCheck = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
|
|
261
|
+
return dDateOnly.getTime() === startDateOnlyCheck.getTime();
|
|
262
|
+
}),
|
|
263
|
+
color: "",
|
|
236
264
|
};
|
|
237
|
-
|
|
238
|
-
|
|
265
|
+
|
|
266
|
+
// Event'i direkt oluştur (sürükle-bırak olmadan)
|
|
267
|
+
if (enabledRange) {
|
|
268
|
+
// Range seçildi, direkt event oluştur (sürükle-bırak devre dışı)
|
|
269
|
+
setEvents((prev) => [...prev, newEvent]);
|
|
270
|
+
|
|
271
|
+
// Callback'i çağır
|
|
272
|
+
if (onCreateEventInfo) {
|
|
273
|
+
onCreateEventInfo(newEvent);
|
|
274
|
+
}
|
|
275
|
+
} else {
|
|
276
|
+
// Range bulunamadı, eski davranış (sürükle-bırak ile seçim)
|
|
277
|
+
setTempEvent(newEvent);
|
|
278
|
+
setIsCreating(true);
|
|
279
|
+
}
|
|
239
280
|
};
|
|
240
281
|
|
|
241
282
|
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.3",
|
|
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,81 @@ 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 ve ranges varsa, tıklanan tarihin range'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' && disableDates.ranges && disableDates.ranges.length > 0) {
|
|
230
|
+
enabledRange = findEnabledRangeForDate(clickedDate, disableDates);
|
|
231
|
+
if (enabledRange) {
|
|
232
|
+
// Range bulundu, range'in tamamını seç
|
|
233
|
+
startDate = enabledRange.start;
|
|
234
|
+
// endDate'i direkt range'in end'i olarak kullan
|
|
235
|
+
// Range'in end'i zaten son günü temsil ediyor (inclusive)
|
|
236
|
+
endDate = enabledRange.end;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Event title'ını gün sayısına göre ayarla
|
|
241
|
+
const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
|
|
242
|
+
const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
|
|
243
|
+
// Gün farkını hesapla (gece sayısı = gün farkı)
|
|
244
|
+
// Örnek: 31 Aralık - 5 Ocak = 5 gece (31-1, 1-2, 2-3, 3-4, 4-5)
|
|
245
|
+
const daysDiff = Math.round((endDateOnly.getTime() - startDateOnly.getTime()) / (24 * 60 * 60 * 1000));
|
|
246
|
+
const eventTitle = daysDiff > 0 ? `${daysDiff} Gece` : "1 Gece";
|
|
247
|
+
|
|
248
|
+
// Event'i oluştur - range'in tamamı seçilmiş olacak
|
|
225
249
|
const newEvent = {
|
|
226
250
|
id: Date.now(),
|
|
227
|
-
title:
|
|
251
|
+
title: eventTitle,
|
|
228
252
|
startDate,
|
|
229
|
-
endDate
|
|
253
|
+
endDate,
|
|
230
254
|
resourceId,
|
|
231
|
-
// Mouse başlangıç pozisyonunu kaydet
|
|
255
|
+
// Mouse başlangıç pozisyonunu kaydet (sürükle-bırak devre dışı olacak)
|
|
232
256
|
startX: e?.clientX || 0,
|
|
233
|
-
startCellIndex: dates.findIndex((d) =>
|
|
234
|
-
|
|
235
|
-
|
|
257
|
+
startCellIndex: dates.findIndex((d) => {
|
|
258
|
+
const dDate = parseDate(d.fullDate);
|
|
259
|
+
const dDateOnly = new Date(dDate.getFullYear(), dDate.getMonth(), dDate.getDate());
|
|
260
|
+
const startDateOnlyCheck = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
|
|
261
|
+
return dDateOnly.getTime() === startDateOnlyCheck.getTime();
|
|
262
|
+
}),
|
|
263
|
+
color: "",
|
|
236
264
|
};
|
|
237
|
-
|
|
238
|
-
|
|
265
|
+
|
|
266
|
+
// Event'i direkt oluştur (sürükle-bırak olmadan)
|
|
267
|
+
if (enabledRange) {
|
|
268
|
+
// Range seçildi, direkt event oluştur (sürükle-bırak devre dışı)
|
|
269
|
+
setEvents((prev) => [...prev, newEvent]);
|
|
270
|
+
|
|
271
|
+
// Callback'i çağır
|
|
272
|
+
if (onCreateEventInfo) {
|
|
273
|
+
onCreateEventInfo(newEvent);
|
|
274
|
+
}
|
|
275
|
+
} else {
|
|
276
|
+
// Range bulunamadı, eski davranış (sürükle-bırak ile seçim)
|
|
277
|
+
setTempEvent(newEvent);
|
|
278
|
+
setIsCreating(true);
|
|
279
|
+
}
|
|
239
280
|
};
|
|
240
281
|
|
|
241
282
|
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
|
+
};
|