freshyo/verifier/admin-apis/apis/store.ts
2026-03-22 20:20:18 +05:30

211 lines
6 KiB
TypeScript

import { router, protectedProcedure } from '@/src/trpc/trpc-index'
import { z } from 'zod';
import { db } from '@/src/db/db_index'
import { storeInfo, productInfo } from '@/src/db/schema'
import { eq, inArray } from 'drizzle-orm';
import { ApiError } from '@/src/lib/api-error'
import { extractKeyFromPresignedUrl, deleteImageUtil, scaffoldAssetUrl } from '@/src/lib/s3-client'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { scheduleStoreInitialization } from '@/src/stores/store-initializer'
export const storeRouter = router({
getStores: protectedProcedure
.query(async ({ ctx }) => {
const stores = await db.query.storeInfo.findMany({
with: {
owner: true,
},
});
Promise.all(stores.map(async store => {
if(store.imageUrl)
store.imageUrl = scaffoldAssetUrl(store.imageUrl)
})).catch((e) => {
throw new ApiError("Unable to find store image urls")
}
)
return {
stores,
count: stores.length,
};
}),
getStoreById: protectedProcedure
.input(z.object({
id: z.number(),
}))
.query(async ({ input, ctx }) => {
const { id } = input;
const store = await db.query.storeInfo.findFirst({
where: eq(storeInfo.id, id),
with: {
owner: true,
},
});
if (!store) {
throw new ApiError("Store not found", 404);
}
store.imageUrl = scaffoldAssetUrl(store.imageUrl);
return {
store,
};
}),
createStore: protectedProcedure
.input(z.object({
name: z.string().min(1, "Name is required"),
description: z.string().optional(),
imageUrl: z.string().optional(),
owner: z.number().min(1, "Owner is required"),
products: z.array(z.number()).optional(),
}))
.mutation(async ({ input, ctx }) => {
const { name, description, imageUrl, owner, products } = input;
// const imageKey = imageUrl ? extractKeyFromPresignedUrl(imageUrl) : undefined;
const imageKey = imageUrl
const [newStore] = await db
.insert(storeInfo)
.values({
name,
description,
imageUrl: imageKey,
owner,
})
.returning();
// Assign selected products to this store
if (products && products.length > 0) {
await db
.update(productInfo)
.set({ storeId: newStore.id })
.where(inArray(productInfo.id, products));
}
// Reinitialize stores to reflect changes
scheduleStoreInitialization()
return {
store: newStore,
message: "Store created successfully",
};
}),
updateStore: protectedProcedure
.input(z.object({
id: z.number(),
name: z.string().min(1, "Name is required"),
description: z.string().optional(),
imageUrl: z.string().optional(),
owner: z.number().min(1, "Owner is required"),
products: z.array(z.number()).optional(),
}))
.mutation(async ({ input, ctx }) => {
const { id, name, description, imageUrl, owner, products } = input;
const existingStore = await db.query.storeInfo.findFirst({
where: eq(storeInfo.id, id),
});
if (!existingStore) {
throw new ApiError("Store not found", 404);
}
const oldImageKey = existingStore.imageUrl;
const newImageKey = imageUrl ? extractKeyFromPresignedUrl(imageUrl) : oldImageKey;
// Delete old image only if:
// 1. New image provided and keys are different, OR
// 2. No new image but old exists (clearing the image)
if (oldImageKey && (
(newImageKey && newImageKey !== oldImageKey) ||
(!newImageKey)
)) {
try {
await deleteImageUtil({keys: [oldImageKey]});
} catch (error) {
console.error('Failed to delete old image:', error);
// Continue with update even if deletion fails
}
}
const [updatedStore] = await db
.update(storeInfo)
.set({
name,
description,
imageUrl: newImageKey,
owner,
})
.where(eq(storeInfo.id, id))
.returning();
if (!updatedStore) {
throw new ApiError("Store not found", 404);
}
// Update products if provided
if (products) {
// First, set storeId to null for products not in the list but currently assigned to this store
await db
.update(productInfo)
.set({ storeId: null })
.where(eq(productInfo.storeId, id));
// Then, assign the selected products to this store
if (products.length > 0) {
await db
.update(productInfo)
.set({ storeId: id })
.where(inArray(productInfo.id, products));
}
}
// Reinitialize stores to reflect changes
scheduleStoreInitialization()
return {
store: updatedStore,
message: "Store updated successfully",
};
}),
deleteStore: protectedProcedure
.input(z.object({
storeId: z.number(),
}))
.mutation(async ({ input, ctx }) => {
const { storeId } = input;
const result = await db.transaction(async (tx) => {
// First, update all products of this store to set storeId to null
await tx
.update(productInfo)
.set({ storeId: null })
.where(eq(productInfo.storeId, storeId));
// Then delete the store
const [deletedStore] = await tx
.delete(storeInfo)
.where(eq(storeInfo.id, storeId))
.returning();
if (!deletedStore) {
throw new ApiError("Store not found", 404);
}
return {
message: "Store deleted successfully",
};
});
// Reinitialize stores to reflect changes (outside transaction)
scheduleStoreInitialization()
return result;
}),
});