mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: add live users avatar indicators
This commit is contained in:
parent
54718d7111
commit
6a47202c78
5 changed files with 100 additions and 15 deletions
67
apps/web/components/Objects/Editor/ActiveAvatars.tsx
Normal file
67
apps/web/components/Objects/Editor/ActiveAvatars.tsx
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import UserAvatar from '../UserAvatar'
|
||||
import { useSession } from '@components/Contexts/SessionContext'
|
||||
import { getUserAvatarMediaDirectory } from '@services/media/media';
|
||||
import { getCollaborationServerUrl } from '@services/config/config';
|
||||
import { useOrg } from '@components/Contexts/OrgContext';
|
||||
|
||||
type ActiveAvatarsProps = {
|
||||
mouseMovements: any;
|
||||
userRandomColor: string;
|
||||
}
|
||||
|
||||
function ActiveAvatars(props: ActiveAvatarsProps) {
|
||||
const session = useSession() as any;
|
||||
const org = useOrg() as any;
|
||||
const [activeUsers, setActiveUsers] = useState({} as any);
|
||||
|
||||
/* Collaboration Features */
|
||||
const collab = getCollaborationServerUrl()
|
||||
const isCollabEnabledOnThisOrg = org?.config.config.GeneralConfig.collaboration && collab
|
||||
|
||||
// Get users from the mouseMovements object
|
||||
useEffect(() => {
|
||||
const users: any = {};
|
||||
Object.keys(props.mouseMovements).forEach((key) => {
|
||||
users[props.mouseMovements[key].user.user_uuid] = props.mouseMovements[key].user;
|
||||
});
|
||||
|
||||
// Remove the current user from the list
|
||||
delete users[session.user.user_uuid];
|
||||
|
||||
setActiveUsers(users);
|
||||
}
|
||||
, [props.mouseMovements, session.user, org]);
|
||||
|
||||
|
||||
return (
|
||||
<div className=''>
|
||||
|
||||
<div className='flex -space-x-2 transition-all ease-linear'>
|
||||
{isCollabEnabledOnThisOrg && Object.keys(activeUsers).map((key) => (
|
||||
<div className='flex' style={{ position: 'relative' }} key={key}>
|
||||
<UserAvatar
|
||||
key={key}
|
||||
width={40}
|
||||
border="border-4"
|
||||
rounded="rounded-full"
|
||||
avatar_url={getUserAvatarMediaDirectory(activeUsers[key].user_uuid, activeUsers[key].avatar_image) as string}
|
||||
/>
|
||||
<div className="h-2 w-2 rounded-full" style={{ position: 'absolute', bottom: -5, right: 16, backgroundColor: props.mouseMovements[key].color }} />
|
||||
</div>
|
||||
))}
|
||||
{session.isAuthenticated && (
|
||||
<div className='z-50'>
|
||||
<UserAvatar
|
||||
width={40}
|
||||
border="border-4"
|
||||
rounded="rounded-full"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ActiveAvatars
|
||||
|
|
@ -48,6 +48,7 @@ import UserAvatar from '../UserAvatar'
|
|||
import randomColor from 'randomcolor'
|
||||
import Collaboration from '@tiptap/extension-collaboration'
|
||||
import CollaborationCursor from '@tiptap/extension-collaboration-cursor'
|
||||
import ActiveAvatars from './ActiveAvatars'
|
||||
|
||||
interface Editor {
|
||||
content: string
|
||||
|
|
@ -59,6 +60,7 @@ interface Editor {
|
|||
hocuspocusProvider: any,
|
||||
isCollabEnabledOnThisOrg: boolean
|
||||
userRandomColor: string
|
||||
mouseMovements: any
|
||||
setContent: (content: string) => void
|
||||
}
|
||||
|
||||
|
|
@ -137,13 +139,14 @@ function Editor(props: Editor) {
|
|||
...(props.isCollabEnabledOnThisOrg ? [
|
||||
Collaboration.configure({
|
||||
document: props.hocuspocusProvider?.document,
|
||||
|
||||
}),
|
||||
|
||||
CollaborationCursor.configure({
|
||||
provider: props.hocuspocusProvider,
|
||||
user: {
|
||||
name: props.session.user.first_name + ' ' + props.session.user.last_name,
|
||||
color: props.userRandomColor ,
|
||||
color: props.userRandomColor,
|
||||
},
|
||||
}),
|
||||
] : []),
|
||||
|
|
@ -267,14 +270,7 @@ function Editor(props: Editor) {
|
|||
/>
|
||||
|
||||
<EditorUserProfileWrapper>
|
||||
{!session.isAuthenticated && <span>Loading</span>}
|
||||
{session.isAuthenticated && (
|
||||
<UserAvatar
|
||||
width={40}
|
||||
border="border-4"
|
||||
rounded="rounded-full"
|
||||
/>
|
||||
)}
|
||||
<ActiveAvatars userRandomColor={props.userRandomColor} mouseMovements={props.mouseMovements} />
|
||||
</EditorUserProfileWrapper>
|
||||
</EditorUsersSection>
|
||||
</EditorTop>
|
||||
|
|
|
|||
|
|
@ -100,6 +100,14 @@ function EditorWrapper(props: EditorWrapperProps): JSX.Element {
|
|||
document: doc,
|
||||
|
||||
// TODO(alpha code): This whole block of code should be improved to something more efficient and less hacky
|
||||
onConnect: () => {
|
||||
// Set the online page instance ID
|
||||
setOnlinePageInstanceID(uuidv4());
|
||||
|
||||
// Set the user color
|
||||
setThisPageColor(randomColor({ luminosity: 'light' }) as string);
|
||||
},
|
||||
|
||||
onAwarenessUpdate: ({ states }) => {
|
||||
const usersStates = states;
|
||||
/* Showing user mouse movement */
|
||||
|
|
@ -121,6 +129,7 @@ function EditorWrapper(props: EditorWrapperProps): JSX.Element {
|
|||
};
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -162,7 +171,7 @@ function EditorWrapper(props: EditorWrapperProps): JSX.Element {
|
|||
return (
|
||||
<>
|
||||
<Toast></Toast>
|
||||
<MouseMovements movements={mouseMovements} onlinePageInstanceID={onlinePageInstanceID} />
|
||||
<MouseMovements org={props.org} movements={mouseMovements} onlinePageInstanceID={onlinePageInstanceID} />
|
||||
<OrgProvider orgslug={props.org.slug}>
|
||||
{!session.isLoading && (<Editor
|
||||
org={props.org}
|
||||
|
|
@ -175,6 +184,7 @@ function EditorWrapper(props: EditorWrapperProps): JSX.Element {
|
|||
hocuspocusProvider={provider}
|
||||
isCollabEnabledOnThisOrg={isCollabEnabledOnThisOrg}
|
||||
userRandomColor={thisPageColor}
|
||||
mouseMovements={mouseMovements}
|
||||
></Editor>)}
|
||||
</OrgProvider>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { m, motion } from "framer-motion";
|
||||
import React from 'react'
|
||||
import { getCollaborationServerUrl } from "@services/config/config";
|
||||
import { motion } from "framer-motion";
|
||||
import React, { useEffect } from 'react'
|
||||
|
||||
interface User {
|
||||
user_uuid: string;
|
||||
|
|
@ -18,12 +19,24 @@ interface Movement {
|
|||
interface MouseMovementsProps {
|
||||
movements: Record<string, Movement>;
|
||||
onlinePageInstanceID: string;
|
||||
org ?: any;
|
||||
}
|
||||
|
||||
function MouseMovements({ movements, onlinePageInstanceID }: MouseMovementsProps): JSX.Element {
|
||||
function MouseMovements({ movements, onlinePageInstanceID, org }: MouseMovementsProps): JSX.Element {
|
||||
|
||||
|
||||
/* Collaboration config */
|
||||
const collab = getCollaborationServerUrl()
|
||||
const isCollabEnabledOnThisOrg = org?.config.config.GeneralConfig.collaboration && collab
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
}
|
||||
, [movements, org]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{Object.keys(movements).map((key) => (
|
||||
{isCollabEnabledOnThisOrg && Object.keys(movements).map((key) => (
|
||||
movements[key].onlinePageInstanceID !== onlinePageInstanceID && (<motion.div
|
||||
key={key}
|
||||
className="flex -space-x-2"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue