UPDATE: User page allows for profile image upload if on their own profile

This commit is contained in:
JustIceO7
2025-02-28 00:37:25 +00:00
parent 2b325746f5
commit 6e4a14c5b6
4 changed files with 94 additions and 20 deletions

View File

@@ -0,0 +1,24 @@
import { useEffect, useState } from "react"
export function useSameUser({ username }: { username: string | undefined }) {
const [isSame, setIsSame] = useState(false);
useEffect(() => {
const fetchStatus = async () => {
try {
const response = await fetch(`/api/user/same/${username}`);
if (!response.ok) {
throw new Error("Failed to validate user");
}
const data = await response.json();
setIsSame(data.same);
} catch (error) {
console.error("Error:", error);
}
};
fetchStatus();
}, []);
return isSame;
}

View File

@@ -11,6 +11,7 @@ import LoadingScreen from "../components/Layout/LoadingScreen";
import { StreamListItem } from "../components/Layout/ListItem";
import { CameraIcon } from "lucide-react";
import { getCategoryThumbnail } from "../utils/thumbnailUtils";
import { useSameUser } from "../hooks/useSameUser";
interface UserProfileData {
id: number;
@@ -36,16 +37,29 @@ const UserPage: React.FC = () => {
const { showAuthModal, setShowAuthModal } = useAuthModal();
const { username: loggedInUsername } = useAuth();
const { username } = useParams();
const [isUser, setIsUser] = useState(true);
const isUser = useSameUser({username});
const navigate = useNavigate();
const bgColors = {
personal: "",
streamer:
"bg-gradient-radial from-[rgba(255, 0, 241, 0.5)] via-[rgba(4, 0, 255, 0.5)] to-[rgba(255, 0, 0, 0.5)]", // offline streamer
user: "bg-gradient-radial from-[rgba(255, 0, 241, 0.5)] via-[rgba(4, 0, 255, 0.5)] to-[rgba(255, 0, 241, 0.5)]",
admin:
"bg-gradient-to-r from-[rgba(255,100,100,0.5)] via-transparent to-[rgba(100,100,255,0.5)]",
// Saves uploaded image as profile picture for the user
const saveUploadedImage = async (event) => {
const img = event.target.files[0];
if (img) {
const formData = new FormData();
formData.append('image', img);
try {
const response = await fetch('/api/user/profile_picture/upload', {
method: 'POST',
body: formData,
});
if (response.ok) {
console.log("Success");
}
} catch (error) {
console.log("Failure");
}
}
};
useEffect(() => {
@@ -108,11 +122,7 @@ const UserPage: React.FC = () => {
return (
<DynamicPageContent
className={`min-h-screen ${/*
profileData.isLive
? "bg-gradient-radial from-[#1a6600] via-[#66ff66] to-[#003900]"
: bgColors[userPageVariant]
*/ ""} text-white flex flex-col`}
className={`min-h-screen text-white flex flex-col`}
>
<div className="flex justify-evenly justify-self-center items-center h-full px-4 py-8 max-w-[80vw] w-full">
<div className="grid grid-cols-4 grid-rows-[0.1fr_4fr] w-full gap-8">
@@ -138,18 +148,25 @@ const UserPage: React.FC = () => {
{/* Profile Picture */}
<div
className="relative -top-[40px] sm:-top-[90px] w-[16vw] h-[16vw] sm:w-[20vw] sm:h-[20vw] max-w-[10em] max-h-[10em]
rounded-full overflow-hidden flex-shrink-0 border-4 border-[var(--user-pfp-border)] inset-0 z-20"
rounded-full flex-shrink-0 border-4 border-[var(--user-pfp-border)] inset-0 z-20"
style={{ boxShadow: "var(--user-pfp-border-shadow)" }}
>
<label
className={`relative ${isUser ? "cursor-pointer group" : ""}`}
className={`relative ${isUser ? "cursor-pointer group" : ""} overflow-visible`}
>
{/* If user is live then displays a live div */}
{Boolean(profileData.isLive) && (
<div className="absolute -bottom-2 left-1/2 transform -translate-x-1/2 bg-red-600 text-white text-sm font-bold py-1 sm:px-5 px-4 z-30 flex items-center justify-center rounded-tr-xl rounded-bl-xl rounded-tl-xl rounded-br-xl">
LIVE
</div>
)}
<img
src="/images/monkey.png"
alt={`${profileData.username}'s profile`}
className="sm:w-full h-full object-cover rounded-full"
className="sm:w-full h-full object-cover rounded-full relative z-0"
/>
{/* If current user is the profile user then allow profile picture swap */}
{isUser && (
<>
<div className="absolute inset-0 bg-black/20 opacity-0 group-hover:opacity-100 transition-opacity duration-200 rounded-full"></div>
@@ -159,7 +176,11 @@ const UserPage: React.FC = () => {
className="text-white bg-black/50 p-1 rounded-full"
/>
</div>
<input type="file" className="hidden" />
<input
type="file"
className="hidden"
onChange={saveUploadedImage}
accept="image/*" />
</>
)}
</label>

View File

@@ -1,4 +1,4 @@
from flask import Blueprint, jsonify, session
from flask import Blueprint, jsonify, session, request
from utils.user_utils import *
from utils.auth import *
from utils.utils import get_category_id
@@ -6,6 +6,9 @@ from blueprints.middleware import login_required
from utils.email import send_email, forgot_password_body, newsletter_conf
import redis
from io import BytesIO
from PIL import Image
redis_url = "redis://redis:6379/1"
r = redis.from_url(redis_url, decode_responses=True)
@@ -33,6 +36,31 @@ def user_stream_key(username: str):
data = db.fetchone("SELECT stream_key FROM users WHERE user_id = ?", (user_id,))
return jsonify({"stream_key": data["stream_key"]})
@login_required
@user_bp.route('/user/profile_picture/upload', methods=['POST'])
def user_profile_picture_save():
"""
Saves user profile picture
"""
user_id = session.get("user_id")
image = request.files['image']
ext = image.filename.split('.')[-1]
image.save(f"/web_server/stream_data/{user_id}.{ext}")
return "Success", 200
@login_required
@user_bp.route('/user/same/<string:username>')
def user_is_same(username):
"""
Returns if given user is current user
"""
current_username = session.get("username")
if username == current_username:
return jsonify({"same": True})
return jsonify({"same": False})
## Subscription Routes
@login_required
@user_bp.route('/user/subscription/<string:streamer_name>')
@@ -146,7 +174,7 @@ def user_login_status():
'username': username,
'user_id': user_id})
@user_bp.route('/user/forgot_password/<string:email>', methods=['GET','POST'])
@user_bp.route('/user/forgot_password/<string:email>', methods=['POST'])
def user_forgot_password(email):
"""
Initializes the function to handle password reset

View File

@@ -28,4 +28,5 @@ flask-oauthlib==0.9.6
celery==5.2.3
redis==5.2.1
python-dateutil
Authlib==1.4.1
Authlib==1.4.1
Pillow==11.1.0