Support Monday/Sunday day of week
This commit is contained in:
@@ -6,10 +6,33 @@
|
|||||||
export let holidays = [];
|
export let holidays = [];
|
||||||
export let optimizedDaysOff = [];
|
export let optimizedDaysOff = [];
|
||||||
export let consecutiveDaysOff = [];
|
export let consecutiveDaysOff = [];
|
||||||
|
export let selectedCountryCode;
|
||||||
|
|
||||||
|
// Function to determine the first day of the week based on locale
|
||||||
|
function getFirstDayOfWeek(locale) {
|
||||||
|
// Convert 'us' to proper locale format
|
||||||
|
const normalizedLocale = locale.toLowerCase() === 'us' ? 'en-US' : `en-${locale.toUpperCase()}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Try to get firstDay from Intl.Locale weekInfo
|
||||||
|
// @ts-ignore .weekInfo exists on all browsers except Firefox
|
||||||
|
const weekFirstDay = new Intl.Locale(normalizedLocale)?.weekInfo?.firstDay;
|
||||||
|
if (weekFirstDay !== undefined) {
|
||||||
|
return weekFirstDay;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Fallback if weekInfo is not supported
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: US starts on Sunday (0), most others on Monday (1)
|
||||||
|
return normalizedLocale === 'en-US' ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Reactive declarations
|
// Reactive declarations
|
||||||
$: daysInMonth = getDaysInMonth(year, month);
|
$: daysInMonth = getDaysInMonth(year, month);
|
||||||
$: firstDay = getFirstDayOfMonth(year, month);
|
$: locale = selectedCountryCode ? new Intl.Locale(selectedCountryCode).toString() : 'us';
|
||||||
|
$: firstDayOfWeek = getFirstDayOfWeek(locale);
|
||||||
|
$: adjustedFirstDay = (getFirstDayOfMonth(year, month) - firstDayOfWeek + 7) % 7;
|
||||||
|
|
||||||
function getDaysInMonth(year, month) {
|
function getDaysInMonth(year, month) {
|
||||||
return new Date(year, month + 1, 0).getDate();
|
return new Date(year, month + 1, 0).getDate();
|
||||||
@@ -58,15 +81,45 @@
|
|||||||
return date >= start && date <= end;
|
return date >= start && date <= end;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to determine if a day is a weekend
|
||||||
|
function isWeekend(day) {
|
||||||
|
const dayOfWeek = (adjustedFirstDay + day - 1) % 7;
|
||||||
|
// Calculate the indices for Saturday and Sunday
|
||||||
|
const saturdayIndex = (6 - firstDayOfWeek + 7) % 7;
|
||||||
|
const sundayIndex = (7 - firstDayOfWeek + 7) % 7;
|
||||||
|
return dayOfWeek === saturdayIndex || dayOfWeek === sundayIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to get the localized day initials based on the first day of the week
|
||||||
|
function getLocalizedDayInitials(locale) {
|
||||||
|
const formatter = new Intl.DateTimeFormat(locale, { weekday: 'short' });
|
||||||
|
const dayInitials = [];
|
||||||
|
for (let i = 0; i < 7; i++) {
|
||||||
|
const date = new Date(Date.UTC(2021, 0, i + 3)); // Start from a known Thursday to ensure full week coverage
|
||||||
|
const dayName = formatter.format(date);
|
||||||
|
dayInitials.push(dayName.charAt(0).toUpperCase());
|
||||||
|
}
|
||||||
|
return dayInitials;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reactive declaration to get the ordered day initials
|
||||||
|
$: orderedDayInitials = getLocalizedDayInitials(locale).slice(firstDayOfWeek).concat(getLocalizedDayInitials(locale).slice(0, firstDayOfWeek));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="calendar">
|
<div class="calendar">
|
||||||
<div class="month-name">{new Date(year, month).toLocaleString('default', { month: 'long' })}</div>
|
<div class="month-name">{new Date(year, month).toLocaleString('default', { month: 'long' })}</div>
|
||||||
{#each Array.from({ length: firstDay }) as _}
|
|
||||||
|
<!-- Day initials header -->
|
||||||
|
{#each orderedDayInitials as dayInitial}
|
||||||
|
<div class="day-initial">{dayInitial}</div>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
{#each Array.from({ length: adjustedFirstDay }) as _}
|
||||||
<div class="day"></div>
|
<div class="day"></div>
|
||||||
{/each}
|
{/each}
|
||||||
{#each Array.from({ length: daysInMonth }, (_, i) => i + 1) as day}
|
{#each Array.from({ length: daysInMonth }, (_, i) => i + 1) as day}
|
||||||
<div class="day {(firstDay + day - 1) % 7 === 0 || (firstDay + day - 1) % 7 === 6 ? 'weekend' : ''} {getHoliday(day) ? 'holiday' : ''} {isOptimizedDayOff(day) ? 'optimized' : ''} {isConsecutiveDayOff(day) ? 'consecutive-day' : ''}">
|
<div class="day {isWeekend(day) ? 'weekend' : ''} {getHoliday(day) ? 'holiday' : ''} {isOptimizedDayOff(day) ? 'optimized' : ''} {isConsecutiveDayOff(day) ? 'consecutive-day' : ''}">
|
||||||
{day}
|
{day}
|
||||||
{#if getHoliday(day)}
|
{#if getHoliday(day)}
|
||||||
<Tooltip text={getHoliday(day).name} />
|
<Tooltip text={getHoliday(day).name} />
|
||||||
@@ -96,6 +149,12 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
.day-initial {
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #c5c6c7;
|
||||||
|
font-size: 0.6em;
|
||||||
|
}
|
||||||
.day {
|
.day {
|
||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@@ -35,6 +35,12 @@
|
|||||||
|
|
||||||
let showHolidaysList = false; // State to toggle the visibility of the holidays list
|
let showHolidaysList = false; // State to toggle the visibility of the holidays list
|
||||||
|
|
||||||
|
$: selectedCountryCode = Object.keys(countriesList).find(code => countriesList[code] === selectedCountry);
|
||||||
|
|
||||||
|
$: if (selectedCountryCode || selectedStateCode || daysOff) {
|
||||||
|
updateHolidays();
|
||||||
|
}
|
||||||
|
|
||||||
function updateStatesList(countryCode) {
|
function updateStatesList(countryCode) {
|
||||||
const hd = new Holidays(countryCode);
|
const hd = new Holidays(countryCode);
|
||||||
statesList = hd.getStates(countryCode) || [];
|
statesList = hd.getStates(countryCode) || [];
|
||||||
@@ -44,7 +50,6 @@
|
|||||||
const stateName = event.target.value;
|
const stateName = event.target.value;
|
||||||
selectedStateCode = Object.keys(statesList).find(code => statesList[code] === stateName);
|
selectedStateCode = Object.keys(statesList).find(code => statesList[code] === stateName);
|
||||||
selectedState = stateName;
|
selectedState = stateName;
|
||||||
updateHolidays();
|
|
||||||
localStorage.setItem('selectedState', selectedState);
|
localStorage.setItem('selectedState', selectedState);
|
||||||
localStorage.setItem('selectedStateCode', selectedStateCode);
|
localStorage.setItem('selectedStateCode', selectedStateCode);
|
||||||
}
|
}
|
||||||
@@ -70,13 +75,12 @@
|
|||||||
daysOff = storedDaysOff ? parseInt(storedDaysOff, 10) : defaultDaysOff;
|
daysOff = storedDaysOff ? parseInt(storedDaysOff, 10) : defaultDaysOff;
|
||||||
selectedState = storedState || '';
|
selectedState = storedState || '';
|
||||||
selectedStateCode = storedStateCode || '';
|
selectedStateCode = storedStateCode || '';
|
||||||
updateHolidays();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const countryCode = Object.keys(countriesList).find(code => countriesList[code] === selectedCountry);
|
if (selectedCountryCode) {
|
||||||
if (countryCode) {
|
updateStatesList(selectedCountryCode);
|
||||||
updateStatesList(countryCode);
|
|
||||||
}
|
}
|
||||||
|
window.addEventListener('keydown', handleKeyDown);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function fetchCountryCode() {
|
async function fetchCountryCode() {
|
||||||
@@ -94,14 +98,11 @@
|
|||||||
|
|
||||||
function handleCountryChange(event) {
|
function handleCountryChange(event) {
|
||||||
const fullValue = event.target.value;
|
const fullValue = event.target.value;
|
||||||
const countryCode = Object.keys(countriesList).find(code => countriesList[code] === fullValue);
|
if (selectedCountryCode) {
|
||||||
if (countryCode) {
|
daysOff = ptoData[selectedCountryCode] || 0;
|
||||||
selectedCountry = fullValue;
|
|
||||||
daysOff = ptoData[countryCode] || 0;
|
|
||||||
selectedState = ''; // Reset state
|
selectedState = ''; // Reset state
|
||||||
selectedStateCode = ''; // Reset state code
|
selectedStateCode = ''; // Reset state code
|
||||||
updateStatesList(countryCode); // Update states list for the new country
|
updateStatesList(selectedCountryCode); // Update states list for the new country
|
||||||
updateHolidays();
|
|
||||||
localStorage.setItem('selectedCountry', selectedCountry);
|
localStorage.setItem('selectedCountry', selectedCountry);
|
||||||
localStorage.setItem('selectedState', selectedState);
|
localStorage.setItem('selectedState', selectedState);
|
||||||
localStorage.setItem('selectedStateCode', selectedStateCode);
|
localStorage.setItem('selectedStateCode', selectedStateCode);
|
||||||
@@ -110,15 +111,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateHolidays() {
|
function updateHolidays() {
|
||||||
const countryCode = Object.keys(countriesList).find(code => countriesList[code] === selectedCountry);
|
if (selectedCountryCode) {
|
||||||
if (countryCode) {
|
updateStatesList(selectedCountryCode);
|
||||||
updateStatesList(countryCode);
|
let allHolidays = getHolidaysForYear(selectedCountryCode, year, selectedStateCode);
|
||||||
let allHolidays = getHolidaysForYear(countryCode, year, selectedStateCode);
|
|
||||||
holidays = allHolidays.map(holiday => ({
|
holidays = allHolidays.map(holiday => ({
|
||||||
...holiday,
|
...holiday,
|
||||||
hidden: isHolidayHidden(holiday)
|
hidden: isHolidayHidden(holiday)
|
||||||
}));
|
}));
|
||||||
// Filter out hidden holidays for calculations
|
|
||||||
const visibleHolidays = holidays.filter(h => !h.hidden);
|
const visibleHolidays = holidays.filter(h => !h.hidden);
|
||||||
optimizedDaysOff = optimizeDaysOff(visibleHolidays, year, daysOff);
|
optimizedDaysOff = optimizeDaysOff(visibleHolidays, year, daysOff);
|
||||||
consecutiveDaysOff = calculateConsecutiveDaysOff(visibleHolidays, optimizedDaysOff, year);
|
consecutiveDaysOff = calculateConsecutiveDaysOff(visibleHolidays, optimizedDaysOff, year);
|
||||||
@@ -142,7 +141,6 @@
|
|||||||
localStorage.setItem('selectedState', selectedState);
|
localStorage.setItem('selectedState', selectedState);
|
||||||
localStorage.setItem('selectedStateCode', selectedStateCode);
|
localStorage.setItem('selectedStateCode', selectedStateCode);
|
||||||
localStorage.setItem('daysOff', daysOff);
|
localStorage.setItem('daysOff', daysOff);
|
||||||
updateHolidays();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleKeyDown(event) {
|
function handleKeyDown(event) {
|
||||||
@@ -665,7 +663,14 @@
|
|||||||
<div class="calendar-grid">
|
<div class="calendar-grid">
|
||||||
{#each months as month}
|
{#each months as month}
|
||||||
<div class="calendar-container">
|
<div class="calendar-container">
|
||||||
<CalendarMonth {year} {month} {holidays} {optimizedDaysOff} {consecutiveDaysOff} />
|
<CalendarMonth
|
||||||
|
year={year}
|
||||||
|
month={month}
|
||||||
|
holidays={holidays}
|
||||||
|
optimizedDaysOff={optimizedDaysOff}
|
||||||
|
consecutiveDaysOff={consecutiveDaysOff}
|
||||||
|
selectedCountryCode={selectedCountryCode}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user