commit 9298a3768f7556c347ccb201761d72fd1a9fb799
parent d029747c0244485d21a4039fadb49309dc656283
Author: MTRNord <mtrnord1@gmail.com>
Date: Tue, 2 May 2023 22:43:49 +0200
Memo all the stuff and make sure to only render leftOverRooms under others
Diffstat:
11 files changed, 82 insertions(+), 51 deletions(-)
diff --git a/src/components/avatar/avatar.tsx b/src/components/avatar/avatar.tsx
@@ -1,4 +1,4 @@
-import { FC } from "react";
+import { FC, memo } from "react";
type AvatarProps = {
/**
@@ -19,7 +19,7 @@ type AvatarProps = {
online: boolean
};
-const Avatar: FC<AvatarProps> = ({ avatarUrl, displayname, dm = false, online = false }: AvatarProps) => {
+const Avatar: FC<AvatarProps> = memo(({ avatarUrl, displayname, dm = false, online = false }: AvatarProps) => {
if (avatarUrl) {
return (
<div className="flex relative min-w-[2rem] min-h-[2rem] justify-center items-center m-0 mr-3 text-xl rounded-full text-white">
@@ -50,6 +50,6 @@ const Avatar: FC<AvatarProps> = ({ avatarUrl, displayname, dm = false, online =
}
</div>
);
-}
+})
export default Avatar;
\ No newline at end of file
diff --git a/src/components/button/button.tsx b/src/components/button/button.tsx
@@ -25,7 +25,7 @@ type ButtonProps = {
readonly: boolean
};
-const Button: FC<ButtonProps> = ({ type = "button", style = "primary", onClick, children, readonly }: ButtonProps) => {
+const Button: FC<ButtonProps> = memo(({ type = "button", style = "primary", onClick, children, readonly }: ButtonProps) => {
if (style === "secondary") {
return <button disabled={readonly} onClick={onClick} className="button bg-orange-400 hover:bg-orange-500 ease-out duration-150 disabled:bg-slate-200 disabled:cursor-not-allowed" type={type}>{children}</button>;
} else if (style === "abort") {
@@ -33,5 +33,5 @@ const Button: FC<ButtonProps> = ({ type = "button", style = "primary", onClick,
} else {
return <button disabled={readonly} onClick={onClick} className="button bg-green-400 hover:bg-green-500 ease-out duration-150 disabled:bg-slate-200 disabled:cursor-not-allowed" type={type}>{children}</button>;
}
-}
-export default memo(Button);
-\ No newline at end of file
+})
+export default Button;
+\ No newline at end of file
diff --git a/src/components/header/header.tsx b/src/components/header/header.tsx
@@ -1,4 +1,4 @@
-import { FC } from "react";
+import { FC, memo } from "react";
type HeaderProps = {
/**
@@ -7,8 +7,8 @@ type HeaderProps = {
children: string
};
-const Header: FC<HeaderProps> = ({ children }: HeaderProps) => {
+const Header: FC<HeaderProps> = memo(({ children }: HeaderProps) => {
return <h1 className='text-black font-bold text-xl'>{children}</h1>;
-}
+})
export default Header
\ No newline at end of file
diff --git a/src/components/input/basic/input.tsx b/src/components/input/basic/input.tsx
@@ -27,7 +27,7 @@ type InputProps = {
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
};
-const Input: FC<InputProps> = ({ placeholder, password = false, autoFocus = false, value, readonly, onChange }: InputProps) => {
+const Input: FC<InputProps> = memo(({ placeholder, password = false, autoFocus = false, value, readonly, onChange }: InputProps) => {
return (
<input
disabled={readonly}
@@ -39,5 +39,5 @@ const Input: FC<InputProps> = ({ placeholder, password = false, autoFocus = fals
onChange={onChange}
/>
);
-}
-export default memo(Input);
-\ No newline at end of file
+})
+export default Input;
+\ No newline at end of file
diff --git a/src/components/input/chat/input.tsx b/src/components/input/chat/input.tsx
@@ -21,7 +21,7 @@ import CodeHighlightPlugin from './plugins/CodeHighlightPlugin';
import EditorTheme from './theme';
import './input.scss';
-import { FC } from 'react';
+import { FC, memo } from 'react';
type ChatInputProps = {
/**
@@ -42,7 +42,7 @@ function Placeholder() {
return <div className="editor-placeholder" id="editor-placeholder">Enter message...</div>;
}
-const ChatInput: FC<ChatInputProps> = ({ namespace, onChange, onError }: ChatInputProps) => {
+const ChatInput: FC<ChatInputProps> = memo(({ namespace, onChange, onError }: ChatInputProps) => {
const initialConfig: InitialConfigType = {
namespace: namespace,
theme: EditorTheme,
@@ -81,6 +81,6 @@ const ChatInput: FC<ChatInputProps> = ({ namespace, onChange, onError }: ChatInp
</div>
</LexicalComposer>
);
-}
+})
export default ChatInput;
\ No newline at end of file
diff --git a/src/components/input/chat/plugins/ToolbarPlugin.tsx b/src/components/input/chat/plugins/ToolbarPlugin.tsx
@@ -10,7 +10,8 @@ import {
MutableRefObject,
Dispatch,
SetStateAction,
- createElement
+ createElement,
+ memo
} from "react";
import {
CAN_REDO_COMMAND,
@@ -97,9 +98,9 @@ const blockTypeToBlockName: BlockTypes = {
type BlockType = keyof typeof blockTypeToBlockName;
-function Divider() {
+const Divider = memo(() => {
return <div className="divider" />;
-}
+})
function positionEditorElement(editor: HTMLDivElement, rect: DOMRect | undefined) {
if (!rect) {
@@ -114,7 +115,7 @@ function positionEditorElement(editor: HTMLDivElement, rect: DOMRect | undefined
}
}
-function FloatingLinkEditor({ editor }: { editor: LexicalEditor }) {
+const FloatingLinkEditor = memo(({ editor }: { editor: LexicalEditor }) => {
const editorRef: MutableRefObject<HTMLDivElement | null> = useRef(null);
const inputRef: MutableRefObject<HTMLInputElement | null> = useRef(null);
const mouseDownRef = useRef(false);
@@ -252,9 +253,9 @@ function FloatingLinkEditor({ editor }: { editor: LexicalEditor }) {
)}
</div>
);
-}
+})
-function Select({ onChange, className, options, value }: { onChange: ChangeEventHandler<HTMLSelectElement>, className: string, options: string[], value: string | ReadonlyArray<string> | number }) {
+const Select = memo(({ onChange, className, options, value }: { onChange: ChangeEventHandler<HTMLSelectElement>, className: string, options: string[], value: string | ReadonlyArray<string> | number }) => {
return (
<select className={className} onChange={onChange} value={value}>
<option hidden={true} value="" />
@@ -265,7 +266,7 @@ function Select({ onChange, className, options, value }: { onChange: ChangeEvent
))}
</select>
);
-}
+})
function getSelectedNode(selection: RangeSelection | GridSelection) {
const anchor = selection.anchor;
@@ -283,12 +284,12 @@ function getSelectedNode(selection: RangeSelection | GridSelection) {
}
}
-function BlockOptionsDropdownList({
+const BlockOptionsDropdownList = memo(({
editor,
blockType,
toolbarRef,
setShowBlockOptionsDropDown
-}: { editor: LexicalEditor, blockType: BlockType, toolbarRef: MutableRefObject<HTMLDivElement | null>, setShowBlockOptionsDropDown: Dispatch<SetStateAction<boolean>> }) {
+}: { editor: LexicalEditor, blockType: BlockType, toolbarRef: MutableRefObject<HTMLDivElement | null>, setShowBlockOptionsDropDown: Dispatch<SetStateAction<boolean>> }) => {
const dropDownRef: MutableRefObject<HTMLDivElement | null> = useRef(null);
useEffect(() => {
@@ -433,9 +434,9 @@ function BlockOptionsDropdownList({
</button>
</div>
);
-}
+})
-export default function ToolbarPlugin() {
+const ToolbarPlugin = memo(() => {
const [editor] = useLexicalComposerContext();
const toolbarRef = useRef(null);
const [canUndo, setCanUndo] = useState(false);
@@ -711,4 +712,6 @@ export default function ToolbarPlugin() {
)}
</div>
);
-}
+})
+
+export default ToolbarPlugin;
+\ No newline at end of file
diff --git a/src/components/login/login.tsx b/src/components/login/login.tsx
@@ -1,11 +1,11 @@
-import { useContext, useState } from 'react';
+import { memo, useContext, useState } from 'react';
import Button from '../button/button';
import Header from '../header/header';
import Input from '../input/basic/input';
import { Navigate } from 'react-router-dom';
import { MatrixContext } from '../../app/sdk/client';
-export function Login() {
+const Login = memo(() => {
const matrixClient = useContext(MatrixContext);
const [loginPending, setLoginPending] = useState(false);
const [loginError, setLoginError] = useState('');
@@ -52,4 +52,6 @@ export function Login() {
</Button>
</form>
);
-}
-\ No newline at end of file
+})
+
+export default Login;
+\ No newline at end of file
diff --git a/src/components/roomList/roomList.tsx b/src/components/roomList/roomList.tsx
@@ -1,4 +1,4 @@
-import { FC, useState } from "react";
+import { FC, memo, useState } from "react";
import RoomListItem from "./roomListItem/roomListItem";
import { ChevronDown, ChevronRight } from "lucide-react";
import './roomList.scss';
@@ -79,13 +79,14 @@ type RoomListRoomsProps = {
hidden: boolean
};
-const RoomListRooms: FC<RoomListRoomsProps> = ({ sectionID, rooms, onClick, activeRoom, hidden }: RoomListRoomsProps) => {
+const RoomListRooms: FC<RoomListRoomsProps> = memo(({ sectionID, rooms, onClick, activeRoom, hidden }: RoomListRoomsProps) => {
+ // Get room ids of rooms
const roomsRendered = rooms.map(room => {
return (
<RoomListItem
roomId={room.roomID}
hidden={hidden}
- key={room.roomID + sectionID}
+ key={`${room.roomID}+${sectionID}`}
avatarUrl={room.avatarUrl}
displayname={room.displayname}
dm={room.dm}
@@ -100,9 +101,9 @@ const RoomListRooms: FC<RoomListRoomsProps> = ({ sectionID, rooms, onClick, acti
{roomsRendered}
</>
);
-}
+})
-const RoomSection: FC<{ section: Section, onRoomClick: (roomID: string) => void, activeRoom: string | undefined }> = ({ section, onRoomClick, activeRoom }: { section: Section, onRoomClick: (roomID: string) => void, activeRoom: string | undefined }) => {
+const RoomSection: FC<{ section: Section, onRoomClick: (roomID: string) => void, activeRoom: string | undefined }> = memo(({ section, onRoomClick, activeRoom }: { section: Section, onRoomClick: (roomID: string) => void, activeRoom: string | undefined }) => {
const [hidden, setHidden] = useState<boolean>(true);
return (
<div key={section.roomID} className="flex flex-col gap-1 pl-4">
@@ -131,9 +132,9 @@ const RoomSection: FC<{ section: Section, onRoomClick: (roomID: string) => void,
)}
</div>
);
-}
+})
-const RoomList: FC<RoomListProps> = ({ sections, rooms }: RoomListProps) => {
+const RoomList: FC<RoomListProps> = memo(({ sections, rooms }: RoomListProps) => {
const [activeRoom, setActiveRoom] = useState<string | undefined>(undefined);
return (
@@ -163,6 +164,6 @@ const RoomList: FC<RoomListProps> = ({ sections, rooms }: RoomListProps) => {
</div>
);
-}
+})
export default RoomList
\ No newline at end of file
diff --git a/src/components/roomList/roomListItem/roomListItem.tsx b/src/components/roomList/roomListItem/roomListItem.tsx
@@ -1,6 +1,6 @@
import { useInView } from "react-intersection-observer";
import Avatar from "../../avatar/avatar";
-import { FC, useContext, useEffect } from "react";
+import { FC, memo, useContext, useEffect } from "react";
import { MatrixContext } from "../../../app/sdk/client";
type RoomListItemProps = {
@@ -38,7 +38,7 @@ type RoomListItemProps = {
hidden: boolean
};
-const RoomListItem: FC<RoomListItemProps> = ({ roomId, avatarUrl, displayname, dm = false, online = false, active = false, onClick, hidden }: RoomListItemProps) => {
+const RoomListItem: FC<RoomListItemProps> = memo(({ roomId, avatarUrl, displayname, dm = false, online = false, active = false, onClick, hidden }: RoomListItemProps) => {
const { ref, inView } = useInView({
triggerOnce: true,
rootMargin: '200px 0px',
@@ -69,6 +69,6 @@ const RoomListItem: FC<RoomListItemProps> = ({ roomId, avatarUrl, displayname, d
}
</div>
);
-}
+})
export default RoomListItem
\ No newline at end of file
diff --git a/src/pages/LoginPage.tsx b/src/pages/LoginPage.tsx
@@ -1,12 +1,13 @@
import './LoginPage.scss';
-import { Login } from '../components/login/login';
+import Login from '../components/login/login';
+import { memo } from 'react';
-function LoginPage() {
+const LoginPage = memo(() => {
return (
<div className="flex flex-col items-center justify-center min-h-screen bg-img">
<Login />
</div>
);
-}
+})
export default LoginPage;
diff --git a/src/pages/MainPage.tsx b/src/pages/MainPage.tsx
@@ -5,7 +5,9 @@ import RoomList, { Section } from '../components/roomList/roomList';
import './MainPage.scss';
import { useProfile, useRooms, useSpaces } from '../app/sdk/client';
import { Room } from '../app/sdk/room';
-export default function MainPage() {
+import { memo } from 'react';
+
+const MainPage = memo(() => {
const profile = useProfile();
const spacesWithRooms = useSpaces();
const rooms = useRooms();
@@ -22,6 +24,18 @@ export default function MainPage() {
return not_a_child && no_parents;
});
+ // Filter rooms which are not part of any space and are not a space.
+ // A room is not part of any space if it is not a child of any space.
+ // A room is not a space if it has not any space as parent.
+ const leftOverRooms = [...rooms].filter(room => {
+ const not_a_child = ![...spacesWithRooms].some(({ children }) => {
+ return [...children].some(otherRoom => otherRoom.roomID === room.roomID);
+ });
+ const no_parents = room.getSpaceParentIDs().length === 0;
+ const not_a_space = !room.isSpace();
+ return not_a_child && no_parents && not_a_space;
+ });
+
// Generate a list of sections.
// Each section apart from special toplevel ones is a space.
// Each space has a list of rooms and subsections.
@@ -80,7 +94,7 @@ export default function MainPage() {
});
// Add the toplevel section "Other" to the end of the list.
- const otherRooms = [...rooms].filter(room => !room.isSpace()).map(room => {
+ const otherRooms = leftOverRooms.filter(room => !room.isSpace()).map(room => {
return {
roomID: room.roomID,
displayname: room.getName(),
@@ -90,6 +104,13 @@ export default function MainPage() {
}
});
+ // Check and print if otherRooms has duplicates.
+ const otherRoomsIDs = otherRooms.map(room => room.roomID);
+ const otherRoomsDuplicates = otherRoomsIDs.filter((id, index) => otherRoomsIDs.indexOf(id) !== index);
+ if (otherRoomsDuplicates.length > 0) {
+ console.error('otherRooms has duplicates', otherRoomsDuplicates);
+ }
+
return <div className='flex flex-row w-full gap-2 min-h-screen h-screen'>
< div className='flex flex-col bg-gradient-to-br from-slate-100 via-gray-200 to-orange-200 border-r-[1px] border-slate-300' >
<div className='flex flex-row gap-2 m-2 p-1 items-center border-b-2'>
@@ -107,4 +128,6 @@ export default function MainPage() {
<ChatInput namespace='Editor' onChange={() => { }} onError={(e) => console.error(e)} />
</div>
</div >
-}
-\ No newline at end of file
+})
+
+export default MainPage;
+\ No newline at end of file