hey-pharmacist-ecommerce 1.1.1 → 1.1.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hey-pharmacist-ecommerce",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "Production-ready, multi-tenant e‑commerce UI + API adapter for Next.js with auth, carts, checkout, orders, theming, and pharmacist-focused UX.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -9,6 +9,7 @@ import { useWishlist } from '@/providers/WishlistProvider';
9
9
  import Image from 'next/image';
10
10
  import { toast } from 'sonner';
11
11
  import { useRouter } from 'next/navigation';
12
+ import { useBasePath } from '@/providers/BasePathProvider';
12
13
 
13
14
 
14
15
  interface ProductCardProps {
@@ -28,6 +29,7 @@ export function ProductCard({
28
29
  className
29
30
  }: ProductCardProps & { className?: string }) {
30
31
  const router = useRouter();
32
+ const { buildPath } = useBasePath();
31
33
  const [isFavorite, setIsFavorite] = useState(isFavorited);
32
34
  const { addToWishlist, removeFromWishlist, isInWishlist } = useWishlist();
33
35
  const [isHovered, setIsHovered] = useState(false);
@@ -233,7 +235,7 @@ export function ProductCard({
233
235
  type="button"
234
236
  onClick={(e) => {
235
237
  e.stopPropagation();
236
- router.push(`/products/${product._id}`);
238
+ router.push(buildPath(`/products/${product._id}`));
237
239
  }}
238
240
  className={`w-full flex items-center justify-center rounded-md px-3 py-2 text-sm font-medium bg-primary-600 hover:bg-primary-700 text-white`}
239
241
  >
package/src/index.ts CHANGED
@@ -6,6 +6,7 @@ export { ThemeProvider, useTheme } from './providers/ThemeProvider';
6
6
  export { AuthProvider, useAuth } from './providers/AuthProvider';
7
7
  export { CartProvider, useCart } from './providers/CartProvider';
8
8
  export { WishlistProvider, useWishlist } from './providers/WishlistProvider';
9
+ export { useBasePath } from './providers/BasePathProvider';
9
10
 
10
11
  // Screens
11
12
  export { ShopScreen } from './screens/ShopScreen';
@@ -0,0 +1,36 @@
1
+ 'use client';
2
+
3
+ import React, { createContext, useContext } from 'react';
4
+
5
+ interface BasePathContextValue {
6
+ basePath: string;
7
+ buildPath: (path: string) => string;
8
+ }
9
+
10
+ const BasePathContext = createContext<BasePathContextValue | undefined>(undefined);
11
+
12
+ export function BasePathProvider({ basePath = '', children }: { basePath?: string; children: React.ReactNode }) {
13
+ const normalized = basePath ? (basePath.startsWith('/') ? basePath : `/${basePath}`) : '';
14
+
15
+ const buildPath = (path: string) => {
16
+ if (!normalized) return path;
17
+ if (!path) return normalized;
18
+ if (path.startsWith(normalized + '/')) return path; // already prefixed
19
+ if (path.startsWith('/')) return `${normalized}${path}`;
20
+ return `${normalized}/${path}`;
21
+ };
22
+
23
+ return (
24
+ <BasePathContext.Provider value={{ basePath: normalized, buildPath }}>
25
+ {children}
26
+ </BasePathContext.Provider>
27
+ );
28
+ }
29
+
30
+ export function useBasePath(): BasePathContextValue {
31
+ const ctx = useContext(BasePathContext);
32
+ if (!ctx) throw new Error('useBasePath must be used within BasePathProvider');
33
+ return ctx;
34
+ }
35
+
36
+
@@ -6,6 +6,7 @@ import { ThemeProvider } from './ThemeProvider';
6
6
  import { AuthProvider } from './AuthProvider';
7
7
  import { CartProvider } from './CartProvider';
8
8
  import { WishlistProvider } from './WishlistProvider';
9
+ import { BasePathProvider } from './BasePathProvider';
9
10
  import { initializeApiAdapter } from '@/lib/api-adapter';
10
11
  import { Toaster } from 'sonner';
11
12
  import { QueryClientProvider } from '@tanstack/react-query';
@@ -15,9 +16,10 @@ interface EcommerceProviderProps {
15
16
  config: EcommerceConfig;
16
17
  children: React.ReactNode;
17
18
  withToaster?: boolean;
19
+ basePath?: string;
18
20
  }
19
21
 
20
- export function EcommerceProvider({ config, children, withToaster = true }: EcommerceProviderProps) {
22
+ export function EcommerceProvider({ config, children, withToaster = true, basePath = '' }: EcommerceProviderProps) {
21
23
  useEffect(() => {
22
24
  // Initialize API adapter with store configuration
23
25
  // This sets up the real backend APIs with proper authentication and store ID
@@ -30,14 +32,16 @@ export function EcommerceProvider({ config, children, withToaster = true }: Ecom
30
32
  return (
31
33
  <QueryClientProvider client={client}>
32
34
  <ThemeProvider config={config}>
33
- <AuthProvider>
34
- <CartProvider>
35
- <WishlistProvider>
36
- {children}
37
- {withToaster && <Toaster position="top-right" richColors />}
38
- </WishlistProvider>
39
- </CartProvider>
40
- </AuthProvider>
35
+ <BasePathProvider basePath={basePath}>
36
+ <AuthProvider>
37
+ <CartProvider>
38
+ <WishlistProvider>
39
+ {children}
40
+ {withToaster && <Toaster position="top-right" richColors />}
41
+ </WishlistProvider>
42
+ </CartProvider>
43
+ </AuthProvider>
44
+ </BasePathProvider>
41
45
  </ThemeProvider>
42
46
  </QueryClientProvider>
43
47
  );
@@ -61,7 +61,7 @@ export function ThemeProvider({ config, children }: ThemeProviderProps) {
61
61
  root.style.setProperty(`--header-via`, primaryShades[600]);
62
62
  root.style.setProperty(`--header-to`, secondaryShades[600]);
63
63
  }
64
- }, [config.colors]);
64
+ }, [config]);
65
65
 
66
66
  return (
67
67
  <ThemeContext.Provider value={{ config }}>
@@ -8,10 +8,12 @@ import { ProductCard } from '@/components/ProductCard';
8
8
  import { useWishlist } from '@/providers/WishlistProvider';
9
9
  import { ProductCardSkeleton } from '@/components/ui/Skeleton';
10
10
  import { useRouter } from 'next/navigation';
11
+ import { useBasePath } from '@/providers/BasePathProvider';
11
12
  import { useProducts } from '@/hooks/useProducts';
12
13
 
13
14
  export default function HomeScreen() {
14
- const router = useRouter();
15
+ const router = useRouter();
16
+ const { buildPath } = useBasePath();
15
17
  const { products, isLoading } = useProducts();
16
18
  const { isInWishlist } = useWishlist();
17
19
 
@@ -156,7 +158,7 @@ export default function HomeScreen() {
156
158
  <ProductCard
157
159
  product={product}
158
160
  isFavorited={isInWishlist(product.id)}
159
- onClickProduct={(p) => router.push(`/products/${p.id}`)}
161
+ onClickProduct={(p) => router.push(buildPath(`/products/${p.id}`))}
160
162
  />
161
163
  </motion.div>
162
164
  );
@@ -12,9 +12,11 @@ import Link from 'next/link';
12
12
  import { AXIOS_CONFIG } from '@/lib/Apis/wrapper';
13
13
  import { useWishlist } from '@/providers/WishlistProvider';
14
14
  import { useRouter } from 'next/navigation';
15
+ import { useBasePath } from '@/providers/BasePathProvider';
15
16
 
16
17
  export default function SearchPage() {
17
- const router = useRouter();
18
+ const router = useRouter();
19
+ const { buildPath } = useBasePath();
18
20
  const searchParams = useSearchParams();
19
21
  const searchQuery = searchParams.get('q') || '';
20
22
  const [products, setProducts] = useState<ExtendedProductDTO[]>([]);
@@ -136,7 +138,7 @@ export default function SearchPage() {
136
138
  <ProductCard
137
139
  product={product}
138
140
  isFavorited={isInWishlist(product.id)}
139
- onClickProduct={(p) => router.push(`/products/${p.id}`)}
141
+ onClickProduct={(p) => router.push(buildPath(`/products/${p.id}`))}
140
142
  />
141
143
  ))}
142
144
  </div>
@@ -23,6 +23,7 @@ import {
23
23
  } from 'lucide-react';
24
24
  import Image from 'next/image';
25
25
  import { useRouter } from 'next/navigation';
26
+ import { useBasePath } from '@/providers/BasePathProvider';
26
27
  import { ProductCard } from '@/components/ProductCard';
27
28
  import { ProductCardSkeleton } from '@/components/ui/Skeleton';
28
29
  import { EmptyState } from '@/components/EmptyState';
@@ -42,6 +43,7 @@ interface ShopScreenProps {
42
43
 
43
44
  export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProps) {
44
45
  const router = useRouter();
46
+ const { buildPath } = useBasePath();
45
47
  const [filters, setFilters] = useState<ProductFilters>(initialFilters);
46
48
  const [page, setPage] = useState(1);
47
49
  const [showFilters, setShowFilters] = useState(false);
@@ -1026,7 +1028,7 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
1026
1028
  product={product}
1027
1029
  onClickProduct={(item) => {
1028
1030
  const productData = encodeURIComponent(JSON.stringify(item));
1029
- router.push(`/products/${item.id}?product=${productData}`);
1031
+ router.push(buildPath(`/products/${item.id}?product=${productData}`));
1030
1032
  }}
1031
1033
  />
1032
1034
  </div>
@@ -1049,7 +1051,7 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
1049
1051
  key={product.id}
1050
1052
  whileHover={{ y: -4 }}
1051
1053
  className="group flex cursor-pointer flex-col gap-6 rounded-2xl border border-gray-100 bg-white p-5 shadow-sm transition hover:shadow-xl md:flex-row md:items-start"
1052
- onClick={() => router.push(`/products/${product.id}`)}
1054
+ onClick={() => router.push(buildPath(`/products/${product.id}`))}
1053
1055
  >
1054
1056
  <div className="relative h-48 w-full overflow-hidden rounded-2xl bg-gray-100 md:h-40 md:w-40">
1055
1057
  <Image
@@ -1111,7 +1113,7 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
1111
1113
  size="sm"
1112
1114
  onClick={(event) => {
1113
1115
  event.stopPropagation();
1114
- router.push(`/products/${product._id}`);
1116
+ router.push(buildPath(`/products/${product._id}`));
1115
1117
  }}
1116
1118
  >
1117
1119
  View product
@@ -23,6 +23,7 @@ import { useWishlistProducts } from '@/hooks/useWishlistProducts';
23
23
  import Image from 'next/image';
24
24
  import { formatPrice } from '@/lib/utils/format';
25
25
  import { ExtendedProductDTO } from '@/lib/Apis';
26
+ import { useBasePath } from '@/providers/BasePathProvider';
26
27
 
27
28
  type SortOption = 'featured' | 'price-low' | 'price-high' | 'name' | 'availability';
28
29
 
@@ -45,6 +46,7 @@ interface InsightCardProps {
45
46
 
46
47
  export default function WishlistScreen() {
47
48
  const router = useRouter();
49
+ const { buildPath } = useBasePath();
48
50
  const { isAuthenticated } = useAuth() || {};
49
51
  const {
50
52
  products: wishlistItems,
@@ -314,7 +316,7 @@ export default function WishlistScreen() {
314
316
  >
315
317
  <ProductCard
316
318
  product={product as ExtendedProductDTO}
317
- onClickProduct={(p) => router.push(`/products/${p.id}`)}
319
+ onClickProduct={(p) => router.push(buildPath(`/products/${p.id}`))}
318
320
  onFavorite={() => handleRemoveFromWishlist(product.id)}
319
321
  isFavorited
320
322
  />