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
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { useEffect } from 'react';
|
|
4
|
+
import { EcommerceConfig } from '@/lib/types';
|
|
5
|
+
import { ThemeProvider } from './ThemeProvider';
|
|
6
|
+
import { AuthProvider } from './AuthProvider';
|
|
7
|
+
import { CartProvider } from './CartProvider';
|
|
8
|
+
import { initializeApiAdapter } from '@/lib/api-adapter';
|
|
9
|
+
import { Toaster } from 'sonner';
|
|
10
|
+
|
|
11
|
+
interface EcommerceProviderProps {
|
|
12
|
+
config: EcommerceConfig;
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function EcommerceProvider({ config, children }: EcommerceProviderProps) {
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
// Initialize API adapter with store configuration
|
|
19
|
+
// This sets up the real backend APIs with proper authentication and store ID
|
|
20
|
+
initializeApiAdapter(config);
|
|
21
|
+
}, [config]);
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<ThemeProvider config={config}>
|
|
25
|
+
<AuthProvider>
|
|
26
|
+
<CartProvider>
|
|
27
|
+
{children}
|
|
28
|
+
<Toaster position="top-right" richColors />
|
|
29
|
+
</CartProvider>
|
|
30
|
+
</AuthProvider>
|
|
31
|
+
</ThemeProvider>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { createContext, useContext, useEffect } from 'react';
|
|
4
|
+
import { EcommerceConfig } from '@/lib/types';
|
|
5
|
+
import { generateColorShades } from '@/lib/utils/colors';
|
|
6
|
+
|
|
7
|
+
interface ThemeContextValue {
|
|
8
|
+
config: EcommerceConfig;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const ThemeContext = createContext<ThemeContextValue | undefined>(undefined);
|
|
12
|
+
|
|
13
|
+
export function useTheme() {
|
|
14
|
+
const context = useContext(ThemeContext);
|
|
15
|
+
if (!context) {
|
|
16
|
+
throw new Error('useTheme must be used within ThemeProvider');
|
|
17
|
+
}
|
|
18
|
+
return context;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface ThemeProviderProps {
|
|
22
|
+
config: EcommerceConfig;
|
|
23
|
+
children: React.ReactNode;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function ThemeProvider({ config, children }: ThemeProviderProps) {
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
// Generate color shades and set CSS variables
|
|
29
|
+
const primaryShades = generateColorShades(config.colors.primary);
|
|
30
|
+
const secondaryShades = generateColorShades(config.colors.secondary);
|
|
31
|
+
const accentShades = generateColorShades(config.colors.accent);
|
|
32
|
+
|
|
33
|
+
const root = document.documentElement;
|
|
34
|
+
|
|
35
|
+
// Set primary color variables
|
|
36
|
+
Object.entries(primaryShades).forEach(([shade, rgb]) => {
|
|
37
|
+
root.style.setProperty(`--color-primary-${shade}`, rgb);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Set secondary color variables
|
|
41
|
+
Object.entries(secondaryShades).forEach(([shade, rgb]) => {
|
|
42
|
+
root.style.setProperty(`--color-secondary-${shade}`, rgb);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Set accent color variables
|
|
46
|
+
Object.entries(accentShades).forEach(([shade, rgb]) => {
|
|
47
|
+
root.style.setProperty(`--color-accent-${shade}`, rgb);
|
|
48
|
+
});
|
|
49
|
+
}, [config.colors]);
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<ThemeContext.Provider value={{ config }}>
|
|
53
|
+
{children}
|
|
54
|
+
</ThemeContext.Provider>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { motion } from 'framer-motion';
|
|
5
|
+
import { ShoppingBag, ArrowRight } from 'lucide-react';
|
|
6
|
+
import { CartItem } from '@/components/CartItem';
|
|
7
|
+
import { EmptyState } from '@/components/EmptyState';
|
|
8
|
+
import { Button } from '@/components/ui/Button';
|
|
9
|
+
import { useCart } from '@/providers/CartProvider';
|
|
10
|
+
import { formatPrice } from '@/lib/utils/format';
|
|
11
|
+
import { useRouter } from 'next/navigation';
|
|
12
|
+
|
|
13
|
+
export function CartScreen() {
|
|
14
|
+
const router = useRouter();
|
|
15
|
+
const { cart, isLoading } = useCart();
|
|
16
|
+
|
|
17
|
+
if (isLoading) {
|
|
18
|
+
return (
|
|
19
|
+
<div className="min-h-screen bg-gray-50 py-12">
|
|
20
|
+
<div className="container mx-auto px-4">
|
|
21
|
+
<p>Loading cart...</p>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!cart || cart.items.length === 0) {
|
|
28
|
+
return (
|
|
29
|
+
<div className="min-h-screen bg-gray-50 py-12">
|
|
30
|
+
<div className="container mx-auto px-4">
|
|
31
|
+
<EmptyState
|
|
32
|
+
icon={ShoppingBag}
|
|
33
|
+
title="Your cart is empty"
|
|
34
|
+
description="Add some products to your cart and they will appear here"
|
|
35
|
+
actionLabel="Continue Shopping"
|
|
36
|
+
onAction={() => router.push('/shop')}
|
|
37
|
+
/>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const subtotal = cart.total;
|
|
44
|
+
const shipping = subtotal > 50 ? 0 : 10;
|
|
45
|
+
const tax = subtotal * 0.1; // 10% tax
|
|
46
|
+
const total = subtotal + shipping + tax;
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div className="min-h-screen bg-gray-50 py-12">
|
|
50
|
+
<div className="container mx-auto px-4">
|
|
51
|
+
{/* Header */}
|
|
52
|
+
<motion.div
|
|
53
|
+
initial={{ opacity: 0, y: 20 }}
|
|
54
|
+
animate={{ opacity: 1, y: 0 }}
|
|
55
|
+
className="mb-8"
|
|
56
|
+
>
|
|
57
|
+
<h1 className="text-4xl font-bold text-gray-900 mb-2">Shopping Cart</h1>
|
|
58
|
+
<p className="text-gray-600">{cart.itemCount} items in your cart</p>
|
|
59
|
+
</motion.div>
|
|
60
|
+
|
|
61
|
+
<div className="grid lg:grid-cols-3 gap-8">
|
|
62
|
+
{/* Cart Items */}
|
|
63
|
+
<div className="lg:col-span-2">
|
|
64
|
+
<div className="space-y-4">
|
|
65
|
+
{cart.items.map((item) => (
|
|
66
|
+
<CartItem key={item.productId} item={item} />
|
|
67
|
+
))}
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
{/* Order Summary */}
|
|
72
|
+
<div className="lg:col-span-1">
|
|
73
|
+
<motion.div
|
|
74
|
+
initial={{ opacity: 0, y: 20 }}
|
|
75
|
+
animate={{ opacity: 1, y: 0 }}
|
|
76
|
+
transition={{ delay: 0.1 }}
|
|
77
|
+
className="bg-white rounded-2xl p-6 shadow-sm sticky top-24"
|
|
78
|
+
>
|
|
79
|
+
<h2 className="text-2xl font-bold text-gray-900 mb-6">Order Summary</h2>
|
|
80
|
+
|
|
81
|
+
<div className="space-y-4 mb-6">
|
|
82
|
+
<div className="flex justify-between text-gray-700">
|
|
83
|
+
<span>Subtotal</span>
|
|
84
|
+
<span className="font-medium">{formatPrice(subtotal)}</span>
|
|
85
|
+
</div>
|
|
86
|
+
<div className="flex justify-between text-gray-700">
|
|
87
|
+
<span>Shipping</span>
|
|
88
|
+
<span className="font-medium">
|
|
89
|
+
{shipping === 0 ? (
|
|
90
|
+
<span className="text-green-600">FREE</span>
|
|
91
|
+
) : (
|
|
92
|
+
formatPrice(shipping)
|
|
93
|
+
)}
|
|
94
|
+
</span>
|
|
95
|
+
</div>
|
|
96
|
+
<div className="flex justify-between text-gray-700">
|
|
97
|
+
<span>Tax (10%)</span>
|
|
98
|
+
<span className="font-medium">{formatPrice(tax)}</span>
|
|
99
|
+
</div>
|
|
100
|
+
<div className="border-t border-gray-200 pt-4">
|
|
101
|
+
<div className="flex justify-between">
|
|
102
|
+
<span className="text-xl font-bold text-gray-900">Total</span>
|
|
103
|
+
<span className="text-2xl font-bold text-gray-900">
|
|
104
|
+
{formatPrice(total)}
|
|
105
|
+
</span>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
{shipping > 0 && (
|
|
111
|
+
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4 mb-6">
|
|
112
|
+
<p className="text-sm text-blue-800">
|
|
113
|
+
Add {formatPrice(50 - subtotal)} more to get FREE shipping!
|
|
114
|
+
</p>
|
|
115
|
+
</div>
|
|
116
|
+
)}
|
|
117
|
+
|
|
118
|
+
<Button
|
|
119
|
+
size="lg"
|
|
120
|
+
onClick={() => router.push('/checkout')}
|
|
121
|
+
className="w-full"
|
|
122
|
+
>
|
|
123
|
+
Proceed to Checkout
|
|
124
|
+
<ArrowRight className="w-5 h-5" />
|
|
125
|
+
</Button>
|
|
126
|
+
|
|
127
|
+
<button
|
|
128
|
+
onClick={() => router.push('/shop')}
|
|
129
|
+
className="w-full mt-4 text-primary-600 hover:text-primary-700 font-medium transition-colors"
|
|
130
|
+
>
|
|
131
|
+
Continue Shopping
|
|
132
|
+
</button>
|
|
133
|
+
</motion.div>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
|
+
import { motion } from 'framer-motion';
|
|
5
|
+
import { useForm } from 'react-hook-form';
|
|
6
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { Lock, CreditCard } from 'lucide-react';
|
|
9
|
+
import { Button } from '@/components/ui/Button';
|
|
10
|
+
import { Input } from '@/components/ui/Input';
|
|
11
|
+
import { useCart } from '@/providers/CartProvider';
|
|
12
|
+
import { useAuth } from '@/providers/AuthProvider';
|
|
13
|
+
import { ordersApi, CreateOrderData } from '@/lib/api/orders';
|
|
14
|
+
import { formatPrice } from '@/lib/utils/format';
|
|
15
|
+
import { useRouter } from 'next/navigation';
|
|
16
|
+
import { toast } from 'sonner';
|
|
17
|
+
|
|
18
|
+
const addressSchema = z.object({
|
|
19
|
+
fullName: z.string().min(2, 'Full name is required'),
|
|
20
|
+
addressLine1: z.string().min(5, 'Address is required'),
|
|
21
|
+
addressLine2: z.string().optional(),
|
|
22
|
+
city: z.string().min(2, 'City is required'),
|
|
23
|
+
state: z.string().min(2, 'State is required'),
|
|
24
|
+
zipCode: z.string().min(5, 'ZIP code is required'),
|
|
25
|
+
country: z.string().min(2, 'Country is required'),
|
|
26
|
+
phone: z.string().min(10, 'Phone number is required'),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const checkoutSchema = z.object({
|
|
30
|
+
shipping: addressSchema,
|
|
31
|
+
billing: addressSchema,
|
|
32
|
+
sameAsShipping: z.boolean(),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
type CheckoutFormData = z.infer<typeof checkoutSchema>;
|
|
36
|
+
|
|
37
|
+
export function CheckoutScreen() {
|
|
38
|
+
const router = useRouter();
|
|
39
|
+
const { cart } = useCart();
|
|
40
|
+
const { isAuthenticated, user } = useAuth();
|
|
41
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
42
|
+
const [sameAsShipping, setSameAsShipping] = useState(true);
|
|
43
|
+
|
|
44
|
+
const {
|
|
45
|
+
register,
|
|
46
|
+
handleSubmit,
|
|
47
|
+
formState: { errors },
|
|
48
|
+
} = useForm<CheckoutFormData>({
|
|
49
|
+
resolver: zodResolver(checkoutSchema),
|
|
50
|
+
defaultValues: {
|
|
51
|
+
sameAsShipping: true,
|
|
52
|
+
shipping: {
|
|
53
|
+
fullName: user ? `${user.firstName} ${user.lastName}` : '',
|
|
54
|
+
phone: user?.phone || '',
|
|
55
|
+
country: 'United States',
|
|
56
|
+
},
|
|
57
|
+
billing: {
|
|
58
|
+
fullName: user ? `${user.firstName} ${user.lastName}` : '',
|
|
59
|
+
phone: user?.phone || '',
|
|
60
|
+
country: 'United States',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const onSubmit = async (data: CheckoutFormData) => {
|
|
66
|
+
if (!isAuthenticated) {
|
|
67
|
+
toast.error('Please login to continue');
|
|
68
|
+
router.push('/login?redirect=/checkout');
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
setIsSubmitting(true);
|
|
73
|
+
try {
|
|
74
|
+
const orderData: CreateOrderData = {
|
|
75
|
+
shippingAddress: data.shipping,
|
|
76
|
+
billingAddress: sameAsShipping ? data.shipping : data.billing,
|
|
77
|
+
sameAsShipping,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const response = await ordersApi.createOrder(orderData);
|
|
81
|
+
|
|
82
|
+
if (response.success && response.data.stripeCheckoutUrl) {
|
|
83
|
+
// Redirect to Stripe checkout
|
|
84
|
+
window.location.href = response.data.stripeCheckoutUrl;
|
|
85
|
+
} else {
|
|
86
|
+
toast.success('Order placed successfully!');
|
|
87
|
+
router.push(`/orders/${response.data.id}`);
|
|
88
|
+
}
|
|
89
|
+
} catch (error: any) {
|
|
90
|
+
toast.error(error.response?.data?.message || 'Failed to place order');
|
|
91
|
+
} finally {
|
|
92
|
+
setIsSubmitting(false);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
if (!cart || cart.items.length === 0) {
|
|
97
|
+
router.push('/cart');
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const subtotal = cart.total;
|
|
102
|
+
const shipping = subtotal > 50 ? 0 : 10;
|
|
103
|
+
const tax = subtotal * 0.1;
|
|
104
|
+
const total = subtotal + shipping + tax;
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<div className="min-h-screen bg-gray-50 py-12">
|
|
108
|
+
<div className="container mx-auto px-4 max-w-6xl">
|
|
109
|
+
{/* Header */}
|
|
110
|
+
<motion.div
|
|
111
|
+
initial={{ opacity: 0, y: 20 }}
|
|
112
|
+
animate={{ opacity: 1, y: 0 }}
|
|
113
|
+
className="mb-8"
|
|
114
|
+
>
|
|
115
|
+
<h1 className="text-4xl font-bold text-gray-900 mb-2">Checkout</h1>
|
|
116
|
+
<p className="text-gray-600">Complete your order</p>
|
|
117
|
+
</motion.div>
|
|
118
|
+
|
|
119
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
120
|
+
<div className="grid lg:grid-cols-3 gap-8">
|
|
121
|
+
{/* Forms */}
|
|
122
|
+
<div className="lg:col-span-2 space-y-6">
|
|
123
|
+
{/* Shipping Address */}
|
|
124
|
+
<motion.div
|
|
125
|
+
initial={{ opacity: 0, y: 20 }}
|
|
126
|
+
animate={{ opacity: 1, y: 0 }}
|
|
127
|
+
transition={{ delay: 0.1 }}
|
|
128
|
+
className="bg-white rounded-2xl p-6 shadow-sm"
|
|
129
|
+
>
|
|
130
|
+
<h2 className="text-2xl font-bold text-gray-900 mb-6">
|
|
131
|
+
Shipping Address
|
|
132
|
+
</h2>
|
|
133
|
+
<div className="grid grid-cols-2 gap-4">
|
|
134
|
+
<div className="col-span-2">
|
|
135
|
+
<Input
|
|
136
|
+
label="Full Name"
|
|
137
|
+
{...register('shipping.fullName')}
|
|
138
|
+
error={errors.shipping?.fullName?.message}
|
|
139
|
+
/>
|
|
140
|
+
</div>
|
|
141
|
+
<div className="col-span-2">
|
|
142
|
+
<Input
|
|
143
|
+
label="Address Line 1"
|
|
144
|
+
{...register('shipping.addressLine1')}
|
|
145
|
+
error={errors.shipping?.addressLine1?.message}
|
|
146
|
+
/>
|
|
147
|
+
</div>
|
|
148
|
+
<div className="col-span-2">
|
|
149
|
+
<Input
|
|
150
|
+
label="Address Line 2 (Optional)"
|
|
151
|
+
{...register('shipping.addressLine2')}
|
|
152
|
+
/>
|
|
153
|
+
</div>
|
|
154
|
+
<Input
|
|
155
|
+
label="City"
|
|
156
|
+
{...register('shipping.city')}
|
|
157
|
+
error={errors.shipping?.city?.message}
|
|
158
|
+
/>
|
|
159
|
+
<Input
|
|
160
|
+
label="State"
|
|
161
|
+
{...register('shipping.state')}
|
|
162
|
+
error={errors.shipping?.state?.message}
|
|
163
|
+
/>
|
|
164
|
+
<Input
|
|
165
|
+
label="ZIP Code"
|
|
166
|
+
{...register('shipping.zipCode')}
|
|
167
|
+
error={errors.shipping?.zipCode?.message}
|
|
168
|
+
/>
|
|
169
|
+
<Input
|
|
170
|
+
label="Country"
|
|
171
|
+
{...register('shipping.country')}
|
|
172
|
+
error={errors.shipping?.country?.message}
|
|
173
|
+
/>
|
|
174
|
+
<div className="col-span-2">
|
|
175
|
+
<Input
|
|
176
|
+
label="Phone Number"
|
|
177
|
+
{...register('shipping.phone')}
|
|
178
|
+
error={errors.shipping?.phone?.message}
|
|
179
|
+
/>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
</motion.div>
|
|
183
|
+
|
|
184
|
+
{/* Billing Address */}
|
|
185
|
+
<motion.div
|
|
186
|
+
initial={{ opacity: 0, y: 20 }}
|
|
187
|
+
animate={{ opacity: 1, y: 0 }}
|
|
188
|
+
transition={{ delay: 0.2 }}
|
|
189
|
+
className="bg-white rounded-2xl p-6 shadow-sm"
|
|
190
|
+
>
|
|
191
|
+
<h2 className="text-2xl font-bold text-gray-900 mb-6">
|
|
192
|
+
Billing Address
|
|
193
|
+
</h2>
|
|
194
|
+
|
|
195
|
+
<label className="flex items-center gap-3 mb-6 cursor-pointer">
|
|
196
|
+
<input
|
|
197
|
+
type="checkbox"
|
|
198
|
+
checked={sameAsShipping}
|
|
199
|
+
onChange={(e) => setSameAsShipping(e.target.checked)}
|
|
200
|
+
className="w-5 h-5 text-primary-600 rounded"
|
|
201
|
+
/>
|
|
202
|
+
<span className="text-gray-700">Same as shipping address</span>
|
|
203
|
+
</label>
|
|
204
|
+
|
|
205
|
+
{!sameAsShipping && (
|
|
206
|
+
<div className="grid grid-cols-2 gap-4">
|
|
207
|
+
<div className="col-span-2">
|
|
208
|
+
<Input
|
|
209
|
+
label="Full Name"
|
|
210
|
+
{...register('billing.fullName')}
|
|
211
|
+
error={errors.billing?.fullName?.message}
|
|
212
|
+
/>
|
|
213
|
+
</div>
|
|
214
|
+
<div className="col-span-2">
|
|
215
|
+
<Input
|
|
216
|
+
label="Address Line 1"
|
|
217
|
+
{...register('billing.addressLine1')}
|
|
218
|
+
error={errors.billing?.addressLine1?.message}
|
|
219
|
+
/>
|
|
220
|
+
</div>
|
|
221
|
+
<div className="col-span-2">
|
|
222
|
+
<Input
|
|
223
|
+
label="Address Line 2 (Optional)"
|
|
224
|
+
{...register('billing.addressLine2')}
|
|
225
|
+
/>
|
|
226
|
+
</div>
|
|
227
|
+
<Input
|
|
228
|
+
label="City"
|
|
229
|
+
{...register('billing.city')}
|
|
230
|
+
error={errors.billing?.city?.message}
|
|
231
|
+
/>
|
|
232
|
+
<Input
|
|
233
|
+
label="State"
|
|
234
|
+
{...register('billing.state')}
|
|
235
|
+
error={errors.billing?.state?.message}
|
|
236
|
+
/>
|
|
237
|
+
<Input
|
|
238
|
+
label="ZIP Code"
|
|
239
|
+
{...register('billing.zipCode')}
|
|
240
|
+
error={errors.billing?.zipCode?.message}
|
|
241
|
+
/>
|
|
242
|
+
<Input
|
|
243
|
+
label="Country"
|
|
244
|
+
{...register('billing.country')}
|
|
245
|
+
error={errors.billing?.country?.message}
|
|
246
|
+
/>
|
|
247
|
+
<div className="col-span-2">
|
|
248
|
+
<Input
|
|
249
|
+
label="Phone Number"
|
|
250
|
+
{...register('billing.phone')}
|
|
251
|
+
error={errors.billing?.phone?.message}
|
|
252
|
+
/>
|
|
253
|
+
</div>
|
|
254
|
+
</div>
|
|
255
|
+
)}
|
|
256
|
+
</motion.div>
|
|
257
|
+
</div>
|
|
258
|
+
|
|
259
|
+
{/* Order Summary */}
|
|
260
|
+
<div className="lg:col-span-1">
|
|
261
|
+
<motion.div
|
|
262
|
+
initial={{ opacity: 0, y: 20 }}
|
|
263
|
+
animate={{ opacity: 1, y: 0 }}
|
|
264
|
+
transition={{ delay: 0.3 }}
|
|
265
|
+
className="bg-white rounded-2xl p-6 shadow-sm sticky top-24"
|
|
266
|
+
>
|
|
267
|
+
<h2 className="text-2xl font-bold text-gray-900 mb-6">
|
|
268
|
+
Order Summary
|
|
269
|
+
</h2>
|
|
270
|
+
|
|
271
|
+
{/* Items */}
|
|
272
|
+
<div className="space-y-4 mb-6 max-h-64 overflow-y-auto">
|
|
273
|
+
{cart.items.map((item) => (
|
|
274
|
+
<div key={item.productId} className="flex gap-3">
|
|
275
|
+
<div className="w-16 h-16 rounded-lg bg-gray-100 flex-shrink-0" />
|
|
276
|
+
<div className="flex-1 min-w-0">
|
|
277
|
+
<p className="font-medium text-gray-900 text-sm truncate">
|
|
278
|
+
{item.product.name}
|
|
279
|
+
</p>
|
|
280
|
+
<p className="text-sm text-gray-500">Qty: {item.quantity}</p>
|
|
281
|
+
</div>
|
|
282
|
+
<p className="font-medium text-gray-900 text-sm">
|
|
283
|
+
{formatPrice(item.product.price * item.quantity)}
|
|
284
|
+
</p>
|
|
285
|
+
</div>
|
|
286
|
+
))}
|
|
287
|
+
</div>
|
|
288
|
+
|
|
289
|
+
<div className="space-y-3 border-t border-gray-200 pt-4 mb-6">
|
|
290
|
+
<div className="flex justify-between text-gray-700">
|
|
291
|
+
<span>Subtotal</span>
|
|
292
|
+
<span className="font-medium">{formatPrice(subtotal)}</span>
|
|
293
|
+
</div>
|
|
294
|
+
<div className="flex justify-between text-gray-700">
|
|
295
|
+
<span>Shipping</span>
|
|
296
|
+
<span className="font-medium">
|
|
297
|
+
{shipping === 0 ? (
|
|
298
|
+
<span className="text-green-600">FREE</span>
|
|
299
|
+
) : (
|
|
300
|
+
formatPrice(shipping)
|
|
301
|
+
)}
|
|
302
|
+
</span>
|
|
303
|
+
</div>
|
|
304
|
+
<div className="flex justify-between text-gray-700">
|
|
305
|
+
<span>Tax</span>
|
|
306
|
+
<span className="font-medium">{formatPrice(tax)}</span>
|
|
307
|
+
</div>
|
|
308
|
+
<div className="border-t border-gray-200 pt-3">
|
|
309
|
+
<div className="flex justify-between">
|
|
310
|
+
<span className="text-xl font-bold text-gray-900">Total</span>
|
|
311
|
+
<span className="text-2xl font-bold text-gray-900">
|
|
312
|
+
{formatPrice(total)}
|
|
313
|
+
</span>
|
|
314
|
+
</div>
|
|
315
|
+
</div>
|
|
316
|
+
</div>
|
|
317
|
+
|
|
318
|
+
<Button
|
|
319
|
+
type="submit"
|
|
320
|
+
size="lg"
|
|
321
|
+
isLoading={isSubmitting}
|
|
322
|
+
className="w-full"
|
|
323
|
+
>
|
|
324
|
+
<CreditCard className="w-5 h-5" />
|
|
325
|
+
Place Order
|
|
326
|
+
</Button>
|
|
327
|
+
|
|
328
|
+
<div className="flex items-center justify-center gap-2 text-sm text-gray-500 mt-4">
|
|
329
|
+
<Lock className="w-4 h-4" />
|
|
330
|
+
<span>Secure checkout powered by Stripe</span>
|
|
331
|
+
</div>
|
|
332
|
+
</motion.div>
|
|
333
|
+
</div>
|
|
334
|
+
</div>
|
|
335
|
+
</form>
|
|
336
|
+
</div>
|
|
337
|
+
</div>
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { motion } from 'framer-motion';
|
|
5
|
+
import { Truck, Package } from 'lucide-react';
|
|
6
|
+
import { OrderCard } from '@/components/OrderCard';
|
|
7
|
+
import { OrderCardSkeleton } from '@/components/ui/Skeleton';
|
|
8
|
+
import { EmptyState } from '@/components/EmptyState';
|
|
9
|
+
import { useCurrentOrders } from '@/hooks/useOrders';
|
|
10
|
+
import { useRouter } from 'next/navigation';
|
|
11
|
+
import Link from 'next/link';
|
|
12
|
+
|
|
13
|
+
export function CurrentOrdersScreen() {
|
|
14
|
+
const router = useRouter();
|
|
15
|
+
const { orders, isLoading } = useCurrentOrders();
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<div className="min-h-screen bg-gray-50 py-12">
|
|
19
|
+
<div className="container mx-auto px-4 max-w-5xl">
|
|
20
|
+
{/* Header */}
|
|
21
|
+
<motion.div
|
|
22
|
+
initial={{ opacity: 0, y: 20 }}
|
|
23
|
+
animate={{ opacity: 1, y: 0 }}
|
|
24
|
+
className="mb-8"
|
|
25
|
+
>
|
|
26
|
+
<div className="flex items-center justify-between">
|
|
27
|
+
<div>
|
|
28
|
+
<h1 className="text-4xl font-bold text-gray-900 mb-2 flex items-center gap-3">
|
|
29
|
+
<Truck className="w-10 h-10 text-primary-600" />
|
|
30
|
+
Current Orders
|
|
31
|
+
</h1>
|
|
32
|
+
<p className="text-gray-600">
|
|
33
|
+
Track your active orders and deliveries
|
|
34
|
+
</p>
|
|
35
|
+
</div>
|
|
36
|
+
<Link
|
|
37
|
+
href="/orders"
|
|
38
|
+
className="text-primary-600 hover:text-primary-700 font-medium"
|
|
39
|
+
>
|
|
40
|
+
View All Orders →
|
|
41
|
+
</Link>
|
|
42
|
+
</div>
|
|
43
|
+
</motion.div>
|
|
44
|
+
|
|
45
|
+
{/* Info Banner */}
|
|
46
|
+
<motion.div
|
|
47
|
+
initial={{ opacity: 0, y: 20 }}
|
|
48
|
+
animate={{ opacity: 1, y: 0 }}
|
|
49
|
+
transition={{ delay: 0.1 }}
|
|
50
|
+
className="bg-blue-50 border border-blue-200 rounded-2xl p-6 mb-8"
|
|
51
|
+
>
|
|
52
|
+
<h3 className="font-semibold text-blue-900 mb-2">Track Your Orders</h3>
|
|
53
|
+
<p className="text-blue-700 text-sm">
|
|
54
|
+
Stay updated on your orders' status. You'll receive notifications when your order is
|
|
55
|
+
being prepared, shipped, and delivered.
|
|
56
|
+
</p>
|
|
57
|
+
</motion.div>
|
|
58
|
+
|
|
59
|
+
{/* Orders List */}
|
|
60
|
+
{isLoading ? (
|
|
61
|
+
<div className="space-y-4">
|
|
62
|
+
{Array.from({ length: 2 }).map((_, i) => (
|
|
63
|
+
<OrderCardSkeleton key={i} />
|
|
64
|
+
))}
|
|
65
|
+
</div>
|
|
66
|
+
) : orders.length > 0 ? (
|
|
67
|
+
<div className="space-y-4">
|
|
68
|
+
{orders.map((order) => (
|
|
69
|
+
<OrderCard key={order.id} order={order} />
|
|
70
|
+
))}
|
|
71
|
+
</div>
|
|
72
|
+
) : (
|
|
73
|
+
<EmptyState
|
|
74
|
+
icon={Package}
|
|
75
|
+
title="No active orders"
|
|
76
|
+
description="You don't have any orders in progress right now"
|
|
77
|
+
actionLabel="Start Shopping"
|
|
78
|
+
onAction={() => router.push('/shop')}
|
|
79
|
+
/>
|
|
80
|
+
)}
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|