first commit

This commit is contained in:
2026-01-17 14:17:42 +05:30
commit 0f194eb9e7
328 changed files with 73544 additions and 0 deletions

View File

@@ -0,0 +1,114 @@
import { NextRequest, NextResponse } from 'next/server'
import { auth } from '@/auth'
import { prisma } from '@/lib/prisma'
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const session = await auth()
if (!session?.user || session.user.role !== 'ADMIN') {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const { id } = await params
const product = await prisma.product.findUnique({
where: { id },
include: {
category: {
select: {
id: true,
name: true
}
}
}
})
if (!product) {
return NextResponse.json({ error: 'Product not found' }, { status: 404 })
}
return NextResponse.json(product)
} catch (error) {
console.error('Error fetching product:', error)
return NextResponse.json(
{ error: 'Failed to fetch product' },
{ status: 500 }
)
}
}
export async function PUT(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const session = await auth()
if (!session?.user || session.user.role !== 'ADMIN') {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const { id } = await params
const body = await request.json()
const { name, description, price, discount, images, stock, sku, isActive, categoryId, weight } = body
const product = await prisma.product.update({
where: { id },
data: {
name,
description,
price,
discount,
images,
stock,
sku,
isActive,
categoryId,
weight,
slug: name.toLowerCase().replace(/[^a-z0-9\s-]/g, '').replace(/\s+/g, '-').replace(/-+/g, '-') + '-' + Date.now()
},
include: {
category: true
}
})
return NextResponse.json(product)
} catch (error) {
console.error('Error updating product:', error)
return NextResponse.json(
{ error: 'Failed to update product' },
{ status: 500 }
)
}
}
export async function DELETE(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const session = await auth()
if (!session?.user || session.user.role !== 'ADMIN') {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const { id } = await params
await prisma.product.delete({
where: { id }
})
return NextResponse.json({ success: true })
} catch (error) {
console.error('Error deleting product:', error)
return NextResponse.json(
{ error: 'Failed to delete product' },
{ status: 500 }
)
}
}

View File

