"feat: add EventItem, EventReview models with seed data and mock files, update User and Event schemas"

This commit is contained in:
louiscklaw
2025-06-03 15:29:05 +08:00
parent a0a4ffcb4e
commit 24920fb313
52 changed files with 2140 additions and 56 deletions

View File

@@ -0,0 +1,75 @@
// src/app/api/product/createEvent/route.ts
//
// PURPOSE:
// create product to db
//
// RULES:
// T.B.A.
//
import type { NextRequest } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
import prisma from '../../../lib/prisma';
// ----------------------------------------------------------------------
/** **************************************
* POST - Events
*************************************** */
export async function POST(req: NextRequest) {
// logger('[Event] list', events.length);
const { data } = await req.json();
const createForm: CreateEventData = data as unknown as CreateEventData;
console.log({ createForm });
try {
console.log({ data });
await prisma.productItem.create({ data: createForm });
return response({ hello: 'world' }, STATUS.OK);
} catch (error) {
console.log({ hello: 'world', data });
return handleError('Event - Create', error);
}
}
type CreateEventData = {
// id: string;
sku: string;
name: string;
code: string;
price: number;
taxes: number;
tags: string[];
sizes: string[];
publish: string;
gender: string[];
coverUrl: string;
images: string[];
colors: string[];
quantity: number;
category: string;
available: number;
totalSold: number;
description: string;
totalRatings: number;
totalReviews: number;
inventoryType: string;
subDescription: string;
priceSale: number;
newLabel: {
content: string;
enabled: boolean;
};
saleLabel: {
content: string;
enabled: boolean;
};
// ratings: {
// name: string;
// starCount: number;
// reviewCount: number;
// }[];
};

View File

@@ -0,0 +1,44 @@
// src/app/api/event/deleteEvent/route.ts
//
// PURPOSE:
// delete event from db by id
//
// RULES:
// T.B.A.
import type { NextRequest } from 'next/server';
import { logger } from 'src/utils/logger';
import { STATUS, response, handleError } from 'src/utils/response';
import prisma from '../../../lib/prisma';
// ----------------------------------------------------------------------
/** **************************************
* handle Delete Events
*************************************** */
export async function DELETE(req: NextRequest) {
try {
const { searchParams } = req.nextUrl;
// RULES: eventId must exist
const eventId = searchParams.get('eventId');
if (!eventId) {
return response({ message: 'Event ID is required!' }, STATUS.BAD_REQUEST);
}
// NOTE: eventId confirmed exist, run below
const event = await prisma.eventItem.delete({ where: { id: eventId } });
if (!event) {
return response({ message: 'Event not found!' }, STATUS.NOT_FOUND);
}
logger('[Event] details', event.id);
return response({ event }, STATUS.OK);
} catch (error) {
return handleError('Event - Get details', error);
}
}

View File

@@ -0,0 +1,3 @@
###
DELETE http://localhost:7272/api/event/deleteEvent?eventId=e99f09a7-dd88-49d5-b1c8-1daf80c2d7b06

View File

@@ -0,0 +1,47 @@
// src/app/api/event/details/route.ts
//
// PURPOSE:
// save event to db by id
//
// RULES:
// T.B.A.
import type { NextRequest } from 'next/server';
import { logger } from 'src/utils/logger';
import { STATUS, response, handleError } from 'src/utils/response';
import prisma from '../../../lib/prisma';
// ----------------------------------------------------------------------
/** **************************************
* GET Event detail
*************************************** */
export async function GET(req: NextRequest) {
try {
const { searchParams } = req.nextUrl;
// RULES: eventId must exist
const eventId = searchParams.get('eventId');
if (!eventId) {
return response({ message: 'Event ID is required!' }, STATUS.BAD_REQUEST);
}
// NOTE: eventId confirmed exist, run below
const event = await prisma.eventItem.findFirst({
include: { reviews: true },
where: { id: eventId },
});
if (!event) {
return response({ message: 'Event not found!' }, STATUS.NOT_FOUND);
}
logger('[Event] details', event.id);
return response({ event }, STATUS.OK);
} catch (error) {
return handleError('Event - Get details', error);
}
}

View File

@@ -0,0 +1,3 @@
###
GET http://localhost:7272/api/event/details?eventId=e99f09a7-dd88-49d5-b1c8-1daf80c2d7b01

View File

