From 77c46b777ff2a3cdbe72cffaf6d5483b29cdb81b Mon Sep 17 00:00:00 2001 From: shafi54 <108669266+shafi-aviz@users.noreply.github.com> Date: Sat, 24 Jan 2026 12:22:50 +0530 Subject: [PATCH] enh --- apps/admin-ui/.expo/types/router.d.ts | 6 +- apps/backend/src/lib/init.ts | 5 + apps/backend/src/lib/product-store.ts | 165 ++++++++++++++ apps/backend/src/lib/redis-client.ts | 8 + apps/backend/src/trpc/common-apis/common.ts | 77 +++---- apps/backend/src/trpc/user-apis/product.ts | 209 +++++++++++++----- .../(tabs)/me/delivery-slots/index.tsx | 2 +- .../components/CheckoutAddressSelector.tsx | 20 +- apps/user-ui/components/ProductCard.tsx | 6 +- apps/user-ui/components/ProductDetail.tsx | 19 +- apps/user-ui/components/SlotSpecificView.tsx | 8 +- apps/user-ui/components/cart-page.tsx | 4 +- apps/user-ui/components/floating-cart-bar.tsx | 2 +- apps/user-ui/hooks/cart-query-hooks.tsx | 17 +- packages/ui/index.ts | 4 +- 15 files changed, 426 insertions(+), 126 deletions(-) create mode 100644 apps/backend/src/lib/product-store.ts diff --git a/apps/admin-ui/.expo/types/router.d.ts b/apps/admin-ui/.expo/types/router.d.ts index 15f1475..6b43803 100644 --- a/apps/admin-ui/.expo/types/router.d.ts +++ b/apps/admin-ui/.expo/types/router.d.ts @@ -6,9 +6,9 @@ export * from 'expo-router'; declare module 'expo-router' { export namespace ExpoRouter { export interface __routes { - hrefInputParams: { pathname: Router.RelativePathString, params?: Router.UnknownInputParams } | { pathname: Router.ExternalPathString, params?: Router.UnknownInputParams } | { pathname: `/`; params?: Router.UnknownInputParams; } | { pathname: `/login`; params?: Router.UnknownInputParams; } | { pathname: `/_sitemap`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/create-product-group` | `/create-product-group`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/add-product` | `/add-product`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/add-slot` | `/add-slot`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/add-store` | `/add-store`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/add-tag` | `/add-tag`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/address-management` | `/address-management`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/complaints` | `/complaints`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/coupons` | `/coupons`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/coupons/reserved-coupons` | `/coupons/reserved-coupons`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/create-coupon` | `/create-coupon`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/customize-app` | `/customize-app`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/customize-app/popular-items` | `/customize-app/popular-items`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/dashboard-banners` | `/dashboard-banners`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/dashboard-banners/create-banner` | `/dashboard-banners/create-banner`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/dashboard` | `/dashboard`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/delivery-sequences` | `/delivery-sequences`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/edit-product` | `/edit-product`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/edit-store` | `/edit-store`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/edit-tag` | `/edit-tag`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/manage-orders` | `/manage-orders`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/orders` | `/orders`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/prices-overview` | `/prices-overview`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/product-groupings` | `/product-groupings`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/product-tags` | `/product-tags`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/products` | `/products`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/rebalance-orders` | `/rebalance-orders`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/slots/slot-details` | `/slots/slot-details`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/slots` | `/slots`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/stores` | `/stores`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/users` | `/users`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/vendor-snippets` | `/vendor-snippets`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/dashboard-banners/edit-banner/[id]` | `/dashboard-banners/edit-banner/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/edit-coupon/[id]` | `/edit-coupon/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/edit-product-group/[id]` | `/edit-product-group/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/edit-slot/[id]` | `/edit-slot/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/order-details/[id]` | `/order-details/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/product-detail/[id]` | `/product-detail/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/user-details/[id]` | `/user-details/[id]`, params: Router.UnknownInputParams & { id: string | number; } }; - hrefOutputParams: { pathname: Router.RelativePathString, params?: Router.UnknownOutputParams } | { pathname: Router.ExternalPathString, params?: Router.UnknownOutputParams } | { pathname: `/`; params?: Router.UnknownOutputParams; } | { pathname: `/login`; params?: Router.UnknownOutputParams; } | { pathname: `/_sitemap`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/create-product-group` | `/create-product-group`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/add-product` | `/add-product`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/add-slot` | `/add-slot`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/add-store` | `/add-store`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/add-tag` | `/add-tag`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/address-management` | `/address-management`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/complaints` | `/complaints`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/coupons` | `/coupons`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/coupons/reserved-coupons` | `/coupons/reserved-coupons`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/create-coupon` | `/create-coupon`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/customize-app` | `/customize-app`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/customize-app/popular-items` | `/customize-app/popular-items`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/dashboard-banners` | `/dashboard-banners`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/dashboard-banners/create-banner` | `/dashboard-banners/create-banner`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/dashboard` | `/dashboard`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/delivery-sequences` | `/delivery-sequences`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/edit-product` | `/edit-product`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/edit-store` | `/edit-store`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/edit-tag` | `/edit-tag`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/manage-orders` | `/manage-orders`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/orders` | `/orders`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/prices-overview` | `/prices-overview`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/product-groupings` | `/product-groupings`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/product-tags` | `/product-tags`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/products` | `/products`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/rebalance-orders` | `/rebalance-orders`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/slots/slot-details` | `/slots/slot-details`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/slots` | `/slots`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/stores` | `/stores`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/users` | `/users`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/vendor-snippets` | `/vendor-snippets`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/dashboard-banners/edit-banner/[id]` | `/dashboard-banners/edit-banner/[id]`, params: Router.UnknownOutputParams & { id: string; } } | { pathname: `${'/(drawer)'}/edit-coupon/[id]` | `/edit-coupon/[id]`, params: Router.UnknownOutputParams & { id: string; } } | { pathname: `${'/(drawer)'}/edit-product-group/[id]` | `/edit-product-group/[id]`, params: Router.UnknownOutputParams & { id: string; } } | { pathname: `${'/(drawer)'}/edit-slot/[id]` | `/edit-slot/[id]`, params: Router.UnknownOutputParams & { id: string; } } | { pathname: `${'/(drawer)'}/order-details/[id]` | `/order-details/[id]`, params: Router.UnknownOutputParams & { id: string; } } | { pathname: `${'/(drawer)'}/product-detail/[id]` | `/product-detail/[id]`, params: Router.UnknownOutputParams & { id: string; } } | { pathname: `${'/(drawer)'}/user-details/[id]` | `/user-details/[id]`, params: Router.UnknownOutputParams & { id: string; } }; - href: Router.RelativePathString | Router.ExternalPathString | `/${`?${string}` | `#${string}` | ''}` | `/login${`?${string}` | `#${string}` | ''}` | `/_sitemap${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/create-product-group${`?${string}` | `#${string}` | ''}` | `/create-product-group${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/add-product${`?${string}` | `#${string}` | ''}` | `/add-product${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/add-slot${`?${string}` | `#${string}` | ''}` | `/add-slot${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/add-store${`?${string}` | `#${string}` | ''}` | `/add-store${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/add-tag${`?${string}` | `#${string}` | ''}` | `/add-tag${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/address-management${`?${string}` | `#${string}` | ''}` | `/address-management${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/complaints${`?${string}` | `#${string}` | ''}` | `/complaints${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/coupons${`?${string}` | `#${string}` | ''}` | `/coupons${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/coupons/reserved-coupons${`?${string}` | `#${string}` | ''}` | `/coupons/reserved-coupons${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/create-coupon${`?${string}` | `#${string}` | ''}` | `/create-coupon${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/customize-app${`?${string}` | `#${string}` | ''}` | `/customize-app${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/customize-app/popular-items${`?${string}` | `#${string}` | ''}` | `/customize-app/popular-items${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/dashboard-banners${`?${string}` | `#${string}` | ''}` | `/dashboard-banners${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/dashboard-banners/create-banner${`?${string}` | `#${string}` | ''}` | `/dashboard-banners/create-banner${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/dashboard${`?${string}` | `#${string}` | ''}` | `/dashboard${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/delivery-sequences${`?${string}` | `#${string}` | ''}` | `/delivery-sequences${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/edit-product${`?${string}` | `#${string}` | ''}` | `/edit-product${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/edit-store${`?${string}` | `#${string}` | ''}` | `/edit-store${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/edit-tag${`?${string}` | `#${string}` | ''}` | `/edit-tag${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/manage-orders${`?${string}` | `#${string}` | ''}` | `/manage-orders${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/orders${`?${string}` | `#${string}` | ''}` | `/orders${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/prices-overview${`?${string}` | `#${string}` | ''}` | `/prices-overview${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/product-groupings${`?${string}` | `#${string}` | ''}` | `/product-groupings${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/product-tags${`?${string}` | `#${string}` | ''}` | `/product-tags${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/products${`?${string}` | `#${string}` | ''}` | `/products${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/rebalance-orders${`?${string}` | `#${string}` | ''}` | `/rebalance-orders${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/slots/slot-details${`?${string}` | `#${string}` | ''}` | `/slots/slot-details${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/slots${`?${string}` | `#${string}` | ''}` | `/slots${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/stores${`?${string}` | `#${string}` | ''}` | `/stores${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/users${`?${string}` | `#${string}` | ''}` | `/users${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/vendor-snippets${`?${string}` | `#${string}` | ''}` | `/vendor-snippets${`?${string}` | `#${string}` | ''}` | { pathname: Router.RelativePathString, params?: Router.UnknownInputParams } | { pathname: Router.ExternalPathString, params?: Router.UnknownInputParams } | { pathname: `/`; params?: Router.UnknownInputParams; } | { pathname: `/login`; params?: Router.UnknownInputParams; } | { pathname: `/_sitemap`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/create-product-group` | `/create-product-group`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/add-product` | `/add-product`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/add-slot` | `/add-slot`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/add-store` | `/add-store`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/add-tag` | `/add-tag`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/address-management` | `/address-management`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/complaints` | `/complaints`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/coupons` | `/coupons`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/coupons/reserved-coupons` | `/coupons/reserved-coupons`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/create-coupon` | `/create-coupon`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/customize-app` | `/customize-app`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/customize-app/popular-items` | `/customize-app/popular-items`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/dashboard-banners` | `/dashboard-banners`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/dashboard-banners/create-banner` | `/dashboard-banners/create-banner`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/dashboard` | `/dashboard`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/delivery-sequences` | `/delivery-sequences`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/edit-product` | `/edit-product`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/edit-store` | `/edit-store`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/edit-tag` | `/edit-tag`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/manage-orders` | `/manage-orders`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/orders` | `/orders`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/prices-overview` | `/prices-overview`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/product-groupings` | `/product-groupings`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/product-tags` | `/product-tags`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/products` | `/products`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/rebalance-orders` | `/rebalance-orders`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/slots/slot-details` | `/slots/slot-details`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/slots` | `/slots`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/stores` | `/stores`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/users` | `/users`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/vendor-snippets` | `/vendor-snippets`; params?: Router.UnknownInputParams; } | `${'/(drawer)'}/dashboard-banners/edit-banner/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `/dashboard-banners/edit-banner/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/edit-coupon/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `/edit-coupon/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/edit-product-group/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `/edit-product-group/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/edit-slot/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `/edit-slot/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/order-details/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `/order-details/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/product-detail/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `/product-detail/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/user-details/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `/user-details/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | { pathname: `${'/(drawer)'}/dashboard-banners/edit-banner/[id]` | `/dashboard-banners/edit-banner/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/edit-coupon/[id]` | `/edit-coupon/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/edit-product-group/[id]` | `/edit-product-group/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/edit-slot/[id]` | `/edit-slot/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/order-details/[id]` | `/order-details/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/product-detail/[id]` | `/product-detail/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/user-details/[id]` | `/user-details/[id]`, params: Router.UnknownInputParams & { id: string | number; } }; + hrefInputParams: { pathname: Router.RelativePathString, params?: Router.UnknownInputParams } | { pathname: Router.ExternalPathString, params?: Router.UnknownInputParams } | { pathname: `/`; params?: Router.UnknownInputParams; } | { pathname: `/login`; params?: Router.UnknownInputParams; } | { pathname: `/_sitemap`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/create-product-group` | `/create-product-group`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/add-product` | `/add-product`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/add-slot` | `/add-slot`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/add-store` | `/add-store`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/add-tag` | `/add-tag`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/address-management` | `/address-management`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/complaints` | `/complaints`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/coupons` | `/coupons`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/coupons/reserved-coupons` | `/coupons/reserved-coupons`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/create-coupon` | `/create-coupon`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/customize-app` | `/customize-app`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/customize-app/popular-items` | `/customize-app/popular-items`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/dashboard` | `/dashboard`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/dashboard-banners` | `/dashboard-banners`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/dashboard-banners/create-banner` | `/dashboard-banners/create-banner`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/delivery-sequences` | `/delivery-sequences`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/edit-product` | `/edit-product`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/edit-store` | `/edit-store`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/edit-tag` | `/edit-tag`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/manage-orders` | `/manage-orders`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/orders` | `/orders`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/prices-overview` | `/prices-overview`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/product-groupings` | `/product-groupings`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/product-tags` | `/product-tags`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/products` | `/products`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/rebalance-orders` | `/rebalance-orders`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/slots` | `/slots`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/slots/slot-details` | `/slots/slot-details`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/stores` | `/stores`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/users` | `/users`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/vendor-snippets` | `/vendor-snippets`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/dashboard-banners/edit-banner/[id]` | `/dashboard-banners/edit-banner/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/edit-coupon/[id]` | `/edit-coupon/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/edit-product-group/[id]` | `/edit-product-group/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/edit-slot/[id]` | `/edit-slot/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/order-details/[id]` | `/order-details/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/product-detail/[id]` | `/product-detail/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/user-details/[id]` | `/user-details/[id]`, params: Router.UnknownInputParams & { id: string | number; } }; + hrefOutputParams: { pathname: Router.RelativePathString, params?: Router.UnknownOutputParams } | { pathname: Router.ExternalPathString, params?: Router.UnknownOutputParams } | { pathname: `/`; params?: Router.UnknownOutputParams; } | { pathname: `/login`; params?: Router.UnknownOutputParams; } | { pathname: `/_sitemap`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/create-product-group` | `/create-product-group`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/add-product` | `/add-product`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/add-slot` | `/add-slot`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/add-store` | `/add-store`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/add-tag` | `/add-tag`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/address-management` | `/address-management`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/complaints` | `/complaints`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/coupons` | `/coupons`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/coupons/reserved-coupons` | `/coupons/reserved-coupons`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/create-coupon` | `/create-coupon`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/customize-app` | `/customize-app`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/customize-app/popular-items` | `/customize-app/popular-items`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/dashboard` | `/dashboard`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/dashboard-banners` | `/dashboard-banners`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/dashboard-banners/create-banner` | `/dashboard-banners/create-banner`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/delivery-sequences` | `/delivery-sequences`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/edit-product` | `/edit-product`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/edit-store` | `/edit-store`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/edit-tag` | `/edit-tag`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/manage-orders` | `/manage-orders`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/orders` | `/orders`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/prices-overview` | `/prices-overview`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/product-groupings` | `/product-groupings`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/product-tags` | `/product-tags`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/products` | `/products`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/rebalance-orders` | `/rebalance-orders`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/slots` | `/slots`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/slots/slot-details` | `/slots/slot-details`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/stores` | `/stores`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/users` | `/users`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/vendor-snippets` | `/vendor-snippets`; params?: Router.UnknownOutputParams; } | { pathname: `${'/(drawer)'}/dashboard-banners/edit-banner/[id]` | `/dashboard-banners/edit-banner/[id]`, params: Router.UnknownOutputParams & { id: string; } } | { pathname: `${'/(drawer)'}/edit-coupon/[id]` | `/edit-coupon/[id]`, params: Router.UnknownOutputParams & { id: string; } } | { pathname: `${'/(drawer)'}/edit-product-group/[id]` | `/edit-product-group/[id]`, params: Router.UnknownOutputParams & { id: string; } } | { pathname: `${'/(drawer)'}/edit-slot/[id]` | `/edit-slot/[id]`, params: Router.UnknownOutputParams & { id: string; } } | { pathname: `${'/(drawer)'}/order-details/[id]` | `/order-details/[id]`, params: Router.UnknownOutputParams & { id: string; } } | { pathname: `${'/(drawer)'}/product-detail/[id]` | `/product-detail/[id]`, params: Router.UnknownOutputParams & { id: string; } } | { pathname: `${'/(drawer)'}/user-details/[id]` | `/user-details/[id]`, params: Router.UnknownOutputParams & { id: string; } }; + href: Router.RelativePathString | Router.ExternalPathString | `/${`?${string}` | `#${string}` | ''}` | `/login${`?${string}` | `#${string}` | ''}` | `/_sitemap${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/create-product-group${`?${string}` | `#${string}` | ''}` | `/create-product-group${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/add-product${`?${string}` | `#${string}` | ''}` | `/add-product${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/add-slot${`?${string}` | `#${string}` | ''}` | `/add-slot${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/add-store${`?${string}` | `#${string}` | ''}` | `/add-store${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/add-tag${`?${string}` | `#${string}` | ''}` | `/add-tag${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/address-management${`?${string}` | `#${string}` | ''}` | `/address-management${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/complaints${`?${string}` | `#${string}` | ''}` | `/complaints${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/coupons${`?${string}` | `#${string}` | ''}` | `/coupons${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/coupons/reserved-coupons${`?${string}` | `#${string}` | ''}` | `/coupons/reserved-coupons${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/create-coupon${`?${string}` | `#${string}` | ''}` | `/create-coupon${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/customize-app${`?${string}` | `#${string}` | ''}` | `/customize-app${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/customize-app/popular-items${`?${string}` | `#${string}` | ''}` | `/customize-app/popular-items${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/dashboard${`?${string}` | `#${string}` | ''}` | `/dashboard${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/dashboard-banners${`?${string}` | `#${string}` | ''}` | `/dashboard-banners${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/dashboard-banners/create-banner${`?${string}` | `#${string}` | ''}` | `/dashboard-banners/create-banner${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/delivery-sequences${`?${string}` | `#${string}` | ''}` | `/delivery-sequences${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/edit-product${`?${string}` | `#${string}` | ''}` | `/edit-product${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/edit-store${`?${string}` | `#${string}` | ''}` | `/edit-store${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/edit-tag${`?${string}` | `#${string}` | ''}` | `/edit-tag${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/manage-orders${`?${string}` | `#${string}` | ''}` | `/manage-orders${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/orders${`?${string}` | `#${string}` | ''}` | `/orders${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/prices-overview${`?${string}` | `#${string}` | ''}` | `/prices-overview${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/product-groupings${`?${string}` | `#${string}` | ''}` | `/product-groupings${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/product-tags${`?${string}` | `#${string}` | ''}` | `/product-tags${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/products${`?${string}` | `#${string}` | ''}` | `/products${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/rebalance-orders${`?${string}` | `#${string}` | ''}` | `/rebalance-orders${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/slots${`?${string}` | `#${string}` | ''}` | `/slots${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/slots/slot-details${`?${string}` | `#${string}` | ''}` | `/slots/slot-details${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/stores${`?${string}` | `#${string}` | ''}` | `/stores${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/users${`?${string}` | `#${string}` | ''}` | `/users${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/vendor-snippets${`?${string}` | `#${string}` | ''}` | `/vendor-snippets${`?${string}` | `#${string}` | ''}` | { pathname: Router.RelativePathString, params?: Router.UnknownInputParams } | { pathname: Router.ExternalPathString, params?: Router.UnknownInputParams } | { pathname: `/`; params?: Router.UnknownInputParams; } | { pathname: `/login`; params?: Router.UnknownInputParams; } | { pathname: `/_sitemap`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/create-product-group` | `/create-product-group`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/add-product` | `/add-product`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/add-slot` | `/add-slot`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/add-store` | `/add-store`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/add-tag` | `/add-tag`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/address-management` | `/address-management`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/complaints` | `/complaints`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/coupons` | `/coupons`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/coupons/reserved-coupons` | `/coupons/reserved-coupons`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/create-coupon` | `/create-coupon`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/customize-app` | `/customize-app`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/customize-app/popular-items` | `/customize-app/popular-items`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/dashboard` | `/dashboard`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/dashboard-banners` | `/dashboard-banners`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/dashboard-banners/create-banner` | `/dashboard-banners/create-banner`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/delivery-sequences` | `/delivery-sequences`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/edit-product` | `/edit-product`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/edit-store` | `/edit-store`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/edit-tag` | `/edit-tag`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/manage-orders` | `/manage-orders`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/orders` | `/orders`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/prices-overview` | `/prices-overview`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/product-groupings` | `/product-groupings`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/product-tags` | `/product-tags`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/products` | `/products`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/rebalance-orders` | `/rebalance-orders`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/slots` | `/slots`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/slots/slot-details` | `/slots/slot-details`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/stores` | `/stores`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/users` | `/users`; params?: Router.UnknownInputParams; } | { pathname: `${'/(drawer)'}/vendor-snippets` | `/vendor-snippets`; params?: Router.UnknownInputParams; } | `${'/(drawer)'}/dashboard-banners/edit-banner/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `/dashboard-banners/edit-banner/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/edit-coupon/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `/edit-coupon/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/edit-product-group/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `/edit-product-group/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/edit-slot/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `/edit-slot/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/order-details/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `/order-details/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/product-detail/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `/product-detail/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `${'/(drawer)'}/user-details/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | `/user-details/${Router.SingleRoutePart}${`?${string}` | `#${string}` | ''}` | { pathname: `${'/(drawer)'}/dashboard-banners/edit-banner/[id]` | `/dashboard-banners/edit-banner/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/edit-coupon/[id]` | `/edit-coupon/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/edit-product-group/[id]` | `/edit-product-group/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/edit-slot/[id]` | `/edit-slot/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/order-details/[id]` | `/order-details/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/product-detail/[id]` | `/product-detail/[id]`, params: Router.UnknownInputParams & { id: string | number; } } | { pathname: `${'/(drawer)'}/user-details/[id]` | `/user-details/[id]`, params: Router.UnknownInputParams & { id: string | number; } }; } } } diff --git a/apps/backend/src/lib/init.ts b/apps/backend/src/lib/init.ts index 1e3532b..0cf5f43 100755 --- a/apps/backend/src/lib/init.ts +++ b/apps/backend/src/lib/init.ts @@ -1,6 +1,7 @@ import roleManager from './roles-manager'; import './notif-job'; import { computeConstants } from './const-store'; +import { initializeProducts } from './product-store'; /** * Initialize all application services @@ -21,6 +22,10 @@ export const initFunc = async (): Promise => { await computeConstants(); console.log('Const store initialized successfully'); + // Initialize product store in Redis + await initializeProducts(); + console.log('Product store initialized successfully'); + // Notification queue and worker are initialized via import console.log('Notification queue and worker initialized'); diff --git a/apps/backend/src/lib/product-store.ts b/apps/backend/src/lib/product-store.ts new file mode 100644 index 0000000..cf60716 --- /dev/null +++ b/apps/backend/src/lib/product-store.ts @@ -0,0 +1,165 @@ +import redisClient from './redis-client'; +import { db } from '../db/db_index'; +import { productInfo, units, productSlots, deliverySlotInfo, specialDeals, storeInfo } from '../db/schema'; +import { generateSignedUrlsFromS3Urls } from './s3-client'; +import { eq, and, gt, sql } from 'drizzle-orm'; + +// Uniform Product Type (matches getProductDetails return) +interface Product { + id: number; + name: string; + shortDescription: string | null; + longDescription: string | null; + price: string; + marketPrice: string | null; + unitNotation: string; + images: string[]; + isOutOfStock: boolean; + store: { id: number; name: string; description: string | null } | null; + incrementStep: number; + productQuantity: number; + isFlashAvailable: boolean; + flashPrice: string | null; + deliverySlots: Array<{ id: number; deliveryTime: Date; freezeTime: Date }>; + specialDeals: Array<{ quantity: string; price: string; validTill: Date }>; +} + +export async function initializeProducts(): Promise { + try { + console.log('Initializing product store in Redis...'); + + // Fetch all products with full details (similar to productMega logic) + const productsData = await db + .select({ + id: productInfo.id, + name: productInfo.name, + shortDescription: productInfo.shortDescription, + longDescription: productInfo.longDescription, + price: productInfo.price, + marketPrice: productInfo.marketPrice, + images: productInfo.images, + isOutOfStock: productInfo.isOutOfStock, + storeId: productInfo.storeId, + unitShortNotation: units.shortNotation, + incrementStep: productInfo.incrementStep, + productQuantity: productInfo.productQuantity, + isFlashAvailable: productInfo.isFlashAvailable, + flashPrice: productInfo.flashPrice, + }) + .from(productInfo) + .innerJoin(units, eq(productInfo.unitId, units.id)); + + // Fetch all stores + const allStores = await db.query.storeInfo.findMany({ + columns: { id: true, name: true, description: true }, + }); + const storeMap = new Map(allStores.map(s => [s.id, s])); + + // Fetch all delivery slots + const allDeliverySlots = await db + .select({ + productId: productSlots.productId, + id: deliverySlotInfo.id, + deliveryTime: deliverySlotInfo.deliveryTime, + freezeTime: deliverySlotInfo.freezeTime, + }) + .from(productSlots) + .innerJoin(deliverySlotInfo, eq(productSlots.slotId, deliverySlotInfo.id)) + .where( + and( + eq(deliverySlotInfo.isActive, true), + gt(deliverySlotInfo.deliveryTime, sql`NOW()`) + ) + ); + const deliverySlotsMap = new Map(); + for (const slot of allDeliverySlots) { + if (!deliverySlotsMap.has(slot.productId)) deliverySlotsMap.set(slot.productId, []); + deliverySlotsMap.get(slot.productId)!.push(slot); + } + + // Fetch all special deals + const allSpecialDeals = await db + .select({ + productId: specialDeals.productId, + quantity: specialDeals.quantity, + price: specialDeals.price, + validTill: specialDeals.validTill, + }) + .from(specialDeals) + .where(gt(specialDeals.validTill, sql`NOW()`)); + const specialDealsMap = new Map(); + for (const deal of allSpecialDeals) { + if (!specialDealsMap.has(deal.productId)) specialDealsMap.set(deal.productId, []); + specialDealsMap.get(deal.productId)!.push(deal); + } + + // Store each product in Redis + for (const product of productsData) { + const signedImages = await generateSignedUrlsFromS3Urls((product.images as string[]) || []); + const store = product.storeId ? storeMap.get(product.storeId) || null : null; + const deliverySlots = deliverySlotsMap.get(product.id) || []; + const specialDeals = specialDealsMap.get(product.id) || []; + + const productObj: Product = { + id: product.id, + name: product.name, + shortDescription: product.shortDescription, + longDescription: product.longDescription, + price: product.price.toString(), + marketPrice: product.marketPrice?.toString() || null, + unitNotation: product.unitShortNotation, + images: signedImages, + isOutOfStock: product.isOutOfStock, + store: store ? { id: store.id, name: store.name, description: store.description } : null, + incrementStep: product.incrementStep, + productQuantity: product.productQuantity, + isFlashAvailable: product.isFlashAvailable, + flashPrice: product.flashPrice?.toString() || null, + deliverySlots: deliverySlots.map(s => ({ id: s.id, deliveryTime: s.deliveryTime, freezeTime: s.freezeTime })), + specialDeals: specialDeals.map(d => ({ quantity: d.quantity.toString(), price: d.price.toString(), validTill: d.validTill })), + }; + + await redisClient.set(`product:${product.id}`, JSON.stringify(productObj)); + } + + console.log('Product store initialized successfully'); + } catch (error) { + console.error('Error initializing product store:', error); + } +} + +export async function getProductById(id: number): Promise { + try { + const key = `product:${id}`; + const data = await redisClient.get(key); + if (!data) return null; + return JSON.parse(data) as Product; + } catch (error) { + console.error(`Error getting product ${id}:`, error); + return null; + } +} + +export async function getAllProducts(): Promise { + try { + // Get all keys matching the pattern "product:*" + const keys = await redisClient.KEYS('product:*'); + + if (keys.length === 0) return []; + + // Get all products using MGET for better performance + const productsData = await redisClient.MGET(keys); + + const products: Product[] = []; + for (const productData of productsData) { + if (productData) { + products.push(JSON.parse(productData) as Product); + } + } + + return products; + } catch (error) { + console.error('Error getting all products:', error); + return []; + } +} \ No newline at end of file diff --git a/apps/backend/src/lib/redis-client.ts b/apps/backend/src/lib/redis-client.ts index 8539efa..a4937cb 100644 --- a/apps/backend/src/lib/redis-client.ts +++ b/apps/backend/src/lib/redis-client.ts @@ -63,6 +63,14 @@ class RedisClient { return await this.client.lPush(key, value); } + async KEYS(pattern: string): Promise { + return await this.client.KEYS(pattern); + } + + async MGET(keys: string[]): Promise<(string | null)[]> { + return await this.client.MGET(keys); + } + disconnect(): void { if (this.isConnected) { this.client.disconnect(); diff --git a/apps/backend/src/trpc/common-apis/common.ts b/apps/backend/src/trpc/common-apis/common.ts index 651cf21..c43265b 100644 --- a/apps/backend/src/trpc/common-apis/common.ts +++ b/apps/backend/src/trpc/common-apis/common.ts @@ -4,6 +4,7 @@ import { productInfo, units, productSlots, deliverySlotInfo, storeInfo, productT import { eq, gt, and, sql, inArray } from 'drizzle-orm'; import { generateSignedUrlsFromS3Urls, generateSignedUrlFromS3Url } from '../../lib/s3-client'; import { z } from 'zod'; +import { getAllProducts as getAllProductsFromCache } from '../../lib/product-store'; export const getNextDeliveryDate = async (productId: number): Promise => { const result = await db @@ -58,76 +59,60 @@ export const commonRouter = router({ .query(async ({ input }) => { const { searchQuery, tagId } = input; - let productIds: number[] | null = null; + // Get all products from cache + let products = await getAllProductsFromCache(); - // If tagId is provided, get products that have this tag + // Apply tag filtering if tagId is provided if (tagId) { + // Get products that have this tag from the database const taggedProducts = await db .select({ productId: productTags.productId }) .from(productTags) .where(eq(productTags.tagId, tagId)); - productIds = taggedProducts.map(tp => tp.productId); + const taggedProductIds = new Set(taggedProducts.map(tp => tp.productId)); + + // Filter products based on tag + products = products.filter(product => taggedProductIds.has(product.id)); } - let whereConditions = []; - - // Add tag filtering - if (productIds && productIds.length > 0) { - whereConditions.push(inArray(productInfo.id, productIds)); - } else if (tagId) { - // If tagId was provided but no products found, return empty array - return { - products: [], - count: 0, - }; - } - - // Add search filtering + // Apply search filtering if searchQuery is provided if (searchQuery) { - whereConditions.push(sql`LOWER(${productInfo.name}) LIKE LOWER(${ '%' + searchQuery + '%' })`); + const searchLower = searchQuery.toLowerCase(); + products = products.filter(product => + product.name.toLowerCase().includes(searchLower) + ); } + // Get suspended product IDs to filter them out + const suspendedProducts = await db + .select({ id: productInfo.id }) + .from(productInfo) + .where(eq(productInfo.isSuspended, true)); + + const suspendedProductIds = new Set(suspendedProducts.map(sp => sp.id)); + // Filter out suspended products - whereConditions.push(eq(productInfo.isSuspended, false)); + products = products.filter(product => !suspendedProductIds.has(product.id)); - const whereCondition = whereConditions.length > 0 ? and(...whereConditions) : undefined; - - const productsWithUnits = await db - .select({ - id: productInfo.id, - name: productInfo.name, - shortDescription: productInfo.shortDescription, - price: productInfo.price, - marketPrice: productInfo.marketPrice, - images: productInfo.images, - isOutOfStock: productInfo.isOutOfStock, - unitShortNotation: units.shortNotation, - incrementStep: productInfo.incrementStep, - productQuantity: productInfo.productQuantity, - storeId: productInfo.storeId, - }) - .from(productInfo) - .innerJoin(units, eq(productInfo.unitId, units.id)) - .where(whereCondition); - - // Generate signed URLs for product images + // Format products to match the expected response structure const formattedProducts = await Promise.all( - productsWithUnits.map(async (product) => { + products.map(async (product) => { const nextDeliveryDate = await getNextDeliveryDate(product.id); return { id: product.id, name: product.name, shortDescription: product.shortDescription, - price: product.price, - marketPrice: product.marketPrice, - unit: product.unitShortNotation, + price: parseFloat(product.price), + marketPrice: product.marketPrice ? parseFloat(product.marketPrice) : null, + unit: product.unitNotation, + unitNotation: product.unitNotation, incrementStep: product.incrementStep, productQuantity: product.productQuantity, - storeId: product.storeId, + storeId: product.store?.id || null, isOutOfStock: product.isOutOfStock, nextDeliveryDate: nextDeliveryDate ? nextDeliveryDate.toISOString() : null, - images: await generateSignedUrlsFromS3Urls((product.images as string[]) || []), + images: product.images, // Already signed URLs from cache }; }) ); diff --git a/apps/backend/src/trpc/user-apis/product.ts b/apps/backend/src/trpc/user-apis/product.ts index d1380a1..92b74e5 100644 --- a/apps/backend/src/trpc/user-apis/product.ts +++ b/apps/backend/src/trpc/user-apis/product.ts @@ -5,6 +5,27 @@ import { productInfo, units, productSlots, deliverySlotInfo, specialDeals, store import { generateSignedUrlsFromS3Urls, generateSignedUrlFromS3Url, generateUploadUrl, claimUploadUrl, extractKeyFromPresignedUrl } from '../../lib/s3-client'; import { ApiError } from '../../lib/api-error'; import { eq, and, gt, sql, inArray, desc } from 'drizzle-orm'; +import { getProductById as getProductByIdFromCache } from '../../lib/product-store'; + +// Uniform Product Type +interface Product { + id: number; + name: string; + shortDescription: string | null; + longDescription: string | null; + price: string; + marketPrice: string | null; + unitNotation: string; + images: string[]; + isOutOfStock: boolean; + store: { id: number; name: string; description: string | null } | null; + incrementStep: number; + productQuantity: number; + isFlashAvailable: boolean; + flashPrice: string | null; + deliverySlots: Array<{ id: number; deliveryTime: Date; freezeTime: Date }>; + specialDeals: Array<{ quantity: string; price: string; validTill: Date }>; +} export const productRouter = router({ getDashboardTags: publicProcedure @@ -32,7 +53,7 @@ export const productRouter = router({ .input(z.object({ id: z.string().regex(/^\d+$/, 'Invalid product ID'), })) - .query(async ({ input }) => { + .query(async ({ input }): Promise => { const { id } = input; const productId = parseInt(id); @@ -40,7 +61,14 @@ export const productRouter = router({ throw new Error('Invalid product ID'); } - // Fetch product with unit information + // First, try to get the product from Redis cache + const cachedProduct = await getProductByIdFromCache(productId); + + if (cachedProduct) { + return cachedProduct; + } + + // If not in cache, fetch from database (fallback) const productData = await db .select({ id: productInfo.id, @@ -53,6 +81,8 @@ export const productRouter = router({ isOutOfStock: productInfo.isOutOfStock, storeId: productInfo.storeId, unitShortNotation: units.shortNotation, + incrementStep: productInfo.incrementStep, + productQuantity: productInfo.productQuantity, isFlashAvailable: productInfo.isFlashAvailable, flashPrice: productInfo.flashPrice, }) @@ -110,25 +140,27 @@ export const productRouter = router({ // Generate signed URLs for images const signedImages = await generateSignedUrlsFromS3Urls((product.images as string[]) || []); - const response = { + const response: Product = { id: product.id, name: product.name, shortDescription: product.shortDescription, longDescription: product.longDescription, - price: product.price, - marketPrice: product.marketPrice, - unit: product.unitShortNotation, + price: product.price.toString(), + marketPrice: product.marketPrice?.toString() || null, + unitNotation: product.unitShortNotation, images: signedImages, isOutOfStock: product.isOutOfStock, - isFlashAvailable: product.isFlashAvailable, - flashPrice: product.flashPrice, store: storeData ? { id: storeData.id, name: storeData.name, description: storeData.description, } : null, + incrementStep: product.incrementStep, + productQuantity: product.productQuantity, + isFlashAvailable: product.isFlashAvailable, + flashPrice: product.flashPrice?.toString() || null, deliverySlots: deliverySlotsData, - specialPackageDeals: specialDealsData, + specialDeals: specialDealsData.map(d => ({ quantity: d.quantity.toString(), price: d.price.toString(), validTill: d.validTill })), }; return response; @@ -222,48 +254,95 @@ export const productRouter = router({ }), getAllProductsSummary: publicProcedure - .query(async () => { - const products = await db - .select({ - id: productInfo.id, - name: productInfo.name, - price: productInfo.price, - marketPrice: productInfo.marketPrice, - images: productInfo.images, - isOutOfStock: productInfo.isOutOfStock, - storeId: productInfo.storeId, - unitShortNotation: units.shortNotation, - incrementStep: productInfo.incrementStep, - isFlashAvailable: productInfo.isFlashAvailable, - flashPrice: productInfo.flashPrice, - productQuantity: productInfo.productQuantity, - }) - .from(productInfo) - .innerJoin(units, eq(productInfo.unitId, units.id)); + .query(async (): Promise => { + // Get all product IDs first + const productIdsResult = await db + .select({ id: productInfo.id }) + .from(productInfo); - // Generate signed URLs for images - const productsWithSignedUrls = await Promise.all( - products.map(async (product) => ({ - id: product.id, - name: product.name, - price: product.price, - marketPrice: product.marketPrice, - unit: product.unitShortNotation, - isOutOfStock: product.isOutOfStock, - storeId: product.storeId, - images: await generateSignedUrlsFromS3Urls((product.images as string[]) || []), - incrementStep: product.incrementStep, - isFlashAvailable: product.isFlashAvailable, - flashPrice: product.flashPrice, - productQuantity: product.productQuantity, - })) - ); + const productIds = productIdsResult.map(p => p.id); - return productsWithSignedUrls; + // Try to get all products from cache first + const cachedProducts: Product[] = []; + const uncachedProductIds: number[] = []; + + console.log(uncachedProductIds) + + for (const id of productIds) { + const cachedProduct = await getProductByIdFromCache(id); + if (cachedProduct) { + cachedProducts.push(cachedProduct); + } else { + uncachedProductIds.push(id); + } + } + + // If there are uncached products, fetch them from DB + let uncachedProductsFromDb: Product[] = []; + if (uncachedProductIds.length > 0) { + const products = await db + .select({ + id: productInfo.id, + name: productInfo.name, + price: productInfo.price, + marketPrice: productInfo.marketPrice, + images: productInfo.images, + isOutOfStock: productInfo.isOutOfStock, + storeId: productInfo.storeId, + unitShortNotation: units.shortNotation, + incrementStep: productInfo.incrementStep, + isFlashAvailable: productInfo.isFlashAvailable, + flashPrice: productInfo.flashPrice, + productQuantity: productInfo.productQuantity, + }) + .from(productInfo) + .innerJoin(units, eq(productInfo.unitId, units.id)) + .where(inArray(productInfo.id, uncachedProductIds)); + + // Fetch all stores + const allStores = await db.query.storeInfo.findMany({ + columns: { id: true, name: true, description: true }, + }); + const storeMap = new Map(allStores.map(s => [s.id, s])); + + // Generate signed URLs for images and build uniform structure + uncachedProductsFromDb = await Promise.all( + products.map(async (product) => { + const signedImages = await generateSignedUrlsFromS3Urls((product.images as string[]) || []); + const store = product.storeId ? storeMap.get(product.storeId) || null : null; + + return { + id: product.id, + name: product.name, + shortDescription: null, + longDescription: null, + price: product.price.toString(), + marketPrice: product.marketPrice?.toString() || null, + unitNotation: product.unitShortNotation, + images: signedImages, + isOutOfStock: product.isOutOfStock, + store: store ? { + id: store.id, + name: store.name, + description: store.description, + } : null, + incrementStep: product.incrementStep, + productQuantity: product.productQuantity, + isFlashAvailable: product.isFlashAvailable, + flashPrice: product.flashPrice?.toString() || null, + deliverySlots: [], + specialDeals: [], + }; + }) + ); + } + + // Combine cached and uncached products + return [...cachedProducts, ...uncachedProductsFromDb]; }), productMega: publicProcedure - .query(async () => { + .query(async (): Promise => { // Fetch all products with unit info const productsData = await db .select({ @@ -277,6 +356,10 @@ export const productRouter = router({ isOutOfStock: productInfo.isOutOfStock, storeId: productInfo.storeId, unitShortNotation: units.shortNotation, + incrementStep: productInfo.incrementStep, + productQuantity: productInfo.productQuantity, + isFlashAvailable: productInfo.isFlashAvailable, + flashPrice: productInfo.flashPrice, }) .from(productInfo) .innerJoin(units, eq(productInfo.unitId, units.id)); @@ -314,23 +397,43 @@ export const productRouter = router({ deliverySlotsMap.get(slot.productId)!.push(slot); } + // Fetch all special deals for all products + const allSpecialDeals = await db + .select({ + productId: specialDeals.productId, + quantity: specialDeals.quantity, + price: specialDeals.price, + validTill: specialDeals.validTill, + }) + .from(specialDeals) + .where(gt(specialDeals.validTill, sql`NOW()`)) + .orderBy(specialDeals.quantity); + // Group by productId + const specialDealsMap = new Map(); + for (const deal of allSpecialDeals) { + if (!specialDealsMap.has(deal.productId)) { + specialDealsMap.set(deal.productId, []); + } + specialDealsMap.get(deal.productId)!.push(deal); + } // Build the response - const response = await Promise.all( + const response: Product[] = await Promise.all( productsData.map(async (product) => { const signedImages = await generateSignedUrlsFromS3Urls((product.images as string[]) || []); const store = product.storeId ? storeMap.get(product.storeId) || null : null; const deliverySlots = deliverySlotsMap.get(product.id) || []; + const specialDeals = specialDealsMap.get(product.id) || []; return { id: product.id, name: product.name, shortDescription: product.shortDescription, longDescription: product.longDescription, - price: product.price, - marketPrice: product.marketPrice, - unit: product.unitShortNotation, + price: product.price.toString(), + marketPrice: product.marketPrice?.toString() || null, + unitNotation: product.unitShortNotation, images: signedImages, isOutOfStock: product.isOutOfStock, store: store ? { @@ -338,8 +441,12 @@ export const productRouter = router({ name: store.name, description: store.description, } : null, + incrementStep: product.incrementStep, + productQuantity: product.productQuantity, + isFlashAvailable: product.isFlashAvailable, + flashPrice: product.flashPrice?.toString() || null, deliverySlots: deliverySlots.map(s => ({ id: s.id, deliveryTime: s.deliveryTime, freezeTime: s.freezeTime })), - specialPackageDeals: [], // Empty since not fetching + specialDeals: specialDeals.map(d => ({ quantity: d.quantity.toString(), price: d.price.toString(), validTill: d.validTill })), }; }) ); diff --git a/apps/user-ui/app/(drawer)/(tabs)/me/delivery-slots/index.tsx b/apps/user-ui/app/(drawer)/(tabs)/me/delivery-slots/index.tsx index d9f4aba..e239577 100644 --- a/apps/user-ui/app/(drawer)/(tabs)/me/delivery-slots/index.tsx +++ b/apps/user-ui/app/(drawer)/(tabs)/me/delivery-slots/index.tsx @@ -142,7 +142,7 @@ export default function DeliverySlots() { {product.name} - ₹{product.price} {product.unit && `per ${product.unit}`} + ₹{product.price} {product.unit && `per ${product.unit}`} {product.isOutOfStock && ( diff --git a/apps/user-ui/components/CheckoutAddressSelector.tsx b/apps/user-ui/components/CheckoutAddressSelector.tsx index a281804..cc6c233 100644 --- a/apps/user-ui/components/CheckoutAddressSelector.tsx +++ b/apps/user-ui/components/CheckoutAddressSelector.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import { View, Text, TouchableOpacity, ScrollView } from 'react-native'; import { tw, BottomDialog } from 'common-ui'; import { useQueryClient } from '@tanstack/react-query'; @@ -17,6 +17,7 @@ const CheckoutAddressSelector: React.FC = ({ }) => { const [showAddAddress, setShowAddAddress] = useState(false); const queryClient = useQueryClient(); + const scrollViewRef = useRef(null); const { data: addresses } = trpc.user.address.getUserAddresses.useQuery(); // Sort addresses with selected first, then default, then others @@ -46,6 +47,11 @@ const CheckoutAddressSelector: React.FC = ({ } }, [sortedAddresses, selectedAddress, onAddressSelect]); + // Reset scroll to left when address is selected + const resetScrollToLeft = () => { + scrollViewRef.current?.scrollTo({ x: 0, y: 0, animated: true }); + }; + return ( <> @@ -74,11 +80,19 @@ const CheckoutAddressSelector: React.FC = ({ ) : ( - + {sortedAddresses.map((address) => ( onAddressSelect(address.id)} + onPress={() => { + onAddressSelect(address.id); + resetScrollToLeft(); + }} style={tw`w-72 p-4 mr-3 bg-gray-50 rounded-xl border-2 ${selectedAddress === address.id ? 'border-brand500 bg-blue-50' : 'border-gray-200' } shadow-sm`} > diff --git a/apps/user-ui/components/ProductCard.tsx b/apps/user-ui/components/ProductCard.tsx index 3315bbd..95b9b53 100644 --- a/apps/user-ui/components/ProductCard.tsx +++ b/apps/user-ui/components/ProductCard.tsx @@ -36,7 +36,7 @@ const ProductCard: React.FC = ({ onPress, showDeliveryInfo = true, miniView = false, -}) => { +}) => { const { data: cartData } = useGetCart(); const { getQuickestSlot } = useProductSlotIdentifier(); const updateCartItem = useUpdateCartItem({ @@ -128,7 +128,7 @@ const ProductCard: React.FC = ({ )} - Quantity: {formatQuantity(item.productQuantity || 1, item.unit).display} + Quantity: {formatQuantity(item.productQuantity || 1, item.unitNotation).display} {showDeliveryInfo && item.nextDeliveryDate && ( @@ -151,7 +151,7 @@ const ProductCard: React.FC = ({ value={quantity} setValue={handleQuantityChange} step={item.incrementStep} - unit={item.unit} + unit={item.unitNotation} /> ) : ( { + if (unit?.toLowerCase() === 'kg' && quantity < 1) { + return { value: `${Math.round(quantity * 1000)} g`, display: `${Math.round(quantity * 1000)}g` }; + } + return { value: `${quantity} ${unit}(s)`, display: `${quantity}${unit}` }; +}; + const ProductDetail: React.FC = ({ productId, isFlashDelivery = false }) => { const router = useRouter(); const [showAllSlots, setShowAllSlots] = useState(false); @@ -239,7 +246,7 @@ const ProductDetail: React.FC = ({ productId, isFlashDeliver ₹{productDetail.price} - / {productDetail.unit} + / {formatQuantity(productDetail.productQuantity || 1, productDetail.unitNotation).display} {/* Show market price discount if available */} {productDetail.marketPrice && ( @@ -256,7 +263,7 @@ const ProductDetail: React.FC = ({ productId, isFlashDeliver {productDetail.isFlashAvailable && productDetail.flashPrice && productDetail.flashPrice !== productDetail.price && ( - Flash Delivery: ₹{productDetail.flashPrice} / {productDetail.unit} + Flash Delivery: ₹{productDetail.flashPrice} / {formatQuantity(productDetail.productQuantity || 1, productDetail.unitNotation).display} )} @@ -273,7 +280,7 @@ const ProductDetail: React.FC = ({ productId, isFlashDeliver value={quantity} setValue={handleQuantityChange} step={1} // Default step for product detail quantifier - unit={productDetail.unit} + unit={productDetail.unitNotation} /> ) : ( @@ -400,7 +407,7 @@ const ProductDetail: React.FC = ({ productId, isFlashDeliver {/* Package Deals */} - {productDetail.specialPackageDeals && productDetail.specialPackageDeals.length > 0 && ( + {productDetail.specialDeals && productDetail.specialDeals.length > 0 && ( @@ -410,9 +417,9 @@ const ProductDetail: React.FC = ({ productId, isFlashDeliver Bulk Savings - {productDetail.specialPackageDeals.map((deal, index) => ( + {productDetail.specialDeals.map((deal: { quantity: string; price: string; validTill: string }, index: number) => ( - Buy {deal.quantity} {productDetail.unit} + Buy {deal.quantity} {formatQuantity(parseFloat(deal.quantity), productDetail.unitNotation).display} ₹{deal.price} ))} diff --git a/apps/user-ui/components/SlotSpecificView.tsx b/apps/user-ui/components/SlotSpecificView.tsx index 2bc2c15..01d2801 100644 --- a/apps/user-ui/components/SlotSpecificView.tsx +++ b/apps/user-ui/components/SlotSpecificView.tsx @@ -293,7 +293,7 @@ const CompactProductCard = ({ onChange={handleQuantityChange} step={item.incrementStep} showUnits={true} - unit={item.unit} + unit={item.unitNotation} /> ) : ( Number(item.price) && ( ₹{item.marketPrice} )} - Quantity: {formatQuantity(item.productQuantity || 1, item.unit).display} + Quantity: {formatQuantity(item.productQuantity || 1, item.unitNotation).display} @@ -390,7 +390,7 @@ export function SlotProducts({ slotId:slotIdParent, storeId:storeIdParent, baseU ); } - const filteredProducts: any[] = storeIdNum ? productsQuery?.data?.filter(p => p.storeId === storeIdNum) || [] : slotQuery.data.products; + const filteredProducts: any[] = storeIdNum ? productsQuery?.data?.filter(p => p.store?.id === storeIdNum) || [] : slotQuery.data.products; return ( @@ -470,7 +470,7 @@ export function FlashDeliveryProducts({ storeId:storeIdParent, baseUrl, onProduc let flashProducts: any[] = []; if (storeIdNum) { // Filter by store and flash availability - flashProducts = productsQuery?.data?.filter(p => p.storeId === storeIdNum && p.isFlashAvailable) || []; + flashProducts = productsQuery?.data?.filter(p => p.store?.id === storeIdNum && p.isFlashAvailable) || []; } else { // Show all flash-available products (no slot filtering) flashProducts = productsQuery?.data?.filter(p => p.isFlashAvailable) || []; diff --git a/apps/user-ui/components/cart-page.tsx b/apps/user-ui/components/cart-page.tsx index 70cf8f0..97590c9 100644 --- a/apps/user-ui/components/cart-page.tsx +++ b/apps/user-ui/components/cart-page.tsx @@ -444,7 +444,7 @@ export default function CartPage({ isFlashDelivery = false }: CartPageProps) { {(() => { const qty = item.product?.productQuantity || 1; - const unit = item.product?.unit || ''; + const unit = item.product?.unitNotation || ''; if (unit?.toLowerCase() === 'kg' && qty < 1) { return `${Math.round(qty * 1000)}g`; } @@ -506,7 +506,7 @@ export default function CartPage({ isFlashDelivery = false }: CartPageProps) { } }} step={item.product.incrementStep} - unit={item.product?.unit} + unit={item.product?.unitNotation} /> diff --git a/apps/user-ui/components/floating-cart-bar.tsx b/apps/user-ui/components/floating-cart-bar.tsx index 914d84e..3751d99 100644 --- a/apps/user-ui/components/floating-cart-bar.tsx +++ b/apps/user-ui/components/floating-cart-bar.tsx @@ -249,7 +249,7 @@ const FloatingCartBar: React.FC = ({ }} step={item.product.incrementStep} showUnits={true} - unit={item.product?.unit} + unit={item.product?.unitNotation} /> diff --git a/apps/user-ui/hooks/cart-query-hooks.tsx b/apps/user-ui/hooks/cart-query-hooks.tsx index 8480897..5058511 100644 --- a/apps/user-ui/hooks/cart-query-hooks.tsx +++ b/apps/user-ui/hooks/cart-query-hooks.tsx @@ -25,11 +25,20 @@ interface LocalCartItem { interface ProductSummary { id: number; name: string; - price: number; - unit: string; - isOutOfStock: boolean; + shortDescription?: string | null; + longDescription?: string | null; + price: string; + marketPrice?: string | null; + unitNotation: string; images: string[]; - incrementStep?: number; + isOutOfStock: boolean; + store?: { id: number; name: string; description?: string | null } | null; + incrementStep: number; + productQuantity: number; + isFlashAvailable: boolean; + flashPrice?: string | null; + deliverySlots: Array<{ id: number; deliveryTime: Date; freezeTime: Date }>; + specialDeals: Array<{ quantity: string; price: string; validTill: Date }>; } interface CartItem { diff --git a/packages/ui/index.ts b/packages/ui/index.ts index a4413dc..33c0462 100755 --- a/packages/ui/index.ts +++ b/packages/ui/index.ts @@ -63,9 +63,9 @@ const isDevMode = Constants.executionEnvironment !== "standalone"; // const BASE_API_URL = API_URL; // const BASE_API_URL = 'http://10.0.2.2:4000'; // const BASE_API_URL = 'http://192.168.100.101:4000'; -// const BASE_API_URL = 'http://192.168.1.9:4000'; +const BASE_API_URL = 'http://192.168.1.14:4000'; // const BASE_API_URL = "https://mf.technocracy.ovh"; -let BASE_API_URL = "https://mf.freshyo.in"; +// let BASE_API_URL = "https://mf.freshyo.in"; // let BASE_API_URL = 'http://192.168.100.103:4000'; // let BASE_API_URL = 'http://192.168.29.219:4000';