cetirizine

An experimental matrix client written in reactjs utilizing tailwind and storybook
git clone git://archive.git.mtrnord.blog/MTRNord/cetirizine.git
Log | Files | Refs | README | LICENSE

roomList.tsx (6650B)


      1 import { FC, memo, useContext, useEffect, useState } from "react";
      2 import RoomListItem from "./roomListItem/roomListItem";
      3 import { ChevronDown, ChevronRight } from "lucide-react";
      4 import './roomList.scss';
      5 import { useNavigate } from "react-router-dom";
      6 import { MatrixContext } from "../../app/sdk/client";
      7 import { useInView } from "react-intersection-observer";
      8 import { OnlineState } from "../../app/sdk/api/otherEnums";
      9 
     10 type Room = {
     11     /**
     12      * The URL of the Avatar image
     13      */
     14     avatarUrl?: string
     15     /**
     16      * The displayname of the room list item
     17      */
     18     displayname: string
     19     /**
     20      * Wether it is a DM or not
     21      */
     22     dm: boolean
     23     /**
     24      * Wether the user is online. Only used if dm is true.
     25      */
     26     online: OnlineState
     27     /**
     28      * The roomid of the Room
     29      */
     30     roomID: string
     31 };
     32 
     33 export type Section = {
     34     /**
     35      * Section Name. Can be a Space or a Tag
     36      */
     37     sectionName: string
     38     /**
     39      * The Rooms within the Section
     40      */
     41     rooms: Room[]
     42     /**
     43      * The Subsections of the Section
     44      */
     45     subsections: Section[]
     46     /**
     47      * The roomid of the Space
     48      */
     49     roomID: string
     50 }
     51 
     52 type RoomListProps = {
     53     /**
     54      * The Sections available
     55      */
     56     sections: Section[]
     57     /**
     58      * Rooms outside of any Sections
     59      */
     60     rooms: Room[]
     61     /**
     62      * Rooms outside of any Sections and DM
     63      */
     64     dmRooms: Room[]
     65 };
     66 
     67 type RoomListRoomsProps = {
     68     /**
     69      * The roomid of the Space
     70      */
     71     sectionID: string
     72     /**
     73      * Rooms
     74      */
     75     rooms: Room[]
     76     /**
     77      * The onClick handler
     78      */
     79     onClick: (roomID: string) => void;
     80     /**
     81      * The activeRoom
     82      */
     83     activeRoom?: string;
     84     /**
     85      * If rooms are hidden
     86      */
     87     hidden: boolean
     88 };
     89 
     90 const RoomListRooms: FC<RoomListRoomsProps> = memo(({ sectionID, rooms, onClick, activeRoom, hidden }: RoomListRoomsProps) => {
     91     // Get room ids of rooms
     92     const roomsRendered = rooms.map(room => {
     93         return (
     94             <RoomListItem
     95                 roomId={room.roomID}
     96                 hidden={hidden}
     97                 key={`${room.roomID}+${sectionID}`}
     98                 avatarUrl={room.avatarUrl}
     99                 displayname={room.displayname}
    100                 dm={room.dm}
    101                 online={room.online}
    102                 active={room.roomID === activeRoom}
    103                 onClick={() => { onClick(room.roomID) }}
    104             />
    105         );
    106     });
    107     return (
    108         <>
    109             {roomsRendered}
    110         </>
    111     );
    112 })
    113 
    114 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 }) => {
    115     const [hidden, setHidden] = useState<boolean>(true);
    116     const matrixClient = useContext(MatrixContext);
    117     const { ref, inView } = useInView({
    118         triggerOnce: true,
    119         threshold: 1,
    120         onChange(inView) {
    121             if (section.roomID !== "other") {
    122                 if (inView) {
    123                     matrixClient.addInViewRoom(section.roomID)
    124                 } else {
    125                     matrixClient.removeInViewRoom(section.roomID)
    126                 }
    127             }
    128         },
    129     });
    130     useEffect(() => {
    131         if (hidden) {
    132             matrixClient.removeSpaceOpen(section.roomID);
    133         } else {
    134             matrixClient.addSpaceOpen(section.roomID);
    135         }
    136     }, [hidden])
    137     return (
    138         <div ref={ref} key={section.roomID} className='room-section'>
    139             {
    140                 inView && <div className="flex flex-row gap-2 py-1 items-center justify-start cursor-pointer h-8 text-slate-600" onClick={() => setHidden(prev => !prev)}>
    141                     {hidden ? <ChevronRight size={14} /> : <ChevronDown size={14} />}
    142                     <span className='font-normal text-base capitalize max-w-[32ch] overflow-hidden text-ellipsis w-full whitespace-nowrap'>{section.sectionName}</span>
    143                 </div >}
    144             {!hidden && inView && (<RoomListRooms
    145                 hidden={hidden}
    146                 sectionID={section.roomID}
    147                 rooms={section.rooms}
    148                 onClick={onRoomClick}
    149                 activeRoom={activeRoom}
    150             />)}
    151             {!hidden && inView && (
    152                 section.subsections.map(section => {
    153                     return (
    154                         <RoomSection
    155                             key={section.roomID}
    156                             section={section}
    157                             onRoomClick={onRoomClick}
    158                             activeRoom={activeRoom}
    159                         />
    160                     );
    161                 })
    162             )}
    163         </div>
    164     );
    165 })
    166 
    167 const RoomList: FC<RoomListProps> = memo(({ sections, rooms, dmRooms }: RoomListProps) => {
    168     const [activeRoom, setActiveRoom] = useState<string | undefined>(undefined);
    169     const navigate = useNavigate();
    170 
    171     return (
    172         <div id='roomlist'>
    173             {dmRooms?.length == 0 ? <></> :
    174                 <RoomSection
    175                     section={{
    176                         sectionName: "DMs",
    177                         roomID: "dms",
    178                         subsections: [],
    179                         rooms: dmRooms
    180                     }}
    181                     onRoomClick={(roomID: string) => {
    182                         setActiveRoom(roomID);
    183                         navigate(`/${encodeURIComponent(roomID)}`);
    184                     }}
    185                     activeRoom={activeRoom}
    186                 />}
    187             {
    188                 sections.map(section => {
    189                     return (
    190                         <RoomSection
    191                             key={section.roomID}
    192                             section={section}
    193                             onRoomClick={(roomID: string) => {
    194                                 setActiveRoom(roomID);
    195                                 navigate(`/${encodeURIComponent(roomID)}`);
    196                             }}
    197                             activeRoom={activeRoom}
    198                         />
    199                     );
    200                 })
    201             }
    202             {rooms.length > 0 ? <RoomSection
    203                 section={{
    204                     sectionName: "Others",
    205                     roomID: "other",
    206                     subsections: [],
    207                     rooms: rooms
    208                 }}
    209                 onRoomClick={(roomID: string) => {
    210                     setActiveRoom(roomID);
    211                     navigate(`/${encodeURIComponent(roomID)}`);
    212                 }}
    213                 activeRoom={activeRoom}
    214             /> : <></>}
    215 
    216         </div>
    217     );
    218 })
    219 
    220 export default RoomList