feat: bootstrap TitipIn application with fullstack architecture, Prisma ORM, and shadcn/ui components

This commit is contained in:
Firman Ramdhani
2026-08-28 11:18:13 +07:00
parent 84f0c1fa99
commit 5faea68379
37 changed files with 11881 additions and 250 deletions
+302
View File
@@ -0,0 +1,302 @@
'use server'
import prisma from '@/lib/prisma'
import { revalidatePath } from 'next/cache'
// === USER ACTIONS ===
export async function checkUser(id: string) {
return await prisma.user.findUnique({ where: { id } })
}
export async function registerUser(id: string, name: string, photo?: string) {
try {
const user = await prisma.user.create({
data: { id, name, photo }
})
return { success: true, user }
} catch (error: any) {
if (error.code === 'P2002') return { success: false, error: 'Nama sudah digunakan.' }
return { success: false, error: 'Terjadi kesalahan.' }
}
}
export async function updateProfile(id: string, name: string, photo?: string) {
try {
const user = await prisma.user.update({
where: { id },
data: { name, photo }
})
revalidatePath('/')
revalidatePath('/profile')
return { success: true, user }
} catch (error: any) {
if (error.code === 'P2002') return { success: false, error: 'Nama sudah digunakan.' }
return { success: false, error: 'Gagal memperbarui profil.' }
}
}
// === ORDER ACTIONS (DASHBOARD & CREATE) ===
export async function getAvailableOrders() {
const startOfDay = new Date()
startOfDay.setHours(0, 0, 0, 0)
const endOfDay = new Date()
endOfDay.setHours(23, 59, 59, 999)
return await prisma.order.findMany({
where: {
status: 'OPEN',
date: { gte: startOfDay, lte: endOfDay }
},
include: {
creator: true,
available_items: true,
submissions: { select: { user_id: true } }
},
orderBy: { date: 'desc' }
})
}
export async function getMyOrders(creator_id: string) {
return await prisma.order.findMany({
where: { creator_id },
include: {
available_items: true,
submissions: { select: { id: true } }
},
orderBy: { date: 'desc' }
})
}
export async function createOrder(data: {
creator_id: string;
title: string;
date: Date;
allow_custom: boolean;
available_items: string[];
}) {
try {
const order = await prisma.order.create({
data: {
title: data.title,
date: data.date,
allow_custom: data.allow_custom,
creator_id: data.creator_id,
status: 'DRAFT',
available_items: {
create: data.available_items.map(name => ({ name }))
}
}
})
revalidatePath('/my-orders')
return { success: true, order }
} catch (error) {
return { success: false, error: 'Gagal membuat order.' }
}
}
export async function duplicateOrder(order_id: string) {
try {
const oldOrder = await prisma.order.findUnique({
where: { id: order_id },
include: { available_items: true }
})
if (!oldOrder) return { success: false, error: 'Order tidak ditemukan' }
const newOrder = await prisma.order.create({
data: {
title: oldOrder.title + ' (Copy)',
date: new Date(),
allow_custom: oldOrder.allow_custom,
creator_id: oldOrder.creator_id,
status: 'DRAFT',
available_items: {
create: oldOrder.available_items.map(ai => ({ name: ai.name }))
}
}
})
revalidatePath('/my-orders')
return { success: true, order: newOrder }
} catch (e) {
return { success: false, error: 'Gagal menduplikasi order.' }
}
}
export async function updateOrder(order_id: string, data: {
title: string;
allow_custom: boolean;
available_items: string[];
}) {
try {
const order = await prisma.order.findUnique({
where: { id: order_id }
})
if (!order) return { success: false, error: 'Order tidak ditemukan' }
if (order.status === 'CLOSE') {
return { success: false, error: 'Order dengan status CLOSE tidak dapat diedit.' }
}
// Delete existing available items and insert updated ones
await prisma.availableItem.deleteMany({
where: { order_id }
})
const updatedOrder = await prisma.order.update({
where: { id: order_id },
data: {
title: data.title,
allow_custom: data.allow_custom,
available_items: {
create: data.available_items.map(name => ({ name }))
}
}
})
revalidatePath('/my-orders')
revalidatePath(`/my-orders/${order_id}`)
revalidatePath('/')
return { success: true, order: updatedOrder }
} catch (error) {
return { success: false, error: 'Gagal memperbarui order.' }
}
}
export async function updateOrderStatus(order_id: string, status: string) {
try {
await prisma.order.update({
where: { id: order_id },
data: { status }
})
revalidatePath('/my-orders')
revalidatePath('/')
return { success: true }
} catch (e) {
return { success: false, error: 'Gagal mengubah status.' }
}
}
export async function deleteOrder(order_id: string) {
try {
const order = await prisma.order.findUnique({
where: { id: order_id }
})
if (!order) return { success: false, error: 'Order tidak ditemukan.' }
if (order.status === 'OPEN') {
return { success: false, error: 'Order berstatus OPEN tidak dapat dihapus. Silakan tutup (CLOSE) terlebih dahulu.' }
}
await prisma.order.delete({
where: { id: order_id }
})
revalidatePath('/my-orders')
revalidatePath('/')
return { success: true }
} catch (e) {
return { success: false, error: 'Gagal menghapus order.' }
}
}
// === ORDER DETAIL ===
export async function getOrderDetail(order_id: string) {
return await prisma.order.findUnique({
where: { id: order_id },
include: {
creator: true,
available_items: true,
submissions: {
include: {
user: true,
items: true
}
}
}
})
}
export async function updateSubmissionPayment(submission_id: string, bill: number | null, payment_status: string) {
try {
await prisma.submission.update({
where: { id: submission_id },
data: { bill, payment_status }
})
revalidatePath(`/my-orders`)
revalidatePath(`/my-purchases`)
return { success: true }
} catch (e) {
return { success: false, error: 'Gagal menyimpan tagihan.' }
}
}
// === SUBMISSION (PESANAN SAYA) ===
export async function getUserSubmission(order_id: string, user_id: string) {
return await prisma.submission.findFirst({
where: { order_id, user_id },
include: { items: true }
})
}
export async function getMyPurchases(user_id: string) {
return await prisma.submission.findMany({
where: { user_id },
include: {
order: {
include: {
creator: true,
available_items: true
}
},
items: true
},
orderBy: {
order: { date: 'desc' }
}
})
}
export async function submitOrder(data: {
order_id: string;
user_id: string;
items: Array<{ name: string; qty: number; is_custom: boolean }>;
}) {
try {
if (data.items.length === 0) {
return { success: false, error: 'Pilih minimal 1 item.' }
}
const existing = await prisma.submission.findFirst({
where: { order_id: data.order_id, user_id: data.user_id }
})
if (existing) {
await prisma.submissionItem.deleteMany({ where: { submission_id: existing.id } })
await prisma.submission.update({
where: { id: existing.id },
data: {
items: {
create: data.items
}
}
})
} else {
await prisma.submission.create({
data: {
order_id: data.order_id,
user_id: data.user_id,
items: {
create: data.items
}
}
})
}
revalidatePath('/')
revalidatePath('/my-purchases')
revalidatePath(`/my-orders/${data.order_id}`)
return { success: true }
} catch (error) {
console.error(error)
return { success: false, error: 'Gagal mengirim pesanan.' }
}
}