diff --git a/public/css/filmList.css b/public/css/filmList.css
new file mode 100644
index 0000000000000000000000000000000000000000..8f447350d328ab233b39b62b5fbbb15072a1f087
--- /dev/null
+++ b/public/css/filmList.css
@@ -0,0 +1,48 @@
+.search-bar {
+    display: flex;
+    width: 400px;
+    height: 48px;
+    padding: 8px 24px;
+    align-items: center;
+    gap: 8px;
+    flex-shrink: 0;
+    border-radius: 32px;
+    background: var(--neutral-grey-base, #404650);
+}
+
+.sort-filter {
+    display: flex;
+    gap: 12px;
+}
+
+.film-card {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    border-radius: 16px;
+    background: var(--neutral-grey-dark, #21252C);
+    width: 210px;
+    overflow: hidden;
+}
+
+/* Styles for Film Image */
+.film-image {
+    width: 100%;
+    height: 280px;
+    border-radius: 12px 12px 0px 0px;
+    background-size: cover;
+    background-repeat: no-repeat;
+}
+
+/* Styles for Film Title */
+.film-title {
+    color: var(--neutral-white, #FCFCFC);
+    text-align: center;
+    font-family: Poppins, sans-serif;
+    font-size: 16px;
+    font-style: normal;
+    font-weight: 700;
+    line-height: normal;
+    flex: 1 0 0;
+    padding: 12px;
+}
\ No newline at end of file
diff --git a/public/css/styles.css b/public/css/styles.css
index b27b3d9eb4bc70f7a2298080b445c6e846d91051..2c7d6525d93d57800909f23f639846a4a3d8aa06 100644
--- a/public/css/styles.css
+++ b/public/css/styles.css
@@ -24,9 +24,15 @@ time, mark, audio, video {
 	vertical-align: baseline;
 }
 
+:root {
+    --neutral-grey-dark: #21252C;
+    --neutral-white: #FCFCFC;
+    --neutral-grey-base: #404650;
+}
 
 * {
   box-sizing: border-box;
+  font-family: Poppins, sans-serif;
 }
 
 /* HTML5 display-role reset for older browsers */
@@ -54,7 +60,7 @@ table {
 }
 
 .text {
-  font-family: 'Open Sans', sans-serif;
+  font-family: Poppins, sans-serif;
 }
 
 .form-container {
diff --git a/public/js/httpClient.js b/public/js/httpClient.js
new file mode 100644
index 0000000000000000000000000000000000000000..d50c5fd53c04110211e71ede8ee316f0a0c519c6
--- /dev/null
+++ b/public/js/httpClient.js
@@ -0,0 +1,45 @@
+class HttpClient {
+    async promiseAjax(url, payload,method) {
+        return new Promise((resolve, reject) => {
+            const xhr = new XMLHttpRequest();
+
+            xhr.onload = () => {
+                try {
+                    const jsonResponse = JSON.parse(xhr.responseText);
+                    resolve(jsonResponse);
+                } catch (e) {
+                    reject(e);
+                }
+            };
+
+            xhr.onerror = () => {
+                reject(new Error("Fetch error"));
+            };
+
+            const usedMethod = method || "GET";
+            const params = new URLSearchParams(payload).toString();
+            xhr.open(
+                usedMethod,
+                usedMethod !== "GET" ? url : payload ? `${url}?${params}` : url
+            );
+            xhr.setRequestHeader("Content-type", "application/json");
+            payload && usedMethod !== "GET" ? xhr.send(JSON.stringify(payload)) : xhr.send();
+        });
+    }
+
+    async get(url, payload) {
+        return await this.promiseAjax(url, payload, "GET");
+    }
+
+    async post(url, payload) {
+        return await this.promiseAjax(url, payload, "POST");
+    }
+
+    async put(url, payload) {
+        return await this.promiseAjax(url, payload, "PUT");
+    }
+
+    async delete(url) {
+        return await this.promiseAjax(url, null, "DELETE");
+    }
+}
diff --git a/public/js/utils.js b/public/js/utils.js
new file mode 100644
index 0000000000000000000000000000000000000000..2b9b33ea6225af21878b5a0129815698d040ddb7
--- /dev/null
+++ b/public/js/utils.js
@@ -0,0 +1,11 @@
+class Utils {
+    debounce(func, timeout = 300) {
+        let timer;
+        return (...args) => {
+            clearTimeout(timer);
+            timer = setTimeout(() => {
+                func.apply(this, args);
+            }, timeout);
+        };
+    }
+}
\ No newline at end of file
diff --git a/src/App.php b/src/App.php
index c6d9097fede08d91b4dd48b05c57c3d248867a23..4967f24232620d06799e260999f890b7fd9d87e8 100644
--- a/src/App.php
+++ b/src/App.php
@@ -2,6 +2,7 @@
 
 namespace app;
 
+use app\controllers\FilmController;
 use app\Router;
 use app\base\BaseController;
 use app\controllers\CreateFilmController;
@@ -35,6 +36,8 @@ class App
     $this->router->addRoute('/review', ReviewController::class);
     $this->router->addRoute('/logout', LoginController::class);
     $this->router->addRoute('/register', RegisterController::class);
+    $this->router->addRoute('/films', FilmController::class);
+    $this->router->addRoute('/search', FilmController::class);
     $this->router->addRoute('/add-film', CreateFilmController::class);
     $this->router->addRoute('/update-film', UpdateFilmController::class);
     $this->router->addRoute('/profile', ProfileController::class);
diff --git a/src/base/BaseRepository.php b/src/base/BaseRepository.php
index a276a5ea411fd9476a3f5e8eedd62c4fb66af76c..9b38df918b0939e2f420d31139d5d874f0200bfb 100644
--- a/src/base/BaseRepository.php
+++ b/src/base/BaseRepository.php
@@ -150,11 +150,11 @@ abstract class BaseRepository
       }
     }
 
-    if ($pageSize && $pageNo) {
+    if (isset($pageSize) && isset($pageNo)) {
       $offset = $pageSize * ($pageNo - 1);
 
       $stmt->bindValue(":pageSize", $pageSize, PDO::PARAM_INT);
-      $stmt->bindValue(":offset", $offset, PDO::PARAM_INT);
+      $stmt->bindValue(":pageNo", $offset, PDO::PARAM_INT);
     }
 
     $stmt->execute();
@@ -178,7 +178,6 @@ abstract class BaseRepository
     }
 
     // Hydrating statement, for sanitizing
-    // echo $sql;
 
     $stmt = $this->pdo->prepare($sql);
 
@@ -271,6 +270,12 @@ abstract class BaseRepository
   public function getDistinctValues($columnName)
   {
     $sql = "SELECT DISTINCT $columnName FROM $this->tableName";
-    return $this->pdo->query($sql);
+    $stmt = $this->pdo->query($sql);
+
+    if ($stmt) {
+      return $stmt->fetchAll(PDO::FETCH_COLUMN);
+    } else {
+      return [];
+    }
   }
 }
diff --git a/src/controllers/FilmController.php b/src/controllers/FilmController.php
new file mode 100644
index 0000000000000000000000000000000000000000..c88a14a7f21e8f10c4c290ca484adf76292bf8ab
--- /dev/null
+++ b/src/controllers/FilmController.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace app\controllers;
+
+use app\base\BaseController;
+use app\Request;
+use app\services\FilmService;
+
+class FilmController extends BaseController
+{
+  public function __construct()
+  {
+    parent::__construct(FilmService::getInstance());
+  }
+
+  protected function get($urlParams)
+  {
+      $uri = Request::getURL();
+      $page = (isset($_GET['page']) and (int) $_GET['page'] >= 1) ? $_GET['page'] : 1;
+      $word = $_GET['q'] ?? "";
+      $genre = $_GET['genre'] ?? 'all';
+      $released_year = $_GET['year'] ?? 'all';
+      $isDesc = $_GET['desc'] ?? false;
+      $order = $_GET['order'] ?? 'title';
+      $data = $this->service->searchAndFilter($word, $order, $isDesc, $genre, $released_year, $page);
+
+      if ($uri == "/films")
+      {
+          $data['genres'] = $this->service->getAllCategoryValues('genre');
+          $data['released_years'] = $this->service->getAllCategoryValues('released_year');
+
+          parent::render($data, 'filmList', "layouts/base");
+      }
+      else
+      {
+          $films = [];
+
+          foreach ($data['films'] as $film)
+          {
+              $films[] = $film->toResponse();
+          }
+          $data['films'] = $films;
+
+          send_json_response($data);
+      }
+  }
+
+}
diff --git a/src/controllers/utils/response.php b/src/controllers/utils/response.php
new file mode 100644
index 0000000000000000000000000000000000000000..1c2d74822b5a862d8f8e519790eea0d4ab18c261
--- /dev/null
+++ b/src/controllers/utils/response.php
@@ -0,0 +1,12 @@
+<?php
+function send_json_response($data = [], $status_code = 200) {
+    http_response_code($status_code);
+    header('Content-Type: application/json');
+
+    $response = [
+        'status' => $status_code,
+        'data' => $data,
+    ];
+
+    echo json_encode($response);
+}
\ No newline at end of file
diff --git a/src/repositories/FilmRepository.php b/src/repositories/FilmRepository.php
index 3cdbf7ab1f36753613ef612738ca1dd3a3c30257..bec39a177167a74ad20bc7b77169436cae4f7552 100644
--- a/src/repositories/FilmRepository.php
+++ b/src/repositories/FilmRepository.php
@@ -28,16 +28,10 @@ class FilmRepository extends BaseRepository
     return $this->findOne(['film_id' => [$film_id, PDO::PARAM_INT]]);
   }
 
