Skip to content
Snippets Groups Projects
Commit 2a6a10f8 authored by arsaizdihar's avatar arsaizdihar
Browse files

feat: add media

parent a21ed552
Branches
Tags
No related merge requests found
src/public/media/
\ No newline at end of file
......@@ -8,6 +8,7 @@ services:
- 8080:80
volumes:
- ./src:/var/www/html
- ./src/php.ini:/usr/local/etc/php/php.ini
networks:
- php-network
depends_on:
......
......@@ -11,6 +11,7 @@ use app\Forms\Validation;
use app\Models\Dorm;
use app\Models\Media;
use app\Models\Owners;
use app\Utils\FileManager;
class DormController extends Controller
{
......@@ -48,6 +49,14 @@ class DormController extends Controller
public function media($params)
{
$dormId = $params["dormId"];
if (Request::getMethod() === "POST") {
$files = Request::getFiles("medias");
if ($files !== null) {
$this->uploadMedia($files, $dormId);
Response::redirect("/dorms/{$dormId}/media");
return;
}
}
$dorm = Dorm::findById($dormId);
$medias = Media::findByDormId($dormId);
......@@ -56,4 +65,21 @@ class DormController extends Controller
"medias" => $medias
]);
}
private function uploadMedia($files, $dorm_id)
{
foreach ($files["name"] as $index => $name) {
$filePath = FileManager::getPathFor($name, $files["type"][$index]);
if ($filePath == false) {
continue;
}
$media = new Media();
$media->dorm_id = $dorm_id;
$media->alt_text = $name;
$media->type = explode("/", $files["type"][$index])[0] === "image" ? "photo" : "video";
$media->endpoint = $filePath;
$media->save();
FileManager::uploadToPublic($files["tmp_name"][$index], $filePath);
}
}
}
......@@ -44,6 +44,6 @@ class Application
$this->router->get("/me", [AuthRequired::class], AuthController::class, 'me');
$this->router->methods(["GET", "POST"], "/dorms/create", [AdminOnly::class], DormController::class, 'create');
$this->router->get("/dorms/{dormId}/media", [AdminOnly::class], DormController::class, 'media');
$this->router->methods(["GET", "POST"], "/dorms/{dormId}/media", [AdminOnly::class], DormController::class, 'media');
}
}
}
\ No newline at end of file
......@@ -54,4 +54,9 @@ class Request
{
return isset($_SESSION['user']);
}
public static function getFiles($fieldName)
{
return $_FILES[$fieldName] ?? null;
}
}
......@@ -138,6 +138,9 @@ class Router
$uri = Request::getPath();
foreach ($this->dynamicRoutes as $routeRegex => $routeHandler) {
if (preg_match($routeRegex, $uri, $matches)) {
if (array_key_exists(Request::getMethod(), $routeHandler) === false) {
return false;
}
[$controllerClass, $middlewares, $action, $vars] = $routeHandler[Request::getMethod()];
$controller = new $controllerClass();
$params = [];
......
<?php
namespace app\Utils;
class FileManager
{
public static function getPathFor($fileName, $fileType)
{
// add timestamp to file name
$fileName = time() . $fileName;
if (str_starts_with($fileType, "image")) {
return "/media/images/$fileName";
} else if (str_starts_with($fileType, "video")) {
return "/media/videos/$fileName";
} else {
return false;
}
}
public static function uploadToPublic($tmp_path, $filePath)
{
$path = __DIR__ . "/../public" . $filePath;
$pathInfo = pathinfo($path);
if (is_dir($pathInfo["dirname"]) === false) {
mkdir($pathInfo["dirname"], 0755, true);
}
move_uploaded_file($tmp_path, $path);
}
}
@extends('layouts/base')
\ No newline at end of file
@extends('layouts/base')
@@head
<link rel="stylesheet" href="/static/styles/dorm-media.css">
@@endhead
<div class="container">
<h1 class="">Media "<?= $dorm->name ?>"</h1>
<? if (count($medias) > 0) : ?>
<section class="slider-wrapper">
<button class="slide-arrow slide-arrow-prev">
&#8249;
</button>
<button class="slide-arrow slide-arrow-next">
&#8250;
</button>
<ul class="slides-container">
<? foreach ($medias as $media) : ?>
<li class="slide">
<? if ($media->type == "video") : ?>
<video src="<?= $media->endpoint ?>" alt="<?= $media->alt_text ?>" controls></video>
<? else : ?>
<img src="<?= $media->endpoint ?>" alt="<?= $media->alt_text ?>">
<? endif; ?>
</li>
<?php endforeach; ?>
</ul>
</section>
<? endif; ?>
<form method="post" enctype="multipart/form-data">
<input type="file" name="medias[]" multiple accept="image/*, video/*" />
<button type="button" class="btn btn-primary dialog-btn" data-dialog="upload-media-dialog">Upload</button>
<div class="dialog-wrapper upload-media-dialog">
<div class="dialog-content">
<h4 class="confirm-title">
Apakah anda yakin ingin upload media?
</h4>
<div class="confirm-action">
<button type="button" class="btn btn-outlined dialog-btn" data-dialog="upload-media-dialog">Batal</button>
<button type="submit" class="btn btn-primary">Upload</button>
</div>
</div>
</div>
</form>
</div>
\ No newline at end of file
file_uploads = On
upload_max_filesize = 100M
post_max_size = 100M
\ No newline at end of file
......@@ -45,3 +45,19 @@ window.addEventListener("load", () => {
}, 5000);
});
});
const slidesWrappers = document.querySelectorAll(".slider-wrapper");
slidesWrappers.forEach((slideWrapper) => {
const slidesContainer = slideWrapper.querySelector(".slides-container");
const slide = slidesContainer.querySelector(".slide");
const prevButton = slideWrapper.querySelector(".slide-arrow-prev");
const nextButton = slideWrapper.querySelector(".slide-arrow-next");
nextButton.addEventListener("click", (event) => {
const slideWidth = slide.clientWidth;
slidesContainer.scrollLeft += slideWidth;
});
prevButton.addEventListener("click", () => {
const slideWidth = slide.clientWidth;
slidesContainer.scrollLeft -= slideWidth;
});
});
.container {
max-width: 720px;
width: 100%;
margin: 0 auto;
}
......@@ -51,6 +51,7 @@ h1 {
.navbar_main {
position: fixed;
top: 0;
z-index: 40;
inset-inline: 0;
background: white;
border-bottom: 1px solid var(--color-gray);
......@@ -265,6 +266,7 @@ td {
.dialog-wrapper {
position: fixed;
z-index: 50;
inset: 0;
background-color: rgba(0, 0, 0, 0.5);
display: none;
......@@ -279,7 +281,7 @@ td {
.dialog-content {
animation: 0.1s ease-out 0s 1 zoomIn;
background-color: white;
padding: 1rem;
padding: 2rem;
border-radius: 0.25rem;
width: 90%;
max-width: 380px;
......@@ -300,7 +302,7 @@ td {
.dialog-content .confirm-title {
font-size: var(--text-lg);
font-weight: 700;
margin-bottom: 1rem;
margin-bottom: 2rem;
}
.dialog-content .confirm-action {
......@@ -314,6 +316,10 @@ td {
flex: 1;
}
.dialog-content .confirm-action .btn {
padding-block: 0.5rem;
}
.toast {
position: fixed;
z-index: 50;
......@@ -356,7 +362,7 @@ td {
width: 100%;
bottom: 0;
height: 0.25rem;
transition: all 5s linear;
transition: width 5s linear;
}
.toast.loaded .toast-progress {
......@@ -370,3 +376,73 @@ td {
.toast.toast-success .toast-progress {
background-color: var(--color-primary);
}
.slider-wrapper {
margin: 1rem;
position: relative;
overflow: hidden;
}
.slides-container {
max-width: 100%;
width: 100%;
aspect-ratio: 16 / 9;
display: flex;
list-style: none;
margin: 0;
padding: 0;
overflow: scroll;
scroll-behavior: smooth;
}
.slide {
width: 100%;
height: 100%;
flex: 1 0 100%;
}
.slide img,
video {
width: 100%;
height: 100%;
object-fit: contain;
}
.slides-container {
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* Internet Explorer 10+ */
}
/* WebKit */
.slides-container::-webkit-scrollbar {
width: 0;
height: 0;
}
.slide-arrow {
position: absolute;
display: flex;
top: 0;
bottom: 0;
margin: auto;
height: 4rem;
background-color: white;
border: none;
width: 2rem;
font-size: 3rem;
padding: 0;
cursor: pointer;
opacity: 0.5;
transition: opacity 100ms;
z-index: 10;
}
.slide-arrow:hover,
.slide-arrow:focus {
opacity: 1;
}
.slide-arrow-prev {
left: 0;
padding-left: 0.25rem;
border-radius: 0 2rem 2rem 0;
}
.slide-arrow-next {
right: 0;
padding-left: 0.75rem;
border-radius: 2rem 0 0 2rem;
}
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