@@ -0,0 +1,30 @@
// src/app/api/event/image/upload/route.ts
//
// PURPOSE:
// handle upload event image
//
// RULES:
// T.B.A.
import type { NextRequest } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
// import prisma from '../../../lib/prisma';
// ----------------------------------------------------------------------
/** **************************************
* GET - Events
*************************************** */
export async function POST(req: NextRequest) {
try {
const { data } = await req.json();
console.log('helloworld');
return response({ hello: 'world' }, STATUS.OK);
} catch (error) {
console.log({ hello: 'world' });
return handleError('Event - store event image', error);
}
}

View File

@@ -0,0 +1,22 @@
// src/app/api/event/list/route.ts
import { logger } from 'src/utils/logger';
import { STATUS, response, handleError } from 'src/utils/response';
import prisma from '../../../lib/prisma';
// ----------------------------------------------------------------------
/** **************************************
* GET - Events
*************************************** */
export async function GET() {
try {
const events = await prisma.eventItem.findMany();
logger('[Event] list', events.length);
return response({ events }, STATUS.OK);
} catch (error) {
return handleError('Event - Get list', error);
}
}

View File

@@ -0,0 +1,3 @@
###
GET http://localhost:7272/api/event/list

View File

@@ -0,0 +1,129 @@
// src/app/api/event/saveEvent/route.ts
//
// PURPOSE:
// save event to db by id
//
// RULES:
// T.B.A.
import type { NextRequest } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
import prisma from '../../../lib/prisma';
// ----------------------------------------------------------------------
/** **************************************
* GET - Events
*************************************** */
export async function POST(req: NextRequest) {
// logger('[Event] list', events.length);
const { data } = await req.json();
try {
const events = await prisma.eventItem.updateMany({
data: {
name: data.name,
sku: data.sku,
code: data.code,
price: data.price,
taxes: data.taxes,
tags: data.tags,
sizes: data.sizes,
publish: data.publish,
gender: data.gender,
coverUrl: data.coverUrl,
images: data.images,
colors: data.colors,
quantity: data.quantity,
category: data.category,
available: data.available,
totalSold: data.totalSold,
description: data.description,
totalRatings: data.totalRatings,
totalReviews: data.totalReviews,
inventoryType: data.inventoryType,
subDescription: data.subDescription,
priceSale: data.priceSale,
//
newLabel: {
content: data.newLabel?.content || '',
enabled: data.newLabel?.enabled ?? false,
},
saleLabel: {
content: data.saleLabel?.content || '',
enabled: data.saleLabel?.enabled ?? false,
},
ratings: {
set: data.ratings.map((rating: { name: string; starCount: number; reviewCount: number }) => ({
name: rating.name,
starCount: rating.starCount,
reviewCount: rating.reviewCount,
})),
},
},
where: { id: data.id },
});
return response({ data }, STATUS.OK);
} catch (error) {
console.log({ data });
return handleError('Event - Get list', error);
}
}
export type IEventItem = {
id: string;
sku: string;
name: string;
code: string;
price: number;
taxes: number;
tags: string[];
sizes: string[];
publish: string;
gender: string[];
coverUrl: string;
images: string[];
colors: string[];
quantity: number;
category: string;
available: number;
totalSold: number;
description: string;
totalRatings: number;
totalReviews: number;
// createdAt: IDateValue;
inventoryType: string;
subDescription: string;
priceSale: number | null;
// reviews: IEventReview[];
newLabel: {
content: string;
enabled: boolean;
};
saleLabel: {
content: string;
enabled: boolean;
};
ratings: {
name: string;
starCount: number;
reviewCount: number;
}[];
};
export type IDateValue = string | number | null;
export type IEventReview = {
id: string;
name: string;
rating: number;
comment: string;
helpful: number;
avatarUrl: string;
postedAt: IDateValue;
isPurchased: boolean;
attachments?: string[];
};

View File

@@ -0,0 +1,35 @@
import type { NextRequest } from 'next/server';
import { logger } from 'src/utils/logger';
import { STATUS, response, handleError } from 'src/utils/response';
import { _events } from 'src/_mock/_event';
// ----------------------------------------------------------------------
export const runtime = 'edge';
/** **************************************
* GET - Search events
*************************************** */
export async function GET(req: NextRequest) {
try {
const { searchParams } = req.nextUrl;
const query = searchParams.get('query')?.trim().toLowerCase();
if (!query) {
return response({ results: [] }, STATUS.OK);
}
const events = _events();
// Accept search by name or sku
const results = events.filter(({ name, sku }) => name.toLowerCase().includes(query) || sku?.toLowerCase().includes(query));
logger('[Event] search-results', results.length);
return response({ results }, STATUS.OK);
} catch (error) {
return handleError('Event - Get search', error);
}
}

