Changeset 7621d7b for frontend/src/pages


Ignore:
Timestamp:
02/08/26 15:38:51 (5 months ago)
Author:
Filip Gavrilovski <filipgavrilovski28@…>
Branches:
main
Children:
821dc0e
Parents:
799f27d
Message:

implement adding a review

File:
1 edited

Legend:

Unmodified
Added
Removed
  • frontend/src/pages/SongDetail.tsx

    r799f27d r7621d7b  
    6767        const [loading, setLoading] = useState(true);
    6868        const [error, setError] = useState<string | null>(null);
    69 
     69        const [showReviewModal, setShowReviewModal] = useState(false);
     70        const [reviewRating, setReviewRating] = useState(0);
     71        const [reviewComment, setReviewComment] = useState("");
     72        const [hoverRating, setHoverRating] = useState(0);
     73        console.log(user);
    7074        useEffect(() => {
    7175                const fetchSong = async () => {
     
    8488                if (id) fetchSong();
    8589        }, [id]);
     90
     91        const handleSubmitReview = async () => {
     92                if (reviewRating === 0) {
     93                        // todo: replace with toast
     94                        alert("Please select a rating");
     95                        return;
     96                }
     97                try {
     98                        await axiosInstance.post(`reviews/${song?.id}`, {
     99                                grade: reviewRating,
     100                                comment: reviewComment,
     101                        });
     102                        const response = await axiosInstance.get(`/songs/${id}/details`);
     103                        setSong(response.data);
     104                } catch (err) {
     105                        // todo: replace with toast
     106                        console.error("Error submitting review:", err);
     107                } finally {
     108                        setShowReviewModal(false);
     109                        setReviewRating(0);
     110                        setReviewComment("");
     111                        setHoverRating(0);
     112                }
     113        };
     114
     115        const deleteReview = async () => {
     116                try {
     117                        await axiosInstance.delete(`reviews/${song?.id}`);
     118                        const response = await axiosInstance.get(`/songs/${id}/details`);
     119                        setSong(response.data);
     120                } catch (err) {
     121                        console.error("Error deleting review:", err);
     122                }
     123        };
    86124
    87125        const toggleLike = async () => {
     
    294332                                </div>
    295333
    296                                 {/* Play button — plays in persistent mini-player */}
    297                                 {song.link && (
    298                                         <section className="mb-10">
    299                                                 {currentSong?.id === song.id ? (
    300                                                         <div className="bg-[#1a1a2e]/60 rounded-xl p-4 flex items-center gap-3">
    301                                                                 <div className="w-10 h-10 rounded-full bg-[#1db954] flex items-center justify-center text-black animate-pulse">
    302                                                                         <svg
    303                                                                                 className="w-5 h-5"
    304                                                                                 fill="currentColor"
    305                                                                                 viewBox="0 0 24 24"
    306                                                                         >
    307                                                                                 <path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
    308                                                                         </svg>
    309                                                                 </div>
    310                                                                 <p className="text-[#1db954] font-medium">
    311                                                                         Now playing in mini-player below
    312                                                                 </p>
    313                                                         </div>
    314                                                 ) : (
    315                                                         <button
    316                                                                 onClick={() =>
    317                                                                         play({
    318                                                                                 id: song.id,
    319                                                                                 title: song.title,
    320                                                                                 artist: song.releasedBy,
    321                                                                                 cover: song.cover,
    322                                                                                 embedUrl: toEmbedUrl(song.link!),
    323                                                                         })
    324                                                                 }
    325                                                                 className="w-full bg-[#1a1a2e]/60 hover:bg-[#1a1a2e]/80 rounded-xl p-4 flex items-center gap-3 transition-colors cursor-pointer group"
    326                                                         >
    327                                                                 <div className="w-10 h-10 rounded-full bg-[#1db954] flex items-center justify-center text-black group-hover:scale-105 transition-transform">
    328                                                                         <svg
    329                                                                                 className="w-5 h-5"
    330                                                                                 fill="currentColor"
    331                                                                                 viewBox="0 0 24 24"
    332                                                                         >
    333                                                                                 <path d="M8 5v14l11-7z" />
    334                                                                         </svg>
    335                                                                 </div>
    336                                                                 <p className="text-white font-medium">Play this song</p>
    337                                                         </button>
    338                                                 )}
    339                                         </section>
    340                                 )}
    341 
    342334                                {/* Credits / Contributions */}
    343335                                {song.contributions.length > 0 && (
     
    402394                                                </h2>
    403395                                                <button
    404                                                         onClick={() => {
    405                                                                 /* TODO: add review modal */
    406                                                         }}
     396                                                        onClick={() => setShowReviewModal(true)}
    407397                                                        className="flex items-center gap-2 bg-[#1db954] hover:bg-[#1ed760] text-black text-sm font-semibold px-4 py-2 rounded-full transition-colors"
    408398                                                >
     
    452442                                                                                        </div>
    453443                                                                                </div>
     444                                                                                {user?.username === review.authorUsername && (
     445                                                                                        <button
     446                                                                                                onClick={deleteReview}
     447                                                                                                className="text-gray-500 hover:text-red-400 transition-colors p-2 rounded-lg hover:bg-red-400/10"
     448                                                                                                title="Delete review"
     449                                                                                        >
     450                                                                                                <svg
     451                                                                                                        className="w-5 h-5"
     452                                                                                                        fill="none"
     453                                                                                                        stroke="currentColor"
     454                                                                                                        viewBox="0 0 24 24"
     455                                                                                                >
     456                                                                                                        <path
     457                                                                                                                strokeLinecap="round"
     458                                                                                                                strokeLinejoin="round"
     459                                                                                                                strokeWidth={2}
     460                                                                                                                d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
     461                                                                                                        />
     462                                                                                                </svg>
     463                                                                                        </button>
     464                                                                                )}
    454465                                                                        </div>
    455466                                                                        <p className="text-gray-300 text-sm leading-relaxed mt-3 pl-12">
     
    462473                                </section>
    463474                        </div>
     475
     476                        {/* Review Modal */}
     477                        {showReviewModal && (
     478                                <div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/70 backdrop-blur-sm">
     479                                        <div className="bg-[#1a1a2e] rounded-2xl p-6 max-w-md w-full shadow-2xl">
     480                                                <div className="flex items-center justify-between mb-6">
     481                                                        <h3 className="text-2xl font-bold">Add Review</h3>
     482                                                        <button
     483                                                                onClick={() => {
     484                                                                        setShowReviewModal(false);
     485                                                                        setReviewRating(0);
     486                                                                        setReviewComment("");
     487                                                                        setHoverRating(0);
     488                                                                }}
     489                                                                className="text-gray-400 hover:text-white transition-colors"
     490                                                        >
     491                                                                <svg
     492                                                                        className="w-6 h-6"
     493                                                                        fill="none"
     494                                                                        stroke="currentColor"
     495                                                                        viewBox="0 0 24 24"
     496                                                                >
     497                                                                        <path
     498                                                                                strokeLinecap="round"
     499                                                                                strokeLinejoin="round"
     500                                                                                strokeWidth={2}
     501                                                                                d="M6 18L18 6M6 6l12 12"
     502                                                                        />
     503                                                                </svg>
     504                                                        </button>
     505                                                </div>
     506
     507                                                {/* Star Rating */}
     508                                                <div className="mb-6">
     509                                                        <label className="block text-sm font-medium mb-3">
     510                                                                Rating <span className="text-red-400">*</span>
     511                                                        </label>
     512                                                        <div className="flex gap-2">
     513                                                                {[1, 2, 3, 4, 5].map((star) => (
     514                                                                        <button
     515                                                                                key={star}
     516                                                                                onClick={() => setReviewRating(star)}
     517                                                                                onMouseEnter={() => setHoverRating(star)}
     518                                                                                onMouseLeave={() => setHoverRating(0)}
     519                                                                                className="transition-transform hover:scale-110"
     520                                                                        >
     521                                                                                <svg
     522                                                                                        className={`w-10 h-10 ${
     523                                                                                                star <= (hoverRating || reviewRating)
     524                                                                                                        ? "text-yellow-400"
     525                                                                                                        : "text-gray-600"
     526                                                                                        }`}
     527                                                                                        fill="currentColor"
     528                                                                                        viewBox="0 0 20 20"
     529                                                                                >
     530                                                                                        <path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
     531                                                                                </svg>
     532                                                                        </button>
     533                                                                ))}
     534                                                        </div>
     535                                                </div>
     536
     537                                                {/* Comment */}
     538                                                <div className="mb-6">
     539                                                        <label className="block text-sm font-medium mb-2">
     540                                                                Comment <span className="text-gray-500">(optional)</span>
     541                                                        </label>
     542                                                        <textarea
     543                                                                value={reviewComment}
     544                                                                onChange={(e) => setReviewComment(e.target.value)}
     545                                                                placeholder="Share your thoughts about this song..."
     546                                                                rows={4}
     547                                                                className="w-full bg-[#0f0f1e] border border-white/10 rounded-lg px-4 py-3 text-white placeholder-gray-500 focus:outline-none focus:border-[#1db954] transition-colors resize-none"
     548                                                        />
     549                                                </div>
     550
     551                                                {/* Actions */}
     552                                                <div className="flex gap-3 justify-end">
     553                                                        <button
     554                                                                onClick={() => {
     555                                                                        setShowReviewModal(false);
     556                                                                        setReviewRating(0);
     557                                                                        setReviewComment("");
     558                                                                        setHoverRating(0);
     559                                                                }}
     560                                                                className="px-5 py-2.5 rounded-full text-sm font-semibold bg-white/10 hover:bg-white/20 transition-colors"
     561                                                        >
     562                                                                Cancel
     563                                                        </button>
     564                                                        <button
     565                                                                onClick={handleSubmitReview}
     566                                                                disabled={reviewRating === 0}
     567                                                                className="px-5 py-2.5 rounded-full text-sm font-semibold bg-[#1db954] hover:bg-[#1ed760] text-black transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
     568                                                        >
     569                                                                Submit
     570                                                        </button>
     571                                                </div>
     572                                        </div>
     573                                </div>
     574                        )}
    464575                </div>
    465576        );
Note: See TracChangeset for help on using the changeset viewer.