diff --git a/webseite-ts-claude/backend/utils/json-modifier.js b/webseite-ts-claude/backend/utils/json-modifier.js deleted file mode 100644 index f0c7847..0000000 --- a/webseite-ts-claude/backend/utils/json-modifier.js +++ /dev/null @@ -1,19 +0,0 @@ -import fs from 'node:fs'; -import { v4 as id } from 'uuid'; - -console.log(id()); // 97412ca6-c7a8-4868-a49b-3cf4c2258dd8 - -try { - const data = JSON.parse(fs.readFileSync('../data/products.json', 'utf-8')); - - const products = data.map((product, index) => { - return { _id: product._id || id(), position: index + 1, ...product }; - }); - - console.log(products); - - fs.writeFileSync('../data/products.json', JSON.stringify(products, null, 2), 'utf-8'); - console.log('File modified'); -} catch (error) { - console.log(error); -} diff --git a/webseite-ts-claude/frontend/dev/scripts/main.js b/webseite-ts-claude/frontend/dev/scripts/main.js deleted file mode 100644 index a1993cb..0000000 --- a/webseite-ts-claude/frontend/dev/scripts/main.js +++ /dev/null @@ -1,49 +0,0 @@ -// import 'bootstrap'; // ohne Pfadangabe (Modul auslesen aus node_modules) funktioniert nur mit JS-Bundler (esbuild, rollup & co.) - -import ProductManager from './modules/ProductManager'; // Dateiendung kann weggelassen werden, wenn ein Bundler eingesetzt wird (esbuild, webpack, rollup, etc.) -import Splide from '@splidejs/splide'; - -(() => { - // === DOM & VARS ======= - const DOM = {}; - - // === INIT ============= - const init = () => { - console.log('init'); - router(); - }; - - // === EVENTHANDLER ===== - - // === XHR/FETCH ======== - - // === FUNCTIONS ======== - const router = () => { - const path = window.location.pathname; - - console.log(path); - - switch (path) { - case '/': - case '/index.html': - console.log('HOME'); - const splider = new Splide('.splide', { - type: 'loop', - fixedHeight: '100%', - height: '100%', - autoHeight: true, - }).mount(); - - // nur Skripte, die für Home relevant ausführen - break; - case '/projects/product-manager.html': - console.log('PRODUCT_MANAGER'); - const pm = ProductManager(); - break; - default: - console.warn('Page not found'); - } - }; - - init(); -})(); diff --git a/webseite-ts-claude/frontend/dev/scripts/modules/ProductManager.js b/webseite-ts-claude/frontend/dev/scripts/modules/ProductManager.js deleted file mode 100644 index 07515e2..0000000 --- a/webseite-ts-claude/frontend/dev/scripts/modules/ProductManager.js +++ /dev/null @@ -1,574 +0,0 @@ -import { Modal } from 'bootstrap'; // ohne Pfadangabe (Modul auslesen aus node_modules) funktioniert nur mit JS-Bundler (esbuild, rollup & co.) -import Toast from './Toast'; - -// import * as bootstrap from 'bootstrap'; -// import 'bootstrap'; - -// import 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js'; // würde auch ohne Bundler funktionieren -// import '../../../node_modules/bootstrap/dist/js/bootstrap.esm.js'; // würde auch ohne Bundler funktionieren - -// Factory Function -const ProductManager = (el = null) => { - // === DOM & VARS ======= - - const BASE_URL = 'http://127.0.0.1:8000'; - - const module = el || document.querySelector('.product-manager') || console.error('Product Manager not found'); - - if (!module) return; - - const DOM = { - module, - table: module.querySelector('.table-products'), - tBody: module.querySelector('tbody'), - inputName: module.querySelector('.input-product-name'), - inputPrice: module.querySelector('.input-product-price'), - btnAdd: module.querySelector('.button-product-add'), - templateRow: module.querySelector('.template-row'), - - // Nav Actions - btnSave: module.querySelector('.button-products-save'), - btnReset: module.querySelector('.button-products-reset'), - - // Modal Edit - modalEdit: module.querySelector('.modal-edit'), - formEdit: module.querySelector('.form-product-edit'), - inputEditName: module.querySelector('.input-edit-name'), - inputEditPrice: module.querySelector('.input-edit-price'), - inputEditId: module.querySelector('.input-edit-id'), - inputEditPosition: module.querySelector('.input-edit-position'), - btnUpdate: module.querySelector('.button-product-update'), - - // Modal Delete - modalDelete: module.querySelector('.modal-delete'), - productName: module.querySelector('strong.product-name'), - btnConfirmDelete: module.querySelector('.button-confirm-delete'), - }; - - console.log(DOM); - const bsModalEdit = new Modal(DOM.modalEdit, { - backdrop: 'static', // true - keyboard: true, - }); - - const bsModalDelete = new Modal(DOM.modalDelete, { - backdrop: 'static', // true - keyboard: true, - }); - - // === INIT ============= - const init = () => { - console.log('init'); - // Funktionaufrufe zu beginn der Anwendung - initProducts(); - - // Event-Lauscher zu beginn der Anwendung - DOM.btnReset.addEventListener('click', onClickReset); - DOM.btnSave.addEventListener('click', onClickSave); - - DOM.btnAdd.addEventListener('click', onClickAdd); - DOM.btnAdd.disabled = true; - DOM.btnConfirmDelete.addEventListener('click', onClickConfirmDelete); - DOM.formEdit.addEventListener('submit', onSubmitEdit); - window.addEventListener('keyup', onKeyUp); - }; - - // === EVENTHANDLER ===== - const onKeyUp = (e) => { - // if (DOM.inputName.value === '' && DOM.inputPrice.value === '') { - // DOM.btnAdd.disabled = true; - // } else { - // DOM.btnAdd.disabled = false; - // } - DOM.btnAdd.disabled = (DOM.inputName.value === '' || DOM.inputPrice.value === ''); // prettier-ignore - }; - - const onClickReset = (e) => { - const btnEl = e.currentTarget; - - // async process - resetProducts().then((data) => { - if (data.success) { - Toast(data.msg, 'success').show(); - loadProducts(); - } - }); - }; - - const onClickSave = (e) => { - const btnEl = e.currentTarget; - const icon = btnEl.querySelector('i'); - - icon.classList.add('fa-jello'); - - // async process - saveProducts().then((data) => { - if (data.success) { - setTimeout(() => { - icon.classList.remove('fa-jello'); - }, 500); - Toast(data.msg, 'success').show(); - } - }); - }; - - const onSubmitEdit = (e) => { - e.preventDefault(); // Standardverhalten unterbinden (Formular nicht an action versenden) - - // console.log(Object.entries(new FormData(DOM.formEdit))); - - const product = { - name: DOM.inputEditName.value, - price: Number(DOM.inputEditPrice.value), - _id: DOM.inputEditId.value, - position: DOM.inputEditPosition.value, - }; - - // update async process - DOM.btnUpdate.querySelector('i').classList.add('fa-spin'); - updateProduct(product).then((data) => { - console.log(data); - if (data.success) { - Toast(data.msg, 'success').show(); - DOM.btnUpdate.querySelector('i').classList.remove('fa-spin'); - loadProducts(); // All Produkte auslesen - resetFields(); - bsModalEdit.hide(); - } else { - Toast(data.msg, 'error').show(); - } - }); - }; - - const onClickAdd = (e) => { - console.log('click'); - - const product = { - name: DOM.inputName.value, - price: Number(DOM.inputPrice.value), - }; - - createProduct(product).then((data) => { - console.log(data); - if (data.success) { - console.log('add'); - Toast(data.msg, 'success').show(); - loadProducts(); - resetFields(); - } - }); - - // addProduct(product); - - disableNonFunctionalButtons(); - }; - - const onClickEdit = (e) => { - const btnEl = e.currentTarget; - const currentRow = parents(btnEl, 'tr')[0]; - const id = currentRow.dataset.id; - - // async fetch - getProduct(id).then((data) => { - // console.log(data); - showModalEdit(data); - }); - }; - - const onClickRemove = (e) => { - const btnEl = e.currentTarget; - const currentRow = parents(btnEl, 'tr')[0]; - const id = currentRow.dataset.id; - - const productName = currentRow.querySelector('.td-name').textContent.trim(); - - DOM.btnConfirmDelete.dataset.id = id; - DOM.productName.textContent = productName; - - // async fetch - // deleteProduct(id).then((data) => { - // if (data.success) { - // Toast(data.msg, 'success').show(); - // console.log('delete: success', data); - // loadProducts(); - // } else { - // Toast(data.msg, 'error').show(); - // console.error(data); - // } - // }); - }; - - const onClickConfirmDelete = (e) => { - const btnEl = e.currentTarget; - const id = btnEl.dataset.id; - - // async fetch - deleteProduct(id).then((data) => { - if (data.success) { - Toast(data.msg, 'success').show(); - bsModalDelete.hide(); - loadProducts(); - } else { - Toast(data.msg, 'error').show(); - console.error(data); - } - }); - }; - - const onClickMoveUp = (e) => { - const btnEl = e.currentTarget; - // const currentRowEl = btnEl.parentNode.parentNode; // aktuelle Zeile (tr) mit dem Button - const currentRowEl = parents(btnEl, 'tr')[0]; - - // ParentNode.insertBefore(referenceElement, targetElement) - // DOM.tBody.insertBefore(currentRowEl, currentRowEl.previousElementSibling); - - // targetElement.before(referenceElement) - currentRowEl.previousElementSibling.before(currentRowEl); - - console.log('move up'); - disableNonFunctionalButtons(); - }; - - const onClickMoveDown = (e) => { - const btnEl = e.currentTarget; - // const currentRowEl = btnEl.parentNode.parentNode; // aktuelle Zeile (tr) mit dem Button - const currentRowEl = parents(btnEl, 'tr')[0]; - - // ParentNode.insertBefore(referenceElement, targetElement) - // DOM.tBody.insertBefore(currentRowEl, currentRowEl.nextElementSibling.nextElementSibling); - - // targetElement.after(referenceElement) - currentRowEl.nextElementSibling.after(currentRowEl); - - console.log('move down'); - disableNonFunctionalButtons(); - }; - - // Drag 'n Drop EventHandler - const onMouseDownDrag = (e) => { - const btnEl = e.currentTarget; - const currentRowEl = parents(btnEl, 'tr')[0]; - currentRowEl.draggable = true; - }; - - const onMouseUpDrag = (e) => { - const btnEl = e.currentTarget; - const currentRowEl = parents(btnEl, 'tr')[0]; - currentRowEl.draggable = false; - }; - - const onDragStart = (e) => { - console.log('DragEvent: ', e); - const currentRowEl = e.currentTarget; // tr <- aktuelle Zeie, die bewegt wird - const idx = [...currentRowEl.parentNode.children].indexOf(currentRowEl); - - e.dataTransfer.setData('text/plain', idx); - // e.dataTransfer.setData('application/json', JSON.stringify({idx, name: sourceElement})); - console.log('tr index:', idx); - }; - - const onDragOver = (e) => { - e.preventDefault(); // WICHTIG! Sonst funktioniert drop EventHandler nicht. - }; - - const onDrop = (e) => { - const currentRowEl = e.currentTarget; // tr <- Zielzeile, auf die gedroppt wird. - const targetIdx = [...currentRowEl.parentNode.children].indexOf(currentRowEl); - const sourceIdx = parseInt(e.dataTransfer.getData('text/plain')); - // const { sourceIdx } = JSON.parse(e.dataTransfer.getData('application/json')); - - console.log({ targetIdx, sourceIdx }); - - // Guard wenn Element auf sich selbst losgelassen wurde, abbruch - if (sourceIdx === targetIdx) { - return; - } - - const draggedEl = DOM.tBody.querySelector(`tr:nth-child(${sourceIdx + 1})`); - // const draggedEl = DOM.tBody.children[sourceIdx] - - // Verschiebe das Element im DOM - if (sourceIdx > targetIdx) { - currentRowEl.before(draggedEl); - } else { - currentRowEl.after(draggedEl); - } - - disableNonFunctionalButtons(); - }; - - // === XHR/FETCH ======== - - // HTTP - Methode - PATCH - // reset products - const resetProducts = async () => { - try { - const response = await fetch(`${BASE_URL}/api/products/reset`, { - method: 'PATCH', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ reset: true }), - }); // HTTP Request URL - if (!response.ok) { - throw new Error('Fetch went wrong.'); - } - const data = await response.json(); // HTTP-Response - - return data; - } catch (error) { - Toast(error, 'error').show(); - - console.error(error); - return error; - } - }; - - // HTTP - Methode - PATCH - // save products - const saveProducts = async () => { - try { - const response = await fetch(`${BASE_URL}/api/products/save`, { - method: 'PATCH', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ save: true }), - }); // HTTP Request URL - if (!response.ok) { - throw new Error('Fetch went wrong.'); - } - const data = await response.json(); // HTTP-Response - - return data; - } catch (error) { - Toast(error, 'error').show(); - - console.error(error); - return error; - } - }; - - // HTTP - Methode - POST - // (C)RUD - create - // BRE(A)D - add - neues Produkt hinzufügen - const createProduct = async (product) => { - try { - const response = await fetch(`${BASE_URL}/api/products`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(product), - }); // HTTP Request URL - if (!response.ok) { - throw new Error('Fetch went wrong.'); - } - const data = await response.json(); // HTTP-Response - - return data; - } catch (error) { - Toast(error, 'error').show(); - - console.error(error); - return error; - } - }; - - // HTTP - Methode - GET - // C(R)UD - Read - // (B)READ - Browse - auslesen aller Produkte - const getProducts = async () => { - try { - const response = await fetch(`${BASE_URL}/api/products`); // HTTP Request URL - if (!response.ok) { - throw new Error('Fetch went wrong.'); - } - const data = await response.json(); // HTTP-Response - - return data; - } catch (error) { - console.error(error); - return error; - } - }; - - // HTTP - Methode - GET - // C(R)UD - Read - // B(R)EAD - Read - auslesen eines Produkts - const getProduct = async (id) => { - try { - const response = await fetch(`${BASE_URL}/api/products/${id}`); // HTTP Request URL - if (!response.ok) { - throw new Error('Fetch went wrong.'); - } - const data = await response.json(); // HTTP-Response - - return data; - } catch (error) { - console.error(error); - return error; - } - }; - - // HTTP - Methode - PUT - // CR(U)D - update - // BR(E)AD - edit - Produkt aktualisieren - const updateProduct = async (product) => { - try { - const response = await fetch(`${BASE_URL}/api/products`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(product), - }); // HTTP Request URL - if (!response.ok) { - throw new Error('Fetch went wrong.'); - } - const data = await response.json(); // HTTP-Response - - return data; - } catch (error) { - console.error(error); - return error; - } - }; - - // HTTP - Methode - DELETE - // CRU(D) - delete - // BREA(D) - delete - Produkt löschen - const deleteProduct = async (id) => { - try { - const response = await fetch(`${BASE_URL}/api/products/${id}`, { - method: 'DELETE', - headers: { - 'Content-Type': 'application/json', - }, - }); // HTTP Request URL - if (!response.ok) { - throw new Error('Fetch went wrong.'); - } - - const data = await response.json(); - return data; - } catch (error) { - console.error(error); - return error; - } - }; - - // === FUNCTIONS ======== - - const initProducts = () => { - getProducts().then((products) => { - products.forEach((product) => { - addProduct(product); - }); - Toast('Init products').show(); - disableNonFunctionalButtons(); - }); - - // PRODUCTS.forEach((product) => { - // addProduct(product); - // }); - //disableNonFunctionalButtons(); - // PRODUCTS.forEach(addProduct); - }; - - const loadProducts = () => { - DOM.tBody.innerHTML = ''; - getProducts().then((data) => { - data.forEach((product) => { - addProduct(product); - }); - disableNonFunctionalButtons(); - }); - }; - - const addProduct = (product) => { - const { name, price, _id: id, position } = product; - - // https://developer.mozilla.org/de/docs/Web/API/HTMLTemplateElement/content - const trEl = DOM.templateRow.content.firstElementChild.cloneNode(true); - - const tdNameEl = trEl.querySelector('.td-name'); - const tdPriceEl = trEl.querySelector('.td-price'); - const btnRemoveEl = trEl.querySelector('.button-product-remove'); - const btnMoveUpEl = trEl.querySelector('.button-product-move-up'); - const btnMoveDownEl = trEl.querySelector('.button-product-move-down'); - - const btnDragEl = trEl.querySelector('.button-drag'); - const btnEditEl = trEl.querySelector('.button-product-edit'); - - tdNameEl.textContent = name; - tdPriceEl.textContent = price; - - btnEditEl.addEventListener('click', onClickEdit); - btnRemoveEl.addEventListener('click', onClickRemove); - btnMoveUpEl.addEventListener('click', onClickMoveUp); - btnMoveDownEl.addEventListener('click', onClickMoveDown); - - // Drag 'n Drop Events - btnDragEl.addEventListener('mousedown', onMouseDownDrag); - btnDragEl.addEventListener('mouseup', onMouseUpDrag); - - trEl.addEventListener('dragstart', onDragStart); - trEl.addEventListener('dragover', onDragOver); - trEl.addEventListener('drop', onDrop); - - trEl.dataset.id = id; //