diff --git a/apps/admin-ui/app/(drawer)/dashboard/customize-app/popular-items.tsx b/apps/admin-ui/app/(drawer)/dashboard/customize-app/popular-items.tsx
index 6101832..15137d1 100644
--- a/apps/admin-ui/app/(drawer)/dashboard/customize-app/popular-items.tsx
+++ b/apps/admin-ui/app/(drawer)/dashboard/customize-app/popular-items.tsx
@@ -416,7 +416,7 @@ export default function CustomizePopularItems() {
multiple={true}
label="Select Products"
placeholder="Choose products..."
- labelFormat={(product) => `${product.name} - ₹${product.price}`}
+ labelFormat={(product) => `${product.productName} - ₹${product.price}`}
/>
diff --git a/apps/admin-ui/components/BannerForm.tsx b/apps/admin-ui/components/BannerForm.tsx
index 033b299..a40b053 100644
--- a/apps/admin-ui/components/BannerForm.tsx
+++ b/apps/admin-ui/components/BannerForm.tsx
@@ -185,7 +185,7 @@ export default function BannerForm({
multiple={true}
label="Select Products"
placeholder="Select products for banner (optional)"
- labelFormat={(product) => `${product.name} (${product.price})`}
+ labelFormat={(product) => `${product.productName} (₹${product.price})`}
/>
diff --git a/apps/admin-ui/components/ProductGroupForm.tsx b/apps/admin-ui/components/ProductGroupForm.tsx
index 7e59918..216a93d 100644
--- a/apps/admin-ui/components/ProductGroupForm.tsx
+++ b/apps/admin-ui/components/ProductGroupForm.tsx
@@ -119,7 +119,7 @@ const ProductGroupForm: React.FC = ({
multiple={true}
label="Products"
placeholder="Select products"
- labelFormat={(product) => `${product.name}${product.shortDescription ? ` - ${product.shortDescription}` : ''}`}
+ labelFormat={(product) => product.label}
/>
{/* Actions */}
diff --git a/apps/admin-ui/components/ProductsSelector.tsx b/apps/admin-ui/components/ProductsSelector.tsx
index 30eba0b..b688a9f 100644
--- a/apps/admin-ui/components/ProductsSelector.tsx
+++ b/apps/admin-ui/components/ProductsSelector.tsx
@@ -9,6 +9,8 @@ interface SkuSummary {
productId: number;
productName: string;
label: string;
+ storeId: number | null;
+ price: string;
}
interface Group {
diff --git a/apps/admin-ui/components/StoreForm.tsx b/apps/admin-ui/components/StoreForm.tsx
index 4a856a7..fd5399e 100644
--- a/apps/admin-ui/components/StoreForm.tsx
+++ b/apps/admin-ui/components/StoreForm.tsx
@@ -45,12 +45,12 @@ const StoreForm = forwardRef((props, ref) => {
const [selectedImages, setSelectedImages] = useState<{ blob: Blob; mimeType: string }[]>([]);
const [displayImages, setDisplayImages] = useState<{ uri?: string }[]>([]);
- // For edit mode, pre-select products belonging to this store
+ // For edit mode, pre-select SKUs belonging to this store's products
const initialSelectedProducts = useMemo(() => {
if (mode !== 'edit' || !productsData?.products) return [];
return productsData.products
.filter(p => p.storeId === storeId)
- .map(p => p.id);
+ .flatMap(p => (p.skus || []).map(sku => sku.id));
}, [mode, productsData?.products, storeId]);
useEffect(() => {
@@ -166,8 +166,8 @@ const StoreForm = forwardRef((props, ref) => {
multiple={true}
label="Products"
placeholder="Select products"
- isDisabled={(product) => product.storeId !== null && product.storeId !== storeId}
- labelFormat={(product) => `${product.name} - ₹${product.price}`}
+ isDisabled={(sku) => sku.storeId !== null && sku.storeId !== storeId}
+ labelFormat={(sku) => `${sku.productName} - ₹${sku.price}`}
/>
Store Image
diff --git a/apps/admin-ui/components/VendorSnippetForm.tsx b/apps/admin-ui/components/VendorSnippetForm.tsx
index 0d0b2fa..87bd2c2 100644
--- a/apps/admin-ui/components/VendorSnippetForm.tsx
+++ b/apps/admin-ui/components/VendorSnippetForm.tsx
@@ -185,7 +185,7 @@ const VendorSnippetForm: React.FC = ({
multiple={true}
label="Select Products"
placeholder="Select products"
- labelFormat={(product) => `${product.name} (${product.unit})`}
+ labelFormat={(product) => product.label}
/>
{formik.errors.skuIds && formik.touched.skuIds && (
{formik.errors.skuIds}
diff --git a/apps/backend/src/trpc/apis/admin-apis/apis/product.ts b/apps/backend/src/trpc/apis/admin-apis/apis/product.ts
index 396dc75..f4475ff 100644
--- a/apps/backend/src/trpc/apis/admin-apis/apis/product.ts
+++ b/apps/backend/src/trpc/apis/admin-apis/apis/product.ts
@@ -606,31 +606,12 @@ export const productRouter = router({
getGroups: protectedProcedure
.query(async (): Promise => {
+ // getAllProductGroupsInDb already returns groups with products mapped
+ // as AdminSku[] (SKU ids per the ProductsSelector).
const groups = await getAllProductGroupsInDb()
- /*
- // Old implementation - direct DB queries:
- const groups = await db.query.productGroupInfo.findMany({
- with: {
- memberships: {
- with: {
- product: true,
- },
- },
- },
- orderBy: desc(productGroupInfo.createdAt),
- });
- */
-
return {
- groups: groups.map(group => ({
- ...group,
- products: group.memberships.map((m: any) => ({
- ...(m.product as AdminProduct),
- images: (m.product.images as string[]) || null,
- })),
- productCount: group.memberships.length,
- })),
+ groups,
}
}),
diff --git a/apps/backend/wrangler.dev.toml b/apps/backend/wrangler.dev.toml
index a86b89b..bdcbe8b 100644
--- a/apps/backend/wrangler.dev.toml
+++ b/apps/backend/wrangler.dev.toml
@@ -9,7 +9,7 @@ routes = [
[[d1_databases]]
binding = "DB"
database_name = "freshyo-backend-dev"
-database_id = "b0c7a47d-3807-4e13-8b3e-fb43a45b02b2"
+database_id = "b2528bdb-0ec0-478e-8765-b118918153c0"
#database_name = "freshyo-dev"
#database_id = "3cad440f-dc14-4baa-ab05-04eb08e206de"
migrations_dir="../../packages/db_helper_sqlite/drizzle"
diff --git a/packages/db_helper_sqlite/drizzle/0002_sku_split.sql b/packages/db_helper_sqlite/drizzle/0002_sku_split.sql
index 5f681dc..2490303 100644
--- a/packages/db_helper_sqlite/drizzle/0002_sku_split.sql
+++ b/packages/db_helper_sqlite/drizzle/0002_sku_split.sql
@@ -187,6 +187,45 @@ DROP TABLE `coupon_applicable_products`;
ALTER TABLE `__new_coupon_applicable_products` RENAME TO `coupon_applicable_products`;
CREATE UNIQUE INDEX `unique_coupon_sku` ON `coupon_applicable_products` (`coupon_id`,`sku_id`);
+-- 5b. Recreate tag + group memberships to reference product_skus.id (SKU ids)
+-- instead of product_info.id. ProductsSelector now saves SKU ids into these.
+CREATE TABLE `__new_product_tags` (
+ `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
+ `product_id` integer NOT NULL,
+ `tag_id` integer NOT NULL,
+ `assigned_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ FOREIGN KEY (`product_id`) REFERENCES `product_skus`(`id`) ON UPDATE no action ON DELETE no action,
+ FOREIGN KEY (`tag_id`) REFERENCES `product_tag_info`(`id`) ON UPDATE no action ON DELETE no action
+);
+
+INSERT INTO `__new_product_tags` (`id`, `product_id`, `tag_id`, `assigned_at`)
+SELECT
+ `pt`.`id`, `m`.`sku_id`, `pt`.`tag_id`, `pt`.`assigned_at`
+FROM `product_tags` `pt`
+JOIN `__product_to_sku` `m` ON `m`.`product_id` = `pt`.`product_id`;
+
+DROP TABLE `product_tags`;
+ALTER TABLE `__new_product_tags` RENAME TO `product_tags`;
+CREATE UNIQUE INDEX `unique_product_tag` ON `product_tags` (`product_id`,`tag_id`);
+
+CREATE TABLE `__new_product_group_membership` (
+ `product_id` integer NOT NULL,
+ `group_id` integer NOT NULL,
+ `added_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ PRIMARY KEY (`product_id`,`group_id`),
+ FOREIGN KEY (`product_id`) REFERENCES `product_skus`(`id`) ON UPDATE no action ON DELETE no action,
+ FOREIGN KEY (`group_id`) REFERENCES `product_group_info`(`id`) ON UPDATE no action ON DELETE no action
+);
+
+INSERT INTO `__new_product_group_membership` (`product_id`, `group_id`, `added_at`)
+SELECT
+ `m`.`sku_id`, `pgm`.`group_id`, `pgm`.`added_at`
+FROM `product_group_membership` `pgm`
+JOIN `__product_to_sku` `m` ON `m`.`product_id` = `pgm`.`product_id`;
+
+DROP TABLE `product_group_membership`;
+ALTER TABLE `__new_product_group_membership` RENAME TO `product_group_membership`;
+
-- 6. Remap JSON product id arrays to sku id arrays (before renaming the columns).
UPDATE `delivery_slot_info` AS `target`
SET `product_ids` = COALESCE(
diff --git a/packages/db_helper_sqlite/src/admin-apis/product.ts b/packages/db_helper_sqlite/src/admin-apis/product.ts
index e7e64f8..0b7ff88 100644
--- a/packages/db_helper_sqlite/src/admin-apis/product.ts
+++ b/packages/db_helper_sqlite/src/admin-apis/product.ts
@@ -660,19 +660,21 @@ export async function getAllProductTags(): Promise }>
+ }) as Array }>
- return tags.map((tag: ProductTagInfoRow & { products: Array }) => ({
+ return tags.map((tag: any) => ({
...mapTagInfo(tag),
- products: tag.products.map((assignment: ProductTagRow & { product: ProductRow }) => ({
+ products: tag.products.map((assignment: any) => ({
productId: assignment.productId,
tagId: assignment.tagId,
assignedAt: assignment.assignedAt,
- product: mapProduct(assignment.product),
+ product: mapSku(assignment.sku, assignment.sku.features, [], assignment.sku.marketStats),
})),
productIds: tag.products.map((assignment: ProductTagRow) => assignment.productId),
}))
@@ -730,7 +732,9 @@ export async function getProductTagById(tagId: number): Promise ({
+ products: (tag.products || []).map((assignment: any) => ({
productId: assignment.productId,
tagId: assignment.tagId,
assignedAt: assignment.assignedAt,
- product: mapProduct(assignment.product),
+ product: mapSku(assignment.sku, assignment.sku.features, [], assignment.sku.marketStats),
})),
- productIds: tag.products.map((assignment: ProductTagRow) => assignment.productId),
+ productIds: (tag.products || []).map((assignment: ProductTagRow) => assignment.productId),
}
}
@@ -776,7 +780,9 @@ export async function updateProductTag(tagId: number, input: UpdateProductTagInp
with: {
products: {
with: {
- product: true,
+ sku: {
+ with: { features: true, marketStats: true },
+ },
},
},
},
@@ -784,13 +790,13 @@ export async function updateProductTag(tagId: number, input: UpdateProductTagInp
return {
...mapTagInfo(tag),
- products: fullTag?.products.map((assignment: ProductTagRow & { product: ProductRow }) => ({
+ products: (fullTag?.products || []).map((assignment: any) => ({
productId: assignment.productId,
tagId: assignment.tagId,
assignedAt: assignment.assignedAt,
- product: mapProduct(assignment.product),
- })) || [],
- productIds: fullTag?.products.map((assignment: ProductTagRow) => assignment.productId) || [],
+ product: mapSku(assignment.sku, assignment.sku.features, [], assignment.sku.marketStats),
+ })),
+ productIds: (fullTag?.products || []).map((assignment: ProductTagRow) => assignment.productId) || [],
}
}
@@ -906,7 +912,9 @@ export async function getAllProductGroups() {
with: {
memberships: {
with: {
- product: true,
+ sku: {
+ with: { features: true, marketStats: true },
+ },
},
},
},
@@ -918,7 +926,9 @@ export async function getAllProductGroups() {
groupName: group.groupName,
description: group.description ?? null,
createdAt: group.createdAt,
- products: group.memberships.map((membership: any) => mapProduct(membership.product)),
+ products: (group.memberships || []).map((membership: any) =>
+ mapSku(membership.sku, membership.sku.features, [], membership.sku.marketStats)
+ ),
productCount: group.memberships.length,
memberships: group.memberships
}))
diff --git a/packages/db_helper_sqlite/src/admin-apis/store.ts b/packages/db_helper_sqlite/src/admin-apis/store.ts
index 650c288..178056e 100644
--- a/packages/db_helper_sqlite/src/admin-apis/store.ts
+++ b/packages/db_helper_sqlite/src/admin-apis/store.ts
@@ -1,5 +1,5 @@
import { db } from '../db/db_index'
-import { storeInfo, productInfo } from '../db/schema'
+import { storeInfo, productInfo, productSkus } from '../db/schema'
import { eq, inArray } from 'drizzle-orm'
import { runBatched } from '../lib/run-batched'
@@ -57,12 +57,23 @@ export async function createStore(
.returning()
if (products && products.length > 0) {
- await runBatched(tx, products, 10, async (t, chunk) => {
- await t
- .update(productInfo)
- .set({ storeId: newStore.id })
- .where(inArray(productInfo.id, chunk))
- })
+ // ProductsSelector sends SKU ids — resolve to the owning product ids
+ // (product_info.storeId is a product-level field).
+ const productIds = products.length > 0
+ ? await tx.query.productSkus.findMany({
+ where: inArray(productSkus.id, products),
+ columns: { productId: true },
+ }).then((rows) => [...new Set(rows.map((r) => r.productId))])
+ : []
+
+ if (productIds.length > 0) {
+ await runBatched(tx, productIds, 10, async (t, chunk) => {
+ await t
+ .update(productInfo)
+ .set({ storeId: newStore.id })
+ .where(inArray(productInfo.id, chunk))
+ })
+ }
}
return {
@@ -109,8 +120,16 @@ export async function updateStore(
.set({ storeId: null })
.where(eq(productInfo.storeId, id))
- if (products.length > 0) {
- await runBatched(tx, products, 10, async (t, chunk) => {
+ // ProductsSelector sends SKU ids — resolve to the owning product ids.
+ const productIds = products.length > 0
+ ? await tx.query.productSkus.findMany({
+ where: inArray(productSkus.id, products),
+ columns: { productId: true },
+ }).then((rows) => [...new Set(rows.map((r) => r.productId))])
+ : []
+
+ if (productIds.length > 0) {
+ await runBatched(tx, productIds, 10, async (t, chunk) => {
await t
.update(productInfo)
.set({ storeId: id })
diff --git a/packages/db_helper_sqlite/src/db/schema.ts b/packages/db_helper_sqlite/src/db/schema.ts
index a6a5c63..c2247b3 100644
--- a/packages/db_helper_sqlite/src/db/schema.ts
+++ b/packages/db_helper_sqlite/src/db/schema.ts
@@ -244,7 +244,7 @@ export const productGroupInfo = sqliteTable('product_group_info', {
})
export const productGroupMembership = sqliteTable('product_group_membership', {
- productId: integer('product_id').notNull().references(() => productInfo.id),
+ productId: integer('product_id').notNull().references(() => productSkus.id),
groupId: integer('group_id').notNull().references(() => productGroupInfo.id),
addedAt: timestampText('added_at').notNull().default(sql`CURRENT_TIMESTAMP`),
}, (t) => ({
@@ -298,7 +298,7 @@ export const productTagInfo = sqliteTable('product_tag_info', {
export const productTags = sqliteTable('product_tags', {
id: integer().primaryKey({ autoIncrement: true }),
- productId: integer('product_id').notNull().references(() => productInfo.id),
+ productId: integer('product_id').notNull().references(() => productSkus.id),
tagId: integer('tag_id').notNull().references(() => productTagInfo.id),
assignedAt: timestampText('assigned_at').notNull().default(sql`CURRENT_TIMESTAMP`),
}, (t) => ({
@@ -630,7 +630,7 @@ export const productTagInfoRelations = relations(productTagInfo, ({ many }) => (
}))
export const productTagsRelations = relations(productTags, ({ one }) => ({
- product: one(productInfo, { fields: [productTags.productId], references: [productInfo.id] }),
+ sku: one(productSkus, { fields: [productTags.productId], references: [productSkus.id] }),
tag: one(productTagInfo, { fields: [productTags.tagId], references: [productTagInfo.id] }),
}))
@@ -760,7 +760,7 @@ export const productGroupInfoRelations = relations(productGroupInfo, ({ many })
}))
export const productGroupMembershipRelations = relations(productGroupMembership, ({ one }) => ({
- product: one(productInfo, { fields: [productGroupMembership.productId], references: [productInfo.id] }),
+ sku: one(productSkus, { fields: [productGroupMembership.productId], references: [productSkus.id] }),
group: one(productGroupInfo, { fields: [productGroupMembership.groupId], references: [productGroupInfo.id] }),
}))
diff --git a/packages/db_helper_sqlite/src/user-apis/product.ts b/packages/db_helper_sqlite/src/user-apis/product.ts
index 8cd373b..b8ea694 100644
--- a/packages/db_helper_sqlite/src/user-apis/product.ts
+++ b/packages/db_helper_sqlite/src/user-apis/product.ts
@@ -242,7 +242,8 @@ export async function getAllProductsWithUnits(tagId?: number): Promise {
const features = sku.features || []
@@ -306,6 +307,8 @@ export interface SkuSummary {
productName: string
label: string
images: unknown
+ storeId: number | null
+ price: string
}
export async function getAllSkusSummary(): Promise {
@@ -314,7 +317,7 @@ export async function getAllSkusSummary(): Promise {
features: true,
marketStats: true,
product: {
- columns: { name: true },
+ columns: { name: true, storeId: true },
},
},
})
@@ -330,6 +333,8 @@ export async function getAllSkusSummary(): Promise {
productName: sku.product?.name ?? 'Unknown',
label,
images: sku.images,
+ storeId: sku.product?.storeId ?? null,
+ price: sku.marketStats?.ourPrice ? String(sku.marketStats.ourPrice) : '0',
}
})
}
diff --git a/packages/shared/types/admin.ts b/packages/shared/types/admin.ts
index a1d122b..d58531a 100644
--- a/packages/shared/types/admin.ts
+++ b/packages/shared/types/admin.ts
@@ -464,7 +464,7 @@ export interface AdminProductTagAssignment {
productId: number;
tagId: number;
assignedAt: Date;
- product: AdminProduct;
+ product: AdminSku;
}
export interface AdminProductTagWithProducts extends AdminProductTagInfo {
@@ -539,7 +539,7 @@ export interface AdminProductGroup {
groupName: string;
description: string | null;
createdAt: Date;
- products: AdminProduct[];
+ products: AdminSku[];
productCount: number;
}