Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
78344ef
initialize vite app with typescript - add tailwind config
magkavetsos Sep 17, 2025
0787be8
add react router
magkavetsos Sep 17, 2025
fb8c2f4
initialize basic screen views - add lucide-react for easy icon usage …
magkavetsos Sep 18, 2025
dfb50c7
add react query to handle all the fetching, mutation and error handli…
magkavetsos Sep 18, 2025
58c0a41
add basic boilerplate for view image details
magkavetsos Sep 18, 2025
3300720
add modal for images
magkavetsos Sep 19, 2025
9e05365
implement breed page - add api call & hook
magkavetsos Sep 20, 2025
e59ae2c
add images modal about breed - common hook for overflow
magkavetsos Sep 20, 2025
e2fb690
add params for better id handling
magkavetsos Sep 20, 2025
12d3058
minor fixes
magkavetsos Sep 20, 2025
8e5c930
add a no favorites yet state for app - consistency in buttons
magkavetsos Sep 20, 2025
ac43ea5
add dev key
magkavetsos Sep 20, 2025
06dce6a
split breeds layout into components - add searchbar functionality wit…
magkavetsos Sep 20, 2025
d087ef3
add favorites implementation - minor fixes
magkavetsos Sep 22, 2025
1f7dc77
add skeletons at breeds and favs pages - split components at fav page
magkavetsos Sep 22, 2025
971d5f2
add shared types in types/ path - minor adjustments
magkavetsos Sep 22, 2025
e6b11d4
folder structure improvements
magkavetsos Sep 22, 2025
8d8961d
improvement for mutations at fav button using optimistic state - mino…
magkavetsos Sep 22, 2025
211d8fb
ts fixes - initiaze react testing library boilerplate for vite
magkavetsos Sep 22, 2025
34cbdbe
add skeleton at homepage also
magkavetsos Sep 22, 2025
716c2e2
some accessibility improvements - remove autofetch add stale time at …
magkavetsos Sep 22, 2025
63353bb
add some basic tests
magkavetsos Sep 22, 2025
6ea63fb
change icon
magkavetsos Sep 22, 2025
480f171
improvement at tests - add test-utils for reuse providers inside test…
magkavetsos Sep 22, 2025
77e6388
update README file
magkavetsos Sep 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
VITE_API_BASE_URL=https://api.thecatapi.com/v1
VITE_API_KEY=live_XPr21647UCZ6sIBxYYwM92b0bcgeL087EyYfnknZHvfzNywJ1y8t7uCf6T4S1Q4U
24 changes: 24 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
101 changes: 88 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,96 @@
# GlobalWebIndex Engineering Challenge
# Platform React Challenge | CatLover App

## Exercise: CatLover
Lightweight React + TypeScript app (Vite) for browsing random cat images, exploring cat breeds, and managing favorite images using deep-linkable modals, and React Query for data fetching/caching. This repo was created as an assessment/demo project and contains small, focused components and hooks.

Create a React application for cat lovers which is going to build upon thecatapi.com and will have 3 views.
The **first** view displays a list of 10 random cat images and a button to load more. Clicking on any of those images opens a modal view with the image and the information about the cat’s breed if available. This would be a link to the second view below - the breed detail. The modal should also contain a form to mark the image as your favourite (a part of the third view as well). Make sure you can copy-paste the URL of the modal and send it to your friends - they should see the same image as you can see.
## Quick start

The **second** view displays a list of cat breeds. Each breed opens a modal again with a list of cat images of that breed. Each of those images must be a link to the image detail from the previous point.
Prerequisites
- Node 16+ and npm (or Yarn/pnpm)

The **third** view allows you do the following things:
Install

- Display your favourite cats
- Remove an image from your favourites (use any UX option you like)
```powershell
npm install
```

You can find the API documentation here: https://developers.thecatapi.com/
We give you a lot of freedom in technologies and ways of doing things. We only insist on you using React.js. Get creative as much as you want, we WILL appreciate it. You will not be evaluated based on how well you follow these instructions, but based on how sensible your solution will be. In case you are not able to implement something you would normally implement for time reasons, make it clear with a comment.
Run (dev)

## Submission
```powershell
npm run dev
```

Once you have built your app, share your code in the mean suits you best
Good luck, potential colleague!
Build / preview

```powershell
npm run build
npm run preview
```

Run tests (Vitest)

```powershell
npm run test
```

Lint

```powershell
npm run lint
```

Open the app at http://localhost:5173

## Environment

Create a `.env` file at project root (or use the same `.env`) and set:

```text
VITE_API_BASE_URL=https://api.thecatapi.com/v1
VITE_API_KEY=your_thecatapi_key_here
```

Notes:
- The API key is required for some endpoints or query parameters (for example `limit` when fetching images).
- Do not commit secrets - For demo purposes, a development API key is included in this repository. In production, API keys must always be stored securely and never committed.

## Features

- Browse random cat images
- Refresh or load more cat images
- Browse and search cat breeds (debounced client-side search)
- Breed cards with metrics and expandable description
- Deep-linkable modals for images and breed details (query params)
- Save / Remove Favorites (React Query mutations - optimistic updates for better performance)
- Skeleton loading states and lazy-loaded images

## Project structure (high level)

- src/
- routes/
- Images/ — random images page, modal, hooks, api
- Breeds/ — breeds page, card, modal, hooks, api
- Favorites/ — favorites page, components, hooks, api
- types/ — shared TypeScript models
- hooks/ — small reusable hooks (debounce, lock body scroll)
- components/ — layout and shared UI
- test-utils.tsx — test helpers

## Testing

This repo uses Vitest + Testing Library for small focused tests. Tests live close to the components they cover (see `src/routes/Favorites/tests`).

## Best practices demonstrated

- Feature-scoped folders and small components
- React Query for caching and mutations
- Centralized TypeScript types (`src/types`) for consistency
- Debounced user input to reduce renders
- Skeletons and lazy loading for better performance
- Accessibility-conscious patterns

## Suggested next steps

- Add optimistic updates for favorites page (immediate UI feedback with rollback)
- Add more tests (hook tests, integration tests for modals)
- Improve accessibility
- Add caching and image CDN optimizations (srcSet, WebP)
23 changes: 23 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
import { globalIgnores } from 'eslint/config'

export default tseslint.config([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
reactHooks.configs['recommended-latest'],
reactRefresh.configs.vite,
],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
},
])
14 changes: 14 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/cat.svg" />
<link rel="stylesheet" href="/src/index.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>CatLover Αpp</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Loading