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:
@@ -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}`))}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -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>}>
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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 = ?
|
||||||
|
|||||||
Reference in New Issue
Block a user