updated select response

This commit is contained in:
Berkay 2025-07-31 22:37:40 +03:00
parent 924b538559
commit b54bbe2db2
16 changed files with 1715 additions and 741 deletions

View File

@ -20,6 +20,9 @@ ENV NODE_ENV=production
COPY --from=builder /usr/src/app/dist ./dist COPY --from=builder /usr/src/app/dist ./dist
COPY --from=builder /usr/src/app/node_modules ./node_modules COPY --from=builder /usr/src/app/node_modules ./node_modules
COPY --from=builder /usr/src/app/package.json ./package.json
RUN npm prune --production
USER node USER node

File diff suppressed because it is too large Load Diff

View File

@ -46,7 +46,7 @@
"@swc/core": "^1.10.7", "@swc/core": "^1.10.7",
"@types/express": "^5.0.0", "@types/express": "^5.0.0",
"@types/jest": "^29.5.14", "@types/jest": "^29.5.14",
"@types/node": "^22.16.5", "@types/node": "^22.17.0",
"@types/supertest": "^6.0.2", "@types/supertest": "^6.0.2",
"eslint": "^9.18.0", "eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.1", "eslint-config-prettier": "^10.0.1",

View File

@ -11,7 +11,7 @@ export class LoginService {
private readonly redis: RedisHandlers, private readonly redis: RedisHandlers,
private readonly passHandlers: PasswordHandlers, private readonly passHandlers: PasswordHandlers,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) {} ) { }
async run(dto: userLoginValidator) { async run(dto: userLoginValidator) {
const foundUser = await this.prisma.users.findFirstOrThrow({ const foundUser = await this.prisma.users.findFirstOrThrow({
@ -137,14 +137,16 @@ export class LoginService {
}); });
selectList = employees; selectList = employees;
} }
let fullName = `${foundPerson.firstname}`;
if (foundPerson.middle_name) fullName += ` ${foundPerson.middle_name}`;
if (foundPerson.birthname) fullName += ` ${foundPerson.birthname}`;
fullName += ` ${foundPerson.surname}`;
const redisData = AuthTokenSchema.parse({ const redisData = AuthTokenSchema.parse({
people: foundPerson, people: foundPerson,
users: foundUser, users: foundUser,
credentials: { credentials: {
person_uu_id: foundPerson.uu_id, uuid: foundPerson.uu_id,
person_name: foundPerson.firstname, fullName: fullName,
person_full_name: `${foundPerson.firstname} ${foundPerson.middle_name || ''} | ${foundPerson.birthname || ''} | ${foundPerson.surname}`,
}, },
selectionList: { selectionList: {
type: foundUser.user_type, type: foundUser.user_type,

View File

@ -19,7 +19,7 @@ export class SelectService {
constructor( constructor(
private readonly redis: RedisHandlers, private readonly redis: RedisHandlers,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) {} ) { }
async run(dto: userSelectValidator, req: Request) { async run(dto: userSelectValidator, req: Request) {
const accessObject = await this.redis.getLoginFromRedis(req); const accessObject = await this.redis.getLoginFromRedis(req);
if (!accessObject) { if (!accessObject) {
@ -196,8 +196,6 @@ export class SelectService {
company: company, company: company,
menu: null, menu: null,
pages: null, pages: null,
config: null,
caches: null,
selection: await this.prisma.build_living_space.findFirstOrThrow({ selection: await this.prisma.build_living_space.findFirstOrThrow({
where: { uu_id: dto.uuid }, where: { uu_id: dto.uuid },
select: { select: {

View File

@ -9,9 +9,8 @@ export type UserType = (typeof UserType)[keyof typeof UserType];
// Credentials // Credentials
export const CredentialsSchema = z.object({ export const CredentialsSchema = z.object({
person_uu_id: z.string(), uuid: z.string(),
person_name: z.string(), fullName: z.string(),
full_name: z.string(),
}); });
export type Credentials = z.infer<typeof CredentialsSchema>; export type Credentials = z.infer<typeof CredentialsSchema>;

View File

@ -25,7 +25,7 @@ export class RedisHandlers {
constructor( constructor(
private readonly cacheService: CacheService, private readonly cacheService: CacheService,
private readonly passwordService: PasswordHandlers, private readonly passwordService: PasswordHandlers,
) {} ) { }
/** /**
* Validates that a Redis key follows the expected format * Validates that a Redis key follows the expected format
@ -125,7 +125,7 @@ export class RedisHandlers {
if (parts[1] === parts[2]) { if (parts[1] === parts[2]) {
const value = await this.cacheService.get(key); const value = await this.cacheService.get(key);
if (value) { if (value) {
return { key, value }; return { key: value.key, value: value.value };
} }
} }
} }

View File

@ -10,6 +10,7 @@
"dependencies": { "dependencies": {
"clsx": "^2.1.1", "clsx": "^2.1.1",
"cookies-next": "^6.1.0", "cookies-next": "^6.1.0",
"glob": "^11.0.3",
"ioredis": "^5.6.1", "ioredis": "^5.6.1",
"lucide-react": "^0.533.0", "lucide-react": "^0.533.0",
"next": "15.4.4", "next": "15.4.4",
@ -550,6 +551,41 @@
"integrity": "sha512-M/T6Zewn7sDaBQEqIZ8Rb+i9y8qfGmq+5SDFSf9sA2lUZTmdDLVdOiQaeDp+Q4wElZ9HG1GAX5KhDaidp6LQsQ==", "integrity": "sha512-M/T6Zewn7sDaBQEqIZ8Rb+i9y8qfGmq+5SDFSf9sA2lUZTmdDLVdOiQaeDp+Q4wElZ9HG1GAX5KhDaidp6LQsQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@isaacs/balanced-match": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
"integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
"engines": {
"node": "20 || >=22"
}
},
"node_modules/@isaacs/brace-expansion": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz",
"integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==",
"dependencies": {
"@isaacs/balanced-match": "^4.0.1"
},
"engines": {
"node": "20 || >=22"
}
},
"node_modules/@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
"dependencies": {
"string-width": "^5.1.2",
"string-width-cjs": "npm:string-width@^4.2.0",
"strip-ansi": "^7.0.1",
"strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
"wrap-ansi": "^8.1.0",
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@isaacs/fs-minipass": { "node_modules/@isaacs/fs-minipass": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
@ -1057,6 +1093,28 @@
"@types/react": "^19.0.0" "@types/react": "^19.0.0"
} }
}, },
"node_modules/ansi-regex": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
}
},
"node_modules/ansi-styles": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001727", "version": "1.0.30001727",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz",
@ -1130,7 +1188,6 @@
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"license": "MIT", "license": "MIT",
"optional": true,
"dependencies": { "dependencies": {
"color-name": "~1.1.4" "color-name": "~1.1.4"
}, },
@ -1142,8 +1199,7 @@
"version": "1.1.4", "version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT", "license": "MIT"
"optional": true
}, },
"node_modules/color-string": { "node_modules/color-string": {
"version": "1.9.1", "version": "1.9.1",
@ -1178,6 +1234,19 @@
"react": ">= 16.8.0" "react": ">= 16.8.0"
} }
}, },
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/csstype": { "node_modules/csstype": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@ -1237,6 +1306,16 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
},
"node_modules/emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
},
"node_modules/enhanced-resolve": { "node_modules/enhanced-resolve": {
"version": "5.18.2", "version": "5.18.2",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz",
@ -1251,6 +1330,43 @@
"node": ">=10.13.0" "node": ">=10.13.0"
} }
}, },
"node_modules/foreground-child": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
"integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
"dependencies": {
"cross-spawn": "^7.0.6",
"signal-exit": "^4.0.1"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/glob": {
"version": "11.0.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz",
"integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==",
"dependencies": {
"foreground-child": "^3.3.1",
"jackspeak": "^4.1.1",
"minimatch": "^10.0.3",
"minipass": "^7.1.2",
"package-json-from-dist": "^1.0.0",
"path-scurry": "^2.0.0"
},
"bin": {
"glob": "dist/esm/bin.mjs"
},
"engines": {
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/graceful-fs": { "node_modules/graceful-fs": {
"version": "4.2.11", "version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
@ -1301,6 +1417,33 @@
"license": "MIT", "license": "MIT",
"optional": true "optional": true
}, },
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"engines": {
"node": ">=8"
}
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
},
"node_modules/jackspeak": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz",
"integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==",
"dependencies": {
"@isaacs/cliui": "^8.0.2"
},
"engines": {
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/jiti": { "node_modules/jiti": {
"version": "2.5.1", "version": "2.5.1",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz",
@ -1562,6 +1705,14 @@
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/lru-cache": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz",
"integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==",
"engines": {
"node": "20 || >=22"
}
},
"node_modules/lucide-react": { "node_modules/lucide-react": {
"version": "0.533.0", "version": "0.533.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.533.0.tgz", "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.533.0.tgz",
@ -1581,11 +1732,24 @@
"@jridgewell/sourcemap-codec": "^1.5.0" "@jridgewell/sourcemap-codec": "^1.5.0"
} }
}, },
"node_modules/minimatch": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz",
"integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==",
"dependencies": {
"@isaacs/brace-expansion": "^5.0.0"
},
"engines": {
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/minipass": { "node_modules/minipass": {
"version": "7.1.2", "version": "7.1.2",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
"dev": true,
"license": "ISC", "license": "ISC",
"engines": { "engines": {
"node": ">=16 || 14 >=14.17" "node": ">=16 || 14 >=14.17"
@ -1766,6 +1930,34 @@
"node": "^10 || ^12 || >=14" "node": "^10 || ^12 || >=14"
} }
}, },
"node_modules/package-json-from-dist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="
},
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"engines": {
"node": ">=8"
}
},
"node_modules/path-scurry": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz",
"integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==",
"dependencies": {
"lru-cache": "^11.0.0",
"minipass": "^7.1.2"
},
"engines": {
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/picocolors": { "node_modules/picocolors": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@ -1905,6 +2097,36 @@
"@img/sharp-win32-x64": "0.34.3" "@img/sharp-win32-x64": "0.34.3"
} }
}, },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dependencies": {
"shebang-regex": "^3.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"engines": {
"node": ">=8"
}
},
"node_modules/signal-exit": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/simple-swizzle": { "node_modules/simple-swizzle": {
"version": "0.2.2", "version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
@ -1930,6 +2152,94 @@
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"dependencies": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^9.2.2",
"strip-ansi": "^7.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/string-width-cjs": {
"name": "string-width",
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/string-width-cjs/node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/string-width-cjs/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"node_modules/string-width-cjs/node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-ansi": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"dependencies": {
"ansi-regex": "^6.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
"node_modules/strip-ansi-cjs": {
"name": "strip-ansi",
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/styled-jsx": { "node_modules/styled-jsx": {
"version": "5.1.6", "version": "5.1.6",
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz",
@ -2029,6 +2339,104 @@
"react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0"
} }
}, },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dependencies": {
"isexe": "^2.0.0"
},
"bin": {
"node-which": "bin/node-which"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/wrap-ansi": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"dependencies": {
"ansi-styles": "^6.1.0",
"string-width": "^5.0.1",
"strip-ansi": "^7.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/wrap-ansi-cjs": {
"name": "wrap-ansi",
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"node_modules/wrap-ansi-cjs/node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/yallist": { "node_modules/yallist": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",

View File

@ -11,6 +11,7 @@
"dependencies": { "dependencies": {
"clsx": "^2.1.1", "clsx": "^2.1.1",
"cookies-next": "^6.1.0", "cookies-next": "^6.1.0",
"glob": "^11.0.3",
"ioredis": "^5.6.1", "ioredis": "^5.6.1",
"lucide-react": "^0.533.0", "lucide-react": "^0.533.0",
"next": "15.4.4", "next": "15.4.4",

View File

@ -1,17 +1,17 @@
'use client'; 'use client';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import { useRouter } from 'next/navigation'; import { useRouter } from '@/i18n/navigation';
import { apiGetFetcher } from '@/lib/fetcher'; import { apiGetFetcher } from '@/lib/fetcher';
export default function PageSelect() { export default function PageSelect() {
const t = useTranslations('Select'); const t = useTranslations('Select');
const router = useRouter(); const router = useRouter();
const [selectionList, setSelectionList] = useState<{ type: string, list: any[] } | null>(null); const [selectionList, setSelectionList] = useState<{ type: string, list: any[] } | null>(null);
const [selectedOption, setSelectedOption] = useState<string | null>(null); const [selectedOption, setSelectedOption] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
const fetchSelectionList = async () => { const fetchSelectionList = async () => {
setIsLoading(true); setIsLoading(true);
try { try {
@ -28,9 +28,9 @@ export default function PageSelect() {
setIsLoading(false); setIsLoading(false);
} }
}; };
fetchSelectionList(); useEffect(() => { fetchSelectionList() }, []);
}, []);
const handleSelection = (id: string) => { setSelectedOption(id) }; const handleSelection = (uuid: string) => { setSelectedOption(uuid) };
const handleContinue = async () => { const handleContinue = async () => {
if (!selectedOption) return; if (!selectedOption) return;
setIsLoading(true); setIsLoading(true);
@ -41,7 +41,7 @@ export default function PageSelect() {
const result = await response.json(); const result = await response.json();
if (response.ok && result.status === 200) { if (response.ok && result.status === 200) {
console.log('Selection successful, redirecting to venue page'); console.log('Selection successful, redirecting to venue page');
router.push('/venue'); if (selectionList?.type === 'employee') { router.push('/office') } else if (selectionList?.type === 'occupant') { router.push('/venue') }
} else { } else {
console.error('Selection failed:', result.message); console.error('Selection failed:', result.message);
alert(`Selection failed: ${result.message || 'Unknown error'}`); alert(`Selection failed: ${result.message || 'Unknown error'}`);
@ -52,6 +52,7 @@ export default function PageSelect() {
} finally { setIsLoading(false) } } finally { setIsLoading(false) }
}; };
if (selectionList) {
return ( return (
<div className="min-h-screen bg-gradient-to-br from-indigo-50 via-white to-cyan-50 p-4 sm:p-6 md:p-8"> <div className="min-h-screen bg-gradient-to-br from-indigo-50 via-white to-cyan-50 p-4 sm:p-6 md:p-8">
<div className="max-w-6xl mx-auto w-full h-full flex flex-col"> <div className="max-w-6xl mx-auto w-full h-full flex flex-col">
@ -279,4 +280,134 @@ export default function PageSelect() {
</div> </div>
</div> </div>
); );
} else {
return (
<>
<div className="min-h-screen bg-gradient-to-br from-indigo-50 via-white to-cyan-50 p-4 sm:p-6 md:p-8">
<div className="max-w-6xl mx-auto w-full h-full flex flex-col">
<div className="text-center mb-8 sm:mb-10 mt-4 sm:mt-6">
<div className="skeleton h-8 w-64 mx-auto mb-2"></div>
<div className="skeleton h-5 w-48 mx-auto"></div>
</div>
<div className="flex-grow flex flex-col">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6 flex-grow">
{/* Skeleton items to match the grid layout */}
<div className="rounded-2xl p-6 shadow-lg border-2 bg-white/90 border-indigo-100">
<div className="flex items-center mb-4">
<div className="skeleton w-12 h-12 rounded-xl mr-4"></div>
<div className="skeleton h-5 w-32"></div>
</div>
<div className="space-y-2">
<div className="flex items-center">
<div className="skeleton h-4 w-16 mr-2"></div>
<div className="skeleton h-4 w-24"></div>
</div>
<div className="pt-2 border-t border-gray-100 mt-2">
<div className="flex items-center mb-1">
<div className="skeleton h-4 w-20 mr-2"></div>
</div>
<div className="ml-6 mt-1 space-y-1">
<div className="flex items-center">
<div className="skeleton h-3 w-12 mr-2"></div>
<div className="skeleton h-3 w-20"></div>
</div>
<div className="flex items-center">
<div className="skeleton h-3 w-12 mr-2"></div>
<div className="skeleton h-3 w-20"></div>
</div>
</div>
</div>
<div className="flex items-center">
<div className="skeleton h-4 w-16 mr-2"></div>
<div className="skeleton h-4 w-32"></div>
</div>
</div>
<div className="mt-4 flex justify-end">
<div className="skeleton w-6 h-6 rounded-full"></div>
</div>
</div>
<div className="rounded-2xl p-6 shadow-lg border-2 bg-white/90 border-indigo-100">
<div className="flex items-center mb-4">
<div className="skeleton w-12 h-12 rounded-xl mr-4"></div>
<div className="skeleton h-5 w-32"></div>
</div>
<div className="space-y-2">
<div className="flex items-center">
<div className="skeleton h-4 w-16 mr-2"></div>
<div className="skeleton h-4 w-24"></div>
</div>
<div className="pt-2 border-t border-gray-100 mt-2">
<div className="flex items-center mb-1">
<div className="skeleton h-4 w-20 mr-2"></div>
</div>
<div className="ml-6 mt-1 space-y-1">
<div className="flex items-center">
<div className="skeleton h-3 w-12 mr-2"></div>
<div className="skeleton h-3 w-20"></div>
</div>
<div className="flex items-center">
<div className="skeleton h-3 w-12 mr-2"></div>
<div className="skeleton h-3 w-20"></div>
</div>
</div>
</div>
<div className="flex items-center">
<div className="skeleton h-4 w-16 mr-2"></div>
<div className="skeleton h-4 w-32"></div>
</div>
</div>
<div className="mt-4 flex justify-end">
<div className="skeleton w-6 h-6 rounded-full"></div>
</div>
</div>
<div className="rounded-2xl p-6 shadow-lg border-2 bg-white/90 border-indigo-100">
<div className="flex items-center mb-4">
<div className="skeleton w-12 h-12 rounded-xl mr-4"></div>
<div className="skeleton h-5 w-32"></div>
</div>
<div className="space-y-2">
<div className="flex items-center">
<div className="skeleton h-4 w-16 mr-2"></div>
<div className="skeleton h-4 w-24"></div>
</div>
<div className="pt-2 border-t border-gray-100 mt-2">
<div className="flex items-center mb-1">
<div className="skeleton h-4 w-20 mr-2"></div>
</div>
<div className="ml-6 mt-1 space-y-1">
<div className="flex items-center">
<div className="skeleton h-3 w-12 mr-2"></div>
<div className="skeleton h-3 w-20"></div>
</div>
<div className="flex items-center">
<div className="skeleton h-3 w-12 mr-2"></div>
<div className="skeleton h-3 w-20"></div>
</div>
</div>
</div>
<div className="flex items-center">
<div className="skeleton h-4 w-16 mr-2"></div>
<div className="skeleton h-4 w-32"></div>
</div>
</div>
<div className="mt-4 flex justify-end">
<div className="skeleton w-6 h-6 rounded-full"></div>
</div>
</div>
</div>
<div className="mt-8 sm:mt-10 flex justify-center">
<div className="skeleton h-14 w-48 rounded-xl"></div>
</div>
</div>
</div>
</div>
</>
)
}
} }

View File

@ -2,10 +2,19 @@
import { Locale } from 'next-intl'; import { Locale } from 'next-intl';
import { checkAccess, checkSelectionOnSelectPage } from '@/app/api/guards'; import { checkAccess, checkSelectionOnSelectPage } from '@/app/api/guards';
import SelectPageClient from './SelectPage'; import SelectPageClient from './SelectPage';
import LocaleSwitcherServer from '@/components/LocaleSwitcherServer';
export default async function PageSelect({ params }: { params: Promise<{ locale: string }> }) { export default async function PageSelect({ params }: { params: Promise<{ locale: string }> }) {
const { locale } = await params; const { locale } = await params;
await checkAccess(locale as Locale); await checkAccess(locale as Locale);
await checkSelectionOnSelectPage(locale as Locale); // await checkSelectionOnSelectPage(locale as Locale);
return <SelectPageClient />;
return (
<div>
<div className='absolute top-2 right-2'>
<LocaleSwitcherServer locale={locale} pathname="/login" />
</div>
<SelectPageClient />
</div>
);
} }

View File

@ -8,7 +8,7 @@ export async function POST(req: NextRequest) {
console.log("Select attempt for UUID:", uuid); console.log("Select attempt for UUID:", uuid);
const response = await doSelect({ uuid }); const response = await doSelect({ uuid });
console.log("Select response:", response);
if (response.status !== 200) { if (response.status !== 200) {
console.log("Select failed with status:", response.status); console.log("Select failed with status:", response.status);
return NextResponse.json({ status: 401, message: "Select failed" }); return NextResponse.json({ status: 401, message: "Select failed" });

View File

@ -1,8 +1,7 @@
'use server'; 'use server';
import { fetchData } from "@/fetchers/fecther"; import { fetchData, fetchDataWithAccessToken } from "@/fetchers/fecther";
import { urlSelectEndpoint, urlLoginEndpoint } from "@/fetchers/urls"; import { urlSelectEndpoint, urlLoginEndpoint } from "@/fetchers/urls";
import { LoginViaAccessKeys } from "@/fetchers/types/login/validations"; import { LoginViaAccessKeys } from "@/fetchers/types/login/validations";
import { setCookieAccessToken, setCookieSelectToken } from "@/fetchers/token/cookies";
async function doLogin(payload: LoginViaAccessKeys) { async function doLogin(payload: LoginViaAccessKeys) {
@ -20,7 +19,7 @@ async function doLogin(payload: LoginViaAccessKeys) {
} }
async function doSelect(payload: { uuid: string }) { async function doSelect(payload: { uuid: string }) {
const response = await fetchData( const response = await fetchDataWithAccessToken(
urlSelectEndpoint, urlSelectEndpoint,
payload, payload,
"POST", "POST",

View File

@ -111,6 +111,23 @@ async function fetchDataWithToken<T>(
return coreFetch<T>(endpoint, { method, cache, timeout }, headers, payload); return coreFetch<T>(endpoint, { method, cache, timeout }, headers, payload);
} }
/**
* Fetch data with authentication token
*/
async function fetchDataWithAccessToken<T>(
endpoint: string,
payload?: any,
method: HttpMethod = "POST",
cache: boolean = false,
timeout: number = DEFAULT_TIMEOUT
): Promise<ApiResponse<T>> {
const accessToken = await getPlainAccessToken();
console.log('accessToken', accessToken);
const headers = { ...defaultHeaders, acs: accessToken };
return coreFetch<T>(endpoint, { method, cache, timeout }, headers, payload);
}
/** /**
* Update data with authentication token and UUID * Update data with authentication token and UUID
*/ */
@ -133,4 +150,4 @@ async function updateDataWithToken<T>(
); );
} }
export { fetchData, fetchDataWithToken, updateDataWithToken }; export { fetchData, fetchDataWithToken, fetchDataWithAccessToken, updateDataWithToken };

View File

@ -1,9 +1,9 @@
import Redis from "ioredis"; import Redis from "ioredis";
const redis = new Redis({ const redis = new Redis({
host: process.env.REDIS_HOST, host: process.env.REDIS_HOST || "10.10.2.15",
port: parseInt(process.env.REDIS_PORT || "6379", 10), port: parseInt(process.env.REDIS_PORT || "6379", 10),
password: process.env.REDIS_PASSWORD || "", password: process.env.REDIS_PASSWORD || "your_strong_password_here",
db: parseInt(process.env.REDIS_DB || "0", 10), db: parseInt(process.env.REDIS_DB || "0", 10),
connectTimeout: 5000, connectTimeout: 5000,
maxRetriesPerRequest: 2, maxRetriesPerRequest: 2,

View File

@ -10,7 +10,7 @@ POSTGRES_USER=postgres
POSTGRES_PASSWORD=password POSTGRES_PASSWORD=password
POSTGRES_DB=postgres POSTGRES_DB=postgres
POSTGRES_HOST=10.10.2.14 POSTGRES_HOST=10.10.2.14
POSTGRES_PORT=5432 POSTGRES_PORT=5432+
POSTGRES_ENGINE=postgresql+psycopg2 POSTGRES_ENGINE=postgresql+psycopg2
POSTGRES_POOL_PRE_PING=True POSTGRES_POOL_PRE_PING=True
POSTGRES_POOL_SIZE=20 POSTGRES_POOL_SIZE=20
@ -18,7 +18,8 @@ POSTGRES_MAX_OVERFLOW=10
POSTGRES_POOL_RECYCLE=600 POSTGRES_POOL_RECYCLE=600
POSTGRES_POOL_TIMEOUT=30 POSTGRES_POOL_TIMEOUT=30
POSTGRES_ECHO=True POSTGRES_ECHO=True
DATABASE_URL="postgresql://postgres:password@10.10.2.14:5432/sample_db?schema=public" #DATABASE_URL="postgresql://postgres:password@10.10.2.14:5432/sample_db?schema=public"
#DATABASE_URL="postgresql://postgres:password@10.10.2.14:5432/postgres?schema=public"
REDIS_HOST=10.10.2.15 REDIS_HOST=10.10.2.15
REDIS_PASSWORD=your_strong_password_here REDIS_PASSWORD=your_strong_password_here