Make 'Product Add' page

This commit is contained in:
Augusto Gunsch 2022-07-28 14:16:55 +02:00
parent 7d2ae0b2d2
commit 16b4d686e3
No known key found for this signature in database
GPG Key ID: F7EEFE29825C72DC
10 changed files with 303 additions and 89 deletions

View File

@ -5,12 +5,14 @@ use ProductList\Http\Request;
use ProductList\Http\RequestHandler;
use ProductList\Http\Route;
$request = new Request($_SERVER);
$request = new Request($_SERVER, $_GET, $_POST);
$handler = new RequestHandler($request);
$handler->registerRoutes([
new Route('GET', 'products', ['ProductList\View\Product', 'list']),
new Route('DELETE', 'products', ['ProductList\View\Product', 'delete']),
new Route('GET', 'test', ['ProductList\View\Product', 'test']),
new Route('GET', 'product', ['ProductList\View\Product', 'get']),
new Route('DELETE', 'product', ['ProductList\View\Product', 'delete']),
new Route('POST', 'product', ['ProductList\View\Product', 'post']),
new Route('GET', 'add-product', function() { readfile('static/add-product.html'); }),
new Route('GET', '', function() { readfile('static/index.html'); }),
]);

View File

@ -5,7 +5,8 @@ class Request
{
private $method;
private $uri;
private $queryString;
private $queryParams;
private $formParams;
public function getMethod()
{
@ -17,19 +18,25 @@ class Request
return $this->uri;
}
public function getQueryString()
public function getQueryParams()
{
return $this->queryString;
return $this->queryParams;
}
public function __construct(array $params)
public function getFormParams()
{
$uri_base = trim($params['REQUEST_URI'], '?'.$params['QUERY_STRING']);
return $this->formParams;
}
public function __construct(array $params, array $queryParams, array $formParams)
{
$uri_base = strtok($params['REQUEST_URI'], '?');
$uri_base = trim(urldecode($uri_base), '/');
$this->uri = explode('/', $uri_base);
$this->method = $params['REQUEST_METHOD'];
parse_str($params['QUERY_STRING'], $this->queryString);
$this->queryParams = $queryParams;
$this->formParams = $formParams;
}
}

View File

