UNPKG

ethiopian-date-picker-and-converter

Version:

A React component library for converting and picking Ethiopian dates.

424 lines (417 loc) 16.7 kB
'use strict'; var React = require('react'); var DateConverter = /** @class */function () { function DateConverter() { this.ethiopianMonths = ['መስከረም', 'ጥቅምት', 'ኅዳር', 'ታህሳስ', 'ጥር', 'የካቲት', 'መጋቢት', 'ሚያዝያ', 'ግንቦት', 'ሰኔ', 'ሐምሌ', 'ነሐሴ', 'ጷጉሜን']; this.ethiopianDays = ['ሰኞ', 'ማክሰኞ', 'ረቡዕ', 'ሐሙስ', 'ዓርብ', 'ቅዳሜ', 'እሑድ']; } DateConverter.prototype.getMonthName = function (month) { if (month < 1 || month > 13) { throw new Error('Invalid month number. Ethiopian months are between 1 and 13.'); } return this.ethiopianMonths[month - 1]; }; DateConverter.prototype.jdFromGregorian = function (date) { var year = date.getFullYear(); var month = date.getMonth() + 1; var day = date.getDate(); var a = Math.floor((14 - month) / 12); var y = year + 4800 - a; var m = month + 12 * a - 3; return day + Math.floor((153 * m + 2) / 5) + 365 * y + Math.floor(y / 4) - Math.floor(y / 100) + Math.floor(y / 400) - 32045; }; DateConverter.prototype.ethiopianFromJD = function (jd) { var r = (jd - 1723856) % 1461; var n = r % 365 + 365 * Math.floor(r / 1460); var year = 4 * Math.floor((jd - 1723856) / 1461) + Math.floor(r / 365) - Math.floor(r / 1460); var month = Math.floor(n / 30) + 1; var day = n % 30 + 1; // Calculate day of week (1 = Monday, 7 = Sunday) // We add 1 to make Monday = 1, and use % 7 to get the correct index var dayOfWeek = (jd + 1) % 7; // Convert to 0-based index for the array var dayIndex = dayOfWeek === 0 ? 6 : dayOfWeek - 1; return { year: year, month: month, day: day, dayOfWeek: this.ethiopianDays[dayIndex] }; }; DateConverter.prototype.parseDate = function (dateString) { if (typeof dateString === 'string') { var _a = dateString.split('-').map(Number), year = _a[0], month = _a[1], day = _a[2]; return new Date(year, month - 1, day); } throw new Error('Invalid date format. Please use YYYY-MM-DD format'); }; DateConverter.prototype.convertGregorianToEthiopian = function (gregorianDate) { var date = this.parseDate(gregorianDate); var jd = this.jdFromGregorian(date); var ethiopianDate = this.ethiopianFromJD(jd); var formattedDate = "".concat(ethiopianDate.dayOfWeek, "\u1363 ").concat(ethiopianDate.day, " ").concat(this.getMonthName(ethiopianDate.month), " ").concat(ethiopianDate.year); return { ethiopianDate: ethiopianDate, formattedDate: formattedDate }; }; return DateConverter; }(); var DatePicker = /** @class */function () { function DatePicker(inputId) { this.converter = new DateConverter(); this.input = document.getElementById(inputId); this.onDateChange = null; this.calendar = null; // Initialize with current Ethiopian date var today = new Date(); var ethiopianDate = this.converter.convertGregorianToEthiopian(this.formatDateToString(today)).ethiopianDate; this.state = { currentYear: ethiopianDate.year, currentMonth: ethiopianDate.month, selectedDate: null }; if (this.input) { this.input.addEventListener('focus', this.showDatePicker.bind(this)); document.addEventListener('click', this.handleClickOutside.bind(this)); } } DatePicker.prototype.isLeapYear = function (year) { // Ethiopian leap year calculation // A year is a leap year if the year divided by 4 gives remainder 3 return year % 4 === 3; }; DatePicker.prototype.getDaysInMonth = function (year, month) { if (month === 13) { // ጷጉሜን has 6 days in leap years, 5 days otherwise return this.isLeapYear(year) ? 6 : 5; } return 30; // All other months have 30 days }; DatePicker.prototype.validateDate = function (year, month, day) { if (month < 1 || month > 13) return false; var daysInMonth = this.getDaysInMonth(year, month); return day >= 1 && day <= daysInMonth; }; DatePicker.prototype.formatDateToString = function (date) { var year = date.getFullYear(); var month = String(date.getMonth() + 1).padStart(2, '0'); var day = String(date.getDate()).padStart(2, '0'); return "".concat(year, "-").concat(month, "-").concat(day); }; DatePicker.prototype.handleClickOutside = function (event) { if (this.calendar && event.target instanceof Node) { if (!this.calendar.contains(event.target) && event.target !== this.input) { this.calendar.remove(); this.calendar = null; } } }; DatePicker.prototype.createNavigationHeader = function () { var _this = this; var header = document.createElement('div'); header.className = 'picker-header'; var prevButton = document.createElement('button'); prevButton.textContent = '←'; prevButton.onclick = function (e) { e.stopPropagation(); // Prevent event from bubbling up _this.navigateMonth(-1); }; var nextButton = document.createElement('button'); nextButton.textContent = '→'; nextButton.onclick = function (e) { e.stopPropagation(); // Prevent event from bubbling up _this.navigateMonth(1); }; // Create month select var monthSelect = document.createElement('select'); monthSelect.className = 'month-select'; monthSelect.onclick = function (e) { return e.stopPropagation(); }; // Prevent closing when clicking the select this.converter.ethiopianMonths.forEach(function (month, index) { var option = document.createElement('option'); option.value = String(index + 1); option.textContent = month; option.selected = index + 1 === _this.state.currentMonth; monthSelect.appendChild(option); }); monthSelect.onchange = function (e) { e.stopPropagation(); // Prevent event from bubbling up var target = e.target; var newMonth = parseInt(target.value); // If there's a selected date, validate it with the new month if (_this.state.selectedDate) { var daysInNewMonth = _this.getDaysInMonth(_this.state.currentYear, newMonth); if (_this.state.selectedDate.day > daysInNewMonth) { // Adjust the selected date to the last day of the new month _this.state.selectedDate.day = daysInNewMonth; } } _this.state.currentMonth = newMonth; _this.updateCalendar(); }; // Create year select var yearSelect = document.createElement('select'); yearSelect.className = 'year-select'; yearSelect.onclick = function (e) { return e.stopPropagation(); }; // Prevent closing when clicking the select var currentYear = this.state.currentYear; var startYear = currentYear - 20; var endYear = currentYear + 20; for (var year = startYear; year <= endYear; year++) { var option = document.createElement('option'); option.value = String(year); option.textContent = String(year); option.selected = year === currentYear; yearSelect.appendChild(option); } yearSelect.onchange = function (e) { e.stopPropagation(); // Prevent event from bubbling up var target = e.target; var newYear = parseInt(target.value); // If there's a selected date and it's in the 13th month, validate it if (_this.state.selectedDate && _this.state.selectedDate.month === 13) { var daysInNewMonth = _this.getDaysInMonth(newYear, 13); if (_this.state.selectedDate.day > daysInNewMonth) { // Adjust the selected date to the last day of ጷጉሜን _this.state.selectedDate.day = daysInNewMonth; } } _this.state.currentYear = newYear; _this.updateCalendar(); }; // Create a container for the selects var selectContainer = document.createElement('div'); selectContainer.className = 'select-container'; selectContainer.style.display = 'flex'; selectContainer.style.gap = '8px'; selectContainer.style.alignItems = 'center'; selectContainer.onclick = function (e) { return e.stopPropagation(); }; // Prevent closing when clicking the container selectContainer.appendChild(monthSelect); selectContainer.appendChild(yearSelect); header.appendChild(prevButton); header.appendChild(selectContainer); header.appendChild(nextButton); return header; }; DatePicker.prototype.navigateMonth = function (delta) { var newMonth = this.state.currentMonth + delta; var newYear = this.state.currentYear; if (newMonth > 13) { newMonth = 1; newYear++; } else if (newMonth < 1) { newMonth = 13; newYear--; } // Validate selected date when navigating months if (this.state.selectedDate) { var daysInNewMonth = this.getDaysInMonth(newYear, newMonth); if (this.state.selectedDate.day > daysInNewMonth) { this.state.selectedDate.day = daysInNewMonth; } } this.state.currentMonth = newMonth; this.state.currentYear = newYear; this.updateCalendar(); }; DatePicker.prototype.createDaysGrid = function () { var _this = this; var _a, _b, _c; var table = document.createElement('table'); table.className = 'calendar-grid'; table.style.width = '100%'; // Create table header with day names var thead = document.createElement('thead'); var headerRow = document.createElement('tr'); var dayNames = ['ሰኞ', 'ማክሰኞ', 'ረቡዕ', 'ሐሙስ', 'ዓርብ', 'ቅዳሜ', 'እሑድ']; dayNames.forEach(function (day) { var th = document.createElement('th'); th.textContent = day; th.style.width = '14.28%'; headerRow.appendChild(th); }); thead.appendChild(headerRow); table.appendChild(thead); // Create table body with day cells var tbody = document.createElement('tbody'); var daysInMonth = this.getDaysInMonth(this.state.currentYear, this.state.currentMonth); var currentRow = document.createElement('tr'); // Get current Ethiopian date for highlighting var today = new Date(); var currentEthiopianDate = this.converter.convertGregorianToEthiopian(this.formatDateToString(today)).ethiopianDate; // Add empty cells for proper day alignment var firstDayOfMonth = this.getFirstDayOfMonth(); for (var i = 0; i < firstDayOfMonth; i++) { var emptyCell = document.createElement('td'); currentRow.appendChild(emptyCell); } var _loop_1 = function (day) { if ((day + firstDayOfMonth - 1) % 7 === 0 && day !== 1) { tbody.appendChild(currentRow); currentRow = document.createElement('tr'); } var td = document.createElement('td'); td.textContent = String(day); td.className = 'day'; // Add current-day class if it's today if (day === currentEthiopianDate.day && this_1.state.currentMonth === currentEthiopianDate.month && this_1.state.currentYear === currentEthiopianDate.year) { td.classList.add('current-day'); } // Add selected-day class if this date is selected if (day === ((_a = this_1.state.selectedDate) === null || _a === void 0 ? void 0 : _a.day) && this_1.state.currentMonth === ((_b = this_1.state.selectedDate) === null || _b === void 0 ? void 0 : _b.month) && this_1.state.currentYear === ((_c = this_1.state.selectedDate) === null || _c === void 0 ? void 0 : _c.year)) { td.classList.add('selected-day'); } td.onclick = function () { return _this.selectDate(day); }; currentRow.appendChild(td); }; var this_1 = this; for (var day = 1; day <= daysInMonth; day++) { _loop_1(day); } tbody.appendChild(currentRow); table.appendChild(tbody); return table; }; DatePicker.prototype.getFirstDayOfMonth = function () { // This is a simplified version. For accurate implementation, // you would need to calculate the actual first day of the Ethiopian month return 0; // Assuming months start on Monday for now }; DatePicker.prototype.selectDate = function (day) { var _a; if (!this.validateDate(this.state.currentYear, this.state.currentMonth, day)) { return; } // Update selected date in state this.state.selectedDate = { year: this.state.currentYear, month: this.state.currentMonth, day: day }; // Update the calendar to show the selection this.updateCalendar(); if (this.input && this.onDateChange) { var formattedDate = "".concat(this.state.selectedDate.day, " ").concat(this.converter.getMonthName(this.state.selectedDate.month), " ").concat(this.state.selectedDate.year); this.input.value = formattedDate; this.onDateChange(formattedDate); (_a = this.calendar) === null || _a === void 0 ? void 0 : _a.remove(); this.calendar = null; } }; DatePicker.prototype.updateCalendar = function () { if (this.calendar) { this.calendar.innerHTML = ''; this.calendar.appendChild(this.createNavigationHeader()); this.calendar.appendChild(this.createDaysGrid()); } }; DatePicker.prototype.showDatePicker = function () { if (this.calendar) { return; } this.calendar = document.createElement('div'); this.calendar.className = 'ethiopian-date-picker'; this.calendar.style.minWidth = '350px'; this.updateCalendar(); // Position the calendar below the input if (this.input) { var rect = this.input.getBoundingClientRect(); this.calendar.style.position = 'absolute'; this.calendar.style.top = "".concat(rect.bottom + 5, "px"); this.calendar.style.left = "".concat(rect.left, "px"); document.body.appendChild(this.calendar); } }; DatePicker.prototype.destroy = function () { if (this.input) { this.input.removeEventListener('focus', this.showDatePicker.bind(this)); document.removeEventListener('click', this.handleClickOutside.bind(this)); } if (this.calendar) { this.calendar.remove(); this.calendar = null; } }; return DatePicker; }(); var EthiopianDatePicker = function (_a) { var _b = _a.id, id = _b === void 0 ? 'default-id-date-picker' : _b, _c = _a.placeholder, placeholder = _c === void 0 ? 'Select a date' : _c, onDateChange = _a.onDateChange; var datePickerRef = React.useRef(null); React.useEffect(function () { datePickerRef.current = new DatePicker(id); datePickerRef.current.onDateChange = function (formattedDate) { onDateChange(formattedDate); }; return function () { if (datePickerRef.current) { datePickerRef.current.destroy(); } }; }, [id, onDateChange]); return React.createElement("div", null, React.createElement("input", { id: id, type: "text", placeholder: placeholder, className: "padded-input", readOnly: true })); }; /** * Converts a Gregorian date to Ethiopian date * @param {string} gregorianDate - The Gregorian date in 'YYYY-MM-DD' format * @param {ReturnFormat} [returnFormat='full'] - The desired format of the returned date * @returns {(string | EthiopianDateObject | null)} The converted Ethiopian date in the specified format * @example * // Returns full format (e.g., 'ሰኞ፣ ጥር 7 ቀን 2016 ዓ.ም.') * EthiopianDateConverter('2024-01-15') * * // Returns date only format (e.g., '2016-5-7') * EthiopianDateConverter('2024-01-15', 'date-only') * * // Returns object format * EthiopianDateConverter('2024-01-15', 'object') */ var EthiopianDateConverter = function (gregorianDate, returnFormat) { if (returnFormat === void 0) { returnFormat = 'full'; } try { var converter = new DateConverter(); var result = converter.convertGregorianToEthiopian(gregorianDate); switch (returnFormat) { case 'date-only': return "".concat(result.ethiopianDate.year, "-").concat(result.ethiopianDate.month, "-").concat(result.ethiopianDate.day); case 'object': return { year: result.ethiopianDate.year, month: result.ethiopianDate.month, day: result.ethiopianDate.day, monthName: converter.getMonthName(result.ethiopianDate.month), weekDay: result.ethiopianDate.dayOfWeek }; case 'full': default: return result.formattedDate; } } catch (error) { console.error('Error converting date:', error); return null; } }; exports.EthiopianDateConverter = EthiopianDateConverter; exports.EthiopianDatePicker = EthiopianDatePicker; //# sourceMappingURL=index.js.map