Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
232 changes: 145 additions & 87 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,87 +1,145 @@
# Frontend Developer Intern Assignment

## Mandatory Tasks
- Follow SolveEase on [Github](https://github.com/solve-ease) and [Linkedin](https://www.linkedin.com/company/solve-ease)
- Star this repo

## Objective
This assignment is designed to assess your practical skills in **React, Next.js, TypeScript, Tailwind CSS, and frontend optimizations**. You will work on an existing **Next.js application** that contains layout/design issues and some configuration bugs. Your task is to identify and resolve these issues, and implement the listed features to enhance the overall user experience.

---

## Tasks

### 1. Fix Cards Layout & Responsiveness
- Correct the existing card grid layout.
- Improve the overall card design (UI/UX sensibility expected).
- Ensure the page is fully responsive across devices (desktop, tablet, mobile).

### 2. Add Navbar (Sticky)
- Implement a navigation bar that remains fixed at the top while scrolling.
- Design should be clean and responsive.

### 3. Optimize Page Load & Performance
- Implement optimizations such as:
- **Lazy loading** for images and non-critical components.
- **Memoization** to avoid unnecessary re-renders.
- **Skeleton loading screens** for better UX during data fetch.

### 4. Implement Pagination
- Add pagination for the workers listing page.
- Each page should load a suitable number of items (e.g., 9–12 cards per page).

### 5. Service Filters
- Implement filters for workers based on **price/day** and **type of service**.
- Filters should work seamlessly with pagination.

### 6. Bug Fixes
- Identify and fix any existing issues in `page.tsx` or configuration files.
- Resolve console warnings or errors.
- Ensure clean and maintainable code following best practices.

### 7. API Integration
- Currently, the workers’ data is being imported directly from `workers.json`.
- Your task is to **serve this data via /api/wprkers API route**.
- Update the frontend page to fetch this data using `fetch` (or any modern method such as `useEffect`, `useSWR`, or React Query).
- Donot delete the existing data loading logic, comment it out.
- Implement:
- **Loading state** (use skeleton screens).
- **Error handling** (show a friendly error message if API fails).
- **Basic caching or memoization** to prevent redundant calls.

---

## Expectations
- Use **TypeScript** and **Tailwind CSS** consistently.
- Follow **component-driven development** principles.
- Write **clean, readable, and reusable code**.
- Optimize for **performance and accessibility**.
- Maintain **Git commit history** (no single "final commit").

---

## Deliverables
1. Fork the repo and work from a branch named: assignment/<your-full-name> (for example: assignment/adarsh-maurya).
2. Implement improvements and features that demonstrate your mastery of the job requirements (UI polish, responsiveness, Tailwind usage, tests, accessibility, performance).
3. Push your branch to GitHub, add a clear README, and (strongly recommended) deploy the app (Vercel/Netlify/GH Pages)
3. Fill in the Google Form with your details for submission.

---

## Evaluation Criteria
- Code quality, readability, and structure.
- UI/UX improvements and responsiveness.
- Correctness of functionality (filters, pagination, sticky navbar, optimisations).
- Debugging and problem-solving approach.
- Git usage and commit practices.
- Handling of API calls, loading states, and error cases.

---

## Notes
- You are free to use libraries like **SWR** or **React Query**, but keep the implementation clean.
- Focus on **real-world production quality code**, not just quick fixes.
- Add comment for any **bug fix or optimization.**
- Document any **extra improvements** you make in your submission.

Good luck 🚀
# Implementation Summary - WorkerHub Application

## ✅ Completed Features

### 1. **Sticky Navbar**
- **File**: `src/components/Navbar.tsx`
- **Features**:
- Fixed position navbar that stays at top during scroll
- Responsive design (mobile hamburger menu)
- Smooth background blur effect on scroll
- Clean, professional styling
- Mobile-first responsive navigation

### 2. **API Integration**
- **File**: `src/app/api/workers/route.ts`
- **Features**:
- RESTful API endpoint at `/api/workers`
- Support for pagination (`page`, `limit` parameters)
- Advanced filtering (service type, price range)
- Sorting options (name, price low-to-high, high-to-low)
- Comprehensive error handling
- Returns metadata (pagination info, filter options)

### 3. **Performance Optimizations**
- **Components**: Multiple files
- **Features**:
- **Memoization**: All components use `React.memo()`
- **Custom Hook**: `useWorkers` with built-in caching
- **Lazy Loading**: Images with Next.js optimization
- **Skeleton Loading**: Professional loading screens
- **Image Optimization**: Priority loading for above-the-fold content
- **Error Boundaries**: Graceful error handling
- **In-Memory Caching**: 5-minute cache for API responses

### 4. **Pagination System**
- **Component**: `src/components/Pagination.tsx`
- **Features**:
- 12 cards per page (configurable)
- Smart page number display (shows ... for large page counts)
- Mobile-friendly design
- Results summary display
- Smooth scroll to top on page change
- Works seamlessly with filters

### 5. **Advanced Filtering**
- **Component**: `src/components/WorkerFilters.tsx`
- **Features**:
- **Service Type Filter**: Dropdown with all available services
- **Price Range Filters**: Min/max price inputs with validation
- **Sorting Options**: Name, price low-to-high, price high-to-low
- **Clear Filters**: One-click filter reset
- **Real-time Updates**: Filters update results immediately
- **URL Integration**: Filters work with pagination

### 6. **Enhanced Card Design**
- **Component**: `src/components/WorkerCard.tsx`
- **Features**:
- Modern card design with hover animations
- Image error handling and fallbacks
- Loading states for images
- Responsive button layout
- Price display with GST included
- Service badges with color coding
- Optimized image loading with `priority` prop

### 7. **State Management & Error Handling**
- **Hook**: `src/hooks/useWorkers.ts`
- **Features**:
- Custom hook for data fetching
- Built-in caching system
- Error state management
- Loading state handling
- Automatic retry functionality
- Cache invalidation

### 8. **Code Quality & Best Practices**
- **Multiple Files**: Error boundaries, type safety, performance utils
- **Features**:
- **TypeScript**: Full type safety throughout
- **Error Boundaries**: Catch and handle React errors
- **ESLint**: Code quality enforcement
- **Accessibility**: Focus management, ARIA labels
- **Performance Utilities**: Debounce, throttle, intersection observer
- **Clean Code**: Modular components, clear naming

## 🏗️ Architecture

### **File Structure**
```
src/
├── app/
│ ├── api/workers/route.ts # API endpoint
│ ├── layout.tsx # Root layout with navbar
│ └── page.tsx # Main workers page
├── components/
│ ├── ErrorBoundary.tsx # Error handling
│ ├── Navbar.tsx # Sticky navigation
│ ├── Pagination.tsx # Pagination controls
│ ├── Skeletons.tsx # Loading skeletons
│ ├── WorkerCard.tsx # Individual worker card
│ └── WorkerFilters.tsx # Filter controls
├── hooks/
│ └── useWorkers.ts # Data fetching hook
├── types/
│ └── workers.ts # TypeScript definitions
└── utils/
└── performance.ts # Performance utilities
```

### **Key Features**
1. **Responsive Design**: Mobile-first approach, works on all devices
2. **Performance**: Optimized loading, caching, and rendering
3. **User Experience**: Smooth animations, loading states, error handling
4. **Code Quality**: TypeScript, ESLint, modular architecture
5. **Accessibility**: Focus management, keyboard navigation
6. **SEO**: Optimized metadata, image loading

## 🚀 Performance Metrics
- **First Load**: Skeleton screens for immediate feedback
- **Image Loading**: Progressive loading with fallbacks
- **Caching**: 5-minute cache reduces API calls
- **Memoization**: Prevents unnecessary re-renders
- **Lazy Loading**: Images load as needed

## 🎯 User Experience
- **Intuitive Filtering**: Easy-to-use filter controls
- **Responsive Design**: Works perfectly on mobile/desktop
- **Fast Interactions**: Immediate feedback on all actions
- **Error Recovery**: Graceful error handling with retry options
- **Accessible**: Keyboard navigation and screen reader support

## 📱 Responsive Breakpoints
- **Mobile**: 1 column (< 640px)
- **Small**: 2 columns (640px - 1024px)
- **Large**: 3 columns (1024px - 1280px)
- **XLarge**: 4 columns (1280px - 1536px)
- **2XLarge**: 5 columns (> 1536px)

## 🔧 Configuration
- **Cards per page**: 12 (configurable in API)
- **Cache duration**: 5 minutes
- **Image priorities**: First 8 cards prioritized
- **API endpoint**: `/api/workers`

All features have been implemented following modern React/Next.js best practices with full TypeScript support, comprehensive error handling, and optimal performance characteristics.
19 changes: 16 additions & 3 deletions next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,22 @@ import type { NextConfig } from "next";

const nextConfig: NextConfig = {
/* config options here */
images:{
domains: ['images.unsplash.com','randomuser.me'],
}
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'images.unsplash.com',
port: '',
pathname: '/**',
},
{
protocol: 'https',
hostname: 'randomuser.me',
port: '',
pathname: '/api/portraits/**',
},
],
},
};

