Compare commits

..

8 Commits

Author SHA1 Message Date
louiscklaw
c1b71fca64 add helloworld API endpoint for product module with test case 2025-06-15 13:54:35 +08:00
louiscklaw
08642a2bf6 "update EventItem model schema with reordered and reorganized fields" 2025-06-15 13:54:24 +08:00
louiscklaw
043d45862c update markdown files and instructions in AI workspace 2025-06-15 13:16:53 +08:00
louiscklaw
8444b947a4 "update product list rendering" 2025-06-15 13:07:47 +08:00
louiscklaw
e791b01160 update, 2025-06-15 12:56:29 +08:00
louiscklaw
8383be13bc update, 2025-06-15 12:44:58 +08:00
louiscklaw
d82afe5a5f update prisma search products, 2025-06-15 12:42:08 +08:00
louiscklaw
1216bef8f8 "update tsconfig patterns and compiler options across all projects" 2025-06-15 12:08:17 +08:00
16 changed files with 107 additions and 102 deletions

View File

@@ -1146,46 +1146,47 @@ model EventReview {
// NOTE: need to consider with Event // NOTE: need to consider with Event
// mapped to IEventItem // mapped to IEventItem
// a.k.a. PartyEvent party-event
model EventItem { model EventItem {
id String @id @default(uuid()) id String @id @default(uuid())
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
// //
sku String
name String
code String
price Float
taxes Float
tags String[]
sizes String[]
publish String
gender String[]
coverUrl String
images String[]
colors String[]
quantity Int
category String
available Int available Int
totalSold Int category String
code String
colors String[]
coverUrl String
description String description String
gender String[]
images String[]
inventoryType String
name String
newLabel Json
price Float
priceSale Float?
publish String
quantity Int
ratings Json[]
saleLabel Json
sizes String[]
sku String
subDescription String
tags String[]
taxes Float
totalRatings Float totalRatings Float
totalReviews Int totalReviews Int
inventoryType String totalSold Int
subDescription String
priceSale Float?
newLabel Json
saleLabel Json
ratings Json[]
// //
eventDate DateTime @default(now())
joinMembers Json[]
title String
currency String
duration_m Float
ageBottom Float ageBottom Float
ageTop Float ageTop Float
location String
avatar String[] avatar String[]
currency String
duration_m Float
eventDate DateTime @default(now())
joinMembers Json[]
location String
title String
// //
reviews EventReview[] reviews EventReview[]
} }

View File

@@ -0,0 +1,16 @@
import type { NextRequest, NextResponse } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
/**
***************************************
* GET - helloworld
***************************************
*/
export async function GET(req: NextRequest, res: NextResponse) {
try {
return response({ helloworld: 'product' }, STATUS.OK);
} catch (error) {
return handleError('Helloworld - Get all', error);
}
}

View File

@@ -0,0 +1,4 @@
###
GET /api/product/helloworld HTTP/1.1
Host: localhost:7272

View File

@@ -1,30 +0,0 @@
// src/app/api/product/image/upload/route.ts
//
// PURPOSE:
// handle upload product 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 - Products
*************************************** */
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('Product - store product image', error);
}
}

View File

@@ -3,11 +3,11 @@ import type { NextRequest } from 'next/server';
import { logger } from 'src/utils/logger'; import { logger } from 'src/utils/logger';
import { STATUS, response, handleError } from 'src/utils/response'; import { STATUS, response, handleError } from 'src/utils/response';
import { _products } from 'src/_mock/_product'; import { getProductBySkuOrName } from 'src/app/services/product.service';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
export const runtime = 'edge'; // export const runtime = 'edge';
/** ************************************** /** **************************************
* GET - Search products * GET - Search products
@@ -21,12 +21,9 @@ export async function GET(req: NextRequest) {
return response({ results: [] }, STATUS.OK); return response({ results: [] }, STATUS.OK);
} }
const products = _products(); const results = await getProductBySkuOrName(query);
// Accept search by name or sku logger('[Product] search-results', results?.length);
const results = products.filter(({ name, sku }) => name.toLowerCase().includes(query) || sku?.toLowerCase().includes(query));
logger('[Product] search-results', results.length);
return response({ results }, STATUS.OK); return response({ results }, STATUS.OK);
} catch (error) { } catch (error) {

View File

@@ -0,0 +1,8 @@
###
GET http://localhost:7272/api/product/search?query=B
###
GET http://localhost:7272/api/product/search?query=Classic
###
GET http://localhost:7272/api/product/search?query=zzzzzz

View File

@@ -68,9 +68,7 @@ type UpdateProduct = {
async function listProducts(): Promise<ProductItem[]> { async function listProducts(): Promise<ProductItem[]> {
return prisma.productItem.findMany({ return prisma.productItem.findMany({
include: { include: { reviews: true },
reviews: true,
},
}); });
} }
@@ -82,6 +80,14 @@ async function getProduct(productId: string): Promise<ProductItem | null> {
}); });
} }
async function getProductBySkuOrName(searchText: string): Promise<ProductItem[] | null> {
return prisma.productItem.findMany({
where: { OR: [{ sku: { contains: searchText, mode: 'insensitive' } }, { name: { contains: searchText, mode: 'insensitive' } }] },
include: { reviews: true },
//
});
}
async function createProduct(productData: any) { async function createProduct(productData: any) {
return await prisma.productItem.create({ data: productData }); return await prisma.productItem.create({ data: productData });
} }
@@ -97,4 +103,4 @@ async function deleteProduct(productId: string) {
return prisma.productItem.delete({ where: { id: productId } }); return prisma.productItem.delete({ where: { id: productId } });
} }
export { getProduct, listProducts, createProduct, updateProduct, deleteProduct, type CreateProduct, type UpdateProduct }; export { getProduct, listProducts, createProduct, updateProduct, deleteProduct, getProductBySkuOrName, type CreateProduct, type UpdateProduct };

View File

@@ -34,9 +34,8 @@
"node_modules", "node_modules",
".next", ".next",
// //
"**/* copy *.tsx", "**/* copy *.*",
"**/* copy.tsx", "**/* copy.*",
"**/*.bak",
"**/*.bak", "**/*.bak",
"**/*.bug", "**/*.bug",
"**/*.del", "**/*.del",