@@ -0,0 +1,61 @@
import { NextRequest, NextResponse } from 'next/server'
import { auth } from '@/auth'
import { prisma } from '@/lib/prisma'
export async function PATCH(request: NextRequest) {
try {
const session = await auth()
if (!session?.user || session.user.role !== 'ADMIN') {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const { productIds, action } = body
if (!productIds || !Array.isArray(productIds) || productIds.length === 0) {
return NextResponse.json(
{ error: 'Product IDs are required' },
{ status: 400 }
)
}
let updateData: any = {}
switch (action) {
case 'activate':
updateData = { isActive: true }
break
case 'deactivate':
updateData = { isActive: false }
break
case 'delete':
await prisma.product.deleteMany({
where: {
id: { in: productIds }
}
})
return NextResponse.json({ success: true })
default:
return NextResponse.json(
{ error: 'Invalid action' },
{ status: 400 }
)
}
await prisma.product.updateMany({
where: {
id: { in: productIds }
},
data: updateData
})
return NextResponse.json({ success: true })
} catch (error) {
console.error('Error in bulk action:', error)
return NextResponse.json(
{ error: 'Failed to perform bulk action' },
{ status: 500 }
)
}
}

View File

@@ -0,0 +1,195 @@
import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '@/lib/prisma'
import { auth } from '@/auth'
export async function GET(request: NextRequest) {
try {
const session = await auth()
if (!session?.user || session.user.role !== 'ADMIN') {
return NextResponse.json(
{ success: false, message: 'Unauthorized' },
{ status: 401 }
)
}
const { searchParams } = new URL(request.url)
const selectedColumns = searchParams.get('columns')?.split(',') || []
const categoryId = searchParams.get('categoryId') || ''
const isActive = searchParams.get('isActive') || ''
const limit = parseInt(searchParams.get('limit') || '10000')
// Build where clause based on filters
const whereClause: any = {}
if (categoryId && categoryId !== '') {
whereClause.categoryId = categoryId
}
if (isActive && isActive !== '') {
whereClause.isActive = isActive === 'true'
}
// Fetch products with category information
const products = await prisma.product.findMany({
where: whereClause,
include: {
category: {
select: { name: true }
}
},
take: limit,
orderBy: { createdAt: 'desc' }
})
// Transform data based on selected columns
const transformedData = products.map(product => {
const baseData = {
id: product.id,
name: product.name,
description: product.description || '',
price: product.price,
discount: product.discount,
stock: product.stock,
sku: product.sku,
slug: product.slug,
isActive: product.isActive,
categoryName: product.category?.name || '',
categoryId: product.categoryId || '',
brand: product.brand || '',
origin: product.origin || '',
weight: product.weight || '',
images: product.images.join(', '),
createdAt: product.createdAt.toISOString(),
updatedAt: product.updatedAt.toISOString(),
// Calculated fields
finalPrice: product.price - (product.price * product.discount / 100),
discountAmount: product.price * product.discount / 100,
stockStatus: product.stock > 10 ? 'In Stock' : product.stock > 0 ? 'Low Stock' : 'Out of Stock',
status: product.isActive ? 'Active' : 'Inactive'
}
// Filter by selected columns if specified
if (selectedColumns.length > 0) {
const filteredData: any = {}
selectedColumns.forEach(column => {
if (column in baseData) {
filteredData[column] = (baseData as any)[column]
}
})
return filteredData
}
return baseData
})
return NextResponse.json({
success: true,
data: transformedData,
count: transformedData.length
})
} catch (error) {
console.error('Product export error:', error)
return NextResponse.json(
{ success: false, message: 'Internal server error' },
{ status: 500 }
)
}
}
export async function POST(request: NextRequest) {
try {
const session = await auth()
if (!session?.user || session.user.role !== 'ADMIN') {
return NextResponse.json(
{ success: false, message: 'Unauthorized' },
{ status: 401 }
)
}
const { columns = [], filters = {} } = await request.json()
const selectedColumns = columns || []
const categoryId = filters.categoryId || ''
const isActive = filters.isActive || ''
const limit = parseInt(filters.limit || '10000')
// Build where clause based on filters
const whereClause: any = {}
if (categoryId && categoryId !== '') {
whereClause.categoryId = categoryId
}
if (isActive && isActive !== '') {
whereClause.isActive = isActive === 'true'
}
// Fetch products with category information
const products = await prisma.product.findMany({
where: whereClause,
include: {
category: {
select: { name: true }
}
},
take: limit,
orderBy: { createdAt: 'desc' }
})
// Transform data based on selected columns
const transformedData = products.map(product => {
const baseData = {
id: product.id,
name: product.name,
description: product.description || '',
price: product.price,
discount: product.discount,
stock: product.stock,
sku: product.sku,
slug: product.slug,
isActive: product.isActive,
categoryName: product.category?.name || '',
categoryId: product.categoryId || '',
brand: product.brand || '',
origin: product.origin || '',
weight: product.weight || '',
images: product.images.join(', '),
createdAt: product.createdAt.toISOString(),
updatedAt: product.updatedAt.toISOString(),
// Calculated fields
finalPrice: product.price - (product.price * product.discount / 100),
discountAmount: product.price * product.discount / 100,
stockStatus: product.stock > 10 ? 'In Stock' : product.stock > 0 ? 'Low Stock' : 'Out of Stock',
status: product.isActive ? 'Active' : 'Inactive'
}
// Filter by selected columns if specified
if (selectedColumns.length > 0) {
const filteredData: any = {}
selectedColumns.forEach((column: string) => {
if (column in baseData) {
filteredData[column] = (baseData as any)[column]
}
})
return filteredData
}
return baseData
})
return NextResponse.json({
success: true,
data: transformedData,
count: transformedData.length
})
} catch (error) {
console.error('Product export error:', error)
return NextResponse.json(
{ success: false, message: 'Internal server error' },
{ status: 500 }
)
}
}

View File

@@ -0,0 +1,162 @@
import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '@/lib/prisma'
import { auth } from '@/auth'
export async function POST(request: NextRequest) {
try {
const session = await auth()
if (!session?.user || session.user.role !== 'ADMIN') {
return NextResponse.json(
{ success: false, message: 'Unauthorized' },
{ status: 401 }
)
}
const { data } = await request.json()
if (!Array.isArray(data) || data.length === 0) {
return NextResponse.json(
{ success: false, message: 'No products provided' },
{ status: 400 }
)
}
let successCount = 0
let errorCount = 0
const errors: string[] = []
// Process products in batches to avoid overwhelming the database
const batchSize = 50
const batches: any[][] = []
for (let i = 0; i < data.length; i += batchSize) {
batches.push(data.slice(i, i + batchSize))
}
for (let batchIndex = 0; batchIndex < batches.length; batchIndex++) {
const batch = batches[batchIndex]
try {
const productsToCreate: any[] = []
const productsToUpdate: any[] = []
for (let index = 0; index < batch.length; index++) {
const productData = batch[index]
try {
// Validate required fields
if (!productData.name || !productData.price) {
errors.push(`Row ${batchIndex * batchSize + index + 1}: Missing required fields (name, price)`)
errorCount++
continue
}
// Check if category exists
let categoryId: string | undefined = undefined
if (productData.categoryId) {
const category = await prisma.category.findUnique({
where: { id: productData.categoryId }
})
if (category) {
categoryId = category.id
} else {
errors.push(`Row ${batchIndex * batchSize + index + 1}: Category with ID '${productData.categoryId}' not found`)
errorCount++
continue
}
}
// Generate SKU if not provided
const sku = productData.sku || `PROD-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
// Prepare product data
const productPayload = {
name: productData.name.trim(),
description: productData.description || '',
price: parseFloat(productData.price) || 0,
discount: parseFloat(productData.discount) || 0,
stock: parseInt(productData.stock) || 0,
sku: sku,
slug: productData.slug || productData.name.toLowerCase().replace(/[^a-z0-9]+/g, '-'),
isActive: productData.active === 'true' || productData.active === true || productData.active === '1' || true,
...(categoryId && { categoryId }),
brand: productData.brand || '',
origin: productData.origin || '',
weight: productData.weight || '',
images: productData.images ? (typeof productData.images === 'string' ? productData.images.split(',').map((img: string) => img.trim()) : []) : []
}
// Check if product exists (by SKU)
const existingProduct = await prisma.product.findUnique({
where: { sku: productPayload.sku }
})
if (existingProduct) {
// Update existing product - create update data without null categoryId
const updatePayload = { ...productPayload }
if (!categoryId) {
delete updatePayload.categoryId
}
productsToUpdate.push({
where: { id: existingProduct.id },
data: updatePayload
})
} else {
// Create new product
productsToCreate.push(productPayload)
}
} catch (error) {
errors.push(`Row ${batchIndex * batchSize + index + 1}: ${error instanceof Error ? error.message : 'Processing error'}`)
errorCount++
}
}
// Create new products
if (productsToCreate.length > 0) {
try {
await prisma.product.createMany({
data: productsToCreate,
skipDuplicates: true
})
successCount += productsToCreate.length
} catch (error) {
errors.push(`Batch ${batchIndex + 1}: Failed to create products - ${error instanceof Error ? error.message : 'Unknown error'}`)
errorCount += productsToCreate.length
}
}
// Update existing products
for (const updateData of productsToUpdate) {
try {
await prisma.product.update(updateData)
successCount++
} catch (error) {
errors.push(`Failed to update product: ${error instanceof Error ? error.message : 'Unknown error'}`)
errorCount++
}
}
} catch (error) {
errors.push(`Batch ${batchIndex + 1}: ${error instanceof Error ? error.message : 'Batch processing error'}`)
errorCount += batch.length
}
}
return NextResponse.json({
success: errorCount === 0,
message: errorCount === 0 ?
`Successfully imported ${successCount} products` :
`Import completed with errors. ${successCount} successful, ${errorCount} failed.`,
successCount,
errorCount,
errors: errors.slice(0, 50) // Limit to first 50 errors
})
} catch (error) {
console.error('Product import error:', error)
return NextResponse.json(
{ success: false, message: 'Internal server error' },
{ status: 500 }
)
}
}

View File

@@ -0,0 +1,54 @@
import { NextRequest, NextResponse } from 'next/server'
import { auth } from '@/auth'
import { prisma } from '@/lib/prisma'
export async function POST(request: NextRequest) {
try {
const session = await auth()
if (!session?.user || session.user.role !== 'ADMIN') {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const { name, description, price, discount, images, stock, sku, isActive, categoryId } = body
// Check if SKU already exists
const existingSku = await prisma.product.findUnique({
where: { sku }
})
if (existingSku) {
return NextResponse.json(
{ error: 'SKU already exists' },
{ status: 400 }
)
}
const product = await prisma.product.create({
data: {
name,
description,
price,
discount,
images,
stock,
sku,
isActive,
categoryId,
slug: name.toLowerCase().replace(/[^a-z0-9\s-]/g, '').replace(/\s+/g, '-').replace(/-+/g, '-') + '-' + Date.now()
},
include: {
category: true
}
})
return NextResponse.json(product)
} catch (error) {
console.error('Error creating product:', error)
return NextResponse.json(
{ error: 'Failed to create product' },
{ status: 500 }
)
}
}