Compare commits

..

7 Commits

1207 changed files with 11691 additions and 6497 deletions

View File

@@ -1,9 +0,0 @@
---
tags: frontend, side-menu
---
# REQ0181 frontend side menu configuration
## sources
`src/layouts/nav-config-dashboard.tsx`

View File

@@ -1,11 +0,0 @@
---
tags: frontend, product, details
---
# REQ0182 frontend product details
frontend page to display product details
## sources
T.B.A.

View File

@@ -1,15 +0,0 @@
---
tags: frontend, product, new
---
# REQ0183 frontend product new
frontend page to create new product
## sources
T.B.A.
## branch
develop/requirements/REQ0183

View File

@@ -1,17 +0,0 @@
---
tags: frontend, product, delete
---
# REQ0184 frontend product delete
frontend page to delete product
list page
## sources
T.B.A.
## branch
develop/requirements/REQ0184

View File

@@ -1,17 +0,0 @@
---
tags: frontend, product, update
---
# REQ0185 frontend product update
frontend page to update product
edit page T.B.A.
## sources
T.B.A.
## branch
develop/requirements/REQ0185

View File

@@ -158,8 +158,3 @@
- [REQ0169: DemoStorageExample](./REQ0169/index.md) - [REQ0169: DemoStorageExample](./REQ0169/index.md)
- [REQ0170: DemoWeatherAppUi](./REQ0170/index.md) - [REQ0170: DemoWeatherAppUi](./REQ0170/index.md)
- [REQ0180: REQ0180 service port schedule](./REQ0180/index.md) - [REQ0180: REQ0180 service port schedule](./REQ0180/index.md)
- [REQ0181: REQ0181 frontend side menu configuration](./REQ0181/index.md)
- [REQ0182: REQ0182 frontend product details](./REQ0182/index.md)
- [REQ0183: REQ0183 frontend product new](./REQ0183/index.md)
- [REQ0184: REQ0184 frontend product delete](./REQ0184/index.md)
- [REQ0185: REQ0185 frontend product update](./REQ0185/index.md)

View File

@@ -1,7 +1,3 @@
**/*del
**/*bak
**/*copy*
# Logs # Logs
logs logs
*.log *.log

View File

@@ -1,9 +1,8 @@
#!/usr/bin/env bash #!/usr/bin/env bash
yarn build
while true; do while true; do
yarn start yarn --dev
yarn dev
echo "restarting..." echo "restarting..."
sleep 1 sleep 1

View File

@@ -5,7 +5,6 @@
"description": "Mock server & assets", "description": "Mock server & assets",
"private": true, "private": true,
"scripts": { "scripts": {
"dev:check": "yarn tsc:w",
"dev": "next dev -p 7272 -H 0.0.0.0", "dev": "next dev -p 7272 -H 0.0.0.0",
"start": "next start -p 7272 -H 0.0.0.0", "start": "next start -p 7272 -H 0.0.0.0",
"build": "next build", "build": "next build",
@@ -20,10 +19,8 @@
"re:build": "yarn clean && yarn install && yarn build", "re:build": "yarn clean && yarn install && yarn build",
"re:build-npm": "npm run clean && npm install && npm run build", "re:build-npm": "npm run clean && npm install && npm run build",
"tsc:dev": "yarn dev & yarn tsc:watch", "tsc:dev": "yarn dev & yarn tsc:watch",
"tsc:print": "npx tsc --showConfig",
"tsc:w": "npx nodemon --delay 3 --ext ts,tsx --exec \"yarn tsc\"",
"tsc:watch": "tsc --noEmit --watch", "tsc:watch": "tsc --noEmit --watch",
"tsc": "tsc --noEmit", "tsc:print": "npx tsc --showConfig",
"migrate": "npx prisma migrate dev --skip-seed", "migrate": "npx prisma migrate dev --skip-seed",
"seed": "tsx ./prisma/seed.ts", "seed": "tsx ./prisma/seed.ts",
"seed:w": "npx nodemon --ext \"ts,tsx,json\" -w prisma --exec \"yarn seed\"", "seed:w": "npx nodemon --ext \"ts,tsx,json\" -w prisma --exec \"yarn seed\"",
@@ -32,9 +29,7 @@
"db:push": "prisma db push --force-reset", "db:push": "prisma db push --force-reset",
"db:push:w": "npx nodemon --delay 1 --watch prisma --ext \"ts,tsx,prisma\" --exec \"yarn db:push && yarn seed\"", "db:push:w": "npx nodemon --delay 1 --watch prisma --ext \"ts,tsx,prisma\" --exec \"yarn db:push && yarn seed\"",
"db:studio": "prisma studio", "db:studio": "prisma studio",
"db:studio:w": "npx nodemon --delay 1 --watch prisma --ext \"prisma\" --exec \"yarn db:studio\"", "db:studio:w": "npx nodemon --delay 1 --watch prisma --ext \"prisma\" --exec \"yarn db:studio\""
"db:dev": "yarn db:push && yarn seed && yarn dev",
"db:dev:w": "npx nodemon --delay 1 --ext \"ts,tsx,prisma\" --exec \"yarn db:dev\""
}, },
"engines": { "engines": {
"node": ">=20" "node": ">=20"
@@ -48,7 +43,6 @@
"@next-auth/prisma-adapter": "^1.0.7", "@next-auth/prisma-adapter": "^1.0.7",
"@prisma/adapter-pg": "^6.8.2", "@prisma/adapter-pg": "^6.8.2",
"@prisma/client": "^5.6.0", "@prisma/client": "^5.6.0",
"@types/bcrypt": "^5.0.2",
"bcrypt": "^5.1.1", "bcrypt": "^5.1.1",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
@@ -71,7 +65,6 @@
"@types/react": "^18.3.20", "@types/react": "^18.3.20",
"@types/react-dom": "^18.3.5", "@types/react-dom": "^18.3.5",
"@typescript-eslint/parser": "^8.28.0", "@typescript-eslint/parser": "^8.28.0",
"concurrently": "^9.1.2",
"eslint": "^9.23.0", "eslint": "^9.23.0",
"eslint-import-resolver-typescript": "^4.2.2", "eslint-import-resolver-typescript": "^4.2.2",
"eslint-plugin-import": "^2.31.0", "eslint-plugin-import": "^2.31.0",

View File

@@ -195,32 +195,32 @@ model ProductItem {
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
// //
available Int
category String
code String
colors String[]
coverUrl String
description String
gender String[]
images String[]
inventoryType String
name String
newLabel Json
price Float
priceSale Float?
publish String
quantity Int
ratings Json[]
reviews ProductReview[]
saleLabel Json
sizes String[]
sku String sku String
subDescription String name String
tags String[] code String
price Float
taxes Float taxes Float
tags String[]
sizes String[]
publish String
gender String[]
coverUrl String
images String[]
colors String[]
quantity Int
category String
available Int
totalSold Int
description String
totalRatings Float totalRatings Float
totalReviews Int totalReviews Int
totalSold Int inventoryType String
subDescription String
priceSale Float?
newLabel Json
saleLabel Json
ratings Json[]
reviews ProductReview[]
} }
model MailSender { model MailSender {
@@ -1144,60 +1144,47 @@ model EventReview {
eventItemId String? eventItemId String?
} }
// 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
// //
available Int @default(99) sku String
category String name String
code String @default("") code String
colors String[] price Float
coverUrl String taxes Float
description String tags String[]
sizes String[]
publish String
gender String[] gender String[]
coverUrl String
images String[] images String[]
inventoryType String @default("") colors String[]
name String @default("") quantity Int
newLabel Json @default("{}") category String
price Float @default(999.9) available Int
priceSale Float? @default(111.1) totalSold Int
publish String @default("") description String
quantity Int @default(99) totalRatings Float
totalReviews Int
inventoryType String
subDescription String
priceSale Float?
newLabel Json
saleLabel Json
ratings Json[] ratings Json[]
saleLabel Json @default("{}")
sizes String[] @default([""])
sku String @default("")
subDescription String @default("")
tags String[] @default([""])
taxes Float @default(5.0)
totalRatings Float @default(5.0)
totalReviews Int @default(10)
totalSold Int @default(10)
// //
ageBottom Float @default(-1)
ageTop Float @default(-1)
avatar String[] @default([""])
currency String @default("HKD")
capacity Int @default(10)
duration_m Float @default(180)
endDate String? @default("")
eventDate DateTime @default(now()) eventDate DateTime @default(now())
isFeatured Boolean @default(false) joinMembers Json[]
joinMembers Json[] @default([]) title String
location String @default("HK") currency String
organizer String @default("") duration_m Float
registrationDeadline String @default("") ageBottom Float
requirements String @default("") ageTop Float
schedule String @default("") location String
speakers String[] @default([]) avatar String[]
sponsors String[] @default([])
startDate String? @default("")
status String? @default("")
title String @default("")
// //
reviews EventReview[] reviews EventReview[]
} }

View File

@@ -1,18 +0,0 @@
#!/usr/bin/env bash
yarn --dev
clear
while true; do
# yarn db:push
# yarn seed
yarn db:studio &
npx nodemon --ext ts,tsx,prisma --exec "yarn dev"
# yarn dev
echo "restarting..."
sleep 1
done

View File

@@ -1,11 +0,0 @@
#!/usr/bin/env bash
yarn --dev
clear
while true; do
npx nodemon --ext prisma --exec "yarn db:push && yarn seed"
echo "restarting..."
sleep 1
done

View File

@@ -1,18 +0,0 @@
#!/usr/bin/env bash
set -x
rm -rf ./**/*Zone.Identifier
# yarn db:push
# npx nodemon --ext ts,tsx --exec "yarn tsc"
set -ex
yarn fm:fix
yarn tsc
yarn build
echo "done"

View File

@@ -1,5 +0,0 @@
#!/usr/bin/env bash
set -x
npm run start

View File

