Skip to content
Snippets Groups Projects
Commit 1bb4bc6d authored by Kenneth Ezekiel's avatar Kenneth Ezekiel
Browse files

Merge branch develop into feat-user-profile

parents 788c7f56 6783b609
No related merge requests found
.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
......@@ -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 {
......
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");
}
}
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
......@@ -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);
......
......@@ -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 [];
}
}
}
<?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);
}
}
}
<?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
......@@ -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);
......
......@@ -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);
}
}
<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
......@@ -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"> -->
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment