Added ability to edit article categories, added compatibility conversion between stock json versions

This commit is contained in:
keplyx 2019-09-12 00:08:46 +02:00
parent 4be6a2b86a
commit 4e1ec778c1
12 changed files with 556 additions and 137 deletions

87
admin/categories.php Normal file
View file

@ -0,0 +1,87 @@
<?php
$relativePath = "../";
$file = '../data/stock-v2.json';
$fp = fopen($file, 'r');
$result = fread($fp, filesize($file));
fclose($fp);
ob_start();
?>
<tr>
<th class="id-column">Id</th>
<th class="name-column">Nom</th>
<th class="icon-column">
<a href="https://materialdesignicons.com/" target="_blank">
Icone
<i class="fas fa-external-link-alt"></i>
</a>
</th>
<th class="actions-column">Actions</th>
</tr>
<?php
$tableHeader = ob_get_clean();
ob_start();
?>
<div class="admin-container">
<a href="index.php">
<button class="btn btn-primary btn-large">Retour</button>
</a>
<h1 class="text-center">Gestion des Catégories</h1>
<h2 class="text-center">Ajouter une catégorie</h2>
<table>
<tbody>
<?= $tableHeader ?>
<tr>
<td>
<input type="text" class="form-control" id="idInput" placeholder="Id">
</td>
<td>
<input type="text" class="form-control" id="nameInput" placeholder="Nom">
</td>
<td>
<input type="text" class="form-control" id="iconInput" placeholder="Icone">
</td>
<td>
<button type="submit" class="btn btn-success" onclick="addNewItem()"><i class="fas fa-check"></i>
</button>
</td>
</tr>
</tbody>
</table>
<h2 class="text-center">Liste des catégories</h2>
<table id="categoriesTable">
<tbody>
<?= $tableHeader ?>
</tbody>
</table>
<div style="display: flex; margin-top: 100px; margin-bottom: 100px">
<button class="btn btn-success btn-lg" style="margin: auto"
onclick="saveDataset()">
Sauvegarder les catégories
</button>
</div>
<script type="text/javascript">
let json_dump = <?php echo $result; ?>;
</script>
</>
<link type="text/css" rel="stylesheet" href="https://cdn.materialdesignicons.com/4.4.95/css/materialdesignicons.min.css"
media="screen,projection"/>
<link type="text/css" rel="stylesheet" href="<?= $relativePath ?>assets/css/admin.css" media="screen,projection"/>
<link type="text/css" rel="stylesheet" href="<?= $relativePath ?>assets/css/categories.css" media="screen,projection"/>
<?php
$pageContent = ob_get_clean();
$pageTitle = "Gestion des catégories";
$pageScripts = "<script type=\"text/javascript\" src=\"" . $relativePath . "assets/js/saveManager.js\"></script><script type=\"text/javascript\" src=\"" . $relativePath . "assets/js/categories.js\"></script>";
include($relativePath . "includes/template.php");
?>

57
admin/convert_json.php Normal file
View file

@ -0,0 +1,57 @@
<?php
echo 'Ouverture du fichier V1...
';
$file = '../data/stock.json';
$fp = fopen($file, 'r');
$result = json_decode(fread($fp, filesize($file)));
fclose($fp);
function getConvertedTypes($oldTypes) {
$newTypes = [];
$counter = 1;
foreach ($oldTypes as $type) {
array_push($newTypes, (object) ["id" => strval($counter), "name" => $type, "icon" => "file"]);
$counter += 1;
}
return $newTypes;
}
function getConvertedArticles($articles, $newTypes) {
foreach ($articles as $article) {
$article->description = "Pas de description";
foreach ($article->type as $key=>$value) {
$article->type[$key] = getTypeIdFromName($value, $newTypes);
}
}
return $articles;
}
function getTypeIdFromName($name, $types) {
foreach ($types as $type) {
if ($type->name == $name)
return $type->id;
}
}
if ($result) {
echo 'Conversion en cours...
';
$newTypes = getConvertedTypes($result->types);
$newArticles = getConvertedArticles($result->articles, $newTypes);
$v2File = json_encode(["types"=>$newTypes, "articles"=>$newArticles]);
echo 'Conversion réussie...
';
echo 'Sauvegarde dans fichier V2...
';
$fp = fopen('../data/stock-v2.json', 'w');
$result = fwrite($fp, $v2File);
fclose($fp);
echo 'Sauvegarde réussie...
';
} else {
echo 'Echec!
'; // Allows to create a newline
var_dump($_POST);
}

