From 9cb5c70d5174332eb306b3792a97f9ee7c126ace Mon Sep 17 00:00:00 2001
From: Ajay Bura <32841439+ajbura@users.noreply.github.com>
Date: Sat, 3 Aug 2024 19:17:53 +0530
Subject: [PATCH 1/2] add back btn for mobile view (#1861)

---
 src/app/components/BackRouteHandler.tsx       |  86 +++++++++++++++
 src/app/components/page/Page.tsx              |  20 ++--
 src/app/components/page/style.css.ts          |  19 +++-
 .../JoinBeforeNavigate.tsx                    |  28 +++--
 src/app/features/lobby/LobbyHeader.tsx        | 101 ++++++++++++------
 src/app/features/room/RoomViewHeader.tsx      |  40 +++++--
 src/app/pages/client/explore/Featured.tsx     |  19 +++-
 src/app/pages/client/explore/Server.tsx       |  36 +++++--
 src/app/pages/client/home/Search.tsx          |  31 ++++--
 src/app/pages/client/inbox/Invites.tsx        |  30 ++++--
 src/app/pages/client/inbox/Notifications.tsx  |  29 +++--
 src/app/pages/client/space/Search.tsx         |  31 ++++--
 12 files changed, 370 insertions(+), 100 deletions(-)
 create mode 100644 src/app/components/BackRouteHandler.tsx

diff --git a/src/app/components/BackRouteHandler.tsx b/src/app/components/BackRouteHandler.tsx
new file mode 100644
index 00000000..fa3d7592
--- /dev/null
+++ b/src/app/components/BackRouteHandler.tsx
@@ -0,0 +1,86 @@
+import { ReactNode, useCallback } from 'react';
+import { matchPath, useLocation, useNavigate } from 'react-router-dom';
+import {
+  getDirectPath,
+  getExplorePath,
+  getHomePath,
+  getInboxPath,
+  getSpacePath,
+} from '../pages/pathUtils';
+import { DIRECT_PATH, EXPLORE_PATH, HOME_PATH, INBOX_PATH, SPACE_PATH } from '../pages/paths';
+
+type BackRouteHandlerProps = {
+  children: (onBack: () => void) => ReactNode;
+};
+export function BackRouteHandler({ children }: BackRouteHandlerProps) {
+  const navigate = useNavigate();
+  const location = useLocation();
+
+  const goBack = useCallback(() => {
+    if (
+      matchPath(
+        {
+          path: HOME_PATH,
+          caseSensitive: true,
+          end: false,
+        },
+        location.pathname
+      )
+    ) {
+      navigate(getHomePath());
+      return;
+    }
+    if (
+      matchPath(
+        {
+          path: DIRECT_PATH,
+          caseSensitive: true,
+          end: false,
+        },
+        location.pathname
+      )
+    ) {
+      navigate(getDirectPath());
+      return;
+    }
+    const spaceMatch = matchPath(
+      {
+        path: SPACE_PATH,
+        caseSensitive: true,
+        end: false,
+      },
+      location.pathname
+    );
+    if (spaceMatch?.params.spaceIdOrAlias) {
+      navigate(getSpacePath(spaceMatch.params.spaceIdOrAlias));
+      return;
+    }
+    if (
+      matchPath(
+        {
+          path: EXPLORE_PATH,
+          caseSensitive: true,
+          end: false,
+        },
+        location.pathname
+      )
+    ) {
+      navigate(getExplorePath());
+      return;
+    }
+    if (
+      matchPath(
+        {
+          path: INBOX_PATH,
+          caseSensitive: true,
+          end: false,
+        },
+        location.pathname
+      )
+    ) {
+      navigate(getInboxPath());
+    }
+  }, [navigate, location]);
+
+  return children(goBack);
+}
diff --git a/src/app/components/page/Page.tsx b/src/app/components/page/Page.tsx
index 4ccb1ec0..a8b9ea04 100644
--- a/src/app/components/page/Page.tsx
+++ b/src/app/components/page/Page.tsx
@@ -87,15 +87,17 @@ export const Page = as<'div'>(({ className, ...props }, ref) => (
   />
 ));
 
-export const PageHeader = as<'div'>(({ className, ...props }, ref) => (
-  <Header
-    as="header"
-    size="600"
-    className={classNames(css.PageHeader, className)}
-    {...props}
-    ref={ref}
-  />
-));
+export const PageHeader = as<'div', css.PageHeaderVariants>(
+  ({ className, balance, ...props }, ref) => (
+    <Header
+      as="header"
+      size="600"
+      className={classNames(css.PageHeader({ balance }), className)}
+      {...props}
+      ref={ref}
+    />
+  )
+);
 
 export const PageContent = as<'div'>(({ className, ...props }, ref) => (
   <div className={classNames(css.PageContent, className)} {...props} ref={ref} />
diff --git a/src/app/components/page/style.css.ts b/src/app/components/page/style.css.ts
index 4807a227..23f2da49 100644
--- a/src/app/components/page/style.css.ts
+++ b/src/app/components/page/style.css.ts
@@ -1,4 +1,5 @@
 import { style } from '@vanilla-extract/css';
+import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
 import { DefaultReset, color, config, toRem } from 'folds';
 
 export const PageNav = style({
@@ -33,11 +34,21 @@ export const PageNavContent = style({
   paddingBottom: config.space.S700,
 });
 
-export const PageHeader = style({
-  paddingLeft: config.space.S400,
-  paddingRight: config.space.S200,
-  borderBottomWidth: config.borderWidth.B300,
+export const PageHeader = recipe({
+  base: {
+    paddingLeft: config.space.S400,
+    paddingRight: config.space.S200,
+    borderBottomWidth: config.borderWidth.B300,
+  },
+  variants: {
+    balance: {
+      true: {
+        paddingLeft: config.space.S200,
+      },
+    },
+  },
 });
+export type PageHeaderVariants = RecipeVariants<typeof PageHeader>;
 
 export const PageContent = style([
   DefaultReset,
diff --git a/src/app/features/join-before-navigate/JoinBeforeNavigate.tsx b/src/app/features/join-before-navigate/JoinBeforeNavigate.tsx
index 1cec6599..028cd560 100644
--- a/src/app/features/join-before-navigate/JoinBeforeNavigate.tsx
+++ b/src/app/features/join-before-navigate/JoinBeforeNavigate.tsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import { Box, Scroll, Text, toRem } from 'folds';
+import { Box, Icon, IconButton, Icons, Scroll, Text, toRem } from 'folds';
 import { useAtomValue } from 'jotai';
 import { RoomCard } from '../../components/room-card';
 import { RoomTopicViewer } from '../../components/room-topic-viewer';
@@ -8,6 +8,8 @@ import { RoomSummaryLoader } from '../../components/RoomSummaryLoader';
 import { useRoomNavigate } from '../../hooks/useRoomNavigate';
 import { useMatrixClient } from '../../hooks/useMatrixClient';
 import { allRoomsAtom } from '../../state/room-list/roomList';
+import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
+import { BackRouteHandler } from '../../components/BackRouteHandler';
 
 type JoinBeforeNavigateProps = { roomIdOrAlias: string; eventId?: string; viaServers?: string[] };
 export function JoinBeforeNavigate({
@@ -18,6 +20,7 @@ export function JoinBeforeNavigate({
   const mx = useMatrixClient();
   const allRooms = useAtomValue(allRoomsAtom);
   const { navigateRoom, navigateSpace } = useRoomNavigate();
+  const screenSize = useScreenSizeContext();
 
   const handleView = (roomId: string) => {
     if (mx.getRoom(roomId)?.isSpaceRoom()) {
@@ -29,11 +32,24 @@ export function JoinBeforeNavigate({
 
   return (
     <Page>
-      <PageHeader>
-        <Box grow="Yes" justifyContent="Center" alignItems="Center" gap="200">
-          <Text size="H3" truncate>
-            {roomIdOrAlias}
-          </Text>
+      <PageHeader balance>
+        <Box grow="Yes" gap="200">
+          <Box shrink="No">
+            {screenSize === ScreenSize.Mobile && (
+              <BackRouteHandler>
+                {(onBack) => (
+                  <IconButton onClick={onBack}>
+                    <Icon src={Icons.ArrowLeft} />
+                  </IconButton>
+                )}
+              </BackRouteHandler>
+            )}
+          </Box>
+          <Box grow="Yes" justifyContent="Center" alignItems="Center" gap="200">
+            <Text size="H3" truncate>
+              {roomIdOrAlias}
+            </Text>
+          </Box>
         </Box>
       </PageHeader>
       <Box grow="Yes">
diff --git a/src/app/features/lobby/LobbyHeader.tsx b/src/app/features/lobby/LobbyHeader.tsx
index e01d3ad5..fa415bd2 100644
--- a/src/app/features/lobby/LobbyHeader.tsx
+++ b/src/app/features/lobby/LobbyHeader.tsx
@@ -31,6 +31,8 @@ import { IPowerLevels, usePowerLevelsAPI } from '../../hooks/usePowerLevels';
 import { UseStateProvider } from '../../components/UseStateProvider';
 import { LeaveSpacePrompt } from '../../components/leave-space-prompt';
 import { stopPropagation } from '../../utils/keyboard';
+import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
+import { BackRouteHandler } from '../../components/BackRouteHandler';
 
 type LobbyMenuProps = {
   roomId: string;
@@ -123,6 +125,7 @@ export function LobbyHeader({ showProfile, powerLevels }: LobbyHeaderProps) {
   const space = useSpace();
   const setPeopleDrawer = useSetSetting(settingsAtom, 'isPeopleDrawer');
   const [menuAnchor, setMenuAnchor] = useState<RectCords>();
+  const screenSize = useScreenSizeContext();
 
   const name = useRoomName(space);
   const avatarMxc = useRoomAvatar(space);
@@ -133,42 +136,72 @@ export function LobbyHeader({ showProfile, powerLevels }: LobbyHeaderProps) {
   };
 
   return (
-    <PageHeader className={showProfile ? undefined : css.Header}>
+    <PageHeader className={showProfile ? undefined : css.Header} balance>
       <Box grow="Yes" alignItems="Center" gap="200">
-        <Box grow="Yes" basis="No" />
-        <Box justifyContent="Center" alignItems="Center" gap="300">
-          {showProfile && (
-            <>
-              <Avatar size="300">
-                <RoomAvatar
-                  roomId={space.roomId}
-                  src={avatarUrl}
-                  alt={name}
-                  renderFallback={() => <Text size="H4">{nameInitials(name)}</Text>}
-                />
-              </Avatar>
-              <Text size="H3" truncate>
-                {name}
-              </Text>
-            </>
+        {screenSize === ScreenSize.Mobile ? (
+          <>
+            <Box shrink="No">
+              <BackRouteHandler>
+                {(onBack) => (
+                  <IconButton onClick={onBack}>
+                    <Icon src={Icons.ArrowLeft} />
+                  </IconButton>
+                )}
+              </BackRouteHandler>
+            </Box>
+            <Box grow="Yes" justifyContent="Center">
+              {showProfile && (
+                <Text size="H3" truncate>
+                  {name}
+                </Text>
+              )}
+            </Box>
+          </>
+        ) : (
+          <>
+            <Box grow="Yes" basis="No" />
+            <Box justifyContent="Center" alignItems="Center" gap="300">
+              {showProfile && (
+                <>
+                  <Avatar size="300">
+                    <RoomAvatar
+                      roomId={space.roomId}
+                      src={avatarUrl}
+                      alt={name}
+                      renderFallback={() => <Text size="H4">{nameInitials(name)}</Text>}
+                    />
+                  </Avatar>
+                  <Text size="H3" truncate>
+                    {name}
+                  </Text>
+                </>
+              )}
+            </Box>
+          </>
+        )}
+        <Box
+          shrink="No"
+          grow={screenSize === ScreenSize.Mobile ? 'No' : 'Yes'}
+          basis={screenSize === ScreenSize.Mobile ? 'Yes' : 'No'}
+          justifyContent="End"
+        >
+          {screenSize !== ScreenSize.Mobile && (
+            <TooltipProvider
+              position="Bottom"
+              offset={4}
+              tooltip={
+                <Tooltip>
+                  <Text>Members</Text>
+                </Tooltip>
+              }
+            >
+              {(triggerRef) => (
+                <IconButton ref={triggerRef} onClick={() => setPeopleDrawer((drawer) => !drawer)}>
+                  <Icon size="400" src={Icons.User} />
+                </IconButton>
+              )}
+            </TooltipProvider>
           )}
-        </Box>
-        <Box shrink="No" grow="Yes" basis="No" justifyContent="End">
-          <TooltipProvider
-            position="Bottom"
-            offset={4}
-            tooltip={
-              <Tooltip>
-                <Text>Members</Text>
-              </Tooltip>
-            }
-          >
-            {(triggerRef) => (
-              <IconButton ref={triggerRef} onClick={() => setPeopleDrawer((drawer) => !drawer)}>
-                <Icon size="400" src={Icons.User} />
-              </IconButton>
-            )}
-          </TooltipProvider>
           <TooltipProvider
             position="Bottom"
             align="End"
diff --git a/src/app/features/room/RoomViewHeader.tsx b/src/app/features/room/RoomViewHeader.tsx
index 709f66c8..0b8ef74e 100644
--- a/src/app/features/room/RoomViewHeader.tsx
+++ b/src/app/features/room/RoomViewHeader.tsx
@@ -52,6 +52,7 @@ import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
 import { stopPropagation } from '../../utils/keyboard';
 import { getMatrixToRoom } from '../../plugins/matrix-to';
 import { getViaServers } from '../../plugins/via-servers';
+import { BackRouteHandler } from '../../components/BackRouteHandler';
 
 type RoomMenuProps = {
   room: Room;
@@ -203,19 +204,36 @@ export function RoomViewHeader() {
   };
 
   return (
-    <PageHeader>
+    <PageHeader balance={screenSize === ScreenSize.Mobile}>
       <Box grow="Yes" gap="300">
+        {screenSize === ScreenSize.Mobile && (
+          <BackRouteHandler>
+            {(onBack) => (
+              <Box shrink="No" alignItems="Center">
+                <IconButton onClick={onBack}>
+                  <Icon src={Icons.ArrowLeft} />
+                </IconButton>
+              </Box>
+            )}
+          </BackRouteHandler>
+        )}
         <Box grow="Yes" alignItems="Center" gap="300">
-          <Avatar size="300">
-            <RoomAvatar
-              roomId={room.roomId}
-              src={avatarUrl}
-              alt={name}
-              renderFallback={() => (
-                <RoomIcon size="200" joinRule={room.getJoinRule() ?? JoinRule.Restricted} filled />
-              )}
-            />
-          </Avatar>
+          {screenSize !== ScreenSize.Mobile && (
+            <Avatar size="300">
+              <RoomAvatar
+                roomId={room.roomId}
+                src={avatarUrl}
+                alt={name}
+                renderFallback={() => (
+                  <RoomIcon
+                    size="200"
+                    joinRule={room.getJoinRule() ?? JoinRule.Restricted}
+                    filled
+                  />
+                )}
+              />
+            </Avatar>
+          )}
           <Box direction="Column">
             <Text size={topic ? 'H5' : 'H3'} truncate>
               {name}
diff --git a/src/app/pages/client/explore/Featured.tsx b/src/app/pages/client/explore/Featured.tsx
index 4838127f..f056cbb5 100644
--- a/src/app/pages/client/explore/Featured.tsx
+++ b/src/app/pages/client/explore/Featured.tsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import { Box, Icon, Icons, Scroll, Text } from 'folds';
+import { Box, Icon, IconButton, Icons, Scroll, Text } from 'folds';
 import { useAtomValue } from 'jotai';
 import { useClientConfig } from '../../../hooks/useClientConfig';
 import { RoomCard, RoomCardGrid } from '../../../components/room-card';
@@ -9,21 +9,38 @@ import {
   Page,
   PageContent,
   PageContentCenter,
+  PageHeader,
   PageHero,
   PageHeroSection,
 } from '../../../components/page';
 import { RoomTopicViewer } from '../../../components/room-topic-viewer';
 import * as css from './style.css';
 import { useRoomNavigate } from '../../../hooks/useRoomNavigate';
+import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize';
+import { BackRouteHandler } from '../../../components/BackRouteHandler';
 
 export function FeaturedRooms() {
   const { featuredCommunities } = useClientConfig();
   const { rooms, spaces } = featuredCommunities ?? {};
   const allRooms = useAtomValue(allRoomsAtom);
+  const screenSize = useScreenSizeContext();
   const { navigateSpace, navigateRoom } = useRoomNavigate();
 
   return (
     <Page>
+      {screenSize === ScreenSize.Mobile && (
+        <PageHeader>
+          <Box shrink="No">
+            <BackRouteHandler>
+              {(onBack) => (
+                <IconButton onClick={onBack}>
+                  <Icon src={Icons.ArrowLeft} />
+                </IconButton>
+              )}
+            </BackRouteHandler>
+          </Box>
+        </PageHeader>
+      )}
       <Box grow="Yes">
         <Scroll hideTrack visibility="Hover">
           <PageContent>
diff --git a/src/app/pages/client/explore/Server.tsx b/src/app/pages/client/explore/Server.tsx
index 1a81c225..1f493df1 100644
--- a/src/app/pages/client/explore/Server.tsx
+++ b/src/app/pages/client/explore/Server.tsx
@@ -13,6 +13,7 @@ import {
   Button,
   Chip,
   Icon,
+  IconButton,
   Icons,
   Input,
   Line,
@@ -42,6 +43,8 @@ import { allRoomsAtom } from '../../../state/room-list/roomList';
 import { useRoomNavigate } from '../../../hooks/useRoomNavigate';
 import { getMxIdServer } from '../../../utils/matrix';
 import { stopPropagation } from '../../../utils/keyboard';
+import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize';
+import { BackRouteHandler } from '../../../components/BackRouteHandler';
 
 const useServerSearchParams = (searchParams: URLSearchParams): ExploreServerPathSearchParams =>
   useMemo(
@@ -344,6 +347,7 @@ export function PublicRooms() {
   const userServer = userId && getMxIdServer(userId);
   const allRooms = useAtomValue(allRoomsAtom);
   const { navigateSpace, navigateRoom } = useRoomNavigate();
+  const screenSize = useScreenSizeContext();
 
   const [searchParams] = useSearchParams();
   const serverSearchParams = useServerSearchParams(searchParams);
@@ -466,7 +470,7 @@ export function PublicRooms() {
 
   return (
     <Page>
-      <PageHeader>
+      <PageHeader balance>
         {isSearch ? (
           <>
             <Box grow="Yes" basis="No">
@@ -482,20 +486,34 @@ export function PublicRooms() {
             </Box>
 
             <Box grow="No" justifyContent="Center" alignItems="Center" gap="200">
-              <Icon size="400" src={Icons.Search} />
+              {screenSize !== ScreenSize.Mobile && <Icon size="400" src={Icons.Search} />}
               <Text size="H3" truncate>
                 Search
               </Text>
             </Box>
-            <Box grow="Yes" />
+            <Box grow="Yes" basis="No" />
           </>
         ) : (
-          <Box grow="Yes" justifyContent="Center" alignItems="Center" gap="200">
-            <Icon size="400" src={Icons.Category} />
-            <Text size="H3" truncate>
-              {server}
-            </Text>
-          </Box>
+          <>
+            <Box grow="Yes" basis="No">
+              {screenSize === ScreenSize.Mobile && (
+                <BackRouteHandler>
+                  {(onBack) => (
+                    <IconButton onClick={onBack}>
+                      <Icon src={Icons.ArrowLeft} />
+                    </IconButton>
+                  )}
+                </BackRouteHandler>
+              )}
+            </Box>
+            <Box grow="Yes" justifyContent="Center" alignItems="Center" gap="200">
+              {screenSize !== ScreenSize.Mobile && <Icon size="400" src={Icons.Category} />}
+              <Text size="H3" truncate>
+                {server}
+              </Text>
+            </Box>
+            <Box grow="Yes" basis="No" />
+          </>
         )}
       </PageHeader>
       <Box grow="Yes">
diff --git a/src/app/pages/client/home/Search.tsx b/src/app/pages/client/home/Search.tsx
index af7b1eb9..d5ddfb77 100644
--- a/src/app/pages/client/home/Search.tsx
+++ b/src/app/pages/client/home/Search.tsx
@@ -1,21 +1,38 @@
 import React, { useRef } from 'react';
-import { Box, Icon, Icons, Text, Scroll } from 'folds';
+import { Box, Icon, Icons, Text, Scroll, IconButton } from 'folds';
 import { Page, PageContent, PageContentCenter, PageHeader } from '../../../components/page';
 import { MessageSearch } from '../../../features/message-search';
 import { useHomeRooms } from './useHomeRooms';
+import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize';
+import { BackRouteHandler } from '../../../components/BackRouteHandler';
 
 export function HomeSearch() {
   const scrollRef = useRef<HTMLDivElement>(null);
   const rooms = useHomeRooms();
+  const screenSize = useScreenSizeContext();
 
   return (
     <Page>
-      <PageHeader>
-        <Box grow="Yes" justifyContent="Center" alignItems="Center" gap="200">
-          <Icon size="400" src={Icons.Search} />
-          <Text size="H3" truncate>
-            Message Search
-          </Text>
+      <PageHeader balance>
+        <Box grow="Yes" alignItems="Center" gap="200">
+          <Box grow="Yes" basis="No">
+            {screenSize === ScreenSize.Mobile && (
+              <BackRouteHandler>
+                {(onBack) => (
+                  <IconButton onClick={onBack}>
+                    <Icon src={Icons.ArrowLeft} />
+                  </IconButton>
+                )}
+              </BackRouteHandler>
+            )}
+          </Box>
+          <Box justifyContent="Center" alignItems="Center" gap="200">
+            {screenSize !== ScreenSize.Mobile && <Icon size="400" src={Icons.Search} />}
+            <Text size="H3" truncate>
+              Message Search
+            </Text>
+          </Box>
+          <Box grow="Yes" basis="No" />
         </Box>
       </PageHeader>
       <Box style={{ position: 'relative' }} grow="Yes">
diff --git a/src/app/pages/client/inbox/Invites.tsx b/src/app/pages/client/inbox/Invites.tsx
index 06e5f6c6..18993081 100644
--- a/src/app/pages/client/inbox/Invites.tsx
+++ b/src/app/pages/client/inbox/Invites.tsx
@@ -4,6 +4,7 @@ import {
   Box,
   Button,
   Icon,
+  IconButton,
   Icons,
   Overlay,
   OverlayBackdrop,
@@ -39,6 +40,8 @@ import { RoomTopicViewer } from '../../../components/room-topic-viewer';
 import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
 import { useRoomNavigate } from '../../../hooks/useRoomNavigate';
 import { useRoomTopic } from '../../../hooks/useRoomMeta';
+import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize';
+import { BackRouteHandler } from '../../../components/BackRouteHandler';
 
 const COMPACT_CARD_WIDTH = 548;
 
@@ -205,6 +208,7 @@ export function Invites() {
     useCallback(() => containerRef.current, []),
     useCallback((width) => setCompact(width <= COMPACT_CARD_WIDTH), [])
   );
+  const screenSize = useScreenSizeContext();
 
   const { navigateRoom, navigateSpace } = useRoomNavigate();
 
@@ -225,12 +229,26 @@ export function Invites() {
 
   return (
     <Page>
-      <PageHeader>
-        <Box grow="Yes" justifyContent="Center" alignItems="Center" gap="200">
-          <Icon size="400" src={Icons.Mail} />
-          <Text size="H3" truncate>
-            Invitations
-          </Text>
+      <PageHeader balance>
+        <Box grow="Yes" gap="200">
+          <Box grow="Yes" basis="No">
+            {screenSize === ScreenSize.Mobile && (
+              <BackRouteHandler>
+                {(onBack) => (
+                  <IconButton onClick={onBack}>
+                    <Icon src={Icons.ArrowLeft} />
+                  </IconButton>
+                )}
+              </BackRouteHandler>
+            )}
+          </Box>
+          <Box alignItems="Center" gap="200">
+            {screenSize !== ScreenSize.Mobile && <Icon size="400" src={Icons.Mail} />}
+            <Text size="H3" truncate>
+              Invitations
+            </Text>
+          </Box>
+          <Box grow="Yes" basis="No" />
         </Box>
       </PageHeader>
       <Box grow="Yes">
diff --git a/src/app/pages/client/inbox/Notifications.tsx b/src/app/pages/client/inbox/Notifications.tsx
index 3425b519..6a8160d8 100644
--- a/src/app/pages/client/inbox/Notifications.tsx
+++ b/src/app/pages/client/inbox/Notifications.tsx
@@ -78,6 +78,8 @@ import { UserAvatar } from '../../../components/user-avatar';
 import { EncryptedContent } from '../../../features/room/message';
 import { useMentionClickHandler } from '../../../hooks/useMentionClickHandler';
 import { useSpoilerClickHandler } from '../../../hooks/useSpoilerClickHandler';
+import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize';
+import { BackRouteHandler } from '../../../components/BackRouteHandler';
 
 type RoomNotificationsGroup = {
   roomId: string;
@@ -484,6 +486,7 @@ export function Notifications() {
   const mx = useMatrixClient();
   const [mediaAutoLoad] = useSetting(settingsAtom, 'mediaAutoLoad');
   const [urlPreview] = useSetting(settingsAtom, 'urlPreview');
+  const screenSize = useScreenSizeContext();
 
   const { navigateRoom } = useRoomNavigate();
   const [searchParams, setSearchParams] = useSearchParams();
@@ -549,12 +552,26 @@ export function Notifications() {
 
   return (
     <Page>
-      <PageHeader>
-        <Box grow="Yes" justifyContent="Center" alignItems="Center" gap="200">
-          <Icon size="400" src={Icons.Message} />
-          <Text size="H3" truncate>
-            Notification Messages
-          </Text>
+      <PageHeader balance>
+        <Box grow="Yes" gap="200">
+          <Box grow="Yes" basis="No">
+            {screenSize === ScreenSize.Mobile && (
+              <BackRouteHandler>
+                {(onBack) => (
+                  <IconButton onClick={onBack}>
+                    <Icon src={Icons.ArrowLeft} />
+                  </IconButton>
+                )}
+              </BackRouteHandler>
+            )}
+          </Box>
+          <Box alignItems="Center" gap="200">
+            {screenSize !== ScreenSize.Mobile && <Icon size="400" src={Icons.Message} />}
+            <Text size="H3" truncate>
+              Notification Messages
+            </Text>
+          </Box>
+          <Box grow="Yes" basis="No" />
         </Box>
       </PageHeader>
 
diff --git a/src/app/pages/client/space/Search.tsx b/src/app/pages/client/space/Search.tsx
index 6e7ac57d..017262b5 100644
--- a/src/app/pages/client/space/Search.tsx
+++ b/src/app/pages/client/space/Search.tsx
@@ -1,5 +1,5 @@
 import React, { useRef } from 'react';
-import { Box, Icon, Icons, Text, Scroll } from 'folds';
+import { Box, Icon, Icons, Text, Scroll, IconButton } from 'folds';
 import { useAtomValue } from 'jotai';
 import { Page, PageContent, PageContentCenter, PageHeader } from '../../../components/page';
 import { MessageSearch } from '../../../features/message-search';
@@ -9,11 +9,14 @@ import { allRoomsAtom } from '../../../state/room-list/roomList';
 import { mDirectAtom } from '../../../state/mDirectList';
 import { roomToParentsAtom } from '../../../state/room/roomToParents';
 import { useMatrixClient } from '../../../hooks/useMatrixClient';
+import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize';
+import { BackRouteHandler } from '../../../components/BackRouteHandler';
 
 export function SpaceSearch() {
   const mx = useMatrixClient();
   const scrollRef = useRef<HTMLDivElement>(null);
   const space = useSpace();
+  const screenSize = useScreenSizeContext();
 
   const mDirects = useAtomValue(mDirectAtom);
   const roomToParents = useAtomValue(roomToParentsAtom);
@@ -25,12 +28,26 @@ export function SpaceSearch() {
 
   return (
     <Page>
-      <PageHeader>
-        <Box grow="Yes" justifyContent="Center" alignItems="Center" gap="200">
-          <Icon size="400" src={Icons.Search} />
-          <Text size="H3" truncate>
-            Message Search
-          </Text>
+      <PageHeader balance>
+        <Box grow="Yes" alignItems="Center" gap="200">
+          <Box grow="Yes" basis="No">
+            {screenSize === ScreenSize.Mobile && (
+              <BackRouteHandler>
+                {(onBack) => (
+                  <IconButton onClick={onBack}>
+                    <Icon src={Icons.ArrowLeft} />
+                  </IconButton>
+                )}
+              </BackRouteHandler>
+            )}
+          </Box>
+          <Box justifyContent="Center" alignItems="Center" gap="200">
+            {screenSize !== ScreenSize.Mobile && <Icon size="400" src={Icons.Search} />}
+            <Text size="H3" truncate>
+              Message Search
+            </Text>
+          </Box>
+          <Box grow="Yes" basis="No" />
         </Box>
       </PageHeader>
       <Box style={{ position: 'relative' }} grow="Yes">

From 681287c46ae6aab6c3a3697a8a062acbebc519c9 Mon Sep 17 00:00:00 2001
From: Ajay Bura <32841439+ajbura@users.noreply.github.com>
Date: Sun, 4 Aug 2024 09:49:37 +0530
Subject: [PATCH 2/2] show unverified tab indicator on sidebar (#1862)

---
 src/app/hooks/useDeviceList.js                | 31 -----------
 src/app/hooks/useDeviceList.ts                | 35 +++++++++++++
 src/app/pages/client/SidebarNav.tsx           | 12 ++++-
 .../pages/client/sidebar/UnverifiedTab.css.ts | 24 +++++++++
 .../pages/client/sidebar/UnverifiedTab.tsx    | 51 +++++++++++++++++++
 src/app/pages/client/sidebar/index.ts         |  1 +
 src/util/matrixUtil.js                        |  2 +-
 7 files changed, 123 insertions(+), 33 deletions(-)
 delete mode 100644 src/app/hooks/useDeviceList.js
 create mode 100644 src/app/hooks/useDeviceList.ts
 create mode 100644 src/app/pages/client/sidebar/UnverifiedTab.css.ts
 create mode 100644 src/app/pages/client/sidebar/UnverifiedTab.tsx

diff --git a/src/app/hooks/useDeviceList.js b/src/app/hooks/useDeviceList.js
deleted file mode 100644
index 7daaad1f..00000000
--- a/src/app/hooks/useDeviceList.js
+++ /dev/null
@@ -1,31 +0,0 @@
-/* eslint-disable import/prefer-default-export */
-import { useState, useEffect } from 'react';
-import { useMatrixClient } from './useMatrixClient';
-
-export function useDeviceList() {
-  const mx = useMatrixClient();
-  const [deviceList, setDeviceList] = useState(null);
-
-  useEffect(() => {
-    let isMounted = true;
-
-    const updateDevices = () => mx.getDevices().then((data) => {
-      if (!isMounted) return;
-      setDeviceList(data.devices || []);
-    });
-    updateDevices();
-
-    const handleDevicesUpdate = (users) => {
-      if (users.includes(mx.getUserId())) {
-        updateDevices();
-      }
-    };
-
-    mx.on('crypto.devicesUpdated', handleDevicesUpdate);
-    return () => {
-      mx.removeListener('crypto.devicesUpdated', handleDevicesUpdate);
-      isMounted = false;
-    };
-  }, [mx]);
-  return deviceList;
-}
diff --git a/src/app/hooks/useDeviceList.ts b/src/app/hooks/useDeviceList.ts
new file mode 100644
index 00000000..daec7cbe
--- /dev/null
+++ b/src/app/hooks/useDeviceList.ts
@@ -0,0 +1,35 @@
+/* eslint-disable import/prefer-default-export */
+import { useState, useEffect } from 'react';
+import { CryptoEvent, IMyDevice } from 'matrix-js-sdk';
+import { CryptoEventHandlerMap } from 'matrix-js-sdk/lib/crypto';
+import { useMatrixClient } from './useMatrixClient';
+
+export function useDeviceList() {
+  const mx = useMatrixClient();
+  const [deviceList, setDeviceList] = useState<IMyDevice[] | null>(null);
+
+  useEffect(() => {
+    let isMounted = true;
+
+    const updateDevices = () =>
+      mx.getDevices().then((data) => {
+        if (!isMounted) return;
+        setDeviceList(data.devices || []);
+      });
+    updateDevices();
+
+    const handleDevicesUpdate: CryptoEventHandlerMap[CryptoEvent.DevicesUpdated] = (users) => {
+      const userId = mx.getUserId();
+      if (userId && users.includes(userId)) {
+        updateDevices();
+      }
+    };
+
+    mx.on(CryptoEvent.DevicesUpdated, handleDevicesUpdate);
+    return () => {
+      mx.removeListener(CryptoEvent.DevicesUpdated, handleDevicesUpdate);
+      isMounted = false;
+    };
+  }, [mx]);
+  return deviceList;
+}
diff --git a/src/app/pages/client/SidebarNav.tsx b/src/app/pages/client/SidebarNav.tsx
index fb6bd742..110e4694 100644
--- a/src/app/pages/client/SidebarNav.tsx
+++ b/src/app/pages/client/SidebarNav.tsx
@@ -10,7 +10,15 @@ import {
   SidebarItemTooltip,
   SidebarItem,
 } from '../../components/sidebar';
-import { DirectTab, HomeTab, SpaceTabs, InboxTab, ExploreTab, UserTab } from './sidebar';
+import {
+  DirectTab,
+  HomeTab,
+  SpaceTabs,
+  InboxTab,
+  ExploreTab,
+  UserTab,
+  UnverifiedTab,
+} from './sidebar';
 import { openCreateRoom, openSearch } from '../../../client/action/navigation';
 
 export function SidebarNav() {
@@ -65,6 +73,8 @@ export function SidebarNav() {
                 </SidebarItemTooltip>
               </SidebarItem>
 
+              <UnverifiedTab />
+
               <InboxTab />
               <UserTab />
             </SidebarStack>
diff --git a/src/app/pages/client/sidebar/UnverifiedTab.css.ts b/src/app/pages/client/sidebar/UnverifiedTab.css.ts
new file mode 100644
index 00000000..e8fe8c51
--- /dev/null
+++ b/src/app/pages/client/sidebar/UnverifiedTab.css.ts
@@ -0,0 +1,24 @@
+import { keyframes, style } from '@vanilla-extract/css';
+import { color, toRem } from 'folds';
+
+const pushRight = keyframes({
+  from: {
+    transform: `translateX(${toRem(2)}) scale(1)`,
+  },
+  to: {
+    transform: 'translateX(0) scale(1)',
+  },
+});
+
+export const UnverifiedTab = style({
+  animationName: pushRight,
+  animationDuration: '400ms',
+  animationIterationCount: 30,
+  animationDirection: 'alternate',
+});
+
+export const UnverifiedAvatar = style({
+  backgroundColor: color.Critical.Container,
+  color: color.Critical.OnContainer,
+  borderColor: color.Critical.ContainerLine,
+});
diff --git a/src/app/pages/client/sidebar/UnverifiedTab.tsx b/src/app/pages/client/sidebar/UnverifiedTab.tsx
new file mode 100644
index 00000000..402ffc2b
--- /dev/null
+++ b/src/app/pages/client/sidebar/UnverifiedTab.tsx
@@ -0,0 +1,51 @@
+import React from 'react';
+import { Badge, color, Icon, Icons, Text } from 'folds';
+import { openSettings } from '../../../../client/action/navigation';
+import { isCrossVerified } from '../../../../util/matrixUtil';
+import {
+  SidebarAvatar,
+  SidebarItem,
+  SidebarItemBadge,
+  SidebarItemTooltip,
+} from '../../../components/sidebar';
+import { useDeviceList } from '../../../hooks/useDeviceList';
+import { tabText } from '../../../organisms/settings/Settings';
+import { useMatrixClient } from '../../../hooks/useMatrixClient';
+import * as css from './UnverifiedTab.css';
+
+export function UnverifiedTab() {
+  const mx = useMatrixClient();
+  const deviceList = useDeviceList();
+  console.log(deviceList);
+  const unverified = deviceList?.filter(
+    (device) => isCrossVerified(mx, device.device_id) === false
+  );
+  console.log(unverified);
+
+  if (!unverified?.length) return null;
+
+  return (
+    <SidebarItem className={css.UnverifiedTab}>
+      <SidebarItemTooltip tooltip="Unverified Sessions">
+        {(triggerRef) => (
+          <SidebarAvatar
+            className={css.UnverifiedAvatar}
+            as="button"
+            ref={triggerRef}
+            outlined
+            onClick={() => openSettings(tabText.SECURITY)}
+          >
+            <Icon style={{ color: color.Critical.Main }} src={Icons.ShieldUser} />
+          </SidebarAvatar>
+        )}
+      </SidebarItemTooltip>
+      <SidebarItemBadge hasCount>
+        <Badge variant="Critical" size="400" fill="Solid" radii="Pill" outlined={false}>
+          <Text as="span" size="L400">
+            {unverified.length}
+          </Text>
+        </Badge>
+      </SidebarItemBadge>
+    </SidebarItem>
+  );
+}
diff --git a/src/app/pages/client/sidebar/index.ts b/src/app/pages/client/sidebar/index.ts
index 63c5d4bb..5da8780b 100644
--- a/src/app/pages/client/sidebar/index.ts
+++ b/src/app/pages/client/sidebar/index.ts
@@ -4,3 +4,4 @@ export * from './SpaceTabs';
 export * from './InboxTab';
 export * from './ExploreTab';
 export * from './UserTab';
+export * from './UnverifiedTab';
diff --git a/src/util/matrixUtil.js b/src/util/matrixUtil.js
index 9f1d9421..7664c3a4 100644
--- a/src/util/matrixUtil.js
+++ b/src/util/matrixUtil.js
@@ -106,7 +106,7 @@ export function isCrossVerified(mx, deviceId) {
     const deviceInfo = mx.getStoredDevice(mx.getUserId(), deviceId);
     const deviceTrust = crossSignInfo.checkDeviceTrust(crossSignInfo, deviceInfo, false, true);
     return deviceTrust.isCrossSigningVerified();
-  } catch {
+  } catch (e) {
     // device does not support encryption
     return null;
   }