UPDATE: Display altered message in chat when sent by streamer;

FIX: Chat order;
FIX: `num_viewers` display on `HomePage`;
FIX: Remove ability for streamer to follow themselves;
This commit is contained in:
Chris-1010
2025-03-06 22:40:21 +00:00
parent 555aedffcb
commit 9c44dfe598
4 changed files with 59 additions and 45 deletions

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect, useRef } from "react"; import React, { useState, useEffect, useRef } from "react";
import Input from "../Input/Input"; import Input from "../Input/Input";
import Button, { ToggleButton } from "../Input/Button"; import Button from "../Input/Button";
import AuthModal from "../Auth/AuthModal"; import AuthModal from "../Auth/AuthModal";
import { useAuthModal } from "../../hooks/useAuthModal"; import { useAuthModal } from "../../hooks/useAuthModal";
import { useAuth } from "../../context/AuthContext"; import { useAuth } from "../../context/AuthContext";
@@ -9,6 +9,7 @@ import { useChat } from "../../context/ChatContext";
import { ArrowLeftFromLineIcon, ArrowRightFromLineIcon, CrownIcon } from "lucide-react"; import { ArrowLeftFromLineIcon, ArrowRightFromLineIcon, CrownIcon } from "lucide-react";
interface ChatMessage { interface ChatMessage {
chatter_id: number;
chatter_username: string; chatter_username: string;
message: string; message: string;
time_sent: string; time_sent: string;
@@ -189,7 +190,12 @@ const ChatPanel: React.FC<ChatPanelProps> = ({ streamId, onViewerCountChange })
{/* Message List */} {/* Message List */}
<div ref={chatContainerRef} id="chat-message-list" className="w-full h-full overflow-y-auto mb-4 space-y-2 rounded-md"> <div ref={chatContainerRef} id="chat-message-list" className="w-full h-full overflow-y-auto mb-4 space-y-2 rounded-md">
{messages.map((msg, index) => ( {messages.map((msg, index) => (
<div key={index} className="flex items-start space-x-2 bg-gray-800 rounded p-2 text-white relative"> <div
key={index}
className={`flex items-start space-x-2 rounded p-2 text-white relative ${
msg.chatter_id === streamId ? "bg-[#0000a0] font-black border-4 border-double border-red-500" : "bg-gray-800"
}`}
>
{/* User avatar with image */} {/* User avatar with image */}
<div <div
className={`w-2em h-2em rounded-full overflow-hidden flex-shrink-0 ${ className={`w-2em h-2em rounded-full overflow-hidden flex-shrink-0 ${
@@ -213,8 +219,12 @@ const ChatPanel: React.FC<ChatPanelProps> = ({ streamId, onViewerCountChange })
<div className="flex items-center space-x-0.5em"> <div className="flex items-center space-x-0.5em">
{/* Username */} {/* Username */}
<span <span
className={`flex items-center gap-2 font-bold text-[1em] ${ className={`flex items-center gap-2 ${
msg.chatter_username === username ? "text-purple-600" : "text-green-400 cursor-pointer" msg.chatter_id === streamId
? "text-[#ff0000] font-black text-[1.2rem]"
: msg.chatter_username === username
? "text-purple-600 font-bold text-[1em]"
: "text-green-400 font-bold text-[1em] cursor-pointer"
}`} }`}
onClick={() => (msg.chatter_username === username ? null : (window.location.href = `/user/${msg.chatter_username}`))} onClick={() => (msg.chatter_username === username ? null : (window.location.href = `/user/${msg.chatter_username}`))}
> >

View File

@@ -46,9 +46,6 @@ const VideoPage: React.FC<VideoPageProps> = ({ streamerId }) => {
}; };
}, [showCheckout]); }, [showCheckout]);
// Increment minutes of stream time every minute
useEffect;
useEffect(() => { useEffect(() => {
// Fetch stream data for this streamer // Fetch stream data for this streamer
fetch(`/api/streams/${streamerId}/data`).then((res) => { fetch(`/api/streams/${streamerId}/data`).then((res) => {
@@ -157,9 +154,9 @@ const VideoPage: React.FC<VideoPageProps> = ({ streamerId }) => {
e.currentTarget.onerror = null; e.currentTarget.onerror = null;
}} }}
alt="streamer" alt="streamer"
className="w-[3em] h-[3em] rounded-full border-[0.15em] border-purple-500 cursor-pointer" className="w-[3em] h-[3em] rounded-full border-[0.15em] border-purple-500 object-cover cursor-pointer"
onClick={() => navigate(`/user/${streamerName}`)} onClick={() => navigate(`/user/${streamerName}`)}
style={{ backgroundColor: 'white' }} style={{ backgroundColor: "white" }}
/> />
<button className="text-white font-bold hover:underline mt-[0.5em]" onClick={() => navigate(`/user/${streamerName}`)}> <button className="text-white font-bold hover:underline mt-[0.5em]" onClick={() => navigate(`/user/${streamerName}`)}>
{streamerName} {streamerName}
@@ -178,9 +175,10 @@ const VideoPage: React.FC<VideoPageProps> = ({ streamerId }) => {
</div> </div>
{/* Streamer Info */} {/* Streamer Info */}
{username != streamerName && (
<div className="flex items-center gap-[0.75em] flex-col lg:flex-row"> <div className="flex items-center gap-[0.75em] flex-col lg:flex-row">
<div className="group flex flex-col items-center lg:items-start"> <div className="group flex flex-col items-center lg:items-start">
{!isFollowing && username === streamerName ? ( {!isFollowing ? (
<button <button
className="bg-purple-600 text-white font-bold px-[1.5em] py-[0.5em] rounded-md hover:bg-purple-700 text-sm" className="bg-purple-600 text-white font-bold px-[1.5em] py-[0.5em] rounded-md hover:bg-purple-700 text-sm"
onClick={() => followUser(streamerId, setShowAuthModal)} onClick={() => followUser(streamerId, setShowAuthModal)}
@@ -198,6 +196,7 @@ const VideoPage: React.FC<VideoPageProps> = ({ streamerId }) => {
)} )}
</div> </div>
</div> </div>
)}
{/* Stream Stats */} {/* Stream Stats */}
<div className="flex flex-col items-center"> <div className="flex flex-col items-center">
@@ -212,9 +211,10 @@ const VideoPage: React.FC<VideoPageProps> = ({ streamerId }) => {
</div> </div>
{/* Subscribe Button */} {/* Subscribe Button */}
{username != streamerName && (
<div className="flex flex-col items-center"> <div className="flex flex-col items-center">
<button <button
className={`bg-red-600 text-white font-bold px-[1.5em] py-[0.5em] rounded-md className={`bg-red-600 text-white text-sm font-bold px-[1.5em] py-[0.5em] rounded-md
${isStripeReady ? "hover:bg-red-700" : "opacity-20 cursor-not-allowed"} transition-all`} ${isStripeReady ? "hover:bg-red-700" : "opacity-20 cursor-not-allowed"} transition-all`}
onClick={() => { onClick={() => {
if (!isLoggedIn) { if (!isLoggedIn) {
@@ -227,6 +227,7 @@ const VideoPage: React.FC<VideoPageProps> = ({ streamerId }) => {
{isStripeReady ? "Subscribe" : "Loading..."} {isStripeReady ? "Subscribe" : "Loading..."}
</button> </button>
</div> </div>
)}
</div> </div>
{showCheckout && ( {showCheckout && (
<Suspense fallback={<div>Loading checkout...</div>}> <Suspense fallback={<div>Loading checkout...</div>}>

View File

@@ -76,9 +76,10 @@ def get_past_chat(stream_id: int):
# fetched in format: [(username, message, time_sent, is_subscribed)] # fetched in format: [(username, message, time_sent, is_subscribed)]
all_chats = db.fetchall(""" all_chats = db.fetchall("""
SELECT username, message, time_sent, is_subscribed SELECT user_id, username, message, time_sent, is_subscribed
FROM ( FROM (
SELECT SELECT
u.user_id,
u.username, u.username,
c.message, c.message,
c.time_sent, c.time_sent,
@@ -95,11 +96,13 @@ def get_past_chat(stream_id: int):
) subquery ) subquery
ORDER BY time_sent ASC; ORDER BY time_sent ASC;
""", (stream_id, stream_id)) """, (stream_id, stream_id))
#! ASC - Oldest to Newest
db.close_connection() db.close_connection()
# Create JSON output of chat_history to pass through NGINX proxy # Create JSON output of chat_history to pass through NGINX proxy
chat_history = [{"chatter_username": chat["username"], chat_history = [{"chatter_id": chat["user_id"],
"chatter_username": chat["username"],
"message": chat["message"], "message": chat["message"],
"time_sent": chat["time_sent"], "time_sent": chat["time_sent"],
"is_subscribed": bool(chat["is_subscribed"])} for chat in all_chats] "is_subscribed": bool(chat["is_subscribed"])} for chat in all_chats]

View File

@@ -100,7 +100,7 @@ def get_user_category_recommendations(user_id = 1, no_categories: int = 4) -> Op
""" """
with Database() as db: with Database() as db:
categories = db.fetchall(""" categories = db.fetchall("""
SELECT categories.category_id, categories.category_name SELECT categories.category_id, categories.category_name, categories.num_viewers
FROM categories FROM categories
JOIN user_preferences ON categories.category_id = user_preferences.category_id JOIN user_preferences ON categories.category_id = user_preferences.category_id
WHERE user_preferences.user_id = ? WHERE user_preferences.user_id = ?