View File

@@ -1,7 +1,8 @@
# GUIDELINE
this is a helloworld api endpoint
this is a demo to handle helloworld record
- this is a helloworld api endpoint
- this is a demo to handle helloworld record
- use single file for single db table/collection only
## `route.ts`

View File

@@ -0,0 +1,39 @@
// src/app/api/helloworld/detail/route.ts
//
// PURPOSE:
// Get single helloworld record detail
//
// RULES:
// - For helloworld requests, return simple response
//
import type { NextRequest } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
import prisma from '../../../lib/prisma';
// ----------------------------------------------------------------------
/**
**************************************
* GET - Handle both helloworld and user details
**************************************
*/
export async function GET(req: NextRequest) {
// Original user details functionality
try {
const { searchParams } = req.nextUrl;
// RULES: helloworldId must exist
const helloworldId = searchParams.get('helloworldId');
if (!helloworldId) return response({ message: 'helloworldId is required!' }, STATUS.BAD_REQUEST);
const helloworld = await prisma.userItem.findFirst({ where: { id: helloworldId } });
if (!helloworld) return response({ message: 'User not found!' }, STATUS.NOT_FOUND);
return response({ helloworld }, STATUS.OK);
} catch (error) {
return handleError('Product - Get details', error);
}
}

View File

@@ -0,0 +1,4 @@
###
GET http://localhost:7272/api/helloworld/details?helloworldId=1165ce3a-29b8-4e1a-9148-1ae08d7e8e01

View File