View File

@@ -99,7 +99,9 @@ export async function createProduct(productData: IProductItem) {
* Work on server * Work on server
*/ */
const data = { productData }; const data = { productData };
await axiosInstance.post(endpoints.product.create, data); const {
data: { id },
} = await axiosInstance.post(endpoints.product.create, data);
/** /**
* Work in local * Work in local
@@ -109,7 +111,7 @@ export async function createProduct(productData: IProductItem) {
(currentData: any) => { (currentData: any) => {
const currentProducts: IProductItem[] = currentData?.products; const currentProducts: IProductItem[] = currentData?.products;
const products = [...currentProducts, productData]; const products = [...currentProducts, { ...productData, id }];
return { ...currentData, products }; return { ...currentData, products };
}, },

View File

@@ -1,39 +1,35 @@
{ {
"compilerOptions": { "compilerOptions": {
"allowJs": true,
/* Bundler */ /* Bundler */
"baseUrl": ".", "baseUrl": ".",
"module": "ESNext", "esModuleInterop": true,
"incremental": true,
"isolatedModules": true,
"jsx": "react-jsx", "jsx": "react-jsx",
"allowJs": true,
"resolveJsonModule": true,
/* Build */
"target": "ES2020",
"lib": [ "lib": [
"ES2020", "ES2020",
"DOM", "DOM",
"DOM.Iterable" "DOM.Iterable"
], ],
"module": "ESNext",
"moduleResolution": "bundler", "moduleResolution": "bundler",
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", "noEmit": true,
"incremental": true, "resolveJsonModule": true,
"skipLibCheck": true, "skipLibCheck": true,
"esModuleInterop": true,
"isolatedModules": true,
/* Linting */ /* Linting */
"strict": true, "strict": true,
"noEmit": true, "strictNullChecks": true,
"strictNullChecks": true /* Build */
"target": "ES2020",
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo"
}, },
"include": [
"src"
],
"exclude": [ "exclude": [
"node_modules", "node_modules",
".next", ".next",
// //
"**/* copy *.tsx", "**/* copy *.*",
"**/* copy.tsx", "**/* copy.*",
"**/*.bak",
"**/*.bak", "**/*.bak",
"**/*.bug", "**/*.bug",
"**/*.del", "**/*.del",
@@ -42,9 +38,12 @@
"**/*.tmp", "**/*.tmp",
"**/*del" "**/*del"
], ],
"include": [
"src"
],
"references": [ "references": [
{ {
"path": "./tsconfig.node.json" "path": "./tsconfig.node.json"
} }
], ]
} }

View File

@@ -6,8 +6,8 @@
"allowSyntheticDefaultImports": true "allowSyntheticDefaultImports": true
}, },
"exclude": [ "exclude": [
"**/* copy *.tsx", "**/* copy *.*",
"**/* copy.tsx", "**/* copy.*",
"**/*.bak", "**/*.bak",
"**/*.bak", "**/*.bak",
"**/*.bug", "**/*.bug",
@@ -16,5 +16,8 @@
"**/*.log", "**/*.log",
"**/*.tmp", "**/*.tmp",
"**/*del" "**/*del"
], "include": ["vite.config.ts"] ],
"include": [
"vite.config.ts"
]
} }

View File

@@ -24,9 +24,8 @@
"node_modules", "node_modules",
".next", ".next",
// //
"**/* copy *.tsx", "**/* copy *.*",
"**/* copy.tsx", "**/* copy.*",
"**/*.bak",
"**/*.bak", "**/*.bak",
"**/*.bug", "**/*.bug",
"**/*.del", "**/*.del",
@@ -43,4 +42,4 @@
"path": "./tsconfig.node.json" "path": "./tsconfig.node.json"
} }
] ]
} }

View File

@@ -1,9 +1,9 @@
{ {
"compilerOptions": { "compilerOptions": {
"allowSyntheticDefaultImports": true,
"composite": true, "composite": true,
"module": "ESNext", "module": "ESNext",
"moduleResolution": "Node", "moduleResolution": "Node"
"allowSyntheticDefaultImports": true
}, },
"exclude": [ "exclude": [
"**/* copy *.tsx", "**/* copy *.tsx",

View File

@@ -0,0 +1 @@
T.B.A.

View File

@@ -1,6 +1,6 @@
```markdown
# Greetings # Greetings
```markdown
Hi, Hi,
Imagine you are a software engineer and i will send you the guideline. Imagine you are a software engineer and i will send you the guideline.

View File

@@ -25,7 +25,7 @@ T.B.A.
1 AI tools/co-pilot 1 AI tools/co-pilot
```prompt ```prompt
please read and follow steps in the markdown files in `98_AI_workspace` folder thanks. please read and follow steps in the markdown files in `98_AI_workspace/software-engineer` folder thanks.
``` ```
<!-- AI: please fill the step to setup project below --> <!-- AI: please fill the step to setup project below -->