mirror of
				https://github.com/owncast/owncast.git
				synced 2025-11-01 02:44:31 +08:00 
			
		
		
		
	Fill out the follower component
This commit is contained in:
		| @ -1,9 +1,19 @@ | ||||
| import { Avatar, Comment } from 'antd'; | ||||
| import React from 'react'; | ||||
| import { Follower } from '../interfaces/follower'; | ||||
|  | ||||
| interface Props { | ||||
|   follower: Follower; | ||||
| } | ||||
|  | ||||
| export default function FollowerCollection(props: Props) { | ||||
|   return <div>This is a single follower</div>; | ||||
| export default function SingleFollower(props: Props) { | ||||
|   const { follower } = props; | ||||
|  | ||||
|   return ( | ||||
|     <Comment | ||||
|       author={follower.username} | ||||
|       avatar={<Avatar src={follower.image} alt="Han Solo" />} | ||||
|       content={follower.name} | ||||
|     /> | ||||
|   ); | ||||
| } | ||||
|  | ||||
| @ -1,9 +1,24 @@ | ||||
| import { Pagination } from 'antd'; | ||||
| import { Follower } from '../interfaces/follower'; | ||||
| import SingleFollower from './Follower'; | ||||
|  | ||||
| interface Props { | ||||
|   total: number; | ||||
|   followers: Follower[]; | ||||
| } | ||||
|  | ||||
| export default function FollowerCollection(props: Props) { | ||||
|   return <div>List of followers go here</div>; | ||||
|   const ITEMS_PER_PAGE = 24; | ||||
|  | ||||
|   const { followers, total } = props; | ||||
|   const pages = Math.ceil(total / ITEMS_PER_PAGE); | ||||
|  | ||||
|   return ( | ||||
|     <div> | ||||
|       {followers.map(follower => ( | ||||
|         <SingleFollower key={follower.link} follower={follower} /> | ||||
|       ))} | ||||
|       <Pagination current={1} pageSize={ITEMS_PER_PAGE} total={pages || 1} /> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
|  | ||||
| @ -1,10 +1,11 @@ | ||||
| import { Spin } from 'antd'; | ||||
| import { Virtuoso } from 'react-virtuoso'; | ||||
| import { useState, useMemo, useCallback, useEffect, useRef } from 'react'; | ||||
| import { LoadingOutlined } from '@ant-design/icons'; | ||||
| import { ChatMessage } from '../../interfaces/chat-message.model'; | ||||
| import { ChatState } from '../../interfaces/application-state'; | ||||
| import ChatUserMessage from './ChatUserMessage'; | ||||
| import { LoadingOutlined } from '@ant-design/icons'; | ||||
| import { MessageType } from '../../interfaces/socket-events'; | ||||
|  | ||||
| interface Props { | ||||
|   messages: ChatMessage[]; | ||||
| @ -16,8 +17,19 @@ export default function ChatContainer(props: Props) { | ||||
|   const loading = state === ChatState.Loading; | ||||
|  | ||||
|   const chatContainerRef = useRef(null); | ||||
|   const spinIcon = <LoadingOutlined style={{fontSize: '32px'}} spin /> | ||||
|   const spinIcon = <LoadingOutlined style={{ fontSize: '32px' }} spin />; | ||||
|  | ||||
|   const getViewForMessage = message => { | ||||
|     switch (message.type) { | ||||
|       case MessageType.CHAT: | ||||
|         return <ChatUserMessage message={message} showModeratorMenu={false} />; | ||||
|       default: | ||||
|         return null; | ||||
|     } | ||||
|     return null; | ||||
|   }; | ||||
|  | ||||
|   console.log(messages); | ||||
|   return ( | ||||
|     <div> | ||||
|       <h1>Chat</h1> | ||||
| @ -26,9 +38,7 @@ export default function ChatContainer(props: Props) { | ||||
|         ref={chatContainerRef} | ||||
|         initialTopMostItemIndex={999} | ||||
|         data={messages} | ||||
|         itemContent={(index, message) => ( | ||||
|           <ChatUserMessage message={message} showModeratorMenu={false} /> | ||||
|         )} | ||||
|         itemContent={(index, message) => getViewForMessage(message)} | ||||
|         followOutput="smooth" | ||||
|       /> | ||||
|     </div> | ||||
|  | ||||
| @ -17,7 +17,7 @@ import { | ||||
| import { | ||||
|   SocketEvent, | ||||
|   ConnectedClientInfoEvent, | ||||
|   SocketMessageType, | ||||
|   MessageType, | ||||
|   ChatEvent, | ||||
| } from '../../interfaces/socket-events'; | ||||
| import handleConnectedClientInfoMessage from './eventhandlers/connectedclientinfo'; | ||||
| @ -102,10 +102,10 @@ export function ClientConfigStore() { | ||||
|  | ||||
|   const handleMessage = (message: SocketEvent) => { | ||||
|     switch (message.type) { | ||||
|       case SocketMessageType.CONNECTED_USER_INFO: | ||||
|       case MessageType.CONNECTED_USER_INFO: | ||||
|         handleConnectedClientInfoMessage(message as ConnectedClientInfoEvent); | ||||
|         break; | ||||
|       case SocketMessageType.CHAT: | ||||
|       case MessageType.CHAT: | ||||
|         handleChatMessage(message as ChatEvent, chatMessages, setChatMessages); | ||||
|         break; | ||||
|       default: | ||||
|  | ||||
| @ -1,6 +1,12 @@ | ||||
| import { useRecoilValue } from 'recoil'; | ||||
| import { Layout, Tabs } from 'antd'; | ||||
| import { chatVisibilityAtom, clientConfigStateAtom } from '../../stores/ClientConfigStore'; | ||||
| import { Layout, Tabs, Layout, Row, Col, Tabs } from 'antd'; | ||||
| import Grid from 'antd/lib/card/Grid'; | ||||
| import { | ||||
|   chatVisibilityAtom, | ||||
|   clientConfigStateAtom, | ||||
|   chatMessagesAtom, | ||||
|   chatStateAtom, | ||||
| } from '../../stores/ClientConfigStore'; | ||||
| import { ClientConfig } from '../../../interfaces/client-config.model'; | ||||
| import CustomPageContent from '../../CustomPageContent'; | ||||
| import OwncastPlayer from '../../video/OwncastPlayer'; | ||||
| @ -10,7 +16,6 @@ import Sidebar from '../Sidebar'; | ||||
| import Footer from '../Footer'; | ||||
| import ChatContainer from '../../chat/ChatContainer'; | ||||
| import { ChatMessage } from '../../../interfaces/chat-message.model'; | ||||
| import { chatMessagesAtom, chatStateAtom } from '../../stores/ClientConfigStore'; | ||||
| import { ChatState, ChatVisibilityState } from '../../../interfaces/application-state'; | ||||
| import ChatTextField from '../../chat/ChatTextField/ChatTextField'; | ||||
|  | ||||
| @ -26,6 +31,10 @@ export default function FooterComponent() { | ||||
|  | ||||
|   const { extraPageContent } = clientConfig; | ||||
|  | ||||
|   const followers: Follower[] = []; | ||||
|  | ||||
|   const total = 0; | ||||
|  | ||||
|   return ( | ||||
|     <Content className={`${s.root}`} data-columns={chatOpen ? 2 : 1}> | ||||
|       <div className={`${s.leftCol}`}> | ||||
| @ -36,7 +45,7 @@ export default function FooterComponent() { | ||||
|               <CustomPageContent content={extraPageContent} /> | ||||
|             </TabPane> | ||||
|             <TabPane tab="Followers" key="2"> | ||||
|               <FollowerCollection /> | ||||
|               <FollowerCollection total={total} followers={followers} /> | ||||
|             </TabPane> | ||||
|           </Tabs> | ||||
|           {chatOpen && ( | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| import { User } from './user.model'; | ||||
|  | ||||
| export enum SocketMessageType { | ||||
| export enum MessageType { | ||||
|   CHAT = 'CHAT', | ||||
|   PING = 'PING', | ||||
|   NAME_CHANGE = 'NAME_CHANGE', | ||||
| @ -21,7 +21,7 @@ export enum SocketMessageType { | ||||
| export interface SocketEvent { | ||||
|   id: string; | ||||
|   timestamp: Date; | ||||
|   type: SocketMessageType; | ||||
|   type: MessageType; | ||||
| } | ||||
|  | ||||
| export interface ConnectedClientInfoEvent extends SocketEvent { | ||||
|  | ||||
| @ -1,8 +1,8 @@ | ||||
| import { message } from 'antd'; | ||||
| import { SocketMessageType } from '../interfaces/socket-events'; | ||||
| import { MessageType } from '../interfaces/socket-events'; | ||||
|  | ||||
| interface SocketMessage { | ||||
|   type: SocketMessageType; | ||||
|   type: MessageType; | ||||
|   data: any; | ||||
| } | ||||
|  | ||||
| @ -96,7 +96,7 @@ export default class WebsocketService { | ||||
|       } | ||||
|  | ||||
|       // Send PONGs | ||||
|       if (message.type === SocketMessageType.PING) { | ||||
|       if (message.type === MessageType.PING) { | ||||
|         this.sendPong(); | ||||
|         return; | ||||
|       } | ||||
| @ -106,7 +106,7 @@ export default class WebsocketService { | ||||
|   // Outbound: Other components can pass an object to `send`. | ||||
|   send(message: any) { | ||||
|     // Sanity check that what we're sending is a valid type. | ||||
|     if (!message.type || !SocketMessageType[message.type]) { | ||||
|     if (!message.type || !MessageType[message.type]) { | ||||
|       console.warn(`Outbound message: Unknown socket message type: "${message.type}" sent.`); | ||||
|     } | ||||
|  | ||||
| @ -116,7 +116,7 @@ export default class WebsocketService { | ||||
|  | ||||
|   // Reply to a PING as a keep alive. | ||||
|   sendPong() { | ||||
|     const pong = { type: SocketMessageType.PONG }; | ||||
|     const pong = { type: MessageType.PONG }; | ||||
|     this.send(pong); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1,14 +1,14 @@ | ||||
| import React from 'react'; | ||||
| import { ComponentStory, ComponentMeta } from '@storybook/react'; | ||||
| import * as FollowerComponent from '../components/Follower'; | ||||
| import SingleFollower from '../components/Follower'; | ||||
|  | ||||
| export default { | ||||
|   title: 'owncast/Follower', | ||||
|   component: FollowerComponent, | ||||
|   component: SingleFollower, | ||||
|   parameters: {}, | ||||
| } as ComponentMeta<typeof FollowerComponent>; | ||||
| } as ComponentMeta<typeof SingleFollower>; | ||||
|  | ||||
| const Template: ComponentStory<typeof FollowerComponent> = args => <FollowerComponent {...args} />; | ||||
| const Template: ComponentStory<typeof SingleFollower> = args => <SingleFollower {...args} />; | ||||
|  | ||||
| export const Example = Template.bind({}); | ||||
| Example.args = { | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Gabe Kangas
					Gabe Kangas