@@ -6,6 +6,11 @@ import { listHelloworlds, deleteHelloworld, updateHelloworld, createNewHelloworl
// import prisma from '../../lib/prisma';
/**
***************************************
* GET - list all Helloworlds
***************************************
*/
export async function GET(req: NextRequest, res: NextResponse) {
try {
const result = await listHelloworlds();

View File

@@ -0,0 +1,23 @@
# GUIDELINE
- this is a helloworld api endpoint
- this is a demo to handle helloworld record
- use single file for single db table/collection only
## `route.ts`
handle `GET`, `POST`, `PUT`, `DELETE`
## `test.http`
store test request
## `../../services/helloworld.service.ts`
helloworld schema CRUD handler
`listHelloworlds` - list helloworld record
`getHelloworld` - get helloworld record by id
`createNewHelloworld` - create helloworld record
`updateHelloworld` - update helloworld record by id
`deleteHelloworld` - delete helloworld record by id

View File

@@ -0,0 +1,76 @@
import type { NextRequest, NextResponse } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
import { listOrders, deleteOrder, updateOrder, createOrder } from 'src/app/services/order.service';
/**
**************************************
* GET - Order
***************************************
*/
export async function GET(req: NextRequest, res: NextResponse) {
try {
const orders = await listOrders();
return response(orders, STATUS.OK);
} catch (error) {
return handleError('Order - Get list', error);
}
}
/**
***************************************
* POST - Create Order
***************************************
*/
export async function POST(req: NextRequest) {
const { data } = await req.json();
try {
const order = await createOrder(data);
return response(order, STATUS.CREATED);
} catch (error) {
return handleError('Order - Create', error);
}
}
/**
***************************************
* PUT - Update Order
***************************************
*/
export async function PUT(req: NextRequest) {
const { searchParams } = req.nextUrl;
const orderId = searchParams.get('orderId');
const { data } = await req.json();
try {
if (!orderId) throw new Error('orderId cannot be null');
const id: number = parseInt(orderId);
const updatedOrder = await updateOrder(id, data);
return response(updatedOrder, STATUS.OK);
} catch (error) {
return handleError('Order - Update', error);
}
}
/**
***************************************
* DELETE - Delete Order
***************************************
*/
export async function DELETE(req: NextRequest) {
const { searchParams } = req.nextUrl;
const orderId = searchParams.get('orderId');
try {
if (!orderId) throw new Error('orderId cannot be null');
const id: number = parseInt(orderId);
await deleteOrder(id);
return response({ success: true }, STATUS.OK);
} catch (error) {
return handleError('Order - Delete', error);
}
}

View File

@@ -0,0 +1,32 @@
###
GET http://localhost:7272/api/order
###
GET http://localhost:7272/api/order?orderId=1
###
POST http://localhost:7272/api/order
content-type: application/json
{
"data": {
"product": "Sample Product",
"quantity": 1,
"price": 99.99
}
}
###
PUT http://localhost:7272/api/order?orderId=1
content-type: application/json
{
"data": {
"product": "Updated Product",
"quantity": 2,
"price": 199.98
}
}
###
DELETE http://localhost:7272/api/order?orderId=1

View File

@@ -0,0 +1,74 @@
import type { NextRequest, NextResponse } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
import { listProducts, deleteProduct, updateProduct, createProduct } from 'src/app/services/product.service';
/**
**************************************
* GET - Product
***************************************
*/
export async function GET(req: NextRequest, res: NextResponse) {
try {
const products = await listProducts();
return response(products, STATUS.OK);
} catch (error) {
return handleError('Product - Get list', error);
}
}
/**
***************************************
* POST - Create Product
***************************************
*/
export async function POST(req: NextRequest) {
const { data } = await req.json();
try {
const product = await createProduct(data);
return response(product, STATUS.CREATED);
} catch (error) {
return handleError('Product - Create', error);
}
}
/**
***************************************
* PUT - Update Product
***************************************
*/
export async function PUT(req: NextRequest) {
const { searchParams } = req.nextUrl;
const productId = searchParams.get('productId');
const { data } = await req.json();
try {
if (!productId) throw new Error('productId cannot be null');
const result = await updateProduct(productId, data);
return response(result, STATUS.OK);
} catch (error) {
return handleError('Product - Update', error);
}
}
/**
***************************************
* DELETE - Delete Product
***************************************
*/
export async function DELETE(req: NextRequest) {
const { searchParams } = req.nextUrl;
const productId = searchParams.get('productId');
try {
if (!productId) throw new Error('productId cannot be null');
await deleteProduct(productId);
return response({ success: true }, STATUS.OK);
} catch (error) {
return handleError('Product - Delete', error);
}
}

View File

@@ -0,0 +1,33 @@
###
GET http://localhost:7272/api/product
###
GET http://localhost:7272/api/product?productId=1
###
POST http://localhost:7272/api/product
content-type: application/json
{
"data": {
"sku": "PROD-001",
"name": "Premium Product",
"price": 99.99,
"quantity": 100,
"category": "Electronics",
}
}
###
PUT http://localhost:7272/api/product?productId=1
content-type: application/json
{
"data": {
"price": 89.99,
"quantity": 95
}
}
###
DELETE http://localhost:7272/api/product?productId=1

View File

@@ -0,0 +1,36 @@
// src/app/api/user/promoteToAdmin/route.ts
//
import type { NextRequest } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
import { changeToAdmin } from 'src/app/services/userItem.service';
/**
***************************************
* PUT - promote user to admin
***************************************
*/
export async function PUT(req: NextRequest) {
const { searchParams } = req.nextUrl;
// userId, the userId going to be admin
// {data: requestUserId}, the userId sending request to promote admin
// the requestUserId should be a admin admin already
const userId = searchParams.get('userId');
const {
data: { requestUserId },
} = await req.json();
try {
if (!userId) return response('userId cannot be null', STATUS.BAD_REQUEST);
if (!requestUserId) return response('requestUserId cannot be null', STATUS.BAD_REQUEST);
const result = await changeToAdmin(userId, requestUserId);
return response(result, STATUS.OK);
} catch (error) {
return handleError('promote to admin', JSON.stringify(error));
}
}

View File

@@ -0,0 +1,33 @@
# step 1 check not a admin
###
GET http://localhost:7272/api/user/details?userId=00b8b53b-dfe6-4b07-8d23-0dc9f75e7a2c
# step 1 check not a admin
###
GET http://localhost:7272/api/user/details?userId=5e072d02-919c-49c4-98b4-9659b8eff231
# step 2 request to change admin
###
PUT http://localhost:7272/api/user/changeToAdmin?userId=00b8b53b-dfe6-4b07-8d23-0dc9f75e7a2c
content-type: application/json
{
"data": {"requestUserId": "5e072d02-919c-49c4-98b4-9659b8eff231"}
}
# step 2 request to change user
###
PUT http://localhost:7272/api/user/changeToUser?userId=00b8b53b-dfe6-4b07-8d23-0dc9f75e7a2c
content-type: application/json
{
"data": {"requestUserId": "5e072d02-919c-49c4-98b4-9659b8eff231"}
}
# step 3 it is now admin
###
GET http://localhost:7272/api/user/details?userId=00b8b53b-dfe6-4b07-8d23-0dc9f75e7a2c

View File

@@ -0,0 +1,36 @@
// src/app/api/user/changeToUser/route.ts
//
import type { NextRequest } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
import { changeToUser } from 'src/app/services/userItem.service';
/**
***************************************
* PUT - change admin back to regular user
***************************************
*/
export async function PUT(req: NextRequest) {
const { searchParams } = req.nextUrl;
// userId, the userId going to be changed to regular user
// {data: requestUserId}, the userId sending request to change role
// the requestUserId should be an admin
const userId = searchParams.get('userId');
const {
data: { requestUserId },
} = await req.json();
try {
if (!userId) throw new Error('userId cannot be null');
if (!requestUserId) throw new Error('requestUserId cannot be null');
const result = await changeToUser(userId, requestUserId);
return response(result, STATUS.OK);
} catch (error) {
return handleError('change to regular user', JSON.stringify(error));
}
}

View File

@@ -0,0 +1,17 @@
###
PUT http://localhost:7272/api/user/changeToUser?userId=cmbfx38e30000ssek6ufjewcp
content-type: application/json
{
"data": {"requestUserId": "cmbfx38kk000esseka9qo8lpt"}
}
###
GET http://localhost:7272/api/user/changeToUser?userId=
###
GET http://localhost:7272/api/user
###
GET http://localhost:7272/api/user?userId=cmbfx38e30000ssek6ufjewcp

View File

@@ -0,0 +1,21 @@
import type { NextRequest, NextResponse } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
import { isAdmin } from 'src/app/services/userItem.service';
// import prisma from '../../lib/prisma';
export async function GET(req: NextRequest, res: NextResponse) {
const { searchParams } = req.nextUrl;
const userId = searchParams.get('userId');
try {
if (!userId) throw new Error('userId cannot be null');
const result = await isAdmin(userId);
return response(result, STATUS.OK);
} catch (error) {
return handleError('Post - Get latest', error);
}
}

View File

@@ -0,0 +1,9 @@
###
GET http://localhost:7272/api/user/checkAdmin?userId=cmbfx38ey0001ssek5pr05o70
###
GET http://localhost:7272/api/user/checkAdmin?userId=cmbfvonkx000411ykuah8pp8s
###
GET http://localhost:7272/api/user/checkAdmin

View File

@@ -1,4 +1,4 @@
// src/app/api/product/details/route.ts
// src/app/api/user/details/route.ts
//
// PURPOSE:
// read user from db by id
@@ -24,9 +24,7 @@ export async function GET(req: NextRequest) {
// RULES: userId must exist
const userId = searchParams.get('userId');
if (!userId) {
return response({ message: 'userId is required!' }, STATUS.BAD_REQUEST);
}
if (!userId) return response({ message: 'userId is required!' }, STATUS.BAD_REQUEST);
// NOTE: userId confirmed exist, run below
const user = await prisma.userItem.findFirst({
@@ -34,9 +32,7 @@ export async function GET(req: NextRequest) {
where: { id: userId },
});
if (!user) {
return response({ message: 'User not found!' }, STATUS.NOT_FOUND);
}
if (!user) return response({ message: 'User not found!' }, STATUS.NOT_FOUND);
logger('[User] details', user.id);

View File

@@ -0,0 +1,21 @@
import type { NextRequest, NextResponse } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
import { isAdmin } from 'src/app/services/userItem.service';
// import prisma from '../../lib/prisma';
export async function GET(req: NextRequest, res: NextResponse) {
const { searchParams } = req.nextUrl;
const userId = searchParams.get('userId');
try {
if (!userId) throw new Error('userId cannot be null');
const result = await isAdmin(userId);
return response(result, STATUS.OK);
} catch (error) {
return handleError('Post - Get latest', error);
}
}

View File

@@ -0,0 +1,2 @@
###
GET http://localhost:7272/api/user

View File

@@ -1,17 +1,20 @@
// src/app/api/product/list/route.ts
//
import { logger } from 'src/utils/logger';
import { STATUS, response, handleError } from 'src/utils/response';
import prisma from '../../../lib/prisma';
import { listUsers } from 'src/app/services/userItem.service';
// ----------------------------------------------------------------------
/** **************************************
/**
***************************************
* GET - Products
*************************************** */
***************************************
*/
export async function GET() {
try {
const users = await prisma.userItem.findMany();
const users = await listUsers();
logger('[User] list', users.length);

View File

@@ -0,0 +1,80 @@
import type { NextRequest, NextResponse } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
import { listUsers, deleteUser, updateUser, createNewUser } from 'src/app/services/userItem.service';
// import prisma from '../../lib/prisma';
export async function GET(req: NextRequest, res: NextResponse) {
try {
const result = await listUsers();
return response(result, STATUS.OK);
} catch (error) {
return handleError('User - Get latest', error);
}
}
/**
***************************************
* POST - create User
***************************************
*/
export async function POST(req: NextRequest) {
const { data } = await req.json();
try {
const createResult = await createNewUser(data);
return response(createResult, STATUS.OK);
} catch (error) {
return handleError('User - Create', error);
}
}
/**
***************************************
* PUT - update User
***************************************
*/
export async function PUT(req: NextRequest) {
const { searchParams } = req.nextUrl;
const userId = searchParams.get('userId');
const { data } = await req.json();
try {
if (!userId) throw new Error('userId cannot null');
const id: number = parseInt(userId);
const updateResult = await updateUser(id, data);
return response(updateResult, STATUS.OK);
} catch (error) {
return handleError('User - Update', error);
}
}
/**
***************************************
* DELETE - update User
***************************************
*/
export async function DELETE(req: NextRequest) {
const { searchParams } = req.nextUrl;
const userId = searchParams.get('userId');
const { data } = await req.json();
try {
if (!userId) throw new Error('userId cannot null');
const id: number = parseInt(userId);
const deleteResult = await deleteUser(id);
return response(deleteResult, STATUS.OK);
} catch (error) {
return handleError('User - Update', error);
}
}

View File

@@ -0,0 +1,26 @@
###
GET http://localhost:7272/api/user
###
GET http://localhost:7272/api/user?userId=cmbfvonhl000011ykdi345yc9
###
POST http://localhost:7272/api/user?userId=1
content-type: application/json
{
"data":{"name": "John Doe"}
}
###
PUT http://localhost:7272/api/user?userId=1
content-type: application/json
{
"data": {"name": "John Doe"}
}
###
DELETE http://localhost:7272/api/user?userId=1

View File

@@ -0,0 +1,66 @@
// src/app/services/AccessLog.service.ts
//
// PURPOSE:
// Service for handling AccessLog records
//
// RULES:
// - All methods return Promises
// - Input validation should be done at controller level
// - Errors should be propagated to caller
import type { AccessLog } from '@prisma/client';
import prisma from '../lib/prisma';
// type CreateAccessLog = {
// userId?: string;
// message?: string;
// metadata?: Record<string, any>;
// };
// type UpdateAccessLog = {
// status?: number;
// metadata?: object;
// };
async function listAccessLogs(): Promise<AccessLog[]> {
return prisma.accessLog.findMany({
orderBy: { timestamp: 'desc' },
take: 100,
});
}
async function getAccessLog(id: string): Promise<AccessLog | null> {
return prisma.accessLog.findUnique({ where: { id } });
}
async function createAccessLog(userId?: string, message?: string, metadata?: Record<string, any>): Promise<AccessLog> {
return prisma.accessLog.create({
data: {
userId,
message,
metadata,
},
});
}
// async function update(id: string, data: UpdateAccessLog): Promise<AccessLog> {
// return prisma.accessLog.update({
// where: { id },
// data: {
// ...data,
// metadata: data.metadata || {},
// },
// });
// }
// async function deleteAccessLog(id: string): Promise<AccessLog> {
// return prisma.accessLog.delete({ where: { id } });
// }
export {
//
getAccessLog,
listAccessLogs,
createAccessLog,
};

View File

@@ -0,0 +1,52 @@
// src/app/services/AppLog.service.ts
//
// REQ0047/T.B.A.
//
// PURPOSE:
// - AppLog example for handling AppLog Record
//
// RULES:
// - T.B.A.
//
import type { AppLog } from '@prisma/client';
import prisma from '../lib/prisma';
type CreateAppLog = {
level: number;
message: string;
};
// type UpdateAppLog = {
// level: number;
// message: string;
// };
async function listAppLogs(): Promise<AppLog[]> {
return prisma.appLog.findMany();
}
async function getAppLog(appLogId: string) {
return prisma.appLog.findFirst({ where: { id: appLogId } });
}
async function createNewAppLog(createForm: CreateAppLog) {
return prisma.appLog.create({ data: createForm });
}
// async function updateAppLog(appLogId: string, updateForm: UpdateAppLog) {
// return prisma.appLog.update({ where: { id: appLogId }, data: updateForm });
// }
async function deleteAppLog(appLogId: string) {
return prisma.appLog.delete({ where: { id: appLogId } });
}
export {
getAppLog,
listAppLogs,
// updateAppLog,
deleteAppLog,
createNewAppLog,
};

View File

@@ -0,0 +1,7 @@
with knowledge in schema.prisma file,
please refer the below helloworld example `helloworld.service.ts`
and create `user.service.ts` to cover user record
thanks
`/home/logic/_wsl_workspace/001_github_ws/HKSingleParty-ws/HKSingleParty/03_source/cms_backend/src/app/services/helloworld.service.ts`

View File

@@ -0,0 +1,65 @@
// src/app/services/event.service.ts
//
// PURPOSE:
// - Service for handling Event records
//
// RULES:
// - Follows same pattern as helloworld.service.ts
//
import type { Event } from '@prisma/client';
import prisma from '../lib/prisma';
type CreateEvent = {
eventDate: DateTime;
title: string;
joinMembers?: Json[];
price: number;
currency: string;
duration_m: number;
ageBottom: number;
ageTop: number;
location: string;
avatar?: string;
memberId?: number;
};
type UpdateEvent = {
eventDate?: DateTime;
title?: string;
joinMembers?: Json[];
price?: number;
currency?: string;
duration_m?: number;
ageBottom?: number;
ageTop?: number;
location?: string;
avatar?: string;
memberId?: number;
};
async function listEvents(): Promise<Event[]> {
return prisma.event.findMany();
}
async function getEvent(eventId: number) {
return prisma.event.findFirst({ where: { id: eventId } });
}
async function createNewEvent(createForm: CreateEvent) {
return prisma.event.create({ data: createForm });
}
async function updateEvent(eventId: number, updateForm: UpdateEvent) {
return prisma.event.update({
where: { id: eventId },
data: updateForm,
});
}
async function deleteEvent(eventId: number) {
return prisma.event.delete({ where: { id: eventId } });
}
export { getEvent, listEvents, updateEvent, deleteEvent, createNewEvent };

View File

@@ -0,0 +1,70 @@
// src/app/services/order.service.ts
//
// PURPOSE:
// - Handle Order Record CRUD operations
// - Manage order status transitions
// - Handle order-event relationships
//
import type { OrderItem } from '@prisma/client';
import prisma from '../lib/prisma';
type CreateOrderItem = {
orderNumber?: string;
// status?: string;
// eventIds?: number[];
};
type UpdateOrderItem = {
orderNumber?: string;
// status?: string;
// last_payment_date?: Date;
// eventIds?: number[];
};
async function listOrders(): Promise<OrderItem[]> {
return prisma.orderItem.findMany();
}
async function getOrder(orderId: string): Promise<OrderItem | null> {
return prisma.orderItem.findFirst({
where: { id: orderId },
});
}
async function createOrder(createForm: CreateOrderItem): Promise<OrderItem> {
return prisma.orderItem.create({
data: createForm,
});
}
async function updateOrder(orderId: string, updateForm: UpdateOrderItem): Promise<OrderItem> {
return prisma.orderItem.update({
where: { id: orderId },
data: updateForm,
});
}
async function deleteOrder(orderId: string): Promise<OrderItem> {
return prisma.orderItem.delete({
where: { id: orderId },
});
}
async function getOrdersByStatus(status: string): Promise<OrderItem[]> {
return prisma.orderItem.findMany({
where: { status },
});
}
export {
getOrder,
listOrders,
createOrder,
updateOrder,
deleteOrder,
getOrdersByStatus,
type CreateOrderItem as CreateOrder,
type UpdateOrderItem as UpdateOrder,
};

View File

@@ -0,0 +1,114 @@
// src/app/services/product.service.ts
//
// PURPOSE:
// - Service for handling ProductItem Record
//
import type { ProductItem } from '@prisma/client';
import prisma from '../lib/prisma';
type CreateProduct = {
sku: string;
name: string;
// price: number;
// code?: string;
// taxes?: number;
// tags?: string[];
// sizes?: string[];
// gender?: string[];
// colors?: string[];
// category?: string;
// quantity?: number;
// available?: number;
// coverUrl?: string;
// images?: string[];
// description?: string;
// subDescription?: string;
// publish?: string;
// totalSold?: number;
// totalRatings?: number;
// totalReviews?: number;
// inventoryType?: string;
// ratings?: number[];
// reviews?: string[];
// result?: string;
// thanks?: string;
};
type UpdateProduct = {
sku?: string;
name?: string;
// price?: number;
// code?: string;
// taxes?: number;
// tags?: string[];
// sizes?: string[];
// gender?: string[];
// colors?: string[];
// category?: string;
// quantity?: number;
// available?: number;
// coverUrl?: string;
// images?: string[];
// description?: string;
// subDescription?: string;
// publish?: string;
// totalSold?: number;
// totalRatings?: number;
// totalReviews?: number;
// inventoryType?: string;
// ratings?: number[];
// reviews?: string[];
// result?: string;
// thanks?: string;
};
async function listProducts(): Promise<ProductItem[]> {
return prisma.productItem.findMany();
}
async function getProduct(productId: string) {
return prisma.productItem.findUnique({ where: { id: productId } });
}
async function createProduct(createForm: CreateProduct) {
// return prisma.productItem.create({
// data: {
// ...createForm,
// code: createForm.code || '',
// taxes: createForm.taxes || 0,
// tags: createForm.tags || [],
// sizes: createForm.sizes || [],
// gender: createForm.gender || [],
// colors: createForm.colors || [],
// category: createForm.category || '',
// quantity: createForm.quantity || 0,
// available: createForm.available || 0,
// coverUrl: createForm.coverUrl || '',
// images: createForm.images || [],
// description: createForm.description || '',
// subDescription: createForm.subDescription || '',
// publish: createForm.publish || 'published',
// totalSold: createForm.totalSold || 0,
// totalRatings: createForm.totalRatings || 0,
// totalReviews: createForm.totalReviews || 0,
// inventoryType: createForm.inventoryType || '',
// ratings: createForm.ratings || [],
// reviews: createForm.reviews || [],
// },
// });
}
async function updateProduct(productId: string, updateForm: UpdateProduct) {
return prisma.productItem.update({
where: { id: productId },
data: updateForm,
});
}
async function deleteProduct(productId: string) {
return prisma.productItem.delete({ where: { id: productId } });
}
export { getProduct, listProducts, createProduct, updateProduct, deleteProduct, type CreateProduct, type UpdateProduct };

View File

@@ -0,0 +1,122 @@
// src/app/services/user.service.ts
//
// PURPOSE:
// - Handle User Record CRUD operations
//
// RULES:
// - Follow Prisma best practices for database operations
// - Validate input data before processing
//
import type { UserItem } from '@prisma/client';
import prisma from '../lib/prisma';
type CreateUser = {
email: string;
// name?: string;
// password: string;
// role?: Role;
// isEmailVerified?: boolean;
// admin?: boolean;
};
type UpdateUser = {
email?: string;
// name?: string;
// password?: string;
// role?: Role;
// isEmailVerified?: boolean;
isAdmin?: boolean;
};
async function listUsers(): Promise<UserItem[]> {
return prisma.userItem.findMany();
}
async function getUserItem(userId: string): Promise<UserItem | null> {
return prisma.userItem.findFirst({ where: { id: userId } });
}
async function updateUser(userId: string, updateForm: UpdateUser): Promise<User> {
return prisma.userItem.update({
where: { id: userId },
data: updateForm,
});
}
// check if userId is a admin
// check if userId is a admin
async function isAdmin(userId: string): Promise<boolean> {
const user = await getUserItem(userId);
return user?.isAdmin === true;
}
async function changeToAdmin(userIdToPromote: string, userIdOfApplicant: string) {
// check the applicant is admin or not
const userApplicant = await getUserItem(userIdOfApplicant);
let promoteResult = {};
if (userApplicant && userApplicant.isAdmin) {
// applicant is an admin
promoteResult = await updateUser(userIdToPromote, { isAdmin: true });
} else {
promoteResult = { status: 'failed', message: 'applicant is not a admin' };
}
return promoteResult;
}
async function changeToUser(userIdToPromote: string, userIdOfApplicant: string) {
// check the applicant is admin or not
const userApplicant = await getUserItem(userIdOfApplicant);
let promoteResult = {};
if (userApplicant && userApplicant.isAdmin) {
// applicant is an admin
promoteResult = await updateUser(userIdToPromote, { isAdmin: false });
} else {
promoteResult = { status: 'failed', message: 'applicant is not a admin' };
}
return promoteResult;
}
async function getUserByEmail(email: string): Promise<void> {
// return prisma.userItem.findUnique({
// where: { email },
// include: {
// Token: true,
// },
// });
}
async function createNewUser(createForm: CreateUser): Promise<void> {
// return prisma.userItem.create({
// data: {
// email: createForm.email,
// name: createForm.name,
// password: createForm.password,
// role: createForm.role || 'USER',
// isEmailVerified: createForm.isEmailVerified || false,
// },
// });
}
async function deleteUser(userId: number): Promise<void> {
// return prisma.userItem.delete({ where: { id: userId } });
}
export {
// getUser,
isAdmin,
listUsers,
updateUser,
deleteUser,
changeToUser,
createNewUser,
changeToAdmin,
getUserByEmail,
type CreateUser,
type UpdateUser,
};