From 1497ee48777b35f96598c88b598b5e4bd501b754 Mon Sep 17 00:00:00 2001
From: afnanramadhan <13521011@std.stei.itb.ac.id>
Date: Fri, 17 Nov 2023 00:14:07 +0700
Subject: [PATCH] feat: add content

---
 app/controllers/content.php        |   8 +
 app/core/app.php                   |   5 +-
 app/views/content/index.php        |  40 +++++
 app/views/navbar/index.php         |   4 +
 public/css/content.css             | 186 ++++++++++++++++++++
 public/css/navbar.css              |  26 +++
 public/js/content.js               | 271 +++++++++++++++++++++++++++++
 server/controller/auth/Content.php |  40 +++++
 8 files changed, 578 insertions(+), 2 deletions(-)
 create mode 100644 app/controllers/content.php
 create mode 100644 app/views/content/index.php
 create mode 100644 public/css/content.css
 create mode 100644 public/js/content.js
 create mode 100644 server/controller/auth/Content.php

diff --git a/app/controllers/content.php b/app/controllers/content.php
new file mode 100644
index 0000000..25898cc
--- /dev/null
+++ b/app/controllers/content.php
@@ -0,0 +1,8 @@
+<?php
+
+class Content extends Controller {
+  public function index() {
+    $this->view('navbar/index');
+    $this->view('content/index');
+  }
+}
\ No newline at end of file
diff --git a/app/core/app.php b/app/core/app.php
index a061b2c..15b5065 100644
--- a/app/core/app.php
+++ b/app/core/app.php
@@ -16,8 +16,9 @@ class App {
       }
       else if ($url[0] == '') {
         $this->controller = 'home';
-      }
-      else {
+      }else if ($url[0] == 'ontent') {
+        $this->controller = 'content';
+      }else {
         $this->controller = 'error404';
       }
       // else {
diff --git a/app/views/content/index.php b/app/views/content/index.php
new file mode 100644
index 0000000..b4603cd
--- /dev/null
+++ b/app/views/content/index.php
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <link rel="stylesheet" href="../../../public/css/content.css">
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
+    <script defer src="../../../public/js/content.js"></script>
+    <script>window.onload = function() {showAll();};</script>
+    <title>NutriCraft</title>
+</head>
+<body>
+    <div>
+        <div class="content">
+            <h1>NutriFacts</h1>
+            <div class="searchsort">
+                <div class="searchcontainer">
+                    <i class="fas fa-search"></i>
+                    <input class="searchinput" id="searchinput" type="text" placeholder="Search" onkeyup=searchDebounce()>
+                </div>
+                <div class="sortcontainer">
+                    <img src="../../../assets/sort.png" alt="">
+                    <select name="sortby" id="pet-select" onclick=Search()>
+                        <option value="Alphabet" class="alpha">Alphabet</option>
+                        <option value="Newest">Newest</option>
+                        <option value="Oldest">Oldest</option>
+                    </select>
+                </div>
+            </div>
+            <div id="isicontent" class="content"></div>
+            <div id="pagination" class="pagination">
+                <button class="prev" onclick=prevPage()>&laquo;</button>
+                <div id="numberpage" class="buttons">
+                </div>
+                
+                <button class="next" onclick=nextPage() >&raquo;</button>
+        </div>
+    </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/app/views/navbar/index.php b/app/views/navbar/index.php
index 5b40cc1..a8d48c1 100644
--- a/app/views/navbar/index.php
+++ b/app/views/navbar/index.php
@@ -22,6 +22,9 @@
                 <a href="/fact">
                     <button type="button" class="fact">Fact</button>
                 </a>
+                <a href="/content">
+                    <button type="button" class="contentnav">Content</button>
+                </a>
             </div>
             <div id="login">
             <?php