-  public function getAllBySearchAndFilter(
-    $word,
-    $order = 'title',
-    $isDesc = false,
-    $genre = 'all',
-    $released_year = 'all',
-    $pageNo = 1,
-    $limit = PAGINATION_LIMIT
-  ) {
-    $where = [];
+  public function getAllBySearchAndFilter($word, $order = 'title', $isDesc= false, $genre = 'all',
+                                          $released_year = 'all', $pageNo = 1, $limit = 10)
+  {
+      $where = [];
 
     if (isset($genre) and !empty($genre) and $genre != 'all') {
       $where['genre'] = [$genre, PDO::PARAM_STR, 'LIKE'];
@@ -52,6 +46,23 @@ class FilmRepository extends BaseRepository
     return $this->findAll($where, $order, $pageNo, $limit, $isDesc);
   }
 
+  public function countRowBySearchAndFilter($word, $genre = 'all', $released_year = 'all')
+  {
+      $where = [];
+
+      if (isset($genre) and !empty($genre) and $genre != 'all') {
+          $where['genre'] = [$genre, PDO::PARAM_STR, 'LIKE'];
+      }
+      if (isset($released_year) and !empty($released_year) and $released_year != 'all') {
+          $where['released_year'] = [$released_year, PDO::PARAM_INT];
+      }
+      if (isset($word) and !empty($word)) {
+          $where['title'] = [$genre, PDO::PARAM_STR, 'LIKE', ['director']];
+      }
+
+      return $this->countRow($where);
+  }
+
   public function getAllCategoryValues($category)
   {
     return $this->getDistinctValues($category);
diff --git a/src/services/FilmService.php b/src/services/FilmService.php
index de99aad9df6d7704dae16e2220d3b9415e262e69..9bc6307cf8c3d2ca299b8d6b93d798c7bfa557f4 100644
--- a/src/services/FilmService.php
+++ b/src/services/FilmService.php
@@ -84,4 +84,30 @@ class FilmService extends BaseService
 
     return $this->repository->update($film, $arrParams);
   }
+
+
+  public function searchAndFilter($word, $order, $isDesc, $genre, $released_year, $page = 1)
+  {
+      $data = null;
+      $word = strtolower(trim($word));
+      $response = $this->repository->getAllBySearchAndFilter($word, $order, $isDesc, $genre, $released_year , $page);
+      $films = [];
+      foreach ($response as $resp) {
+          $film = new FilmModel();
+          $films[] = $film->constructFromArray($resp);
+      }
+      $data['films'] = $films;
+
+        $row_count = $this->repository->countRowBySearchAndFilter($word, $genre, $released_year);
+        $total_page = ceil($row_count/10);
+        $data['total_page'] = $total_page;
+
+        return $data;
+    }
+
+    public function getAllCategoryValues($category)
+    {
+        return $this->repository->getAllCategoryValues($category);
+    }
+
 }
diff --git a/views/filmList.php b/views/filmList.php
new file mode 100644
index 0000000000000000000000000000000000000000..6660afd0c29e8267937ad6b9d2676c3a45dfc333
--- /dev/null
+++ b/views/filmList.php
@@ -0,0 +1,69 @@
+<div>
+    <div class="search-bar">
+        <input type="text" id="search-input" placeholder="Search film title or director">
+    </div>
+
+    <div class="sort-filter">
+        <select id="sort-by">
+            <option value="title">Sort by Title</option>
+            <option value="released-year">Sort by Released Year</option>
+        </select>
+
+        <select id="sort-order">
+            <option value="ascending">Ascending</option>
+            <option value="descending">Descending</option>
+        </select>
+
+        <select id="filter-genre">
+            <option value="" disabled selected>Choose Genre</option>
+            <?php
+            if (isset($data['genres']))
+            {
+                foreach ($data['genres'] as $genre) {
+                    echo "<option value='$genre'>$genre</option>";
+                }
+            }
+            ?>
+        </select>
+
+        <select id="filter-year">
+            <option value="" disabled selected>Choose Released Year</option>
+            <?php
+            if (isset($data['released_years']))
+            {
+                foreach ($data['released_years'] as $year) {
+                    echo "<option value='$year'>$year</option>";
+                }
+            }
+            ?>
+        </select>
+    </div>
+
+    <div class="film-card-container">
+        <?php
+        if (isset($data['films']))
+        {
+            foreach ($data['films'] as $film) {
+                echo "<div class='film-card'>
+                    <div class='film-image' style='background-image: url($film->image_path);'></div>
+                    <div class='film-title'> $film->title </div>
+                </div>";
+            }
+        }
+        ?>
+    </div>
+
+    <div class="pagination">
+        <button id="prev-page">Previous</button>
+        <?php
+        $totalPages = $data['total_page'];
+        $currentPage = $_GET['page'] ?? 1;
+
+        for ($i = 1; $i <= $totalPages; $i++) {
+            echo "<a href='?page=$i' id='current-page' class='page-number " . ($i == $currentPage ? 'active' : '') . "'>$i</a>";
+        }
+        ?>
+        <button id="next-page">Next</button>
+    </div>
+    <script></script>
+</div>
\ No newline at end of file
diff --git a/views/layouts/base.php b/views/layouts/base.php
index e602316656d6b08fb73725225dc16efd44d1da87..34170daa4bc9712813d3e84c69a14f2f32e0103f 100644
--- a/views/layouts/base.php
+++ b/views/layouts/base.php
@@ -7,12 +7,10 @@
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <link rel='stylesheet' href='/public/css/navbar.css'>
   <link rel='stylesheet' href='/public/css/styles.css'>
+  <link rel='stylesheet' href='/public/css/filmList.css'>
   <link rel="preconnect" href="https://fonts.googleapis.com">
   <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-  <link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&display=swap" rel="stylesheet">
-  <link rel="preconnect" href="https://fonts.googleapis.com">
-  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-  <link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
+  <link href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,400;0,500;0,600;0,700;0,800;1,400;1,500;1,600;1,700;1,800&display=swap" rel="stylesheet">
   <!-- <link rel="stylesheet" href="public/css/lib.css">
   <link rel="stylesheet" href="public/css/shared.css">
   <link rel="stylesheet" href="public/css/home.css"> -->