View file

@ -1,87 +1,20 @@
<?php
$relativePath = "../";
$file='../data/stock.json';
$fp = fopen($file, 'r');
$result = fread($fp,filesize($file));
fclose($fp);
ob_start();
?>
<tr>
<th class="name-column">Nom</th>
<th class="quantity-column">Quantité</th>
<th class="price-column">Prix</th>
<th class="code-column">Code Barre</th>
<th class="type-column">Type</th>
<th class="image-column">Image</th>
<th class="actions-column">Actions</th>
</tr>
<?php
$tableHeader = ob_get_clean();
ob_start();
?>
<div class="stock-container">
<h1 class="text-center">Gestion des Stocks</h1>
<h2 class="text-center">Ajouter un article</h2>
<table>
<tbody>
<?= $tableHeader ?>
<tr>
<td>
<input type="text" class="form-control" id="nameInput" placeholder="Nom">
</td>
<td>
<input type="number" class="form-control" id="quantityInput" placeholder="Quantité">
</td>
<td>
<input type="text" class="form-control" id="priceInput" placeholder="Prix">
</td>
<td>
<input type="text" class="form-control" id="codeInput" placeholder="Code Barre">
</td>
<td id="typeCheckboxesCell">
</td>
<td>
<input type="text" class="form-control" id="imageInput" placeholder="Lien Image">
</td>
<td>
<button type="submit" class="btn btn-success" onclick="addNewItem()"><i class="fas fa-check"></i>
</button>
</td>
</tr>
</tbody>
</table>
<h2 class="text-center">Liste d'articles</h2>
<table id="stockTable">
<tbody>
<?= $tableHeader ?>
</tbody>
</table>
<div style="display: flex; margin-top: 100px">
<button class="btn btn-success btn-lg" style="margin: auto"
onclick="saveDataset()">
Sauvegarder le stock
</button>
</div>
<script type="text/javascript">
let json_dump = <?php echo $result; ?>;
</script>
</>
<link type="text/css" rel="stylesheet" href="<?= $relativePath ?>assets/css/stock.css" media="screen,projection"/>
<div class="admin-container">
<a href="stock.php">
<button class="btn btn-primary btn-large">Gestion des stocks</button>
</a>
<a href="categories.php">
<button class="btn btn-primary btn-large">Gestion des catégories</button>
</a>
</div>
<link type="text/css" rel="stylesheet" href="<?= $relativePath ?>assets/css/admin.css" media="screen,projection"/>
<?php
$pageContent = ob_get_clean();
$pageTitle = "Gestion";
$pageScripts = "<script type=\"text/javascript\" src=\"" . $relativePath . "assets/js/stock.js\"></script>";
$pageTitle = "Admin";
include($relativePath . "includes/template.php");
?>

113
admin/stock.php Normal file
View file

