@codesinger0/shared-components 1.1.83 → 1.1.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/FullscreenCarousel.jsx +43 -27
- package/dist/components/LargeItemCard.jsx +35 -11
- package/dist/components 2/AccessibilityMenu.jsx +474 -0
- package/dist/components 2/AdvantagesList.jsx +89 -0
- package/dist/components 2/ArticlesList.jsx +269 -0
- package/dist/components 2/DualTextCard.jsx +73 -0
- package/dist/components 2/FloatingWhatsAppButton.jsx +180 -0
- package/dist/components 2/FullscreenCarousel.jsx +292 -0
- package/dist/components 2/Hero.jsx +198 -0
- package/dist/components 2/IconGrid.jsx +144 -0
- package/dist/components 2/IntroSection.jsx +74 -0
- package/dist/components 2/LargeItemCard.jsx +267 -0
- package/dist/components 2/MasonryItemCard.jsx +247 -0
- package/dist/components 2/Menu.d.ts +26 -0
- package/dist/components 2/Menu.jsx +268 -0
- package/dist/components 2/MyOrdersDisplay.jsx +311 -0
- package/dist/components 2/QAAccordion.jsx +212 -0
- package/dist/components 2/SmallItemCard.jsx +152 -0
- package/dist/components 2/SmallItemsGrid.jsx +313 -0
- package/dist/components 2/TextListCards.jsx +107 -0
- package/dist/components 2/ToastProvider.jsx +38 -0
- package/dist/components 2/UnderConstruction.jsx +76 -0
- package/dist/components 2/VideoCard.jsx +88 -0
- package/dist/components 2/cart/CartItem.jsx +101 -0
- package/dist/components 2/cart/FloatingCartButton.jsx +49 -0
- package/dist/components 2/cart/OrderForm.jsx +960 -0
- package/dist/components 2/cart/ShoppingCartModal.jsx +229 -0
- package/dist/components 2/clubMembership/ClubMembershipModal.jsx +289 -0
- package/dist/components 2/clubMembership/ClubPromoModal.jsx +108 -0
- package/dist/components 2/elements/CTAButton.jsx +17 -0
- package/dist/components 2/elements/FixedWidthHeroVideo.jsx +92 -0
- package/dist/components 2/elements/ImageLightbox.jsx +112 -0
- package/dist/components 2/elements/RoundButton.jsx +44 -0
- package/dist/components 2/elements/SmallButton.jsx +35 -0
- package/dist/components 2/elements/Toast.jsx +37 -0
- package/dist/components 2/elements/VideoLightbox.jsx +76 -0
- package/dist/components 2/modals/ItemDetailsModal.jsx +192 -0
- package/dist/components 2/products/CategoryList.jsx +24 -0
- package/dist/components 2/products/PriceRangeSlider.jsx +162 -0
- package/dist/components 2/products/ProductsDisplay.jsx +40 -0
- package/dist/components 2/products/ProductsSidebar.jsx +46 -0
- package/dist/components 2/products/SubcategorySection.jsx +37 -0
- package/dist/context 2/CartContext.jsx +165 -0
- package/dist/context 2/ItemModalContext.jsx +40 -0
- package/dist/hooks 2/useScrollLock.js +52 -0
- package/dist/index 2.js +45 -0
- package/dist/integrations 2/emailService.js +167 -0
- package/dist/styles 2/shared-components.css +29 -0
- package/dist/utils 2/ScrollManager.jsx +85 -0
- package/dist/utils 2/ScrollToTop.jsx +14 -0
- package/package.json +1 -1
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { motion, AnimatePresence } from 'framer-motion';
|
|
3
|
+
import { Link } from 'react-router-dom';
|
|
4
|
+
import { useMediaQuery } from "react-responsive";
|
|
5
|
+
import useScrollLock from '../hooks/useScrollLock';
|
|
6
|
+
|
|
7
|
+
const Menu = ({
|
|
8
|
+
// Business info
|
|
9
|
+
businessInfo = {},
|
|
10
|
+
|
|
11
|
+
// Navigation items
|
|
12
|
+
navigationItems = [],
|
|
13
|
+
|
|
14
|
+
// Auth/Action buttons component
|
|
15
|
+
AuthButtonsComponent = null,
|
|
16
|
+
|
|
17
|
+
// User context (for admin check)
|
|
18
|
+
isAdmin = false,
|
|
19
|
+
|
|
20
|
+
// Customization
|
|
21
|
+
mobileBreakpoint = 900,
|
|
22
|
+
logoClassName = '',
|
|
23
|
+
menuItemClassName = '',
|
|
24
|
+
sidebarWidth = 'w-80',
|
|
25
|
+
|
|
26
|
+
// Callbacks
|
|
27
|
+
onMenuItemClick = () => { },
|
|
28
|
+
|
|
29
|
+
// Children to display above menu items
|
|
30
|
+
children = null,
|
|
31
|
+
}) => {
|
|
32
|
+
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
|
|
33
|
+
const isMobile = useMediaQuery({ maxWidth: mobileBreakpoint });
|
|
34
|
+
|
|
35
|
+
// Close sidebar when clicking outside
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
const handleClickOutside = (event) => {
|
|
38
|
+
if (isSidebarOpen && !event.target.closest('.sidebar') && !event.target.closest('.hamburger')) {
|
|
39
|
+
setIsSidebarOpen(false);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
if (isSidebarOpen) {
|
|
44
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return () => {
|
|
48
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
49
|
+
};
|
|
50
|
+
}, [isSidebarOpen]);
|
|
51
|
+
|
|
52
|
+
useScrollLock(isSidebarOpen && isMobile);
|
|
53
|
+
|
|
54
|
+
const toggleSidebar = () => {
|
|
55
|
+
setIsSidebarOpen(!isSidebarOpen);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const handleMenuItemClick = (item) => {
|
|
59
|
+
setIsSidebarOpen(false);
|
|
60
|
+
onMenuItemClick(item);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const DesktopMenu = () => (
|
|
64
|
+
<nav className="sticky top-0 z-50 bg-menu border-b-2 border-primary">
|
|
65
|
+
{/* Parent container with two vertically stacked sections */}
|
|
66
|
+
<div className="w-full">
|
|
67
|
+
|
|
68
|
+
{/* Top section - Logo and Children content */}
|
|
69
|
+
{children && (<div className="w-full flex items-center py-4 px-6">
|
|
70
|
+
{/* Logo - takes only required space */}
|
|
71
|
+
<Link to="/" className={`flex-shrink-0 ${logoClassName}`}>
|
|
72
|
+
<div className="relative w-24 h-12 lg:w-32 lg:h-16 overflow-hidden flex items-center justify-center">
|
|
73
|
+
<img
|
|
74
|
+
src={businessInfo.logo}
|
|
75
|
+
alt={businessInfo.name}
|
|
76
|
+
className="relative z-10 w-full h-full object-contain"
|
|
77
|
+
onError={(e) => {
|
|
78
|
+
e.target.style.display = 'none';
|
|
79
|
+
e.target.nextElementSibling.style.display = 'flex';
|
|
80
|
+
}}
|
|
81
|
+
/>
|
|
82
|
+
{/* Fallback text */}
|
|
83
|
+
<div
|
|
84
|
+
className="relative z-10 w-full h-full flex items-center justify-center text-primary text-xs font-bold"
|
|
85
|
+
style={{ display: 'none' }}
|
|
86
|
+
>
|
|
87
|
+
{businessInfo.name?.slice(0, 2) || ''}
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
</Link>
|
|
91
|
+
|
|
92
|
+
{/* Children - grows to fill available space */}
|
|
93
|
+
<div className="flex-grow">
|
|
94
|
+
{children}
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
)}
|
|
98
|
+
|
|
99
|
+
{/* Bottom section - Menu navigation bar */}
|
|
100
|
+
<div className="w-full px-6 py-4 flex justify-between items-center">
|
|
101
|
+
{/* Left side - Auth buttons */}
|
|
102
|
+
<div className="flex items-center">
|
|
103
|
+
{AuthButtonsComponent && <AuthButtonsComponent />}
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
{/* Center / Right side - Menu items */}
|
|
107
|
+
<div className="flex-1 flex justify-center">
|
|
108
|
+
<div className="flex items-center space-x-6 space-x-reverse" dir="rtl">
|
|
109
|
+
{navigationItems.map((item, index) => (
|
|
110
|
+
item.adminRoute && !isAdmin ? null : (
|
|
111
|
+
<Link
|
|
112
|
+
key={index}
|
|
113
|
+
to={item.href}
|
|
114
|
+
onClick={() => handleMenuItemClick(item)}
|
|
115
|
+
className={`subtitle font-normal cursor-pointer menu-item-hover px-4 py-2 rounded-md text transition-colors duration-500 ease-in-out hover:text-primary ${menuItemClassName}`}
|
|
116
|
+
>
|
|
117
|
+
{item.label}
|
|
118
|
+
</Link>
|
|
119
|
+
)
|
|
120
|
+
))}
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
{/* Right Side Render logo here if no children */}
|
|
125
|
+
{!children && (
|
|
126
|
+
<Link to="/" className={`flex-shrink-0 ${logoClassName}`}>
|
|
127
|
+
<div className="relative w-24 h-12 lg:w-32 lg:h-16 overflow-hidden flex items-center justify-center">
|
|
128
|
+
<img
|
|
129
|
+
src={businessInfo.logo}
|
|
130
|
+
alt={businessInfo.name}
|
|
131
|
+
className="relative z-10 w-full h-full object-contain"
|
|
132
|
+
onError={(e) => {
|
|
133
|
+
e.target.style.display = 'none';
|
|
134
|
+
e.target.nextElementSibling.style.display = 'flex';
|
|
135
|
+
}}
|
|
136
|
+
/>
|
|
137
|
+
{/* Fallback text */}
|
|
138
|
+
<div
|
|
139
|
+
className="relative z-10 w-full h-full flex items-center justify-center text-primary text-xs font-bold"
|
|
140
|
+
style={{ display: 'none' }}
|
|
141
|
+
>
|
|
142
|
+
{businessInfo.name?.slice(0, 2) || ''}
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
</Link>
|
|
146
|
+
)}
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
</nav>
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// Mobile Menu Component
|
|
153
|
+
const MobileMenu = () => (
|
|
154
|
+
<>
|
|
155
|
+
<nav className="sticky top-0 z-50 bg-menu px-4 py-2">
|
|
156
|
+
<div className="flex justify-between items-center">
|
|
157
|
+
{AuthButtonsComponent && <AuthButtonsComponent isMobile={true} />}
|
|
158
|
+
|
|
159
|
+
{/* Mobile Logo */}
|
|
160
|
+
<Link to="/" className={`text-primary font-bold text-xl ${logoClassName}`}>
|
|
161
|
+
<div className="text-primary font-bold text-lg">
|
|
162
|
+
<div className="w-25 h-12 overflow-hidden flex items-center justify-center">
|
|
163
|
+
<img
|
|
164
|
+
src={businessInfo.logo}
|
|
165
|
+
alt={businessInfo.name}
|
|
166
|
+
className="w-full h-full object-contain"
|
|
167
|
+
onError={(e) => {
|
|
168
|
+
e.target.style.display = 'none';
|
|
169
|
+
e.target.nextElementSibling.style.display = 'flex';
|
|
170
|
+
}}
|
|
171
|
+
/>
|
|
172
|
+
{/* Fallback text */}
|
|
173
|
+
<div
|
|
174
|
+
className="w-full h-full flex items-center justify-center text-primary text-xs font-bold"
|
|
175
|
+
style={{ display: 'none' }}
|
|
176
|
+
>
|
|
177
|
+
{businessInfo.name?.slice(0, 2) || ''}
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
</Link>
|
|
182
|
+
|
|
183
|
+
{/* Children next to logo */}
|
|
184
|
+
{children && (
|
|
185
|
+
<div>
|
|
186
|
+
{children}
|
|
187
|
+
</div>
|
|
188
|
+
)}
|
|
189
|
+
|
|
190
|
+
{/* Hamburger button */}
|
|
191
|
+
<button
|
|
192
|
+
className="hamburger flex flex-col justify-center items-center w-8 h-8 focus:outline-none text-main"
|
|
193
|
+
onClick={toggleSidebar}
|
|
194
|
+
aria-label="תפריט"
|
|
195
|
+
>
|
|
196
|
+
<span className={`hamburger-line block w-6 h-0.5 mb-1 ${isSidebarOpen ? 'rotate-45 translate-y-1.5' : ''}`} style={{ backgroundColor: 'var(--text)' }}></span>
|
|
197
|
+
<span className={`hamburger-line block w-6 h-0.5 mb-1 ${isSidebarOpen ? 'opacity-0' : ''}`} style={{ backgroundColor: 'var(--text)' }}></span>
|
|
198
|
+
<span className={`hamburger-line block w-6 h-0.5 ${isSidebarOpen ? '-rotate-45 -translate-y-1.5' : ''}`} style={{ backgroundColor: 'var(--text)' }}></span>
|
|
199
|
+
</button>
|
|
200
|
+
</div>
|
|
201
|
+
</nav>
|
|
202
|
+
|
|
203
|
+
{/* Overlay + Sidebar (animated) */}
|
|
204
|
+
<AnimatePresence>
|
|
205
|
+
{isSidebarOpen && (
|
|
206
|
+
<>
|
|
207
|
+
{/* Overlay fade */}
|
|
208
|
+
<motion.div
|
|
209
|
+
key="overlay"
|
|
210
|
+
initial={{ opacity: 0 }}
|
|
211
|
+
animate={{ opacity: 0.5 }}
|
|
212
|
+
exit={{ opacity: 0 }}
|
|
213
|
+
transition={{ duration: 0.2 }}
|
|
214
|
+
className="fixed inset-0 bg-black z-40 supports-[height:100dvh]:h-[100dvh]"
|
|
215
|
+
onClick={() => setIsSidebarOpen(false)}
|
|
216
|
+
aria-hidden="true"
|
|
217
|
+
/>
|
|
218
|
+
|
|
219
|
+
{/* Sidebar spring slide */}
|
|
220
|
+
<motion.aside
|
|
221
|
+
key="sidebar"
|
|
222
|
+
initial={{ x: '100%' }}
|
|
223
|
+
animate={{ x: 0 }}
|
|
224
|
+
exit={{ x: '100%' }}
|
|
225
|
+
transition={{ type: 'spring', stiffness: 320, damping: 28, mass: 0.9 }}
|
|
226
|
+
className={`sidebar fixed top-0 right-0 h-full ${sidebarWidth} bg-white shadow-lg z-50`}
|
|
227
|
+
role="dialog"
|
|
228
|
+
aria-label="תפריט צד"
|
|
229
|
+
>
|
|
230
|
+
<div className="p-6">
|
|
231
|
+
{/* Close button */}
|
|
232
|
+
<div className="flex justify-start mb-8">
|
|
233
|
+
<button
|
|
234
|
+
onClick={() => setIsSidebarOpen(false)}
|
|
235
|
+
className="text-black hover:text-gray-700 text-2xl"
|
|
236
|
+
aria-label="סגור תפריט"
|
|
237
|
+
>
|
|
238
|
+
×
|
|
239
|
+
</button>
|
|
240
|
+
</div>
|
|
241
|
+
|
|
242
|
+
{/* Menu items */}
|
|
243
|
+
<div className="flex flex-col space-y-3">
|
|
244
|
+
{navigationItems.map((item, index) => (
|
|
245
|
+
item.adminRoute && !isAdmin ? null : (
|
|
246
|
+
<Link
|
|
247
|
+
key={index}
|
|
248
|
+
to={item.href}
|
|
249
|
+
onClick={() => handleMenuItemClick(item)}
|
|
250
|
+
className={`text-lg py-3 px-2 text-black text-right ${menuItemClassName}`}
|
|
251
|
+
>
|
|
252
|
+
{item.label}
|
|
253
|
+
</Link>
|
|
254
|
+
)
|
|
255
|
+
))}
|
|
256
|
+
</div>
|
|
257
|
+
</div>
|
|
258
|
+
</motion.aside>
|
|
259
|
+
</>
|
|
260
|
+
)}
|
|
261
|
+
</AnimatePresence>
|
|
262
|
+
</>
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
return isMobile ? <MobileMenu /> : <DesktopMenu />;
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
export default Menu;
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { motion } from 'framer-motion';
|
|
3
|
+
import RoundButton from './elements/RoundButton';
|
|
4
|
+
import {
|
|
5
|
+
ShoppingBag,
|
|
6
|
+
ChevronDown,
|
|
7
|
+
ChevronUp,
|
|
8
|
+
LogIn,
|
|
9
|
+
Calendar,
|
|
10
|
+
CreditCard,
|
|
11
|
+
ExternalLink,
|
|
12
|
+
Clock,
|
|
13
|
+
FileText,
|
|
14
|
+
Package,
|
|
15
|
+
Truck,
|
|
16
|
+
MapPin
|
|
17
|
+
} from 'lucide-react';
|
|
18
|
+
|
|
19
|
+
const statusMap = {
|
|
20
|
+
link_pending: { label: 'ממתין לתשלום', color: 'bg-yellow-100 text-yellow-800 border-yellow-200' },
|
|
21
|
+
link_requested: { label: 'ממתין לתשלום', color: 'bg-yellow-100 text-yellow-800 border-yellow-200' },
|
|
22
|
+
payment_completed: { label: 'הושלמה', color: 'bg-green-100 text-green-800 border-green-200' },
|
|
23
|
+
payment_failed: { label: 'תשלום נכשל', color: 'bg-red-100 text-red-800 border-red-200' },
|
|
24
|
+
payment_cancelled: { label: 'בוטלה', color: 'bg-gray-100 text-gray-800 border-gray-200' },
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const MyOrdersDisplay = ({
|
|
28
|
+
// Data
|
|
29
|
+
orders = [],
|
|
30
|
+
loading = false,
|
|
31
|
+
isAuthenticated = false,
|
|
32
|
+
currentUser = null,
|
|
33
|
+
|
|
34
|
+
// Actions
|
|
35
|
+
onLoginClick,
|
|
36
|
+
onProductsClick,
|
|
37
|
+
onPaymentClick,
|
|
38
|
+
onInvoiceClick,
|
|
39
|
+
|
|
40
|
+
// Customization
|
|
41
|
+
formatDate,
|
|
42
|
+
isPaymentLinkValid,
|
|
43
|
+
className = '',
|
|
44
|
+
...props
|
|
45
|
+
}) => {
|
|
46
|
+
const [expandedItems, setExpandedItems] = useState(new Set());
|
|
47
|
+
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (orders.length > 0) {
|
|
50
|
+
setExpandedItems(new Set(orders.map(order => order.id)));
|
|
51
|
+
}
|
|
52
|
+
}, [orders.length]);
|
|
53
|
+
|
|
54
|
+
const toggleItemsExpansion = (orderId) => {
|
|
55
|
+
const newExpanded = new Set(expandedItems);
|
|
56
|
+
if (newExpanded.has(orderId)) {
|
|
57
|
+
newExpanded.delete(orderId);
|
|
58
|
+
} else {
|
|
59
|
+
newExpanded.add(orderId);
|
|
60
|
+
}
|
|
61
|
+
setExpandedItems(newExpanded);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// Default formatDate if not provided
|
|
65
|
+
const defaultFormatDate = (date) => {
|
|
66
|
+
if (!date) return 'לא זמין';
|
|
67
|
+
const dateObj = date.toDate ? date.toDate() : new Date(date);
|
|
68
|
+
return new Intl.DateTimeFormat('he-IL', {
|
|
69
|
+
timeZone: 'Asia/Jerusalem',
|
|
70
|
+
day: '2-digit',
|
|
71
|
+
month: '2-digit',
|
|
72
|
+
year: 'numeric',
|
|
73
|
+
hour: '2-digit',
|
|
74
|
+
minute: '2-digit'
|
|
75
|
+
}).format(dateObj);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// Default isPaymentLinkValid if not provided
|
|
79
|
+
const defaultIsPaymentLinkValid = (order) => {
|
|
80
|
+
if (!order.paymentLink || !order.paymentExpiresAt) return false;
|
|
81
|
+
return new Date() < new Date(order.paymentExpiresAt);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const formatDateFn = formatDate || defaultFormatDate;
|
|
85
|
+
const isPaymentLinkValidFn = isPaymentLinkValid || defaultIsPaymentLinkValid;
|
|
86
|
+
|
|
87
|
+
if (loading) {
|
|
88
|
+
return (
|
|
89
|
+
<div className={`space-y-6 ${className}`} {...props}>
|
|
90
|
+
<div className="glass-card p-8">
|
|
91
|
+
<div className="animate-pulse space-y-4">
|
|
92
|
+
<div className="h-8 bg-gray-200 rounded w-1/3"></div>
|
|
93
|
+
<div className="h-4 bg-gray-200 rounded w-1/2"></div>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
<div className="grid gap-4">
|
|
97
|
+
{[...Array(3)].map((_, i) => (
|
|
98
|
+
<div key={i} className="glass-card p-6 animate-pulse">
|
|
99
|
+
<div className="space-y-3">
|
|
100
|
+
<div className="h-4 bg-gray-200 rounded w-1/4"></div>
|
|
101
|
+
<div className="h-6 bg-gray-200 rounded w-1/6"></div>
|
|
102
|
+
<div className="h-4 bg-gray-200 rounded w-1/3"></div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
))}
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (!isAuthenticated) {
|
|
112
|
+
return (
|
|
113
|
+
<div className={`max-w-md mx-auto mt-20 ${className}`} {...props}>
|
|
114
|
+
<div className="glass-card p-8 text-center">
|
|
115
|
+
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
|
116
|
+
<LogIn className="w-8 h-8 text-blue-600" />
|
|
117
|
+
</div>
|
|
118
|
+
<h2 className="text-2xl font-bold text-main mb-4">נדרשת התחברות</h2>
|
|
119
|
+
<p className="text-main mb-6">
|
|
120
|
+
כדי לצפות בהיסטוריית ההזמנות שלך, יש להתחבר לחשבון
|
|
121
|
+
</p>
|
|
122
|
+
<RoundButton
|
|
123
|
+
onClick={onLoginClick}
|
|
124
|
+
variant="primary"
|
|
125
|
+
>
|
|
126
|
+
התחברות לחשבון
|
|
127
|
+
</RoundButton>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<div className={`container mx-auto px-4 py-8 space-y-8 ${className}`} {...props}>
|
|
135
|
+
{/* Header */}
|
|
136
|
+
<div className="glass-card p-8 text-center">
|
|
137
|
+
<div className="w-16 h-16 bg-gradient-to-r from-orange-400 to-pink-400 rounded-full flex items-center justify-center mx-auto mb-4">
|
|
138
|
+
<ShoppingBag className="w-8 h-8 text-white" />
|
|
139
|
+
</div>
|
|
140
|
+
<h1 className="text-3xl font-bold text-main mb-2">ההזמנות שלי</h1>
|
|
141
|
+
<p className="text-main">
|
|
142
|
+
שלום {currentUser?.firstName || currentUser?.displayName || currentUser?.name}, כאן תוכל לראות את כל ההזמנות שביצעת
|
|
143
|
+
</p>
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
{/* Orders List */}
|
|
147
|
+
<div className="space-y-4" dir="rtl">
|
|
148
|
+
{orders.length === 0 ? (
|
|
149
|
+
<div className="glass-card p-12 text-center">
|
|
150
|
+
<div className="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
|
151
|
+
<ShoppingBag className="w-8 h-8 text-main" />
|
|
152
|
+
</div>
|
|
153
|
+
<h3 className="text-xl font-bold text-main mb-2">אין הזמנות</h3>
|
|
154
|
+
<p className="text-main mb-6">עדיין לא ביצעת הזמנות. בואו נתחיל לקנות!</p>
|
|
155
|
+
<RoundButton
|
|
156
|
+
onClick={onProductsClick}
|
|
157
|
+
variant="primary"
|
|
158
|
+
>
|
|
159
|
+
לצפייה במוצרים
|
|
160
|
+
</RoundButton>
|
|
161
|
+
</div>
|
|
162
|
+
) : (
|
|
163
|
+
orders.map((order) => (
|
|
164
|
+
<motion.div
|
|
165
|
+
key={order.id}
|
|
166
|
+
initial={{ opacity: 0, y: 20 }}
|
|
167
|
+
animate={{ opacity: 1, y: 0 }}
|
|
168
|
+
className="glass-card border-0"
|
|
169
|
+
>
|
|
170
|
+
{/* Order Header */}
|
|
171
|
+
<div className="p-6 border-b border-white/20">
|
|
172
|
+
<div className="flex justify-between items-start mb-4">
|
|
173
|
+
<div>
|
|
174
|
+
<h3 className="text-primary text-lg font-bold">
|
|
175
|
+
הזמנה #{order.simpleOrderNumber || order.id?.slice(-8)}
|
|
176
|
+
</h3>
|
|
177
|
+
<div className="flex items-center gap-4 mt-2 text-sm text-main">
|
|
178
|
+
<div className="flex items-center gap-1">
|
|
179
|
+
<Calendar className="w-4 h-4" />
|
|
180
|
+
{formatDateFn(order.createdAt)}
|
|
181
|
+
</div>
|
|
182
|
+
<div className="flex items-center gap-1">
|
|
183
|
+
<CreditCard className="w-4 h-4" />
|
|
184
|
+
₪{order.totalAmount}
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
<span className={`px-3 py-1 rounded-full text-xs font-bold border ${statusMap[order.paymentStatus]?.color || 'bg-gray-100 text-main'
|
|
189
|
+
}`}>
|
|
190
|
+
{statusMap[order.paymentStatus]?.label || order.paymentStatus}
|
|
191
|
+
</span>
|
|
192
|
+
</div>
|
|
193
|
+
|
|
194
|
+
{/* Delivery Info */}
|
|
195
|
+
<div className="text-sm space-y-1">
|
|
196
|
+
<div className="flex items-center gap-2 text-primary">
|
|
197
|
+
{order.deliveryMethod === 'delivery' ? (
|
|
198
|
+
<>
|
|
199
|
+
<Truck className="w-4 h-4" />
|
|
200
|
+
<span><strong>משלוח</strong></span>
|
|
201
|
+
</>
|
|
202
|
+
) : (
|
|
203
|
+
order.orderType === 'product' && (
|
|
204
|
+
<>
|
|
205
|
+
<Package className="w-4 h-4" />
|
|
206
|
+
<span><strong>איסוף עצמי</strong></span>
|
|
207
|
+
</>)
|
|
208
|
+
)}
|
|
209
|
+
</div>
|
|
210
|
+
{order.deliveryMethod === 'delivery' && order.deliveryAddress && (
|
|
211
|
+
<div className="flex items-center gap-2 text-main">
|
|
212
|
+
<MapPin className="w-4 h-4" />
|
|
213
|
+
<span>{order.deliveryCity}, {order.deliveryAddress}</span>
|
|
214
|
+
</div>
|
|
215
|
+
)}
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
|
|
219
|
+
{/* Order Items */}
|
|
220
|
+
<div className="p-6">
|
|
221
|
+
{order.items && order.items.length > 0 && (
|
|
222
|
+
<div className="mb-4">
|
|
223
|
+
<button
|
|
224
|
+
onClick={() => toggleItemsExpansion(order.id)}
|
|
225
|
+
className="flex items-center gap-2 text-sm font-medium text-primary hover:text-primary-dark transition-colors"
|
|
226
|
+
>
|
|
227
|
+
פריטי ההזמנה ({order.items.length})
|
|
228
|
+
{expandedItems.has(order.id) ? (
|
|
229
|
+
<ChevronUp className="w-4 h-4" />
|
|
230
|
+
) : (
|
|
231
|
+
<ChevronDown className="w-4 h-4" />
|
|
232
|
+
)}
|
|
233
|
+
</button>
|
|
234
|
+
|
|
235
|
+
{expandedItems.has(order.id) && (
|
|
236
|
+
<div className="mt-3 p-4 bg-white/10 rounded-lg space-y-2">
|
|
237
|
+
{order.items.map((item, index) => (
|
|
238
|
+
<div key={index} className="flex justify-between items-center text-sm text-main">
|
|
239
|
+
<div>
|
|
240
|
+
<span className="font-medium">{item.name || item.product_name}</span>
|
|
241
|
+
<span className="text-main mr-2">× {item.quantity}</span>
|
|
242
|
+
</div>
|
|
243
|
+
<div className="flex items-center gap-2">
|
|
244
|
+
<span className="text-main">ליח:'</span>
|
|
245
|
+
<span className="text-price">₪{item.unit_price}</span>
|
|
246
|
+
<span className="text-main">סה"כ:</span>
|
|
247
|
+
<span className="font-bold text-price">₪{item.total_price}</span>
|
|
248
|
+
</div>
|
|
249
|
+
</div>
|
|
250
|
+
))}
|
|
251
|
+
{order.deliveryFee > 0 && order.deliveryMethod === "delivery" && (
|
|
252
|
+
<div className="flex justify-between items-center text-sm text-main">
|
|
253
|
+
<div>
|
|
254
|
+
<span className="font-medium">משלוח</span>
|
|
255
|
+
</div>
|
|
256
|
+
<div className="flex items-center gap-2">
|
|
257
|
+
<span className="font-bold text-price">₪{order.deliveryFee}</span>
|
|
258
|
+
</div>
|
|
259
|
+
</div>)}
|
|
260
|
+
</div>
|
|
261
|
+
)}
|
|
262
|
+
</div>
|
|
263
|
+
)}
|
|
264
|
+
|
|
265
|
+
{/* Payment Actions */}
|
|
266
|
+
<div className="flex flex-wrap gap-3">
|
|
267
|
+
{/* Payment Link */}
|
|
268
|
+
{order.paymentStatus === 'pending' && order.paymentLink && (
|
|
269
|
+
<div>
|
|
270
|
+
{isPaymentLinkValidFn(order) ? (
|
|
271
|
+
<RoundButton
|
|
272
|
+
onClick={() => onPaymentClick(order)}
|
|
273
|
+
variant="primary"
|
|
274
|
+
size="small"
|
|
275
|
+
>
|
|
276
|
+
<ExternalLink className="w-4 h-4 ml-1" />
|
|
277
|
+
השלמת תשלום
|
|
278
|
+
</RoundButton>
|
|
279
|
+
) : (
|
|
280
|
+
<div className="text-sm text-red-600 flex items-center gap-2">
|
|
281
|
+
<Clock className="w-4 h-4" />
|
|
282
|
+
פג תוקף קישור התשלום
|
|
283
|
+
</div>
|
|
284
|
+
)}
|
|
285
|
+
</div>
|
|
286
|
+
)}
|
|
287
|
+
|
|
288
|
+
{/* Invoice Link */}
|
|
289
|
+
{order.invoice_url && (
|
|
290
|
+
<RoundButton
|
|
291
|
+
onClick={() => onInvoiceClick(order)}
|
|
292
|
+
variant="outline"
|
|
293
|
+
size="small"
|
|
294
|
+
>
|
|
295
|
+
<div className='flex'>
|
|
296
|
+
<FileText className="w-4 h-4 ml-1" />
|
|
297
|
+
הצג חשבונית
|
|
298
|
+
</div>
|
|
299
|
+
</RoundButton>
|
|
300
|
+
)}
|
|
301
|
+
</div>
|
|
302
|
+
</div>
|
|
303
|
+
</motion.div>
|
|
304
|
+
))
|
|
305
|
+
)}
|
|
306
|
+
</div>
|
|
307
|
+
</div>
|
|
308
|
+
);
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
export default MyOrdersDisplay;
|