feat: initial implementation of modern modular webshop (shop core)

This commit is contained in:
DanielS
2026-04-30 23:41:56 +02:00
commit 5538d87283
72 changed files with 12853 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
'use server'
import { createClient } from '@/lib/supabase/server'
import { revalidatePath } from 'next/cache'
import { Order } from '../types'
export async function submitOrder(orderData: {
product_id: string;
selected_modules: string[];
total_amount: number;
customer_details: any;
}) {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) throw new Error('Not authenticated')
const { data, error } = await supabase
.from('orders')
.insert([{
user_id: user.id,
total_amount: orderData.total_amount,
items: {
product_id: orderData.product_id,
modules: orderData.selected_modules
},
billing_details: orderData.customer_details,
status: 'pending'
}])
.select()
.single()
if (error) throw error
revalidatePath('/admin/orders') // If there was an admin orders page
return data
}

View File

@@ -0,0 +1,84 @@
'use server'
import { createClient } from '@/lib/supabase/server'
import { revalidatePath } from 'next/cache'
import { Product, ProductModule } from '../types'
export async function getProducts() {
const supabase = await createClient()
const { data, error } = await supabase
.from('products')
.select('*, modules:product_modules(*)')
.order('created_at', { ascending: false })
if (error) throw error
return data as Product[]
}
export async function createProduct(product: Omit<Product, 'id' | 'created_at' | 'updated_at'>, modules: Omit<ProductModule, 'id' | 'product_id' | 'created_at'>[]) {
const supabase = await createClient()
// Start a transaction-like approach (Supabase doesn't have cross-table transactions easily in one call via JS client without RPC)
const { data: newProduct, error: productError } = await supabase
.from('products')
.insert([product])
.select()
.single()
if (productError) throw productError
if (modules.length > 0) {
const modulesWithId = modules.map(m => ({ ...m, product_id: newProduct.id }))
const { error: modulesError } = await supabase
.from('product_modules')
.insert(modulesWithId)
if (modulesError) throw modulesError
}
revalidatePath('/admin/products')
revalidatePath('/order')
return newProduct
}
export async function updateProduct(id: string, product: Partial<Product>, modules: any[]) {
const supabase = await createClient()
const { error: productError } = await supabase
.from('products')
.update(product)
.eq('id', id)
if (productError) throw productError
// For modules, a simple approach is to delete and re-insert or use upsert if they have IDs
// To keep it simple: Delete all modules and re-insert the current list
await supabase.from('product_modules').delete().eq('product_id', id)
if (modules.length > 0) {
const modulesWithId = modules.map(m => ({
name: m.name,
description: m.description,
additional_price: m.additional_price,
is_required: m.is_required,
product_id: id
}))
const { error: modulesError } = await supabase
.from('product_modules')
.insert(modulesWithId)
if (modulesError) throw modulesError
}
revalidatePath('/admin/products')
revalidatePath('/order')
}
export async function deleteProduct(id: string) {
const supabase = await createClient()
const { error } = await supabase.from('products').delete().eq('id', id)
if (error) throw error
revalidatePath('/admin/products')
revalidatePath('/order')
}