hey-pharmacist-ecommerce 1.0.0
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/README.md +269 -0
- package/dist/index.d.mts +564 -0
- package/dist/index.d.ts +564 -0
- package/dist/index.js +7541 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +7485 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +70 -0
- package/src/components/CartItem.tsx +103 -0
- package/src/components/EmptyState.tsx +27 -0
- package/src/components/Footer.tsx +147 -0
- package/src/components/Header.tsx +151 -0
- package/src/components/OrderCard.tsx +98 -0
- package/src/components/ProductCard.tsx +122 -0
- package/src/components/ui/Badge.tsx +31 -0
- package/src/components/ui/Button.tsx +61 -0
- package/src/components/ui/Input.tsx +45 -0
- package/src/components/ui/Modal.tsx +79 -0
- package/src/components/ui/Skeleton.tsx +46 -0
- package/src/hooks/useOrders.ts +98 -0
- package/src/hooks/useProducts.ts +125 -0
- package/src/index.ts +71 -0
- package/src/lib/Apis/api.ts +46 -0
- package/src/lib/Apis/apis/addresses-api.ts +1461 -0
- package/src/lib/Apis/apis/auth-api.ts +945 -0
- package/src/lib/Apis/apis/blogs-api.ts +582 -0
- package/src/lib/Apis/apis/cart-api.ts +456 -0
- package/src/lib/Apis/apis/categories-api.ts +725 -0
- package/src/lib/Apis/apis/chats-api.ts +1101 -0
- package/src/lib/Apis/apis/contact-us-api.ts +394 -0
- package/src/lib/Apis/apis/discounts-api.ts +763 -0
- package/src/lib/Apis/apis/drafts-api.ts +448 -0
- package/src/lib/Apis/apis/events-api.ts +1311 -0
- package/src/lib/Apis/apis/file-proccesor-api.ts +293 -0
- package/src/lib/Apis/apis/health-api.ts +119 -0
- package/src/lib/Apis/apis/images-api.ts +271 -0
- package/src/lib/Apis/apis/inventory-api.ts +375 -0
- package/src/lib/Apis/apis/marketing-api.ts +3099 -0
- package/src/lib/Apis/apis/notifications-api.ts +843 -0
- package/src/lib/Apis/apis/open-aiapi.ts +513 -0
- package/src/lib/Apis/apis/orders-api.ts +1343 -0
- package/src/lib/Apis/apis/payment-methods-api.ts +411 -0
- package/src/lib/Apis/apis/payments-api.ts +469 -0
- package/src/lib/Apis/apis/product-attributes-api.ts +538 -0
- package/src/lib/Apis/apis/product-favorite-list-api.ts +321 -0
- package/src/lib/Apis/apis/product-variants-api.ts +648 -0
- package/src/lib/Apis/apis/products-api.ts +1442 -0
- package/src/lib/Apis/apis/review-api.ts +1383 -0
- package/src/lib/Apis/apis/roles-api.ts +614 -0
- package/src/lib/Apis/apis/shipping-api.ts +703 -0
- package/src/lib/Apis/apis/statistics-api.ts +234 -0
- package/src/lib/Apis/apis/stores-api.ts +1519 -0
- package/src/lib/Apis/apis/sub-categories-api.ts +1208 -0
- package/src/lib/Apis/apis/user-groups-api.ts +1198 -0
- package/src/lib/Apis/apis/users-api.ts +1403 -0
- package/src/lib/Apis/apis/web-hooks-api.ts +198 -0
- package/src/lib/Apis/base.ts +70 -0
- package/src/lib/Apis/configuration.ts +75 -0
- package/src/lib/Apis/index.ts +17 -0
- package/src/lib/Apis/models/add-contact-to-list-dto.ts +33 -0
- package/src/lib/Apis/models/add-message-dto.ts +56 -0
- package/src/lib/Apis/models/address-created-request.ts +134 -0
- package/src/lib/Apis/models/address.ts +164 -0
- package/src/lib/Apis/models/allow-user-credit-dto.ts +27 -0
- package/src/lib/Apis/models/appointment.ts +75 -0
- package/src/lib/Apis/models/available-dates-dto.ts +33 -0
- package/src/lib/Apis/models/available-suggested-dates-dto.ts +33 -0
- package/src/lib/Apis/models/blog.ts +75 -0
- package/src/lib/Apis/models/browser-stats-response-dto.ts +40 -0
- package/src/lib/Apis/models/bulk-move-subcategories-dto.ts +33 -0
- package/src/lib/Apis/models/bulk-unassign-subcategories-dto.ts +27 -0
- package/src/lib/Apis/models/campaign-content-response-dto.ts +40 -0
- package/src/lib/Apis/models/campaign-draft-dto.ts +175 -0
- package/src/lib/Apis/models/campaign-draft-response-dto.ts +40 -0
- package/src/lib/Apis/models/campaign-draft-schedule-dto.ts +49 -0
- package/src/lib/Apis/models/campaign-draft-schedule-response-dto.ts +40 -0
- package/src/lib/Apis/models/campaign-draft-sending-dto.ts +43 -0
- package/src/lib/Apis/models/campaign-draft-sending-response-dto.ts +40 -0
- package/src/lib/Apis/models/cart-body-dto.ts +40 -0
- package/src/lib/Apis/models/cart-body-populated.ts +47 -0
- package/src/lib/Apis/models/cart-item-populated.ts +41 -0
- package/src/lib/Apis/models/cart-item.ts +33 -0
- package/src/lib/Apis/models/cart-response-dto.ts +70 -0
- package/src/lib/Apis/models/categories-paginated-response-dto.ts +52 -0
- package/src/lib/Apis/models/category-filters.ts +40 -0
- package/src/lib/Apis/models/category-populated.ts +106 -0
- package/src/lib/Apis/models/category-sub-category-populated.ts +51 -0
- package/src/lib/Apis/models/category.ts +99 -0
- package/src/lib/Apis/models/categorys-headlines-response-dto.ts +40 -0
- package/src/lib/Apis/models/change-user-email-dto.ts +27 -0
- package/src/lib/Apis/models/chat.ts +33 -0
- package/src/lib/Apis/models/check-notifications-response-dto.ts +33 -0
- package/src/lib/Apis/models/contact-aggregated-stats-response-dto.ts +40 -0
- package/src/lib/Apis/models/contact-full-dto.ts +93 -0
- package/src/lib/Apis/models/contact-full-response-dto.ts +40 -0
- package/src/lib/Apis/models/contact-list-stats-response-dto.ts +40 -0
- package/src/lib/Apis/models/contact-lists-response-dto.ts +40 -0
- package/src/lib/Apis/models/contact-us.ts +81 -0
- package/src/lib/Apis/models/country-stats-response-dto.ts +40 -0
- package/src/lib/Apis/models/create-address-dto.ts +134 -0
- package/src/lib/Apis/models/create-blog-dto.ts +45 -0
- package/src/lib/Apis/models/create-category-dto.ts +45 -0
- package/src/lib/Apis/models/create-chat-dto.ts +39 -0
- package/src/lib/Apis/models/create-contact-dto.ts +39 -0
- package/src/lib/Apis/models/create-contact-list-dto.ts +27 -0
- package/src/lib/Apis/models/create-discount-dto.ts +208 -0
- package/src/lib/Apis/models/create-draft-dto.ts +67 -0
- package/src/lib/Apis/models/create-email-template-dto.ts +51 -0
- package/src/lib/Apis/models/create-event-dto.ts +52 -0
- package/src/lib/Apis/models/create-marketing-campaign-dto.ts +81 -0
- package/src/lib/Apis/models/create-message-dto.ts +57 -0
- package/src/lib/Apis/models/create-notification-dto.ts +75 -0
- package/src/lib/Apis/models/create-product-attribute-dto.ts +33 -0
- package/src/lib/Apis/models/create-product-dto.ts +94 -0
- package/src/lib/Apis/models/create-review-dto.ts +63 -0
- package/src/lib/Apis/models/create-role-dto.ts +57 -0
- package/src/lib/Apis/models/create-single-variant-product-dto.ts +155 -0
- package/src/lib/Apis/models/create-store-address-dto.ts +134 -0
- package/src/lib/Apis/models/create-store-dto.ts +105 -0
- package/src/lib/Apis/models/create-sub-category-dto.ts +45 -0
- package/src/lib/Apis/models/create-user-dto.ts +89 -0
- package/src/lib/Apis/models/create-user-group-dto.ts +39 -0
- package/src/lib/Apis/models/create-variant-dto.ts +119 -0
- package/src/lib/Apis/models/create-zone-dto.ts +82 -0
- package/src/lib/Apis/models/custom-product-dto.ts +63 -0
- package/src/lib/Apis/models/default-payment-method-request-dto.ts +27 -0
- package/src/lib/Apis/models/delete-file-dto.ts +27 -0
- package/src/lib/Apis/models/delete-many-files-dto.ts +27 -0
- package/src/lib/Apis/models/discount-paginated-response.ts +52 -0
- package/src/lib/Apis/models/discount.ts +245 -0
- package/src/lib/Apis/models/discounts-insights-dto.ts +57 -0
- package/src/lib/Apis/models/draft.ts +79 -0
- package/src/lib/Apis/models/email-invoice-dto.ts +45 -0
- package/src/lib/Apis/models/email-template-response-dto.ts +117 -0
- package/src/lib/Apis/models/event.ts +76 -0
- package/src/lib/Apis/models/extended-product-dto.ts +204 -0
- package/src/lib/Apis/models/fileproccesor-upload-body.ts +27 -0
- package/src/lib/Apis/models/forget-password.ts +27 -0
- package/src/lib/Apis/models/frequently-bought-product-dto.ts +71 -0
- package/src/lib/Apis/models/general-stats-response-dto.ts +40 -0
- package/src/lib/Apis/models/generate-day-slots-dto.ts +51 -0
- package/src/lib/Apis/models/generate-month-slots-dto.ts +57 -0
- package/src/lib/Apis/models/generate-week-slots-dto.ts +57 -0
- package/src/lib/Apis/models/google-analytics-request-dto.ts +55 -0
- package/src/lib/Apis/models/google-analytics-response-dto.ts +39 -0
- package/src/lib/Apis/models/group-with-no-users-dto.ts +75 -0
- package/src/lib/Apis/models/group-with-users-dto.ts +76 -0
- package/src/lib/Apis/models/images-upload-body.ts +27 -0
- package/src/lib/Apis/models/index.ts +197 -0
- package/src/lib/Apis/models/inventory-paginated-response.ts +75 -0
- package/src/lib/Apis/models/link-stats-response-dto.ts +40 -0
- package/src/lib/Apis/models/login-dto.ts +33 -0
- package/src/lib/Apis/models/manual-discount.ts +49 -0
- package/src/lib/Apis/models/manual-order-dto.ts +133 -0
- package/src/lib/Apis/models/manual-shipping-dto.ts +45 -0
- package/src/lib/Apis/models/marketing-campaign-content-dto.ts +27 -0
- package/src/lib/Apis/models/marketing-list-contact-dto.ts +51 -0
- package/src/lib/Apis/models/move-subcategory-dto.ts +27 -0
- package/src/lib/Apis/models/my-favorite-list-dto.ts +52 -0
- package/src/lib/Apis/models/notification.ts +93 -0
- package/src/lib/Apis/models/object-id.ts +21 -0
- package/src/lib/Apis/models/open-api.ts +33 -0
- package/src/lib/Apis/models/order-paginated-response.ts +52 -0
- package/src/lib/Apis/models/order.ts +214 -0
- package/src/lib/Apis/models/orders-insights-dto.ts +69 -0
- package/src/lib/Apis/models/paginated-products-dto.ts +52 -0
- package/src/lib/Apis/models/payment-method-data.ts +34 -0
- package/src/lib/Apis/models/payment-method.ts +51 -0
- package/src/lib/Apis/models/payment-time-line-dto.ts +56 -0
- package/src/lib/Apis/models/payment.ts +182 -0
- package/src/lib/Apis/models/payments-insights-dto.ts +69 -0
- package/src/lib/Apis/models/payments-paginated-response.ts +52 -0
- package/src/lib/Apis/models/pick-type-class.ts +51 -0
- package/src/lib/Apis/models/populated-chat-dto.ts +95 -0
- package/src/lib/Apis/models/populated-discount.ts +246 -0
- package/src/lib/Apis/models/populated-order.ts +209 -0
- package/src/lib/Apis/models/prefered-pick-or-delivery-time-dto.ts +33 -0
- package/src/lib/Apis/models/price-range.ts +33 -0
- package/src/lib/Apis/models/product-attribute.ts +57 -0
- package/src/lib/Apis/models/product-variant.ts +167 -0
- package/src/lib/Apis/models/product.ts +136 -0
- package/src/lib/Apis/models/products-insights-dto.ts +45 -0
- package/src/lib/Apis/models/rate-dto.ts +123 -0
- package/src/lib/Apis/models/refill-request-dto.ts +75 -0
- package/src/lib/Apis/models/refill-request.ts +105 -0
- package/src/lib/Apis/models/register-or-login-with-gmail.ts +27 -0
- package/src/lib/Apis/models/reserve-appointment.ts +261 -0
- package/src/lib/Apis/models/review.ts +93 -0
- package/src/lib/Apis/models/role.ts +69 -0
- package/src/lib/Apis/models/schedule-campaign-draft-dto.ts +27 -0
- package/src/lib/Apis/models/send-test-email-dto.ts +28 -0
- package/src/lib/Apis/models/shallow-parent-category-dto.ts +33 -0
- package/src/lib/Apis/models/shipment-details-dto.ts +88 -0
- package/src/lib/Apis/models/shipment-status-dto.ts +117 -0
- package/src/lib/Apis/models/shipment-with-order.ts +105 -0
- package/src/lib/Apis/models/shipment.ts +104 -0
- package/src/lib/Apis/models/shipping-info.ts +88 -0
- package/src/lib/Apis/models/single-browser-stats-dto.ts +45 -0
- package/src/lib/Apis/models/single-contact-aggregated-stats-dto.ts +129 -0
- package/src/lib/Apis/models/single-contact-list-stats-dto.ts +117 -0
- package/src/lib/Apis/models/single-country-stats-dto.ts +39 -0
- package/src/lib/Apis/models/single-general-stats.ts +153 -0
- package/src/lib/Apis/models/single-link-stats-dto.ts +39 -0
- package/src/lib/Apis/models/single-message-populated.ts +59 -0
- package/src/lib/Apis/models/single-notification-dto.ts +99 -0
- package/src/lib/Apis/models/single-product-media.ts +74 -0
- package/src/lib/Apis/models/single-recipient-dto.ts +33 -0
- package/src/lib/Apis/models/single-suggest-attribute.ts +33 -0
- package/src/lib/Apis/models/statistic-dto.ts +171 -0
- package/src/lib/Apis/models/store-entity.ts +117 -0
- package/src/lib/Apis/models/store.ts +135 -0
- package/src/lib/Apis/models/sub-category-headlines-only-response-dto.ts +39 -0
- package/src/lib/Apis/models/sub-category.ts +93 -0
- package/src/lib/Apis/models/suggest-attributes.ts +28 -0
- package/src/lib/Apis/models/suggested-slot.ts +33 -0
- package/src/lib/Apis/models/table-cell-dto.ts +33 -0
- package/src/lib/Apis/models/table-dto.ts +34 -0
- package/src/lib/Apis/models/tadmin-session-data.ts +47 -0
- package/src/lib/Apis/models/track-dto.ts +94 -0
- package/src/lib/Apis/models/tracking-status-location-base.ts +45 -0
- package/src/lib/Apis/models/tracking-status-substatus.ts +39 -0
- package/src/lib/Apis/models/tracking-status.ts +71 -0
- package/src/lib/Apis/models/transfere-patient-request.ts +123 -0
- package/src/lib/Apis/models/transfere-patients-request-dto.ts +99 -0
- package/src/lib/Apis/models/tuser-session-data.ts +34 -0
- package/src/lib/Apis/models/update-address-dto.ts +134 -0
- package/src/lib/Apis/models/update-blog-dto.ts +45 -0
- package/src/lib/Apis/models/update-campaign-draft-content-dto.ts +27 -0
- package/src/lib/Apis/models/update-category-dto.ts +45 -0
- package/src/lib/Apis/models/update-discount-dto.ts +208 -0
- package/src/lib/Apis/models/update-event-dto.ts +52 -0
- package/src/lib/Apis/models/update-items-order-dto.ts +27 -0
- package/src/lib/Apis/models/update-marketing-camp-draft-dto.ts +81 -0
- package/src/lib/Apis/models/update-message-dto.ts +57 -0
- package/src/lib/Apis/models/update-product-attribute-dto.ts +33 -0
- package/src/lib/Apis/models/update-product-dto.ts +96 -0
- package/src/lib/Apis/models/update-product-variant-dto.ts +119 -0
- package/src/lib/Apis/models/update-refill-request-dto.ts +75 -0
- package/src/lib/Apis/models/update-review-dto.ts +63 -0
- package/src/lib/Apis/models/update-role-dto.ts +57 -0
- package/src/lib/Apis/models/update-store-dto.ts +105 -0
- package/src/lib/Apis/models/update-sub-category-dto.ts +45 -0
- package/src/lib/Apis/models/update-transfere-patients-request-dto.ts +99 -0
- package/src/lib/Apis/models/update-user-dto.ts +239 -0
- package/src/lib/Apis/models/update-user-group-dto.ts +39 -0
- package/src/lib/Apis/models/update-zone-dto.ts +82 -0
- package/src/lib/Apis/models/upload-pdf-body.ts +27 -0
- package/src/lib/Apis/models/used-by.ts +87 -0
- package/src/lib/Apis/models/user-entity.ts +220 -0
- package/src/lib/Apis/models/user-group.ts +75 -0
- package/src/lib/Apis/models/user-insights-dto.ts +39 -0
- package/src/lib/Apis/models/user-with-no-id.ts +226 -0
- package/src/lib/Apis/models/user.ts +232 -0
- package/src/lib/Apis/models/users-paginated-response.ts +52 -0
- package/src/lib/Apis/models/verify-email-dto.ts +33 -0
- package/src/lib/Apis/models/zone-single-size.ts +51 -0
- package/src/lib/Apis/models/zone.ts +106 -0
- package/src/lib/Apis/wrapper.ts +37 -0
- package/src/lib/api/auth.ts +81 -0
- package/src/lib/api/cart.ts +42 -0
- package/src/lib/api/client.ts +118 -0
- package/src/lib/api/orders.ts +53 -0
- package/src/lib/api/products.ts +51 -0
- package/src/lib/api-adapter/auth-adapter.ts +196 -0
- package/src/lib/api-adapter/cart-adapter.ts +193 -0
- package/src/lib/api-adapter/config.ts +76 -0
- package/src/lib/api-adapter/index.ts +13 -0
- package/src/lib/api-adapter/mappers.ts +147 -0
- package/src/lib/api-adapter/orders-adapter.ts +195 -0
- package/src/lib/api-adapter/products-adapter.ts +194 -0
- package/src/lib/types/index.ts +152 -0
- package/src/lib/utils/colors.ts +51 -0
- package/src/lib/utils/format.ts +48 -0
- package/src/providers/AuthProvider.tsx +117 -0
- package/src/providers/CartProvider.tsx +131 -0
- package/src/providers/EcommerceProvider.tsx +34 -0
- package/src/providers/ThemeProvider.tsx +57 -0
- package/src/screens/CartScreen.tsx +140 -0
- package/src/screens/CheckoutScreen.tsx +340 -0
- package/src/screens/CurrentOrdersScreen.tsx +85 -0
- package/src/screens/LoginScreen.tsx +149 -0
- package/src/screens/OrdersScreen.tsx +86 -0
- package/src/screens/ProductDetailScreen.tsx +255 -0
- package/src/screens/ProfileScreen.tsx +211 -0
- package/src/screens/RegisterScreen.tsx +200 -0
- package/src/screens/ShopScreen.tsx +233 -0
- package/src/styles/globals.css +51 -0
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "hey-pharmacist-ecommerce",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Multi-tenant e-commerce package for Next.js",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"src"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"dev": "next dev",
|
|
14
|
+
"build": "tsup",
|
|
15
|
+
"lint": "next lint",
|
|
16
|
+
"type-check": "tsc --noEmit"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"react": "^18.2.0",
|
|
20
|
+
"react-dom": "^18.2.0",
|
|
21
|
+
"next": "^14.0.0",
|
|
22
|
+
"axios": "^1.6.0",
|
|
23
|
+
"framer-motion": "^10.16.0",
|
|
24
|
+
"lucide-react": "^0.294.0",
|
|
25
|
+
"react-hook-form": "^7.48.0",
|
|
26
|
+
"zod": "^3.22.0",
|
|
27
|
+
"@hookform/resolvers": "^3.3.0",
|
|
28
|
+
"sonner": "^1.2.0",
|
|
29
|
+
"zustand": "^4.4.0",
|
|
30
|
+
"cookies-next": "^4.0.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^20.0.0",
|
|
34
|
+
"@types/react": "^18.2.0",
|
|
35
|
+
"@types/react-dom": "^18.2.0",
|
|
36
|
+
"typescript": "^5.3.0",
|
|
37
|
+
"tailwindcss": "^3.3.0",
|
|
38
|
+
"postcss": "^8.4.0",
|
|
39
|
+
"autoprefixer": "^10.4.0",
|
|
40
|
+
"tsup": "^8.0.0",
|
|
41
|
+
"eslint": "^8.0.0",
|
|
42
|
+
"eslint-config-next": "^14.0.0"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"react": "^18.0.0",
|
|
46
|
+
"react-dom": "^18.0.0",
|
|
47
|
+
"next": "^14.0.0"
|
|
48
|
+
},
|
|
49
|
+
"keywords": [
|
|
50
|
+
"ecommerce",
|
|
51
|
+
"nextjs",
|
|
52
|
+
"multi-tenant",
|
|
53
|
+
"react",
|
|
54
|
+
"tailwindcss",
|
|
55
|
+
"stripe",
|
|
56
|
+
"pharmacy",
|
|
57
|
+
"online-store"
|
|
58
|
+
],
|
|
59
|
+
"author": "Your Name",
|
|
60
|
+
"license": "MIT",
|
|
61
|
+
"repository": {
|
|
62
|
+
"type": "git",
|
|
63
|
+
"url": "https://github.com/yourusername/hey-pharmacist-customer.git"
|
|
64
|
+
},
|
|
65
|
+
"bugs": {
|
|
66
|
+
"url": "https://github.com/yourusername/hey-pharmacist-customer/issues"
|
|
67
|
+
},
|
|
68
|
+
"homepage": "https://github.com/yourusername/hey-pharmacist-customer#readme"
|
|
69
|
+
}
|
|
70
|
+
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
|
+
import { motion } from 'framer-motion';
|
|
5
|
+
import { Minus, Plus, Trash2 } from 'lucide-react';
|
|
6
|
+
import { CartItem as CartItemType } from '@/lib/types';
|
|
7
|
+
import { formatPrice } from '@/lib/utils/format';
|
|
8
|
+
import { useCart } from '@/providers/CartProvider';
|
|
9
|
+
import Image from 'next/image';
|
|
10
|
+
|
|
11
|
+
interface CartItemProps {
|
|
12
|
+
item: CartItemType;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function CartItem({ item }: CartItemProps) {
|
|
16
|
+
const { updateQuantity, removeFromCart } = useCart();
|
|
17
|
+
const [isUpdating, setIsUpdating] = useState(false);
|
|
18
|
+
|
|
19
|
+
const handleUpdateQuantity = async (newQuantity: number) => {
|
|
20
|
+
if (newQuantity < 1) return;
|
|
21
|
+
setIsUpdating(true);
|
|
22
|
+
try {
|
|
23
|
+
await updateQuantity(item.productId, newQuantity);
|
|
24
|
+
} finally {
|
|
25
|
+
setIsUpdating(false);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const handleRemove = async () => {
|
|
30
|
+
await removeFromCart(item.productId);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const itemTotal = item.product.price * item.quantity;
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<motion.div
|
|
37
|
+
layout
|
|
38
|
+
initial={{ opacity: 0, y: 20 }}
|
|
39
|
+
animate={{ opacity: 1, y: 0 }}
|
|
40
|
+
exit={{ opacity: 0, x: -100 }}
|
|
41
|
+
className="flex gap-4 bg-white p-4 rounded-xl border border-gray-200 hover:border-primary-300 transition-colors"
|
|
42
|
+
>
|
|
43
|
+
{/* Product Image */}
|
|
44
|
+
<div className="relative w-24 h-24 rounded-lg overflow-hidden flex-shrink-0 bg-gray-100">
|
|
45
|
+
<Image
|
|
46
|
+
src={item.product.images[0] || '/placeholder-product.jpg'}
|
|
47
|
+
alt={item.product.name}
|
|
48
|
+
fill
|
|
49
|
+
className="object-cover"
|
|
50
|
+
/>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
{/* Product Info */}
|
|
54
|
+
<div className="flex-1 min-w-0">
|
|
55
|
+
<h3 className="text-lg font-semibold text-gray-900 truncate">
|
|
56
|
+
{item.product.name}
|
|
57
|
+
</h3>
|
|
58
|
+
<p className="text-sm text-gray-500 mt-1">
|
|
59
|
+
{formatPrice(item.product.price)} each
|
|
60
|
+
</p>
|
|
61
|
+
|
|
62
|
+
{/* Quantity Controls */}
|
|
63
|
+
<div className="flex items-center gap-3 mt-3">
|
|
64
|
+
<div className="flex items-center border-2 border-gray-200 rounded-lg">
|
|
65
|
+
<button
|
|
66
|
+
onClick={() => handleUpdateQuantity(item.quantity - 1)}
|
|
67
|
+
disabled={isUpdating || item.quantity <= 1}
|
|
68
|
+
className="p-2 hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
|
69
|
+
>
|
|
70
|
+
<Minus className="w-4 h-4" />
|
|
71
|
+
</button>
|
|
72
|
+
<span className="px-4 font-medium min-w-[3rem] text-center">
|
|
73
|
+
{item.quantity}
|
|
74
|
+
</span>
|
|
75
|
+
<button
|
|
76
|
+
onClick={() => handleUpdateQuantity(item.quantity + 1)}
|
|
77
|
+
disabled={isUpdating}
|
|
78
|
+
className="p-2 hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
|
79
|
+
>
|
|
80
|
+
<Plus className="w-4 h-4" />
|
|
81
|
+
</button>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
<button
|
|
85
|
+
onClick={handleRemove}
|
|
86
|
+
className="p-2 text-red-600 hover:bg-red-50 rounded-lg transition-colors"
|
|
87
|
+
aria-label="Remove item"
|
|
88
|
+
>
|
|
89
|
+
<Trash2 className="w-5 h-5" />
|
|
90
|
+
</button>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
{/* Item Total */}
|
|
95
|
+
<div className="text-right">
|
|
96
|
+
<p className="text-xl font-bold text-gray-900">
|
|
97
|
+
{formatPrice(itemTotal)}
|
|
98
|
+
</p>
|
|
99
|
+
</div>
|
|
100
|
+
</motion.div>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { LucideIcon } from 'lucide-react';
|
|
3
|
+
import { Button } from './ui/Button';
|
|
4
|
+
|
|
5
|
+
interface EmptyStateProps {
|
|
6
|
+
icon: LucideIcon;
|
|
7
|
+
title: string;
|
|
8
|
+
description: string;
|
|
9
|
+
actionLabel?: string;
|
|
10
|
+
onAction?: () => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function EmptyState({ icon: Icon, title, description, actionLabel, onAction }: EmptyStateProps) {
|
|
14
|
+
return (
|
|
15
|
+
<div className="flex flex-col items-center justify-center py-16 px-4">
|
|
16
|
+
<div className="w-24 h-24 bg-gray-100 rounded-full flex items-center justify-center mb-6">
|
|
17
|
+
<Icon className="w-12 h-12 text-gray-400" />
|
|
18
|
+
</div>
|
|
19
|
+
<h3 className="text-2xl font-bold text-gray-900 mb-2">{title}</h3>
|
|
20
|
+
<p className="text-gray-600 text-center max-w-md mb-8">{description}</p>
|
|
21
|
+
{actionLabel && onAction && (
|
|
22
|
+
<Button onClick={onAction}>{actionLabel}</Button>
|
|
23
|
+
)}
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { Mail, Phone, MapPin, Facebook, Twitter, Instagram } from 'lucide-react';
|
|
5
|
+
import { useTheme } from '@/providers/ThemeProvider';
|
|
6
|
+
import Link from 'next/link';
|
|
7
|
+
|
|
8
|
+
export function Footer() {
|
|
9
|
+
const { config } = useTheme();
|
|
10
|
+
|
|
11
|
+
const footerLinks = {
|
|
12
|
+
shop: [
|
|
13
|
+
{ label: 'All Products', href: '/shop' },
|
|
14
|
+
{ label: 'Categories', href: '/categories' },
|
|
15
|
+
{ label: 'Featured', href: '/featured' },
|
|
16
|
+
{ label: 'New Arrivals', href: '/new' },
|
|
17
|
+
],
|
|
18
|
+
account: [
|
|
19
|
+
{ label: 'My Account', href: '/account' },
|
|
20
|
+
{ label: 'Orders', href: '/orders' },
|
|
21
|
+
{ label: 'Wishlist', href: '/wishlist' },
|
|
22
|
+
{ label: 'Cart', href: '/cart' },
|
|
23
|
+
],
|
|
24
|
+
support: [
|
|
25
|
+
{ label: 'Contact Us', href: '/contact' },
|
|
26
|
+
{ label: 'FAQs', href: '/faqs' },
|
|
27
|
+
{ label: 'Shipping Info', href: '/shipping' },
|
|
28
|
+
{ label: 'Returns', href: '/returns' },
|
|
29
|
+
],
|
|
30
|
+
legal: [
|
|
31
|
+
{ label: 'Privacy Policy', href: '/privacy' },
|
|
32
|
+
{ label: 'Terms of Service', href: '/terms' },
|
|
33
|
+
{ label: 'Cookie Policy', href: '/cookies' },
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<footer className="bg-gray-900 text-gray-300">
|
|
39
|
+
<div className="container mx-auto px-4 py-16">
|
|
40
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-12">
|
|
41
|
+
{/* Brand Column */}
|
|
42
|
+
<div className="lg:col-span-2">
|
|
43
|
+
<h3 className="text-2xl font-bold text-white mb-4">{config.storeName}</h3>
|
|
44
|
+
<p className="text-gray-400 mb-6 max-w-md">
|
|
45
|
+
Your trusted online store for quality products. We deliver excellence with every order.
|
|
46
|
+
</p>
|
|
47
|
+
<div className="space-y-3">
|
|
48
|
+
<div className="flex items-center gap-3">
|
|
49
|
+
<Mail className="w-5 h-5 text-primary-500" />
|
|
50
|
+
<span>support@{config.storeName.toLowerCase().replace(/\s+/g, '')}.com</span>
|
|
51
|
+
</div>
|
|
52
|
+
<div className="flex items-center gap-3">
|
|
53
|
+
<Phone className="w-5 h-5 text-primary-500" />
|
|
54
|
+
<span>+1 (555) 123-4567</span>
|
|
55
|
+
</div>
|
|
56
|
+
<div className="flex items-center gap-3">
|
|
57
|
+
<MapPin className="w-5 h-5 text-primary-500" />
|
|
58
|
+
<span>123 Store Street, City, Country</span>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
{/* Shop Links */}
|
|
64
|
+
<div>
|
|
65
|
+
<h4 className="text-lg font-semibold text-white mb-4">Shop</h4>
|
|
66
|
+
<ul className="space-y-2">
|
|
67
|
+
{footerLinks.shop.map((link) => (
|
|
68
|
+
<li key={link.href}>
|
|
69
|
+
<Link
|
|
70
|
+
href={link.href}
|
|
71
|
+
className="hover:text-primary-500 transition-colors"
|
|
72
|
+
>
|
|
73
|
+
{link.label}
|
|
74
|
+
</Link>
|
|
75
|
+
</li>
|
|
76
|
+
))}
|
|
77
|
+
</ul>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
{/* Account Links */}
|
|
81
|
+
<div>
|
|
82
|
+
<h4 className="text-lg font-semibold text-white mb-4">Account</h4>
|
|
83
|
+
<ul className="space-y-2">
|
|
84
|
+
{footerLinks.account.map((link) => (
|
|
85
|
+
<li key={link.href}>
|
|
86
|
+
<Link
|
|
87
|
+
href={link.href}
|
|
88
|
+
className="hover:text-primary-500 transition-colors"
|
|
89
|
+
>
|
|
90
|
+
{link.label}
|
|
91
|
+
</Link>
|
|
92
|
+
</li>
|
|
93
|
+
))}
|
|
94
|
+
</ul>
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
{/* Support Links */}
|
|
98
|
+
<div>
|
|
99
|
+
<h4 className="text-lg font-semibold text-white mb-4">Support</h4>
|
|
100
|
+
<ul className="space-y-2">
|
|
101
|
+
{footerLinks.support.map((link) => (
|
|
102
|
+
<li key={link.href}>
|
|
103
|
+
<Link
|
|
104
|
+
href={link.href}
|
|
105
|
+
className="hover:text-primary-500 transition-colors"
|
|
106
|
+
>
|
|
107
|
+
{link.label}
|
|
108
|
+
</Link>
|
|
109
|
+
</li>
|
|
110
|
+
))}
|
|
111
|
+
</ul>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
{/* Bottom Bar */}
|
|
116
|
+
<div className="border-t border-gray-800 mt-12 pt-8 flex flex-col md:flex-row justify-between items-center gap-4">
|
|
117
|
+
<p className="text-gray-400 text-sm">
|
|
118
|
+
© {new Date().getFullYear()} {config.storeName}. All rights reserved.
|
|
119
|
+
</p>
|
|
120
|
+
|
|
121
|
+
{/* Social Links */}
|
|
122
|
+
<div className="flex items-center gap-4">
|
|
123
|
+
<a
|
|
124
|
+
href="#"
|
|
125
|
+
className="w-10 h-10 bg-gray-800 hover:bg-primary-600 rounded-full flex items-center justify-center transition-colors"
|
|
126
|
+
>
|
|
127
|
+
<Facebook className="w-5 h-5" />
|
|
128
|
+
</a>
|
|
129
|
+
<a
|
|
130
|
+
href="#"
|
|
131
|
+
className="w-10 h-10 bg-gray-800 hover:bg-primary-600 rounded-full flex items-center justify-center transition-colors"
|
|
132
|
+
>
|
|
133
|
+
<Twitter className="w-5 h-5" />
|
|
134
|
+
</a>
|
|
135
|
+
<a
|
|
136
|
+
href="#"
|
|
137
|
+
className="w-10 h-10 bg-gray-800 hover:bg-primary-600 rounded-full flex items-center justify-center transition-colors"
|
|
138
|
+
>
|
|
139
|
+
<Instagram className="w-5 h-5" />
|
|
140
|
+
</a>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
</footer>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
|
+
import { motion, AnimatePresence } from 'framer-motion';
|
|
5
|
+
import { ShoppingCart, User, Menu, X, Search, Heart } from 'lucide-react';
|
|
6
|
+
import { useAuth } from '@/providers/AuthProvider';
|
|
7
|
+
import { useCart } from '@/providers/CartProvider';
|
|
8
|
+
import { useTheme } from '@/providers/ThemeProvider';
|
|
9
|
+
import Link from 'next/link';
|
|
10
|
+
import Image from 'next/image';
|
|
11
|
+
|
|
12
|
+
export function Header() {
|
|
13
|
+
const { config } = useTheme();
|
|
14
|
+
const { user, isAuthenticated } = useAuth();
|
|
15
|
+
const { cart } = useCart();
|
|
16
|
+
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
|
17
|
+
|
|
18
|
+
const navLinks = [
|
|
19
|
+
{ href: '/shop', label: 'Shop' },
|
|
20
|
+
{ href: '/categories', label: 'Categories' },
|
|
21
|
+
{ href: '/about', label: 'About' },
|
|
22
|
+
{ href: '/contact', label: 'Contact' },
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<header className="sticky top-0 z-40 bg-white/80 backdrop-blur-xl border-b border-gray-200 shadow-sm">
|
|
27
|
+
<div className="container mx-auto px-4">
|
|
28
|
+
<div className="flex items-center justify-between h-20">
|
|
29
|
+
{/* Logo */}
|
|
30
|
+
<Link href="/" className="flex items-center gap-3">
|
|
31
|
+
<div className="relative w-12 h-12">
|
|
32
|
+
<Image
|
|
33
|
+
src={config.logo}
|
|
34
|
+
alt={config.storeName}
|
|
35
|
+
fill
|
|
36
|
+
className="object-contain"
|
|
37
|
+
/>
|
|
38
|
+
</div>
|
|
39
|
+
<span className="text-2xl font-bold text-gray-900 hidden sm:block">
|
|
40
|
+
{config.storeName}
|
|
41
|
+
</span>
|
|
42
|
+
</Link>
|
|
43
|
+
|
|
44
|
+
{/* Desktop Navigation */}
|
|
45
|
+
<nav className="hidden lg:flex items-center gap-8">
|
|
46
|
+
{navLinks.map((link) => (
|
|
47
|
+
<Link
|
|
48
|
+
key={link.href}
|
|
49
|
+
href={link.href}
|
|
50
|
+
className="text-gray-700 hover:text-primary-600 font-medium transition-colors relative group"
|
|
51
|
+
>
|
|
52
|
+
{link.label}
|
|
53
|
+
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-primary-600 group-hover:w-full transition-all duration-300" />
|
|
54
|
+
</Link>
|
|
55
|
+
))}
|
|
56
|
+
</nav>
|
|
57
|
+
|
|
58
|
+
{/* Actions */}
|
|
59
|
+
<div className="flex items-center gap-4">
|
|
60
|
+
{/* Search */}
|
|
61
|
+
<button className="p-2 hover:bg-gray-100 rounded-lg transition-colors">
|
|
62
|
+
<Search className="w-5 h-5 text-gray-700" />
|
|
63
|
+
</button>
|
|
64
|
+
|
|
65
|
+
{/* Favorites */}
|
|
66
|
+
<button className="p-2 hover:bg-gray-100 rounded-lg transition-colors relative">
|
|
67
|
+
<Heart className="w-5 h-5 text-gray-700" />
|
|
68
|
+
</button>
|
|
69
|
+
|
|
70
|
+
{/* Cart */}
|
|
71
|
+
<Link
|
|
72
|
+
href="/cart"
|
|
73
|
+
className="p-2 hover:bg-gray-100 rounded-lg transition-colors relative"
|
|
74
|
+
>
|
|
75
|
+
<ShoppingCart className="w-5 h-5 text-gray-700" />
|
|
76
|
+
{cart && cart.itemCount > 0 && (
|
|
77
|
+
<span className="absolute -top-1 -right-1 w-5 h-5 bg-primary-600 text-white text-xs font-bold rounded-full flex items-center justify-center">
|
|
78
|
+
{cart.itemCount}
|
|
79
|
+
</span>
|
|
80
|
+
)}
|
|
81
|
+
</Link>
|
|
82
|
+
|
|
83
|
+
{/* User Menu */}
|
|
84
|
+
{isAuthenticated ? (
|
|
85
|
+
<Link
|
|
86
|
+
href="/account"
|
|
87
|
+
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
|
|
88
|
+
>
|
|
89
|
+
<User className="w-5 h-5 text-gray-700" />
|
|
90
|
+
</Link>
|
|
91
|
+
) : (
|
|
92
|
+
<Link
|
|
93
|
+
href="/login"
|
|
94
|
+
className="hidden sm:block px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors font-medium"
|
|
95
|
+
>
|
|
96
|
+
Sign In
|
|
97
|
+
</Link>
|
|
98
|
+
)}
|
|
99
|
+
|
|
100
|
+
{/* Mobile Menu Button */}
|
|
101
|
+
<button
|
|
102
|
+
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
|
103
|
+
className="lg:hidden p-2 hover:bg-gray-100 rounded-lg transition-colors"
|
|
104
|
+
>
|
|
105
|
+
{isMobileMenuOpen ? (
|
|
106
|
+
<X className="w-6 h-6" />
|
|
107
|
+
) : (
|
|
108
|
+
<Menu className="w-6 h-6" />
|
|
109
|
+
)}
|
|
110
|
+
</button>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
{/* Mobile Menu */}
|
|
115
|
+
<AnimatePresence>
|
|
116
|
+
{isMobileMenuOpen && (
|
|
117
|
+
<motion.div
|
|
118
|
+
initial={{ height: 0, opacity: 0 }}
|
|
119
|
+
animate={{ height: 'auto', opacity: 1 }}
|
|
120
|
+
exit={{ height: 0, opacity: 0 }}
|
|
121
|
+
className="lg:hidden overflow-hidden border-t border-gray-200"
|
|
122
|
+
>
|
|
123
|
+
<nav className="py-4 space-y-2">
|
|
124
|
+
{navLinks.map((link) => (
|
|
125
|
+
<Link
|
|
126
|
+
key={link.href}
|
|
127
|
+
href={link.href}
|
|
128
|
+
onClick={() => setIsMobileMenuOpen(false)}
|
|
129
|
+
className="block px-4 py-3 hover:bg-gray-50 rounded-lg text-gray-700 font-medium"
|
|
130
|
+
>
|
|
131
|
+
{link.label}
|
|
132
|
+
</Link>
|
|
133
|
+
))}
|
|
134
|
+
{!isAuthenticated && (
|
|
135
|
+
<Link
|
|
136
|
+
href="/login"
|
|
137
|
+
onClick={() => setIsMobileMenuOpen(false)}
|
|
138
|
+
className="block px-4 py-3 bg-primary-600 text-white rounded-lg text-center font-medium"
|
|
139
|
+
>
|
|
140
|
+
Sign In
|
|
141
|
+
</Link>
|
|
142
|
+
)}
|
|
143
|
+
</nav>
|
|
144
|
+
</motion.div>
|
|
145
|
+
)}
|
|
146
|
+
</AnimatePresence>
|
|
147
|
+
</div>
|
|
148
|
+
</header>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { motion } from 'framer-motion';
|
|
5
|
+
import { Package, Calendar, CreditCard, ExternalLink } from 'lucide-react';
|
|
6
|
+
import { Order, OrderStatus } from '@/lib/types';
|
|
7
|
+
import { formatPrice, formatDate } from '@/lib/utils/format';
|
|
8
|
+
import { Badge } from './ui/Badge';
|
|
9
|
+
import Link from 'next/link';
|
|
10
|
+
|
|
11
|
+
interface OrderCardProps {
|
|
12
|
+
order: Order;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const statusConfig: Record<OrderStatus, { variant: 'success' | 'warning' | 'primary' | 'danger' | 'gray', label: string }> = {
|
|
16
|
+
[OrderStatus.PENDING]: { variant: 'warning', label: 'Pending' },
|
|
17
|
+
[OrderStatus.PROCESSING]: { variant: 'primary', label: 'Processing' },
|
|
18
|
+
[OrderStatus.SHIPPED]: { variant: 'primary', label: 'Shipped' },
|
|
19
|
+
[OrderStatus.DELIVERED]: { variant: 'success', label: 'Delivered' },
|
|
20
|
+
[OrderStatus.CANCELLED]: { variant: 'danger', label: 'Cancelled' },
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export function OrderCard({ order }: OrderCardProps) {
|
|
24
|
+
const config = statusConfig[order.status];
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<motion.div
|
|
28
|
+
initial={{ opacity: 0, y: 20 }}
|
|
29
|
+
animate={{ opacity: 1, y: 0 }}
|
|
30
|
+
whileHover={{ y: -4 }}
|
|
31
|
+
className="bg-white rounded-2xl p-6 shadow-sm hover:shadow-xl transition-all duration-300 border border-gray-100"
|
|
32
|
+
>
|
|
33
|
+
{/* Header */}
|
|
34
|
+
<div className="flex justify-between items-start mb-4">
|
|
35
|
+
<div>
|
|
36
|
+
<h3 className="text-lg font-bold text-gray-900 flex items-center gap-2">
|
|
37
|
+
<Package className="w-5 h-5 text-primary-600" />
|
|
38
|
+
Order #{order.orderNumber}
|
|
39
|
+
</h3>
|
|
40
|
+
<p className="text-sm text-gray-500 mt-1 flex items-center gap-2">
|
|
41
|
+
<Calendar className="w-4 h-4" />
|
|
42
|
+
{formatDate(order.createdAt, 'long')}
|
|
43
|
+
</p>
|
|
44
|
+
</div>
|
|
45
|
+
<Badge variant={config.variant}>{config.label}</Badge>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
{/* Items Preview */}
|
|
49
|
+
<div className="space-y-2 mb-4">
|
|
50
|
+
{order.items.slice(0, 2).map((item) => (
|
|
51
|
+
<div key={item.id} className="flex items-center gap-3 text-sm">
|
|
52
|
+
<div className="w-12 h-12 rounded-lg bg-gray-100 flex-shrink-0" />
|
|
53
|
+
<div className="flex-1 min-w-0">
|
|
54
|
+
<p className="font-medium text-gray-900 truncate">{item.productName}</p>
|
|
55
|
+
<p className="text-gray-500">Qty: {item.quantity}</p>
|
|
56
|
+
</div>
|
|
57
|
+
<p className="font-semibold text-gray-900">{formatPrice(item.price)}</p>
|
|
58
|
+
</div>
|
|
59
|
+
))}
|
|
60
|
+
{order.items.length > 2 && (
|
|
61
|
+
<p className="text-sm text-gray-500 pl-15">
|
|
62
|
+
+{order.items.length - 2} more item{order.items.length - 2 > 1 ? 's' : ''}
|
|
63
|
+
</p>
|
|
64
|
+
)}
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
{/* Footer */}
|
|
68
|
+
<div className="flex justify-between items-center pt-4 border-t border-gray-200">
|
|
69
|
+
<div>
|
|
70
|
+
<p className="text-sm text-gray-500">Total Amount</p>
|
|
71
|
+
<p className="text-2xl font-bold text-gray-900">{formatPrice(order.total)}</p>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<div className="flex gap-2">
|
|
75
|
+
{order.stripeCheckoutUrl && order.paymentStatus !== 'paid' && (
|
|
76
|
+
<a
|
|
77
|
+
href={order.stripeCheckoutUrl}
|
|
78
|
+
target="_blank"
|
|
79
|
+
rel="noopener noreferrer"
|
|
80
|
+
className="inline-flex items-center gap-2 px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors"
|
|
81
|
+
>
|
|
82
|
+
<CreditCard className="w-4 h-4" />
|
|
83
|
+
Pay Now
|
|
84
|
+
</a>
|
|
85
|
+
)}
|
|
86
|
+
<Link
|
|
87
|
+
href={`/orders/${order.id}`}
|
|
88
|
+
className="inline-flex items-center gap-2 px-4 py-2 border-2 border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
|
89
|
+
>
|
|
90
|
+
View Details
|
|
91
|
+
<ExternalLink className="w-4 h-4" />
|
|
92
|
+
</Link>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
</motion.div>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|