Skip to content

Commit

Permalink
Merge pull request #118 from GTZ-STUDIO/develop
Browse files Browse the repository at this point in the history
Merge develop into master
  • Loading branch information
Verzaccii authored Apr 8, 2024
2 parents 25b24d8 + 7cde3dd commit fe937f4
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 58 deletions.
8 changes: 5 additions & 3 deletions lvlgg_backend/favourite/serializers.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from rest_framework import serializers

from .models import Favourite


class FavouriteSerializer(serializers.ModelSerializer):
blog_id = serializers.IntegerField(source='blog.id')
blog_title = serializers.CharField(source='blog.title')
blog_game = serializers.CharField(source='blog.game')

class Meta:
model = Favourite
fields = "__all__"
fields = ('blog_id', 'blog_title', 'blog_game')
14 changes: 9 additions & 5 deletions lvlgg_backend/favourite/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,12 +247,16 @@ def test_favourite_list(self):
# Test without sign in
response = self.client.get(reverse("favourite_list"))
self.assertEqual(response.status_code, 403)

# User1 sign in check favourite list
#Sign In
sign_in_payload = {"username": "user1", "password": "12345"}
self.client.post(
reverse("sign_in"), sign_in_payload, content_type="application/json"
)

url = "/account/signin/"

response = self.client.post(url, sign_in_payload, content_type="application/json")
self.assertEqual(response.status_code, 200)

