import { Location } from 'history' ; import { formatRelative , format } from 'date-fns' ; import { toMap , omit } from '@proton/shared/lib/helpers/object' ; import { Label , LabelCount } from '@proton/shared/lib/interfaces/Label' ; import { diff , unique } from '@proton/shared/lib/helpers/array' ; import { MAILBOX_LABEL_IDS } from '@proton/shared/lib/constants' ; import { MailSettings } from '@proton/shared/lib/interfaces' ; import { Message } from '@proton/shared/lib/interfaces/mail/Message' ; import { hasAttachments as messageHasAttachments } from '@proton/shared/lib/mail/messages' ; import { Folder } from '@proton/shared/lib/interfaces/Folder' ; import { ELEMENT_TYPES } from '../constants' ; import { Element } from '../models/element' ; import { Sort , SearchParameters , Filter } from '../models/tools' ; import { isConversationMode } from './mailSettings' ; import { isUnread as conversationIsUnread , hasAttachments as conversationHasAttachments , getNumAttachments as conversationNumAttachments , getLabelIDs as conversationGetLabelIDs , getTime as conversationGetTime , } from './conversation' ; import { LabelIDsChanges } from '../models/event' ; import { Conversation } from '../models/conversation' ; const { INBOX , TRASH , SPAM , ARCHIVE , SCHEDULED } = MAILBOX_LABEL_IDS ; export interface TypeParams { labelID ? : string ; mailSettings ? : any ; location : Location ; } export const getCurrentType = ( { labelID , mailSettings , location } ) => isConversationMode ( labelID , mailSettings , location ) ? ELEMENT_TYPES . CONVERSATION : ELEMENT_TYPES . MESSAGE ; export const isMessage = ( element ) : boolean => typeof ( element as Message ) ?. ConversationID === 'string' ; export const isConversation = ( element ) : boolean => ! isMessage ( element ) ; param element param labelID export const getDate = ( element , labelID ) => { if ( ! element ) { return new Date ( ) ; } const time = isMessage ( element ) ? element . Time : conversationGetTime ( element , labelID ) ; return new Date ( ( time || 0 ) * 1000 ) ; } ; param element . Time return export const getReadableTime = ( element , labelID ) => formatRelative ( getDate ( element , labelID ) , new Date ( ) ) ; export const getReadableFullTime = ( element , labelID ) => format ( getDate ( element , labelID ) , 'Ppp' ) ; param element param labelID export const isUnread = ( element , labelID ) => { if ( ! element ) { return false ; } if ( isMessage ( element ) ) { return ( element as Message ) . Unread !== 0 ; } return conversationIsUnread ( element as Conversation , labelID ) ; } ; export const isUnreadMessage = ( message ) => isUnread ( message , undefined ) ; export const getLabelIDs = ( element , contextLabelID ) => isMessage ( element ) ? ( element as Message | undefined ) ?. LabelIDs ?. reduce < { [ labelID ] : boolean | undefined ; } > ( ( acc , labelID ) => { acc [ labelID ] = true ; return acc ; } , { } ) || { } : conversationGetLabelIDs ( element , contextLabelID ) ; export const hasLabel = ( element , labelID ) => getLabelIDs ( element , undefined ) [ labelID ] !== undefined ; export const isStarred = ( element ) => hasLabel ( element , MAILBOX_LABEL_IDS . STARRED ) ; export const getSize = ( element ) => element . Size || 0 ; export const sort = ( elements , sort , labelID ) => { const getValue = { Time : ( element , labelID ) => getDate ( element , labelID ) . getTime ( ) , Size : getSize , } [ sort . sort ] as any ; const compare = ( a , b ) => { let valueA = getValue ( a , labelID ) ; let valueB = getValue ( b , labelID ) ; if ( valueA === valueB && sort . sort === 'Time' ) { valueA = a . Order || 0 ; valueB = b . Order || 0 ; } return sort . desc ? valueB - valueA : valueA - valueB ; } ; return [ ... elements ] . sort ( ( e1 , e2 ) => compare ( e1 , e2 ) ) ; } ; export const getCounterMap = ( labels , conversationCounters , messageCounters , mailSettings , location ) => { const labelIDs = [ ... Object . values ( MAILBOX_LABEL_IDS ) , ... labels . map ( ( label ) => label . ID || '' ) ] ; const conversationCountersMap = toMap ( conversationCounters , 'LabelID' ) as { [ labelID ] : LabelCount ; } ; const messageCountersMap = toMap ( messageCounters , 'LabelID' ) as { [ labelID ] : LabelCount ; } ; return labelIDs . reduce < { [ labelID ] : LabelCount | undefined ; } > ( ( acc , labelID ) => { const conversationMode = isConversationMode ( labelID , mailSettings , location ) ; const countersMap = conversationMode ? conversationCountersMap : messageCountersMap ; acc [ labelID ] = countersMap [ labelID ] ; return acc ; } , { } ) ; } ; export const hasAttachments = ( element ) => isMessage ( element ) ? messageHasAttachments ( element as Message ) : conversationHasAttachments ( element ) ; export const getNumAttachments = ( element ) => isMessage ( element ) ? ( element as Message ) ?. NumAttachments || 0 : conversationNumAttachments ( element ) ; /**
 * Starting from the element LabelIDs list, add and remove labels from an event manager event
 */ export const parseLabelIDsInEvent = < T extends Element > ( element , changes ) : T => { const omitted = omit ( changes , [ 'LabelIDsRemoved' , 'LabelIDsAdded' ] ) ; if ( isMessage ( element ) ) { if ( omitted ?. LabelIDs ) { return { ... element , ... omitted } ; } const LabelIDs = unique ( diff ( ( element as Message ) . LabelIDs || [ ] , changes . LabelIDsRemoved || [ ] ) . concat ( changes . LabelIDsAdded || [ ] ) ) ; return { ... element , ... omitted , LabelIDs } ; } return { ... element , ... omitted } ; } ; export const isSearch = ( searchParams ) => ! ! searchParams . address || searchParams . attachments !== undefined || ! ! searchParams . begin || ! ! searchParams . end || ! ! searchParams . from || ! ! searchParams . keyword || ! ! searchParams . to || ! ! searchParams . wildcard ; export const isFilter = ( filter ) => Object . keys ( filter ) . length > 0 ; /**
 * Get the IDs of the folder where the element is currently located
 */ export const getCurrentFolderIDs = ( element , customFoldersList ) : string [ ] => { const labelIDs = getLabelIDs ( element , undefined ) ; const standardFolders = { [ INBOX ] : true , [ TRASH ] : true , [ SPAM ] : true , [ ARCHIVE ] : true , [ SCHEDULED ] : true , } ; const customFolders = toMap ( customFoldersList , 'ID' ) ; return Object . keys ( labelIDs ) . filter ( ( labelID ) => standardFolders [ labelID ] || customFolders [ labelID ] ) || '' ; } ;