You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			160 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			TypeScript
		
	
			
		
		
	
	
			160 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			TypeScript
		
	
| import moment from 'moment';
 | |
| import { compact, groupBy, sortBy } from 'lodash';
 | |
| 
 | |
| import { MediaItemType } from '../../LightboxGallery';
 | |
| 
 | |
| // import { missingCaseError } from '../../../util/missingCaseError';
 | |
| 
 | |
| type StaticSectionType = 'today' | 'yesterday' | 'thisWeek' | 'thisMonth';
 | |
| type YearMonthSectionType = 'yearMonth';
 | |
| 
 | |
| interface GenericSection<T> {
 | |
|   type: T;
 | |
|   mediaItems: Array<MediaItemType>;
 | |
| }
 | |
| type StaticSection = GenericSection<StaticSectionType>;
 | |
| type YearMonthSection = GenericSection<YearMonthSectionType> & {
 | |
|   year: number;
 | |
|   month: number;
 | |
| };
 | |
| export type Section = StaticSection | YearMonthSection;
 | |
| export const groupMediaItemsByDate = (
 | |
|   timestamp: number,
 | |
|   mediaItems: Array<MediaItemType>
 | |
| ): Array<Section> => {
 | |
|   const referenceDateTime = moment.utc(timestamp);
 | |
| 
 | |
|   const sortedMediaItem = sortBy(mediaItems, mediaItem => {
 | |
|     const { message } = mediaItem;
 | |
| 
 | |
|     return -message.received_at;
 | |
|   });
 | |
|   const messagesWithSection = sortedMediaItem.map(
 | |
|     withSection(referenceDateTime)
 | |
|   );
 | |
|   const groupedMediaItem = groupBy(messagesWithSection, 'type');
 | |
|   const yearMonthMediaItem = Object.values(
 | |
|     groupBy(groupedMediaItem.yearMonth, 'order')
 | |
|   ).reverse();
 | |
| 
 | |
|   return compact([
 | |
|     toSection(groupedMediaItem.today),
 | |
|     toSection(groupedMediaItem.yesterday),
 | |
|     toSection(groupedMediaItem.thisWeek),
 | |
|     toSection(groupedMediaItem.thisMonth),
 | |
|     ...yearMonthMediaItem.map(toSection),
 | |
|   ]);
 | |
| };
 | |
| 
 | |
| const toSection = (
 | |
|   messagesWithSection: Array<MediaItemWithSection> | undefined
 | |
| ): Section | undefined => {
 | |
|   if (!messagesWithSection || messagesWithSection.length === 0) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   const firstMediaItemWithSection: MediaItemWithSection =
 | |
|     messagesWithSection[0];
 | |
|   if (!firstMediaItemWithSection) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   const mediaItems = messagesWithSection.map(
 | |
|     messageWithSection => messageWithSection.mediaItem
 | |
|   );
 | |
|   switch (firstMediaItemWithSection.type) {
 | |
|     case 'today':
 | |
|     case 'yesterday':
 | |
|     case 'thisWeek':
 | |
|     case 'thisMonth':
 | |
|       return {
 | |
|         type: firstMediaItemWithSection.type,
 | |
|         mediaItems,
 | |
|       };
 | |
|     case 'yearMonth':
 | |
|       return {
 | |
|         type: firstMediaItemWithSection.type,
 | |
|         year: firstMediaItemWithSection.year,
 | |
|         month: firstMediaItemWithSection.month,
 | |
|         mediaItems,
 | |
|       };
 | |
|     default:
 | |
|       // NOTE: Investigate why we get the following error:
 | |
|       // error TS2345: Argument of type 'any' is not assignable to parameter
 | |
|       // of type 'never'.
 | |
|       // return missingCaseError(firstMediaItemWithSection.type);
 | |
|       return;
 | |
|   }
 | |
| };
 | |
| 
 | |
| interface GenericMediaItemWithSection<T> {
 | |
|   order: number;
 | |
|   type: T;
 | |
|   mediaItem: MediaItemType;
 | |
| }
 | |
| type MediaItemWithStaticSection = GenericMediaItemWithSection<
 | |
|   StaticSectionType
 | |
| >;
 | |
| type MediaItemWithYearMonthSection = GenericMediaItemWithSection<
 | |
|   YearMonthSectionType
 | |
| > & {
 | |
|   year: number;
 | |
|   month: number;
 | |
| };
 | |
| type MediaItemWithSection =
 | |
|   | MediaItemWithStaticSection
 | |
|   | MediaItemWithYearMonthSection;
 | |
| 
 | |
| const withSection = (referenceDateTime: moment.Moment) => (
 | |
|   mediaItem: MediaItemType
 | |
| ): MediaItemWithSection => {
 | |
|   const today = moment(referenceDateTime).startOf('day');
 | |
|   const yesterday = moment(referenceDateTime)
 | |
|     .subtract(1, 'day')
 | |
|     .startOf('day');
 | |
|   const thisWeek = moment(referenceDateTime).startOf('isoWeek');
 | |
|   const thisMonth = moment(referenceDateTime).startOf('month');
 | |
| 
 | |
|   const { message } = mediaItem;
 | |
|   const mediaItemReceivedDate = moment.utc(message.received_at);
 | |
|   if (mediaItemReceivedDate.isAfter(today)) {
 | |
|     return {
 | |
|       order: 0,
 | |
|       type: 'today',
 | |
|       mediaItem,
 | |
|     };
 | |
|   }
 | |
|   if (mediaItemReceivedDate.isAfter(yesterday)) {
 | |
|     return {
 | |
|       order: 1,
 | |
|       type: 'yesterday',
 | |
|       mediaItem,
 | |
|     };
 | |
|   }
 | |
|   if (mediaItemReceivedDate.isAfter(thisWeek)) {
 | |
|     return {
 | |
|       order: 2,
 | |
|       type: 'thisWeek',
 | |
|       mediaItem,
 | |
|     };
 | |
|   }
 | |
|   if (mediaItemReceivedDate.isAfter(thisMonth)) {
 | |
|     return {
 | |
|       order: 3,
 | |
|       type: 'thisMonth',
 | |
|       mediaItem,
 | |
|     };
 | |
|   }
 | |
| 
 | |
|   const month: number = mediaItemReceivedDate.month();
 | |
|   const year: number = mediaItemReceivedDate.year();
 | |
| 
 | |
|   return {
 | |
|     order: year * 100 + month,
 | |
|     type: 'yearMonth',
 | |
|     month,
 | |
|     year,
 | |
|     mediaItem,
 | |
|   };
 | |
| };
 |