time-period-selector-react
Version:
TimePeriodSelector - Drag to Select Time Period of the Day
210 lines (209 loc) • 9.33 kB
JavaScript
import * as __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__ from "react/jsx-runtime";
import * as __WEBPACK_EXTERNAL_MODULE_react__ from "react";
import "./index.css";
const weekDays = [
'Mon',
'Tue',
'Wed',
'Thu',
'Fri',
'Sat',
'Sun'
];
const weekDayDisplayZh = {
Mon: '周一',
Tue: '周二',
Wed: '周三',
Thu: '周四',
Fri: '周五',
Sat: '周六',
Sun: '周日'
};
const weekDayDisplayEn = {
Mon: 'Monday',
Tue: 'Tuesday',
Wed: 'Wednesday',
Thu: 'Thursday',
Fri: 'Friday',
Sat: 'Saturday',
Sun: 'Sunday'
};
function TimePeriodSelector(props) {
const { style, title, language = 'en', showTime, value, onChange } = props;
const weekDayDisplay = 'en' === language ? weekDayDisplayEn : weekDayDisplayZh;
const [selectedSlots, setSelectedSlots] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(value || {
Mon: [],
Tue: [],
Wed: [],
Thu: [],
Fri: [],
Sat: [],
Sun: []
});
const [isSelecting, setIsSelecting] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(false);
const [selectionStart, setSelectionStart] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(null);
const handleClick = (day, hour)=>{
if (isSelecting) return;
const newSelectedSlots = {
...selectedSlots
};
const currentHours = selectedSlots[day];
if (currentHours.includes(hour)) newSelectedSlots[day] = currentHours.filter((h)=>h !== hour);
else newSelectedSlots[day] = [
...currentHours,
hour
].sort((a, b)=>a - b);
setSelectedSlots(newSelectedSlots);
onChange?.(newSelectedSlots);
};
const handleMouseDown = (day, hour)=>{
setIsSelecting(true);
setSelectionStart({
day,
hour
});
};
const handleMouseEnter = (day, hour)=>{
if (!isSelecting || !selectionStart || selectionStart.day !== day) return;
const minHour = Math.min(selectionStart.hour, hour);
const maxHour = Math.max(selectionStart.hour, hour);
const hours = Array.from({
length: maxHour - minHour + 1
}, (_, i)=>minHour + i);
const newSelectedSlots = {
...selectedSlots,
[day]: Array.from(new Set([
...selectedSlots[day],
...hours
])).sort((a, b)=>a - b)
};
setSelectedSlots(newSelectedSlots);
onChange?.(newSelectedSlots);
};
const handleMouseUp = ()=>{
setIsSelecting(false);
setSelectionStart(null);
};
const formatSelectedTimes = ()=>Object.entries(selectedSlots).filter(([, hours])=>hours.length > 0).map(([day, hours])=>{
const timeRanges = [];
let start = hours[0];
let prev = hours[0];
for(let i = 1; i <= hours.length; i++)if (i === hours.length || hours[i] !== prev + 1) {
timeRanges.push([
start,
prev + 1
]);
if (i < hours.length) {
start = hours[i];
prev = hours[i];
}
} else prev = hours[i];
const formattedHours = timeRanges.map(([start, end])=>`${String(start).padStart(2, '0')}:00~${String(end).padStart(2, '0')}:00`).join('、');
return `${weekDayDisplay[day]} ${formattedHours}`;
}).join('\n');
const handleClear = ()=>{
const emptySlots = {
Mon: [],
Tue: [],
Wed: [],
Thu: [],
Fri: [],
Sat: [],
Sun: []
};
setSelectedSlots(emptySlots);
onChange?.(emptySlots);
};
return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsxs)("div", {
className: "time-period-selector",
style: style,
children: [
/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsxs)("div", {
className: "time-period-header",
children: [
/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsx)("h3", {
className: "time-period-title",
children: title
}),
/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsx)("a", {
onClick: handleClear,
className: "clear-button",
children: 'zh' === language ? '清空' : 'Clear'
})
]
}),
/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsxs)("table", {
className: "time-period-table",
children: [
/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsxs)("thead", {
className: "time-period-thead",
children: [
/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsxs)("tr", {
children: [
/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsx)("th", {
rowSpan: 2,
className: "time-period-th",
children: 'zh' === language ? '日期/时间' : 'Date/Time'
}),
/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsx)("th", {
colSpan: 12,
className: "time-period-th",
children: "00:00~12:00"
}),
/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsx)("th", {
colSpan: 12,
className: "time-period-th",
children: "12:00~24:00"
})
]
}),
/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsx)("tr", {
children: Array.from({
length: 24
}).map((_, i)=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsx)("th", {
className: "time-period-hour-th",
children: i
}, i))
})
]
}),
/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsx)("tbody", {
children: weekDays.map((day)=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsxs)("tr", {
children: [
/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsx)("td", {
className: "time-period-day",
children: weekDayDisplay[day]
}),
Array.from({
length: 24
}).map((_, hourIndex)=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsx)("td", {
className: `time-period-hour ${selectedSlots[day].includes(hourIndex) ? 'selected' : ''}`,
onMouseDown: ()=>handleMouseDown(day, hourIndex),
onMouseEnter: ()=>handleMouseEnter(day, hourIndex),
onMouseUp: handleMouseUp,
onClick: ()=>handleClick(day, hourIndex)
}, hourIndex))
]
}, day))
})
]
}),
showTime && /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsxs)(__WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.Fragment, {
children: [
/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsx)("div", {
className: "time-period-divider"
}),
/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsx)("div", {
className: "time-period-selected-times",
children: 'zh' === language ? '已选择时间:' : 'Selected Times:'
}),
/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__.jsx)("pre", {
className: "time-period-selected-times-text",
children: formatSelectedTimes()
})
]
})
]
});
}
export { TimePeriodSelector };