/** * Copyright (C) Paul Sarando * Distributed under the Eclipse Public License (http://www.eclipse.org/legal/epl-v10.html). */ import React from "react"; import { GondorCalendarYear, GondorDate, GondorHolidays, GondorMonths, GondorWeekdays, GondorLeapYearRuleEnum, GondorReckoningEnum, makeGondorCalendarDates, } from "../GondorReckoning"; import { datesMatch, fullYearDate } from "../Utils"; import DateCell, { dateKey } from "./DateCell"; import IntercalaryDay from "./IntercalaryDay"; import WeekDayHeaderCell, { addMonthFiller, addVerticalMonthFiller, } from "./WeekDayHeaderCell"; import "./tolkien-calendars.css"; import { LanguageEnum } from "./controls/LanguagePicker"; import { MonthLayoutEnum, VerticalLayoutFiller, } from "./controls/MonthViewLayout"; interface GondorCalendarProps { caption?: string | boolean; className?: string; language?: LanguageEnum; monthView?: number; monthViewLayout?: MonthLayoutEnum; startDay?: number; yearView?: boolean; date?: Date; startDate?: Date; reckoning?: GondorReckoningEnum; calendarRules?: GondorLeapYearRuleEnum; calendar?: GondorCalendarYear; } interface GondorDateProps { date: GondorDate; today: Date; language: LanguageEnum; reckoning: GondorReckoningEnum; } interface GondorYearProps { dates: GondorDate[]; today: Date; language: LanguageEnum; reckoning: GondorReckoningEnum; } interface GondorMonthProps extends GondorYearProps { monthView: number; } const defaultCaption = (reckoning: GondorReckoningEnum) => { switch (reckoning) { case GondorReckoningEnum.KINGS: return "Kings' Reckoning"; case GondorReckoningEnum.STEWARDS: return "Stewards' Reckoning"; case GondorReckoningEnum.NEW: return "New Reckoning"; default: // should never happen return "Gondor Reckoning"; } }; const getDateColor = ( reckoning: GondorReckoningEnum, date: GondorDate, monthColor: string ) => { if (date.className !== undefined) { return date.className; } if ( reckoning === GondorReckoningEnum.NEW && date.month === 5 && date.day === 30 ) { return "holiday"; } return monthColor; }; const GondorDateCell = ({ date, today, language, reckoning, }: GondorDateProps) => { switch (date.day) { case "Yestarë": case "Tuilérë": case "Cormarë": case "Loëndë": case "Enderë": case "Yáviérë": case "Mettarë": const holiday = GondorHolidays[date.day]; return ( ); default: const startMonth = reckoning === GondorReckoningEnum.NEW ? 3 : 0; const month = GondorMonths[(date.month + startMonth) % 12]; const weekday = GondorWeekdays[date.weekDay]; const className = getDateColor(reckoning, date, month.className); return ( ); } }; const GondorMonth = ({ monthView, dates, today, language, reckoning, }: GondorMonthProps) => { const weeks: React.JSX.Element[] = []; let week: React.JSX.Element[] = []; let i = 0, date = dates[i], endere = 1; for (; i < dates.length && date.month !== monthView; i++, date = dates[i]) { // seek ahead to current month view } addMonthFiller(week, date.weekDay); for (; i < dates.length && monthView === date.month; i++, date = dates[i]) { week.push( ); if (date.weekDay === 6) { weeks.push({week}); week = []; } } switch (monthView) { case 2: if (date.day === "Tuilérë") { week.push( ); } break; case 5: date = dates[i]; for ( ; date.day === "Enderë" || date.day === "Loëndë"; i++, date = dates[i] ) { week.push( ); if (date.weekDay === 6) { weeks.push({week}); week = []; } } break; case 8: if (date.day === "Yáviérë") { week.push( ); } break; default: break; } if (week.length > 0) { weeks.push({week}); } return weeks; }; const GondorMonthVertical = ({ monthView, dates, today, language, reckoning, }: GondorMonthProps) => { let weeks = GondorWeekdays.map(function (weekday) { const weekdayName = weekday[language]; return [ , ]; }); let i = 0, date = dates[i], endere = 1; for (; i < dates.length && date.month !== monthView; i++, date = dates[i]) { // seek ahead to current month view } addVerticalMonthFiller(weeks, date.weekDay); for (; i < dates.length && monthView === date.month; i++, date = dates[i]) { weeks[date.weekDay].push( ); } switch (monthView) { case 2: if (date.day === "Tuilérë") { weeks[date.weekDay].push( ); } break; case 5: date = dates[i]; for ( ; date.day === "Enderë" || date.day === "Loëndë"; i++, date = dates[i] ) { weeks[date.weekDay].push( ); } break; case 8: if (date.day === "Yáviérë") { weeks[date.weekDay].push( ); } break; default: break; } if (weeks[0].length > 6) { weeks = GondorWeekdays.map(function (weekday, i) { const week = weeks[i]; const weekdayName = weekday[language]; week.shift(); week.unshift( ); return week; }); } return weeks.map(function (week, i) { return {week}; }); }; const GondorYear = ({ dates, today, language, reckoning }: GondorYearProps) => { const weeks: React.JSX.Element[] = []; let week: React.JSX.Element[] = [], endere = 1; addMonthFiller(week, dates[0].weekDay); for (let i = 0, date = dates[i]; i < dates.length; i++, date = dates[i]) { week.push( ); if (date.weekDay === 6) { weeks.push({week}); week = []; } } if (week.length > 0) { weeks.push({week}); } return weeks; }; const GondorCalendar = (props: GondorCalendarProps) => { const { caption, className, language = LanguageEnum.QUENYA, monthViewLayout = MonthLayoutEnum.VERTICAL, startDay = 21, yearView = false, } = props; const nextDate = props.date || new Date(); const [today, setToday] = React.useState(nextDate); const nextStartDate = props.startDate || fullYearDate(0, 11, startDay); const [startDate, setStartDate] = React.useState(nextStartDate); const nextReckoning = props.reckoning || GondorReckoningEnum.STEWARDS; const [reckoning, setReckoning] = React.useState(nextReckoning); const nextRules = props.calendarRules || GondorLeapYearRuleEnum.GREGORIAN; const [calendarRules, setCalendarRules] = React.useState(nextRules); const [calendar, setCalendar] = React.useState( () => props.calendar || makeGondorCalendarDates( today, startDate, reckoning, calendarRules ) ); const updateToday = !datesMatch(today, nextDate); if (updateToday) { setToday(nextDate); } const updateStartDate = !datesMatch(startDate, nextStartDate); if (updateStartDate) { setStartDate(nextStartDate); } const updateReckoning = reckoning !== nextReckoning; if (updateReckoning) { setReckoning(nextReckoning); } const updateRules = calendarRules !== nextRules; if (updateRules) { setCalendarRules(nextRules); } const updateCalendar = props.calendar && props.calendar !== calendar; if ( updateCalendar || updateToday || updateStartDate || updateReckoning || updateRules ) { setCalendar( props.calendar || makeGondorCalendarDates( nextDate, nextStartDate, nextReckoning, nextRules ) ); } const { dates, todayGondor } = calendar; const monthView = props.monthView === undefined ? todayGondor.month : props.monthView; return ( {caption && ( )} {monthViewLayout === MonthLayoutEnum.VERTICAL && !yearView ? ( ) : ( {GondorWeekdays.map(function (weekday) { const weekdayName = weekday[language]; return ( ); })} )} {yearView ? ( ) : monthViewLayout === MonthLayoutEnum.VERTICAL ? ( ) : ( )}
{caption === true ? defaultCaption(reckoning) : caption}
); }; GondorCalendar.RECKONING_KINGS = GondorReckoningEnum.KINGS; GondorCalendar.RECKONING_STEWARDS = GondorReckoningEnum.STEWARDS; GondorCalendar.RECKONING_NEW = GondorReckoningEnum.NEW; GondorCalendar.RECKONING_RULES_TRADITIONAL = GondorLeapYearRuleEnum.TRADITIONAL; GondorCalendar.RECKONING_RULES_GREGORIAN = GondorLeapYearRuleEnum.GREGORIAN; GondorCalendar.MONTH_VIEW_VERTICAL = MonthLayoutEnum.VERTICAL; GondorCalendar.MONTH_VIEW_HORIZONTAL = MonthLayoutEnum.HORIZONTAL; GondorCalendar.LANGUAGE_ENGLISH = LanguageEnum.ENGLISH; GondorCalendar.LANGUAGE_QUENYA = LanguageEnum.QUENYA; GondorCalendar.LANGUAGE_SINDARIN = LanguageEnum.SINDARIN; export default GondorCalendar; export { defaultCaption };