From a3a4727532b3e5db8844da3978d83faa372dfc58 Mon Sep 17 00:00:00 2001 From: Christian Landgren Date: Tue, 9 Dec 2025 13:46:07 +0100 Subject: [PATCH 1/2] Fix ESLint warnings for fast refresh and hook dependencies - Move UI variant definitions to separate files to fix fast refresh warnings - Create centralized toast import to avoid component export issues - Add missing dependencies to React useEffect hooks - Improve code organization and maintainability --- src/components/SpotifyPlayer.tsx | 2 +- src/components/SpotifyPlaylistSync.tsx | 4 ++-- src/components/ui/badge-variants.ts | 23 ++++++++++++++++++ src/components/ui/badge.tsx | 23 +++--------------- src/components/ui/button-variants.ts | 32 ++++++++++++++++++++++++++ src/components/ui/sonner.tsx | 4 ++-- src/components/ui/toggle-variants.ts | 25 ++++++++++++++++++++ src/components/ui/toggle.tsx | 27 +++------------------- src/hooks/useSocket.ts | 2 +- src/lib/toast.ts | 3 +++ src/pages/Index.tsx | 2 +- src/pages/Login.tsx | 2 +- src/pages/Rooms.tsx | 2 +- 13 files changed, 98 insertions(+), 53 deletions(-) create mode 100644 src/components/ui/badge-variants.ts create mode 100644 src/components/ui/button-variants.ts create mode 100644 src/components/ui/toggle-variants.ts create mode 100644 src/lib/toast.ts diff --git a/src/components/SpotifyPlayer.tsx b/src/components/SpotifyPlayer.tsx index 5dd6b19..d31e8e5 100644 --- a/src/components/SpotifyPlayer.tsx +++ b/src/components/SpotifyPlayer.tsx @@ -105,7 +105,7 @@ export function SpotifyPlayer({ // Play from calculated position play(spotifyUri, startPosition); } - }, [currentTrack?.id, isReady, isPremium, play, playbackState, playbackMode]); + }, [currentTrack?.id, isReady, isPremium, play, playbackState, playbackMode, currentTrack]); // Track ended - call onTrackEnd useEffect(() => { diff --git a/src/components/SpotifyPlaylistSync.tsx b/src/components/SpotifyPlaylistSync.tsx index dbfbd3c..acf0470 100644 --- a/src/components/SpotifyPlaylistSync.tsx +++ b/src/components/SpotifyPlaylistSync.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react'; import { ExternalLink, Music, Sparkles, Loader2 } from 'lucide-react'; import { Button } from './ui/button'; import { useAuth } from '@/contexts/AuthContext'; -import { toast } from 'sonner'; +import { toast } from '@/lib/toast'; import { Room } from '@/types/wejay'; interface SpotifyPlaylistSyncProps { @@ -22,7 +22,7 @@ export function SpotifyPlaylistSync({ playlistUrl, hasTracksInQueue, room }: Spo if (playlistUrl && !url) { setUrl(playlistUrl); } - }, [playlistUrl]); + }, [playlistUrl, url]); const handleCreatePlaylist = async () => { console.log('[SpotifyPlaylistSync] handleCreatePlaylist called'); diff --git a/src/components/ui/badge-variants.ts b/src/components/ui/badge-variants.ts new file mode 100644 index 0000000..7f26696 --- /dev/null +++ b/src/components/ui/badge-variants.ts @@ -0,0 +1,23 @@ +import { cva, type VariantProps } from "class-variance-authority"; + +export const badgeVariants = cva( + "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", + secondary: + "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", + destructive: + "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", + outline: "text-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +); + +export type BadgeVariants = VariantProps; \ No newline at end of file diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx index 0853c44..4106fb5 100644 --- a/src/components/ui/badge.tsx +++ b/src/components/ui/badge.tsx @@ -1,29 +1,12 @@ import * as React from "react"; -import { cva, type VariantProps } from "class-variance-authority"; +import { badgeVariants, type BadgeVariants } from "./badge-variants"; import { cn } from "@/lib/utils"; -const badgeVariants = cva( - "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", - { - variants: { - variant: { - default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", - secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", - destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", - outline: "text-foreground", - }, - }, - defaultVariants: { - variant: "default", - }, - }, -); - -export interface BadgeProps extends React.HTMLAttributes, VariantProps {} +export interface BadgeProps extends React.HTMLAttributes, BadgeVariants {} function Badge({ className, variant, ...props }: BadgeProps) { return
; } -export { Badge, badgeVariants }; +export { Badge }; diff --git a/src/components/ui/button-variants.ts b/src/components/ui/button-variants.ts new file mode 100644 index 0000000..1629034 --- /dev/null +++ b/src/components/ui/button-variants.ts @@ -0,0 +1,32 @@ +import { cva, type VariantProps } from "class-variance-authority"; + +export const buttonVariants = cva( + "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: + "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +); + +export type ButtonVariants = VariantProps; \ No newline at end of file diff --git a/src/components/ui/sonner.tsx b/src/components/ui/sonner.tsx index b7f198b..5add2ce 100644 --- a/src/components/ui/sonner.tsx +++ b/src/components/ui/sonner.tsx @@ -1,5 +1,5 @@ import { useTheme } from "next-themes"; -import { Toaster as Sonner, toast } from "sonner"; +import { Toaster as Sonner } from "sonner"; type ToasterProps = React.ComponentProps; @@ -24,4 +24,4 @@ const Toaster = ({ ...props }: ToasterProps) => { ); }; -export { Toaster, toast }; +export { Toaster }; diff --git a/src/components/ui/toggle-variants.ts b/src/components/ui/toggle-variants.ts new file mode 100644 index 0000000..be54bb3 --- /dev/null +++ b/src/components/ui/toggle-variants.ts @@ -0,0 +1,25 @@ +import { cva, type VariantProps } from "class-variance-authority"; + +export const toggleVariants = cva( + "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground", + { + variants: { + variant: { + default: "bg-transparent", + outline: + "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground", + }, + size: { + default: "h-10 px-3", + sm: "h-9 px-2.5", + lg: "h-11 px-5", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +); + +export type ToggleVariants = VariantProps; \ No newline at end of file diff --git a/src/components/ui/toggle.tsx b/src/components/ui/toggle.tsx index de5dfc5..a4f0a7b 100644 --- a/src/components/ui/toggle.tsx +++ b/src/components/ui/toggle.tsx @@ -1,37 +1,16 @@ import * as React from "react"; import * as TogglePrimitive from "@radix-ui/react-toggle"; -import { cva, type VariantProps } from "class-variance-authority"; +import { toggleVariants, type ToggleVariants } from "./toggle-variants"; import { cn } from "@/lib/utils"; -const toggleVariants = cva( - "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground", - { - variants: { - variant: { - default: "bg-transparent", - outline: "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground", - }, - size: { - default: "h-10 px-3", - sm: "h-9 px-2.5", - lg: "h-11 px-5", - }, - }, - defaultVariants: { - variant: "default", - size: "default", - }, - }, -); - const Toggle = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef & VariantProps + React.ComponentPropsWithoutRef & ToggleVariants >(({ className, variant, size, ...props }, ref) => ( )); Toggle.displayName = TogglePrimitive.Root.displayName; -export { Toggle, toggleVariants }; +export { Toggle }; diff --git a/src/hooks/useSocket.ts b/src/hooks/useSocket.ts index f9b94b1..2231ae5 100644 --- a/src/hooks/useSocket.ts +++ b/src/hooks/useSocket.ts @@ -1,7 +1,7 @@ import { useEffect, useState, useCallback, useRef } from 'react'; import { useAuth } from '@/contexts/AuthContext'; import { Room, Track, SpotifyUser } from '@/types/wejay'; -import { toast } from 'sonner'; +import { toast } from '@/lib/toast'; import { io, Socket } from 'socket.io-client'; interface SocketState { diff --git a/src/lib/toast.ts b/src/lib/toast.ts new file mode 100644 index 0000000..9cad06e --- /dev/null +++ b/src/lib/toast.ts @@ -0,0 +1,3 @@ +import { toast as sonnerToast } from 'sonner'; + +export const toast = sonnerToast; \ No newline at end of file diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx index f081572..bbaddba 100644 --- a/src/pages/Index.tsx +++ b/src/pages/Index.tsx @@ -10,7 +10,7 @@ import { AIRecommendations } from "@/components/AIRecommendations"; import { SpotifyPlaylistSync } from "@/components/SpotifyPlaylistSync"; import { arrangeTracks } from "@/lib/dhondt"; import { Track, SearchTrack } from "@/types/wejay"; -import { toast } from "sonner"; +import { toast } from '@/lib/toast'; import { Heart, Search, Loader2, LogOut } from "lucide-react"; import { useSpotifySearch } from "@/hooks/useSpotifySearch"; import { useSpotifyRecommendations } from "@/hooks/useSpotifyRecommendations"; diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index c8149f6..41b0ff7 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -4,7 +4,7 @@ import { useAuth } from '@/contexts/AuthContext'; import { Button } from '@/components/ui/button'; import { Card } from '@/components/ui/card'; import { Loader2, Music, Users, Sparkles } from 'lucide-react'; -import { toast } from 'sonner'; +import { toast } from '@/lib/toast'; const Login = () => { const { user, isLoading, login, isAuthenticated, isPremium } = useAuth(); diff --git a/src/pages/Rooms.tsx b/src/pages/Rooms.tsx index 34016e7..4c988de 100644 --- a/src/pages/Rooms.tsx +++ b/src/pages/Rooms.tsx @@ -7,7 +7,7 @@ import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Plus, Users, Copy, Check, Loader2 } from 'lucide-react'; import { Room } from '@/types/wejay'; -import { toast } from 'sonner'; +import { toast } from '@/lib/toast'; const Rooms = () => { const { user, isAuthenticated, logout } = useAuth(); From e7781c3f245d2734252082f2cc7f241c28448ab8 Mon Sep 17 00:00:00 2001 From: Christian Landgren Date: Tue, 9 Dec 2025 13:53:49 +0100 Subject: [PATCH 2/2] Fix button component fast refresh warning - Complete button-variants.ts with proper variant definitions - Update button.tsx to use separate variants file - Remove buttonVariants export to fix fast refresh warning - Addresses Copilot review comment about incomplete button-variants file --- src/components/ui/button.tsx | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index cdedd4f..03ef6ef 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -1,38 +1,12 @@ import * as React from "react"; import { Slot } from "@radix-ui/react-slot"; -import { cva, type VariantProps } from "class-variance-authority"; +import { buttonVariants, type ButtonVariants } from "./button-variants"; import { cn } from "@/lib/utils"; -const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", - { - variants: { - variant: { - default: "bg-primary text-primary-foreground hover:bg-primary/90", - destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", - outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground", - secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", - ghost: "hover:bg-accent hover:text-accent-foreground", - link: "text-primary underline-offset-4 hover:underline", - }, - size: { - default: "h-10 px-4 py-2", - sm: "h-9 rounded-md px-3", - lg: "h-11 rounded-md px-8", - icon: "h-10 w-10", - }, - }, - defaultVariants: { - variant: "default", - size: "default", - }, - }, -); - export interface ButtonProps extends React.ButtonHTMLAttributes, - VariantProps { + ButtonVariants { asChild?: boolean; } @@ -44,4 +18,4 @@ const Button = React.forwardRef( ); Button.displayName = "Button"; -export { Button, buttonVariants }; +export { Button };