@ -20,7 +20,12 @@ class RequestHandler
{
foreach ($this->routes as $route) {
if ($route->matches($this->request)) {
$route->execute($this->request);
try {
$route->execute($this->request);
} catch (\Exception $e) {
http_response_code(500);
echo $e->getMessage();
}
return;
}
}

View File

@ -3,21 +3,25 @@ namespace ProductList\View;
use ProductList\Http\Request;
use ProductList\Model\Product as ProductModel;
use ProductList\Model\DVD;
use ProductList\Model\Furniture;
use ProductList\Model\Book;
use ProductList\Exception\NotFoundException;
class Product
class Product extends View
{
public static function list(Request $request)
public static function get(Request $request)
{
header('Content-Type: application/json');
echo json_encode(ProductModel::selectAll());
}
public static function delete(Request $request)
{
$queryString = $request->getQueryString();
$queryParams = $request->getQueryParams();
if (array_key_exists('id', $queryString)) {
$ids = explode(',', $queryString['id']);
if (array_key_exists('id', $queryParams)) {
$ids = explode(',', $queryParams['id']);
$ids = array_map('intval', $ids);
foreach($ids as $id) {
@ -44,7 +48,70 @@ class Product
}
}
public static function add(Request $request)
public static function post(Request $request)
{
$params= $request->getFormParams();
$expected = [
'sku',
'name',
'price',
'productType',
'weight',
'size',
'height',
'width',
'length'
];
if (self::expectArgs($expected, $params)) {
$product = null;
$type = $params['productType'];
switch($type) {
case 'dvd':
$product = new DVD(
$params['sku'],
$params['name'],
$params['price'],
$params['size'],
);
break;
case 'furniture':
$product = new Furniture(
$params['sku'],
$params['name'],
$params['price'],
$params['height'],
$params['width'],
$params['length'],
);
break;
case 'book':
$product = new Book(
$params['sku'],
$params['name'],
$params['price'],
$params['weight'],
);
break;
default:
http_response_code(400);
echo "Invalid 'productType' value '$type'";
return;
}
//try {
$product->insert();
//} catch (\Exception $e) {
//}
}
}
public static function test(Request $request)
{
$params= $request->getQueryParams();
if (self::expectArgs(['testarg'], $params)) {
echo var_dump($params);
}
}
}

22
src/View/View.php Normal file
View File

@ -0,0 +1,22 @@
<?php
namespace ProductList\View;
abstract class View
{
protected static function expectArgs(array $args, array $provided) {
$keys = array_keys($provided);
$missing = array_diff($args, $keys);
if (count($missing) > 0) {
http_response_code(400);
$missing = join("', '", $missing);
echo "Missing parameters '$missing'";
return false;
}
return true;
}
}

View File

@ -1,16 +1,83 @@
<html>
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="static/index.css"/>
<title>Product Add</title>
</head>
<body>
<div id="header">
<h1 id="title">Product Add</h1>
<div id="buttons">
<a href="/"><button>Save</button></a>
<a href="/"><button>Cancel</button></a>
</div>
</div>
</body>
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="static/stylesheet.css"/>
<title>Product Add</title>
</head>
<body>
<div id="header">
<h1 id="title">Product Add</h1>
<div id="buttons">
<div class="header-button"><button type="submit" form="product_form" id="save">Save</button></div>
<div class="header-button"><a href="/"><button>Cancel</button></a></div>
</div>
</div>
<div id="main">
<form id="product_form">
<div id="basic-info" class="form-section">
<table>
<tr>
<td><label for="sku">SKU</label></td>
<td><input type="text" id="sku" name="sku" required></td>
</tr>
<tr>
<td><label for="name">Name</label></td>
<td><input type="text" id="name" name="name" required></td>
</tr>
<tr>
<td><label for="price">Price ($)</label></td>
<td><input type="number" id="price" name="price" required></td>
</tr>
</table>
</div>
<div id="type-switcher" class="form-section">
<label for="productType">Type Switcher</label>
<select name="productType" id="productType">
<option value="dvd">DVD</option>
<option value="furniture">Furniture</option>
<option value="book">Book</option>
</select>
</div>
<div id="attribute" class="form-section">
<div id="dvd" class="hidden">
<table>
<tr>
<td><label for="size">Size (MB)</label></td>
<td><input type="text" id="size" name="size"></td>
</tr>
</table>
Please, provide size
</div>
<div id="furniture" class="hidden">
<table>
<tr>
<td><label for="height">Height (CM)</label></td>
<td><input type="text" id="height" name="height"></td>
</tr>
<tr>
<td><label for="width">Width (CM)</label></td>
<td><input type="text" id="width" name="width"></td>
</tr>
<tr>
<td><label for="length">Length (CM)</label></td>
<td><input type="text" id="length" name="length"></td>
</tr>
</table>
Please, provide dimensions
</div>
<div id="book" class="hidden">
<table>
<tr>
<td><label for="weight">Weight (KG)</label></td>
<td><input type="text" id="weight" name="weight"></td>
</tr>
</table>
Please, provide weight
</div>
</div>
</form>
</div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="static/add-product.js"></script>
</html>

29
static/add-product.js Normal file
View File

@ -0,0 +1,29 @@
let currentTypeForm = document.getElementById($('#productType').val());
currentTypeForm.querySelectorAll('input').forEach(input => input.required = true);
currentTypeForm.classList.remove('hidden');
$('#productType').on('change', e => {
const newTypeForm = document.getElementById(e.target.value);
currentTypeForm.classList.add('hidden');
newTypeForm.classList.remove('hidden');
currentTypeForm.querySelectorAll('input').forEach(input => input.required = false);
newTypeForm.querySelectorAll('input').forEach(input => input.required = true);
currentTypeForm = newTypeForm;
});
$('#product_form').on('submit', e=> {
e.preventDefault();
$.ajax(
'product',
{
method: 'POST',
data: $('#product_form').serializeArray(),
success: _ => window.location.href = '/',
error: jqXHR => alert(jqXHR.responseText),
}
);
});

View File

@ -1,20 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="static/index.css"/>
<title>Product List</title>
</head>
<body>
<div id="header">
<h1 id="title">Product List</h1>
<div id="buttons">
<a href="add-product"><button>ADD</button></a>
<button id="delete-product-btn">MASS DELETE</button>
</div>
</div>
<div id="products">
</div>
</body>
<script src="static/index.js"></script>
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="static/stylesheet.css"/>
<title>Product List</title>
</head>
<body>
<div id="header">
<h1 id="title">Product List</h1>
<div id="buttons">
<div class="header-button"><a href="add-product"><button>ADD</button></a></div>
<div class="header-button"><button id="delete-product-btn">MASS DELETE</button></div>
</div>
</div>
<div id="products">
</div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="static/index.js"></script>
</html>

View File

@ -1,45 +1,40 @@
const productsList = document.getElementById('products');
const loadItems = () => {
const xhttp = new XMLHttpRequest();
$.ajax(
'product',
{
success: data => {
const boxes = data.map(product =>
`<div class="product">
<input type="checkbox" class="delete-checkbox" value="${product.id}">
<p>
${product.sku}<br>
${product.name}<br>
${product.price} $<br>
${product.attribute}
</p>
</div>`
);
xhttp.onload = function() {
const products = JSON.parse(this.responseText);
const boxes = products.map(product =>
`<div class="product">
<input type="checkbox" class="delete-checkbox" value="${product.id}">
<p>
${product.sku}<br>
${product.name}<br>
${product.price} $<br>
${product.attribute}
</p>
</div>`
)
productsList.innerHTML = boxes.join('\n');
}
xhttp.open('GET', 'products', true);
xhttp.send();
$('#products').html(boxes.join('\n'));
},
error: jqXHR => alert(jqXHR.responseText),
}
)
}
loadItems();
const deleteSelected = () => {
const checkboxes = document.querySelectorAll('input[class="delete-checkbox"]:checked');
let values = [];
checkboxes.forEach(checkbox => values.push(checkbox.value));
$('#delete-product-btn').on('click', () => {
let values = [];
const checkboxes = document.querySelectorAll('input[class="delete-checkbox"]:checked');
checkboxes.forEach(checkbox => values.push(checkbox.value));
const xhttp = new XMLHttpRequest();
xhttp.onload = function() {
loadItems();
}
xhttp.open('DELETE', `products?id=${values.join(',')}`, true);
xhttp.send();
}
const deleteButton = document.getElementById('delete-product-btn');
deleteButton.addEventListener('click', deleteSelected);
$.ajax(
`product?id=${values.join(',')}`,
{
method: 'DELETE',
success: loadItems,
error: jqXHR => alert(jqXHR.responseText),
}
)
});

View File

@ -14,16 +14,15 @@ body {
margin: 0 1em;
}
#buttons a {
.header-button {
align-self: center;
margin: 0 2em;
}
#buttons button {
font-family: cursive;
padding: .5em 1em;
font-size: 1rem;
margin: 0 2em;
align-self: center;
background-color: white;
border: 2px solid black;
box-shadow: 2px 2px black;
@ -56,3 +55,23 @@ body {
position: absolute;
top: 0px;
}
.hidden {
display: none;
}
#main {
margin: 2em;
}
.form-section {
margin: 2em;
}
td:nth-child(2) {
padding-left: 2em;
}
#productType {
margin-left: 2em;
}