@ -0,0 +1,113 @@
<?php
$relativePath = "../";
$file = '../data/stock-v2.json';
$fp = fopen($file, 'r');
$result = fread($fp, filesize($file));
fclose($fp);
ob_start();
?>
<tr>
<th class="name-column">Nom</th>
<th class="description-column">Description</th>
<th class="quantity-column">Quantité</th>
<th class="price-column">Prix</th>
<th class="code-column">Code Barre</th>
<th class="type-column">Type</th>
<th class="image-column">Image</th>
<th class="actions-column">Actions</th>
</tr>
<?php
$tableHeader = ob_get_clean();
ob_start();
?>
<div class="admin-container">
<a href="index.php">
<button class="btn btn-primary btn-large">Retour</button>
</a>
<h1 class="text-center">Gestion des Stocks</h1>
<?php if ($result): ?>
<h2 class="text-center">Ajouter un article</h2>
<table>
<tbody>
<?= $tableHeader ?>
<tr>
<td>
<input type="text" class="form-control" id="nameInput" placeholder="Nom">
</td>
<td>
<input type="text" class="form-control" id="descriptionInput" placeholder="Description">
</td>
<td>
<input type="number" class="form-control" id="quantityInput" placeholder="Quantité">
</td>
<td>
<input type="text" class="form-control" id="priceInput" placeholder="Prix">
</td>
<td>
<input type="text" class="form-control" id="codeInput" placeholder="Code Barre">
</td>
<td id="typeCheckboxesCell">
</td>
<td>
<input type="text" class="form-control" id="imageInput" placeholder="Lien Image">
</td>
<td>
<button type="submit" class="btn btn-success" onclick="addNewItem()"><i class="fas fa-check"></i>
</button>
</td>
</tr>
</tbody>
</table>
<h2 class="text-center">Liste d'articles</h2>
<table id="stockTable">
<tbody>
<?= $tableHeader ?>
</tbody>
</table>
<div style="display: flex; margin-top: 100px; margin-bottom: 100px">
<button class="btn btn-success btn-lg" style="margin: auto"
onclick="saveDataset()">
Sauvegarder le stock
</button>
</div>
<?php else: ?>
<h2 class="text-center">Fichier de stock V2 non trouvé</h2>
<div style="display: flex; margin-top: 50px; margin-bottom: 50px">
<button class="btn btn-success btn-lg" style="margin: auto"
onclick="SaveManager.convertToV2()">
Convertir le stock existant en V2
</button>
</div>
<?php endif; ?>
<script type="text/javascript">
let json_dump =
<?php
if ($result)
echo $result;
else
echo 'undefined'
?>;
</script>
</>
<link type="text/css" rel="stylesheet" href="https://cdn.materialdesignicons.com/4.4.95/css/materialdesignicons.min.css"
media="screen,projection"/>
<link type="text/css" rel="stylesheet" href="<?= $relativePath ?>assets/css/admin.css" media="screen,projection"/>
<link type="text/css" rel="stylesheet" href="<?= $relativePath ?>assets/css/stock.css" media="screen,projection"/>
<?php
$pageContent = ob_get_clean();
$pageTitle = "Gestion du stock";
$pageScripts = "<script type=\"text/javascript\" src=\"" . $relativePath . "assets/js/saveManager.js\"></script><script type=\"text/javascript\" src=\"" . $relativePath . "assets/js/stock.js\"></script>";
include($relativePath . "includes/template.php");
?>

View file

@ -5,8 +5,12 @@ $_POST = json_decode($rest_json, true);
//var_dump($_POST);
$fp = fopen('../data/stock-v2.json', 'w');
$result = fwrite($fp, json_encode($_POST["v2"]));
fclose($fp);
$fp = fopen('../data/stock.json', 'w');
$result = fwrite($fp, json_encode($_POST));
$result = fwrite($fp, json_encode($_POST["v1"]));
fclose($fp);
if ($result) {

View file

@ -11,7 +11,7 @@ if ($_POST["password"] != $password)
die("Wrong Password");
// open the file and get the stock
$file = '../data/stock.json';
$file = '../data/stock-v2.json';
$fp = fopen($file, 'r');
$result = json_decode(fread($fp, filesize($file)));
fclose($fp);

9
assets/css/admin.css Normal file
View file

@ -0,0 +1,9 @@
.admin-container {
width: 90%;
margin: 50px auto auto auto;
}
table {
width: 100%;
margin-bottom: 20px;
}

19
assets/css/categories.css Normal file
View file

@ -0,0 +1,19 @@
#categoriesTable tr {
border-bottom: 1px solid #dedede;
}
.mdi {
font-size: 2rem;
}
.actions-column {
width: 100px;
}
.id-column {
width: 200px;
}
.icon-column {
width: 200px;
}

View file