export default nextConfig;
93 changes: 86 additions & 7 deletions src/app/api/workers/route.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,97 @@
import { NextResponse } from 'next/server'
import { NextRequest, NextResponse } from 'next/server'
import workersData from '../../../../workers.json'
import { WorkerType } from '@/types/workers'

export async function GET() {
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
const page = parseInt(searchParams.get('page') || '1')
const limit = parseInt(searchParams.get('limit') || '12')
const service = searchParams.get('service')
const minPrice = searchParams.get('minPrice')
const maxPrice = searchParams.get('maxPrice')
const sortBy = searchParams.get('sortBy') || 'name'

// Filter workers
let filteredWorkers: WorkerType[] = workersData
.filter((worker: WorkerType) => worker.pricePerDay > 0)
.filter((worker: WorkerType) => worker.id !== null)

// Apply service filter
if (service && service !== 'all') {
filteredWorkers = filteredWorkers.filter(
(worker: WorkerType) => worker.service.toLowerCase().includes(service.toLowerCase())
)
}

// Apply price range filter
if (minPrice) {
filteredWorkers = filteredWorkers.filter(
(worker: WorkerType) => worker.pricePerDay >= parseInt(minPrice)
)
}

if (maxPrice) {
filteredWorkers = filteredWorkers.filter(
(worker: WorkerType) => worker.pricePerDay <= parseInt(maxPrice)
)
}

// Sort workers
filteredWorkers.sort((a: WorkerType, b: WorkerType) => {
switch (sortBy) {
case 'price-low':
return a.pricePerDay - b.pricePerDay
case 'price-high':
return b.pricePerDay - a.pricePerDay
case 'name':
default:
return a.name.localeCompare(b.name)
}
})

// Calculate pagination
const totalWorkers = filteredWorkers.length
const totalPages = Math.ceil(totalWorkers / limit)
const startIndex = (page - 1) * limit
const endIndex = startIndex + limit
const paginatedWorkers = filteredWorkers.slice(startIndex, endIndex)

// Get unique services for filter options
const services = [...new Set(workersData.map((worker: WorkerType) => worker.service))]
const priceRange = {
min: Math.min(...workersData.map((worker: WorkerType) => worker.pricePerDay)),
max: Math.max(...workersData.map((worker: WorkerType) => worker.pricePerDay))
}

return NextResponse.json({
success: true,
data: workersData
data: {
workers: paginatedWorkers,
pagination: {
currentPage: page,
totalPages,
totalWorkers,
hasNext: page < totalPages,
hasPrevious: page > 1,
limit
},
filters: {
services,
priceRange
}
}
})
} catch (error) {
console.error('API Error:', error)
return NextResponse.json({
success: false,
error: 'Failed to fetch workers data'
}, { status: 500 })
return NextResponse.json(
{
success: false,
error: 'Failed to fetch workers data',
data: null
},
{ status: 500 }
)
}
}

Loading