@@ -73,6 +76,7 @@ if (isset($_COOKIE['user'])) {
             <a href="/home">Home</a>
             <a href="/meals">Meals</a>
             <a href="/fact">Fact</a>
+            <a href="/content">Content</a>
         </div>
     </div>
 </body>
diff --git a/public/css/content.css b/public/css/content.css
new file mode 100644
index 0000000..c5d3294
--- /dev/null
+++ b/public/css/content.css
@@ -0,0 +1,186 @@
+@import url('https://fonts.googleapis.com/css2?family=Nunito&display=swap');
+
+*{
+    font-family: 'Nunito', sans-serif;
+}
+
+.content {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+}
+
+.searchsort {
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    align-items: center;
+    gap: 20px;
+    margin-bottom: 20px;
+}
+
+.searchsort input {
+    border: none;
+    outline: none;
+}
+
+.searchsort div:hover, .searchsort div:focus-within {
+    border: 1px solid #288990;
+    transform: scale(1.001); /* Slightly scale up on hover */
+    box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
+
+}
+
+.searchcontainer {
+    border: 1px solid #000000;
+    border-radius: 20px;
+    padding: 5px;
+    width: 40vw;
+}
+
+.searchcontainer input {
+    width: 80%;
+    padding-left: 5px;
+}
+
+
+.sortcontainer {
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    align-items: center;
+    border: 1px solid #000000;
+    border-radius: 20px;
+    padding: 5px;
+}
+
+.sortcontainer img {
+    width: 20px;
+    height: 20px;
+}
+
+.sortcontainer select {
+    border: none;
+    outline: none;
+    background-color: transparent;
+}
+
+
+.video-card {
+    border: 1px solid #EF4800;
+    border-radius: 20px;
+    margin: 10px;
+    width: 60%;
+    overflow: hidden;
+}
+
+.video-card:hover {
+    border: 1px solid #288990;
+    transform: scale(1.001); /* Slightly scale up on hover */
+    box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
+}
+
+.cardcontent {
+    display: flex;
+    flex-direction: row;
+    background-color: #FFFFFF;
+    cursor: pointer;
+    gap: 20px;
+    /* border-bottom: 1px solid #EF4800; */
+}
+
+.cardcontent img {
+    width: 20%;
+    height: 10%;
+    border-bottom-left-radius: 0;
+    /* border-top-right-radius: 20px; */
+    border-bottom-right-radius: 20px;
+}
+
+.cardcontent h3{
+    margin-top: 28px;
+    margin-bottom: 0;
+    font-size: 24px
+}
+
+.cardcontent p {
+    margin-top: 5px;
+}
+
+.video-content {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    max-height: 0;
+    overflow: hidden;
+    transition: max-height 0.3s ease-out;
+    
+}
+
+.video-content video {
+    width: 95%;
+    height: 30vw;
+    /* margin: 23px; */
+}
+
+.pagination {
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    align-items: center;
+    /* gap: 10px; */
+    margin-top: 20px;
+    margin-bottom: 50px;
+}
+
+.pagination button {
+    border: 1px solid #EF4800;
+    background-color: transparent;
+    color: #EF4800;
+    width: 40px;
+    height: 40px;
+    border-radius: 10px;
+    font-size: 16px;
+    font-weight: 600;
+    cursor: pointer;
+    transition: background-color 0.3s ease, color 0.3s ease;
+}
+
+.pagination button:hover {
+    background-color: #EF4800;
+    color: #FFFFFF;
+    transition: background-color 0.3s ease, color 0.3s ease;
+}
+
+.pagination button:focus {
+    outline: none;
+}
+
+.page{
+    gap: 10px;
+    margin-left: 5px;
+    margin-right: 5px;
+}
+
+.next{
+    margin-left: 5px;
+}
+
+.prev{
+    margin-right: 5px;
+}
+
+ #selected {
+    background-color: #EF4800;
+    color: #FFFFFF;
+    transition: background-color 0.3s ease, color 0.3s ease;
+}
+
+.buttons button:hover {
+    /* back color brigther orange than selected */
+    background-color: #FF6B00;
+    color: #FFFFFF;
+    transition: background-color 0.3s ease, color 0.3s ease;
+} 
\ No newline at end of file
diff --git a/public/css/navbar.css b/public/css/navbar.css
index ef89cb7..3cf17b5 100644
--- a/public/css/navbar.css
+++ b/public/css/navbar.css
@@ -128,6 +128,32 @@ body {
 
 }
 