@@ -16,7 +16,11 @@ export const _contacts = () =>
address: _mock.fullAddress(index), address: _mock.fullAddress(index),
avatarUrl: _mock.image.avatar(index), avatarUrl: _mock.image.avatar(index),
phoneNumber: _mock.phoneNumber(index), phoneNumber: _mock.phoneNumber(index),
status: ([0, 1, 6, 12].includes(index) && 'online') || ([3, 8, 14].includes(index) && 'offline') || ([4, 10, 16].includes(index) && 'busy') || 'always', status:
([0, 1, 6, 12].includes(index) && 'online') ||
([3, 8, 14].includes(index) && 'offline') ||
([4, 10, 16].includes(index) && 'busy') ||
'always',
})); }));
export const _conversations = () => { export const _conversations = () => {

View File

@@ -6,7 +6,8 @@ import { _tags } from './assets';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
const generateAttachments = () => Array.from({ length: 20 }, (_, index) => _mock.image.cover(index)); const generateAttachments = () =>
Array.from({ length: 20 }, (_, index) => _mock.image.cover(index));
const generateAssignees = () => const generateAssignees = () =>
Array.from({ length: 20 }, (_, index) => ({ Array.from({ length: 20 }, (_, index) => ({
@@ -67,14 +68,24 @@ const createTask = (index: number, status: string) => {
assignee: assignedUser.slice(0, index), assignee: assignedUser.slice(0, index),
description: _mock.description(index), description: _mock.description(index),
due: [fAdd({ days: index + 1 }), fAdd({ days: index + 2 })], due: [fAdd({ days: index + 1 }), fAdd({ days: index + 2 })],
priority: ([1, 3].includes(index) && PRIORITY_LEVEL.hight) || ([2, 4].includes(index) && PRIORITY_LEVEL.medium) || PRIORITY_LEVEL.low, priority:
attachments: (index === 1 && attachmentList.slice(11, 15)) || (index === 5 && attachmentList.slice(4, 9)) || [], ([1, 3].includes(index) && PRIORITY_LEVEL.hight) ||
([2, 4].includes(index) && PRIORITY_LEVEL.medium) ||
PRIORITY_LEVEL.low,
attachments:
(index === 1 && attachmentList.slice(11, 15)) ||
(index === 5 && attachmentList.slice(4, 9)) ||
[],
status, status,
}; };
}; };
const tasks = () => ({ const tasks = () => ({
[COLUMN_IDS.id1]: [createTask(1, COLUMN_NAMES.name1), createTask(2, COLUMN_NAMES.name1), createTask(3, COLUMN_NAMES.name1)], [COLUMN_IDS.id1]: [
createTask(1, COLUMN_NAMES.name1),
createTask(2, COLUMN_NAMES.name1),
createTask(3, COLUMN_NAMES.name1),
],
[COLUMN_IDS.id2]: [createTask(4, COLUMN_NAMES.name2), createTask(5, COLUMN_NAMES.name2)], [COLUMN_IDS.id2]: [createTask(4, COLUMN_NAMES.name2), createTask(5, COLUMN_NAMES.name2)],
[COLUMN_IDS.id3]: [], [COLUMN_IDS.id3]: [],
[COLUMN_IDS.id4]: [createTask(6, COLUMN_NAMES.name4)], [COLUMN_IDS.id4]: [createTask(6, COLUMN_NAMES.name4)],

View File

@@ -28,11 +28,20 @@ export const _mails = () =>
Array.from({ length: 9 }, (_, index) => { Array.from({ length: 9 }, (_, index) => {
const files = _files(); const files = _files();
const attachments = (index === 1 && files.slice(0, 2)) || (index === 2 && files.slice(0, 4)) || (index === 5 && files.slice(4, 10)) || []; const attachments =
(index === 1 && files.slice(0, 2)) ||
(index === 2 && files.slice(0, 4)) ||
(index === 5 && files.slice(4, 10)) ||
[];
const folder = ([1, 2].includes(index) && 'spam') || ([3, 4].includes(index) && 'sent') || 'inbox'; const folder =
([1, 2].includes(index) && 'spam') || ([3, 4].includes(index) && 'sent') || 'inbox';
const labelIds = (index === 1 && ['promotions', 'forums']) || (index === 2 && ['forums']) || (index === 5 && ['social']) || []; const labelIds =
(index === 1 && ['promotions', 'forums']) ||
(index === 2 && ['forums']) ||
(index === 5 && ['social']) ||
[];
const from = { const from = {
name: _mock.fullName(index), name: _mock.fullName(index),

View File

@@ -78,8 +78,11 @@ export const _mock = {
avatar: (index: number) => `${CONFIG.basePath}/assets/images/avatar/avatar-${index + 1}.webp`, avatar: (index: number) => `${CONFIG.basePath}/assets/images/avatar/avatar-${index + 1}.webp`,
travel: (index: number) => `${CONFIG.basePath}/assets/images/travel/travel-${index + 1}.webp`, travel: (index: number) => `${CONFIG.basePath}/assets/images/travel/travel-${index + 1}.webp`,
course: (index: number) => `${CONFIG.basePath}/assets/images/course/course-${index + 1}.webp`, course: (index: number) => `${CONFIG.basePath}/assets/images/course/course-${index + 1}.webp`,
company: (index: number) => `${CONFIG.basePath}/assets/images/company/company-${index + 1}.webp`, company: (index: number) =>
product: (index: number) => `${CONFIG.basePath}/assets/images/m-product/product-${index + 1}.webp`, `${CONFIG.basePath}/assets/images/company/company-${index + 1}.webp`,
portrait: (index: number) => `${CONFIG.basePath}/assets/images/portrait/portrait-${index + 1}.webp`, product: (index: number) =>
`${CONFIG.basePath}/assets/images/m-product/product-${index + 1}.webp`,
portrait: (index: number) =>
`${CONFIG.basePath}/assets/images/portrait/portrait-${index + 1}.webp`,
}, },
}; };

View File

@@ -3,7 +3,16 @@ import { _tags } from './assets';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
const COLORS = ['#FF4842', '#1890FF', '#FFC0CB', '#00AB55', '#FFC107', '#7F00FF', '#000000', '#FFFFFF']; const COLORS = [
'#FF4842',
'#1890FF',
'#FFC0CB',
'#00AB55',
'#FFC107',
'#7F00FF',
'#000000',
'#FFFFFF',
];
const DESCRIPTION = ` const DESCRIPTION = `
<h6>Specifications</h6> <h6>Specifications</h6>
@@ -84,7 +93,8 @@ const DESCRIPTION = `
`; `;
const generateAttachments = () => Array.from({ length: 20 }, (_, index) => _mock.image.product(index)); const generateAttachments = () =>
Array.from({ length: 20 }, (_, index) => _mock.image.product(index));
const generateReviews = () => { const generateReviews = () => {
const attachments = generateAttachments(); const attachments = generateAttachments();
@@ -98,7 +108,11 @@ const generateReviews = () => {
rating: _mock.number.rating(index), rating: _mock.number.rating(index),
avatarUrl: _mock.image.avatar(index), avatarUrl: _mock.image.avatar(index),
helpful: _mock.number.nativeL(index), helpful: _mock.number.nativeL(index),
attachments: (index === 1 && attachments.slice(0, 1)) || (index === 3 && attachments.slice(2, 4)) || (index === 5 && attachments.slice(5, 8)) || [], attachments:
(index === 1 && attachments.slice(0, 1)) ||
(index === 3 && attachments.slice(2, 4)) ||
(index === 5 && attachments.slice(5, 8)) ||
[],
})); }));
}; };
@@ -178,6 +192,7 @@ export const _products = () =>
newLabel: { enabled: [1, 2, 3].includes(index), content: 'NEW' }, newLabel: { enabled: [1, 2, 3].includes(index), content: 'NEW' },
saleLabel: { enabled: [4, 5].includes(index), content: 'SALE' }, saleLabel: { enabled: [4, 5].includes(index), content: 'SALE' },
sizes: ['6', '7', '8', '8.5', '9', '9.5', '10', '10.5', '11', '11.5', '12', '13'], sizes: ['6', '7', '8', '8.5', '9', '9.5', '10', '10.5', '11', '11.5', '12', '13'],
subDescription: 'Featuring the original ripple design inspired by Japanese bullet trains, the Nike Air Max 97 lets you push your style full-speed ahead.', subDescription:
'Featuring the original ripple design inspired by Japanese bullet trains, the Nike Air Max 97 lets you push your style full-speed ahead.',
}; };
}); });

View File

@@ -1,6 +1,9 @@
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
export const _id = Array.from({ length: 40 }, (_, index) => `e99f09a7-dd88-49d5-b1c8-1daf80c2d7b${index + 1}`); export const _id = Array.from(
{ length: 40 },
(_, index) => `e99f09a7-dd88-49d5-b1c8-1daf80c2d7b${index + 1}`
);
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@@ -34,24 +37,36 @@ export const _booleans = [
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
export const _prices = [ export const _prices = [
83.74, 97.14, 68.71, 85.21, 52.17, 25.18, 43.84, 60.98, 98.42, 53.37, 72.75, 56.61, 64.55, 77.32, 60.62, 79.81, 93.68, 47.44, 76.24, 92.87, 72.91, 20.54, 83.74, 97.14, 68.71, 85.21, 52.17, 25.18, 43.84, 60.98, 98.42, 53.37, 72.75, 56.61, 64.55, 77.32,
94.25, 37.51, 60.62, 79.81, 93.68, 47.44, 76.24, 92.87, 72.91, 20.54, 94.25, 37.51,
]; ];
export const _ratings = [4.2, 3.7, 4.5, 3.5, 0.5, 3.0, 2.5, 2.8, 4.9, 3.6, 2.5, 1.7, 3.9, 2.8, 4.1, 4.5, 2.2, 3.2, 0.6, 1.3, 3.8, 3.8, 3.8, 2.0]; export const _ratings = [
4.2, 3.7, 4.5, 3.5, 0.5, 3.0, 2.5, 2.8, 4.9, 3.6, 2.5, 1.7, 3.9, 2.8, 4.1, 4.5, 2.2, 3.2, 0.6,
1.3, 3.8, 3.8, 3.8, 2.0,
];
export const _ages = [30, 26, 59, 47, 29, 46, 18, 56, 39, 19, 45, 18, 46, 56, 38, 41, 44, 48, 32, 45, 42, 60, 33, 57]; export const _ages = [
30, 26, 59, 47, 29, 46, 18, 56, 39, 19, 45, 18, 46, 56, 38, 41, 44, 48, 32, 45, 42, 60, 33, 57,
];
export const _percents = [ export const _percents = [
10.1, 13.6, 28.2, 42.1, 37.2, 18.5, 40.1, 94.8, 91.4, 53.0, 25.4, 62.9, 86.6, 62.4, 35.4, 17.6, 52.0, 6.8, 95.3, 26.6, 69.9, 92.1, 46.2, 85.6, 10.1, 13.6, 28.2, 42.1, 37.2, 18.5, 40.1, 94.8, 91.4, 53.0, 25.4, 62.9, 86.6, 62.4, 35.4, 17.6,
52.0, 6.8, 95.3, 26.6, 69.9, 92.1, 46.2, 85.6,
]; ];
export const _nativeS = [11, 10, 7, 10, 12, 5, 10, 1, 8, 8, 10, 11, 12, 8, 4, 11, 8, 9, 4, 9, 2, 6, 3, 7]; export const _nativeS = [
11, 10, 7, 10, 12, 5, 10, 1, 8, 8, 10, 11, 12, 8, 4, 11, 8, 9, 4, 9, 2, 6, 3, 7,
];
export const _nativeM = [497, 763, 684, 451, 433, 463, 951, 194, 425, 435, 807, 521, 538, 839, 394, 269, 453, 821, 364, 849, 804, 776, 263, 239]; export const _nativeM = [
497, 763, 684, 451, 433, 463, 951, 194, 425, 435, 807, 521, 538, 839, 394, 269, 453, 821, 364,
849, 804, 776, 263, 239,
];
export const _nativeL = [ export const _nativeL = [
9911, 1947, 9124, 6984, 8488, 2034, 3364, 8401, 8996, 5271, 8478, 1139, 8061, 3035, 6733, 3952, 2405, 3127, 6843, 4672, 6995, 6053, 5192, 9686, 9911, 1947, 9124, 6984, 8488, 2034, 3364, 8401, 8996, 5271, 8478, 1139, 8061, 3035, 6733, 3952,
2405, 3127, 6843, 4672, 6995, 6053, 5192, 9686,
]; ];
export const _fullAddress = [ export const _fullAddress = [

View File

@@ -10,8 +10,7 @@ import type { NextRequest } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response'; import { STATUS, response, handleError } from 'src/utils/response';
// import { AccessLogService } from '../../../../modules/AccessLog/AccessLog.service'; import { AccessLogService } from '../../../../modules/AccessLog/AccessLog.service';
import { getAccessLogById } from 'src/app/services/access-log.service';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@@ -28,7 +27,7 @@ export async function GET(req: NextRequest) {
const accessLogId = searchParams.get('accessLogId'); const accessLogId = searchParams.get('accessLogId');
if (!accessLogId) return response({ message: 'accessLogId is required!' }, STATUS.BAD_REQUEST); if (!accessLogId) return response({ message: 'accessLogId is required!' }, STATUS.BAD_REQUEST);
const accessLog = await getAccessLogById(accessLogId); const accessLog = await AccessLogService.findById(accessLogId);
if (!accessLog) return response({ message: 'AccessLog not found!' }, STATUS.NOT_FOUND); if (!accessLog) return response({ message: 'AccessLog not found!' }, STATUS.NOT_FOUND);

View File

@@ -2,7 +2,7 @@ import type { NextRequest, NextResponse } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response'; import { STATUS, response, handleError } from 'src/utils/response';
import { listAccessLogs } from 'src/app/services/access-log.service'; import { listAccessLogs } from 'src/app/services/AccessLog.service';
// import prisma from '../../lib/prisma'; // import prisma from '../../lib/prisma';

View File

@@ -2,7 +2,7 @@ import type { NextRequest, NextResponse } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response'; import { STATUS, response, handleError } from 'src/utils/response';
import { listAppLogs, deleteAppLog, createNewAppLog } from 'src/app/services/app-log.service'; import { listAppLogs, deleteAppLog, updateAppLog, createNewAppLog } from 'src/app/services/AppLog.service';
// import prisma from '../../lib/prisma'; // import prisma from '../../lib/prisma';
@@ -34,29 +34,28 @@ export async function POST(req: NextRequest) {
} }
} }
// TODO: delete `update AppLog` /**
// /** ***************************************
// *************************************** * PUT - update AppLog
// * PUT - update AppLog ***************************************
// *************************************** */
// */ export async function PUT(req: NextRequest) {
// export async function PUT(req: NextRequest) { const { searchParams } = req.nextUrl;
// const { searchParams } = req.nextUrl; const appLogId = searchParams.get('appLogId');
// const appLogId = searchParams.get('appLogId');
// const { data } = await req.json(); const { data } = await req.json();
// try { try {
// if (!appLogId) throw new Error('appLogId cannot null'); if (!appLogId) throw new Error('appLogId cannot null');
// const id: number = parseInt(appLogId); const id: number = parseInt(appLogId);
// const updateResult = await updateAppLog(id, data); const updateResult = await updateAppLog(id, data);
// return response(updateResult, STATUS.OK); return response(updateResult, STATUS.OK);
// } catch (error) { } catch (error) {
// return handleError('AppLog - Update', error); return handleError('AppLog - Update', error);
// } }
// } }
/** /**
*************************************** ***************************************
@@ -73,7 +72,7 @@ export async function DELETE(req: NextRequest) {
if (!appLogId) throw new Error('appLogId cannot null'); if (!appLogId) throw new Error('appLogId cannot null');
const id: number = parseInt(appLogId); const id: number = parseInt(appLogId);
const deleteResult = await deleteAppLog(id.toString()); const deleteResult = await deleteAppLog(id);
return response(deleteResult, STATUS.OK); return response(deleteResult, STATUS.OK);
} catch (error) { } catch (error) {

View File

@@ -8,7 +8,7 @@ import { STATUS, response, handleError } from 'src/utils/response';
import { JWT_SECRET } from 'src/_mock/_auth'; import { JWT_SECRET } from 'src/_mock/_auth';
import { getUserById } from 'src/app/services/user.service'; import { getUserById } from 'src/app/services/user.service';
import { createAccessLog } from 'src/app/services/access-log.service'; import { createAccessLog } from 'src/app/services/AccessLog.service';
import { flattenNextjsRequest } from '../sign-in/flattenNextjsRequest'; import { flattenNextjsRequest } from '../sign-in/flattenNextjsRequest';

View File

@@ -4,7 +4,7 @@ import { sign } from 'src/utils/jwt';
import { STATUS, response, handleError } from 'src/utils/response'; import { STATUS, response, handleError } from 'src/utils/response';
import { JWT_SECRET, JWT_EXPIRES_IN } from 'src/_mock/_auth'; import { JWT_SECRET, JWT_EXPIRES_IN } from 'src/_mock/_auth';
import { createAccessLog } from 'src/app/services/access-log.service'; import { createAccessLog } from 'src/app/services/AccessLog.service';
import prisma from '../../../lib/prisma'; import prisma from '../../../lib/prisma';
import { flattenNextjsRequest } from './flattenNextjsRequest'; import { flattenNextjsRequest } from './flattenNextjsRequest';

View File

@@ -12,7 +12,7 @@ import { STATUS, response, handleError } from 'src/utils/response';
import { L_INFO, L_ERROR } from 'src/constants'; import { L_INFO, L_ERROR } from 'src/constants';
import { getEvent } from 'src/app/services/eventItem.service'; import { getEvent } from 'src/app/services/eventItem.service';
import { createAppLog } from 'src/app/services/app-log.service'; import { createAppLog } from 'src/app/services/AppLog.service';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------

View File

@@ -7,28 +7,29 @@ import { _events } from 'src/_mock/_event';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// export const runtime = 'edge'; export const runtime = 'edge';
/** ************************************** /** **************************************
* GET - Search events * GET - Search events
*************************************** */ *************************************** */
export async function GET(req: NextRequest) { export async function GET(req: NextRequest) {
// try { try {
// const { searchParams } = req.nextUrl;
// TODO: implement search events const query = searchParams.get('query')?.trim().toLowerCase();
//
// 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) { if (!query) {
return handleError('Event - Get search not implemented', {}); 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

@@ -11,7 +11,7 @@ import type { NextRequest } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response'; import { STATUS, response, handleError } from 'src/utils/response';
import { L_INFO, L_ERROR } from 'src/constants'; import { L_INFO, L_ERROR } from 'src/constants';
import { createAppLog } from 'src/app/services/app-log.service'; import { createAppLog } from 'src/app/services/AppLog.service';
import prisma from '../../../lib/prisma'; import prisma from '../../../lib/prisma';
import { flattenNextjsRequest } from '../../auth/sign-in/flattenNextjsRequest'; import { flattenNextjsRequest } from '../../auth/sign-in/flattenNextjsRequest';

View File

@@ -24,7 +24,9 @@ export async function GET(req: NextRequest) {
const products = _products(); const products = _products();
// Accept search by name or sku // Accept search by name or sku
const results = products.filter(({ name, sku }) => name.toLowerCase().includes(query) || sku?.toLowerCase().includes(query)); const results = products.filter(
({ name, sku }) => name.toLowerCase().includes(query) || sku?.toLowerCase().includes(query)
);
logger('[Product] search-results', results.length); logger('[Product] search-results', results.length);

View File

@@ -25,8 +25,13 @@ const ENDPOINTS = {
}; };
function loggerData(action?: string, value?: unknown) { function loggerData(action?: string, value?: unknown) {
const columnsWithTasks = boardData.columns.map((col) => `${col.name} (${boardData.tasks[col.id].length} tasks)`); const columnsWithTasks = boardData.columns.map(
logger('[Kanban] get-board', `columns (${boardData.columns.length}): ${JSON.stringify(columnsWithTasks, null, 2)}`); (col) => `${col.name} (${boardData.tasks[col.id].length} tasks)`
);
logger(
'[Kanban] get-board',
`columns (${boardData.columns.length}): ${JSON.stringify(columnsWithTasks, null, 2)}`
);
if (value || action) { if (value || action) {
logger(`[Kanban] ${action}`, value); logger(`[Kanban] ${action}`, value);
} }
@@ -121,7 +126,9 @@ async function updateColumn(req: NextRequest) {
// Find and update the specified column. // Find and update the specified column.
updateBoardData({ updateBoardData({
columns: boardData.columns.map((col) => (col.id === columnId ? { ...col, name: columnName } : col)), columns: boardData.columns.map((col) =>
col.id === columnId ? { ...col, name: columnName } : col
),
}); });
loggerData('updated-column', columnName); loggerData('updated-column', columnName);
@@ -215,7 +222,9 @@ async function updateTask(req: NextRequest) {
updateBoardData({ updateBoardData({
tasks: { tasks: {
...boardData.tasks, ...boardData.tasks,
[columnId]: boardData.tasks[columnId].map((task) => (task.id === taskData.id ? { ...task, ...taskData } : task)), [columnId]: boardData.tasks[columnId].map((task) =>
task.id === taskData.id ? { ...task, ...taskData } : task
),
}, },
}); });

View File

@@ -31,7 +31,10 @@ export async function GET(req: NextRequest) {
} }
// Get filtered mails // Get filtered mails
const filteredMails = label.type === 'custom' ? mails.filter((mail) => mail.labelIds.includes(labelId!)) : filterMailsByLabelId(mails, labelId); const filteredMails =
label.type === 'custom'
? mails.filter((mail) => mail.labelIds.includes(labelId!))
: filterMailsByLabelId(mails, labelId);
logger(`[Mail] label-[${labelId}]`, filteredMails.length); logger(`[Mail] label-[${labelId}]`, filteredMails.length);

View File

@@ -28,7 +28,7 @@ export async function POST(req: NextRequest) {
try { try {
const order = await createOrder(data); const order = await createOrder(data);
return response(order, STATUS.OK); return response(order, STATUS.CREATED);
} catch (error) { } catch (error) {
return handleError('Order - Create', error); return handleError('Order - Create', error);
} }
@@ -48,7 +48,7 @@ export async function PUT(req: NextRequest) {
if (!orderId) throw new Error('orderId cannot be null'); if (!orderId) throw new Error('orderId cannot be null');
const id: number = parseInt(orderId); const id: number = parseInt(orderId);
const updatedOrder = await updateOrder(id.toString(), data); const updatedOrder = await updateOrder(id, data);
return response(updatedOrder, STATUS.OK); return response(updatedOrder, STATUS.OK);
} catch (error) { } catch (error) {
return handleError('Order - Update', error); return handleError('Order - Update', error);
@@ -68,7 +68,7 @@ export async function DELETE(req: NextRequest) {
if (!orderId) throw new Error('orderId cannot be null'); if (!orderId) throw new Error('orderId cannot be null');
const id: number = parseInt(orderId); const id: number = parseInt(orderId);
await deleteOrder(id.toString()); await deleteOrder(id);
return response({ success: true }, STATUS.OK); return response({ success: true }, STATUS.OK);
} catch (error) { } catch (error) {
return handleError('Order - Delete', error); return handleError('Order - Delete', error);

View File

@@ -24,7 +24,9 @@ export async function GET(req: NextRequest) {
const products = _products(); const products = _products();
// Accept search by name or sku // Accept search by name or sku
const results = products.filter(({ name, sku }) => name.toLowerCase().includes(query) || sku?.toLowerCase().includes(query)); const results = products.filter(
({ name, sku }) => name.toLowerCase().includes(query) || sku?.toLowerCase().includes(query)
);
logger('[Product] search-results', results.length); logger('[Product] search-results', results.length);

View File

@@ -47,7 +47,9 @@ export async function GET(req: NextRequest) {
products: paginatedProducts, products: paginatedProducts,
totalPages, totalPages,
totalItems, totalItems,
categoryOptions: Array.from(new Set(_products.map(({ category: c_category }) => c_category))), // Remove duplicate categories categoryOptions: Array.from(
new Set(_products.map(({ category: c_category }) => c_category))
), // Remove duplicate categories
}, },
STATUS.OK STATUS.OK
); );
@@ -68,7 +70,9 @@ function paginateProducts(products: Products, page: number, perPage: number) {
function filterProducts(products: Products, searchQuery: string, category: string) { function filterProducts(products: Products, searchQuery: string, category: string) {
return products.filter(({ id, name, category: prodCategory }) => { return products.filter(({ id, name, category: prodCategory }) => {
// Accept search by id or name // Accept search by id or name
const matchesSearch = searchQuery ? id.includes(searchQuery) || name.toLowerCase().includes(searchQuery) : true; const matchesSearch = searchQuery
? id.includes(searchQuery) || name.toLowerCase().includes(searchQuery)
: true;
const matchesCategory = category ? prodCategory === category : true; const matchesCategory = category ? prodCategory === category : true;
return matchesSearch && matchesCategory; return matchesSearch && matchesCategory;

View File

@@ -1,40 +0,0 @@
// src/app/api/party-event/create/route.ts
//
// PURPOSE:
// Create new party event in db
//
// RULES:
// T.B.A.
import type { NextRequest } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
import { isDev } from 'src/constants';
import { createEvent } from 'src/app/services/party-event.service';
// ----------------------------------------------------------------------
/** **************************************
* POST - Create PartyEvent
*************************************** */
export async function POST(req: NextRequest) {
const { partyEventData } = await req.json();
try {
if (isDev) {
console.log({ partyEventData });
}
const created = await createEvent(partyEventData);
if (isDev) {
console.log('Event created successfully');
}
return response(created, STATUS.OK);
} catch (error) {
console.error('Error creating event:', { partyEventData });
return handleError('PartyEvent - Create', error);
}
}

View File

@@ -1,34 +0,0 @@
###
POST http://localhost:7272/api/party-event/create
Content-Type: application/json
{
"partyEventData": {
"title": "Summer Music Festival",
"description": "Annual summer music festival featuring local bands and artists",
"startDate": "2024-07-15T18:00:00Z",
"endDate": "2024-07-15T23:00:00Z",
"location": "Central Park, Hong Kong",
"coverUrl": "",
"images": [
"data:image/png;base64,C",
"data:image/png;base64,C"
],
"tags": [
"Music",
"Festival"
],
"status": "upcoming",
"capacity": 500,
"price": 150.00,
"organizer": "HK Music Society",
"category": "Music",
"isFeatured": true,
"registrationDeadline": "2024-07-10T00:00:00Z",
"requirements": "Age 18+",
"schedule": "18:00 Doors open\n19:00 First performance\n21:00 Main act",
"speakers": ["DJ Lee", "Band XYZ"],
"sponsors": ["HK Radio", "Music Magazine"]
}
}

View File

@@ -1,22 +0,0 @@
import type { NextRequest } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
import { deleteEvent } from 'src/app/services/party-event.service';
/** **************************************
* PATCH - Delete PartyEvent
*************************************** */
export async function PATCH(req: NextRequest) {
try {
const { eventId } = await req.json();
if (!eventId) throw new Error('eventId cannot be null');
await deleteEvent(eventId);
return response({ eventId }, STATUS.OK);
} catch (error) {
return handleError('PartyEvent - Delete', error);
}
}

View File

@@ -1,8 +0,0 @@
###
PATCH http://localhost:7272/api/party-event/delete
Content-Type: application/json
{
"eventId": "e99f09a7-dd88-49d5-b1c8-1daf80c2d7b01"
}

View File

@@ -1,56 +0,0 @@
// src/app/api/party-event/details/route.ts
//
// PURPOSE:
// Get party 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 { L_INFO, L_ERROR } from 'src/constants';
import { getEvent } from 'src/app/services/party-event.service';
import { createAppLog } from 'src/app/services/app-log.service';
import { flattenNextjsRequest } from '../../auth/sign-in/flattenNextjsRequest';
// ----------------------------------------------------------------------
/**
**************************************
* GET PartyEvent detail
***************************************
*/
export async function GET(req: NextRequest) {
const debug = { 'req.headers': flattenNextjsRequest(req) };
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 getEvent(eventId);
if (!event) {
return response({ message: 'Event not found!' }, STATUS.NOT_FOUND);
}
logger('[PartyEvent] details', event.id);
createAppLog(L_INFO, 'Get event detail OK', debug);
return response({ event }, STATUS.OK);
} catch (error) {
createAppLog(L_ERROR, 'event detail error', debug);
return handleError('PartyEvent - Get details', error);
}
}

View File

@@ -1,9 +0,0 @@
###
# Get details for a specific party event
GET http://localhost:7272/api/party-event/details?eventId=e99f09a7-dd88-49d5-b1c8-1daf80c2d7b01
###
# Alternative format with different ID
GET http://localhost:7272/api/party-event/details?eventId=evt_987654321

View File

@@ -1,16 +0,0 @@
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: 'party-event' }, STATUS.OK);
} catch (error) {
return handleError('Helloworld - Get all', error);
}
}

View File

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

View File

@@ -1,38 +0,0 @@
// src/app/api/party-event/list/route.ts
//
// PURPOSE:
// List all party events from db
//
// RULES:
// T.B.A.
import type { NextRequest } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
import { L_INFO, L_ERROR } from 'src/constants';
import { createAppLog } from 'src/app/services/app-log.service';
import { listEvents } from 'src/app/services/party-event.service';
import { flattenNextjsRequest } from '../../auth/sign-in/flattenNextjsRequest';
// ----------------------------------------------------------------------
/** **************************************
* GET - PartyEvents list
*************************************** */
export async function GET(req: NextRequest) {
const debug = { 'req.headers': flattenNextjsRequest(req) };
try {
const events = await listEvents();
createAppLog(L_INFO, 'party-event list ok', {});
return response({ events }, STATUS.OK);
} catch (error) {
createAppLog(L_ERROR, 'party-event list error', debug);
return handleError('PartyEvent - Get list', error);
}
}

View File

@@ -1,14 +0,0 @@
###
# Basic list all party events
GET http://localhost:7272/api/party-event/list
###
# List upcoming party events
GET http://localhost:7272/api/party-event/list?status=upcoming
###
# List featured party events
GET http://localhost:7272/api/party-event/list?isFeatured=true

View File

@@ -1,75 +0,0 @@
import type { NextRequest, NextResponse } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
import { listEvents, deleteEvent, updateEvent, createEvent } from 'src/app/services/party-event.service';
/**
**************************************
* GET - PartyEvent
***************************************
*/
export async function GET(req: NextRequest, res: NextResponse) {
try {
const events = await listEvents();
return response(events, STATUS.OK);
} catch (error) {
return handleError('PartyEvent - Get list', error);
}
}
/**
***************************************
* POST - Create PartyEvent
***************************************
*/
export async function POST(req: NextRequest) {
const OPERATION = 'PartyEvent - Create';
const { data } = await req.json();
try {
const event = await createEvent(data);
return response(OPERATION, STATUS.OK);
} catch (error) {
return handleError(OPERATION, error);
}
}
/**
***************************************
* PUT - Update PartyEvent
***************************************
*/
export async function PUT(req: NextRequest) {
const { searchParams } = req.nextUrl;
const eventId = searchParams.get('eventId');
const { data } = await req.json();
try {
if (!eventId) throw new Error('eventId cannot be null');
const result = await updateEvent(eventId, data);
return response(result, STATUS.OK);
} catch (error) {
return handleError('PartyEvent - Update', error);
}
}
/**
***************************************
* DELETE - Delete PartyEvent
***************************************
*/
export async function DELETE(req: NextRequest) {
const { searchParams } = req.nextUrl;
const eventId = searchParams.get('eventId');
try {
if (!eventId) throw new Error('eventId cannot be null');
await deleteEvent(eventId);
return response({ success: true }, STATUS.OK);
} catch (error) {
return handleError('PartyEvent - Delete', error);
}
}

View File

@@ -1,34 +0,0 @@
import type { NextRequest } from 'next/server';
import { logger } from 'src/utils/logger';
import { STATUS, response, handleError } from 'src/utils/response';
import { IEventItem } from '../update/route';
// import { searchEvents } from 'src/app/services/party-event.service';
// ----------------------------------------------------------------------
/** **************************************
* GET - Search PartyEvents
*************************************** */
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 results: IEventItem[] = [];
// TODO: search party event not implemented
console.log('search party event not implemented');
// const results = await searchEvents(query);
logger('[PartyEvent] search-results', results?.length);
return response({ results }, STATUS.OK);
} catch (error) {
return handleError('PartyEvent - Get search', error);
}
}

View File

@@ -1,24 +0,0 @@
###
# Search party events by title
GET http://localhost:7272/api/party-event/search?query=Music
###
# Search party events by location
GET http://localhost:7272/api/party-event/search?query=Central+Park
###
# Search party events by tag
GET http://localhost:7272/api/party-event/search?query=Festival
###
# Combined search with multiple parameters
GET http://localhost:7272/api/party-event/search?query=Summer&location=Hong+Kong&category=Music
###
# No results expected
GET http://localhost:7272/api/party-event/search?query=zzzzzz

View File

@@ -1,57 +0,0 @@
// src/app/api/party-event/update/route.ts
//
// PURPOSE:
// Update party event in db by id
//
// RULES:
// T.B.A.
import type { NextRequest } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
import { updateEvent } from 'src/app/services/party-event.service';
// ----------------------------------------------------------------------
/** **************************************
* PUT - Update PartyEvent
*************************************** */
export async function PUT(req: NextRequest) {
const { partyEventData } = await req.json();
const { id } = partyEventData;
if (!id) return response({ message: 'id not found' }, STATUS.ERROR);
try {
const result = await updateEvent(id, partyEventData);
return response({ result }, STATUS.OK);
} catch (error) {
console.error('Error updating event:', { partyEventData });
return handleError('PartyEvent - Update', error);
}
}
export type IEventItem = {
id: string;
title: string;
description: string;
startDate: Date;
endDate: Date;
location: string;
coverUrl: string;
images: string[];
tags: string[];
status: string;
capacity: number;
price: number;
organizer: string;
category: string;
isFeatured: boolean;
registrationDeadline: Date;
requirements: string[];
schedule: string;
speakers: string[];
sponsors: string[];
};

View File

@@ -1,35 +0,0 @@
###
PUT http://localhost:7272/api/party-event/update
Content-Type: application/json
{
"partyEventData": {
"id":"e99f09a7-dd88-49d5-b1c8-1daf80c2d7b01",
"title": "Summer Music Festival",
"description": "Annual summer music festival featuring local bands and artists",
"startDate": "2024-07-15T18:00:00Z",
"endDate": "2024-07-15T23:00:00Z",
"location": "Central Park, Hong Kong",
"coverUrl": "",
"images": [
"data:image/png;base64,C",
"data:image/png;base64,C"
],
"tags": [
"Music",
"Festival"
],
"status": "upcoming",
"capacity": 500,
"price": 150.00,
"organizer": "HK Music Society",
"category": "Music",
"isFeatured": true,
"registrationDeadline": "2024-07-10T00:00:00Z",
"requirements": "Age 18+",
"schedule": "18:00 Doors open\n19:00 First performance\n21:00 Main act",
"speakers": ["DJ Lee", "Band XYZ"],
"sponsors": ["HK Radio", "Music Magazine"]
}
}

View File

@@ -24,7 +24,10 @@ export async function GET(req: NextRequest) {
const posts = _posts(); const posts = _posts();
// Accept search by title or description // Accept search by title or description
const results = posts.filter(({ title, description }) => title.toLowerCase().includes(query) || description?.toLowerCase().includes(query)); const results = posts.filter(
({ title, description }) =>
title.toLowerCase().includes(query) || description?.toLowerCase().includes(query)
);
logger('[Post] search-results', results.length); logger('[Post] search-results', results.length);

View File

@@ -1,46 +0,0 @@
// src/app/api/product/createProduct/route.ts
// REQ0183 frontend product new
//
// PURPOSE:
// create product to db
//
// RULES:
// T.B.A.
//
import type { NextRequest } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
import { isDev } from 'src/constants';
import prisma from '../../../lib/prisma';
import { createProduct } from 'src/app/services/product.service';
// import { createProduct } from 'src/app/services/product.service';
// ----------------------------------------------------------------------
/** **************************************
* POST - Products
*************************************** */
export async function POST(req: NextRequest) {
const { productData } = await req.json();
try {
if (isDev) {
console.log({ productData });
}
const created = await createProduct(productData);
// const created = await prisma.productItem.create({ data: productData });
if (isDev) {
console.log('create done');
}
return response(created, STATUS.OK);
} catch (error) {
console.log({ hello: 'world', productData });
return handleError('Product - Create', error);
}
}

View File

@@ -1,51 +0,0 @@
###
POST http://localhost:7272/api/product/create
Content-Type: application/json
{
"productData": {
"available": 99,
"category": "T-shirts",
"code": "PD-12345",
"colors": [
"Red"
],
"coverUrl": "",
"description": "this is description, 会員管理機能は、単なるデータ管理ツール以上の価値を持ちます。 企業は顧客の情報や動向を深く理解し、長期的な顧客関係の構築やロイヤルティの確立、そして迅速な市場変動への対応に直結します。 会員管理機能は、現代のビジネスにおいて企業の競争力を高める基盤として欠かせないものとなっています。",
"gender": [
"Men"
],
"images": [
"data:image/png;base64,C",
"data:image/png;base64,C"
],
"inventoryType": "test",
"name": "hello product",
"newLabel": {
"enabled": false,
"content": ""
},
"price": 99.99,
"priceSale": null,
"publish": "yes",
"quantity": 99,
"saleLabel": {
"enabled": false,
"content": ""
},
"sizes": [
"7"
],
"sku": "SK-122345",
"subDescription": "this is test sub-description",
"tags": [
"Travel",
"Finance"
],
"taxes": 0,
"totalRatings": 1,
"totalReviews": 1,
"totalSold": 1
}
}

View File

@@ -0,0 +1,75 @@
// src/app/api/product/createProduct/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 - Products
*************************************** */
export async function POST(req: NextRequest) {
// logger('[Product] list', products.length);
const { data } = await req.json();
const createForm: CreateProductData = data as unknown as CreateProductData;
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('Product - Create', error);
}
}
type CreateProductData = {
// 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

@@ -1,22 +0,0 @@
import type { NextRequest } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response';
import { deleteProduct } from 'src/app/services/product.service';
/** **************************************
* PATCH - Delete product
*************************************** */
export async function PATCH(req: NextRequest) {
try {
const { productId } = await req.json();
if (!productId) throw new Error('productId cannot be null');
await deleteProduct(productId);
return response({ productId }, STATUS.OK);
} catch (error) {
return handleError('Product - Delete', error);
}
}

View File

@@ -1,8 +0,0 @@
###
PATCH http://localhost:7272/api/product/delete
Content-Type: application/json
{
"productId" :"e99f09a7-dd88-49d5-b1c8-1daf80c2d7b06"
}

View File

@@ -0,0 +1,44 @@
// src/app/api/product/deleteProduct/route.ts
//
// PURPOSE:
// delete product 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 Products
*************************************** */
export async function DELETE(req: NextRequest) {
try {
const { searchParams } = req.nextUrl;
// RULES: productId must exist
const productId = searchParams.get('productId');
if (!productId) {
return response({ message: 'Product ID is required!' }, STATUS.BAD_REQUEST);
}
// NOTE: productId confirmed exist, run below
const product = await prisma.productItem.delete({ where: { id: productId } });
if (!product) {
return response({ message: 'Product not found!' }, STATUS.NOT_FOUND);
}
logger('[Product] details', product.id);
return response({ product }, STATUS.OK);
} catch (error) {
return handleError('Product - Get details', error);
}
}

View File

@@ -0,0 +1,3 @@
###
DELETE http://localhost:7272/api/product/deleteProduct?productId=e99f09a7-dd88-49d5-b1c8-1daf80c2d7b06

View File

@@ -1,7 +1,5 @@
// src/app/api/product/details/route.ts // src/app/api/product/details/route.ts
// //
// REQ0182 frontend product details
//
// PURPOSE: // PURPOSE:
// get product from db by id // get product from db by id
// //
@@ -15,7 +13,7 @@ import { STATUS, response, handleError } from 'src/utils/response';
import { L_INFO, L_ERROR } from 'src/constants'; import { L_INFO, L_ERROR } from 'src/constants';
import { getProduct } from 'src/app/services/product.service'; import { getProduct } from 'src/app/services/product.service';
import { createAppLog } from 'src/app/services/app-log.service'; import { createAppLog } from 'src/app/services/AppLog.service';
import { flattenNextjsRequest } from '../../auth/sign-in/flattenNextjsRequest'; import { flattenNextjsRequest } from '../../auth/sign-in/flattenNextjsRequest';

View File

@@ -1,5 +1,3 @@
### ###
GET http://localhost:7272/api/product/details?productId=e99f09a7-dd88-49d5-b1c8-1daf80c2d7b01
###
GET http://localhost:7272/api/product/details?productId=e99f09a7-dd88-49d5-b1c8-1daf80c2d7b01 GET http://localhost:7272/api/product/details?productId=e99f09a7-dd88-49d5-b1c8-1daf80c2d7b01

View File

@@ -1,16 +0,0 @@
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

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

View File

@@ -0,0 +1,30 @@
// 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

@@ -11,7 +11,7 @@ import type { NextRequest } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response'; import { STATUS, response, handleError } from 'src/utils/response';
import { L_INFO, L_ERROR } from 'src/constants'; import { L_INFO, L_ERROR } from 'src/constants';
import { createAppLog } from 'src/app/services/app-log.service'; import { createAppLog } from 'src/app/services/AppLog.service';
import { listProducts } from 'src/app/services/product.service'; import { listProducts } from 'src/app/services/product.service';
import { flattenNextjsRequest } from '../../auth/sign-in/flattenNextjsRequest'; import { flattenNextjsRequest } from '../../auth/sign-in/flattenNextjsRequest';

View File

@@ -0,0 +1,23 @@
import { logger } from 'src/utils/logger';
import { STATUS, response, handleError } from 'src/utils/response';
import { _products } from 'src/_mock/_product';
// ----------------------------------------------------------------------
export const runtime = 'edge';
/** **************************************
* GET - Products
*************************************** */
export async function GET() {
try {
const products = _products();
logger('[Product] list', products.length);
return response({ products }, STATUS.OK);
} catch (error) {
return handleError('Product - Get list', error);
}
}

View File

@@ -24,14 +24,13 @@ export async function GET(req: NextRequest, res: NextResponse) {
*************************************** ***************************************
*/ */
export async function POST(req: NextRequest) { export async function POST(req: NextRequest) {
const OPERATION = 'Product - Create';
const { data } = await req.json(); const { data } = await req.json();
try { try {
const product = await createProduct(data); const product = await createProduct(data);
return response(OPERATION, STATUS.OK); return response(product, STATUS.CREATED);
} catch (error) { } catch (error) {
return handleError(OPERATION, error); return handleError('Product - Create', error);
} }
} }

View File

@@ -17,58 +17,58 @@ import prisma from '../../../lib/prisma';
/** ************************************** /** **************************************
* GET - Products * GET - Products
*************************************** */ *************************************** */
export async function PUT(req: NextRequest) { export async function POST(req: NextRequest) {
// logger('[Product] list', products.length); // logger('[Product] list', products.length);
const { productData } = await req.json(); const { data } = await req.json();
try { try {
const products = await prisma.productItem.updateMany({ const products = await prisma.productItem.updateMany({
data: { data: {
name: productData.name, name: data.name,
sku: productData.sku, sku: data.sku,
code: productData.code, code: data.code,
price: productData.price, price: data.price,
taxes: productData.taxes, taxes: data.taxes,
tags: productData.tags, tags: data.tags,
sizes: productData.sizes, sizes: data.sizes,
publish: productData.publish, publish: data.publish,
gender: productData.gender, gender: data.gender,
coverUrl: productData.coverUrl, coverUrl: data.coverUrl,
images: productData.images, images: data.images,
colors: productData.colors, colors: data.colors,
quantity: productData.quantity, quantity: data.quantity,
category: productData.category, category: data.category,
available: productData.available, available: data.available,
totalSold: productData.totalSold, totalSold: data.totalSold,
description: productData.description, description: data.description,
totalRatings: productData.totalRatings, totalRatings: data.totalRatings,
totalReviews: productData.totalReviews, totalReviews: data.totalReviews,
inventoryType: productData.inventoryType, inventoryType: data.inventoryType,
subDescription: productData.subDescription, subDescription: data.subDescription,
priceSale: productData.priceSale, priceSale: data.priceSale,
// //
newLabel: { newLabel: {
content: productData.newLabel?.content || '', content: data.newLabel?.content || '',
enabled: productData.newLabel?.enabled ?? false, enabled: data.newLabel?.enabled ?? false,
}, },
saleLabel: { saleLabel: {
content: productData.saleLabel?.content || '', content: data.saleLabel?.content || '',
enabled: productData.saleLabel?.enabled ?? false, enabled: data.saleLabel?.enabled ?? false,
}, },
ratings: { ratings: {
set: productData.ratings.map((rating: { name: string; starCount: number; reviewCount: number }) => ({ set: data.ratings.map((rating: { name: string; starCount: number; reviewCount: number }) => ({
name: rating.name, name: rating.name,
starCount: rating.starCount, starCount: rating.starCount,
reviewCount: rating.reviewCount, reviewCount: rating.reviewCount,
})), })),
}, },
}, },
where: { id: productData.id }, where: { id: data.id },
}); });
return response({ data: productData }, STATUS.OK); return response({ data }, STATUS.OK);
} catch (error) { } catch (error) {
console.log({ data: productData }); console.log({ data });
return handleError('Product - Get list', error); return handleError('Product - Get list', 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 { getProductBySkuOrName } from 'src/app/services/product.service'; import { _products } from 'src/_mock/_product';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// export const runtime = 'edge'; export const runtime = 'edge';
/** ************************************** /** **************************************
* GET - Search products * GET - Search products
@@ -21,9 +21,12 @@ export async function GET(req: NextRequest) {
return response({ results: [] }, STATUS.OK); return response({ results: [] }, STATUS.OK);
} }
const results = await getProductBySkuOrName(query); const products = _products();
logger('[Product] search-results', results?.length); // Accept search by name or sku
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

@@ -1,8 +0,0 @@
###
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

@@ -1,52 +0,0 @@
###
PUT http://localhost:7272/api/product/update
Content-Type: application/json
{
"productData": {
"available": 99,
"category": "T-shirts",
"code": "PD-12345",
"colors": [
"Red"
],
"coverUrl": "",
"description": "this is description, 会員管理機能は、単なるデータ管理ツール以上の価値を持ちます。 企業は顧客の情報や動向を深く理解し、長期的な顧客関係の構築やロイヤルティの確立、そして迅速な市場変動への対応に直結します。 会員管理機能は、現代のビジネスにおいて企業の競争力を高める基盤として欠かせないものとなっています。",
"gender": [
"Men"
],
"images": [
"data:image/png;base64,C",
"data:image/png;base64,C"
],
"inventoryType": "test",
"name": "hello product",
"newLabel": {
"enabled": false,
"content": ""
},
"price": 99.99,
"priceSale": null,
"publish": "yes",
"quantity": 99,
"ratings":[],
"saleLabel": {
"enabled": false,
"content": ""
},
"sizes": [
"7"
],
"sku": "SK-122345",
"subDescription": "this is test sub-description",
"tags": [
"Travel",
"Finance"
],
"taxes": 0,
"totalRatings": 1,
"totalReviews": 1,
"totalSold": 1
}
}

View File

@@ -1,7 +1,6 @@
import prisma from '@/lib/prisma';
import { NextResponse } from 'next/server'; import { NextResponse } from 'next/server';
import prisma from 'src/app/lib/prisma';
// GET: 获取所有学生 // GET: 获取所有学生
export async function GET() { export async function GET() {
try { try {

View File

@@ -4,7 +4,7 @@ import type { NextRequest } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response'; import { STATUS, response, handleError } from 'src/utils/response';
import { changeToAdmin } from 'src/app/services/user-item.service'; import { changeToAdmin } from 'src/app/services/userItem.service';
/** /**
*************************************** ***************************************

View File

@@ -4,7 +4,7 @@ import type { NextRequest } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response'; import { STATUS, response, handleError } from 'src/utils/response';
import { changeToUser } from 'src/app/services/user-item.service'; import { changeToUser } from 'src/app/services/userItem.service';
/** /**
*************************************** ***************************************

View File

@@ -2,7 +2,7 @@ import type { NextRequest, NextResponse } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response'; import { STATUS, response, handleError } from 'src/utils/response';
import { isAdmin } from 'src/app/services/user-item.service'; import { isAdmin } from 'src/app/services/userItem.service';
// import prisma from '../../lib/prisma'; // import prisma from '../../lib/prisma';
@@ -14,8 +14,8 @@ export async function GET(req: NextRequest, res: NextResponse) {
if (!userId) throw new Error('userId cannot be null'); if (!userId) throw new Error('userId cannot be null');
const result = await isAdmin(userId); const result = await isAdmin(userId);
return response(result ? 'true' : 'false', STATUS.OK); return response(result, STATUS.OK);
} catch (error) { } catch (error) {
return handleError('GET - checkAdmin', error); return handleError('Post - Get latest', error);
} }
} }

View File

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

View File

@@ -3,7 +3,7 @@
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 { listUsers } from 'src/app/services/user-item.service'; import { listUsers } from 'src/app/services/userItem.service';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------

View File

@@ -2,7 +2,7 @@ import type { NextRequest, NextResponse } from 'next/server';
import { STATUS, response, handleError } from 'src/utils/response'; import { STATUS, response, handleError } from 'src/utils/response';
import { listUsers, deleteUser, updateUser, createNewUser } from 'src/app/services/user-item.service'; import { listUsers, deleteUser, updateUser, createNewUser } from 'src/app/services/userItem.service';
// import prisma from '../../lib/prisma'; // import prisma from '../../lib/prisma';
@@ -22,17 +22,14 @@ export async function GET(req: NextRequest, res: NextResponse) {
*************************************** ***************************************
*/ */
export async function POST(req: NextRequest) { export async function POST(req: NextRequest) {
const OPERATION = 'User - Create';
const { data } = await req.json(); const { data } = await req.json();
try { try {
// TODO: temporary ignore output from function due to `createNewUser` is still a dummy const createResult = await createNewUser(data);
// const createResult = await createNewUser(data);
await createNewUser(data);
return response(OPERATION, STATUS.OK); return response(createResult, STATUS.OK);
} catch (error) { } catch (error) {
return handleError(OPERATION, error); return handleError('User - Create', error);
} }
} }
@@ -51,7 +48,7 @@ export async function PUT(req: NextRequest) {
if (!userId) throw new Error('userId cannot null'); if (!userId) throw new Error('userId cannot null');
const id: number = parseInt(userId); const id: number = parseInt(userId);
const updateResult = await updateUser(id.toString(), data); const updateResult = await updateUser(id, data);
return response(updateResult, STATUS.OK); return response(updateResult, STATUS.OK);
} catch (error) { } catch (error) {
@@ -74,10 +71,10 @@ export async function DELETE(req: NextRequest) {
if (!userId) throw new Error('userId cannot null'); if (!userId) throw new Error('userId cannot null');
const id: number = parseInt(userId); const id: number = parseInt(userId);
await deleteUser(id); const deleteResult = await deleteUser(id);
return response('User - Delete', STATUS.OK); return response(deleteResult, STATUS.OK);
} catch (error) { } catch (error) {
return handleError('User - Delete', error); return handleError('User - Update', error);
} }
} }

View File

@@ -24,7 +24,9 @@ export async function GET(req: NextRequest) {
const products = _products(); const products = _products();
// Accept search by name or sku // Accept search by name or sku
const results = products.filter(({ name, sku }) => name.toLowerCase().includes(query) || sku?.toLowerCase().includes(query)); const results = products.filter(
({ name, sku }) => name.toLowerCase().includes(query) || sku?.toLowerCase().includes(query)
);
logger('[Product] search-results', results.length); logger('[Product] search-results', results.length);

View File

@@ -30,15 +30,10 @@ async function listAccessLogs(): Promise<AccessLog[]> {
}); });
} }
// TODO: obsoleted getAccessLog, use getAccessLogById instead
async function getAccessLog(id: string): Promise<AccessLog | null> { async function getAccessLog(id: string): Promise<AccessLog | null> {
return prisma.accessLog.findUnique({ where: { id } }); return prisma.accessLog.findUnique({ where: { id } });
} }
async function getAccessLogById(id: string): Promise<AccessLog | null> {
return prisma.accessLog.findUnique({ where: { id } });
}
async function createAccessLog(userId?: string, message?: string, metadata?: Record<string, any>): Promise<AccessLog> { async function createAccessLog(userId?: string, message?: string, metadata?: Record<string, any>): Promise<AccessLog> {
return prisma.accessLog.create({ return prisma.accessLog.create({
data: { data: {
@@ -49,10 +44,6 @@ async function createAccessLog(userId?: string, message?: string, metadata?: Rec
}); });
} }
function helloworld(): string {
return 'helloworld';
}
// async function update(id: string, data: UpdateAccessLog): Promise<AccessLog> { // async function update(id: string, data: UpdateAccessLog): Promise<AccessLog> {
// return prisma.accessLog.update({ // return prisma.accessLog.update({
// where: { id }, // where: { id },
@@ -72,7 +63,4 @@ export {
getAccessLog, getAccessLog,
listAccessLogs, listAccessLogs,
createAccessLog, createAccessLog,
getAccessLogById,
//
helloworld,
}; };

View File

@@ -6,14 +6,11 @@
// RULES: // RULES:
// - Follows same pattern as helloworld.service.ts // - Follows same pattern as helloworld.service.ts
// //
import type { Event } from '@prisma/client';
import prisma from '../lib/prisma';
type CreateEvent = { type CreateEvent = {
eventDate: Date; eventDate: DateTime;
title: string; title: string;
joinMembers?: JSON[]; joinMembers?: Json[];
price: number; price: number;
currency: string; currency: string;
duration_m: number; duration_m: number;
@@ -25,9 +22,9 @@ type CreateEvent = {
}; };
type UpdateEvent = { type UpdateEvent = {
eventDate?: Date; eventDate?: DateTime;
title?: string; title?: string;
joinMembers?: JSON[]; joinMembers?: Json[];
price?: number; price?: number;
currency?: string; currency?: string;
duration_m?: number; duration_m?: number;
@@ -38,9 +35,9 @@ type UpdateEvent = {
memberId?: number; memberId?: number;
}; };
async function listEvents(): Promise<Event[]> { // async function listEvents(): Promise<Event[]> {
return prisma.event.findMany(); // return prisma.event.findMany();
} // }
// async function getEvent(eventId: number) { // async function getEvent(eventId: number) {
// return prisma.event.findFirst({ where: { id: eventId } }); // return prisma.event.findFirst({ where: { id: eventId } });

View File

@@ -12,9 +12,9 @@ import type { EventItem } from '@prisma/client';
import prisma from '../lib/prisma'; import prisma from '../lib/prisma';
type CreateEvent = { type CreateEvent = {
eventDate: Date; eventDate: DateTime;
title: string; title: string;
joinMembers?: JSON[]; joinMembers?: Json[];
price: number; price: number;
currency: string; currency: string;
duration_m: number; duration_m: number;
@@ -26,9 +26,9 @@ type CreateEvent = {
}; };
type UpdateEvent = { type UpdateEvent = {
eventDate?: Date; eventDate?: DateTime;
title?: string; title?: string;
joinMembers?: JSON[]; joinMembers?: Json[];
price?: number; price?: number;
currency?: string; currency?: string;
duration_m?: number; duration_m?: number;

View File

@@ -11,24 +11,9 @@ import type { OrderItem } from '@prisma/client';
import prisma from '../lib/prisma'; import prisma from '../lib/prisma';
type CreateOrderItem = { type CreateOrderItem = {
// orderNumber?: string; orderNumber?: string;
// status?: string; // status?: string;
// eventIds?: number[]; // eventIds?: number[];
taxes: number;
status: string;
shipping: number;
discount: number;
subtotal: number;
orderNumber: string;
totalAmount: number;
totalQuantity: number;
history: Record<string, any>;
payment: Record<string, any>;
customer: Record<string, any>;
delivery: Record<string, any>;
items: Record<string, any>[];
shippingAddress: Record<string, any>;
}; };
type UpdateOrderItem = { type UpdateOrderItem = {

View File

@@ -1,92 +0,0 @@
// src/app/services/party-event.service.ts
//
// PURPOSE:
// - Service for handling EventItem (PartyEvent) Record
//
import type { EventItem } from '@prisma/client';
import prisma from '../lib/prisma';
type CreateEvent = {
name: string;
title: string;
eventDate: Date;
location: string;
duration_m: number;
ageBottom?: number;
ageTop?: number;
currency?: string;
price?: number;
priceSale?: number;
coverUrl?: string;
images?: string[];
description?: string;
subDescription?: string;
publish?: string;
category?: string;
tags?: string[];
joinMembers?: any[];
};
type UpdateEvent = {
name?: string;
title?: string;
eventDate?: Date;
location?: string;
duration_m?: number;
ageBottom?: number;
ageTop?: number;
currency?: string;
price?: number;
priceSale?: number;
coverUrl?: string;
images?: string[];
description?: string;
subDescription?: string;
publish?: string;
category?: string;
tags?: string[];
joinMembers?: any[];
};
async function listEvents(): Promise<EventItem[]> {
return prisma.eventItem.findMany({
include: { reviews: true },
});
}
async function getEvent(eventId: string): Promise<EventItem | null> {
return prisma.eventItem.findUnique({
where: { id: eventId },
include: { reviews: true },
});
}
async function getEventByNameOrTitle(searchText: string): Promise<EventItem[] | null> {
return prisma.eventItem.findMany({
where: {
OR: [{ name: { contains: searchText, mode: 'insensitive' } }, { title: { contains: searchText, mode: 'insensitive' } }],
},
include: { reviews: true },
});
}
async function createEvent(eventData: any) {
return await prisma.eventItem.create({ data: eventData });
}
async function updateEvent(eventId: string, updateForm: UpdateEvent) {
return prisma.eventItem.update({
where: { id: eventId },
data: updateForm,
});
}
async function deleteEvent(eventId: string) {
return prisma.eventItem.delete({
where: { id: eventId },
});
}
export { getEvent, listEvents, createEvent, updateEvent, deleteEvent, getEventByNameOrTitle, type CreateEvent, type UpdateEvent };

View File

@@ -1,7 +1,5 @@
// src/app/services/product.service.ts // src/app/services/product.service.ts
// //
// REQ0182 frontend product details
//
// PURPOSE: // PURPOSE:
// - Service for handling ProductItem Record // - Service for handling ProductItem Record
// //
@@ -67,29 +65,39 @@ type UpdateProduct = {
}; };
async function listProducts(): Promise<ProductItem[]> { async function listProducts(): Promise<ProductItem[]> {
return prisma.productItem.findMany({ return prisma.productItem.findMany();
include: { reviews: true },
});
} }
async function getProduct(productId: string): Promise<ProductItem | null> { async function getProduct(productId: string): Promise<ProductItem | null> {
return prisma.productItem.findUnique({ return prisma.productItem.findUnique({ where: { id: productId } });
where: { id: productId },
include: { reviews: true },
//
});
} }
async function getProductBySkuOrName(searchText: string): Promise<ProductItem[] | null> { async function createProduct(createForm: CreateProduct) {
return prisma.productItem.findMany({ // return prisma.productItem.create({
where: { OR: [{ sku: { contains: searchText, mode: 'insensitive' } }, { name: { contains: searchText, mode: 'insensitive' } }] }, // data: {
include: { reviews: true }, // ...createForm,
// // code: createForm.code || '',
}); // taxes: createForm.taxes || 0,
} // tags: createForm.tags || [],
// sizes: createForm.sizes || [],
async function createProduct(productData: any) { // gender: createForm.gender || [],
return await prisma.productItem.create({ data: productData }); // 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) { async function updateProduct(productId: string, updateForm: UpdateProduct) {
@@ -103,4 +111,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, getProductBySkuOrName, type CreateProduct, type UpdateProduct }; export { getProduct, listProducts, createProduct, updateProduct, deleteProduct, type CreateProduct, type UpdateProduct };

View File

@@ -38,7 +38,7 @@ async function getUserItem(userId: string): Promise<UserItem | null> {
return prisma.userItem.findFirst({ where: { id: userId } }); return prisma.userItem.findFirst({ where: { id: userId } });
} }
async function updateUser(userId: string, updateForm: UpdateUser): Promise<UserItem> { async function updateUser(userId: string, updateForm: UpdateUser): Promise<User> {
return prisma.userItem.update({ return prisma.userItem.update({
where: { id: userId }, where: { id: userId },
data: updateForm, data: updateForm,
@@ -82,7 +82,7 @@ async function changeToUser(userIdToPromote: string, userIdOfApplicant: string)
return promoteResult; return promoteResult;
} }
async function getUserById(id: string): Promise<UserItem | null> { async function getUserById1(id: string): Promise<UserItem | null> {
return prisma.userItem.findFirst({ where: { id } }); return prisma.userItem.findFirst({ where: { id } });
} }

View File

@@ -1,9 +1,7 @@
const isDev = process.env.NODE_ENV === 'development';
const L_ERROR = 0; const L_ERROR = 0;
const L_WARN = 1; const L_WARN = 1;
const L_INFO = 2; const L_INFO = 2;
const L_DEBUG = 3; const L_DEBUG = 3;
const L_TRACE = 4; const L_TRACE = 4;
export { L_WARN, L_INFO, L_ERROR, L_DEBUG, L_TRACE, isDev }; export { L_WARN, L_INFO, L_ERROR, L_DEBUG, L_TRACE };

View File

@@ -13,7 +13,8 @@ type ConfigType = {
export const CONFIG: ConfigType = { export const CONFIG: ConfigType = {
appVersion: packageJson.version, appVersion: packageJson.version,
basePath: process.env.NODE_ENV === 'production' ? process.env.PRODUCTION_API : process.env.DEV_API, basePath:
process.env.NODE_ENV === 'production' ? process.env.PRODUCTION_API : process.env.DEV_API,
cors: { cors: {
/** /**
* [] = allow all origins * [] = allow all origins

View File

@@ -2,6 +2,7 @@ import bcrypt from 'bcrypt';
const generateHash = async (password: string) => bcrypt.hash(password, await bcrypt.genSalt(10)); const generateHash = async (password: string) => bcrypt.hash(password, await bcrypt.genSalt(10));
const validatePassword = async (password: string, hash: string) => bcrypt.compare(password, hash as string); const validatePassword = async (password: string, hash: string) =>
bcrypt.compare(password, hash as string);
export { generateHash, validatePassword }; export { generateHash, validatePassword };

View File

@@ -40,7 +40,11 @@ export function logger(label: string, value: unknown, breakLine: boolean = false
if (value === null || value === undefined) { if (value === null || value === undefined) {
formattedValue = String(value); formattedValue = String(value);
} else if (type === 'object') { } else if (type === 'object') {
formattedValue = JSON.stringify(value, null, breakLine || JSON.stringify(value).length > 50 ? 2 : 0); formattedValue = JSON.stringify(
value,
null,
breakLine || JSON.stringify(value).length > 50 ? 2 : 0
);
} else { } else {
formattedValue = String(value); formattedValue = String(value);
} }

View File

@@ -15,8 +15,10 @@ export function setDate(now: Date, options: { days?: number; hours?: number; min
return new Date(`${year}-${month}-${days ?? today} ${hours}:${minutes}`).toJSON(); return new Date(`${year}-${month}-${days ?? today} ${hours}:${minutes}`).toJSON();
} }
export const subHours = (value: number, option: 'years' | 'months' | 'days' | 'hours' | 'minutes' | 'seconds' | 'milliseconds') => export const subHours = (
dayjs().subtract(value, option).format(); value: number,
option: 'years' | 'months' | 'days' | 'hours' | 'minutes' | 'seconds' | 'milliseconds'
) => dayjs().subtract(value, option).format();
// years, // years,
// months, // months,
@@ -36,7 +38,15 @@ export type DurationProps = {
milliseconds?: number; milliseconds?: number;
}; };
export function fSub({ years = 0, months = 0, days = 0, hours = 0, minutes = 0, seconds = 0, milliseconds = 0 }: DurationProps) { export function fSub({
years = 0,
months = 0,
days = 0,
hours = 0,
minutes = 0,
seconds = 0,
milliseconds = 0,
}: DurationProps) {
const result = dayjs() const result = dayjs()
.subtract( .subtract(
dayjs.duration({ dayjs.duration({
@@ -54,7 +64,15 @@ export function fSub({ years = 0, months = 0, days = 0, hours = 0, minutes = 0,
return result; return result;
} }
export function fAdd({ years = 0, months = 0, days = 0, hours = 0, minutes = 0, seconds = 0, milliseconds = 0 }: DurationProps) { export function fAdd({
years = 0,
months = 0,
days = 0,
hours = 0,
minutes = 0,
seconds = 0,
milliseconds = 0,
}: DurationProps) {
const result = dayjs() const result = dayjs()
.add( .add(
dayjs.duration({ dayjs.duration({

View File

@@ -34,16 +34,16 @@
"node_modules", "node_modules",
".next", ".next",
// //
"**/* copy *.*", "**/* copy *.tsx",
"**/* copy.*", "**/* copy.tsx",
"**/*.bak",
"**/*.bak", "**/*.bak",
"**/*.bug", "**/*.bug",
"**/*.del", "**/*.del",
"**/*.draft", "**/*.draft",
"**/*.log", "**/*.log",
"**/*.tmp", "**/*.tmp",
"**/*del", "**/*del"
"prisma/*"
], ],
"include": [ "include": [
"next-env.d.ts", "next-env.d.ts",

View File

@@ -770,13 +770,6 @@
dependencies: dependencies:
tslib "^2.4.0" tslib "^2.4.0"
"@types/bcrypt@^5.0.2":
version "5.0.2"
resolved "https://registry.yarnpkg.com/@types/bcrypt/-/bcrypt-5.0.2.tgz#22fddc11945ea4fbc3655b3e8b8847cc9f811477"
integrity sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ==
dependencies:
"@types/node" "*"
"@types/estree@^1.0.6": "@types/estree@^1.0.6":
version "1.0.7" version "1.0.7"
resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz" resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz"
@@ -797,13 +790,6 @@
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.17.tgz#fb85a04f47e9e4da888384feead0de05f7070355" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.17.tgz#fb85a04f47e9e4da888384feead0de05f7070355"
integrity sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ== integrity sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==
"@types/node@*":
version "24.0.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-24.0.1.tgz#e9bfcb1c35547437c294403b7bec497772a88b0a"
integrity sha512-MX4Zioh39chHlDJbKmEgydJDS3tspMP/lnQC67G3SWsTnb9NeYVWOjkxpOSy4oMfPs4StcWHwBrvUb4ybfnuaw==
dependencies:
undici-types "~7.8.0"
"@types/node@^22.13.13": "@types/node@^22.13.13":
version "22.13.13" version "22.13.13"
resolved "https://registry.npmjs.org/@types/node/-/node-22.13.13.tgz" resolved "https://registry.npmjs.org/@types/node/-/node-22.13.13.tgz"
@@ -1021,7 +1007,7 @@ ansi-regex@^5.0.1:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
ansi-styles@^4.0.0, ansi-styles@^4.1.0: ansi-styles@^4.1.0:
version "4.3.0" version "4.3.0"
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
@@ -1239,7 +1225,7 @@ caniuse-lite@^1.0.30001579:
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001707.tgz" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001707.tgz"
integrity sha512-3qtRjw/HQSMlDWf+X79N206fepf4SOOU6SQLMaq/0KkZLmSjPxAkBOQQ+FxbHKfHmYLZFfdWsO3KA90ceHPSnw== integrity sha512-3qtRjw/HQSMlDWf+X79N206fepf4SOOU6SQLMaq/0KkZLmSjPxAkBOQQ+FxbHKfHmYLZFfdWsO3KA90ceHPSnw==
chalk@^4.0.0, chalk@^4.1.2: chalk@^4.0.0:
version "4.1.2" version "4.1.2"
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@@ -1257,15 +1243,6 @@ client-only@0.0.1:
resolved "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz" resolved "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz"
integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==
cliui@^8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
dependencies:
string-width "^4.2.0"
strip-ansi "^6.0.1"
wrap-ansi "^7.0.0"
clsx@^2.1.1: clsx@^2.1.1:
version "2.1.1" version "2.1.1"
resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz" resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz"
@@ -1293,19 +1270,6 @@ concat-map@0.0.1:
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
concurrently@^9.1.2:
version "9.1.2"
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-9.1.2.tgz#22d9109296961eaee773e12bfb1ce9a66bc9836c"
integrity sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==
dependencies:
chalk "^4.1.2"
lodash "^4.17.21"
rxjs "^7.8.1"
shell-quote "^1.8.1"
supports-color "^8.1.1"
tree-kill "^1.2.2"
yargs "^17.7.2"
console-control-strings@^1.0.0, console-control-strings@^1.1.0: console-control-strings@^1.0.0, console-control-strings@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
@@ -1636,11 +1600,6 @@ esbuild@~0.25.0:
"@esbuild/win32-ia32" "0.25.5" "@esbuild/win32-ia32" "0.25.5"
"@esbuild/win32-x64" "0.25.5" "@esbuild/win32-x64" "0.25.5"
escalade@^3.1.1:
version "3.2.0"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5"
integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==
escape-string-regexp@^4.0.0: escape-string-regexp@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz"
@@ -1972,11 +1931,6 @@ gauge@^3.0.0:
strip-ansi "^6.0.1" strip-ansi "^6.0.1"
wide-align "^1.1.2" wide-align "^1.1.2"
get-caller-file@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.2.7, get-intrinsic@^1.3.0: get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.2.7, get-intrinsic@^1.3.0:
version "1.3.0" version "1.3.0"
resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz" resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz"
@@ -3017,11 +2971,6 @@ regexp.prototype.flags@^1.5.3:
gopd "^1.2.0" gopd "^1.2.0"
set-function-name "^2.0.2" set-function-name "^2.0.2"
require-directory@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
resolve-from@^4.0.0: resolve-from@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz"
@@ -3086,13 +3035,6 @@ run-parallel@^1.1.9:
dependencies: dependencies:
queue-microtask "^1.2.2" queue-microtask "^1.2.2"
rxjs@^7.8.1:
version "7.8.2"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.2.tgz#955bc473ed8af11a002a2be52071bf475638607b"
integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==
dependencies:
tslib "^2.1.0"
safe-array-concat@^1.1.3: safe-array-concat@^1.1.3:
version "1.1.3" version "1.1.3"
resolved "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz" resolved "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz"
@@ -3196,11 +3138,6 @@ shebang-regex@^3.0.0:
resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
shell-quote@^1.8.1:
version "1.8.3"
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.3.tgz#55e40ef33cf5c689902353a3d8cd1a6725f08b4b"
integrity sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==
side-channel-list@^1.0.0: side-channel-list@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz" resolved "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz"
@@ -3271,7 +3208,7 @@ streamsearch@^1.1.0:
resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz" resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz"
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.2.3:
version "4.2.3" version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -3346,7 +3283,7 @@ string_decoder@^1.1.1:
dependencies: dependencies:
safe-buffer "~5.2.0" safe-buffer "~5.2.0"
strip-ansi@^6.0.0, strip-ansi@^6.0.1: strip-ansi@^6.0.1:
version "6.0.1" version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -3382,13 +3319,6 @@ supports-color@^7.1.0:
dependencies: dependencies:
has-flag "^4.0.0" has-flag "^4.0.0"
supports-color@^8.1.1:
version "8.1.1"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
dependencies:
has-flag "^4.0.0"
supports-preserve-symlinks-flag@^1.0.0: supports-preserve-symlinks-flag@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz"
@@ -3426,11 +3356,6 @@ tr46@~0.0.3:
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
tree-kill@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
ts-api-utils@^2.0.1: ts-api-utils@^2.0.1:
version "2.1.0" version "2.1.0"
resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz" resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz"
@@ -3465,7 +3390,7 @@ tsconfig-paths@^3.15.0:
minimist "^1.2.6" minimist "^1.2.6"
strip-bom "^3.0.0" strip-bom "^3.0.0"
tslib@^2.1.0, tslib@^2.4.0: tslib@^2.4.0:
version "2.8.1" version "2.8.1"
resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
@@ -3561,11 +3486,6 @@ undici-types@~6.20.0:
resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz" resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz"
integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==
undici-types@~7.8.0:
version "7.8.0"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.8.0.tgz#de00b85b710c54122e44fbfd911f8d70174cd294"
integrity sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==
unique-names-generator@^4.7.1: unique-names-generator@^4.7.1:
version "4.7.1" version "4.7.1"
resolved "https://registry.yarnpkg.com/unique-names-generator/-/unique-names-generator-4.7.1.tgz#966407b12ba97f618928f77322cfac8c80df5597" resolved "https://registry.yarnpkg.com/unique-names-generator/-/unique-names-generator-4.7.1.tgz#966407b12ba97f618928f77322cfac8c80df5597"
@@ -3673,15 +3593,6 @@ word-wrap@^1.2.5:
resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz"
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrappy@1: wrappy@1:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
@@ -3692,11 +3603,6 @@ xtend@^4.0.0:
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
y18n@^5.0.5:
version "5.0.8"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
yallist@^4.0.0: yallist@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
@@ -3707,24 +3613,6 @@ yaml@^1.10.0:
resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
yargs-parser@^21.1.1:
version "21.1.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
yargs@^17.7.2:
version "17.7.2"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
dependencies:
cliui "^8.0.1"
escalade "^3.1.1"
get-caller-file "^2.0.5"
require-directory "^2.1.1"
string-width "^4.2.3"
y18n "^5.0.5"
yargs-parser "^21.1.1"
yn@3.1.1: yn@3.1.1:
version "3.1.1" version "3.1.1"
resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz"

View File

@@ -1,23 +1,14 @@
#
# REQ0180 service port schedule
#
services: services:
frontend: frontend:
command: "sleep infinity" command: 'sleep infinity'
ports:
- 8080:8080
mobile: mobile:
command: "sleep infinity" command: 'sleep infinity'
ports:
- 8081:3000
cms_backend: cms_backend:
command: "sleep infinity" command: 'sleep infinity'
ports:
- 7272:7272
- 5555:5555
postgres: postgres:
# container_name: postgres
ports: ports:
- 5432:5432 - '5432:5432'

View File

@@ -1,6 +1,3 @@
#
# REQ0180 service port schedule
#
volumes: volumes:
db: db:
driver: local driver: local
@@ -14,8 +11,8 @@ services:
- 10001:8080 - 10001:8080
volumes: volumes:
- ../frontend:/app - ../frontend:/app
working_dir: "/app" working_dir: '/app'
command: "./scripts/20_prod.sh" command: './dev.sh'
mobile: mobile:
image: 192.168.10.61:5000/hksingleparty_mobile image: 192.168.10.61:5000/hksingleparty_mobile
@@ -25,8 +22,8 @@ services:
- 10004:3000 - 10004:3000
volumes: volumes:
- ../mobile:/app - ../mobile:/app
working_dir: "/app" working_dir: '/app'
command: "./scripts/20_prod.sh" command: './dev.sh'
cms_backend: cms_backend:
image: 192.168.10.61:5000/demo_minimal_kit_backend image: 192.168.10.61:5000/demo_minimal_kit_backend
@@ -39,8 +36,8 @@ services:
- 10003:5555 - 10003:5555
volumes: volumes:
- ../cms_backend:/app - ../cms_backend:/app
working_dir: "/app" working_dir: '/app'
command: "./scripts/20_prod.sh" command: './dev.sh'
postgres: postgres:
image: postgres:14.1-alpine image: postgres:14.1-alpine
@@ -48,6 +45,6 @@ services:
env_file: env_file:
- .env - .env
expose: expose:
- "5432" - '5432'
volumes: volumes:
- db:/var/lib/postgresql/data - db:/var/lib/postgresql/data

View File

@@ -1,7 +1,3 @@
**/*del
**/*bak
**/*copy*
# Logs # Logs
logs logs
*.log *.log

View File

@@ -2,9 +2,8 @@
yarn --dev yarn --dev
clear
while true; do while true; do
# yarn tsc:print # yarn tsc:print
yarn lint:print yarn lint:print

View File

@@ -92,8 +92,6 @@ const sortImportsRules = () => {
}; };
return { return {
'perfectionist/sort-named-imports': [1, { type: 'line-length', order: 'asc' }],
'perfectionist/sort-named-exports': [1, { type: 'line-length', order: 'asc' }],
'perfectionist/sort-exports': [ 'perfectionist/sort-exports': [
1, 1,
{ {
@@ -102,6 +100,8 @@ const sortImportsRules = () => {
groupKind: 'values-first', groupKind: 'values-first',
}, },
], ],
'perfectionist/sort-named-imports': [1, { type: 'line-length', order: 'asc' }],
'perfectionist/sort-named-exports': [1, { type: 'line-length', order: 'asc' }],
'perfectionist/sort-imports': [ 'perfectionist/sort-imports': [
2, 2,
{ {

View File

@@ -6,7 +6,6 @@
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev:check": "yarn tsc:w",
"dev": "vite", "dev": "vite",
"start": "vite preview", "start": "vite preview",
"build": "tsc && vite build", "build": "tsc && vite build",
@@ -22,10 +21,8 @@
"re:build": "yarn clean && yarn install && yarn build", "re:build": "yarn clean && yarn install && yarn build",
"re:build-npm": "npm run clean && npm install && npm run build", "re:build-npm": "npm run clean && npm install && npm run build",
"tsc:dev": "yarn dev & yarn tsc:watch", "tsc:dev": "yarn dev & yarn tsc:watch",
"tsc:print": "npx tsc --showConfig",
"tsc:w": "npx nodemon --delay 3 --ext ts,tsx --exec \"yarn tsc\"",
"tsc:watch": "tsc --noEmit --watch", "tsc:watch": "tsc --noEmit --watch",
"tsc": "tsc --noEmit" "tsc:print": "npx tsc --showConfig"
}, },
"engines": { "engines": {
"node": ">=20" "node": ">=20"
@@ -46,7 +43,6 @@
"@fontsource-variable/noto-sans-sc": "^5.2.5", "@fontsource-variable/noto-sans-sc": "^5.2.5",
"@fontsource-variable/noto-sans-tc": "^5.2.5", "@fontsource-variable/noto-sans-tc": "^5.2.5",
"@fontsource-variable/nunito-sans": "^5.2.5", "@fontsource-variable/nunito-sans": "^5.2.5",
"@fontsource-variable/public-sans": "^5.2.5",
"@fontsource/barlow": "^5.2.5", "@fontsource/barlow": "^5.2.5",
"@fullcalendar/core": "^6.1.15", "@fullcalendar/core": "^6.1.15",
"@fullcalendar/daygrid": "^6.1.15", "@fullcalendar/daygrid": "^6.1.15",
@@ -56,7 +52,7 @@
"@fullcalendar/timegrid": "^6.1.15", "@fullcalendar/timegrid": "^6.1.15",
"@fullcalendar/timeline": "^6.1.15", "@fullcalendar/timeline": "^6.1.15",
"@hookform/resolvers": "^4.1.3", "@hookform/resolvers": "^4.1.3",
"@ianvs/prettier-plugin-sort-imports": "^4.4.2", "@ianvs/prettier-plugin-sort-imports": "^4.4.1",
"@iconify/react": "^5.2.0", "@iconify/react": "^5.2.0",
"@mui/lab": "^7.0.0-beta.10", "@mui/lab": "^7.0.0-beta.10",
"@mui/material": "^7.0.1", "@mui/material": "^7.0.1",

View File

@@ -12,7 +12,7 @@ const config = {
trailingComma: 'es5', trailingComma: 'es5',
plugins: [ plugins: [
// //
'@ianvs/prettier-plugin-sort-imports', // '@ianvs/prettier-plugin-sort-imports',
], ],
}; };

View File

@@ -1,15 +0,0 @@
#!/usr/bin/env bash
set -x
rm -rf ./**/*Zone.Identifier
set -ex
yarn fm:fix
yarn tsc
yarn build
echo "done"

Some files were not shown because too many files have changed in this diff Show More