#Check Favourites
response = self.client.get(reverse("favourite_list"))
self.assertEqual(response.status_code, 200)
data = json.loads(response.content)
Expand Down
6 changes: 3 additions & 3 deletions lvlgg_backend/favourite/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def get_queryset(self):
200: Success
403: Unauthorized
"""
favourite = Favourite.objects.all()
client = self.request.user
client_favourite = favourite.filter(client=client)
return client_favourite
return Favourite.objects.filter(client=client)


69 changes: 69 additions & 0 deletions lvlgg_frontend/src/Components/FavoriteButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React, { useState, useEffect } from 'react';
import axios from 'axios';

const FavoriteButton = ({ blogId, initialIsFavorited, onToggle }) => {
const backendUrl = process.env.REACT_APP_BACKEND_URL;

const [loading, setLoading] = useState(false);
const [isFavorited, setIsFavorited] = useState(initialIsFavorited);

useEffect(() => {
const fetchFavorites = async () => {
try {
const response = await axios.get(`${backendUrl}/favourite/list/`);
const favorites = response.data.map((favorite) => favorite.blog_id);
setIsFavorited(favorites.includes(blogId));
} catch (error) {
console.error('Failed to fetch favorites:', error);
}
};

fetchFavorites();
}, [backendUrl, blogId]);

const handleToggleFavorite = async () => {
setLoading(true);
setIsFavorited(!isFavorited); // Update the state immediately

try {
const csrfToken = getCookie('csrftoken');
const action = isFavorited ? 'unsubscribe' : 'subscribe';
const method = isFavorited ? 'DELETE' : 'POST';

await axios.request({
url: `${backendUrl}/favourite/${action}/${blogId}/`,
method: method,
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken,
},
withCredentials: true,
});
onToggle();
} catch (error) {
console.error('Failed to toggle favorite:', error);

setIsFavorited(!isFavorited);
} finally {
setLoading(false);
}
};

const getCookie = (name) => {
const cookieValue = document.cookie
.split('; ')
.find((row) => row.startsWith(`${name}=`));
if (cookieValue) {
return cookieValue.split('=')[1];
}
return null;
};

return (
<button onClick={handleToggleFavorite} disabled={loading}>
{isFavorited ? 'Unfavorite' : 'Favorite'}
</button>
);
};

export default FavoriteButton;
8 changes: 7 additions & 1 deletion lvlgg_frontend/src/Components/Navbar.css
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,6 @@
.circle {
width: 50px;
height: 50px;
background-color: #333;
border-radius: 50%;
margin-top:33%;
margin-left: 33%;
Expand All @@ -227,6 +226,13 @@
filter: drop-shadow(0 6px 20px rgba(56, 125, 255, 0.017));
}

.game-image {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 50%;
}

.circle:hover {
box-shadow: 0 6px 20px rgb(41, 230, 236);
-webkit-filter: drop-shadow(0 6px 20px rgb(6, 240, 248));
Expand Down
43 changes: 31 additions & 12 deletions lvlgg_frontend/src/Components/Navbar.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, {useState,useContext,useEffect, useCallback} from "react";
import { Link, useHistory } from "react-router-dom";
import { Link, useHistory, useLocation } from "react-router-dom";
import "./Navbar.css";
import { Button } from "./Button";
import { AuthContext } from "../Contexts/AuthContext";
Expand All @@ -17,10 +17,24 @@ function Navbar() {
const [user, setUser] = useState("");
const [favorites, setFavorites] = useState([]);

const handleClick = () => setClick(!click);
const handleClick = () => {
setClick(!click);
if(isSignedIn){
fetchFavorites();
}
};
const closeMobileMenu = () => setClick(false);

const history = useHistory();
const location = useLocation();

const gameImageMap = {
EldenRing: 'images/eldenRing.png',
Dota2: 'images/dota.jpg',
LeagueOfLegends: 'images/league.png',
BaldursGate3: 'images/baldursGate.png',
CSGO: 'images/csgo.jpg',
};

const handleDropDown = () => {
setIsDropdownOpen(!isDropdownOpen);
Expand All @@ -46,7 +60,7 @@ function Navbar() {
return null;
};

const fetchFavorites = async () => {
const fetchFavorites = useCallback(async () => {
try {
const response = await axios.get(`${backendUrl}/favourite/list/`, {
headers: {
Expand All @@ -56,19 +70,20 @@ function Navbar() {
withCredentials: true,
});
const userFavorites = response.data
.filter((favorite) => favorite.client === parseInt(userPk))
.map((favorite) => favorite.blog);
setFavorites(userFavorites);

} catch (error) {
console.error("Error fetching favorites:", error);
}
};
}, [backendUrl]);

useEffect(() => {
if (isSignedIn) {
fetchFavorites();
}
},);

}, [isSignedIn, fetchFavorites]);


const handleUsername = useCallback(() => {
axios
Expand All @@ -81,7 +96,6 @@ function Navbar() {
})
.then((response) => {
if (response.status === 200) {
console.log("got Username successfully");
setUser(response.data.username);
} else {
console.log("Username change unsuccessful");
Expand Down Expand Up @@ -119,10 +133,14 @@ function Navbar() {
});
};

useEffect(() => {
setIsFavoritesOpen(false);
}, [location.pathname]);

return (
<>
<nav className="navbar">
<div data-testid="Navbar-1" className="navbar-container">
<div data-testid="Navbar-1" className="navbar-container" onClick={handleClick}>
<Link to="/" className="navbar-logo">
LVLUP <i className="fa-solid fa-arrow-up"></i>
</Link>
Expand Down Expand Up @@ -182,17 +200,18 @@ function Navbar() {
)}
</div>
)}
{isSignedIn && (
{isSignedIn && !location.pathname.includes('/blog/') && (
<div className={`favorites-dropdown ${isFavoritesOpen ? 'open' : ''}`} onMouseEnter={handleFavorites} onMouseLeave={handleFavorites}>
<div className="profile-icon">
<img src="/images/star.png" alt="Favourites" />
</div>
{isFavoritesOpen && (
<div className="favorites-dropdown-content">
{favorites.map((favorite) => (
<Link key={favorite} to={`/blog/${favorite}`}>
<Link key={favorite} to={`/blog/${favorite.blog_id}`}>
<div className="circle">
<div className="tooltip">{favorite}</div>
<img className="game-image" src={gameImageMap[favorite.blog_game]} alt={favorite.blog_game} />
<div className="tooltip">{favorite.blog_title}</div>
</div>
</Link>
))}
Expand Down
40 changes: 8 additions & 32 deletions lvlgg_frontend/src/Components/Pages/BlogDetail.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useEffect, useState, useContext, useCallback } from 'react';
import { useParams, useHistory } from 'react-router-dom';
import { AuthContext } from '../../Contexts/AuthContext'
import FavoriteButton from '../FavoriteButton';
import axios from 'axios';
import '../../App.css';

Expand All @@ -18,7 +19,6 @@ const BlogDetail = () => {
const [isDisliked, setIsDisliked] = useState(false);
const [isFavorited, setIsFavorited] = useState(false);


const gameImageMap = {
"EldenRing": "url(/images/eldenRing.png)",
"LeagueOfLegends": "url(/images/league.png)",
Expand Down Expand Up @@ -87,29 +87,6 @@ const BlogDetail = () => {
});
};

const handleFavorite = () => {
const csrfToken = getCookie('csrftoken');
const action = isFavorited ? 'unsubscribe' : 'subscribe';
const method = isFavorited ? 'DELETE' : 'POST';
axios.request({
url: `${backendUrl}/favourite/${action}/${id}/`,
method: method,
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken,
},
withCredentials: true,
})
.then(response => {
setIsFavorited(!isFavorited);
localStorage.setItem(`favorited-${id}`, !isFavorited);
alert(`Guide ${isFavorited ? 'Unfavorited' : 'Favorited'}`);
})
.catch(error => {
console.error(`Error ${isFavorited ? 'unfavoriting' : 'favoriting'} blog:`, error);
});
};

const fetchComments = useCallback(() => {
axios.get(`${backendUrl}/comment/get_comments/${id}/`)
.then(response => {
Expand Down Expand Up @@ -158,15 +135,12 @@ const BlogDetail = () => {
axios.get(`${backendUrl}/blog/get_blog/?id=${id}`)
.then(response => {
setBlog(response.data.blogs[0]);

const isFavoritedLocal = localStorage.getItem(`favorited-${id}`);
setIsFavorited(isFavoritedLocal === 'true');

fetchComments();
})
.catch(error => {
console.error('Error fetching blog:', error);
});

}, [id, history, backendUrl, fetchComments]);

return (
Expand All @@ -185,9 +159,11 @@ const BlogDetail = () => {
<div className="like-dislike-buttons">
<button onClick={handleLike}>Like</button>
<button onClick={handleDislike}>Dislike</button>
<button onClick={handleFavorite} className="favorite-button">
{isFavorited ? 'Unfavorite' : 'Favorite'}
</button>
<FavoriteButton
blogId={blog?.id}
initialIsFavorited={isFavorited}
onToggle={() => setIsFavorited(!isFavorited)}
/>
</div>
</div>
)}
Expand Down Expand Up @@ -218,4 +194,4 @@ const BlogDetail = () => {
);
};

export default BlogDetail;
export default BlogDetail;
1 change: 0 additions & 1 deletion lvlgg_frontend/src/Components/Pages/SignIn.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const SignIn = () => {
const history = useHistory();

const handleSignIn = () => {
// Handle sign-in logic here
console.log("Signing in...");
axios
.post(`${backendUrl}/account/signin/`, {
Expand Down
2 changes: 1 addition & 1 deletion lvlgg_frontend/src/Components/RecommendedGuides.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const RecommendedGuides = () => {
EldenRing: 'images/eldenRing.png',
Dota2: 'images/dota.jpg',
LeagueOfLegends: 'images/league.png',
BaldursGate3: 'images/baldursgate.png',
BaldursGate3: 'images/baldursGate.png',
CSGO: 'images/csgo.jpg',
};

Expand Down

0 comments on commit fe937f4

Please sign in to comment.