@ -1,6 +1,6 @@
table {
width: 100%;
margin-bottom: 20px;
.name-column {
width: 200px;
}
.quantity-column, .price-column {
@ -24,12 +24,10 @@ table {
width: 100px;
}
.stock-container {
width: 90%;
margin: 50px auto auto auto;
}
#stockTable tr {
border-bottom: 1px solid #dedede;
}
.row-img {
height: 50px;
}

135
assets/js/categories.js Normal file
View file

@ -0,0 +1,135 @@
let currentDataset = [];
let currentTypes = [];
let originalEditedItem = {};
function initValuesFromPHPDump() {
currentDataset = json_dump.articles; // json_dump is set using PHP
currentTypes = json_dump.types;
console.log(currentDataset);
console.log(currentTypes);
generateTable(currentTypes);
}
$(document).ready(function () {
initValuesFromPHPDump();
setEditFieldValues('', '', '');
});
function generateTable(dataset) {
for (let i = 0; i < dataset.length; i++) {
generateLine(dataset[i]);
}
}
function generateLine(item) {
$.selector_cache('#categoriesTable').append(
'<tr id="row_' + item.id + '">' +
'<td>' + item.id + '</td>' +
'<td>' + item.name + '</td>' +
'<td><span class="mdi mdi-' + item.icon + '"></span></td>' +
'<td>' +
'<button class="btn btn-danger" id="delete_' + item.id + '" onclick="deleteItem(this)"><i class="fas fa-times"></i></button>' +
'<button class="btn btn-primary" id="edit_' + item.id + '" onclick="editItem(this)"><i class="fas fa-edit"></i></button>' +
'</td>' +
'</tr>'
);
}
function addNewItem() {
if (isItemInputFilled()) {
let item = {
id: $.selector_cache('#idInput').val(),
name: $.selector_cache('#nameInput').val(),
icon: $.selector_cache('#iconInput').val(),
};
if (isIdAvailable(item.id)) {
updateExistingItemsType(originalEditedItem.id, item.id);
setEditFieldValues('', '', '');
currentTypes.push(item);
generateLine(item);
}
}
}
function editItem(elem) {
if (isItemInputEmpty()) {
let id = elem.id.replace('edit_', '');
let item = getTypeOfId(id);
originalEditedItem = item;
setEditFieldValues(item.id, item.name, item.icon);
removeItemFromList(item); // Move the item in the edit fields
}
}
function deleteItem(elem) {
let id = elem.id.replace('delete_', '');
let item = getTypeOfId(id);
updateExistingItemsType(id, undefined);
removeItemFromList(item);
}
function removeItemFromList(item) {
currentTypes.splice(currentTypes.indexOf(item), 1);
$('#row_' + item.id).remove();
}
function setEditFieldValues(id, name, icon) {
$.selector_cache('#idInput').val(id);
$.selector_cache('#nameInput').val(name);
$.selector_cache('#iconInput').val(icon);
}
function updateExistingItemsType(oldTypeID, newTypeID) {
for (let i = 0; i < currentDataset.length; i++) {
for (let k = 0; k < currentDataset[i].type.length; k++) {
if (currentDataset[i].type[k] === oldTypeID) {
console.log(newTypeID);
if (newTypeID !== undefined)
currentDataset[i].type[k] = newTypeID;
else
currentDataset[i].type.splice(k, 1);
break;
}
}
}
}
function getTypeOfId(id) {
let item = {};
for (let i = 0; i < currentTypes.length; i++) {
if (currentTypes[i].id === id) {
item = currentTypes[i];
break;
}
}
return item;
}
function isIdAvailable(id) {
let isAvailable = true;
for (let i = 0; i < currentTypes.length; i++) {
if (currentTypes[i].id === id) {
isAvailable = false;
break;
}
}
return isAvailable;
}
function isItemInputEmpty() {
return $.selector_cache('#idInput').val() === '' &&
$.selector_cache('#nameInput').val() === '' &&
$.selector_cache('#iconInput').val() === '';
}
function isItemInputFilled() {
return $.selector_cache('#idInput').val() !== '' &&
$.selector_cache('#nameInput').val() !== '' &&
$.selector_cache('#iconInput').val() !== '';
}
function saveDataset() {
SaveManager.saveData(currentTypes, currentDataset);
}

78
assets/js/saveManager.js Normal file
View file

@ -0,0 +1,78 @@
class SaveManager {
static saveData(types, dataset) {
let finalDataset = {
v1: SaveManager.generateV1JSON(types, dataset),
v2: SaveManager.generateV2JSON(types, dataset)
};
console.log(finalDataset);
$.ajax({
type: "POST",
url: "write_json.php",
data: JSON.stringify(finalDataset),
dataType: "json",
contentType: "application/json; charset=utf-8",
complete: function (data) {
alert(data.responseText);
console.log(data);
},
});
}
static generateV1JSON(savedTypes, savedDataset) {
let types = [];
// Replace type objects by names
for (let i = 0; i < savedTypes.length; i++) {
types.push(savedTypes[i].name);
}
let dataset = JSON.parse(JSON.stringify(savedDataset)); // Deep copy of object
for (let i = 0; i < dataset.length; i++) {
// Replace type ids by names
for (let k = 0; k < dataset[i].type.length; k++) {
dataset[i].type[k] = SaveManager.getTypeOfId(savedTypes, dataset[i].type[k]).name;
}
// remove the description field
delete dataset[i].description
}
return {
types: types,
articles: dataset
}
}
static generateV2JSON(savedTypes, savedDataset) {
return {
types: savedTypes,
articles: savedDataset
}
}
static getTypeOfId(types, id) {
let item = {};
for (let i = 0; i < types.length; i++) {
if (types[i].id === id) {
item = types[i];
break;
}
}
return item;
}
static convertToV2() {
$.ajax({
type: "POST",
url: "convert_json.php",
dataType: "json",
contentType: "application/json; charset=utf-8",
complete: function (data) {
alert(data.responseText);
console.log(data);
window.location.reload();
},
});
}
}

View file

@ -1,23 +1,3 @@
let defaultTypes = [
'Nouveau',
'Alimentaire',
'Boissons',
'Utilitaires'
];
let defaultStock = [
{
name: 'Granola',
quantity: '2',
price: '1.3',
code: '7622210601988',
image : 'https://cookieandkate.com/images/2015/10/granola-mixed-in-bowl.jpg',
type: [
'Alimentaire',
]
}
];
let currentDataset = [];
let currentTypes = [];
@ -32,8 +12,11 @@ function initValuesFromPHPDump() {
$(document).ready(function () {
initValuesFromPHPDump();
generateTypeCheckboxes();
if (json_dump !== undefined) {
initValuesFromPHPDump();
generateTypeCheckboxes();
}
setEditFieldValues('', '', '', '', '', '', '');
});
@ -47,11 +30,12 @@ function generateLine(item) {
$.selector_cache('#stockTable').append(
'<tr id="row_' + item.code + '">' +
'<td>' + item.name + '</td>' +
'<td>' + item.description + '</td>' +
'<td>' + item.quantity + '</td>' +
'<td>' + item.price + '</td>' +
'<td>' + item.code + '</td>' +
'<td><ul id="typeList_' + item.code + '"></ul></td>' +
'<td><a href="' + item.image + '" target="_blank">LINK</a></td>' +
'<td><span id="typeList_' + item.code + '"></span></td>' +
'<td><a href="' + item.image + '" target="_blank"><img class="row-img" src="' + item.image + '"/></a></td>' +
'<td>' +
'<button class="btn btn-danger" id="delete_' + item.code + '" onclick="deleteItem(this)"><i class="fas fa-times"></i></button>' +
'<button class="btn btn-primary" id="edit_' + item.code + '" onclick="editItem(this)"><i class="fas fa-edit"></i></button>' +
@ -60,24 +44,37 @@ function generateLine(item) {
);
// Fill in the type cell
for (let i = 0; i < item.type.length; i++) {
let type = getTypeOfId(item.type[i]);
$('#typeList_' + item.code).append(
'<li>' + item.type[i] + '</li>'
'<span class="mdi mdi-' + type.icon + '"></span>'
);
}
}
function generateTypeCheckboxes() {
for (let i = 0; i < currentTypes.length; i++) {
let id = 'typeCheck_' + currentTypes[i];
let id = 'typeCheck_' + currentTypes[i].id;
$('#typeCheckboxesCell').append(
'<div class="form-check">' +
'<input type="checkbox" class="form-check-input" id="' + id + '">' +
'<label class="form-check-label" for="' + id + '">' + currentTypes[i] + '</label>' +
'<label class="form-check-label" for="' + id + '">' +
'<span class="mdi mdi-' + currentTypes[i].icon + '"></span>' + currentTypes[i].name + '</label>' +
'</div>'
);
}
}
function getTypeOfId(id) {
let item = {};
for (let i = 0; i < currentTypes.length; i++) {
if (currentTypes[i].id === id) {
item = currentTypes[i];
break;
}
}
return item;
}
function getItemOfCode(code) {
let item = {};
for (let i = 0; i < currentDataset.length; i++) {
@ -93,6 +90,7 @@ function addNewItem() {
if (isItemInputFilled()) {
let item = {
name: $.selector_cache('#nameInput').val(),
description: $.selector_cache('#descriptionInput').val(),
quantity: $.selector_cache('#quantityInput').val(),
price: $.selector_cache('#priceInput').val(),
code: $.selector_cache('#codeInput').val(),
@ -100,7 +98,7 @@ function addNewItem() {
image: $.selector_cache('#imageInput').val(),
};
if (isCodeAvailable(item.code)) {
setEditFieldValues('', '', '', '', [], '');
setEditFieldValues('', '', '', '', [], '', '');
currentDataset.push(item);
generateLine(item);
}
@ -111,7 +109,7 @@ function editItem(elem) {
if (isItemInputEmpty()) {
let code = elem.id.replace('edit_', '');
let item = getItemOfCode(code);
setEditFieldValues(item.name, item.quantity, item.price, item.code, item.type, item.image);
setEditFieldValues(item.name, item.description, item.quantity, item.price, item.code, item.type, item.image);
removeItemFromList(item); // Move the item in the edit fields
}
}
@ -130,9 +128,9 @@ function removeItemFromList(item) {
function getTypesChecked() {
let types = [];
for (let i = 0; i < currentTypes.length; i++) {
let id = 'typeCheck_' + currentTypes[i];
let id = 'typeCheck_' + currentTypes[i].id;
if ($('#' + id).is(':checked')) {
types.push(currentTypes[i]);
types.push(currentTypes[i].id);
}
}
return types;
@ -140,14 +138,15 @@ function getTypesChecked() {
function setTypesChecked(types) {
for (let i = 0; i < currentTypes.length; i++) {
let id = 'typeCheck_' + currentTypes[i];
$('#' + id).prop('checked', types.indexOf(currentTypes[i]) !== -1);
let id = 'typeCheck_' + currentTypes[i].id;
$('#' + id).prop('checked', types.indexOf(currentTypes[i].id) !== -1);
}
return types;
}
function setEditFieldValues(name, quantity, price, code, type, image) {
function setEditFieldValues(name, description, quantity, price, code, type, image) {
$.selector_cache('#nameInput').val(name);
$.selector_cache('#descriptionInput').val(description);
$.selector_cache('#quantityInput').val(quantity);
$.selector_cache('#priceInput').val(price);
$.selector_cache('#codeInput').val(code);
@ -169,6 +168,7 @@ function isCodeAvailable (code) {
function isItemInputEmpty() {
return $.selector_cache('#nameInput').val() === '' &&
$.selector_cache('#descriptionInput').val() === '' &&
$.selector_cache('#quantityInput').val() === '' &&
$.selector_cache('#priceInput').val() === '' &&
$.selector_cache('#codeInput').val() === '' &&
@ -178,6 +178,7 @@ function isItemInputEmpty() {
function isItemInputFilled() {
return $.selector_cache('#nameInput').val() !== '' &&
$.selector_cache('#descriptionInput').val() !== '' &&
$.selector_cache('#quantityInput').val() !== '' &&
$.selector_cache('#priceInput').val() !== '' &&
$.selector_cache('#codeInput').val() !== '' &&
@ -188,22 +189,7 @@ function isItemInputFilled() {
function saveDataset() {
let finalDataset = {
types: currentTypes,
articles: currentDataset
};
console.log(finalDataset);
$.ajax({
type: "POST",
url: "write_json.php",
data: JSON.stringify(finalDataset),
dataType: "json",
contentType: "application/json; charset=utf-8",
complete: function (data) {
alert(data.responseText);
console.log(data);
},
});
SaveManager.saveData(currentTypes, currentDataset);
}