>
<?php
/**
* AddProductController
*/
class AddProductController {
public function index() {
$title = 'Home';
require_once APP_ROOT . '/app/Views/addproduct.php';
}
public function store() {
// file_put_contents('log.txt', print_r($_FILES, true) . "\n", FILE_APPEND);
$zielOrdner = dirname(__DIR__, 2) . '/public/uploads/';
if (!is_dir($zielOrdner)) {
mkdir($zielOrdner, 0755, true); // Ordner erstellen, falls er nicht existiert
}
$erfolgreichGespeichert = []; // Hier sammeln wir die Pfade der fertigen Bilder
$fehlerMeldungen = []; // Hier sammeln wir Fehler
// Prüfen, ob das Array 'images' ankam
if (isset($_FILES['images'])) {
// Zählen, wie viele Bilder im Array stecken
$anzahlBilder = count($_FILES['images']['name']);
$erlaubteTypen = [
'image/jpeg' => 'jpg',
'image/png' => 'png',
'image/gif' => 'gif',
'image/webp' => 'webp'
];
// Schleife durch alle hochgeladenen Bilder
for ($i = 0; $i < $anzahlBilder; $i++) {
$temporaererPfad = $_FILES['images']['tmp_name'][$i];
$originalName = $_FILES['images']['name'][$i];
$fehlerCode = $_FILES['images']['error'][$i];
// 1. Prüfen, ob die Datei überhaupt hochgeladen wurde (z.B. bei leeren Feldern)
if ($fehlerCode === UPLOAD_ERR_NO_FILE) {
continue; // Überspringen
}
// 2. Gab es einen generellen Übertragungsfehler?
if ($fehlerCode !== UPLOAD_ERR_OK) {
$fehlerMeldungen[] = "Fehler bei '$originalName' (Code: $fehlerCode).";
continue; // Zum nächsten Bild springen
}
// 3. SICHERHEITS-CHECK: Ist es wirklich ein Bild?
$bildInfo = getimagesize($temporaererPfad);
if ($bildInfo === false) {
$fehlerMeldungen[] = "'$originalName' ist kein gültiges Bild und wurde blockiert!";
continue;
}
// 4. MIME-Type überprüfen (Nur bestimmte Formate erlauben)
$echterMimeType = $bildInfo['mime'];
if (!array_key_exists($echterMimeType, $erlaubteTypen)) {
$fehlerMeldungen[] = "'$originalName' hat ein falsches Format (Nur JPG, PNG, GIF, WebP).";
continue;
}
// 5. Neuen, sicheren Dateinamen generieren
$sichereEndung = $erlaubteTypen[$echterMimeType];
// uniqid() generiert einen einmaligen Namen, das $i sorgt dafür, dass
// Bilder in der gleichen Millisekunde keine Konflikte machen.
$neuerDateiname = uniqid('img_') . '_' . $i . '.' . $sichereEndung;
$endgueltigerPfad = $zielOrdner . $neuerDateiname;
// 6. Datei verschieben
if (move_uploaded_file($temporaererPfad, $endgueltigerPfad)) {
// Wenn erfolgreich, merken wir uns den Pfad
$erfolgreichGespeichert[] =['image_url'=> $endgueltigerPfad,'is_main_image'=> $i === 0 ? true : false, 'sort_order' => $i];
} else {
$fehlerMeldungen[] = "'$originalName' konnte nicht auf dem Server gespeichert werden.";
}
}
file_put_contents('logtest.txt', "Erfolgreich: " . print_r($erfolgreichGespeichert, true) . "\n", FILE_APPEND);
if(isset($_POST)){
file_put_contents('logpost.txt', print_r($_POST, true) . "\n", FILE_APPEND);
$name = $_POST['name'] ?? '';
$description = $_POST['description'] ?? '';
$price = $_POST['price'] ?? 0;
$sku = strtoupper(bin2hex(random_bytes(4)));
$productModel = new ProductModel();
$productModel->addProduct($name, $sku, $price, $description, $erfolgreichGespeichert);
}
// ---------------------------------------------------------
// ZUSAMMENFASSUNG ZURÜCK AN JAVASCRIPT SENDEN (als JSON)
// ---------------------------------------------------------
//header('Content-Type: application/json');
echo json_encode([
'status' => count($fehlerMeldungen) === 0 ? 'success' : 'partial',
'gespeichert' => $erfolgreichGespeichert,
'fehler' => $fehlerMeldungen
]);
} else {
echo json_encode(['status' => 'error', 'message' => 'Keine Bilder empfangen.']);
}
// $name = $_POST['name'];
// $price = $_POST['price'];
// $description = $_POST['description'];
// $image = $_FILES['image']['name'];
// $target = "uploads/" . basename($image);
// Move the uploaded file to the target directory
// if (move_uploaded_file($_FILES['image']['tmp_name'], $target)) {
// // File upload successful, now save product details to the database
// $db = new Database();
// $db->query("INSERT INTO products (name, price, description, image) VALUES (:name, :price, :description, :image)");
// $db->bind(':name', $name);
// $db->bind(':price', $price);
// $db->bind(':description', $description);
// $db->bind(':image', $image);
// if ($db->execute()) {
// header('Location: ' . URL_ROOT . '/products');
// exit();
// } else {
// echo "Error saving product to database.";
// }
// } else {
// echo "Error uploading image.";
// }
}
}
?>
<?php
class AuthController
{
public function login()
{
$model = new LoginModel();
$AuthStatus= $model->authenticate($_POST['email'], $_POST['password']);
if ($AuthStatus) {
// Erfolg
$_SESSION['user'] = $AuthStatus;
header('Location: ' . APP_URL . 'home');
exit;
} else{
$login_Msg = 'Ungültige Zugangsdaten';
}
// Fehler
$error = 'Ungültige Zugangsdaten';
require APP_ROOT . '/app/Views/login.php';
}
public function logout()
{
session_start();
session_destroy();
header('Location: ' . APP_URL . 'login');
exit;
}
public function register (){
$vorname = htmlentities($_POST['vorname']);
$nachname = htmlentities($_POST['nachname']);
$email =filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);
$adresse = htmlentities($_POST['adresse']);
$geburtsdatum = htmlentities($_POST['geburtsdatum']);
$password = htmlentities($_POST['password']);
$password_confirm = htmlentities($_POST['password_confirm']);
// Validierung
if (empty($vorname) || empty($nachname) || empty($email) || empty($adresse) || empty($geburtsdatum) || empty($password) || empty($password_confirm)) {
$error = 'Alle Felder müssen ausgefüllt sein!';
$title = 'Registrierung';
require_once APP_ROOT . '/app/Views/register.php';
return;
}
if($password !== $password_confirm){
$error = 'Die Passwörter stimmen nicht überein!';
$title = 'Registrierung';
require_once APP_ROOT . '/app/Views/register.php';
return;
}
$model = new RegisterModel();
$registerStatus = $model->register($vorname, $nachname, $email, $adresse, $geburtsdatum, $password);
if ($registerStatus) {
$success = 'Registrierung erfolgreich! Du kannst dich jetzt anmelden.';
require_once APP_ROOT . '/app/Views/register.php';
} else {
$error = 'Registrierung fehlgeschlagen. Bitte versuche es erneut.';
require_once APP_ROOT . '/app/Views/register.php';
}
}
}
?><?php
/**
* Home Controller
*/
class HomeController {
public function index() {
$title = 'Home';
require_once APP_ROOT . '/app/Views/home.php';
}
}
?>
<?php
class LoginController {
public function index() {
$title = 'Login';
require_once APP_ROOT . '/app/Views/login.php';
}
}<?php
class ProductController {
public function index() {
$id = $_GET['params']['id'] ?? null;
if (!$id) {
echo "Produkt ID fehlt";
return;
}
$productModel = new ProductModel();
$product = $productModel->getProductById($id);
if (!$product || empty($product)) {
echo "Produkt nicht gefunden";
return;
exit;
}
// Extrahiere die Produktdaten
extract($product[0]);
// Lade Produktbilder
$imagesData = $productModel->getProductImages($id);
$images = [];
if ($imagesData) {
foreach ($imagesData as $img) {
$images[] = $img['image_path'];
}
}
// Lade die View
require_once APP_ROOT . '/app/Views/products.php';
}
}<?php
class RegisterController {
public function index() {
$title = 'Registrierung';
require_once APP_ROOT . '/app/Views/register.php';
}
public function store() {
// POST-Anfrage verarbeiten
$vorname = trim($_POST['vorname'] ?? '');
$nachname = trim($_POST['nachname'] ?? '');
$email = trim($_POST['email'] ?? '');
$adresse = trim($_POST['adresse'] ?? '');
$geburtsdatum = trim($_POST['geburtsdatum'] ?? '');
$password = trim($_POST['password'] ?? '');
$password_confirm = trim($_POST['password_confirm'] ?? '');
// Validierung
if (empty($vorname) || empty($nachname) || empty($email) || empty($adresse) || empty($geburtsdatum) || empty($password) || empty($password_confirm)) {
$error = 'Alle Felder müssen ausgefüllt sein!';
$title = 'Registrierung';
require_once APP_ROOT . '/app/Views/register.php';
return;
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$error = 'Bitte gib eine gültige E-Mail Adresse ein!';
$title = 'Registrierung';
require_once APP_ROOT . '/app/Views/register.php';
return;
}
if (strlen($password) < 6) {
$error = 'Das Passwort muss mindestens 6 Zeichen lang sein!';
$title = 'Registrierung';
require_once APP_ROOT . '/app/Views/register.php';
return;
}
if ($password !== $password_confirm) {
$error = 'Die Passwörter stimmen nicht überein!';
$title = 'Registrierung';
require_once APP_ROOT . '/app/Views/register.php';
return;
}
// Geburtsdatum validieren
$dob = DateTime::createFromFormat('Y-m-d', $geburtsdatum);
if (!$dob || $dob > new DateTime()) {
$error = 'Bitte gib ein gültiges Geburtsdatum ein!';
$title = 'Registrierung';
require_once APP_ROOT . '/app/Views/register.php';
return;
}
// TODO: Prüfe ob Email bereits existiert
// TODO: Speichere neuen Benutzer in der Datenbank mit gehashtem Passwort
// password_hash($password, PASSWORD_BCRYPT)
$success = 'Registrierung erfolgreich! Du kannst dich jetzt anmelden.';
$_POST = []; // Clear form
$title = 'Registrierung';
require_once APP_ROOT . '/app/Views/register.php';
}
}<?php
/**
* test Controller
*/
class TestController {
public function index() {
$title = 'test';
// echo "Test funktioniert!";
require_once APP_ROOT . '/app/Views/test.php';
}
}
?>
<?php
$_SESSION['cart_items'] ;
//=[['product_id'=>13,'count'=>1],['product_id'=>14,'cout'=>2]];
class CartController{
public $products=[];
public function getCart_items(){
header('Content-Type: application/json');
$cart_itemes=$_SESSION['cart_items'] ?? [];
// echo json_encode($cart_itemes);
$model=new ProductModel();
foreach($cart_itemes as $key => $item){
$cart_itemes[$key]+=$model->getProductForcart($item['product_id']);
}
echo json_encode($cart_itemes);
// file_put_contents('TEST.txt', print_r($cart_itemes));
}
public function addToCart($product_id){
$cart_itemes=$_SESSION['cart_items'] ?? [];
if(isset($cart_itemes[$product_id])){
$cart_itemes[$product_id]++;
}else{
$cart_itemes[$product_id]=1;
}
$_SESSION['cart_items']=$cart_itemes;
}
public function update(){
$input = json_decode(file_get_contents('php://input'), true);
$product_id = $input['product_id'] ?? null;
$quantity = $input['quantity'] ?? null;
if ($product_id !== null && $quantity !== null) {
$cart_itemes=$_SESSION['cart_items'] ?? [];
$found = false;
foreach ($cart_itemes as $key => $item) {
if (isset($item['product_id']) && $item['product_id'] == $product_id) {
$found = true;
if ($quantity > 0) {
$cart_itemes[$key]['count'] = (int)$quantity;
} else {
unset($cart_itemes[$key]);
}
break;
}
}
// reindex numeric keys
$cart_itemes = array_values($cart_itemes);
$_SESSION['cart_items'] = $cart_itemes;
if ($found) {
echo json_encode(['status' => 'success', 'cart' => $cart_itemes]);
} else {
echo json_encode(['status' => 'error', 'message' => 'Product not in cart']);
}
} else {
echo json_encode(['status' => 'error', 'message' => 'Invalid input']);
}
}
}
<?php
require_once dirname(__DIR__) . '/../config/config.php';
class DbModel{
private $host = DB_HOST;
private $db_name = DB_NAME;
private $username = DB_USER;
private $password = DB_PASS;
public $conn;
public $sql;
public $dat=[];
public $fehler;
public function __construct(){
try {
$this->conn = new PDO(
"mysql:host={$this->host};dbname={$this->db_name};charset=utf8",
$this->username,
$this->password,
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
} catch (PDOException $e) {
die("Datenbankverbindung fehlgeschlagen: " . $e->getMessage());
}
}
//select funktion
public function select ($table, $spalten=["*"], $where = [], $fehler = "Fehler bei SELECT") {
// $where =[spalte => bedinung]
$dat=[];
$sql = "select ";
$spalten_last=end($spalten);
reset($spalten);
foreach($spalten as $e){
if ($e == $spalten_last) {
$sql .= " " . $e . " ";
}else{
$sql .= " " . $e . ",";
}}
$sql .= " from " . $table;
if (!empty($where)) {
$sql.=" where";
$lastkey=array_key_last($where);
foreach ($where as $key => $value) {
if ($lastkey!=$key){
$sql.= " ".$key ."= :$key and";
$dat[$key]=$value;
}else{
$sql.= " ".$key ."= :$key ";
$dat[$key]=$value;
}
}
}
// Klasseneigenschaften setzen und ausführen
$this->sql = $sql;
$this->dat = $dat;
$this->fehler = $fehler;
return $this->execute();
}
#select funktion Ende
#isert funktion Anfang
/**
* Insert in Tabelle
* @param string $table
* @param array $inhalt ['spalte' => 'wert']
* @param string $fehler
* @return mixed lastInsertId oder bool
*/
public function insert($table, $inhalt, $fehler = "fehler von insert"){
$this->fehler = $fehler;
$this->dat = [];
$this->sql= "insert into $table (";
foreach ($inhalt as $key => $value) {
$this->sql.="$key ,";
$this->dat[$key]=$value;
}
$this->sql =rtrim($this->sql,",");
$this->sql.=") Values (";
foreach($inhalt as $key=>$value){
$this->sql.= " :$key ,";
}
$this->sql =rtrim($this->sql,",");
$this->sql.=" )";
return $this->execute();
}
#insert funktion Ende
/**
* Update-Funktion
* @param string $table Tabelle
* @param array $inhalt ['spalte' => 'wert']
* @param array $where ['spalte' => 'wert']
* @param string $fehler Fehlertext
* @return int Anzahl betroffener Zeilen
*/
public function update($table, $inhalt, $where = [], $fehler = "Fehler bei UPDATE"){
$this->fehler = $fehler;
$this->dat = [];
$this->sql = "UPDATE $table SET ";
// Set-Teil
foreach ($inhalt as $key => $value) {
$this->sql .= "$key = :u_$key ,";
$this->dat["u_$key"] = $value;
}
$this->sql = rtrim($this->sql, ",");
// Where-Teil
if (!empty($where)) {
$this->sql .= " WHERE ";
$lastkey = array_key_last($where);
foreach ($where as $key => $value) {
if ($lastkey != $key) {
$this->sql .= "$key = :w_$key AND ";
} else {
$this->sql .= "$key = :w_$key ";
}
$this->dat["w_$key"] = $value;
}
}
return $this->execute();
}
/**
* Delete-Funktion
* @param string $table Tabelle
* @param array $where ['spalte' => 'wert']
* @param string $fehler Fehlertext
* @return int Anzahl betroffener Zeilen
*/
public function delete($table, $where = [], $fehler = "Fehler bei DELETE"){
$this->fehler = $fehler;
$this->dat = [];
$this->sql = "DELETE FROM $table";
if (!empty($where)) {
$this->sql .= " WHERE ";
$lastkey = array_key_last($where);
foreach ($where as $key => $value) {
if ($lastkey != $key) {
$this->sql .= "$key = :$key AND ";
} else {
$this->sql .= "$key = :$key ";
}
$this->dat[$key] = $value;
}
}
return $this->execute();
}
public function rawquery($sql, $dat = [], $fehler = "Fehler bei Query"){
$this->fehler = $fehler;
$this->dat = $dat;
$this->sql = $sql;
return $this->execute();
}
/**
* Führt die vorbereitete SQL-Anweisung aus und liefert je nach Typ sinnvolle Rückgabe zurück:
* - SELECT: Array von Arrays
* - INSERT: lastInsertId()
* - UPDATE/DELETE: Anzahl betroffener Zeilen (rowCount)
*/
private function execute()
{
try {
$stmt = $this->conn->prepare($this->sql);
$stmt->execute($this->dat);
$sqlTrim = ltrim($this->sql);
$verb = strtolower(strtok($sqlTrim, " "));
if ($verb === 'select') {
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
if ($verb === 'insert') {
return $this->conn->lastInsertId();
}
if (in_array($verb, ['update', 'delete'])) {
return $stmt->rowCount();
}
// Standardmäßig die Anzahl der betroffenen Zeilen zurückgeben
return $stmt->rowCount();
} catch (PDOException $e) {
die("$this->fehler: " . $e->getMessage());
}
}
}
<?php
class LoginModel {
private $db;
public function __construct() {
$this->db = new DbModel();
}
public function authenticate($email, $password) {
$users = $this->db->select('users', ['id',"company_id","email","password"], ['email' => $email]);
$user = $users[0] ?? null;
if ($user && password_verify($password, $user['password'])) {
return $user;
} else {
return false;
}
}
}<?php
class ProductModel extends DbModel{
public function __construct() {
parent::__construct();
}
public function addProduct($name,$sku, $price, $description, array $images ) {
$lastinsertid= $this->insert('products', [
'sku' => $sku,
'name' => $name,
'price' => $price,
'description' => $description,
]);
//bessern
foreach($images as $image){
$this->addProductImage($lastinsertid,$image['sort_order'],$image['image_url'],$image['is_main_image']);
}
}
public function addProductImage($productId,$sort_order, $imagePath,$isMainImage = false) {
$this->insert('product_images', [
'product_id' => $productId,
'image_url' => $imagePath,
'is_main_image' => $isMainImage ,
'sort_order' => $sort_order +1
]);
}
public function getProductById($id) {
$product_array= $this->select('products', ['*'], ['id' => $id]);
return $product_array;
}
public function getProductForcart($id) {
$product= $this->select('products', ['name','price','stock'], ['id' => $id]);
if(!empty($product)){
$product_images=$this->getProductImages($id,['image_url'],['is_main_image' => 1]);
$product['images']=$product_images ?? [];
return $product;
}
}
public function getProductImages($productId,$columns=['*'],$where=[]){
return $this->select('product_images', $columns, array_merge(['product_id' => $productId],$where));
}
}<?php
class registerModel {
private $db;
public function __construct() {
$this->db = new DbModel();
}
public function register($vorname, $nachname, $email, $adresse, $geburtsdatum, $password) {
// Überprüfen, ob die E-Mail bereits existiert
$existingUser = $this->db->select('users', ['id'], ['email' => $email]);
if (!empty($existingUser)) {
return false; // E-Mail bereits registriert
}
// Passwort hashen
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
// Benutzer in der Datenbank speichern
$this->db->insert('users', [
'vorname' => $vorname,
'nachname' => $nachname,
'email' => $email,
'adresse' => $adresse,
'geburtsdatum' => $geburtsdatum,
'password' => $hashedPassword
]);
return true; // Registrierung erfolgreich
}
}<?php
/**
* Router Class - Object-Oriented Routing
*/
class Router {
private $routes = [];
public function get($path, $handler) {
$this->addRoute('GET', $path, $handler);
}
public function post($path, $handler) {
$this->addRoute('POST', $path, $handler);
}
public function put($path, $handler) {
$this->addRoute('PUT', $path, $handler);
}
private function addRoute($method, $path, $handler) {
$this->routes[] = [
'method' => $method,
'path' => $path,
'handler' => $handler
];
}
public function dispatch() {
$requestMethod = $_SERVER['REQUEST_METHOD'];
if (!empty($_GET['url'])) {
$requestUri = trim($_GET['url'], '/');
} else {
$requestUri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$basePath = str_replace('/index.php', '', $_SERVER['SCRIPT_NAME']);
$requestUri = str_replace($basePath, '', $requestUri);
$requestUri = trim($requestUri, '/');
}
$urlSegments = explode('/', $requestUri);
foreach ($this->routes as $route) {
$routePath = trim($route['path'], '/');
$routeSegments = explode('/', $routePath);
if ($route['method'] === $requestMethod && $this->matchRoute($routeSegments, $urlSegments)) {
$this->callHandler($route['handler'], $urlSegments, $routeSegments);
return;
}
}
// Default route
$this->callHandler('HomeController@index');
}
private function matchRoute($routeSegments, $urlSegments) {
if (count($routeSegments) !== count($urlSegments)) {
return false;
}
foreach ($routeSegments as $i => $segment) {
if ($segment[0] === ':') continue; // Dynamischer Parameter
if ($segment !== $urlSegments[$i]) return false;
}
return true;
}
private function callHandler($handler, $urlSegments = [], $routeSegments = []) {
// Parameter speichern in $_GET['params']
$_GET['params'] = [];
foreach ($routeSegments as $i => $segment) {
if ($segment[0] === ':') {
$paramName = substr($segment, 1);
$_GET['params'][$paramName] = $urlSegments[$i];
}
}
list($controllerName, $methodName) = explode('@', $handler);
$controllerFile = APP_ROOT . '/app/Controllers/' . $controllerName . '.php';
if (file_exists($controllerFile)) {
require_once $controllerFile;
if (class_exists($controllerName)) {
$controller = new $controllerName();
if (method_exists($controller, $methodName)) {
$controller->$methodName();
} else {
echo "Method $methodName not found in $controllerName";
}
} else {
echo "Class $controllerName not found";
}
} else {
echo "Controller $controllerName not found";
}
}
}
?><!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Neues Produkt anlegen</title>
<style>
/* --- CSS STYLING --- */
:root {
--primary-color: #4A90E2;
--background: #f4f7f6;
--surface: #ffffff;
--text: #333333;
--border: #e0e0e0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: var(--background);
color: var(--text);
padding: 2rem;
margin: 0;
display: flex;
justify-content: center;
}
.container {
background: var(--surface);
padding: 2rem;
border-radius: 10px;
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
width: 100%;
max-width: 600px;
}
h2 {
margin-top: 0;
border-bottom: 2px solid var(--border);
padding-bottom: 10px;
}
.form-group {
margin-bottom: 1.5rem;
}
label {
display: block;
font-weight: bold;
margin-bottom: 0.5rem;
font-size: 0.9rem;
}
input[type="text"],
input[type="number"],
textarea {
width: 100%;
padding: 10px;
border: 1px solid var(--border);
border-radius: 5px;
box-sizing: border-box;
font-family: inherit;
}
textarea {
resize: vertical;
min-height: 100px;
}
.row {
display: flex;
gap: 1rem;
}
.row .form-group {
flex: 1;
}
.checkbox-group {
display: flex;
align-items: center;
gap: 10px;
cursor: pointer;
}
input[type="checkbox"] {
width: 18px;
height: 18px;
cursor: pointer;
}
/* --- NEU: Styling für Upload und Drag & Drop --- */
.file-upload-wrapper {
position: relative;
border: 2px dashed var(--primary-color);
border-radius: 8px;
padding: 20px;
text-align: center;
background: #f9fbfd;
transition: background 0.3s;
}
.file-upload-wrapper:hover {
background: #f1f5f9;
}
input[type="file"] {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0; /* Versteckt das hässliche Standard-Feld, aber hält es anklickbar */
cursor: pointer;
}
.upload-text {
color: var(--primary-color);
font-weight: bold;
}
#imagePreview {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 15px;
}
/* Styling für die einzelnen Bild-Kacheln */
.preview-item {
position: relative;
width: 90px;
height: 90px;
border-radius: 5px;
overflow: hidden;
border: 1px solid var(--border);
cursor: grab; /* Zeigt an, dass man es greifen kann */
background: #fff;
}
.preview-item:active {
cursor: grabbing;
}
.preview-item img {
width: 100%;
height: 100%;
object-fit: cover;
pointer-events: none; /* Wichtig für Drag & Drop, damit das Bild nicht stört */
}
/* Das rote X zum Löschen eines Bildes */
.remove-btn {
position: absolute;
top: 2px;
right: 2px;
background: rgba(255, 0, 0, 0.8);
color: white;
border: none;
border-radius: 50%;
width: 20px;
height: 20px;
font-size: 12px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.remove-btn:hover {
background: red;
}
/* Highlight-Effekt beim Drüberziehen */
.preview-item.drag-over {
border: 2px dashed var(--primary-color);
opacity: 0.5;
}
button[type="submit"] {
background-color: var(--primary-color);
color: white;
border: none;
padding: 12px 20px;
font-size: 1rem;
border-radius: 5px;
cursor: pointer;
width: 100%;
font-weight: bold;
transition: background 0.3s;
margin-top: 1rem;
}
button[type="submit"]:hover {
background-color: #357ABD;
}
#output {
margin-top: 2rem;
padding: 1rem;
background: #2d2d2d;
color: #4ae26a;
border-radius: 5px;
font-family: monospace;
display: none;
white-space: pre-wrap;
}
</style>
</head>
<body>
<div class="container">
<h2>Neues Produkt anlegen</h2>
<form id="productForm">
<div class="row">
<div class="form-group">
<label for="name">Produktname *</label>
<input type="text" id="name" name="name" required placeholder="z.B. Premium T-Shirt">
</div>
<!-- <div class="form-group">
<label for="sku">Artikelnummer (SKU) *</label>
<input type="text" id="sku" name="sku" required placeholder="z.B. TS-001-RED">
</div> -->
</div>
<div class="form-group">
<label for="description">Beschreibung</label>
<textarea id="description" name="description" placeholder="Beschreibe dein Produkt..."></textarea>
</div>
<div class="row">
<div class="form-group">
<label for="price">Preis (€) *</label>
<input type="number" id="price" name="price" step="0.01" min="0" required placeholder="19.99">
</div>
<div class="form-group">
<label for="stock">Lagerbestand *</label>
<input type="number" id="stock" name="stock" step="1" min="0" required placeholder="50">
</div>
</div>
<div class="form-group">
<label>Produktbilder (Zuerst Hauptbild, Drag & Drop zum Sortieren)</label>
<div class="file-upload-wrapper">
<span class="upload-text">Bilder hierher ziehen oder klicken zum Auswählen</span>
<input type="file" id="images" name="images" accept="image/png, image/jpeg, image/webp" multiple>
</div>
<div id="imagePreview"></div>
</div>
<div class="form-group">
<label class="checkbox-group">
<input type="checkbox" id="isActive" name="isActive" checked>
Produkt sofort im Shop aktivieren
</label>
</div>
<button type="submit">Produkt speichern</button>
</form>
<div id="output"></div>
</div>
<script>
/* --- JAVASCRIPT LOGIK --- */
const form = document.getElementById('productForm');
const imageInput = document.getElementById('images');
const previewContainer = document.getElementById('imagePreview');
const outputBox = document.getElementById('output');
// Unser eigener Speicher für die Bilder (da wir das input-Feld nicht sortieren können)
let selectedFiles = [];
let dragStartIndex; // Merkt sich, welches Bild gerade gezogen wird
// 1. Bilder auswählen und zum Array hinzufügen
imageInput.addEventListener('change', function() {
const files = Array.from(this.files);
files.forEach(file => {
if(file.type.startsWith('image/')) {
selectedFiles.push(file); // Ins eigene Array schieben
}
});
// Das Input-Feld wieder leeren, damit man das gleiche Bild nochmal anklicken könnte
this.value = '';
// Vorschau neu zeichnen
renderPreview();
});
// 2. Funktion zum Zeichnen der Vorschau-Bilder
function renderPreview() {
previewContainer.innerHTML = ''; // Alles leeren
selectedFiles.forEach((file, index) => {
// Den Container (die Kachel) für ein Bild bauen
const item = document.createElement('div');
item.classList.add('preview-item');
item.setAttribute('draggable', 'true'); // Wichtig für Drag & Drop
item.setAttribute('data-index', index);
// Das Bild erzeugen
const img = document.createElement('img');
img.src = URL.createObjectURL(file);
img.onload = () => URL.revokeObjectURL(img.src); // Speicherplatz freigeben
// Den Löschen-Button bauen
const removeBtn = document.createElement('button');
removeBtn.classList.add('remove-btn');
removeBtn.innerHTML = '✖';
removeBtn.type = 'button'; // Wichtig, sonst schickt der Button das Formular ab
removeBtn.onclick = () => {
selectedFiles.splice(index, 1); // Bild aus Array löschen
renderPreview(); // Neu zeichnen
};
// Drag & Drop Events anfügen
item.addEventListener('dragstart', dragStart);
item.addEventListener('dragover', dragOver);
item.addEventListener('drop', dragDrop);
item.addEventListener('dragenter', dragEnter);
item.addEventListener('dragleave', dragLeave);
item.appendChild(img);
item.appendChild(removeBtn);
previewContainer.appendChild(item);
});
}
// --- DRAG & DROP LOGIK ---
function dragStart(e) {
dragStartIndex = +this.getAttribute('data-index');
}
function dragOver(e) {
e.preventDefault(); // Zwingend notwendig, um das "Drop" Event zu erlauben
}
function dragEnter(e) {
this.classList.add('drag-over'); // Zeigt visuell, wo das Bild landen würde
}
function dragLeave(e) {
this.classList.remove('drag-over');
}
function dragDrop(e) {
this.classList.remove('drag-over');
const dragEndIndex = +this.getAttribute('data-index');
// Elemente im Array vertauschen (Das gezogene Bild an die neue Position setzen)
const itemToMove = selectedFiles.splice(dragStartIndex, 1)[0];
selectedFiles.splice(dragEndIndex, 0, itemToMove);
// Ansicht aktualisieren
renderPreview();
}
// 3. Formular absenden (Jetzt übernehmen wir die volle Kontrolle)
form.addEventListener('submit', function(event) {
// Wir MÜSSEN das Standard-Absenden blockieren, da wir unser eigenes `selectedFiles` Array haben
event.preventDefault();
// FormData sammelt alle Text-Inputs automatisch
const formData = new FormData(form);
// Da das Standard-Feld für Bilder leer ist (wir haben es oben geleert),
// fügen wir jetzt unsere mühsam sortierten Bilder manuell hinzu!
selectedFiles.forEach((file, index) => {
// Fügt die Dateien als Array "images[]" an das Backend an
formData.append('images[]', file);
});
// --- HIER KOMMT DIE ECHTE BACKEND ANBINDUNG HIN ---
fetch('<?php echo APP_URL; ?>addproduct', {
method: 'POST',
body: formData
}).then(response => {
// Erfolgreich gespeichert!
response.json().then(data => {
alert(data.status); // Zeigt die Erfolgsmeldung vom Backend
// Hier könntest du auch die Seite neu laden oder zum Produkt-Listing weiterleiten
});
});
// --- SIMULATION FÜR DICH ZUR ANSICHT ---
const resultData = {
name: formData.get('name'),
sku: formData.get('sku'),
price: formData.get('price'),
// Zeigt dir, dass die Dateien in der korrekten, neuen Reihenfolge vorliegen:
uploadedFiles: selectedFiles.map((f, i) => `Position ${i+1}: ${f.name}`)
};
// outputBox.style.display = 'block';
// outputBox.textContent = "Senden simuliert! Die sortierten Bilder werden jetzt so ans PHP-Backend übergeben:\n\n" + JSON.stringify(resultData, null, 4);
});
</script>
</body>
</html><nav class="navbar">
<!-- LOGO -->
<div class="logo">
WEB<span>SHOP</span>
</div>
<!-- MENÜ -->
<ul class="nav-links" id="menu">
<li><a href="#">Startseite</a></li>
<li><a href="#">Produkte</a></li>
<li><a href="#">Kollektionen</a></li>
<li><a href="#">Über uns</a></li>
<li><a href="#">Kontakt</a></li>
</ul>
<!-- RECHTS -->
<div class="right-side">
<!-- WARENKORB -->
<button class="cart-btn" id="openCart">
<div class="cart-count">2</div>
<!-- SVG -->
<svg
fill="none"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
viewBox="0 0 24 24">
<circle cx="9" cy="21" r="1"></circle>
<circle cx="20" cy="21" r="1"></circle>
<path d="M1 1h4l2.68 13.39
a2 2 0 0 0 2 1.61h9.72
a2 2 0 0 0 2-1.61L23 6H6"></path>
</svg>
</button>
<!-- HAMBURGER -->
<div class="hamburger" id="hamburger">
<span></span>
<span></span>
<span></span>
</div>
</div>
</nav>
<!-- OVERLAY -->
<div class="cart-overlay" id="cartOverlay"></div>
<!-- SIDEBAR -->
<aside class="cart-sidebar" id="cartSidebar">
<!-- HEADER -->
<div class="cart-header">
<h2>Warenkorb</h2>
<button class="close-cart" id="closeCart">
✕
</button>
</div>
<!-- PRODUKTE -->
<div class="cart-items" id="cart-Items">
<!-- ITEM -->
<div class="cart-item">
<img src="https://picsum.photos/100" alt="Produkt">
<div class="item-info">
<h3>Premium Hoodie</h3>
<p>79,99 €</p>
<div class="quantity">
<button>-</button>
<span>1</span>
<button>+</button>
</div>
</div>
</div>
<!-- ITEM -->
<div class="cart-item" >
<img src="https://picsum.photos/101" alt="Produkt">
<div class="item-info">
<h3>Sneaker Pro</h3>
<p>129,99 €</p>
<div class="quantity">
<button>-</button>
<span>2</span>
<button>+</button>
</div>
</div>
</div>
</div>
<!-- FOOTER -->
<div class="cart-footer">
<div class="cart-total">
<span>Gesamt</span>
<strong id="full_price">339,97 €</strong>
</div>
<button class="checkout-btn">
Zur Kasse
</button>
</div>
</aside>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo isset($title) ? $title : 'MVC Application'; ?></title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.container {
background: white;
padding: 50px;
border-radius: 10px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
text-align: center;
max-width: 600px;
}
h1 {
color: #333;
margin-bottom: 20px;
}
p {
color: #666;
line-height: 1.6;
}
</style>
</head>
<body>
<div class="container">
<h1>Willkommen zur MVC-Anwendung</h1>
<p>Ihre MVC-Struktur wurde erfolgreich aufgesetzt!</p>
<p style="margin-top: 30px; font-size: 14px; color: #999;">
Ordnerstruktur: app/ (Models, Views, Controllers) | config/ | public/
</p>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
<style>
body {
font-family: Arial, sans-serif;
background: #f0f4f8;
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
margin: 0;
}
.login-box {
width: 360px;
padding: 30px 40px;
background: #fff;
box-shadow: 0 8px 25px rgba(0,0,0,0.1);
border-radius: 10px;
}
.login-box h1 {
font-size: 24px;
margin-bottom: 20px;
text-align: center;
color: #333;
}
.input-group {
margin-bottom: 18px;
}
.input-group label {
display: block;
margin-bottom: 6px;
color: #555;
font-size: 14px;
}
.input-group input {
width: 100%;
padding: 10px;
border: 1px solid #ccd6dd;
border-radius: 6px;
font-size: 14px;
box-sizing: border-box;
}
.login-action {
margin-top: 20px;
text-align: center;
}
.login-action button {
width: 100%;
padding: 11px;
background: #4d84ff;
color: white;
border: none;
border-radius: 6px;
font-size: 15px;
cursor: pointer;
}
.login-action button:hover {
background: #3f6ee6;
}
</style>
</head>
<body>
<div class="login-box">
<h1>Login</h1>
<form method="post" action="./login">
<div class="input-group">
<label for="username">Benutzername</label>
<input type="email" id="email" name="email" required autofocus>
</div>
<div class="input-group">
<label for="password">Passwort</label>
<input type="password" id="password" name="password" required>
</div>
<div class="login-action">
<button type="submit">Anmelden</button>
</div>
<div><?php echo $login_Msg ?? "" ?> </div>
</form>
</div>
</body>
</html><!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo htmlspecialchars($name ?? 'Produkt'); ?> - Shop</title>
</style>
<link rel="stylesheet" href="<?= APP_URL ?>/styles/header.css">
</head>
<body>
<?php require_once APP_ROOT . '/app/Views/header.php'; ?>
<script src="<?= APP_URL ?>/scripts/header.js"></script>
</body>
</html><!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Registrierung</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.container {
background: white;
padding: 40px;
border-radius: 10px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
width: 100%;
max-width: 550px;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
}
h1 {
text-align: center;
color: #333;
margin-bottom: 30px;
font-size: 28px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
color: #555;
font-weight: bold;
}
input {
width: 100%;
padding: 12px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 14px;
transition: border-color 0.3s;
}
input:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 5px rgba(102, 126, 234, 0.1);
}
.btn-register {
width: 100%;
padding: 12px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 5px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
transition: transform 0.2s;
margin-top: 10px;
}
.btn-register:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
}
.login-link {
text-align: center;
margin-top: 20px;
color: #666;
}
.login-link a {
color: #667eea;
text-decoration: none;
font-weight: bold;
}
.login-link a:hover {
text-decoration: underline;
}
.error {
background-color: #fee;
color: #c33;
padding: 12px;
border-radius: 5px;
margin-bottom: 20px;
border-left: 4px solid #c33;
}
.success {
background-color: #efe;
color: #3c3;
padding: 12px;
border-radius: 5px;
margin-bottom: 20px;
border-left: 4px solid #3c3;
}
</style>
</head>
<body>
<div class="container">
<h1>Registrierung</h1>
<?php if (isset($error) && !empty($error)): ?>
<div class="error"><?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>
<?php if (isset($success) && !empty($success)): ?>
<div class="success"><?php echo htmlspecialchars($success); ?></div>
<?php endif; ?>
<form method="POST" action="<?php echo APP_URL; ?>register">
<div class="form-row">
<div class="form-group">
<label for="vorname">Vorname:</label>
<input
type="text"
id="vorname"
name="vorname"
required
placeholder="Max"
value="<?php echo isset($_POST['vorname']) ? htmlspecialchars($_POST['vorname']) : ''; ?>"
>
</div>
<div class="form-group">
<label for="nachname">Nachname:</label>
<input
type="text"
id="nachname"
name="nachname"
required
placeholder="Mustermann"
value="<?php echo isset($_POST['nachname']) ? htmlspecialchars($_POST['nachname']) : ''; ?>"
>
</div>
</div>
<div class="form-group">
<label for="email">E-Mail Adresse:</label>
<input
type="email"
id="email"
name="email"
required
placeholder="deine@email.de"
value="<?php echo isset($_POST['email']) ? htmlspecialchars($_POST['email']) : ''; ?>"
>
</div>
<div class="form-group">
<label for="adresse">Adresse:</label>
<input
type="text"
id="adresse"
name="adresse"
required
placeholder="Musterstraße 123, 12345 Musterstadt"
value="<?php echo isset($_POST['adresse']) ? htmlspecialchars($_POST['adresse']) : ''; ?>"
>
</div>
<div class="form-group">
<label for="geburtsdatum">Geburtsdatum:</label>
<input
type="date"
id="geburtsdatum"
name="geburtsdatum"
required
value="<?php echo isset($_POST['geburtsdatum']) ? htmlspecialchars($_POST['geburtsdatum']) : ''; ?>"
>
</div>
<div class="form-row">
<div class="form-group">
<label for="password">Passwort:</label>
<input
type="password"
id="password"
name="password"
required
placeholder="Mindestens 6 Zeichen"
minlength="6"
>
</div>
<div class="form-group">
<label for="password_confirm">Passwort wiederholen:</label>
<input
type="password"
id="password_confirm"
name="password_confirm"
required
placeholder="Passwort bestätigen"
minlength="6"
>
</div>
</div>
<button type="submit" class="btn-register">Registrieren</button>
</form>
<div class="login-link">
Bereits registriert? <a href="<?php echo APP_URL; ?>login">Hier anmelden</a>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo isset($title) ? $title : 'MVC Application'; ?></title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.container {
background: white;
padding: 50px;
border-radius: 10px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
text-align: center;
max-width: 600px;
}
h1 {
color: #333;
margin-bottom: 20px;
}
p {
color: #666;
line-height: 1.6;
}
</style>
</head>
<body>
<div class="container">
<h1>Willkommen zur MVC-Anwendung</h1>
<p>Ihre MVC-Struktur wurde erfolgreich aufgesetzt!</p>
<p style="margin-top: 30px; font-size: 14px; color: #999;">
Ordnerstruktur: app/ (Models, Views, Controllers) | config/ | public/
</p>
</div>
</body>
</html>
<?php
/**
* Autoload Configuration
*/
// Autoload Models
function autoloadModel($class) {
$modelFile = APP_ROOT . '/app/Models/' . $class . '.php';
if (file_exists($modelFile)) {
require_once $modelFile;
}
}
spl_autoload_register('autoloadModel');
// Autoload Controllers
function autoloadController($class) {
$controllerFile = APP_ROOT . '/app/Controllers/' . $class . '.php';
if (file_exists($controllerFile)) {
require_once $controllerFile;
}
}
spl_autoload_register('autoloadController');
?>
<?php
/**
* MVC Application - Main Entry Point
* Located in public folder (Document Root)
*/
define('APP_ROOT', dirname(__FILE__) . '/..');
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || $_SERVER['SERVER_PORT'] == 443 ? 'https://' : 'http://';
define('APP_URL', $scheme . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['SCRIPT_NAME']), '\\/') . '/');
// Start session
session_start();
// Autoload classes
require_once APP_ROOT . '/config/autoload.php';
// Include Router
require_once APP_ROOT . '/app/Router.php';
// Create Router instance
$router = new Router();
// Define routes
$router->get('/home', 'HomeController@index');
$router->get('/login', 'LoginController@index');
$router->post('/login', 'AuthController@login');
$router->get('/test', 'TestController@index');
$router->get('/logout', 'AuthController@logout');
$router->get('/register', 'RegisterController@index');
$router->post('/register', 'AuthController@register');
$router->get('/addproduct', 'AddProductController@index');
$router->post('/addproduct', 'AddProductController@store');
$router->get('/products/:id', 'ProductController@index');
$router->get('/cart', 'CartController@getCart_items');
$router->put('/cart', 'CartController@update');
// Dispatch the route
$router->dispatch();
?>
const baseUrl = window.location.origin +"/shop/public"; // Dynamisch die Basis-URL ermitteln
const hamburger = document.getElementById("hamburger");
const menu = document.getElementById("menu");
hamburger.addEventListener("click", () => {
menu.classList.toggle("active");
getCartItems();
});
// warenkorb
const openCart = document.getElementById("openCart");
const closeCart = document.getElementById("closeCart");
const cartSidebar = document.getElementById("cartSidebar");
const cartOverlay = document.getElementById("cartOverlay");
const fullPriceElement = document.getElementById("full_price");
let delayTimer;
/* ÖFFNEN */
openCart.addEventListener("click", () => {
cartSidebar.classList.add("active");
cartOverlay.classList.add("active");
});
/* SCHLIESSEN */
closeCart.addEventListener("click", () => {
cartSidebar.classList.remove("active");
cartOverlay.classList.remove("active");
});
/* OVERLAY */
cartOverlay.addEventListener("click", () => {
cartSidebar.classList.remove("active");
cartOverlay.classList.remove("active");
});
// cart inhalt
function getCartItems() {
fetch(baseUrl+'/cart')
.then(response => response.json())
.then(data => {
const cartItemsContainer = document.getElementById('cart-Items');
cartItemsContainer.innerHTML = '';
console.log(data);
data.forEach(item => {
const cartItem = document.createElement('div');
cartItem.classList.add('cart-item');
const product = item[0] || {};
const imageUrl = item.images && item.images[0] ? item.images[0].image_url : '';
const quantity = item.count ?? item.quantity ?? 0;
const id = item.id ?? item.product_id ?? '';
cartItem.innerHTML = `
<img src="${imageUrl.replace(/\\/g, '/')}" alt="${product.name || ''}">
<div class="cart-item-details">
<h4>${product.name || 'Unknown product'}</h4>
<p>Price: $${product.price || '0.00'}</p>
<div class="quantity">
<button onclick='removeQuantity()'>-</button>
<span>${quantity}</span>
<button onclick=addQuantity()>+</button>
<input type="hidden" value="${id}">
</div>
</div>
`;
cartItemsContainer.appendChild(cartItem);
});
console.log(data);
})
.catch(error => console.error('Error fetching cart items:', error));
}
window.onload = getCartItems;
function addQuantity() {
event.target.previousElementSibling.textContent = parseInt(event.target.previousElementSibling.textContent) + 1;
let id = event.target.nextElementSibling.value;
let quantity = parseInt(event.target.previousElementSibling.textContent);
delyupdate(() => updateCart(id, quantity));
}
function removeQuantity() {
const quantityElement = event.target.nextElementSibling;
const currentQuantity = parseInt(quantityElement.textContent);
if (currentQuantity > 0) {
quantityElement.textContent = currentQuantity - 1;
let id = event.target.parentElement.querySelector('input[type="hidden"]').value;
let quantity = parseInt(event.target.nextElementSibling.textContent);
delyupdate(() => updateCart(id, quantity));
}
}
function delyupdate(functionName) {
if (delayTimer) {
clearTimeout(delayTimer);
}
delayTimer= setTimeout(() => {
functionName();
}, 1000);
}
function updateCart(id, quantity) {
fetch(baseUrl+'/cart', {
method: 'put',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ product_id : id, quantity: quantity })
})
.then(response => response.json())
.then(data => {
console.log('Cart updated:', data); })
.catch(error => console.error('Error updating cart:', error));
}
cartSidebar.addEventListener('click', function(event) {
cartSidebar.querySelectorAll('.cart-item').forEach(item => {
const priceElement = item.querySelector('.cart-item-details p');
const priceText = priceElement.textContent.replace('Price: $', '').trim();
console.log(priceText);
// const priceMatch = priceText.match(/Price: \$(\d+(\.\d{2})?)/);
const price = priceText;
const quantityElement = item.querySelector('.quantity span');
const quantity = parseInt(quantityElement.textContent);
const totalPrice = (price * quantity).toFixed(2);
// priceElement.textContent = `Price: $${totalPrice}`;
fullPriceElement.textContent = `Total: $${totalPrice}`;
});
});
*{
margin:0;
padding:0;
box-sizing:border-box;
font-family:Inter, Arial, sans-serif;
}
body{
background:#f5f7fb;
min-height:100vh;
}
/* =========================
NAVBAR
========================= */
.navbar{
width:100%;
height:85px;
background:#ffffff;
display:flex;
align-items:center;
justify-content:space-between;
padding:0 50px;
border-bottom:1px solid #e8edf3;
position:sticky;
top:0;
z-index:999;
}
/* =========================
LOGO
========================= */
.logo{
font-size:28px;
font-weight:800;
color:#111827;
letter-spacing:-1px;
}
.logo span{
color:#2563eb;
}
/* =========================
MENÜ
========================= */
.nav-links{
display:flex;
list-style:none;
gap:40px;
}
.nav-links a{
text-decoration:none;
color:#374151;
font-size:16px;
font-weight:500;
position:relative;
transition:0.3s;
}
.nav-links a::after{
content:"";
position:absolute;
left:0;
bottom:-8px;
width:0%;
height:2px;
background:#2563eb;
transition:0.3s;
}
.nav-links a:hover{
color:#111827;
}
.nav-links a:hover::after{
width:100%;
}
/* =========================
RECHTE SEITE
========================= */
.right-side{
display:flex;
align-items:center;
gap:18px;
}
/* =========================
WARENKORB BUTTON
========================= */
.cart-btn{
position:relative;
width:56px;
height:56px;
border:none;
border-radius:18px;
background:#111827;
display:flex;
align-items:center;
justify-content:center;
cursor:pointer;
transition:0.3s;
box-shadow:
0 10px 25px rgba(17,24,39,0.15);
}
.cart-btn:hover{
transform:translateY(-2px);
background:#2563eb;
}
.cart-btn svg{
width:24px;
height:24px;
stroke:white;
}
/* BADGE */
.cart-count{
position:absolute;
top:-5px;
right:-5px;
width:24px;
height:24px;
border-radius:50%;
background:#2563eb;
color:white;
font-size:12px;
font-weight:700;
display:flex;
align-items:center;
justify-content:center;
border:3px solid white;
}
/* =========================
HAMBURGER
========================= */
.hamburger{
width:48px;
height:48px;
border-radius:14px;
background:#f3f4f6;
display:none;
flex-direction:column;
justify-content:center;
align-items:center;
gap:5px;
cursor:pointer;
transition:0.3s;
}
.hamburger:hover{
background:#e5e7eb;
}
.hamburger span{
width:22px;
height:2px;
background:#111827;
border-radius:10px;
transition:0.3s;
}
/* =========================
MOBILE
========================= */
@media(max-width:950px){
.navbar{
padding:0 20px;
}
.hamburger{
display:flex;
}
.nav-links{
position:absolute;
top:85px;
left:0;
width:100%;
background:white;
flex-direction:column;
align-items:center;
gap:30px;
padding:40px 0;
border-bottom:1px solid #e5e7eb;
display:none;
}
.nav-links.active{
display:flex;
}
}
/* warenkorb */
*{
margin:0;
padding:0;
box-sizing:border-box;
font-family:Inter, Arial, sans-serif;
}
body{
background:#f4f7fb;
min-height:100vh;
}
/* =========================
BUTTON
========================= */
.cart-button{
position:fixed;
top:30px;
right:30px;
width:64px;
height:64px;
border:none;
border-radius:20px;
background:#111827;
color:white;
display:flex;
align-items:center;
justify-content:center;
cursor:pointer;
box-shadow:
0 10px 30px rgba(0,0,0,0.15);
transition:0.3s;
}
.cart-button:hover{
transform:translateY(-3px);
background:#2563eb;
}
.cart-button svg{
width:28px;
height:28px;
}
/* BADGE */
.cart-count{
position:absolute;
top:-5px;
right:-5px;
width:24px;
height:24px;
border-radius:50%;
background:#2563eb;
color:white;
display:flex;
align-items:center;
justify-content:center;
font-size:12px;
font-weight:700;
border:3px solid white;
}
/* =========================
OVERLAY
========================= */
.cart-overlay{
position:fixed;
inset:0;
background:rgba(0,0,0,0.45);
opacity:0;
visibility:hidden;
transition:0.3s;
z-index:998;
}
.cart-overlay.active{
opacity:1;
visibility:visible;
}
/* =========================
SIDEBAR
========================= */
.cart-sidebar{
position:fixed;
top:0;
right:-450px;
width:420px;
max-width:100%;
height:100vh;
background:white;
z-index:999;
display:flex;
flex-direction:column;
transition:0.35s ease;
box-shadow:
-10px 0 40px rgba(0,0,0,0.12);
}
.cart-sidebar.active{
right:0;
}
/* =========================
HEADER
========================= */
.cart-header{
padding:25px;
display:flex;
justify-content:space-between;
align-items:center;
border-bottom:1px solid #e5e7eb;
}
.cart-header h2{
font-size:24px;
color:#111827;
}
.close-cart{
width:42px;
height:42px;
border:none;
border-radius:12px;
background:#f3f4f6;
cursor:pointer;
font-size:18px;
transition:0.3s;
}
.close-cart:hover{
background:#e5e7eb;
}
/* =========================
ITEMS
========================= */
.cart-items{
flex:1;
overflow-y:auto;
padding:25px;
}
.cart-item{
display:flex;
gap:18px;
margin-bottom:25px;
}
.cart-item img{
width:95px;
height:95px;
object-fit:cover;
border-radius:16px;
}
.item-info{
flex:1;
}
.item-info h3{
font-size:18px;
margin-bottom:8px;
color:#111827;
}
.item-info p{
color:#2563eb;
font-weight:700;
margin-bottom:15px;
}
/* =========================
QUANTITY
========================= */
.quantity{
display:flex;
align-items:center;
gap:12px;
}
.quantity button{
width:34px;
height:34px;
border:none;
border-radius:10px;
background:#f3f4f6;
cursor:pointer;
font-size:18px;
transition:0.3s;
}
.quantity button:hover{
background:#e5e7eb;
}
/* =========================
FOOTER
========================= */
.cart-footer{
padding:25px;
border-top:1px solid #e5e7eb;
}
.cart-total{
display:flex;
justify-content:space-between;
margin-bottom:20px;
font-size:18px;
}
.cart-total strong{
color:#111827;
}
/* CHECKOUT */
.checkout-btn{
width:100%;
height:58px;
border:none;
border-radius:16px;
background:#111827;
color:white;
font-size:17px;
font-weight:600;
cursor:pointer;
transition:0.3s;
}
.checkout-btn:hover{
background:#2563eb;
}