You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			161 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			TypeScript
		
	
			
		
		
	
	
			161 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			TypeScript
		
	
| import React, { useEffect } from 'react';
 | |
| import { useDispatch, useSelector } from 'react-redux';
 | |
| 
 | |
| import styled from 'styled-components';
 | |
| import { parseOpenGroupV2 } from '../../../session/apis/open_group_api/opengroupV2/JoinOpenGroupV2';
 | |
| import { sogsV3FetchPreviewBase64 } from '../../../session/apis/open_group_api/sogsv3/sogsV3FetchFile';
 | |
| import { updateDefaultBase64RoomData } from '../../../state/ducks/defaultRooms';
 | |
| import { StateType } from '../../../state/reducer';
 | |
| import { Avatar, AvatarSize } from '../../avatar/Avatar';
 | |
| import { Flex } from '../../basic/Flex';
 | |
| import { PillContainerHoverable, StyledPillContainerHoverable } from '../../basic/PillContainer';
 | |
| import { SessionSpinner } from '../../basic/SessionSpinner';
 | |
| import { H3 } from '../../basic/Text';
 | |
| 
 | |
| export type JoinableRoomProps = {
 | |
|   completeUrl: string;
 | |
|   name: string;
 | |
|   roomId: string;
 | |
|   imageId?: string;
 | |
|   onClick?: (completeUrl: string) => void;
 | |
|   base64Data?: string;
 | |
| };
 | |
| 
 | |
| const SessionJoinableRoomAvatar = (props: JoinableRoomProps) => {
 | |
|   const dispatch = useDispatch();
 | |
|   useEffect(() => {
 | |
|     let isCancelled = false;
 | |
| 
 | |
|     try {
 | |
|       const parsedInfos = parseOpenGroupV2(props.completeUrl);
 | |
|       const imageID = props.imageId;
 | |
|       if (parsedInfos) {
 | |
|         if (props.base64Data) {
 | |
|           return;
 | |
|         }
 | |
|         if (isCancelled) {
 | |
|           return;
 | |
|         }
 | |
|         // eslint-disable-next-line more/no-then
 | |
|         sogsV3FetchPreviewBase64({ ...parsedInfos, imageID })
 | |
|           .then(base64 => {
 | |
|             if (isCancelled) {
 | |
|               return;
 | |
|             }
 | |
|             const payload = {
 | |
|               roomId: props.roomId,
 | |
|               base64Data: base64 || '',
 | |
|             };
 | |
|             dispatch(updateDefaultBase64RoomData(payload));
 | |
|           })
 | |
|           .catch(e => {
 | |
|             if (isCancelled) {
 | |
|               return;
 | |
|             }
 | |
|             window?.log?.warn('sogsV3FetchPreview failed', e);
 | |
|             const payload = {
 | |
|               roomId: props.roomId,
 | |
|               base64Data: '',
 | |
|             };
 | |
|             dispatch(updateDefaultBase64RoomData(payload));
 | |
|           });
 | |
|       }
 | |
|     } catch (e) {
 | |
|       window?.log?.warn(e.message);
 | |
|     }
 | |
|     // eslint-disable-next-line consistent-return
 | |
|     return () => {
 | |
|       isCancelled = true;
 | |
|     };
 | |
|   }, [props.imageId, props.completeUrl, dispatch, props.base64Data, props.roomId]);
 | |
| 
 | |
|   return (
 | |
|     <Avatar
 | |
|       size={AvatarSize.XS}
 | |
|       base64Data={props.base64Data}
 | |
|       {...props}
 | |
|       pubkey=""
 | |
|       onAvatarClick={() => props.onClick?.(props.completeUrl)}
 | |
|     />
 | |
|   );
 | |
| };
 | |
| 
 | |
| const StyledRoomName = styled(Flex)`
 | |
|   overflow: hidden;
 | |
|   white-space: nowrap;
 | |
|   text-overflow: ellipsis;
 | |
|   padding: 0 10px;
 | |
| `;
 | |
| 
 | |
| const SessionJoinableRoomName = (props: JoinableRoomProps) => {
 | |
|   return <StyledRoomName>{props.name}</StyledRoomName>;
 | |
| };
 | |
| 
 | |
| const SessionJoinableRoomRow = (props: JoinableRoomProps) => {
 | |
|   const { onClick, completeUrl } = props;
 | |
|   const onClickWithUrl = onClick
 | |
|     ? () => {
 | |
|         onClick?.(completeUrl);
 | |
|       }
 | |
|     : undefined;
 | |
| 
 | |
|   return (
 | |
|     <StyledPillContainerHoverable>
 | |
|       <PillContainerHoverable onClick={onClickWithUrl} margin="5px" padding="5px">
 | |
|         <SessionJoinableRoomAvatar {...props} />
 | |
|         <SessionJoinableRoomName {...props} />
 | |
|       </PillContainerHoverable>
 | |
|     </StyledPillContainerHoverable>
 | |
|   );
 | |
| };
 | |
| 
 | |
| const JoinableRooms = (props: {
 | |
|   alreadyJoining: boolean;
 | |
|   onJoinClick?: (completeUrl: string) => void;
 | |
| }) => {
 | |
|   const joinableRooms = useSelector((state: StateType) => state.defaultRooms);
 | |
| 
 | |
|   return (
 | |
|     <>
 | |
|       {joinableRooms.rooms.map(r => {
 | |
|         return (
 | |
|           <SessionJoinableRoomRow
 | |
|             key={r.id}
 | |
|             completeUrl={r.completeUrl}
 | |
|             name={r.name}
 | |
|             roomId={r.id}
 | |
|             imageId={r.imageId}
 | |
|             base64Data={r.base64Data}
 | |
|             onClick={props.onJoinClick}
 | |
|           />
 | |
|         );
 | |
|       })}
 | |
|     </>
 | |
|   );
 | |
| };
 | |
| 
 | |
| export const SessionJoinableRooms = (props: {
 | |
|   onJoinClick?: (completeUrl: string) => void;
 | |
|   alreadyJoining: boolean;
 | |
| }) => {
 | |
|   const joinableRooms = useSelector((state: StateType) => state.defaultRooms);
 | |
| 
 | |
|   if (!joinableRooms.inProgress && !joinableRooms.rooms?.length) {
 | |
|     window?.log?.info('no default joinable rooms yet and not in progress');
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   return (
 | |
|     <Flex container={true} flexGrow={1} flexDirection="column" width="93%">
 | |
|       <H3 text={window.i18n('orJoinOneOfThese')} />
 | |
|       <Flex container={true} flexGrow={0} flexWrap="wrap" justifyContent="center">
 | |
|         {joinableRooms.inProgress ? (
 | |
|           <SessionSpinner loading={true} />
 | |
|         ) : (
 | |
|           <JoinableRooms {...props} />
 | |
|         )}
 | |
|       </Flex>
 | |
|     </Flex>
 | |
|   );
 | |
| };
 |