fix(products): ordenar produtos do maior para o menor preco, permitir limpar input de preco/stock sem ficar negativo, e impedir adicionar mais quantidade ao carrinho do que o stock disponivel
This commit is contained in:
@@ -13,7 +13,7 @@ export const ProductList = ({
|
||||
onAdd?: (id: string) => void;
|
||||
}) => (
|
||||
<div className="grid grid-cols-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-3 sm:gap-6">
|
||||
{products.map((p) => {
|
||||
{[...products].sort((a, b) => b.price - a.price).map((p) => {
|
||||
const lowStock = p.stock <= 3;
|
||||
return (
|
||||
<Card key={p.id} className="relative overflow-hidden border-none glass-card rounded-2xl sm:rounded-[2rem] group hover:shadow-2xl transition-all duration-300 flex flex-col">
|
||||
|
||||
@@ -500,6 +500,34 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
};
|
||||
|
||||
const addToCart: AppContextValue['addToCart'] = (item) => {
|
||||
if (item.type === 'product') {
|
||||
const shop = state.shops.find((shp) => shp.id === item.shopId);
|
||||
const prod = shop?.products.find((p) => p.id === item.refId);
|
||||
if (prod) {
|
||||
const maxStock = prod.stock;
|
||||
const existingItem = state.cart.find((c) => c.refId === item.refId && c.type === 'product' && c.shopId === item.shopId);
|
||||
const currentQty = existingItem ? existingItem.qty : 0;
|
||||
|
||||
if (currentQty >= maxStock) {
|
||||
addToast(`Não é possível adicionar mais unidades. Apenas ${maxStock} unidades em stock.`, 'info');
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentQty + item.qty > maxStock) {
|
||||
const allowedQty = maxStock - currentQty;
|
||||
setState((s) => {
|
||||
const cart = [...s.cart];
|
||||
const idx = cart.findIndex((c) => c.refId === item.refId && c.type === item.type && c.shopId === item.shopId);
|
||||
if (idx >= 0) cart[idx].qty = maxStock;
|
||||
else cart.push({ ...item, qty: allowedQty });
|
||||
return { ...s, cart };
|
||||
});
|
||||
addToast(`Adicionado apenas ${allowedQty} unidades. Limite de stock atingido.`, 'info');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setState((s) => {
|
||||
const cart = [...s.cart];
|
||||
const idx = cart.findIndex((c) => c.refId === item.refId && c.type === item.type && c.shopId === item.shopId);
|
||||
|
||||
@@ -141,8 +141,8 @@ function DashboardInner({ shop }: { shop: BarberShop }) {
|
||||
const [svcDuration, setSvcDuration] = useState<number>(30);
|
||||
|
||||
const [prodName, setProdName] = useState('');
|
||||
const [prodPrice, setProdPrice] = useState<number>(30);
|
||||
const [prodStock, setProdStock] = useState<number>(10);
|
||||
const [prodPrice, setProdPrice] = useState<string>('30');
|
||||
const [prodStock, setProdStock] = useState<string>('10');
|
||||
|
||||
const [barberName, setBarberName] = useState('');
|
||||
const [barberSpecs, setBarberSpecs] = useState('');
|
||||
@@ -296,10 +296,20 @@ function DashboardInner({ shop }: { shop: BarberShop }) {
|
||||
|
||||
const addNewProduct = () => {
|
||||
if (!prodName.trim()) return;
|
||||
addProduct(shop.id, { name: prodName, price: Number(prodPrice) || 0, stock: Number(prodStock) || 0 });
|
||||
const priceNum = parseFloat(prodPrice);
|
||||
const stockNum = parseInt(prodStock, 10);
|
||||
if (isNaN(priceNum) || priceNum < 0) {
|
||||
alert('O preço deve ser um número positivo.');
|
||||
return;
|
||||
}
|
||||
if (isNaN(stockNum) || stockNum < 0) {
|
||||
alert('O stock deve ser um número positivo.');
|
||||
return;
|
||||
}
|
||||
addProduct(shop.id, { name: prodName, price: priceNum, stock: stockNum });
|
||||
setProdName('');
|
||||
setProdPrice(30);
|
||||
setProdStock(10);
|
||||
setProdPrice('30');
|
||||
setProdStock('10');
|
||||
};
|
||||
|
||||
const addNewBarber = () => {
|
||||
@@ -1116,7 +1126,7 @@ function DashboardInner({ shop }: { shop: BarberShop }) {
|
||||
</div>
|
||||
)}
|
||||
<div className="space-y-3 mb-6">
|
||||
{shop.products.map((p) => (
|
||||
{[...shop.products].sort((a, b) => b.price - a.price).map((p) => (
|
||||
<div
|
||||
key={p.id}
|
||||
className={`flex items-center justify-between p-4 border rounded-lg ${p.stock <= 3 ? 'border-indigo-300 bg-indigo-50' : 'border-slate-200'
|
||||
@@ -1150,8 +1160,33 @@ function DashboardInner({ shop }: { shop: BarberShop }) {
|
||||
<h3 className="text-base font-semibold text-slate-900 mb-3">Adicionar novo produto</h3>
|
||||
<div className="grid md:grid-cols-4 gap-3">
|
||||
<Input label="Nome" placeholder="Ex: Pomada" value={prodName} onChange={(e) => setProdName(e.target.value)} />
|
||||
<Input label="Preço" type="number" placeholder="30" value={prodPrice} onChange={(e) => setProdPrice(Number(e.target.value))} />
|
||||
<Input label="Stock inicial" type="number" placeholder="10" value={prodStock} onChange={(e) => setProdStock(Number(e.target.value))} />
|
||||
<Input
|
||||
label="Preço"
|
||||
type="number"
|
||||
placeholder="30"
|
||||
min="0"
|
||||
step="0.01"
|
||||
value={prodPrice}
|
||||
onChange={(e) => {
|
||||
const val = e.target.value;
|
||||
if (val === '' || parseFloat(val) >= 0) {
|
||||
setProdPrice(val);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Input
|
||||
label="Stock inicial"
|
||||
type="number"
|
||||
placeholder="10"
|
||||
min="0"
|
||||
value={prodStock}
|
||||
onChange={(e) => {
|
||||
const val = e.target.value;
|
||||
if (val === '' || parseInt(val, 10) >= 0) {
|
||||
setProdStock(val);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<div className="flex items-end">
|
||||
<Button onClick={addNewProduct} className="w-full">
|
||||
<PlusIcon size={16} className="mr-2" />
|
||||
|
||||
Reference in New Issue
Block a user