mirror of
https://github.com/arkorty/Osborne.git
synced 2026-03-18 00:57:14 +00:00
user fixes
This commit is contained in:
@@ -208,6 +208,7 @@ const Room = () => {
|
|||||||
const socketRef = useRef<WebSocket | null>(null);
|
const socketRef = useRef<WebSocket | null>(null);
|
||||||
const editorRef = useRef<CodeEditorRef>(null);
|
const editorRef = useRef<CodeEditorRef>(null);
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
const currentUserRef = useRef<User | null>(null);
|
||||||
const [isClient, setIsClient] = useState(false);
|
const [isClient, setIsClient] = useState(false);
|
||||||
const [content, setContent] = useState("");
|
const [content, setContent] = useState("");
|
||||||
const [status, setStatus] = useState("Disconnected");
|
const [status, setStatus] = useState("Disconnected");
|
||||||
@@ -317,6 +318,10 @@ const Room = () => {
|
|||||||
contentRef.current = content;
|
contentRef.current = content;
|
||||||
}, [content]);
|
}, [content]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
currentUserRef.current = currentUser;
|
||||||
|
}, [currentUser]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsClient(true);
|
setIsClient(true);
|
||||||
|
|
||||||
@@ -604,7 +609,19 @@ const Room = () => {
|
|||||||
|
|
||||||
const pingInterval = setInterval(() => {
|
const pingInterval = setInterval(() => {
|
||||||
if (socketRef.current?.readyState === WebSocket.OPEN) {
|
if (socketRef.current?.readyState === WebSocket.OPEN) {
|
||||||
socketRef.current.send(JSON.stringify({ type: "ping" }));
|
socketRef.current.send(JSON.stringify({ type: "ping", code: roomCode }));
|
||||||
|
|
||||||
|
// Also send user activity update to keep status current
|
||||||
|
if (currentUserRef.current) {
|
||||||
|
const activityMessage: UserActivity = {
|
||||||
|
type: "user-activity",
|
||||||
|
code: roomCode,
|
||||||
|
userId: currentUserRef.current.id,
|
||||||
|
isTyping: false,
|
||||||
|
currentLine: undefined
|
||||||
|
};
|
||||||
|
socketRef.current.send(JSON.stringify(activityMessage));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, 30000);
|
}, 30000);
|
||||||
|
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ export const CommentsPanel: React.FC<CommentsPageProps> = ({
|
|||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<span className="text-xs font-medium text-foreground">
|
<span className="text-xs font-medium text-foreground">
|
||||||
{comment.author}
|
{currentUser && comment.authorId === currentUser.id ? 'You' : comment.author}
|
||||||
</span>
|
</span>
|
||||||
{comment.lineNumber !== null && (
|
{comment.lineNumber !== null && (
|
||||||
<Badge
|
<Badge
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ export const LeftPanel: React.FC<LeftPanelProps> = ({
|
|||||||
const [localMediaFiles, setLocalMediaFiles] = useState<MediaFile[]>(mediaFiles);
|
const [localMediaFiles, setLocalMediaFiles] = useState<MediaFile[]>(mediaFiles);
|
||||||
const [usersScrollState, setUsersScrollState] = useState({ top: false, bottom: false });
|
const [usersScrollState, setUsersScrollState] = useState({ top: false, bottom: false });
|
||||||
const [mediaScrollState, setMediaScrollState] = useState({ top: false, bottom: false });
|
const [mediaScrollState, setMediaScrollState] = useState({ top: false, bottom: false });
|
||||||
|
const [statusUpdateTrigger, setStatusUpdateTrigger] = useState(0);
|
||||||
|
|
||||||
const usersScrollRef = useRef<HTMLDivElement>(null);
|
const usersScrollRef = useRef<HTMLDivElement>(null);
|
||||||
const mediaScrollRef = useRef<HTMLDivElement>(null);
|
const mediaScrollRef = useRef<HTMLDivElement>(null);
|
||||||
@@ -69,6 +70,20 @@ export const LeftPanel: React.FC<LeftPanelProps> = ({
|
|||||||
setActiveUsers(users);
|
setActiveUsers(users);
|
||||||
}, [users]);
|
}, [users]);
|
||||||
|
|
||||||
|
// Update user statuses periodically
|
||||||
|
useEffect(() => {
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
setStatusUpdateTrigger(prev => prev + 1);
|
||||||
|
}, 5000); // Update every 5 seconds to be more responsive
|
||||||
|
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Force re-render when status should be updated (dependency on statusUpdateTrigger)
|
||||||
|
useEffect(() => {
|
||||||
|
// This effect doesn't need to do anything, just triggers re-render
|
||||||
|
}, [statusUpdateTrigger]);
|
||||||
|
|
||||||
// Scroll detection function
|
// Scroll detection function
|
||||||
const handleScroll = (element: HTMLDivElement | null, setState: (state: { top: boolean; bottom: boolean }) => void) => {
|
const handleScroll = (element: HTMLDivElement | null, setState: (state: { top: boolean; bottom: boolean }) => void) => {
|
||||||
if (!element) return;
|
if (!element) return;
|
||||||
@@ -579,6 +594,7 @@ export const LeftPanel: React.FC<LeftPanelProps> = ({
|
|||||||
onClose={() => handleModalChange(null)}
|
onClose={() => handleModalChange(null)}
|
||||||
onDelete={onFileDelete}
|
onDelete={onFileDelete}
|
||||||
getFileUrl={getFileUrl}
|
getFileUrl={getFileUrl}
|
||||||
|
currentUser={currentUser}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -23,12 +23,22 @@ interface MediaFile {
|
|||||||
uploadedBy: string;
|
uploadedBy: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface User {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
color: string;
|
||||||
|
lastSeen: Date;
|
||||||
|
isTyping?: boolean;
|
||||||
|
currentLine?: number;
|
||||||
|
}
|
||||||
|
|
||||||
interface MediaModalProps {
|
interface MediaModalProps {
|
||||||
file: MediaFile | null;
|
file: MediaFile | null;
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onDelete?: (fileId: string) => void;
|
onDelete?: (fileId: string) => void;
|
||||||
getFileUrl: (file: MediaFile) => string;
|
getFileUrl: (file: MediaFile) => string;
|
||||||
|
currentUser?: User | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MediaModal: React.FC<MediaModalProps> = ({
|
export const MediaModal: React.FC<MediaModalProps> = ({
|
||||||
@@ -36,7 +46,8 @@ export const MediaModal: React.FC<MediaModalProps> = ({
|
|||||||
isOpen,
|
isOpen,
|
||||||
onClose,
|
onClose,
|
||||||
onDelete,
|
onDelete,
|
||||||
getFileUrl
|
getFileUrl,
|
||||||
|
currentUser
|
||||||
}) => {
|
}) => {
|
||||||
if (!isOpen || !file) return null;
|
if (!isOpen || !file) return null;
|
||||||
|
|
||||||
@@ -169,7 +180,7 @@ export const MediaModal: React.FC<MediaModalProps> = ({
|
|||||||
{file.type.split('/')[1] || 'file'}
|
{file.type.split('/')[1] || 'file'}
|
||||||
</Badge>
|
</Badge>
|
||||||
<span className="text-sm text-muted-foreground">
|
<span className="text-sm text-muted-foreground">
|
||||||
Uploaded by {file.uploadedBy}
|
Uploaded by {currentUser && file.uploadedBy === currentUser.name ? 'You' : file.uploadedBy}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex space-x-2">
|
<div className="flex space-x-2">
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ export const CommentsPanel: React.FC<CommentsPageProps> = ({
|
|||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<span className="text-xs font-medium text-foreground">
|
<span className="text-xs font-medium text-foreground">
|
||||||
{comment.author}
|
{currentUser && comment.authorId === currentUser.id ? 'You' : comment.author}
|
||||||
</span>
|
</span>
|
||||||
{comment.lineNumber !== null && (
|
{comment.lineNumber !== null && (
|
||||||
<Badge
|
<Badge
|
||||||
|
|||||||
Reference in New Issue
Block a user