mirror of
https://gitlab.com/davidels1986/ore-cart-checkout.git
synced 2026-10-30 02:59:13 +00:00
Enhance cart feedback
Added a visual cart add-to-item feedback (toast with product image) and updated CartDrawer to prioritize imageUrl from NocoDB, falling back to existing image. X-Lovable-Edit-ID: edt-b27feb3c-dde0-4c33-b4e3-dd819dbf8807 Co-authored-by: CyberTechDroid <229118619+CyberTechDroid@users.noreply.github.com>
This commit is contained in:
commit
fa208b8ac5
5 changed files with 1844 additions and 50 deletions
|
|
@ -132,7 +132,7 @@ export function CartDrawer() {
|
|||
<div className="flex gap-3">
|
||||
<div className="h-16 w-16 rounded-lg bg-card flex items-center justify-center shrink-0">
|
||||
<img
|
||||
src={item.product.image}
|
||||
src={item.product.imageUrl ?? item.product.image}
|
||||
alt={item.product.name}
|
||||
className="h-12 w-12 object-contain"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,36 @@
|
|||
import { ShoppingCart, Plus } from 'lucide-react';
|
||||
import { ShoppingCart, Plus, Check } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { Product } from '@/types';
|
||||
import { useCart } from '@/context/CartContext';
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
|
||||
interface ProductCardProps {
|
||||
product: Product;
|
||||
}
|
||||
|
||||
export function ProductCard({ product }: ProductCardProps) {
|
||||
const { addItem } = useCart();
|
||||
const { addItem, setIsCartOpen } = useCart();
|
||||
const { toast } = useToast();
|
||||
const [justAdded, setJustAdded] = useState(false);
|
||||
|
||||
const handleAdd = (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
addItem(product);
|
||||
setJustAdded(true);
|
||||
setTimeout(() => setJustAdded(false), 1200);
|
||||
toast({
|
||||
title: '✓ Added to cart',
|
||||
description: product.name,
|
||||
action: (
|
||||
<Button size="sm" variant="outline" onClick={() => setIsCartOpen(true)}>
|
||||
View Cart
|
||||
</Button>
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="card-hover group overflow-hidden border bg-card">
|
||||
|
|
@ -30,14 +51,10 @@ export function ProductCard({ product }: ProductCardProps) {
|
|||
/>
|
||||
<Button
|
||||
size="icon"
|
||||
className="absolute top-1.5 right-1.5 h-8 w-8 md:h-8 md:w-8 opacity-100 md:opacity-0 md:group-hover:opacity-100 transition-all md:transform md:translate-y-2 md:group-hover:translate-y-0 touch-manipulation"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
addItem(product);
|
||||
}}
|
||||
className={`absolute top-1.5 right-1.5 h-8 w-8 md:h-8 md:w-8 opacity-100 md:opacity-0 md:group-hover:opacity-100 transition-all md:transform md:translate-y-2 md:group-hover:translate-y-0 touch-manipulation ${justAdded ? 'bg-green-600 hover:bg-green-600' : ''}`}
|
||||
onClick={handleAdd}
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
{justAdded ? <Check className="h-4 w-4" /> : <Plus className="h-4 w-4" />}
|
||||
</Button>
|
||||
</div>
|
||||
<CardContent className="p-2 md:p-3">
|
||||
|
|
@ -56,16 +73,13 @@ export function ProductCard({ product }: ProductCardProps) {
|
|||
<span className="text-primary font-semibold text-[10px] md:text-sm hidden sm:inline">Quote</span>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
addItem(product);
|
||||
}}
|
||||
onClick={handleAdd}
|
||||
className="gap-1 h-9 md:h-8 px-2 md:px-3 text-[10px] md:text-xs w-full sm:w-auto touch-manipulation"
|
||||
>
|
||||
<ShoppingCart className="h-3 w-3 md:h-4 md:w-4" />
|
||||
<span className="hidden sm:inline">Add</span>
|
||||
<Plus className="h-3 w-3 sm:hidden" />
|
||||
<span className="hidden sm:inline">{justAdded ? 'Added!' : 'Add'}</span>
|
||||
{!justAdded && <Plus className="h-3 w-3 sm:hidden" />}
|
||||
{justAdded && <Check className="h-3 w-3 sm:hidden" />}
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
|
|
|||
|
|
@ -1,31 +1,35 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"types": ["vitest/globals"],
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": false,
|
||||
"lib": [
|
||||
"ES2020",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"module": "ESNext",
|
||||
"moduleDetection": "force",
|
||||
"moduleResolution": "bundler",
|
||||
"noEmit": true,
|
||||
"noFallthroughCasesInSwitch": false,
|
||||
"noImplicitAny": false,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noImplicitAny": false,
|
||||
"noFallthroughCasesInSwitch": false,
|
||||
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
]
|
||||
},
|
||||
"skipLibCheck": true,
|
||||
"strict": false,
|
||||
"target": "ES2020",
|
||||
"types": [
|
||||
"vitest/globals"
|
||||
],
|
||||
"useDefineForClassFields": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
||||
|
|
@ -1,16 +1,24 @@
|
|||
{
|
||||
"files": [],
|
||||
"references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }],
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
"noImplicitAny": false,
|
||||
"noUnusedParameters": false,
|
||||
"skipLibCheck": true,
|
||||
"allowJs": true,
|
||||
"noImplicitAny": false,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
]
|
||||
},
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Reference in a new issue