+.contentnav{
+    /* transparent button */
+    background-color: transparent;
+    border: none;
+    color: #000000;
+    text-align: center;
+    text-decoration: none;
+    font-size: 20px;
+    font-weight: bold;
+    cursor: pointer;
+    transform: scale(1); /* Default scale */
+    transition: transform 0.3s; 
+    /* animation underline on hover home */
+    text-decoration: none;
+    text-decoration-color: transparent;
+    text-decoration-thickness: 2px;
+    text-underline-offset: 2px;
+    text-decoration-skip-ink: none;
+}
+
+/* animation underline on hover home */
+.contentnav:hover{
+    transform: scale(1.2); /* Increased scale */
+
+}
+
 .login{
     background-color: #EF4800;
     border: none;
diff --git a/public/js/content.js b/public/js/content.js
new file mode 100644
index 0000000..6c68d33
--- /dev/null
+++ b/public/js/content.js
@@ -0,0 +1,271 @@
+
+function toggleVideo(card) {
+    var content = card.querySelector('.video-content'); // Use card parameter to find .video-content within the clicked card
+    // console.log(content)
+    if (content && content.style.maxHeight) { // Check if content is not null
+        content.style.maxHeight = null;
+    } else if (content) { // Check if content is not null
+        content.style.maxHeight = "50vw";
+    }
+}
+
+let Page = 1;
+let TotalPage;
+
+// Add a click event listener to a parent container (e.g., isicontent)
+document.getElementById("isicontent").addEventListener("click", function(event) {
+    const target = event.target;
+
+    // Check if the clicked element has the class .video-card
+    if (target.classList.contains("video-card")) {
+        toggleVideo(target);
+    }
+});
+
+
+function capitalizeWords(str) {
+    return str.split(' ').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ');
+  }
+
+  
+  // masi salah
+const pagination = () => {
+    const pageNumber = "pageNumber";
+    const search = document.getElementById('searchinput').value;
+    const xhttp = new XMLHttpRequest();
+    xhttp.onreadystatechange = function() {
+        if (this.readyState === 4){
+            let response = this.response;
+            const startIndex = response.indexOf('[');
+            const jsonStr = response.substring(startIndex);
+            const jsonObject = JSON.parse(jsonStr);
+            
+            const numberpage = document.getElementById('numberpage');
+            TotalPage=Math.ceil(jsonObject.length / 2);
+            let html = "";
+            for (let i = 1; i <= Math.ceil(jsonObject.length / 2); i++) {
+                if(i == 1){
+                    html += `<button type='button' class="page" value=${i} id='selected' onclick='selectPage(); getPage(${i});' ">${i}</button>`;
+                }else{
+                    html += `<button type='button' class="page" value=${i} onclick='selectPage(); getPage(${i});' ">${i}</button>`;
+                }
+            }
+            numberpage.innerHTML = html;
+        }
+    };
+    xhttp.open('GET', `../../server/controller/auth/Content.php?pageNumber=${pageNumber}&search=${search}`, true);
+    xhttp.send();
+}
+
+
+// pagination();
+const Search = () => {
+    const search = capitalizeWords(document.getElementById('searchinput').value);
+    const select = document.getElementById('pet-select').value;
+    xhttp = new XMLHttpRequest();
+    xhttp.onreadystatechange = function() {
+        if (this.readyState === 4){
+            
+            let response = this.response;
+            const startIndex = response.indexOf('[');
+            const jsonStr = response.substring(startIndex);
+            const jsonObject = JSON.parse(jsonStr);
+            
+            // console.log(jsonStr);
+
+
+            const parentElement = document.getElementById("isicontent");
+            
+            let html = "";
+            for (let i = 0; i < jsonObject.length; i++) {
+                const content = jsonObject[i];
+                html += `
+                <div class="video-card" onclick="toggleVideo(this)">
+                <div class="cardcontent">
+                <img src="${content.path_photo}" alt="">
+                <div class="card-title">
+                <h3>${content.title}</h3>
+                            <p>${content.highlight}</p>
+                            </div>
+                    </div>
+                    <div class="video-content">
+                    <video src="${content.path_file}" controls></video>
+                    </div>
+                    </div>
+                    `;
+                }
+                
+                parentElement.innerHTML = html;
+            }
+            
+            
+            pagination();
+        };
+        xhttp.open('GET', `../../server/controller/auth/Content.php?search=${search}&select=${select}&page=${Page}`, true);
+        xhttp.send(JSON.stringify({search: search, select: select}));
+
+}
+
+const showAll = () => {
+    const show = "all";
+    const select = document.getElementById('pet-select').value;
+    // console.log(Page);
+    xhttp = new XMLHttpRequest();
+    xhttp.onreadystatechange = function() {
+        if (this.readyState === 4){
+            let response = this.response;
+            const startIndex = response.indexOf('[');
+            const jsonStr = response.substring(startIndex);
+            const jsonObject = JSON.parse(jsonStr);
+            // console.log(jsonStr);
+            
+            
+            const parentElement = document.getElementById("isicontent");
+            let html = "";
+            for (let i = 0; i < jsonObject.length; i++) {
+            const content = jsonObject[i];
+            html += `
+            <div class="video-card" onclick="toggleVideo(this)">
+            <div class="cardcontent">
+            <img src="${content.path_photo}" alt="">
+            <div class="card-title">
+            <h2>${content.title}</h2>
+            <p>${content.highlight}</p>
+            </div>
+            </div>
+            <div class="video-content">
+                    <video src="${content.path_file}" controls></video>
+                    </div>
+            </div>
+            `;
+        }
+        {/* <div class="video-content">
+        <iframe src="https://www.youtube.com/embed/l970HoJ7g7o?si=61k4a2ioQf4YfpFF" frameborder="0" allowfullscreen></iframe>
+    </div> */}
+            parentElement.innerHTML = html;        
+            pagination();
+        }
+    };  
+    xhttp.open('GET', `../../server/controller/auth/Content.php?show=${show}&Select=${select}&page=${Page}`, true);
+    xhttp.send();
+
+}
+
+const selectpagination = () => {
+    const show = "all";
+    const select = document.getElementById('pet-select').value;
+    // console.log(Page);
+    xhttp = new XMLHttpRequest();
+    xhttp.onreadystatechange = function() {
+        if (this.readyState === 4){
+            let response = this.response;
+            const startIndex = response.indexOf('[');
+            const jsonStr = response.substring(startIndex);
+            const jsonObject = JSON.parse(jsonStr);
+            // console.log(jsonStr);
+            
+            
+            const parentElement = document.getElementById("isicontent");
+            let html = "";
+            for (let i = 0; i < jsonObject.length; i++) {
+            const content = jsonObject[i];
+            html += `
+            <div class="video-card" onclick="toggleVideo(this)">
+            <div class="cardcontent">
+            <img src="${content.path_photo}" alt="">
+            <div class="card-title">
+            <h3>${content.title}</h3>
+            <p>${content.highlight}</p>
+            </div>
+            </div>
+            <div class="video-content">
+                    <video src="${content.path_file}" controls></video>
+                    </div>
+            </div>
+            `;
+        }
+        {/* <div class="video-content">
+        <iframe src="https://www.youtube.com/embed/l970HoJ7g7o?si=61k4a2ioQf4YfpFF" frameborder="0" allowfullscreen></iframe>
+    </div> */}
+            parentElement.innerHTML = html;        
+        }
+    };  
+    xhttp.open('GET', `../../server/controller/auth/Content.php?show=${show}&Select=${select}&page=${Page}`, true);
+    xhttp.send();
+
+}
+
+
+const prevPage = () =>{
+    const search = document.getElementById('searchinput').value;
+    if(Page>1){
+        Page-=1
+        if(search==''){
+            selectpagination();
+        }else{
+            Search();
+        }
+    }
+}
+
+const nextPage = () =>{
+    const search = document.getElementById('searchinput').value;
+    if(Page<TotalPage){
+        Page+=1
+        // console.log(Page);
+        // console.log("HAI");
+        if(search==''){
+            showAll();
+        }else{
+            Search();
+        }
+    }
+}
+
+function getPage(pa){
+    Page = pa;
+    // console.log(Page);
+}
+
+
+function debounce(func, timeout = 500){
+    let timer;
+    return (...args) => {
+        clearTimeout(timer);
+        timer = setTimeout(() => { func.apply(this, args); }, timeout);
+    };
+}
+
+function selectPage (){
+    const buttons = document.querySelectorAll('#numberpage button');
+    // console.log(buttons);
+    // Add click event listeners to each button
+    buttons.forEach(button => {
+        button.addEventListener('click', () => {
+            // Remove the 'selected' id from the currently selected button
+            const currentlySelectedButton = document.querySelector('#selected');
+            currentlySelectedButton.removeAttribute('id');
+
+            // Add the 'selected' id to the clicked button
+            button.id = 'selected';
+
+            // Optionally, you can add a CSS class to style the selected button
+            buttons.forEach(btn => btn.classList.remove('selected'));
+            button.classList.add('selected');
+        });
+    });
+}
+
+
+document.getElementById('numberpage').addEventListener('click',()=>{
+    const search = document.getElementById('searchinput').value;
+    if(search==''){
+        console.log("HAI");
+        selectpagination();
+    }else{
+        Search();
+    }
+})
+
+
+const searchDebounce = debounce(() => Search());
\ No newline at end of file
diff --git a/server/controller/auth/Content.php b/server/controller/auth/Content.php
new file mode 100644
index 0000000..049fa66
--- /dev/null
+++ b/server/controller/auth/Content.php
@@ -0,0 +1,40 @@
+<?php
+
+use data\Content;
+require_once('../../handler/data/Content.php');
+require_once('../../db/Database.php');
+
+$content = new Content();
+
+
+if(isset($_GET['select'])){
+    $select = $_GET['select'];
+    $page = $_GET['page'];
+    $page = ($page-1)*10;
+    if(isset($_GET['search'])){
+        $search = $_GET['search'];
+        $result = $content->FindByTitle($search, $select, $page);
+    }else{
+        $result = $content->FindAllPaging($select, $page);
+    }
+    
+    echo json_encode($result);
+}
+
+if(isset($_GET['show'])){
+    $page = $_GET['page'];
+    $page = ($page-1)*2;
+    $select = $_GET['Select'];
+    $result = $content->FindAllPaging($select, $page);
+    echo json_encode($result);
+}
+
+if(isset($_GET['pageNumber'])){
+    if(isset($_GET['search'])){
+        $search = $_GET['search'];
+        $result = $content->FindAllSearch($search);
+    }else{
+        $result = $content->FindAll($search);
+    }
+    echo json_encode($result);
+}
\ No newline at end of file
-- 
GitLab