hey-pharmacist-ecommerce 1.1.9 → 1.1.11

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.9",
3
+ "version": "1.1.11",
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",
@@ -573,103 +573,101 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
573
573
 
574
574
  const renderFiltersPanel = () => (
575
575
  <>
576
- <div className="space-y-8">
577
- <div className="space-y-8">
578
- <div className="flex items-start justify-between gap-3">
579
- <div>
580
- <h3 className="text-lg font-semibold text-gray-900">Refine results</h3>
581
- <p className="mt-1 text-sm text-gray-500">
582
- Filter by category, price, and availability to find the perfect fit faster.
583
- </p>
584
- </div>
585
- {hasActiveFilters && (
586
- <button
587
- type="button"
588
- onClick={handleClearFilters}
589
- className="text-sm font-semibold text-primary-600 hover:text-primary-700"
590
- >
591
- Clear all
592
- </button>
593
- )}
594
- </div>
595
-
596
- <div className="space-y-6">
597
- <div className="space-y-3">
598
- <h4 className="text-xs font-semibold uppercase tracking-[0.2em] text-gray-500">Categories</h4>
599
- <div className="space-y-2">
600
- {sortedCategories.length === 0 && (
601
- <span className="text-sm text-gray-500">No categories available yet.</span>
576
+ <div className="space-y-8">
577
+ <div className="space-y-8">
578
+ <div className="flex items-start justify-between gap-3">
579
+ <div>
580
+ <h3 className="text-lg font-semibold text-gray-900">Refine results</h3>
581
+ <p className="mt-1 text-sm text-gray-500">
582
+ Filter by category, price, and availability to find the perfect fit faster.
583
+ </p>
584
+ </div>
585
+ {hasActiveFilters && (
586
+ <button
587
+ type="button"
588
+ onClick={handleClearFilters}
589
+ className="text-sm font-semibold text-primary-600 hover:text-primary-700"
590
+ >
591
+ Clear all
592
+ </button>
602
593
  )}
603
- {sortedCategories.map((category) => {
604
- const isCategoryActive = categoryFilter === category.id;
605
- const isExpanded = !!expandedCategories[category.id as string];
606
- return (
607
- <div key={category.id} className="rounded-xl border-gray-100 bg-white/50">
608
- <div
609
- role="button"
610
- tabIndex={0}
611
- onClick={() => {
612
- // Selecting a category also expands it for quick access to subcategories
613
- if (!isExpanded) toggleCategoryExpand(category.id ?? '');
614
- handleCategoryChange(category.id ?? '');
615
- }}
616
- className={`flex w-full items-center justify-between rounded-xl px-3 py-2 text-sm font-medium transition ${
617
- isCategoryActive
618
- ? 'text-primary-700 bg-primary-50'
619
- : 'text-gray-700 hover:text-primary-700 hover:bg-primary-50/50'
620
- }`}
621
- >
622
- <span className="flex items-center gap-2">
623
- <span className='font-medium'>{category.name}</span>
624
- {category.productCount > 0 && (
625
- <span className={`ml-1 rounded-full bg-gray-100 px-2 py-0.5 text-xs ${isCategoryActive ? 'text-primary-700' : 'text-gray-500'}`}>
626
- {category.productCount}
594
+ </div>
595
+
596
+ <div className="space-y-6">
597
+ <div className="space-y-3">
598
+ <h4 className="text-xs font-semibold uppercase tracking-[0.2em] text-gray-500">Categories</h4>
599
+ <div className="space-y-2">
600
+ {sortedCategories.length === 0 && (
601
+ <span className="text-sm text-gray-500">No categories available yet.</span>
602
+ )}
603
+ {sortedCategories.map((category) => {
604
+ const isCategoryActive = categoryFilter === category.id;
605
+ const isExpanded = !!expandedCategories[category.id as string];
606
+ return (
607
+ <div key={category.id} className="rounded-xl border-gray-100 bg-white/50">
608
+ <div
609
+ role="button"
610
+ tabIndex={0}
611
+ onClick={() => {
612
+ // Selecting a category also expands it for quick access to subcategories
613
+ if (!isExpanded) toggleCategoryExpand(category.id ?? '');
614
+ handleCategoryChange(category.id ?? '');
615
+ }}
616
+ className={`flex w-full items-center justify-between rounded-xl px-3 py-2 text-sm font-medium transition ${isCategoryActive
617
+ ? 'text-primary-700 bg-primary-50'
618
+ : 'text-gray-700 hover:text-primary-700 hover:bg-primary-50/50'
619
+ }`}
620
+ >
621
+ <span className="flex items-center gap-2">
622
+ <span className='font-medium'>{category.name}</span>
623
+ {category.productCount > 0 && (
624
+ <span className={`ml-1 rounded-full bg-gray-100 px-2 py-0.5 text-xs ${isCategoryActive ? 'text-primary-700' : 'text-gray-500'}`}>
625
+ {category.productCount}
626
+ </span>
627
+ )}
627
628
  </span>
628
- )}
629
- </span>
630
- <button
631
- type="button"
632
- onClick={(e) => {
633
- e.preventDefault();
634
- e.stopPropagation();
635
- toggleCategoryExpand(category.id ?? '');
636
- }}
637
- className="rounded-md p-1 hover:bg-gray-100"
638
- aria-label={isExpanded ? 'Collapse' : 'Expand'}
639
- >
640
- <ChevronDown className={`h-4 w-4 transition-transform ${isExpanded ? 'rotate-180 text-primary-600' : 'rotate-0 text-gray-400'}`} />
641
- </button>
642
- </div>
643
- {isExpanded && Array.isArray(category.categorySubCategories) && category.categorySubCategories.length > 0 && (
644
- <div className="mt-1 border-gray-100 px-2 pb-2 pl-4">
645
- <div className="divide-y divide-gray-100">
646
- {category.categorySubCategories.map((sub) => {
647
- const isSubActive = subCategoryFilter === sub.id;
648
- return (
649
- <button
650
- key={sub.id}
651
- type="button"
652
- onClick={() => handleSubCategoryChange(category.id ?? '', sub.id)}
653
- className={`block w-full px-2 py-2 text-sm text-start transition ${
654
- isSubActive
655
- ? 'text-primary-700'
656
- : 'text-gray-600 hover:text-primary-700 '
657
- }`}
658
- >
659
- {sub.name}
660
- </button>
661
- );
662
- })}
629
+ <button
630
+ type="button"
631
+ onClick={(e) => {
632
+ e.preventDefault();
633
+ e.stopPropagation();
634
+ toggleCategoryExpand(category.id ?? '');
635
+ }}
636
+ className="rounded-md p-1 hover:bg-gray-100"
637
+ aria-label={isExpanded ? 'Collapse' : 'Expand'}
638
+ >
639
+ <ChevronDown className={`h-4 w-4 transition-transform ${isExpanded ? 'rotate-180 text-primary-600' : 'rotate-0 text-gray-400'}`} />
640
+ </button>
663
641
  </div>
642
+ {isExpanded && Array.isArray(category.categorySubCategories) && category.categorySubCategories.length > 0 && (
643
+ <div className="mt-1 border-gray-100 px-2 pb-2 pl-4">
644
+ <div className="divide-y divide-gray-100">
645
+ {category.categorySubCategories.map((sub) => {
646
+ const isSubActive = subCategoryFilter === sub.id;
647
+ return (
648
+ <button
649
+ key={sub.id}
650
+ type="button"
651
+ onClick={() => handleSubCategoryChange(category.id ?? '', sub.id)}
652
+ className={`block w-full px-2 py-2 text-sm text-start transition ${isSubActive
653
+ ? 'text-primary-700'
654
+ : 'text-gray-600 hover:text-primary-700 '
655
+ }`}
656
+ >
657
+ {sub.name}
658
+ </button>
659
+ );
660
+ })}
661
+ </div>
662
+ </div>
663
+ )}
664
664
  </div>
665
- )}
666
- </div>
667
- );
668
- })}
665
+ );
666
+ })}
667
+ </div>
668
+ </div>
669
669
  </div>
670
670
  </div>
671
- </div>
672
- </div>
673
671
 
674
672
  <div className="space-y-4">
675
673
  <h4 className="text-xs font-semibold uppercase tracking-[0.2em] text-gray-500">
@@ -683,11 +681,10 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
683
681
  type="button"
684
682
  key={range.value}
685
683
  onClick={() => handlePriceRangeSelect(range.value)}
686
- className={`rounded-full border px-3 py-1.5 text-sm font-medium transition ${
687
- isActive
684
+ className={`rounded-full border px-3 py-1.5 text-sm font-medium transition ${isActive
688
685
  ? 'border-secondary-600 bg-secondary-600 text-white shadow-lg shadow-secondary-500/30'
689
686
  : 'border-gray-200 bg-white text-gray-600 hover:border-secondary-300 hover:text-secondary-600'
690
- }`}
687
+ }`}
691
688
  >
692
689
  {range.label}
693
690
  </button>
@@ -731,11 +728,10 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
731
728
  <button
732
729
  type="button"
733
730
  onClick={handleToggleStock}
734
- className={`flex w-full items-center justify-between rounded-xl border px-4 py-3 text-sm font-medium transition ${
735
- inStockOnly
731
+ className={`flex w-full items-center justify-between rounded-xl border px-4 py-3 text-sm font-medium transition ${inStockOnly
736
732
  ? 'border-primary-500 bg-primary-50 text-primary-700'
737
733
  : 'border-gray-200 bg-white text-gray-600 hover:border-primary-300 hover:text-primary-600'
738
- }`}
734
+ }`}
739
735
  >
740
736
  <span>In stock only</span>
741
737
  <Sparkles className="h-4 w-4 text-primary-500" />
@@ -743,11 +739,10 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
743
739
  <button
744
740
  type="button"
745
741
  onClick={handleToggleNewArrivals}
746
- className={`mt-2 flex w-full items-center justify-between rounded-xl border px-4 py-3 text-sm font-medium transition ${
747
- newArrivals
742
+ className={`mt-2 flex w-full items-center justify-between rounded-xl border px-4 py-3 text-sm font-medium transition ${newArrivals
748
743
  ? 'border-secondary-500 bg-secondary-50 text-secondary-700'
749
744
  : 'border-gray-200 bg-white text-gray-600 hover:border-secondary-300 hover:text-secondary-600'
750
- }`}
745
+ }`}
751
746
  >
752
747
  <span>New arrivals (last 30 days)</span>
753
748
  <Sparkles className="h-4 w-4 text-secondary-500" />
@@ -864,11 +859,10 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
864
859
  initial={{ opacity: 0, y: 20 }}
865
860
  animate={{ opacity: 1, y: 0 }}
866
861
  transition={{ delay: 0.2 + index * 0.05 }}
867
- className={`rounded-2xl border p-5 backdrop-blur ${
868
- card.id === 'new' && newArrivals
862
+ className={`rounded-2xl border p-5 backdrop-blur ${card.id === 'new' && newArrivals
869
863
  ? 'border-white/40 bg-white/25 ring-2 ring-white/30'
870
864
  : 'border-white/20 bg-white/15'
871
- } ${card.id === 'new' ? 'cursor-pointer hover:bg-white/20' : ''}`}
865
+ } ${card.id === 'new' ? 'cursor-pointer hover:bg-white/20' : ''}`}
872
866
  onClick={card.id === 'new' ? handleToggleNewArrivals : undefined}
873
867
  role={card.id === 'new' ? 'button' : undefined}
874
868
  aria-pressed={card.id === 'new' ? (newArrivals ? 'true' : 'false') : undefined}
@@ -932,11 +926,10 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
932
926
  <button
933
927
  type="button"
934
928
  onClick={() => setViewMode('grid')}
935
- className={`flex items-center gap-2 rounded-l-xl px-4 py-2 text-sm font-medium transition ${
936
- viewMode === 'grid'
929
+ className={`flex items-center gap-2 rounded-l-xl px-4 py-2 text-sm font-medium transition ${viewMode === 'grid'
937
930
  ? 'bg-primary-50 text-primary-600'
938
931
  : 'text-gray-500 hover:text-gray-700'
939
- }`}
932
+ }`}
940
933
  aria-pressed={viewMode === 'grid'}
941
934
  >
942
935
  <LayoutGrid className="h-4 w-4" />
@@ -945,11 +938,10 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
945
938
  <button
946
939
  type="button"
947
940
  onClick={() => setViewMode('list')}
948
- className={`flex items-center gap-2 rounded-r-xl px-4 py-2 text-sm font-medium transition ${
949
- viewMode === 'list'
941
+ className={`flex items-center gap-2 rounded-r-xl px-4 py-2 text-sm font-medium transition ${viewMode === 'list'
950
942
  ? 'bg-primary-50 text-primary-600'
951
943
  : 'text-gray-500 hover:text-gray-700'
952
- }`}
944
+ }`}
953
945
  aria-pressed={viewMode === 'list'}
954
946
  >
955
947
  <LayoutList className="h-4 w-4" />
@@ -1027,8 +1019,7 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
1027
1019
  <ProductCard
1028
1020
  product={product}
1029
1021
  onClickProduct={(item) => {
1030
- const productData = encodeURIComponent(JSON.stringify(item));
1031
- router.push(buildPath(`/products/${item.id}?product=${productData}`));
1022
+ router.push(buildPath(`/products/${item._id}`));
1032
1023
  }}
1033
1024
  />
1034
1025
  </div>
@@ -1040,10 +1031,10 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
1040
1031
  const discount =
1041
1032
  product.priceBeforeDiscount && product.priceBeforeDiscount > product.finalPrice
1042
1033
  ? Math.round(
1043
- ((product.priceBeforeDiscount - product.finalPrice) /
1044
- product.priceBeforeDiscount) *
1045
- 100
1046
- )
1034
+ ((product.priceBeforeDiscount - product.finalPrice) /
1035
+ product.priceBeforeDiscount) *
1036
+ 100
1037
+ )
1047
1038
  : 0;
1048
1039
 
1049
1040
  return (
@@ -1051,7 +1042,7 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
1051
1042
  key={product.id}
1052
1043
  whileHover={{ y: -4 }}
1053
1044
  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"
1054
- onClick={() => router.push(buildPath(`/products/${product.id}`))}
1045
+ onClick={() => router.push(buildPath(`/products/${product._id}`))}
1055
1046
  >
1056
1047
  <div className="relative h-48 w-full overflow-hidden rounded-2xl bg-gray-100 md:h-40 md:w-40">
1057
1048
  <Image