diff --git a/src/bundles/extra.ts b/src/bundles/extra.ts index fed2f2a1c..241614bd8 100644 --- a/src/bundles/extra.ts +++ b/src/bundles/extra.ts @@ -4,6 +4,7 @@ export { default as ForwardPicker } from '../components/main/ForwardPicker'; export { default as Errors } from '../components/main/Errors'; export { default as Notifications } from '../components/main/Notifications'; export { default as SafeLinkModal } from '../components/main/SafeLinkModal'; +export { default as HistoryCalendar } from '../components/main/HistoryCalendar'; export { default as CalendarModal } from '../components/common/CalendarModal'; export { default as DeleteMessageModal } from '../components/common/DeleteMessageModal'; diff --git a/src/components/main/HistoryCalendar.async.tsx b/src/components/main/HistoryCalendar.async.tsx new file mode 100644 index 000000000..830846bb9 --- /dev/null +++ b/src/components/main/HistoryCalendar.async.tsx @@ -0,0 +1,16 @@ +import React, { FC, memo } from '../../lib/teact/teact'; +import { Bundles } from '../../util/moduleLoader'; + +import { OwnProps } from './HistoryCalendar'; + +import useModuleLoader from '../../hooks/useModuleLoader'; + +const HistoryCalendarAsync: FC = (props) => { + const { isOpen } = props; + const HistoryCalendar = useModuleLoader(Bundles.Extra, 'HistoryCalendar', !isOpen); + + // eslint-disable-next-line react/jsx-props-no-spreading + return HistoryCalendar ? : undefined; +}; + +export default memo(HistoryCalendarAsync); diff --git a/src/components/main/HistoryCalendar.tsx b/src/components/main/HistoryCalendar.tsx new file mode 100644 index 000000000..1c44b58d9 --- /dev/null +++ b/src/components/main/HistoryCalendar.tsx @@ -0,0 +1,52 @@ +import React, { FC, memo, useCallback } from '../../lib/teact/teact'; +import { withGlobal } from '../../lib/teact/teactn'; + +import { GlobalActions } from '../../global/types'; + +import { pick } from '../../util/iteratees'; +import useLang from '../../hooks/useLang'; + +import CalendarModal from '../common/CalendarModal'; + +export type OwnProps = { + isOpen: boolean; +}; + +type StateProps = { + selectedAt?: number; +}; + +type DispatchProps = Pick; + +const HistoryCalendar: FC = ({ + isOpen, selectedAt, searchMessagesByDate, closeHistoryCalendar, +}) => { + const handleJumpToDate = useCallback((date: Date) => { + searchMessagesByDate({ timestamp: date.valueOf() / 1000 }); + closeHistoryCalendar(); + }, [closeHistoryCalendar, searchMessagesByDate]); + + const lang = useLang(); + + return ( + + ); +}; + +export default memo(withGlobal( + (global): StateProps => { + return { + selectedAt: global.historyCalendarSelectedAt, + }; + }, + (setGlobal, actions): DispatchProps => pick(actions, [ + 'searchMessagesByDate', 'closeHistoryCalendar', + ]), +)(HistoryCalendar)); diff --git a/src/components/main/Main.tsx b/src/components/main/Main.tsx index 3b5cd205e..0ea6a46db 100644 --- a/src/components/main/Main.tsx +++ b/src/components/main/Main.tsx @@ -30,6 +30,7 @@ import Notifications from './Notifications.async'; import Errors from './Errors.async'; import ForwardPicker from './ForwardPicker.async'; import SafeLinkModal from './SafeLinkModal.async'; +import HistoryCalendar from './HistoryCalendar.async'; import './Main.scss'; @@ -44,6 +45,7 @@ type StateProps = { hasErrors: boolean; audioMessage?: ApiMessage; safeLinkModalUrl?: string; + isHistoryCalendarOpen: boolean; }; type DispatchProps = Pick; @@ -58,7 +60,6 @@ let DEBUG_isLogged = false; const Main: FC = ({ lastSyncTime, - loadAnimatedEmojis, isLeftColumnShown, isRightColumnShown, isMediaViewerOpen, @@ -68,6 +69,8 @@ const Main: FC = ({ hasErrors, audioMessage, safeLinkModalUrl, + isHistoryCalendarOpen, + loadAnimatedEmojis, }) => { if (DEBUG && !DEBUG_isLogged) { DEBUG_isLogged = true; @@ -171,6 +174,7 @@ const Main: FC = ({ {audioMessage && } + ); }; @@ -206,6 +210,7 @@ export default memo(withGlobal( hasErrors: Boolean(global.errors.length), audioMessage, safeLinkModalUrl: global.safeLinkModalUrl, + isHistoryCalendarOpen: Boolean(global.historyCalendarSelectedAt), }; }, (setGlobal, actions): DispatchProps => pick(actions, ['loadAnimatedEmojis']), diff --git a/src/components/middle/MessageList.scss b/src/components/middle/MessageList.scss index 52731f9b5..37cef9eae 100644 --- a/src/components/middle/MessageList.scss +++ b/src/components/middle/MessageList.scss @@ -186,11 +186,23 @@ body:not(.is-scrolling-messages) &.stuck { opacity: 0; + + span { + pointer-events: none; + } } body.animation-level-0 & { transition: none; } + + &.interactive { + cursor: pointer; + } + + span { + pointer-events: auto; + } } &.scrolled .sticky-date { diff --git a/src/components/middle/MessageList.tsx b/src/components/middle/MessageList.tsx index 3a6afcef5..11a394213 100644 --- a/src/components/middle/MessageList.tsx +++ b/src/components/middle/MessageList.tsx @@ -22,7 +22,8 @@ import { selectScrollOffset, selectThreadTopMessageId, selectFirstMessageId, - selectScheduledMessages, selectCurrentMessageIds, + selectScheduledMessages, + selectCurrentMessageIds, } from '../../modules/selectors'; import { getMessageOriginalId, @@ -92,7 +93,7 @@ type StateProps = { }; type DispatchProps = Pick; const BOTTOM_THRESHOLD = 100; @@ -138,6 +139,7 @@ const MessageList: FC = ({ botDescription, threadTopMessageId, hasLinkedChat, + openHistoryCalendar, }) => { // eslint-disable-next-line no-null/no-null const containerRef = useRef(null); @@ -557,9 +559,10 @@ const MessageList: FC = ({ type, threadTopMessageId, threadFirstMessageId, - hasLinkedChat, + Boolean(hasLinkedChat), messageGroups ? type === 'scheduled' : false, !messageGroups || !shouldAnimateAppearanceRef.current, + openHistoryCalendar, )} ) : ( @@ -580,11 +583,12 @@ function renderMessages( memoFirstUnreadIdRef: { current: number | undefined }, threadId: number, type: MessageListType, - threadTopMessageId?: number, - threadFirstMessageId?: number, - hasLinkedChat?: boolean, - isSchedule = false, - noAppearanceAnimation = false, + threadTopMessageId: number | undefined, + threadFirstMessageId: number | undefined, + hasLinkedChat: boolean, + isSchedule: boolean, + noAppearanceAnimation: boolean, + openHistoryCalendar: Function, ) { const unreadDivider = (
@@ -701,7 +705,11 @@ function renderMessages( key={dateGroup.datetime} teactFastList > -
+
openHistoryCalendar({ selectedAt: dateGroup.datetime }) : undefined} + > {isSchedule && dateGroup.originalDate === SCHEDULED_WHEN_ONLINE && ( lang('MessageScheduledUntilOnline') @@ -785,5 +793,6 @@ export default memo(withGlobal( 'markMessageListRead', 'markMessagesRead', 'setScrollOffset', + 'openHistoryCalendar', ]), )(MessageList)); diff --git a/src/components/middle/MobileSearch.tsx b/src/components/middle/MobileSearch.tsx index 0f6c4d039..ba2b44a22 100644 --- a/src/components/middle/MobileSearch.tsx +++ b/src/components/middle/MobileSearch.tsx @@ -9,12 +9,10 @@ import { GlobalActions } from '../../global/types'; import { debounce } from '../../util/schedulers'; import { selectCurrentTextSearch, selectCurrentChat } from '../../modules/selectors'; import { pick } from '../../util/iteratees'; -import useFlag from '../../hooks/useFlag'; -import useLang from '../../hooks/useLang'; +import { getDayStartAt } from '../../util/dateFormat'; import Button from '../ui/Button'; import SearchInput from '../ui/SearchInput'; -import CalendarModal from '../common/CalendarModal'; import './MobileSearch.scss'; @@ -28,10 +26,11 @@ type StateProps = { query?: string; totalCount?: number; foundIds?: number[]; + isHistoryCalendarOpen?: boolean; }; type DispatchProps = Pick; @@ -43,16 +42,16 @@ const MobileSearchFooter: FC = ({ query, totalCount, foundIds, + isHistoryCalendarOpen, setLocalTextSearchQuery, searchTextMessagesLocal, focusMessage, closeLocalTextSearch, - searchMessagesByDate, + openHistoryCalendar, }) => { // eslint-disable-next-line no-null/no-null const inputRef = useRef(null); const [focusedIndex, setFocusedIndex] = useState(0); - const [isCalendarOpen, openCalendar, closeCalendar] = useFlag(); // Fix for iOS keyboard useEffect(() => { @@ -113,7 +112,7 @@ const MobileSearchFooter: FC = ({ useLayoutEffect(() => { const searchInput = document.querySelector('#MobileSearch input')!; searchInput.blur(); - }, [isCalendarOpen]); + }, [isHistoryCalendarOpen]); const handleMessageSearchQueryChange = useCallback((newQuery: string) => { setLocalTextSearchQuery({ query: newQuery }); @@ -123,11 +122,6 @@ const MobileSearchFooter: FC = ({ } }, [searchTextMessagesLocal, setLocalTextSearchQuery]); - const handleJumpToDate = useCallback((date: Date) => { - searchMessagesByDate({ timestamp: date.valueOf() / 1000 }); - closeCalendar(); - }, [closeCalendar, searchMessagesByDate]); - const handleUp = useCallback(() => { if (chat && foundIds) { const newFocusIndex = focusedIndex + 1; @@ -144,8 +138,6 @@ const MobileSearchFooter: FC = ({ } }, [chat, focusedIndex, focusMessage, foundIds]); - const lang = useLang(); - return (
@@ -178,7 +170,7 @@ const MobileSearchFooter: FC = ({ round size="smaller" color="translucent" - onClick={openCalendar} + onClick={() => openHistoryCalendar({ selectedAt: getDayStartAt(Date.now()) })} ariaLabel="Search messages by date" > @@ -204,13 +196,6 @@ const MobileSearchFooter: FC = ({
-
); }; @@ -230,6 +215,7 @@ export default memo(withGlobal( query, totalCount, foundIds, + isHistoryCalendarOpen: Boolean(global.historyCalendarSelectedAt), }; }, (setGlobal, actions): DispatchProps => pick(actions, [ @@ -237,6 +223,6 @@ export default memo(withGlobal( 'searchTextMessagesLocal', 'focusMessage', 'closeLocalTextSearch', - 'searchMessagesByDate', + 'openHistoryCalendar', ]), )(MobileSearchFooter)); diff --git a/src/components/right/RightHeader.tsx b/src/components/right/RightHeader.tsx index 08728d46f..30bd7b68b 100644 --- a/src/components/right/RightHeader.tsx +++ b/src/components/right/RightHeader.tsx @@ -19,14 +19,13 @@ import { } from '../../modules/selectors'; import { isChatAdmin, isChatChannel, isChatPrivate } from '../../modules/helpers'; import useCurrentOrPrev from '../../hooks/useCurrentOrPrev'; -import useFlag from '../../hooks/useFlag'; import useLang from '../../hooks/useLang'; -import CalendarModal from '../common/CalendarModal.async'; import SearchInput from '../ui/SearchInput'; import Button from '../ui/Button'; import Transition from '../ui/Transition'; import './RightHeader.scss'; +import { getDayStartAt } from '../../util/dateFormat'; type OwnProps = { chatId?: number; @@ -52,7 +51,7 @@ type StateProps = { type DispatchProps = Pick; const COLUMN_CLOSE_DELAY_MS = 300; @@ -102,13 +101,11 @@ const RightHeader: FC = ({ setGifSearchQuery, searchTextMessagesLocal, toggleManagement, - searchMessagesByDate, + openHistoryCalendar, }) => { // eslint-disable-next-line no-null/no-null const backButtonRef = useRef(null); - const [isCalendarOpen, openCalendar, closeCalendar] = useFlag(); - const handleMessageSearchQueryChange = useCallback((query: string) => { setLocalTextSearchQuery({ query }); @@ -117,11 +114,6 @@ const RightHeader: FC = ({ } }, [searchTextMessagesLocal, setLocalTextSearchQuery]); - const handleJumpToDate = useCallback((date: Date) => { - searchMessagesByDate({ timestamp: date.valueOf() / 1000 }); - closeCalendar(); - }, [closeCalendar, searchMessagesByDate]); - const handleStickerSearchQueryChange = useCallback((query: string) => { setStickerSearchQuery({ query }); }, [setStickerSearchQuery]); @@ -205,7 +197,7 @@ const RightHeader: FC = ({ round size="smaller" color="translucent" - onClick={openCalendar} + onClick={() => openHistoryCalendar({ selectedAt: getDayStartAt(Date.now()) })} ariaLabel="Search messages by date" > @@ -312,15 +304,6 @@ const RightHeader: FC = ({ > {renderHeaderContent} - {!IS_MOBILE_SCREEN && ( - - )}
); }; @@ -356,6 +339,6 @@ export default memo(withGlobal( 'setGifSearchQuery', 'searchTextMessagesLocal', 'toggleManagement', - 'searchMessagesByDate', + 'openHistoryCalendar', ]), )(RightHeader)); diff --git a/src/global/types.ts b/src/global/types.ts index ad583e32c..a443a62d1 100644 --- a/src/global/types.ts +++ b/src/global/types.ts @@ -389,6 +389,7 @@ export type GlobalState = { }; safeLinkModalUrl?: string; + historyCalendarSelectedAt?: number; }; export type ActionTypes = ( @@ -397,7 +398,7 @@ export type ActionTypes = ( 'showNotification' | 'dismissNotification' | 'showError' | 'dismissError' | // ui 'toggleChatInfo' | 'setIsUiReady' | 'addRecentEmoji' | 'addRecentSticker' | 'toggleLeftColumn' | - 'toggleSafeLinkModal' | + 'toggleSafeLinkModal' | 'openHistoryCalendar' | 'closeHistoryCalendar' | // auth 'setAuthPhoneNumber' | 'setAuthCode' | 'setAuthPassword' | 'signUp' | 'returnToAuthPhoneNumber' | 'signOut' | 'setAuthRememberMe' | 'clearAuthError' | 'uploadProfilePhoto' | 'gotToAuthQrCode' | 'clearCache' | diff --git a/src/modules/actions/ui/misc.ts b/src/modules/actions/ui/misc.ts index 5f1073151..b23526b3e 100644 --- a/src/modules/actions/ui/misc.ts +++ b/src/modules/actions/ui/misc.ts @@ -199,3 +199,19 @@ addReducer('toggleSafeLinkModal', (global, actions, payload) => { safeLinkModalUrl, }; }); + +addReducer('openHistoryCalendar', (global, actions, payload) => { + const { selectedAt } = payload; + + return { + ...global, + historyCalendarSelectedAt: selectedAt, + }; +}); + +addReducer('closeHistoryCalendar', (global) => { + return { + ...global, + historyCalendarSelectedAt: undefined, + }; +});