Skip to content

Commit

Permalink
Refactor: FetchMovieRecommendationsButton ui
Browse files Browse the repository at this point in the history
  • Loading branch information
edwardsavin committed May 27, 2023
1 parent 01ee1e4 commit 23f2557
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 19 deletions.
68 changes: 64 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@radix-ui/react-dropdown-menu": "^2.0.4",
"@radix-ui/react-navigation-menu": "^1.1.2",
"@radix-ui/react-separator": "^1.0.2",
"@radix-ui/react-slot": "^1.0.2",
"@tanstack/react-query": "^4.28.0",
"@trpc/client": "^10.18.0",
"@trpc/next": "^10.18.0",
Expand Down
17 changes: 8 additions & 9 deletions src/components/movie-recommendation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import { api } from "~/utils/api";
import type { MovieInfo } from "~/pages/api/tmdb-fetch-movie-info";
import type { Movie } from "./movie-recommendations-button";

type MovieRecommendationsProps = {
movies: Movie[];
recommendationId: string;
};

// Display the movie recommendations modal with a poster, title, release year, overview and links to TMDB and Letterboxd
export const MovieModal = ({
movieInfo,
Expand Down Expand Up @@ -151,11 +156,6 @@ export const MovieCard = (movieInfo: MovieInfo) => {
);
};

type MovieRecommendationsProps = {
movies: Movie[];
recommendationId: string;
};

// Render all aggregated movie recommendations
export const MovieRecommendations = ({
movies,
Expand Down Expand Up @@ -231,10 +231,9 @@ export const MovieRecommendations = ({
return (
<div className="mt-8 flex flex-col">
<div className="m:grid-cols-2 mt-4 grid grid-cols-1 gap-5 md:grid-cols-3 lg:grid-cols-5">
{moviesInfo &&
moviesInfo.map((movieInfo: MovieInfo) => {
return <MovieCard key={movieInfo.id} {...movieInfo} />;
})}
{moviesInfo?.map((movieInfo: MovieInfo) => (
<MovieCard key={movieInfo.id} {...movieInfo} />
))}
</div>
</div>
);
Expand Down
37 changes: 31 additions & 6 deletions src/components/movie-recommendations-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { toast } from "react-hot-toast";
import getMovieRecommendations from "~/utils/get-movie-recommendations";
import { useEffect, useState } from "react";
import { api } from "~/utils/api";
import { Loader2 } from "lucide-react";
import { Button } from "./ui/button";
import type { TrackData } from "~/utils/hooks/use-recent-tracks";

export type MovieData = {
Expand Down Expand Up @@ -38,6 +40,8 @@ const FetchMovieRecommendationsButton = ({
const { mutate: mutateRecommendation } =
api.recommendation.create.useMutation();

const [isFetching, setIsFetching] = useState<boolean>(false);

useEffect(() => {
if (recommendedMovies.length > 0 && recommendationId) {
handleMovieData({
Expand All @@ -50,6 +54,7 @@ const FetchMovieRecommendationsButton = ({

const handleClick = async () => {
try {
setIsFetching(true);
let movies = await getMovieRecommendations(songs, temperature);

// Increase temperature on each request to get more diverse results
Expand All @@ -74,6 +79,7 @@ const FetchMovieRecommendationsButton = ({
// Set unique key to force re-render of MovieRecommendations component
setUniqueKey(Date.now());
setRecommendedMovies(mappedMovies as Movie[]);
setIsFetching(false);

mutateRecommendation(
{
Expand All @@ -92,12 +98,31 @@ const FetchMovieRecommendationsButton = ({
};

return (
<button
className="rounded-md bg-white px-4 py-2 text-black"
onClick={handleClick as () => void}
>
Get movie recommendations
</button>
<>
{isFetching && (
<Button
className="bg-gradient-to-r from-blue-900 to-purple-900 px-10 py-7 font-clash_display text-lg text-gray-50"
disabled
>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Loading...
</Button>
)}

{!isFetching && (
<Button
className="
bg-gradient-to-r from-blue-900 to-purple-900 px-14 py-7
font-clash_display text-lg font-semibold text-gray-50 shadow-lg shadow-blue-700/30
transition hover:from-blue-800 hover:to-purple-800 hover:shadow-blue-700/40
focus:outline-none
"
onClick={handleClick as () => void}
>
Moodify
</Button>
)}
</>
);
};

Expand Down
55 changes: 55 additions & 0 deletions src/components/ui/button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from "~/lib/utils"

const buttonVariants = cva(
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background",
{
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 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: "underline-offset-4 hover:underline text-primary",
},
size: {
default: "h-10 py-2 px-4",
sm: "h-9 px-3 rounded-md",
lg: "h-11 px-8 rounded-md",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)

export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = "Button"

export { Button, buttonVariants }

0 comments on commit 23f2557

Please sign in to comment.