feat: implement app directory routing, authentication flow, and dynamic reporting module

This commit is contained in:
Firman Ramdhani
2026-08-28 15:50:01 +07:00
parent 3e68d12ce4
commit 84e6599b23
28 changed files with 1869 additions and 478 deletions
+179 -12
View File
@@ -3,38 +3,204 @@
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 } })
import { hashPassword, verifyPassword, encrypt, decrypt } from '@/lib/auth'
import { cookies } from 'next/headers'
// === AUTHENTICATION ACTIONS ===
export async function loginUser(username: string, password: string) {
try {
const user = await prisma.user.findUnique({ where: { username } })
if (!user) return { success: false, error: 'Username tidak ditemukan.' }
if (!user.is_active) return { success: false, error: 'Akun Anda dinonaktifkan.' }
const isMatch = await verifyPassword(password, user.password)
if (!isMatch) return { success: false, error: 'Password salah.' }
const sessionData = {
id: user.id,
username: user.username,
name: user.name,
role: user.role,
photo: user.photo
}
const sessionToken = await encrypt(sessionData);
(await cookies()).set('session', sessionToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
path: '/'
})
return { success: true, user: sessionData }
} catch (e) {
console.error("Login Error:", e)
return { success: false, error: 'Terjadi kesalahan saat login.' }
}
}
export async function registerUser(id: string, name: string, photo?: string) {
export async function registerUser(name: string, username: string, password: string) {
try {
const hashedPassword = await hashPassword(password)
const user = await prisma.user.create({
data: { id, name, photo }
data: { name, username, password: hashedPassword }
})
return { success: true, user }
const sessionData = {
id: user.id,
username: user.username,
name: user.name,
role: user.role,
photo: user.photo
}
const sessionToken = await encrypt(sessionData);
(await cookies()).set('session', sessionToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
path: '/'
})
return { success: true, user: sessionData }
} catch (error: any) {
if (error.code === 'P2002') return { success: false, error: 'Nama sudah digunakan.' }
console.error("Register Error:", error)
if (error.code === 'P2002') return { success: false, error: 'Username sudah digunakan.' }
return { success: false, error: 'Terjadi kesalahan.' }
}
}
export async function updateProfile(id: string, name: string, photo?: string) {
export async function logoutUser() {
(await cookies()).delete('session')
return { success: true }
}
export async function getSessionUser() {
const cookie = (await cookies()).get('session')?.value
if (!cookie) return null
return await decrypt(cookie)
}
export async function updateProfile(id: string, name: string, photo?: string | null) {
try {
const user = await prisma.user.update({
where: { id },
data: { name, photo }
data: { name, photo: photo === undefined ? undefined : (photo || null) }
})
// Update session cookie with new data
const sessionData = {
id: user.id,
username: user.username,
name: user.name,
role: user.role,
photo: user.photo
}
const sessionToken = await encrypt(sessionData);
(await cookies()).set('session', sessionToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
path: '/'
})
revalidatePath('/')
revalidatePath('/profile')
return { success: true, user }
return { success: true, user: sessionData }
} catch (error: any) {
if (error.code === 'P2002') return { success: false, error: 'Nama sudah digunakan.' }
return { success: false, error: 'Gagal memperbarui profil.' }
}
}
export async function changePassword(id: string, oldPass: string, newPass: string) {
try {
const user = await prisma.user.findUnique({ where: { id } })
if (!user) return { success: false, error: 'User tidak ditemukan.' }
const isMatch = await verifyPassword(oldPass, user.password)
if (!isMatch) return { success: false, error: 'Password lama salah.' }
const hashed = await hashPassword(newPass)
await prisma.user.update({
where: { id },
data: { password: hashed }
})
return { success: true }
} catch (e) {
return { success: false, error: 'Gagal mengganti password.' }
}
}
// === USER MANAGEMENT (SUPERADMIN) ===
export async function getUsers(page = 1, limit = 10) {
const skip = (page - 1) * limit
const [users, total] = await Promise.all([
prisma.user.findMany({ skip, take: limit, orderBy: { created_at: 'desc' } }),
prisma.user.count()
])
return { users, total, totalPages: Math.ceil(total / limit) }
}
export async function createUserByAdmin(name: string, username: string, password: string, role: string) {
try {
const hashedPassword = await hashPassword(password)
await prisma.user.create({
data: { name, username, password: hashedPassword, role }
})
revalidatePath('/users')
return { success: true }
} catch (e: any) {
if (e.code === 'P2002') return { success: false, error: 'Username sudah digunakan.' }
return { success: false, error: 'Gagal membuat user.' }
}
}
export async function toggleUserActive(id: string, is_active: boolean) {
try {
const user = await prisma.user.findUnique({ where: { id } })
if (user?.role === 'superadmin') return { success: false, error: 'Data Superadmin tidak bisa dinonaktifkan.' }
await prisma.user.update({
where: { id },
data: { is_active }
})
revalidatePath('/users')
return { success: true }
} catch (e) {
return { success: false, error: 'Gagal mengupdate status user.' }
}
}
export async function deleteUser(id: string) {
try {
const user = await prisma.user.findUnique({ where: { id } })
if (user?.role === 'superadmin') return { success: false, error: 'Data Superadmin tidak bisa dihapus.' }
await prisma.user.delete({ where: { id } })
revalidatePath('/users')
return { success: true }
} catch (e) {
return { success: false, error: 'Gagal menghapus user.' }
}
}
export async function resetUserPassword(id: string, newPass: string) {
try {
const hashed = await hashPassword(newPass)
await prisma.user.update({
where: { id },
data: { password: hashed }
})
revalidatePath('/users')
return { success: true }
} catch (e) {
return { success: false, error: 'Gagal mereset password.' }
}
}
// === ORDER ACTIONS (DASHBOARD & CREATE) ===
export async function getAvailableOrders() {
const startOfDay = new Date()
@@ -91,6 +257,7 @@ export async function createOrder(data: {
revalidatePath('/my-orders')
return { success: true, order }
} catch (error) {
console.error("Create Order Error:", error)
return { success: false, error: 'Gagal membuat order.' }
}
}
@@ -225,7 +392,7 @@ export async function updateSubmissionPayment(submission_id: string, bill: numbe
revalidatePath(`/reports`)
return { success: true }
} catch (e) {
return { success: false, error: 'Gagal menyimpan tagihan.' }
console.error(e); return { success: false, error: 'Gagal menyimpan tagihan.' }
}
}