import { useMemo , useState } from 'react' ; import { c } from 'ttag' ; import { fromUnixTime , getUnixTime , addDays , addHours , startOfDay } from 'date-fns' ; import { fromUTCDate , fromLocalDate , toUTCDate , convertUTCDateTimeToZone , convertZonedDateTimeToUTC , getTimezone , getTimeZoneOptions , toLocalDate , } from '@proton/shared/lib/date/timezone' ; import { AutoReplyDuration } from '@proton/shared/lib/constants' ; import { AutoResponder as tsAutoResponder } from '@proton/shared/lib/interfaces' ; import { DAY_SECONDS , HOUR_SECONDS , MINUTES_SECONDS , getDurationOptions , getMatchingTimezone } from '../utils' ; import { AutoReplyFormDate , AutoReplyFormModel } from './interfaces' ; const getDefaultFixedTimes = ( ) => ( { StartTime : getUnixTime ( new Date ( ) ) , EndTime : getUnixTime ( addHours ( addDays ( new Date ( ) , 7 ) , 2 ) ) , } ) ; export const getDefaultAutoResponder = ( AutoResponder ? ) => { const timezones = getTimeZoneOptions ( ) ; return { ... AutoResponder , Subject : 'Auto' , Message : AutoResponder ?. Message || c ( 'Autoresponse' ) . t `I'm out of the office with limited access to my email.` , Repeat : AutoReplyDuration . FIXED , DaysSelected : [ ] , IsEnabled : true , Zone : getMatchingTimezone ( getTimezone ( ) , timezones ) . value , ... getDefaultFixedTimes ( ) , } ; } ; const toDateTimes = ( unixTimestamp , timezone , repeat ) => { if ( repeat === AutoReplyDuration . PERMANENT ) { return { } ; } if ( repeat === AutoReplyDuration . FIXED ) { const zonedTime = convertUTCDateTimeToZone ( fromUTCDate ( fromUnixTime ( unixTimestamp ) ) , timezone ) ; return { date : startOfDay ( toLocalDate ( zonedTime ) ) , time : new Date ( 2000 , 0 , 1 , zonedTime . hours , zonedTime . minutes ) , } ; } const day = Math . floor ( unixTimestamp / DAY_SECONDS ) ; const secondsInDay = unixTimestamp % DAY_SECONDS ; const hours = Math . floor ( secondsInDay / HOUR_SECONDS ) ; const minutes = Math . floor ( ( secondsInDay - hours * HOUR_SECONDS ) / 60 ) ; const localTime = new Date ( 2000 , 0 , 1 , hours , minutes ) ; if ( repeat === AutoReplyDuration . DAILY ) { return { time : localTime , } ; } if ( repeat === AutoReplyDuration . MONTHLY ) { return { day : day % 31 , time : localTime , } ; } if ( repeat === AutoReplyDuration . WEEKLY ) { return { day : day % 7 , time : localTime , } ; } } ; export const getMatchingValues = ( { Zone , Repeat } ) => { const duration = getDurationOptions ( ) . find ( ( { value } ) => value === Repeat ) ; const timezones = getTimeZoneOptions ( ) ; const matchingTimezone = getMatchingTimezone ( Zone , timezones ) || getMatchingTimezone ( getTimezone ( ) , timezones ) ; return { timezone : matchingTimezone , duration , } ; } ; export const toModel = ( { Message , StartTime , EndTime , DaysSelected , Subject , IsEnabled } , { timezone , duration } ) : AutoReplyFormModel => { return { message : Message , daysOfWeek : DaysSelected , subject : Subject , enabled : IsEnabled , duration , timezone , start : toDateTimes ( StartTime , timezone , duration ) || { } , end : toDateTimes ( EndTime , timezone , duration ) || { } , } ; } ; const toUnixTime = ( { date = new Date ( ) , time = new Date ( ) , day = new Date ( ) . getDay ( ) } , timezone , repeat ) => { if ( repeat === AutoReplyDuration . PERMANENT ) { return 0 ; } const utcUnixTime = time . getHours ( ) * HOUR_SECONDS + time . getMinutes ( ) * MINUTES_SECONDS ; switch ( repeat ) { case AutoReplyDuration . FIXED : return getUnixTime ( toUTCDate ( convertZonedDateTimeToUTC ( { ... fromLocalDate ( date ) , hours : time . getHours ( ) , minutes : time . getMinutes ( ) , } , timezone ) ) ) ; case AutoReplyDuration . DAILY : return utcUnixTime ; case AutoReplyDuration . WEEKLY : return day * DAY_SECONDS + utcUnixTime ; case AutoReplyDuration . MONTHLY : return day * DAY_SECONDS + utcUnixTime ; default : return utcUnixTime ; } } ; const toAutoResponder = ( { message , duration , daysOfWeek , timezone , subject , start , end , } ) : tsAutoResponder => ( { Message : message , Repeat : duration , DaysSelected : daysOfWeek , Zone : timezone , Subject : subject , IsEnabled : true , StartTime : toUnixTime ( start , timezone , duration ) , EndTime : toUnixTime ( end , timezone , duration ) , } ) ; type UpdateFunction = ( value : number | number [ ] | string | boolean | AutoReplyFormDate , extra ? : Partial < AutoReplyFormModel > ) => void ; const useAutoReplyForm = ( AutoResponder ) => { const matches = useMemo ( ( ) => getMatchingValues ( AutoResponder ) , [ AutoResponder ] ) ; const getInitialModel = ( ) => { return toModel ( AutoResponder . IsEnabled ? AutoResponder : getDefaultAutoResponder ( AutoResponder ) , { timezone : matches . timezone ?. value , duration : matches . duration ?. value || AutoReplyDuration . FIXED , } ) ; } ; const [ model , setModel ] = useState < AutoReplyFormModel > ( getInitialModel ( ) ) ; const updateModel = ( key ) : UpdateFunction => { if ( key === 'duration' ) { return ( value ) => setModel ( { ... toModel ( { ... AutoResponder , /**
                     * When switching to fixed repeat duration, reset the start time and end time
                     * to avoid having the date be 1/1/1970
                     */ ... ( value === AutoReplyDuration . FIXED && AutoResponder . Repeat !== AutoReplyDuration . FIXED ? { ... getDefaultFixedTimes ( ) , } : undefined ) , } , { timezone : matches . timezone ?. value , duration : value as AutoReplyDuration , } ) , } ) ; } const [ a , b ] = key . split ( '.' ) ; return ( value ) => { const genericSetter = ( value , extra ? ) => setModel ( ( prev ) => ( { ... prev , [ a ] : ! b ? value : { ... prev [ a ] , [ b ] : value , } , ... extra , } ) ) ; if ( model . start . date && model . end . date && model . start . time && model . end . time ) { const valueDate = new Date ( value as string ) ; if ( key === 'start.date' ) { if ( valueDate . getTime ( ) === model . end . date . getTime ( ) && model . start . time . getTime ( ) > model . end . time . getTime ( ) ) { return genericSetter ( value , { end : { date : model . end . date , time : model . start . time } } ) ; } if ( valueDate . getTime ( ) > model . end . date . getTime ( ) ) { return genericSetter ( value , { end : { date : valueDate , time : model . start . time } } ) ; } } if ( key === 'start.time' && model . start . date . getTime ( ) === model . end . date . getTime ( ) && valueDate . getTime ( ) > model . end . time . getTime ( ) ) { return genericSetter ( value , { end : { date : model . end . date , time : valueDate } } ) ; } if ( key === 'end.date' ) { if ( valueDate . getTime ( ) === model . start . date . getTime ( ) && model . end . time . getTime ( ) < model . start . time . getTime ( ) ) { return genericSetter ( value , { end : { date : model . start . date , time : model . start . time } } ) ; } if ( valueDate . getTime ( ) < model . start . date . getTime ( ) ) { if ( model . end . time . getTime ( ) > model . start . time . getTime ( ) ) { return genericSetter ( value , { end : { date : model . start . date , time : model . start . time } } ) ; } return genericSetter ( value , { end : { date : model . start . date , time : model . end . time } } ) ; } } if ( key === 'end.time' && model . start . date . getTime ( ) === model . end . date . getTime ( ) && valueDate . getTime ( ) < model . start . time . getTime ( ) ) { return genericSetter ( value , { end : { date : model . end . date , time : model . start . time } } ) ; } } return genericSetter ( value ) ; } ; } ; return { model , toAutoResponder , updateModel , } ; } ; export default useAutoReplyForm ;