yearAndMonthFoundation.ts 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. import { setMonth, setYear } from 'date-fns';
  2. import BaseFoundation, { DefaultAdapter } from '../base/foundation';
  3. import { PresetPosition } from './foundation';
  4. import { ArrayElement } from '../utils/type';
  5. import { strings } from './constants';
  6. import { PanelType } from './monthsGridFoundation';
  7. import { cloneDeep } from 'lodash';
  8. type Type = ArrayElement<typeof strings.TYPE_SET>;
  9. export interface YearAndMonthFoundationProps {
  10. currentYear: { left: number; right: number };
  11. currentMonth: { left: number; right: number };
  12. onSelect?: (obj: { currentMonth: { left: number; right: number }; currentYear: { left: number; right: number } }) => void;
  13. onBackToMain?: () => void;
  14. locale?: any;
  15. localeCode?: string;
  16. monthCycled?: boolean;
  17. yearCycled?: boolean;
  18. noBackBtn?: boolean;
  19. disabledDate?: (date: Date) => boolean;
  20. density?: string;
  21. presetPosition?: PresetPosition;
  22. renderQuickControls?: any;
  23. renderDateInput?: any;
  24. type?: Type;
  25. yearAndMonthOpts?: any
  26. }
  27. export interface YearAndMonthFoundationState {
  28. years: Array<{ value: number; year: number }>;
  29. months: Array<{ value: number; month: number }>;
  30. currentYear: { left: number; right: number };
  31. currentMonth: { left: number; right: number }
  32. }
  33. export interface YearAndMonthAdapter extends DefaultAdapter<YearAndMonthFoundationProps, YearAndMonthFoundationState> {
  34. setCurrentYear: (currentYear: { left: number; right: number }, cb?: () => void) => void;
  35. setCurrentMonth: (currentMonth: { left: number; right: number }) => void;
  36. setCurrentYearAndMonth: (currentYear: { left: number; right: number }, currentMonth: { left: number; right: number }) => void;
  37. notifySelectYear: (year: { left: number; right: number }) => void;
  38. notifySelectMonth: (month: { left: number; right: number }) => void;
  39. notifySelectYearAndMonth: (year: { left: number; right: number }, month: { left: number; right: number }) => void;
  40. notifyBackToMain: () => void
  41. }
  42. export interface MonthScrollItem {
  43. [k: string]: any;
  44. month: number;
  45. value: string;
  46. disabled: boolean
  47. }
  48. export interface YearScrollItem {
  49. [k: string]: any;
  50. year: number;
  51. value: number;
  52. disabled: boolean
  53. }
  54. export default class YearAndMonthFoundation extends BaseFoundation<YearAndMonthAdapter> {
  55. constructor(adapter: YearAndMonthAdapter) {
  56. super({ ...adapter });
  57. }
  58. // eslint-disable-next-line @typescript-eslint/no-empty-function
  59. init() {}
  60. // eslint-disable-next-line @typescript-eslint/no-empty-function
  61. destroy() {}
  62. selectYear(item: YearScrollItem, panelType?: PanelType) {
  63. // const year = item.value;
  64. const { currentYear, currentMonth } = this.getStates();
  65. const { type } = this.getProps();
  66. const left = strings.PANEL_TYPE_LEFT;
  67. const right = strings.PANEL_TYPE_RIGHT;
  68. const year = cloneDeep(currentYear);
  69. year[panelType] = item.value;
  70. // make sure the right panel time is always less than the left panel time
  71. if (type === 'monthRange') {
  72. const isSameYearIllegalDate = year[left] === year[right] && currentMonth[left] > currentMonth[right];
  73. if ((panelType === left && item.value > year[right]) || (panelType === left && isSameYearIllegalDate)) {
  74. // 1. select left year and left year > right year
  75. // 2. select left year, left year = right year, but left date > right date
  76. year[right] = item.value + 1;
  77. } else if (panelType === right && isSameYearIllegalDate) {
  78. // 1. select right year, left year = right year, but left date > right date
  79. year[left] = item.value - 1;
  80. }
  81. }
  82. this._adapter.setCurrentYear(year, () => this.autoSelectMonth(item, panelType, year));
  83. this._adapter.notifySelectYear(year);
  84. }
  85. selectMonth(item: MonthScrollItem, panelType?: PanelType) {
  86. const { currentMonth, currentYear } = this.getStates();
  87. const { type } = this.getProps();
  88. const left = strings.PANEL_TYPE_LEFT;
  89. const right = strings.PANEL_TYPE_RIGHT;
  90. const month = cloneDeep(currentMonth);
  91. month[panelType] = item.month;
  92. // make sure the right panel time is always less than the left panel time
  93. if (type === 'monthRange' && panelType === left && currentYear[left] === currentYear[right] && item.value > month[right]) {
  94. month[right] = item.month + 1;
  95. }
  96. this._adapter.setCurrentMonth(month);
  97. this._adapter.notifySelectMonth(month);
  98. }
  99. /**
  100. * After selecting a year, if the currentMonth is disabled, automatically select a non-disabled month
  101. */
  102. autoSelectMonth(item: YearScrollItem, panelType: PanelType, year: { left: number; right: number }) {
  103. const { disabledDate, locale } = this._adapter.getProps();
  104. const { months, currentMonth } = this._adapter.getStates();
  105. const currentDate = setYear(Date.now(), item.year);
  106. const isCurrentMonthDisabled = disabledDate(setMonth(currentDate, currentMonth[panelType] - 1));
  107. if (isCurrentMonthDisabled) {
  108. const currentIndex = months.findIndex(({ month }) => month === currentMonth[panelType]);
  109. let validMonth: typeof months[number];
  110. // First look in the back, if you can't find it in the back, then look in the front
  111. validMonth = months.slice(currentIndex).find(({ month }) => !disabledDate(setMonth(currentDate, month - 1)));
  112. if (!validMonth) {
  113. validMonth = months.slice(0, currentIndex).find(({ month }) => !disabledDate(setMonth(currentDate, month - 1)));
  114. }
  115. if (validMonth) {
  116. const month = cloneDeep(currentMonth);
  117. month[panelType] = validMonth.month;
  118. // change year and month same time
  119. this._adapter.setCurrentYearAndMonth(year, month);
  120. this._adapter.notifySelectYearAndMonth(year, month);
  121. }
  122. }
  123. }
  124. backToMain() {
  125. this._adapter.notifyBackToMain();
  126. }
  127. }