This commit is contained in:
Philippe Torrel
2026-08-28 08:56:54 +02:00
parent 536c222251
commit 92348fc25d
209 changed files with 22154 additions and 34 deletions

View File

@@ -9,7 +9,7 @@
"version": "0.0.0",
"dependencies": {
"@splidejs/react-splide": "^0.7.12",
"axios": "^1.19.0",
"axios": "^1.20.0",
"bootstrap": "^5.3.8",
"react": "^19.2.8",
"react-dom": "^19.2.8",
@@ -19,7 +19,7 @@
"devDependencies": {
"@types/react": "^19.2.18",
"@types/react-dom": "^19.2.5",
"@vitejs/plugin-react": "^6.1.0",
"@vitejs/plugin-react": "^6.1.1",
"oxlint": "^1.80.0",
"sass-embedded": "^1.103.1",
"vite": "^8.2.2"
@@ -1022,9 +1022,9 @@
}
},
"node_modules/@vitejs/plugin-react": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.1.0.tgz",
"integrity": "sha512-qd2BzUBehkov86WFhg0JkEFEYyCLG9uPCe6qWTY/kRlss9OvJrOF2UbIWT7p+8IzZHkEu0DNGHc4HSv+JdDLsw==",
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.1.1.tgz",
"integrity": "sha512-yxLaQV9gkhS8ezJqCM6+ndU7mDY6gqAg75NQ+0IjwEI8IYOmQCgkRwHKVSfWXW076DsqMo0Dk+0FK1U+M5RgFw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1070,9 +1070,9 @@
"license": "MIT"
},
"node_modules/axios": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.19.0.tgz",
"integrity": "sha512-ht/iuYZXEjFxLH/Hkezgd7m6JKlHHXEUSneaDz8uZe1Gj5QZtCnpyDsckvAiEnT89OEbCLmnte4R4sn7P0EKFw==",
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz",
"integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.16.0",

View File

