diff --git a/package-lock.json b/package-lock.json
index 3fdb753..693fb7e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,6 +8,7 @@
"name": "frontend_dev_assignment",
"version": "0.1.0",
"dependencies": {
+ "lucide-react": "^0.544.0",
"next": "15.5.4",
"react": "19.1.0",
"react-dom": "19.1.0"
@@ -4453,6 +4454,15 @@
"loose-envify": "cli.js"
}
},
+ "node_modules/lucide-react": {
+ "version": "0.544.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.544.0.tgz",
+ "integrity": "sha512-t5tS44bqd825zAW45UQxpG2CvcC4urOwn2TrwSH8u+MjeE+1NnWl6QqeQ/6NdjMqdOygyiT9p3Ev0p1NJykxjw==",
+ "license": "ISC",
+ "peerDependencies": {
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/magic-string": {
"version": "0.30.19",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
diff --git a/package.json b/package.json
index 252da23..7843e0e 100644
--- a/package.json
+++ b/package.json
@@ -9,19 +9,20 @@
"lint": "eslint"
},
"dependencies": {
+ "lucide-react": "^0.544.0",
+ "next": "15.5.4",
"react": "19.1.0",
- "react-dom": "19.1.0",
- "next": "15.5.4"
+ "react-dom": "19.1.0"
},
"devDependencies": {
- "typescript": "^5",
+ "@eslint/eslintrc": "^3",
+ "@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
- "@tailwindcss/postcss": "^4",
- "tailwindcss": "^4",
"eslint": "^9",
"eslint-config-next": "15.5.4",
- "@eslint/eslintrc": "^3"
+ "tailwindcss": "^4",
+ "typescript": "^5"
}
}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index f7fa87e..9386ec6 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -25,7 +25,7 @@ export default function RootLayout({
return (
{children}
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 23eaf49..429340f 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,57 +1,69 @@
'use client'
+import { ImageContainer } from '@/components/images-container'
+import {Navbar} from '@/components/navbar'
import { WorkerType } from '@/types/workers'
import Image from 'next/image'
import { useState, useEffect } from 'react'
-export default function WorkersPage() {
- const [workersData, setWorkersData] = useState([])
+// export default function WorkersPage() {
+// const [workersData, setWorkersData] = useState([])
- useEffect(() => {
- const loadData = async () => {
- try {
- const response = await import('../../workers.json')
- setWorkersData(response.default)
- } catch (error) {
- console.error('Failed to load workers:', error)
- }
- }
- loadData()
- loadData()
- }, [])
+// const loadData = async () => {
+// try {
+// const response = await fetch('/api/workers')
+// const data = await response.json()
+// setWorkersData(data.data)
+// } catch (error) {
+// console.error('Failed to load workers:', error)
+// }
+// }
- return (
-
- Our Workers
+// useEffect(() => {
+// loadData()
+// }, [])
-
- {workersData
- .filter((worker) => worker.pricePerDay > 0)
- .filter((worker) => worker.id !== null)
- .sort((a, b) => a.name.localeCompare(b.name))
- .map((worker: WorkerType) => (
-
-
-
-
-
-
{worker.name}
-
{worker.service}
-
- ₹{Math.round(worker.pricePerDay * 1.18)} / day
-
-
-
- ))}
-
-
- )
-}
+// return (
+//
+// Our Workers
+
+//
+// {workersData
+// .filter((worker) => worker.pricePerDay > 0)
+// .filter((worker) => worker.id !== null)
+// .sort((a, b) => a.name.localeCompare(b.name))
+// .map((worker: WorkerType) => (
+//
+//
+//
+//
+//
+//
{worker.name}
+//
{worker.service}
+//
+// ₹{Math.round(worker.pricePerDay * 1.18)} / day
+//
+//
+//
+// ))}
+//
+//
+// )
+// }
+
+export default function WorkersPage(){
+return (
+ <>
+
+
+ >
+)
+}
\ No newline at end of file
diff --git a/src/components/image-card.tsx b/src/components/image-card.tsx
new file mode 100644
index 0000000..10ffcba
--- /dev/null
+++ b/src/components/image-card.tsx
@@ -0,0 +1,32 @@
+import Image from "next/image"
+import { WorkerType } from "@/types/workers"
+
+export function ImageCard({ id, name, service, image, pricePerDay }: WorkerType) {
+ return (
+
+
+
+
+
+
+
{name}
+
{service}
+
+ ₹{pricePerDay}/day
+
+
+
+
+ )
+}
diff --git a/src/components/images-container.tsx b/src/components/images-container.tsx
new file mode 100644
index 0000000..7273166
--- /dev/null
+++ b/src/components/images-container.tsx
@@ -0,0 +1,129 @@
+"use client"
+
+import { useEffect, useState, useMemo } from "react"
+import { ImageCard } from "./image-card"
+import { useWorkers } from "@/hooks/useWorkers"
+import { WorkerType } from "@/types/workers"
+import { ChevronLeft, ChevronRight } from "lucide-react"
+
+function SkeletonCard() {
+ return (
+
+ )
+}
+
+export function ImageContainer() {
+ const { workers, loading } = useWorkers()
+ const [counter, setCounter] = useState(0)
+ const [priceRange, setPriceRange] = useState<[number, number]>([0, 10000])
+ const [serviceType, setServiceType] = useState("all")
+
+ const services = useMemo(() => {
+ const unique = Array.from(new Set(workers.map((w) => w.service)))
+ return ["all", ...unique]
+ }, [workers])
+
+ const filteredWorkers = useMemo(() => {
+ return workers.filter((w) => {
+ const inPriceRange = w.pricePerDay >= priceRange[0] && w.pricePerDay <= priceRange[1]
+ const matchesService = serviceType === "all" || w.service.toLowerCase() === serviceType.toLowerCase()
+ return inPriceRange && matchesService
+ })
+ }, [workers, priceRange, serviceType])
+
+ const sliceWorkers = useMemo(() => {
+ return filteredWorkers.slice(counter, counter + 12)
+ }, [filteredWorkers, counter])
+
+ useEffect(() => {
+ setCounter(0)
+ }, [priceRange, serviceType])
+
+ const handleNext = () => {
+ setCounter((prev) => (prev + 12 >= filteredWorkers.length ? 0 : prev + 12))
+ }
+
+ const handlePrev = () => {
+ setCounter((prev) => (prev - 12 < 0 ? Math.max(filteredWorkers.length - 12, 0) : prev - 12))
+ }
+
+ if (loading) {
+ return (
+
+ {Array.from({ length: 12 }).map((_, i) => (
+
+ ))}
+
+ )
+ }
+
+ return (
+
+
+
+ {sliceWorkers.length > 0 ? (
+ <>
+
+ {sliceWorkers.map((worker) => (
+
+ ))}
+
+
+
+
+
+
+ >
+ ) : (
+
No workers found.
+ )}
+
+ )
+}
diff --git a/src/components/navbar.tsx b/src/components/navbar.tsx
new file mode 100644
index 0000000..5038d2c
--- /dev/null
+++ b/src/components/navbar.tsx
@@ -0,0 +1,62 @@
+"use client"
+
+import { useState } from "react"
+import Link from "next/link"
+import { Menu, X } from "lucide-react"
+
+export function Navbar() {
+ const [isOpen, setIsOpen] = useState(false)
+
+ return (
+
+ )
+}
diff --git a/src/hooks/useWorkers.tsx b/src/hooks/useWorkers.tsx
new file mode 100644
index 0000000..44f3e0c
--- /dev/null
+++ b/src/hooks/useWorkers.tsx
@@ -0,0 +1,30 @@
+"use client"
+import { useState, useEffect } from "react"
+import { WorkerType } from "@/types/workers"
+
+export function useWorkers() {
+
+ const [workers, setWorkers] = useState([])
+ const [loading, setLoading] = useState(false);
+
+ const fetchWorkers = async () => {
+ try {
+ setLoading(true)
+ const response = await fetch('/api/workers')
+ const data = await response.json();
+ setWorkers(data.data)
+ } catch (e) {
+ console.log(e)
+ }
+ finally{
+ setLoading(false);
+ }
+ }
+
+ useEffect(() => {
+ fetchWorkers()
+ }, [])
+
+
+ return { workers, setWorkers, loading, setLoading }
+}
\ No newline at end of file