133 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
			
		
		
	
	
			133 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
| import type { RangeValue, PickerMode } from '../interface';
 | |
| import type { GenerateConfig } from '../generate';
 | |
| import { getValue, updateValues } from '../utils/miscUtil';
 | |
| import { getClosingViewDate, isSameYear, isSameMonth, isSameDecade } from '../utils/dateUtil';
 | |
| import type { Ref } from 'vue';
 | |
| import { watch, computed, ref } from 'vue';
 | |
| 
 | |
| function getStartEndDistance<DateType>(
 | |
|   startDate: DateType,
 | |
|   endDate: DateType,
 | |
|   picker: PickerMode,
 | |
|   generateConfig: GenerateConfig<DateType>,
 | |
| ): 'same' | 'closing' | 'far' {
 | |
|   const startNext = getClosingViewDate(startDate, picker, generateConfig, 1);
 | |
| 
 | |
|   function getDistance(compareFunc: (start: DateType | null, end: DateType | null) => boolean) {
 | |
|     if (compareFunc(startDate, endDate)) {
 | |
|       return 'same';
 | |
|     }
 | |
|     if (compareFunc(startNext, endDate)) {
 | |
|       return 'closing';
 | |
|     }
 | |
|     return 'far';
 | |
|   }
 | |
| 
 | |
|   switch (picker) {
 | |
|     case 'year':
 | |
|       return getDistance((start, end) => isSameDecade(generateConfig, start, end));
 | |
|     case 'quarter':
 | |
|     case 'month':
 | |
|       return getDistance((start, end) => isSameYear(generateConfig, start, end));
 | |
|     default:
 | |
|       return getDistance((start, end) => isSameMonth(generateConfig, start, end));
 | |
|   }
 | |
| }
 | |
| 
 | |
| function getRangeViewDate<DateType>(
 | |
|   values: RangeValue<DateType>,
 | |
|   index: 0 | 1,
 | |
|   picker: PickerMode,
 | |
|   generateConfig: GenerateConfig<DateType>,
 | |
| ): DateType | null {
 | |
|   const startDate = getValue(values, 0);
 | |
|   const endDate = getValue(values, 1);
 | |
| 
 | |
|   if (index === 0) {
 | |
|     return startDate;
 | |
|   }
 | |
| 
 | |
|   if (startDate && endDate) {
 | |
|     const distance = getStartEndDistance(startDate, endDate, picker, generateConfig);
 | |
|     switch (distance) {
 | |
|       case 'same':
 | |
|         return startDate;
 | |
|       case 'closing':
 | |
|         return startDate;
 | |
|       default:
 | |
|         return getClosingViewDate(endDate, picker, generateConfig, -1);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return startDate;
 | |
| }
 | |
| 
 | |
| export default function useRangeViewDates<DateType>({
 | |
|   values,
 | |
|   picker,
 | |
|   defaultDates,
 | |
|   generateConfig,
 | |
| }: {
 | |
|   values: Ref<RangeValue<DateType>>;
 | |
|   picker: Ref<PickerMode>;
 | |
|   defaultDates: RangeValue<DateType> | undefined;
 | |
|   generateConfig: Ref<GenerateConfig<DateType>>;
 | |
| }): [Ref<DateType>, Ref<DateType>, (viewDate: DateType | null, index: 0 | 1) => void] {
 | |
|   const defaultViewDates = ref<[DateType | null, DateType | null]>([
 | |
|     getValue(defaultDates, 0),
 | |
|     getValue(defaultDates, 1),
 | |
|   ]);
 | |
|   const viewDates = ref<RangeValue<DateType>>(null);
 | |
|   const startDate = computed(() => getValue(values.value, 0));
 | |
|   const endDate = computed(() => getValue(values.value, 1));
 | |
| 
 | |
|   const getViewDate = (index: 0 | 1): DateType => {
 | |
|     // If set default view date, use it
 | |
|     if (defaultViewDates.value[index]) {
 | |
|       return defaultViewDates.value[index]! as DateType;
 | |
|     }
 | |
| 
 | |
|     return (
 | |
|       (getValue(viewDates.value, index) as any) ||
 | |
|       getRangeViewDate(values.value, index, picker.value, generateConfig.value) ||
 | |
|       startDate.value ||
 | |
|       endDate.value ||
 | |
|       generateConfig.value.getNow()
 | |
|     );
 | |
|   };
 | |
| 
 | |
|   const startViewDate = ref(null);
 | |
| 
 | |
|   const endViewDate = ref(null);
 | |
|   watch(
 | |
|     viewDates,
 | |
|     () => {
 | |
|       startViewDate.value = getViewDate(0);
 | |
|       endViewDate.value = getViewDate(1);
 | |
|     },
 | |
|     { immediate: true },
 | |
|   );
 | |
| 
 | |
|   function setViewDate(viewDate: DateType | null, index: 0 | 1) {
 | |
|     if (viewDate) {
 | |
|       let newViewDates = updateValues(viewDates.value, viewDate as any, index);
 | |
|       // Set view date will clean up default one
 | |
|       // Should always be an array
 | |
|       defaultViewDates.value = updateValues(defaultViewDates.value, null, index) || [null, null];
 | |
| 
 | |
|       // Reset another one when not have value
 | |
|       const anotherIndex = (index + 1) % 2;
 | |
|       if (!getValue(values.value, anotherIndex)) {
 | |
|         newViewDates = updateValues(newViewDates, viewDate, anotherIndex);
 | |
|       }
 | |
| 
 | |
|       viewDates.value = newViewDates;
 | |
|     } else if (startDate.value || endDate.value) {
 | |
|       // Reset all when has values when `viewDate` is `null` which means from open trigger
 | |
|       viewDates.value = null;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return [startViewDate, endViewDate, setViewDate];
 | |
| }
 |