@@ -11,7 +11,7 @@
},
"dependencies": {
"@splidejs/react-splide": "^0.7.12",
"axios": "^1.19.0",
"axios": "^1.20.0",
"bootstrap": "^5.3.8",
"react": "^19.2.8",
"react-dom": "^19.2.8",
@@ -21,7 +21,7 @@
"devDependencies": {
"@types/react": "^19.2.18",
"@types/react-dom": "^19.2.5",
"@vitejs/plugin-react": "^6.1.0",
"@vitejs/plugin-react": "^6.1.1",
"oxlint": "^1.80.0",
"sass-embedded": "^1.103.1",
"vite": "^8.2.2"

View File

@@ -7,10 +7,13 @@ const InputAmount = (props) => {
// EventHandlers ================
const handleChange = (e) => {
console.log(e); // Event-Objekte wurden um React Methoden und Eigenschaften erweitert. (SyntheticBaseEvent anstatt InputEvent)
console.log(e.target.value);
};
const inputValue = e.target.value;
const numericRegExp = new RegExp(/^-?\d*$/); // regular expression for numbers (including optional minus sign)
if (!numericRegExp.test(inputValue)) return;
// setAmount(inputValue);
props.onHandleAmount(inputValue);
};
const handleClickDec = (e) => {
// Guard
if (amount < min) return;

View File

@@ -1,22 +1,108 @@
import { useCallback, useMemo, useReducer, useState } from 'react';
import RowProduct from './content/RowProduct';
// Reducer (bei größerer Applikaitonsstuktur ausgelagert)
const initialState = (props) => {
// Validierung und Error Checks
return { items: props.items || [] };
};
const reducer = (state, action) => {
const { type, payload } = action;
switch (type) {
case 'UPDATE_AMOUNT':
return {
...state,
items: state.items.map((item) =>
item._id === payload.id
? { ...item, stock: payload.amount } //
: item,
),
};
case 'UPDATE_PRICE':
return {
...state,
items: state.items.map((item) =>
item._id === payload.id
? { ...item, price: payload.price } //
: item,
),
};
default:
console.warn('no action found');
return state;
}
};
const TableProducts = (props) => {
const {
items = [
{
_id: '1',
title: 'Example Product 1',
sku: 'ABC1234',
stock: 2,
price: 15.2,
},
],
} = props;
// const {
// items = [
// {
// _id: '1',
// title: 'Example Product 1',
// sku: 'ABC1234',
// stock: 2,
// price: 15.2,
// },
// ],
// } = props;
const [{ items }, dispatch] = useReducer(reducer, initialState(props));
// const [items, setItems] = useState(
// props.items || [
// {
// _id: '1',
// title: 'Example Product 1',
// sku: 'ABC1234',
// stock: 2,
// price: 15.2,
// },
// ],
// );
// EventHandler ============
const handleAmount = useCallback((amount, id) => {
dispatch({ type: 'UPDATE_AMOUNT', payload: { amount, id } });
// setItems((prevItems) => {
// return prevItems.map((item) => (item._id === id ? { ...item, stock: amount } : item));
// });
}, []);
const handlePrice = useCallback((price, id) => {
dispatch({ type: 'UPDATE_PRICE', payload: { price, id } });
// setItems((prevItems) => {
// return prevItems.map((item) => (item._id === id ? { ...item, price: price } : item));
// });
}, []);
// Functions ===============
const totalPrice = useMemo(() => {
// [0, {stock: 2, price, 15.2}, {...}]
return items.reduce((sum, obj) => {
return sum + Number(obj.stock) * Number(obj.price);
}, 0);
}, [items]);
// useCallback weiter Einsatzbereich in Kombination mit ref- Attribut
const theadRef = useCallback((el) => {
if (el) console.log(el);
}, []);
// const getTotalPrice = () => {
// // [0, {stock: 2, price, 15.2}, {...}]
// return items.reduce((sum, obj) => {
// return sum + Number(obj.stock) * Number(obj.price);
// }, 0);
// };
return (
<div className="m-table-products table-products">
<div className="container py-2">
<table className="table table-striped">
<thead className="table-dark">
<thead className="table-dark" ref={theadRef}>
<tr>
<th>SKU</th>
<th>Stock</th>
@@ -26,12 +112,20 @@ const TableProducts = (props) => {
</tr>
</thead>
<tbody>
{items.length > 0 && items.map((product, idx) => <RowProduct key={`row-product-${idx}`} {...product} />)}
{items.length > 0 &&
items.map((product, idx) => (
<RowProduct
key={`row-product-${idx}`}
{...product}
onHandleAmount={handleAmount}
onHandlePrice={handlePrice}
/>
))}
</tbody>
<tfoot>
<tr>
<td colSpan={4}>Total:</td>
<td></td>
<td>{totalPrice.toFixed(2)}</td>
</tr>
</tfoot>
</table>

View File

@@ -1,21 +1,23 @@
import { useState } from 'react';
// import { useState } from 'react';
import InputAmount from '../../inputs/InputAmount';
import InputPrice from '../../inputs/InputPrice';
const RowProduct = (props) => {
// const { sku = '', stock: amount = 0, price = 0, title = '' } = props;
const { sku = '', title = '' } = props;
const { _id, sku = '', stock: amount = 0, price = 0, title = '' } = props;
//const { sku = '', title = '' } = props;
const [amount, setAmount] = useState(props.stock || 0);
const [price, setPrice] = useState(props.price || 0);
// const [amount, setAmount] = useState(props.stock || 0);
// const [price, setPrice] = useState(props.price || 0);
// Eventhandler
const handleAmount = (val) => {
setAmount(val);
// setAmount(val);
props.onHandleAmount(val, _id);
};
const handlePrice = (val) => {
setPrice(val);
// setPrice(val);
props.onHandlePrice(val, _id);
};
return (

View File

@@ -7,6 +7,19 @@
.input-group {
margin-bottom: 0 !important;
}
&:last-child {
text-align: right;
}
}
}
tfoot {
tr {
td {
&:last-child {
border-top: 2px solid #222;
font-weight: 700;
}
}
}
}
}