-
Notifications
You must be signed in to change notification settings - Fork 565
Frontend Assignment - Emir B. #759
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
…; add base dark layout (Header/Footer) and routes
…onents; wire global ErrorBoundary; install lucide-react icons
…e”; show title/year/rating
…tle gradient effect
…gradient), ratings and key metadata
…empty tabs gracefully
…arch functionality and loading states
… hero dimensions; add custom hook for document title management
…lToTop component for improved navigation; update PillTabs styling; refine MovieHero gradients and loading behavior; adjust scrollbar styles for better aesthetics
…HomeRails for improved structure; add SearchResultsSection for handling search results; implement useTmdbSearch hook for data fetching and error handling
…rgins and paddings for improved responsiveness and aesthetics
…improve layout; implement custom hook for document title management; update storyline heading style in OverviewSection
…e project structure.
…dd Vercel configuration for rewrites
…jects; clean up MovieHeroSkeleton and update test assertions for clarity
…uctions, and improve testing section
…d CastSection components
… improve semantics
|
||
url.search = search.toString(); | ||
|
||
const res = await fetch(url.toString(), init); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nowadays I would want to use react-query and build the tmdb lib around useQuery primitives with hooks like useMovies
and useMovieDetails
or something like that, you get caching OOTB that way.
setLoading(true); | ||
setError(null); | ||
|
||
fetchJson<SearchResponse>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the loading around here (loading / error) can be subsumed into react-query (now called tanstack query), as the useQuery
hook implements all of this for you.
You would like build your query key for useQuery with the page and page size in mind.
); | ||
}) | ||
.finally(() => { | ||
if (!controller.signal.aborted) setLoading(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's very nice seeing someone be aware of and use abort controllers!
<div className="absolute inset-0"> | ||
{heroBg ? ( | ||
<div | ||
className="absolute inset-0 bg-cover bg-center blur-sm scale-105" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gotta love tailwind
: "bg-[#00ad99] hover:bg-[#009b89]" | ||
} | ||
text-white disabled:opacity-60 | ||
`} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think i'd recommend looking at clsx and the full tailwind utility suite. Shadcn also uses these utilities, it makes conditional classes behave without messy nested logic like this. So you could refacotr this bit into:
<button
className={cn(
loading
? "bg-[#00ad99]/40 cursor-not-allowed"
: "bg-[#00ad99] hover:bg-[#009b89]",
"inline-flex items-center justify-center gap-2 rounded-lg px-5 py-2 text-lg font-medium transition-colors duration-200 text-white disabled:opacity-60"
)}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Set up for a cn
function is documented here: https://ui.shadcn.com/docs/installation/manual
|
||
type SearchResponse = TmdbPage<TmdbMovie>; | ||
|
||
export function useTmdbSearch(query: string, page: number) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great intuition to pull this hook out - having it be useQuery inside will erase a lot of the complexity too.
🎬 CinEmir — TMDB Movie Explorer
A sleek, fast movie browser built with React + TypeScript + Vite, styled with Tailwind, and powered by TMDB. It features a dynamic, cinematic UI, smooth navigation, rich details, and a polished mobile experience.
🌐 Live Demo
👉 cinemir.vercel.app
✨ Highlights
🧱 Tech Stack
📦 Getting Started
🔐 Environment Variables
Create
.env
from the example and add your TMDB key:This product uses the TMDB API but is not endorsed or certified by TMDB.
🧪 Testing
Unit: Vitest + Testing Library
Run:
Folder convention:
E2E: Playwright
webServer
Run:
🌐 Deployment (Vercel)
This is a client-side SPA; add a rewrite so all routes serve
index.html
:vercel.json
Then:
assignment
).VITE_TMDB_API_KEY
in Project → Settings → Environment Variables.vite build
• Output:dist
If you saw the Vercel default 404 page, you were missing the rewrite above.
🔧 Developer Notes
?tab=overview|videos|photos
(resets to overview when navigating to a new movie)👏 Credits
📄 License
MIT — do what you love. 💚