puwanath commited on
Commit
f36d113
·
verified ·
1 Parent(s): 35541ef

Upload components/ProductGrid.jsx with huggingface_hub

Browse files
Files changed (1) hide show
  1. components/ProductGrid.jsx +176 -0
components/ProductGrid.jsx ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useEffect } from 'react';
2
+ import {
3
+ Plus,
4
+ Minus,
5
+ ShoppingBag,
6
+ Heart,
7
+ Search,
8
+ Filter,
9
+ Grid,
10
+ List
11
+ } from 'lucide-react';
12
+
13
+ const ProductGrid = ({
14
+ products,
15
+ activeCategory,
16
+ onAddToCart,
17
+ onProductClick
18
+ }) => {
19
+ const [searchQuery, setSearchQuery] = useState('');
20
+ const [gridView, setGridView] = useState(true);
21
+ const [filteredProducts, setFilteredProducts] = useState([]);
22
+
23
+ useEffect(() => {
24
+ let result = products;
25
+
26
+ // Filter by category
27
+ if (activeCategory !== 'all') {
28
+ result = result.filter(product => product.category === activeCategory);
29
+ }
30
+
31
+ // Filter by search query
32
+ if (searchQuery) {
33
+ result = result.filter(product =>
34
+ product.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
35
+ product.description.toLowerCase().includes(searchQuery.toLowerCase())
36
+ );
37
+ }
38
+
39
+ setFilteredProducts(result);
40
+ }, [products, activeCategory, searchQuery]);
41
+
42
+ const formatPrice = (price) => {
43
+ return new Intl.NumberFormat('th-TH', {
44
+ style: 'currency',
45
+ currency: 'THB'
46
+ }).format(price);
47
+ };
48
+
49
+ return (
50
+ <div className="flex-1 overflow-y-auto p-4">
51
+ {/* Search and Filter */}
52
+ <div className="mb-6 space-y-4">
53
+ <div className="flex flex-col sm:flex-row gap-4">
54
+ <div className="relative flex-1">
55
+ <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-pos-text-secondary w-5 h-5" />
56
+ <input
57
+ type="text"
58
+ placeholder="ค้นหาสินค้า..."
59
+ value={searchQuery}
60
+ onChange={(e) => setSearchQuery(e.target.value)}
61
+ className="w-full pl-10 pr-4 py-3 rounded-xl border border-pos-border focus:ring-2 focus:ring-primary-500 focus:border-transparent outline-none transition-all"
62
+ />
63
+ </div>
64
+
65
+ <div className="flex gap-2">
66
+ <button
67
+ onClick={() => setGridView(true)}
68
+ className={`p-3 rounded-xl border ${gridView
69
+ ? 'bg-primary-600 text-white border-primary-600'
70
+ : 'border-pos-border text-pos-text-secondary hover:bg-pos-bg'}`}
71
+ >
72
+ <Grid className="w-5 h-5" />
73
+ </button>
74
+ <button
75
+ onClick={() => setGridView(false)}
76
+ className={`p-3 rounded-xl border ${!gridView
77
+ ? 'bg-primary-600 text-white border-primary-600'
78
+ : 'border-pos-border text-pos-text-secondary hover:bg-pos-bg'}`}
79
+ >
80
+ <List className="w-5 h-5" />
81
+ </button>
82
+ <button className="p-3 rounded-xl border border-pos-border text-pos-text-secondary hover:bg-pos-bg">
83
+ <Filter className="w-5 h-5" />
84
+ </button>
85
+ </div>
86
+ </div>
87
+ </div>
88
+
89
+ {/* Products */}
90
+ <div className={gridView ? "grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4" : "space-y-3"}>
91
+ {filteredProducts.length > 0 ? (
92
+ filteredProducts.map((product) => (
93
+ <div
94
+ key={product.id}
95
+ onClick={() => onProductClick(product)}
96
+ className="group bg-white rounded-2xl border border-pos-border overflow-hidden hover:shadow-xl transition-all duration-300 hover:border-primary-200 cursor-pointer"
97
+ >
98
+ <div className="relative aspect-square overflow-hidden">
99
+ <img
100
+ src={product.image}
101
+ alt={product.name}
102
+ className="w-full h-full object-cover group-hover:scale-110 transition-transform duration-300"
103
+ />
104
+ <div className="absolute top-2 right-2">
105
+ <button className="p-2 bg-white/90 rounded-full hover:bg-white shadow-sm transition-colors">
106
+ <Heart className="w-4 h-4 text-red-500" />
107
+ </button>
108
+ </div>
109
+ {product.discount > 0 && (
110
+ <div className="absolute top-2 left-2 bg-danger text-white px-2 py-1 rounded-lg text-xs font-bold">
111
+ -{product.discount}%
112
+ </div>
113
+ )}
114
+ <div className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/60 to-transparent p-4">
115
+ <p className="text-white text-xs font-medium">{product.categoryName}</p>
116
+ </div>
117
+ </div>
118
+
119
+ <div className="p-3">
120
+ <h3 className="font-bold text-pos-text mb-1 truncate">{product.name}</h3>
121
+ <div className="flex justify-between items-center">
122
+ <div className="flex flex-col">
123
+ {product.discount > 0 ? (
124
+ <>
125
+ <span className="text-xs text-pos-text-secondary line-through">
126
+ {formatPrice(product.price)}
127
+ </span>
128
+ <span className="text-lg font-bold text-primary-600">
129
+ {formatPrice(product.price * (1 - product.discount/100))}
130
+ </span>
131
+ </>
132
+ ) : (
133
+ <span className="text-lg font-bold text-pos-text">
134
+ {formatPrice(product.price)}
135
+ </span>
136
+ )}
137
+ </div>
138
+ <button
139
+ onClick={(e) => {
140
+ e.stopPropagation();
141
+ onAddToCart(product);
142
+
143
+ className="p-2 bg-primary-50 text-primary-600 rounded-xl hover:bg-primary-600 hover:text-white transition-colors"
144
+ >
145
+ <ShoppingBag className="w-5 h-5" />
146
+ </button>
147
+ </div>
148
+ </div>
149
+ </div>
150
+ ))
151
+ ) : (
152
+ <div className="col-span-full py-12 text-center">
153
+ <div className="w-20 h-20 bg-pos-bg rounded-full flex items-center justify-center mx-auto mb-4">
154
+ <Search className="w-10 h-10 text-pos-text-secondary" />
155
+ </div>
156
+ <h3 className="text-lg font-medium text-pos-text mb-2">ไม่พบสินค้า</h3>
157
+ <p className="text-pos-text-secondary">
158
+ {searchQuery
159
+ ? `ไม่พบผลลัพธ์สำหรับ "${searchQuery}"`
160
+ : "โปรดเลือกหมวดหมู่หรือลองค้นหาใหม่"}
161
+ </p>
162
+ </div>
163
+ )}
164
+ </div>
165
+
166
+ {/* Product count */}
167
+ <div className="mt-4 text-center">
168
+ <p className="text-sm text-pos-text-secondary">
169
+ แสดง {filteredProducts.length} ของ {products.length} ผลิตภัณฑ์
170
+ </p>
171
+ </div>
172
+ </div>
173
+ );
174
+ };
175
+
176
+ export default ProductGrid;