client frontend added

This commit is contained in:
2025-05-19 23:12:23 +03:00
parent 5f7cb35ccc
commit fdf9d2edb8
507 changed files with 40655 additions and 510 deletions

View File

@@ -39,6 +39,7 @@
"cmdk": "^1.1.1",
"date-fns": "^4.1.0",
"flatpickr": "^4.6.13",
"ioredis": "^5.6.1",
"lucide-react": "^0.487.0",
"next": "^15.2.4",
"next-crypto": "^1.0.8",
@@ -739,6 +740,12 @@
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@ioredis/commands": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==",
"license": "MIT"
},
"node_modules/@isaacs/fs-minipass": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
@@ -3700,6 +3707,15 @@
"node": ">=6"
}
},
"node_modules/cluster-key-slot": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/cmdk": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz",
@@ -3922,7 +3938,6 @@
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -3979,6 +3994,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/denque": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.10"
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -5358,6 +5382,30 @@
"node": ">= 0.4"
}
},
"node_modules/ioredis": {
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.6.1.tgz",
"integrity": "sha512-UxC0Yv1Y4WRJiGQxQkP0hfdL0/5/6YvdfOOClRgJ0qppSarkhneSa6UvkMkms0AkdGimSH3Ikqm+6mkMmX7vGA==",
"license": "MIT",
"dependencies": {
"@ioredis/commands": "^1.1.1",
"cluster-key-slot": "^1.1.0",
"debug": "^4.3.4",
"denque": "^2.1.0",
"lodash.defaults": "^4.2.0",
"lodash.isarguments": "^3.1.0",
"redis-errors": "^1.2.0",
"redis-parser": "^3.0.0",
"standard-as-callback": "^2.1.0"
},
"engines": {
"node": ">=12.22.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/ioredis"
}
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
@@ -6181,6 +6229,18 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/lodash.defaults": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
"license": "MIT"
},
"node_modules/lodash.isarguments": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==",
"license": "MIT"
},
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -6366,7 +6426,6 @@
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true,
"license": "MIT"
},
"node_modules/nanoid": {
@@ -7096,6 +7155,27 @@
}
}
},
"node_modules/redis-errors": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
"integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/redis-parser": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
"integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
"license": "MIT",
"dependencies": {
"redis-errors": "^1.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
@@ -7605,6 +7685,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/standard-as-callback": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==",
"license": "MIT"
},
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",

View File

@@ -40,6 +40,7 @@
"cmdk": "^1.1.1",
"date-fns": "^4.1.0",
"flatpickr": "^4.6.13",
"ioredis": "^5.6.1",
"lucide-react": "^0.487.0",
"next": "^15.2.4",
"next-crypto": "^1.0.8",

View File

@@ -1,182 +0,0 @@
"use server";
import NextCrypto from "next-crypto";
import { fetchData, fetchDataWithToken } from "@/apicalls/api-fetcher";
import { baseUrlAuth, cookieObject, tokenSecret } from "@/apicalls/basics";
import { cookies } from "next/headers";
const loginEndpoint = `${baseUrlAuth}/authentication/login`;
const loginSelectEndpoint = `${baseUrlAuth}/authentication/select`;
const logoutEndpoint = `${baseUrlAuth}/authentication/logout`;
console.log("loginEndpoint", loginEndpoint);
console.log("loginSelectEndpoint", loginSelectEndpoint);
interface LoginViaAccessKeys {
accessKey: string;
password: string;
rememberMe: boolean;
}
interface LoginSelectEmployee {
company_uu_id: string;
}
interface LoginSelectOccupant {
build_living_space_uu_id: any;
}
async function logoutActiveSession() {
const cookieStore = await cookies();
const response = await fetchDataWithToken(logoutEndpoint, {}, "GET", false);
cookieStore.delete("accessToken");
cookieStore.delete("accessObject");
cookieStore.delete("userProfile");
cookieStore.delete("userSelection");
return response;
}
async function loginViaAccessKeys(payload: LoginViaAccessKeys) {
try {
const cookieStore = await cookies();
const nextCrypto = new NextCrypto(tokenSecret);
const response = await fetchData(
loginEndpoint,
{
access_key: payload.accessKey,
password: payload.password,
remember_me: payload.rememberMe,
},
"POST",
false
);
console.log("response", response);
if (response.status === 200 || response.status === 202) {
const loginRespone: any = response?.data;
const accessToken = await nextCrypto.encrypt(loginRespone.access_token);
const accessObject = await nextCrypto.encrypt(
JSON.stringify({
userType: loginRespone.user_type,
selectionList: loginRespone.selection_list,
})
);
const userProfile = await nextCrypto.encrypt(
JSON.stringify(loginRespone.user)
);
cookieStore.set({
name: "accessToken",
value: accessToken,
...cookieObject,
});
cookieStore.set({
name: "accessObject",
value: accessObject,
...cookieObject,
});
cookieStore.set({
name: "userProfile",
value: JSON.stringify(userProfile),
...cookieObject,
});
try {
return {
completed: true,
message: "Login successful",
status: 200,
data: loginRespone,
};
} catch (error) {
console.error("JSON parse error:", error);
return {
completed: false,
message: "Login NOT successful",
status: 401,
data: "{}",
};
}
}
return {
completed: false,
// error: response.error || "Login failed",
// message: response.message || "Authentication failed",
status: response.status || 500,
};
} catch (error) {
console.error("Login error:", error);
return {
completed: false,
// error: error instanceof Error ? error.message : "Login error",
// message: "An error occurred during login",
status: 500,
};
}
}
async function loginSelectEmployee(payload: LoginSelectEmployee) {
const cookieStore = await cookies();
const nextCrypto = new NextCrypto(tokenSecret);
const companyUUID = payload.company_uu_id;
const selectResponse: any = await fetchDataWithToken(
loginSelectEndpoint,
{
company_uu_id: companyUUID,
},
"POST",
false
);
cookieStore.delete("userSelection");
if (selectResponse.status === 200 || selectResponse.status === 202) {
const usersSelection = await nextCrypto.encrypt(
JSON.stringify({
selected: companyUUID,
user_type: "employee",
})
);
cookieStore.set({
name: "userSelection",
value: usersSelection,
...cookieObject,
});
}
return selectResponse;
}
async function loginSelectOccupant(payload: LoginSelectOccupant) {
const livingSpaceUUID = payload.build_living_space_uu_id;
const cookieStore = await cookies();
const nextCrypto = new NextCrypto(tokenSecret);
const selectResponse: any = await fetchDataWithToken(
loginSelectEndpoint,
{
build_living_space_uu_id: livingSpaceUUID,
},
"POST",
false
);
cookieStore.delete("userSelection");
if (selectResponse.status === 200 || selectResponse.status === 202) {
const usersSelection = await nextCrypto.encrypt(
JSON.stringify({
selected: livingSpaceUUID,
user_type: "occupant",
})
);
cookieStore.set({
name: "userSelection",
value: usersSelection,
...cookieObject,
});
}
return selectResponse;
}
export {
loginViaAccessKeys,
loginSelectEmployee,
loginSelectOccupant,
logoutActiveSession,
};

View File

@@ -1,148 +0,0 @@
"use server";
import { fetchDataWithToken } from "@/apicalls/api-fetcher";
import { baseUrlAuth, tokenSecret } from "@/apicalls/basics";
import { cookies } from "next/headers";
import NextCrypto from "next-crypto";
const checkToken = `${baseUrlAuth}/authentication/token/check`;
const pageValid = `${baseUrlAuth}/authentication/page/valid`;
const siteUrls = `${baseUrlAuth}/authentication/sites/list`;
const nextCrypto = new NextCrypto(tokenSecret);
async function checkAccessTokenIsValid() {
const response = await fetchDataWithToken(checkToken, {}, "GET", false);
return response?.status === 200 || response?.status === 202 ? true : false;
}
async function retrievePageList() {
const response: any = await fetchDataWithToken(siteUrls, {}, "GET", false);
return response?.status === 200 || response?.status === 202
? response.data?.sites
: null;
}
async function retrieveApplicationbyUrl(pageUrl: string) {
const response: any = await fetchDataWithToken(
pageValid,
{
page_url: pageUrl,
},
"POST",
false
);
return response?.status === 200 || response?.status === 202
? response.data?.application
: null;
}
async function retrieveAccessToken() {
const cookieStore = await cookies();
const encrpytAccessToken = cookieStore.get("accessToken")?.value || "";
return encrpytAccessToken
? await nextCrypto.decrypt(encrpytAccessToken)
: null;
}
async function retrieveUserType() {
const cookieStore = await cookies();
const encrpytaccessObject = cookieStore.get("accessObject")?.value || "{}";
const decrpytUserType = JSON.parse(
(await nextCrypto.decrypt(encrpytaccessObject)) || "{}"
);
return decrpytUserType ? decrpytUserType : null;
}
async function retrieveAccessObjects() {
const cookieStore = await cookies();
const encrpytAccessObject = cookieStore.get("accessObject")?.value || "";
const decrpytAccessObject = await nextCrypto.decrypt(encrpytAccessObject);
return decrpytAccessObject ? JSON.parse(decrpytAccessObject) : null;
}
async function retrieveUserSelection() {
const cookieStore = await cookies();
const encrpytUserSelection = cookieStore.get("userSelection")?.value || "";
let objectUserSelection = {};
let decrpytUserSelection: any = await nextCrypto.decrypt(
encrpytUserSelection
);
decrpytUserSelection = decrpytUserSelection
? JSON.parse(decrpytUserSelection)
: null;
console.log("decrpytUserSelection", decrpytUserSelection);
const userSelection = decrpytUserSelection?.selected;
const accessObjects = (await retrieveAccessObjects()) || {};
console.log("accessObjects", accessObjects);
if (decrpytUserSelection?.user_type === "employee") {
const companyList = accessObjects?.selectionList;
const selectedCompany = companyList.find(
(company: any) => company.uu_id === userSelection
);
if (selectedCompany) {
objectUserSelection = { userType: "employee", selected: selectedCompany };
}
} else if (decrpytUserSelection?.user_type === "occupant") {
const buildingsList = accessObjects?.selectionList;
// Iterate through all buildings
if (buildingsList) {
// Loop through each building
for (const buildKey in buildingsList) {
const building = buildingsList[buildKey];
// Check if the building has occupants
if (building.occupants && building.occupants.length > 0) {
// Find the occupant with the matching build_living_space_uu_id
const occupant = building.occupants.find(
(occ: any) => occ.build_living_space_uu_id === userSelection
);
if (occupant) {
objectUserSelection = {
userType: "occupant",
selected: {
...occupant,
buildName: building.build_name,
buildNo: building.build_no,
},
};
break;
}
}
}
}
}
return {
...objectUserSelection,
};
}
// const avatarInfo = await retrieveAvatarInfo();
// lang: avatarInfo?.data?.lang
// ? String(avatarInfo?.data?.lang).toLowerCase()
// : undefined,
// avatar: avatarInfo?.data?.avatar,
// fullName: avatarInfo?.data?.full_name,
// async function retrieveAvatarInfo() {
// const response = await fetchDataWithToken(
// `${baseUrlAuth}/authentication/avatar`,
// {},
// "POST"
// );
// return response;
// }
export {
checkAccessTokenIsValid,
retrieveAccessToken,
retrieveUserType,
retrieveAccessObjects,
retrieveUserSelection,
retrieveApplicationbyUrl,
retrievePageList,
// retrieveavailablePages,
};

View File

@@ -1,5 +1,5 @@
"use server";
import { retrieveAccessToken } from "@/apicalls/mutual/cookies/token";
import { retrieveAccessToken } from "@/apifetchers/mutual/cookies/token";
import {
DEFAULT_RESPONSE,
defaultHeaders,
@@ -27,30 +27,6 @@ const createTimeoutPromise = (
});
};
/**
* Prepares a standardized API response
* @param response The response data
* @param statusCode HTTP status code
* @returns Standardized API response
*/
const prepareResponse = <T>(
response: T,
statusCode: number
): ApiResponse<T> => {
try {
return {
status: statusCode,
data: response || ({} as T),
};
} catch (error) {
console.error("Error preparing response:", error);
return {
...DEFAULT_RESPONSE,
error: "Response parsing error",
} as ApiResponse<T>;
}
};
/**
* Core fetch function with timeout and error handling
* @param url The URL to fetch
@@ -66,22 +42,22 @@ async function coreFetch<T>(
payload?: any
): Promise<ApiResponse<T>> {
const { method = "POST", cache = false, timeout = DEFAULT_TIMEOUT } = options;
try {
// Setup controller for timeout handling
const controller = new AbortController();
const signal = controller.signal;
// Prepare fetch options
const fetchOptions: RequestInit = {
method,
headers,
cache: cache ? "force-cache" : "no-cache",
signal,
signal: controller.signal,
};
// Add body if needed
// Add body for non-GET requests with payload
if (method !== "GET" && payload) {
fetchOptions.body = JSON.stringify(
// Handle special case for updateDataWithToken
payload.payload ? payload.payload : payload
);
}
@@ -89,22 +65,22 @@ async function coreFetch<T>(
// Create timeout promise
const timeoutPromise = createTimeoutPromise(timeout, controller);
// Race between fetch and timeout
const response = (await Promise.race([
// Execute request with timeout
const response = await Promise.race([
fetch(url, fetchOptions),
timeoutPromise,
])) as Response;
]);
const responseJson = await response.json();
if (process.env.NODE_ENV !== "production") {
console.log("Fetching:", url, fetchOptions);
console.log("Response:", responseJson);
}
return prepareResponse(responseJson, response.status);
// Parse response
const responseData = await response.json();
// Return standardized response
return {
status: response.status,
data: responseData || ({} as T),
};
} catch (error) {
console.error(`Fetch error (${url}):`, error);
console.error(`API Error (${url}):`, error);
return {
...DEFAULT_RESPONSE,
error: error instanceof Error ? error.message : "Network error",

View File

@@ -19,7 +19,7 @@ const baseUrlBuilding = formatServiceUrl(
process.env.NEXT_PUBLIC_BUILDING_SERVICE_URL || "building_service:8006"
);
const baseUrlPeople = formatServiceUrl(
process.env.NEXT_PUBLIC_VALIDATION_SERVICE_URL || "identity_service:8009"
process.env.NEXT_PUBLIC_VALIDATION_SERVICE_URL || "validation_service:8009"
);
// Types for better type safety
@@ -37,7 +37,8 @@ interface FetchOptions {
timeout?: number;
}
const tokenSecret = process.env.TOKENSECRET_90 || "";
const tokenSecret =
process.env.TOKENSECRET_90 || "787a4a44-2a27-454d-8918-35ceab50592d";
const cookieObject: any = {
httpOnly: true,
@@ -53,7 +54,7 @@ const DEFAULT_TIMEOUT = 10000; // 10 seconds
const defaultHeaders = {
accept: "application/json",
language: "tr",
domain: "management.com.tr",
domain: "evyos.com.tr",
tz: "GMT+3",
"Content-type": "application/json",
};

View File

@@ -0,0 +1,218 @@
"use server";
import NextCrypto from "next-crypto";
import { fetchData, fetchDataWithToken } from "@/apifetchers/api-fetcher";
import { baseUrlAuth, cookieObject, tokenSecret } from "@/apifetchers/basics";
import { cookies } from "next/headers";
import { setNewCompleteToRedis, getCompleteFromRedis } from "@/apifetchers/mutual/context/complete/fetch";
import {
defaultClientHeader,
defaultClientMenu,
defaultClientOnline,
defaultClientPageConfig,
defaultLinkList
} from "@/types/mutual/context/validations";
import { retrievePageList } from "@/apifetchers/mutual/cookies/token";
import { setMenuToRedis } from "@/apifetchers/mutual/context/page/menu/fetch";
const loginEndpoint = `${baseUrlAuth}/authentication/login`;
const loginSelectEndpoint = `${baseUrlAuth}/authentication/select`;
const logoutEndpoint = `${baseUrlAuth}/authentication/logout`;
interface LoginViaAccessKeys {
accessKey: string;
password: string;
rememberMe: boolean;
}
interface LoginSelect {
uuid: string;
}
interface LoginSelectOccupant {
uuid: any;
}
async function logoutActiveSession() {
const cookieStore = await cookies();
const response = await fetchDataWithToken(logoutEndpoint, {}, "GET", false);
cookieStore.delete("eys-zzz");
cookieStore.delete("eys-yyy");
cookieStore.delete("eys-sel");
return response;
}
async function initRedis(loginRespone: any, firstSelection: any, accessToken: string, redisKey: string) {
let alreadyAtRedis = null
try {
const redisData = await getCompleteFromRedis();
alreadyAtRedis = redisData;
} catch (error) { }
if (!alreadyAtRedis) {
const loginObjectToRedis = {
online: {
...defaultClientOnline,
lastLogin: new Date(),
userType: `${loginRespone.user_type}`.toUpperCase(),
lang: loginRespone.user.person.country_code.toLowerCase(),
},
pageConfig: defaultClientPageConfig,
menu: defaultClientMenu,
header: defaultClientHeader,
selection: { selectionList: loginRespone.selection_list, activeSelection: firstSelection },
user: loginRespone.user,
settings: { lastOnline: new Date(), token: accessToken },
chatRoom: defaultLinkList,
notifications: defaultLinkList,
messages: defaultLinkList,
}
await setNewCompleteToRedis(loginObjectToRedis, redisKey);
}
}
async function loginViaAccessKeys(payload: LoginViaAccessKeys) {
const cookieStore = await cookies();
try {
const response = await fetchData(
loginEndpoint,
{
access_key: payload.accessKey,
password: payload.password,
remember_me: payload.rememberMe,
},
"POST",
false
);
if (response.status === 200 || response.status === 202) {
const loginRespone: any = response?.data;
const firstSelection = loginRespone.selection_list.find((item: any) => item.uu_id === loginRespone.selection_list[0].uu_id);
const nextCrypto = new NextCrypto(tokenSecret);
const accessToken = await nextCrypto.encrypt(loginRespone.access_token);
const redisKey = `CLIENT:${loginRespone.user_type.toUpperCase()}:${firstSelection.uu_id}`;
const redisKeyAccess = await nextCrypto.encrypt(redisKey);
const usersSelection = await nextCrypto.encrypt(
JSON.stringify({
selected: firstSelection.uu_id,
userType: loginRespone.user_type.toUpperCase(),
redisKey,
})
);
await initRedis(loginRespone, firstSelection, accessToken, redisKey);
cookieStore.set({
name: "eys-zzz",
value: accessToken,
...cookieObject,
});
cookieStore.set({
name: "eys-yyy",
value: redisKeyAccess,
...cookieObject,
});
cookieStore.set({
name: "eys-sel",
value: usersSelection,
...cookieObject,
});
try {
return {
completed: true,
message: "Login successful",
status: 200,
data: loginRespone,
};
} catch (error) {
console.error("JSON parse error:", error);
return {
completed: false,
message: "Login NOT successful",
status: 401,
data: "{}",
};
}
}
return {
completed: false,
// error: response.error || "Login failed",
// message: response.message || "Authentication failed",
status: response.status || 500,
};
} catch (error) {
console.error("Login error:", error);
return {
completed: false,
// error: error instanceof Error ? error.message : "Login error",
// message: "An error occurred during login",
status: 500,
};
}
}
async function loginSelectEmployee(payload: LoginSelect) {
const cookieStore = await cookies();
const nextCrypto = new NextCrypto(tokenSecret);
const employeeUUID = payload.uuid;
const redisKey = `CLIENT:EMPLOYEE:${employeeUUID}`;
const selectResponse: any = await fetchDataWithToken(loginSelectEndpoint, { uuid: employeeUUID }, "POST", false);
cookieStore.delete("eys-sel");
if (selectResponse.status === 200 || selectResponse.status === 202) {
const usersSelection = await nextCrypto.encrypt(
JSON.stringify({
selected: employeeUUID,
userType: "employee",
redisKey,
})
);
cookieStore.set({
name: "eys-sel",
value: usersSelection,
...cookieObject,
});
try {
const pageList = await retrievePageList()
await setMenuToRedis({
selectionList: pageList,
activeSelection: "/dashboard"
})
} catch (error) { }
}
return selectResponse;
}
async function loginSelectOccupant(payload: LoginSelectOccupant) {
const livingSpaceUUID = payload.uuid;
const cookieStore = await cookies();
const nextCrypto = new NextCrypto(tokenSecret);
const selectResponse: any = await fetchDataWithToken(loginSelectEndpoint, { uuid: livingSpaceUUID }, "POST", false);
const redisKey = `CLIENT:OCCUPANT:${livingSpaceUUID}`;
cookieStore.delete("eys-sel");
if (selectResponse.status === 200 || selectResponse.status === 202) {
const usersSelection = await nextCrypto.encrypt(
JSON.stringify({
selected: livingSpaceUUID,
userType: "OCCUPANT",
redisKey,
})
);
cookieStore.set({
name: "eys-sel",
value: usersSelection,
...cookieObject,
});
}
return selectResponse;
}
export {
loginViaAccessKeys,
loginSelectEmployee,
loginSelectOccupant,
logoutActiveSession,
};

View File

@@ -0,0 +1,32 @@
"use server";
import { redis } from "@/lib/redis";
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
import { ClientRedisToken } from "@/types/mutual/context/validations";
const getCompleteFromRedis = async (): Promise<ClientRedisToken> => {
const decrpytUserSelection = await functionRetrieveUserSelection()
const redisKey = decrpytUserSelection?.redisKey;
if (!redisKey) throw new Error("No redis key found");
const result = await redis.get(`${redisKey}`);
if (!result) throw new Error("No data found in redis");
return JSON.parse(result);
}
const setCompleteToRedis = async (completeObject: ClientRedisToken) => {
const decrpytUserSelection = await functionRetrieveUserSelection()
if (!decrpytUserSelection) throw new Error("No user selection found");
const redisKey = decrpytUserSelection?.redisKey;
if (!redisKey) throw new Error("No redis key found");
if (!completeObject) throw new Error("No complete object provided");
await redis.set(redisKey, JSON.stringify(completeObject));
return true;
}
const setNewCompleteToRedis = async (completeObject: ClientRedisToken, redisKey: string) => {
if (!redisKey) throw new Error("No redis key found");
if (!completeObject) throw new Error("No complete object provided");
await redis.set(redisKey, JSON.stringify(completeObject));
return true;
}
export { getCompleteFromRedis, setCompleteToRedis, setNewCompleteToRedis };

View File

@@ -0,0 +1,32 @@
"use server";
import { redis } from "@/lib/redis";
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
import { ClientSelection } from "@/types/mutual/context/validations";
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
const getSelectionFromRedis = async (): Promise<ClientSelection> => {
try {
const decrpytUserSelection = await functionRetrieveUserSelection();
const redisKey = decrpytUserSelection?.redisKey;
if (redisKey === "default") { return { selectionList: [], activeSelection: {} } }
const result = await redis.get(`${redisKey}`);
if (!result) { return { selectionList: [], activeSelection: {} } }
const parsedResult = JSON.parse(result);
if (!parsedResult.selection) { return { selectionList: [], activeSelection: {} } }
return parsedResult.selection;
} catch (error) { return { selectionList: [], activeSelection: {} } }
}
const setSelectionToRedis = async (selectionObject: ClientSelection) => {
const decrpytUserSelection = await functionRetrieveUserSelection()
if (!decrpytUserSelection) throw new Error("No user selection found");
const redisKey = decrpytUserSelection?.redisKey;
if (!redisKey) throw new Error("No redis key found");
if (!selectionObject) throw new Error("No selection object provided");
const oldData = await getCompleteFromRedis();
if (!oldData) throw new Error("No old data found in redis");
await setCompleteToRedis({ ...oldData, selection: selectionObject })
return true;
}
export { getSelectionFromRedis, setSelectionToRedis };

View File

@@ -0,0 +1,30 @@
"use server";
import { redis } from "@/lib/redis";
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
import { ClientSettings } from "@/types/mutual/context/validations";
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
const getSettingsFromRedis = async (): Promise<ClientSettings> => {
const decrpytUserSelection = await functionRetrieveUserSelection()
const redisKey = decrpytUserSelection?.redisKey;
if (!redisKey) throw new Error("No redis key found");
const result = await redis.get(`${redisKey}`);
if (!result) throw new Error("No data found in redis");
const parsedResult = JSON.parse(result);
if (!parsedResult.settings) throw new Error("No settings found in redis");
return parsedResult.settings;
}
const setSettingsToRedis = async (settingsObject: ClientSettings) => {
const decrpytUserSelection = await functionRetrieveUserSelection()
if (!decrpytUserSelection) throw new Error("No user selection found");
const redisKey = decrpytUserSelection?.redisKey;
if (!redisKey) throw new Error("No redis key found");
if (!settingsObject) throw new Error("No settings object provided");
const oldData = await getCompleteFromRedis();
if (!oldData) throw new Error("No old data found in redis");
await setCompleteToRedis({ ...oldData, settings: settingsObject })
return true;
}
export { getSettingsFromRedis, setSettingsToRedis };

View File

@@ -0,0 +1,30 @@
"use server";
import { redis } from "@/lib/redis";
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
import { ClientUser } from "@/types/mutual/context/validations";
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
const getUserFromRedis = async (): Promise<ClientUser> => {
const decrpytUserSelection = await functionRetrieveUserSelection()
const redisKey = decrpytUserSelection?.redisKey;
if (!redisKey) throw new Error("No redis key found");
const result = await redis.get(`${redisKey}`);
if (!result) throw new Error("No data found in redis");
const parsedResult = JSON.parse(result);
if (!parsedResult.user) throw new Error("No user found in redis");
return parsedResult.user;
}
const setUserToRedis = async (userObject: ClientUser) => {
const decrpytUserSelection = await functionRetrieveUserSelection()
if (!decrpytUserSelection) throw new Error("No user selection found");
const redisKey = decrpytUserSelection?.redisKey;
if (!redisKey) throw new Error("No redis key found");
if (!userObject) throw new Error("No user object provided");
const oldData = await getCompleteFromRedis();
if (!oldData) throw new Error("No old data found in redis");
await setCompleteToRedis({ ...oldData, user: userObject });
return true;
}
export { getUserFromRedis, setUserToRedis };

View File

@@ -0,0 +1,31 @@
"use server";
import { redis } from "@/lib/redis";
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
import { ClientSettings } from "@/types/mutual/context/validations";
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
const getConfigFromRedis = async (): Promise<ClientSettings> => {
const decrpytUserSelection = await functionRetrieveUserSelection()
const redisKey = decrpytUserSelection?.redisKey;
if (!redisKey) throw new Error("No redis key found");
const result = await redis.get(`${redisKey}`);
if (!result) throw new Error("No data found in redis");
const parsedResult = JSON.parse(result);
if (!parsedResult.settings) throw new Error("No settings found in redis");
return parsedResult.settings;
}
const setConfigToRedis = async (settingsObject: ClientSettings) => {
const decrpytUserSelection = await functionRetrieveUserSelection()
if (!decrpytUserSelection) throw new Error("No user selection found");
const redisKey = decrpytUserSelection?.redisKey;
if (!redisKey) throw new Error("No redis key found");
if (!settingsObject) throw new Error("No settings object provided");
const oldData = await getCompleteFromRedis();
if (!oldData) throw new Error("No old data found in redis");
await setCompleteToRedis({ ...oldData, settings: settingsObject });
return true;
}
export { getConfigFromRedis, setConfigToRedis };

View File

@@ -0,0 +1,30 @@
"use server";
import { redis } from "@/lib/redis";
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
import { ClientMenu } from "@/types/mutual/context/validations";
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
const getMenuFromRedis = async (): Promise<ClientMenu> => {
const decrpytUserSelection = await functionRetrieveUserSelection()
const redisKey = decrpytUserSelection?.redisKey;
if (!redisKey) throw new Error("No redis key found");
const result = await redis.get(`${redisKey}`);
if (!result) throw new Error("No data found in redis");
const parsedResult = JSON.parse(result);
if (!parsedResult.menu) throw new Error("No menu found in redis");
return parsedResult.menu;
}
const setMenuToRedis = async (menuObject: ClientMenu) => {
const decrpytUserSelection = await functionRetrieveUserSelection()
if (!decrpytUserSelection) throw new Error("No user selection found");
const redisKey = decrpytUserSelection?.redisKey;
if (!redisKey) throw new Error("No redis key found");
if (!menuObject) throw new Error("No menu object provided");
const oldData = await getCompleteFromRedis();
if (!oldData) throw new Error("No old data found in redis");
await setCompleteToRedis({ ...oldData, menu: menuObject });
return true;
}
export { getMenuFromRedis, setMenuToRedis };

View File

@@ -0,0 +1,82 @@
"use server";
import { redis } from "@/lib/redis";
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
import { ClientOnline } from "@/types/mutual/context/validations";
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
const getOnlineFromRedis = async (): Promise<ClientOnline> => {
try {
// Get user selection with default fallback
const decrpytUserSelection = await functionRetrieveUserSelection();
const redisKey = decrpytUserSelection?.redisKey;
// If we have a default redisKey, return a default online object
if (redisKey === "default") {
return {
lang: "en",
userType: "occupant",
lastLogin: new Date(),
lastLogout: new Date(),
lastAction: new Date(),
lastPage: "/auth/login",
timezone: "GMT+3"
};
}
// Try to get data from Redis
const result = await redis.get(`${redisKey}`);
if (!result) {
return {
lang: "en",
userType: "occupant",
lastLogin: new Date(),
lastLogout: new Date(),
lastAction: new Date(),
lastPage: "/auth/login",
timezone: "GMT+3"
};
}
// Parse the result
const parsedResult = JSON.parse(result);
if (!parsedResult.online) {
return {
lang: "en",
userType: "occupant",
lastLogin: new Date(),
lastLogout: new Date(),
lastAction: new Date(),
lastPage: "/auth/login",
timezone: "GMT+3"
};
}
return parsedResult.online;
} catch (error) {
console.error("Error getting online from Redis:", error);
// Return default online object in case of any error
return {
lang: "en",
userType: "occupant",
lastLogin: new Date(),
lastLogout: new Date(),
lastAction: new Date(),
lastPage: "/auth/login",
timezone: "GMT+3"
};
}
}
const setOnlineToRedis = async (onlineObject: ClientOnline) => {
const decrpytUserSelection = await functionRetrieveUserSelection()
if (!decrpytUserSelection) throw new Error("No user selection found");
const redisKey = decrpytUserSelection?.redisKey;
if (!redisKey) throw new Error("No redis key found");
if (!onlineObject) throw new Error("No online object provided");
const oldData = await getCompleteFromRedis();
if (!oldData) throw new Error("No old data found in redis");
await setCompleteToRedis({ ...oldData, online: onlineObject });
return true;
}
export { getOnlineFromRedis, setOnlineToRedis };

View File

@@ -0,0 +1,57 @@
"use server";
import NextCrypto from "next-crypto";
import { fetchDataWithToken } from "@/apifetchers/api-fetcher";
import { baseUrlAuth, baseUrlRestriction, tokenSecret } from "@/apifetchers/basics";
import { cookies } from "next/headers";
const checkToken = `${baseUrlAuth}/authentication/token/check`;
const pageValid = `${baseUrlRestriction}/restrictions/page/valid`;
const siteUrls = `${baseUrlRestriction}/restrictions/sites/list`;
const nextCrypto = new NextCrypto(tokenSecret);
function fetchResponseStatus(response: any) {
return 199 < response?.status && response?.status < 300;
}
async function checkAccessTokenIsValid() {
try {
const response = await fetchDataWithToken(checkToken, {}, "GET", false);
return fetchResponseStatus(response) ? true : false;
} catch (error) {
console.error("Error checking token validity:", error);
return false;
}
}
async function retrievePageList() {
const response: any = await fetchDataWithToken(siteUrls, {}, "GET", false);
return fetchResponseStatus(response) ? response.data?.sites : null;
}
async function retrieveApplicationbyUrl(pageUrl: string) {
const response: any = await fetchDataWithToken(pageValid, { page_url: pageUrl }, "POST", false);
return fetchResponseStatus(response) ? response.data?.application : null;
}
async function retrieveAccessToken() {
const cookieStore = await cookies();
const encrpytAccessToken = cookieStore.get("eys-zzz")?.value || "";
return encrpytAccessToken ? await nextCrypto.decrypt(encrpytAccessToken) : null;
}
async function retrieveAccessObjects() {
const cookieStore = await cookies();
const encrpytAccessObject = cookieStore.get("eys-yyy")?.value || "";
const decrpytAccessObject = await nextCrypto.decrypt(encrpytAccessObject);
return decrpytAccessObject ? JSON.parse(decrpytAccessObject) : null;
}
export {
checkAccessTokenIsValid,
retrieveAccessToken,
retrieveAccessObjects,
retrieveApplicationbyUrl,
retrievePageList,
};

View File

@@ -0,0 +1,33 @@
"use server";
import NextCrypto from "next-crypto";
import { cookieObject, tokenSecret } from "@/apifetchers/basics";
import { cookies } from "next/headers";
const nextCrypto = new NextCrypto(tokenSecret);
const functionRetrieveUserSelection = async () => {
const cookieStore = await cookies();
const encrpytUserSelection = cookieStore.get("eys-sel")?.value || "";
if (!encrpytUserSelection) throw new Error("No user selection found");
const decrpytUserSelection = await nextCrypto.decrypt(encrpytUserSelection);
if (!decrpytUserSelection) throw new Error("No user selection found");
return JSON.parse(decrpytUserSelection);
}
const functionSetUserSelection = async (userSelection: any) => {
const cookieStore = await cookies();
const encrpytUserSelection = await nextCrypto.encrypt(JSON.stringify(userSelection));
if (!encrpytUserSelection) throw new Error("No user selection found");
cookieStore.set({
name: "eys-sel",
value: encrpytUserSelection,
...cookieObject,
});
}
const functionRemoveUserSelection = async () => {
const cookieStore = await cookies();
cookieStore.delete("eys-sel");
}
export { functionRetrieveUserSelection, functionSetUserSelection, functionRemoveUserSelection };

View File

@@ -1,10 +1,12 @@
'use server';
import { AuthLayout } from "@/layouts/auth/layout";
import { AuthServerProps } from "@/validations/mutual/pages/props";
import { checkContextPageOnline } from "@/components/mutual/context/online/context";
import getPage from "@/webPages/getPage";
const AuthPageEn = async ({ params, searchParams }: AuthServerProps) => {
const lang = "en";
const online = await checkContextPageOnline();
const lang = online?.lang || "en";
const awaitedParams = await params;
const awaitedSearchParams = await searchParams;
const pageUrlFromParams = `/${awaitedParams.page?.join("/")}` || "/login";

View File

@@ -1,15 +0,0 @@
'use server';
import { AuthServerProps } from "@/validations/mutual/pages/props";
import { AuthLayout } from "@/layouts/auth/layout";
import getPage from "@/webPages/getPage";
const AuthPageTr = async ({ params, searchParams }: AuthServerProps) => {
const lang = "tr";
const awaitedParams = await params;
const awaitedSearchParams = await searchParams;
const pageUrlFromParams = `/${awaitedParams.page?.join("/")}` || "/login";
const FoundPage = getPage(pageUrlFromParams, { language: lang, query: awaitedSearchParams });
return <AuthLayout lang={lang} page={FoundPage} activePageUrl={pageUrlFromParams} />
}
export default AuthPageTr;

View File

@@ -1,15 +0,0 @@
'use server';
import { DashboardLayout } from "@/layouts/dashboard/layout";
import { MaindasboardPageProps } from "@/validations/mutual/dashboard/props";
const MainEnPage: React.FC<MaindasboardPageProps> = async ({ params, searchParams }) => {
const parameters = await params;
const searchParameters = await searchParams;
return (
<div className="flex flex-col items-center justify-center">
<DashboardLayout lang="en" params={parameters} searchParams={searchParameters} />
</div>
);
}
export default MainEnPage;

View File

@@ -1,15 +0,0 @@
'use server';
import { DashboardLayout } from "@/layouts/dashboard/layout";
import { MaindasboardPageProps } from "@/validations/mutual/dashboard/props";
const MainTrPage: React.FC<MaindasboardPageProps> = async ({ params, searchParams }) => {
const parameters = await params;
const searchParameters = await searchParams;
return (
<div className="flex flex-col items-center justify-center">
<DashboardLayout lang="tr" params={parameters} searchParams={searchParameters} />
</div>
);
}
export default MainTrPage;

View File

@@ -0,0 +1,33 @@
import { NextResponse } from "next/server";
import { retrieveAccessToken } from "@/apifetchers/mutual/cookies/token";
export async function GET() {
try {
// Check if token exists
const token = await retrieveAccessToken();
if (!token) {
return NextResponse.json({
status: 401,
data: null,
error: "No token found",
});
}
// In a real implementation, you would validate the token
// For now, just return success if a token exists
return NextResponse.json({
status: 200,
data: {
valid: true,
},
});
} catch (error) {
console.error("Error checking token:", error);
return NextResponse.json({
status: 500,
data: null,
error: "Error validating token",
});
}
}

View File

@@ -0,0 +1,22 @@
import {
getSelectionFromRedis,
setSelectionToRedis,
} from "@/apifetchers/mutual/context/dash/selection/fetch";
import { NextResponse } from "next/server";
export async function GET() {
const selection = await getSelectionFromRedis();
return NextResponse.json({
status: 200,
data: selection || null,
});
}
export async function POST(request: Request) {
const selection = await request.json();
await setSelectionToRedis(selection);
return NextResponse.json({
status: 200,
data: selection || null,
});
}

View File

@@ -0,0 +1,16 @@
import {
getSettingsFromRedis,
setSettingsToRedis,
} from "@/apifetchers/mutual/context/dash/settings/fetch";
import { NextResponse } from "next/server";
export async function GET() {
const settings = await getSettingsFromRedis();
return NextResponse.json(settings);
}
export async function POST(request: Request) {
const settings = await request.json();
await setSettingsToRedis(settings);
return NextResponse.json(settings);
}

View File

@@ -0,0 +1,16 @@
import {
getUserFromRedis,
setUserToRedis,
} from "@/apifetchers/mutual/context/dash/user/fetch";
import { NextResponse } from "next/server";
export async function GET() {
const user = await getUserFromRedis();
return NextResponse.json(user);
}
export async function POST(request: Request) {
const user = await request.json();
await setUserToRedis(user);
return NextResponse.json(user);
}

View File

@@ -0,0 +1,16 @@
import {
getConfigFromRedis,
setConfigToRedis,
} from "@/apifetchers/mutual/context/page/config/fetch";
import { NextResponse } from "next/server";
export async function GET() {
const config = await getConfigFromRedis();
return NextResponse.json(config);
}
export async function POST(request: Request) {
const config = await request.json();
await setConfigToRedis(config);
return NextResponse.json(config);
}

View File

@@ -0,0 +1,22 @@
import {
getMenuFromRedis,
setMenuToRedis,
} from "@/apifetchers/mutual/context/page/menu/fetch";
import { NextResponse } from "next/server";
export async function GET() {
const menu = await getMenuFromRedis();
return NextResponse.json({
status: 200,
data: menu,
});
}
export async function POST(request: Request) {
const menu = await request.json();
await setMenuToRedis(menu);
return NextResponse.json({
status: 200,
data: menu,
});
}

View File

@@ -0,0 +1,22 @@
import {
getOnlineFromRedis,
setOnlineToRedis,
} from "@/apifetchers/mutual/context/page/online/fetch";
import { NextResponse } from "next/server";
export async function GET() {
const online = await getOnlineFromRedis();
return NextResponse.json({
status: 200,
data: online,
});
}
export async function POST(request: Request) {
const online = await request.json();
await setOnlineToRedis(online);
return NextResponse.json({
status: 200,
data: online,
});
}

View File

@@ -1,20 +0,0 @@
import { retrieveUserSelection } from "@/apicalls/cookies/token";
import { NextResponse } from "next/server";
export async function POST(): Promise<NextResponse> {
try {
const userSelection = await retrieveUserSelection();
console.log("userSelection", userSelection);
if (userSelection) {
return NextResponse.json({
status: 200,
message: "User selection found",
data: userSelection,
});
}
} catch (error) {}
return NextResponse.json({
status: 500,
message: "User selection not found",
});
}

View File

@@ -1,11 +1,10 @@
import { loginViaAccessKeys } from "@/apicalls/custom/login/login";
import { NextResponse } from "next/server";
import { loginViaAccessKeys } from "@/apifetchers/custom/login/login";
import { loginSchemaEmail } from "@/webPages/auth/login/schemas";
export async function POST(req: Request): Promise<NextResponse> {
try {
const headers = req.headers;
console.log("headers", Object.entries(headers));
const body = await req.json();
const dataValidated = {
accessKey: body.email,

View File

@@ -1,20 +1,16 @@
import { API_BASE_URL } from "@/config/config";
import { NextResponse } from "next/server";
export async function POST() {
async function retrieveAvailableApplication(): Promise<string[]> {
return new Promise((resolve) => {
const mockList = [
"management/account/tenant/something",
"management/account/tenant/somethingSecond",
"building/parts/tenant/something",
];
resolve(mockList);
});
}
const availableApplications = await retrieveAvailableApplication();
return NextResponse.json({
status: 200,
data: availableApplications,
const result = await fetch(`${API_BASE_URL}/context/page/menu`, {
method: "GET",
headers: { "Content-Type": "application/json" },
});
try {
const data = await result.json();
return NextResponse.json({ status: 200, data: data });
} catch (error) {
console.log(error);
return NextResponse.json({ status: 500, message: "No data is found" });
}
}

View File

@@ -1,9 +1,9 @@
import { z } from "zod";
import { loginSelectEmployee } from "@/apicalls/custom/login/login";
import { loginSelectEmployee } from "@/apifetchers/custom/login/login";
import { NextResponse } from "next/server";
const loginSchemaEmployee = z.object({
company_uu_id: z.string(),
uuid: z.string(),
});
export async function POST(req: Request): Promise<NextResponse> {
@@ -12,7 +12,7 @@ export async function POST(req: Request): Promise<NextResponse> {
console.log("headers", Object.entries(headers));
const body = await req.json();
const dataValidated = {
company_uu_id: body.company_uu_id,
uuid: body.uuid,
};
const validatedLoginBody = loginSchemaEmployee.safeParse(body);
if (!validatedLoginBody.success) {

View File

@@ -1,18 +1,17 @@
import { z } from "zod";
import { loginSelectOccupant } from "@/apicalls/custom/login/login";
import { loginSelectOccupant } from "@/apifetchers/custom/login/login";
import { NextResponse } from "next/server";
const loginSchemaOccupant = z.object({
build_living_space_uu_id: z.string(),
uuid: z.string(),
});
export async function POST(req: Request): Promise<NextResponse> {
try {
const headers = req.headers;
console.log("headers", Object.entries(headers));
const body = await req.json();
const dataValidated = {
build_living_space_uu_id: body.build_living_space_uu_id,
uuid: body.uuid,
};
const validatedLoginBody = loginSchemaOccupant.safeParse(body);
if (!validatedLoginBody.success) {

View File

@@ -63,7 +63,6 @@ export async function handleCreateOperation(
}
if (createFunction) {
console.log("Body:", body);
const result = await createFunction(body);
return createResponse(result);
}
@@ -90,7 +89,6 @@ export async function handleUpdateOperation(
return errorResponse("UUID not found", 400);
}
if (updateFunction) {
console.log("Body:", body);
const result = await updateFunction(body, uuid);
return updateResponse(result);
}
@@ -136,12 +134,10 @@ export function createCreateHandler(
createFunction?: CreateFunction,
requiredFields: string[] = []
) {
console.log("Required fields:", requiredFields);
// This handler only takes the body parameter, not the request
return withErrorHandling((body: any) => {
// Ensure we're only passing the actual body data to the create function
if (body && typeof body === 'object' && body.body) {
console.log("Extracting body from request body");
return handleCreateOperation(body.body, createFunction, requiredFields);
}
return handleCreateOperation(body, createFunction, requiredFields);

View File

@@ -2,10 +2,11 @@ import { ContentProps } from "@/validations/mutual/dashboard/props";
import { resolveWhichPageToRenderMulti } from "@/pages/resolver/resolver";
import ContentToRenderNoPage from "@/pages/mutual/noContent/page";
const PageToBeChildrendMulti: React.FC<ContentProps> = async ({ lang, translations, activePageUrl, mode }) => {
const PageToBeChildrendMulti: React.FC<ContentProps> = async ({ lang, activePageUrl, mode }) => {
const ApplicationToRender = await resolveWhichPageToRenderMulti({ activePageUrl })
if (!ApplicationToRender) return <ContentToRenderNoPage lang={lang} />
return <ApplicationToRender lang={lang} translations={translations} activePageUrl={activePageUrl} mode={mode} />
return <ApplicationToRender lang={lang} activePageUrl={activePageUrl} mode={mode} />
}
export default PageToBeChildrendMulti

View File

@@ -2,18 +2,23 @@
import { FC, Suspense } from "react";
import { ContentProps, ModeTypes, ModeTypesList } from "@/validations/mutual/dashboard/props";
import LoadingContent from "@/components/mutual/loader/component";
import PageToBeChildrendSingle from "./PageToBeChildrendSingle";
import PageToBeChildrendMulti from "./PageToBeChildrendMulti";
const ContentComponent: FC<ContentProps> = async ({ lang, translations, activePageUrl, isMulti, mode }) => {
// const ContentComponent: FC<ContentProps> = async ({ lang, translations, activePageUrl, isMulti, mode }) => {
// const modeFromQuery = ModeTypesList.includes(mode || '') ? mode : 'shortList'
// const renderProps = { lang, translations, activePageUrl, mode: modeFromQuery as ModeTypes }
// const PageToBeChildrend = isMulti ? PageToBeChildrendMulti : PageToBeChildrendSingle
// const loadingContent = <LoadingContent height="h-16" size="w-36 h-48" plane="h-full w-full" />
// const classNameDiv = "fixed top-24 left-80 right-0 py-10 px-15 border-emerald-150 border-l-2 overflow-y-auto h-[calc(100vh-64px)]"
// return <div className={classNameDiv}><Suspense fallback={loadingContent}><PageToBeChildrend {...renderProps} /></Suspense></div>
// };
const ContentComponent: FC<ContentProps> = async ({ lang, activePageUrl, mode }) => {
const modeFromQuery = ModeTypesList.includes(mode || '') ? mode : 'shortList'
const renderProps = { lang, translations, activePageUrl, mode: modeFromQuery as ModeTypes }
const PageToBeChildrend = isMulti ? PageToBeChildrendMulti : PageToBeChildrendSingle
const renderProps = { lang, activePageUrl, mode: modeFromQuery as ModeTypes }
const loadingContent = <LoadingContent height="h-16" size="w-36 h-48" plane="h-full w-full" />
const classNameDiv = "fixed top-24 left-80 right-0 py-10 px-15 border-emerald-150 border-l-2 overflow-y-auto h-[calc(100vh-64px)]"
return (
<div className={classNameDiv}><Suspense fallback={loadingContent}><PageToBeChildrend {...renderProps} /></Suspense></div>
);
return <div className={classNameDiv}><Suspense fallback={loadingContent}><PageToBeChildrendMulti {...renderProps} /></Suspense></div>
};
export default ContentComponent;

View File

@@ -1,12 +1,23 @@
'use server';
import { FC } from "react";
import { langGetKey } from "@/lib/langGet";
import { FooterProps } from "@/validations/mutual/dashboard/props";
import { AllProps } from "@/validations/mutual/dashboard/props";
const FooterComponent: FC<FooterProps> = ({ translations }) => {
const translations = {
en: {
footer: "footer",
page: "page"
},
tr: {
footer: "footer",
page: "sayfa"
}
}
const FooterComponent: FC<AllProps> = ({ lang, activePageUrl, prefix, mode }) => {
return (
<div className="fixed text-center bottom-0 left-0 right-0 h-16 p-4 border-t border-emerald-150 border-t-2 shadow-sm backdrop-blur-sm bg-emerald-50">
<h1>{langGetKey(translations, "footer")}: {langGetKey(translations, "page")}</h1>
<h1>{langGetKey(translations[lang], "footer")}: {langGetKey(translations[lang], "page")}</h1>
</div>
);
};

View File

@@ -1,17 +1,35 @@
'use server';
import { FC } from "react";
import { HeaderProps } from "@/validations/mutual/dashboard/props";
'use client';
import { FC, useState, useEffect } from "react";
import { AllProps } from "@/validations/mutual/dashboard/props";
import LanguageSelectionComponent from "@/components/mutual/languageSelection/component";
import { langGetKey } from "@/lib/langGet";
import { checkContextPageOnline } from "@/components/mutual/context/online/context";
const HeaderComponent: FC<HeaderProps> = ({ translations, lang, activePageUrl, prefix }) => {
const translations = {
en: {
selectedPage: "selectedPage",
page: "page"
},
tr: {
selectedPage: "seçiliSayfa",
page: "sayfa"
}
}
const HeaderComponent: FC<AllProps> = ({ lang, activePageUrl, prefix, mode }) => {
const [online, setOnline] = useState(false);
useEffect(() => {
checkContextPageOnline().then((online) => {
setOnline(online);
});
}, []);
return (
<div className="flex justify-between h-24 items-center p-4 border-emerald-150 border-b-2 shadow-sm backdrop-blur-sm sticky top-0 z-50 bg-emerald-50">
<div className="flex flex-row justify-center items-center">
<p className="text-2xl font-bold mx-3">{langGetKey(translations, 'selectedPage')} :</p>
<p className="text-lg font-bold mx-3"> {langGetKey(translations, 'page')}</p>
<p className="text-2xl font-bold mx-3">{langGetKey(translations[lang], 'selectedPage')} :</p>
<p className="text-lg font-bold mx-3"> {langGetKey(translations[lang], 'page')}</p>
</div>
<div>{JSON.stringify(online)}</div>
<LanguageSelectionComponent lang={lang} activePage={activePageUrl} prefix={prefix} />
</div>
);

View File

@@ -1,11 +1,12 @@
'use client';
import { FC, useState, useEffect } from "react";
import { MenuProps } from "@/validations/mutual/dashboard/props";
import { langGetKey } from "@/lib/langGet";
import { AllProps } from "@/validations/mutual/dashboard/props";
import { parseURlFormString } from "@/lib/menuGet";
import { menuTranslation } from "@/languages/mutual/menu"
import FirstLayerDropdown from "./firstLayerComponent";
import SecondLayerDropdown from "./secondLayerComponent";
import ThirdLayerDropdown from "./thirdLayerComponent";
import { checkContextPageMenu } from "@/components/mutual/context/menu/context";
// Define types for menu structure
type ThirdLayerItem = Record<string, any>;
@@ -13,146 +14,109 @@ type SecondLayerItems = Record<string, ThirdLayerItem>;
type FirstLayerItems = Record<string, SecondLayerItems>;
type MenuStructure = FirstLayerItems;
const MenuComponent: FC<MenuProps> = ({ lang, menuItems, menuTranslationsFlatten, activePageUrl }) => {
// State for tracking expanded menu items
// Helper function to get translation for a URL path
const getMenuTranslation = (translations: any, urlPath: string) => {
if (translations[urlPath]) {
return translations[urlPath];
}
const cleanPath = urlPath.startsWith('/') ? urlPath.substring(1) : urlPath;
if (translations[cleanPath]) {
return translations[cleanPath];
}
const pathWithSlash = urlPath.startsWith('/') ? urlPath : `/${urlPath}`;
if (translations[pathWithSlash]) {
return translations[pathWithSlash];
}
const keys = Object.keys(translations);
for (const key of keys) {
const cleanKey = key.startsWith('/') ? key.substring(1) : key;
const cleanUrlPath = urlPath.startsWith('/') ? urlPath.substring(1) : urlPath;
if (cleanUrlPath.includes(cleanKey) || cleanKey.includes(cleanUrlPath)) {
return translations[key];
}
}
const parts = urlPath.split('/');
return parts[parts.length - 1] || urlPath;
};
const MenuComponent: FC<AllProps> = ({ lang, activePageUrl, prefix, mode }) => {
const [availableApplications, setAvailableApplications] = useState<string[]>([]);
useEffect(() => {
checkContextPageMenu().then((apps) => {
console.log('apps', apps);
setAvailableApplications(apps?.selectionList || []);
});
}, []);
const [expandedFirstLayer, setExpandedFirstLayer] = useState<string | null>(null);
const [expandedSecondLayer, setExpandedSecondLayer] = useState<string | null>(null);
const [menuStructure, setMenuStructure] = useState<MenuStructure>({});
// Parse active URL to determine which menu items should be active
const menuTranslationWLang = menuTranslation[lang];
const activePathLayers = parseURlFormString(activePageUrl).data;
const activeFirstLayer = activePathLayers[0] || null;
const activeSecondLayer = activePathLayers[1] || null;
const activeThirdLayer = activePathLayers[2] || null;
const activeThirdLayer = activePathLayers.slice(2, activePathLayers.length).join("/");
// Initialize expanded state based on active path
useEffect(() => {
if (activeFirstLayer) {
setExpandedFirstLayer(activeFirstLayer);
if (activeSecondLayer) {
setExpandedSecondLayer(activeSecondLayer);
const newMenuStructure: MenuStructure = {};
availableApplications.forEach((appPath: string) => {
const cleanPath = appPath.startsWith('/') ? appPath.substring(1) : appPath;
const pathParts = cleanPath.split('/');
if (pathParts.length >= 3) {
const firstLayer = pathParts[0];
const secondLayer = pathParts[1];
const thirdLayer = pathParts.slice(2).join('/');
if (!newMenuStructure[firstLayer]) { newMenuStructure[firstLayer] = {} }
if (!newMenuStructure[firstLayer][secondLayer]) { newMenuStructure[firstLayer][secondLayer] = {} }
newMenuStructure[firstLayer][secondLayer][thirdLayer] = true;
}
}
}, [activeFirstLayer, activeSecondLayer]);
// Process menu items into a hierarchical structure
useEffect(() => {
const processedStructure: MenuStructure = {};
Object.entries(menuItems).forEach(([path, _]: [string, any]) => {
const layers = parseURlFormString(path).data;
const firstLayer = layers[0];
const secondLayer = layers[1];
const thirdLayer = layers[2];
// Create first layer if it doesn't exist
if (!processedStructure[firstLayer]) {
processedStructure[firstLayer] = {};
}
// Create second layer if it doesn't exist
if (!processedStructure[firstLayer][secondLayer]) {
processedStructure[firstLayer][secondLayer] = {};
}
// Add third layer
processedStructure[firstLayer][secondLayer][thirdLayer] = {};
});
setMenuStructure(newMenuStructure);
}, [availableApplications]);
setMenuStructure(processedStructure);
}, [menuItems]);
useEffect(() => { if (activeFirstLayer) { setExpandedFirstLayer(activeFirstLayer); if (activeSecondLayer) { setExpandedSecondLayer(activeSecondLayer) } } }, [activeFirstLayer, activeSecondLayer]);
// Handle click on first layer menu item
const handleFirstLayerClick = (key: string) => {
if (expandedFirstLayer === key) {
// If already expanded, collapse it
setExpandedFirstLayer(null);
setExpandedSecondLayer(null);
} else {
// Otherwise expand it
setExpandedFirstLayer(key);
setExpandedSecondLayer(null);
}
};
const handleFirstLayerClick = (key: string) => { if (expandedFirstLayer === key) { setExpandedFirstLayer(null); setExpandedSecondLayer(null) } else { setExpandedFirstLayer(key); setExpandedSecondLayer(null) } };
const handleSecondLayerClick = (key: string) => { if (expandedSecondLayer === key) { setExpandedSecondLayer(null) } else { setExpandedSecondLayer(key) } };
// Handle click on second layer menu item
const handleSecondLayerClick = (key: string) => {
if (expandedSecondLayer === key) {
// If already expanded, collapse it
setExpandedSecondLayer(null);
} else {
// Otherwise expand it
setExpandedSecondLayer(key);
}
};
// Render third layer menu items
const renderThirdLayerItems = (firstLayerKey: string, secondLayerKey: string, thirdLayerItems: ThirdLayerItem) => {
const baseUrl = `/${firstLayerKey}/${secondLayerKey}`;
return Object.keys(thirdLayerItems).map(thirdLayerKey => {
const isActive =
activeFirstLayer === firstLayerKey &&
activeSecondLayer === secondLayerKey &&
activeThirdLayer === thirdLayerKey;
const isActive = activeFirstLayer === firstLayerKey && activeSecondLayer === secondLayerKey && activeThirdLayer === thirdLayerKey;
const mergeUrl = `${baseUrl}/${thirdLayerKey}`;
const url = `/${lang}${baseUrl}/${thirdLayerKey}`;
return (
<div key={`${thirdLayerKey}-item`} className="ml-2 my-1">
<ThirdLayerDropdown
isActive={isActive}
innerText={langGetKey(menuTranslationsFlatten, thirdLayerKey)}
url={url}
/>
</div>
);
console.log('mergeUrl', mergeUrl);
return <div key={`${thirdLayerKey}-item`} className="ml-2 my-1"><ThirdLayerDropdown isActive={isActive} innerText={getMenuTranslation(menuTranslationWLang, mergeUrl)} url={url} /></div>
});
};
// Render second layer menu items
const renderSecondLayerItems = (firstLayerKey: string, secondLayerItems: SecondLayerItems) => {
return Object.entries(secondLayerItems).map(([secondLayerKey, thirdLayerItems]) => {
const isActive = activeFirstLayer === firstLayerKey && activeSecondLayer === secondLayerKey;
const isExpanded = expandedSecondLayer === secondLayerKey;
const mergeUrl = `/${firstLayerKey}/${secondLayerKey}`;
console.log('mergeUrl', mergeUrl);
return (
<div key={`${secondLayerKey}-item`} className="ml-2 my-1">
<SecondLayerDropdown
isActive={isActive}
isExpanded={isExpanded}
innerText={langGetKey(menuTranslationsFlatten, secondLayerKey)}
onClick={() => handleSecondLayerClick(secondLayerKey)}
/>
{isExpanded && (
<div className="ml-2 mt-1">
{renderThirdLayerItems(firstLayerKey, secondLayerKey, thirdLayerItems)}
</div>
)}
<SecondLayerDropdown isActive={isActive} isExpanded={isExpanded} innerText={getMenuTranslation(menuTranslationWLang, mergeUrl)} onClick={() => handleSecondLayerClick(secondLayerKey)} />
{isExpanded && (<div className="ml-2 mt-1">{renderThirdLayerItems(firstLayerKey, secondLayerKey, thirdLayerItems)}</div>)}
</div>
);
});
};
// Render first layer menu items
const renderFirstLayerItems = () => {
return Object.entries(menuStructure).map(([firstLayerKey, secondLayerItems]) => {
const isActive = activeFirstLayer === firstLayerKey;
const isExpanded = expandedFirstLayer === firstLayerKey;
const mergeUrl = `/${firstLayerKey}`;
console.log('mergeUrl', mergeUrl);
return (
<div key={`${firstLayerKey}-item`} className="mb-2">
<FirstLayerDropdown
isActive={isActive}
isExpanded={isExpanded}
innerText={langGetKey(menuTranslationsFlatten, firstLayerKey)}
onClick={() => handleFirstLayerClick(firstLayerKey)}
/>
{isExpanded && (
<div className="mt-1">
{renderSecondLayerItems(firstLayerKey, secondLayerItems)}
</div>
)}
<FirstLayerDropdown isActive={isActive} isExpanded={isExpanded} innerText={getMenuTranslation(menuTranslationWLang, mergeUrl)} onClick={() => handleFirstLayerClick(firstLayerKey)} />
{isExpanded && (<div className="mt-1">{renderSecondLayerItems(firstLayerKey, secondLayerItems)}</div>)}
</div>
);
});

View File

@@ -0,0 +1,35 @@
import { ClientPageConfig } from "@/types/mutual/context/validations";
import { API_BASE_URL } from "@/config/config";
async function checkContextPageConfig(): Promise<ClientPageConfig> {
const result = await fetch(`${API_BASE_URL}/context/page/config`, {
method: "GET",
headers: { "Content-Type": "application/json" },
});
try {
const data = await result.json();
return data;
} catch (error) {
throw new Error("No data is found");
}
}
async function setContextPageConfig({
pageConfig,
}: {
pageConfig: ClientPageConfig;
}) {
const result = await fetch(`${API_BASE_URL}/context/page/config`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(pageConfig),
});
try {
const data = await result.json();
return data;
} catch (error) {
throw new Error("No data is set");
}
}
export { checkContextPageConfig, setContextPageConfig };

View File

@@ -0,0 +1,34 @@
import { ClientMenu } from "@/types/mutual/context/validations";
import { API_BASE_URL } from "@/config/config";
async function checkContextPageMenu() {
const result = await fetch(`${API_BASE_URL}/context/page/menu`, {
method: "GET",
headers: { "Content-Type": "application/json" },
});
try {
const data = await result.json();
console.log("checkContextPageMenu ", data);
if (data.status == 200) return data.data;
} catch (error) {
console.log(error);
throw new Error("No data is found");
}
}
async function setContextPageMenu(setMenu: ClientMenu) {
const result = await fetch(`${API_BASE_URL}/context/page/menu`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(setMenu),
});
try {
const data = await result.json();
return data;
} catch (error) {
console.log(error);
throw new Error("No data is set");
}
}
export { checkContextPageMenu, setContextPageMenu };

View File

@@ -0,0 +1,29 @@
import { ClientOnline } from "@/types/mutual/context/validations";
import { API_BASE_URL } from "@/config/config";
async function checkContextPageOnline() {
const result = await fetch(`${API_BASE_URL}/context/page/online`, {
method: "GET",
headers: { "Content-Type": "application/json" },
});
try {
const data = await result.json();
if (data.status == 200) return data.data;
} catch (error) {}
return null;
}
async function setContextPageOnline(setOnline: ClientOnline) {
const result = await fetch(`${API_BASE_URL}/context/page/online`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(setOnline),
});
try {
const data = await result.json();
if (data.status == 200) return data.data;
} catch (error) {}
return null;
}
export { checkContextPageOnline, setContextPageOnline };

View File

@@ -0,0 +1,37 @@
import { ClientSelection } from "@/types/mutual/context/validations";
import { API_BASE_URL } from "@/config/config";
async function checkContextDashSelection() {
try {
const result = await fetch(`${API_BASE_URL}/context/dash/selection`, {
method: "GET",
headers: { "Content-Type": "application/json" },
});
const data = await result.json();
if (data.status === 200) return data.data;
} catch (error) {}
return null;
}
async function setContextDashUserSelection({
userSet,
}: {
userSet: ClientSelection;
}) {
try {
const result = await fetch(`${API_BASE_URL}/context/dash/selection`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(userSet),
});
const data = await result.json();
if (data.status === 200) return data.data;
} catch (error) {
console.error("Error setting dash selection:", error);
}
return null;
}
export { checkContextDashSelection, setContextDashUserSelection };

View File

@@ -0,0 +1,33 @@
import { ClientUser } from "@/types/mutual/context/validations";
import { API_BASE_URL } from "@/config/config";
async function checkContextDashUserInfo(): Promise<ClientUser> {
const result = await fetch(`${API_BASE_URL}/context/dash/user`, {
method: "GET",
headers: { "Content-Type": "application/json" },
});
try {
const data = await result.json();
return data;
} catch (error) {
console.log(error);
throw new Error("No data is found");
}
}
async function setContextDashUserInfo({ userSet }: { userSet: ClientUser }) {
const result = await fetch(`${API_BASE_URL}/context/dash/user`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(userSet),
});
try {
const data = await result.json();
return data;
} catch (error) {
console.log(error);
throw new Error("No data is set");
}
}
export { checkContextDashUserInfo, setContextDashUserInfo };

View File

@@ -1,31 +1,25 @@
'use server';
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent } from "@/components/mutual/shadcnui/dropdown-menu";
'use client';
import { useState, useEffect } from "react";
import { DropdownMenu, DropdownMenuTrigger } from "@/components/mutual/shadcnui/dropdown-menu";
import { Button } from "@/components/mutual/shadcnui/button";
import { languageSelectionTranslation } from "@/languages/mutual/languageSelection";
import { langGetKey, langGet } from "@/lib/langGet";
import { LanguageTypes } from "@/validations/mutual/language/validations";
import { checkContextPageOnline, setContextPageOnline } from "@/components/mutual/context/online/context";
import LanguageSelectionItem from "./languageItem";
const LanguageSelectionComponent: React.FC<{ lang: LanguageTypes, activePage: string, prefix: string }> = ({ lang, activePage, prefix }) => {
const translations = langGet(lang, languageSelectionTranslation);
const getPageWithLocale = (locale: LanguageTypes): string => { return `${prefix}/${locale}/${activePage}` }
const englishButtonProps = {
activeLang: lang,
buttonsLang: "en",
refUrl: getPageWithLocale("en"),
innerText: langGetKey(translations, "english")
}
const turkishButtonProps = {
activeLang: lang,
buttonsLang: "tr",
refUrl: getPageWithLocale("tr"),
innerText: langGetKey(translations, "turkish")
}
const getPageWithLocale = (locale: LanguageTypes): string => { return `${prefix}/${activePage}` }
const [online, setOnline] = useState<any>({});
useEffect(() => { const online = checkContextPageOnline(); setOnline({ ...online, lang: lang }) }, []);
const englishButtonProps = { activeLang: lang, buttonsLang: "en", refUrl: getPageWithLocale("en"), innerText: langGetKey(translations, "english") }
const turkishButtonProps = { activeLang: lang, buttonsLang: "tr", refUrl: getPageWithLocale("tr"), innerText: langGetKey(translations, "turkish") }
return (
<div className="flex items-end justify-end">
<div>{JSON.stringify(online)}</div>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button className="w-48 h-12 text-center text-md">{langGetKey(translations, "title")}</Button>

View File

@@ -3,10 +3,21 @@ import { useState, FC } from "react";
import { DropdownMenuContent, DropdownMenuLabel } from "@/components/mutual/shadcnui/dropdown-menu";
import Link from "next/link";
import LoadingContent from "@/components/mutual/loader/component";
import { setContextPageOnline, checkContextPageOnline } from "@/components/mutual/context/online/context";
const RenderLinkComponent: FC<{ refUrl: string, innerText: string, setisL: (isLoading: boolean) => void }> = ({ refUrl, innerText, setisL }) => {
const RenderLinkComponent: FC<{ refUrl: string, innerText: string, setisL: (isLoading: boolean) => void, buttonsLang: string }> = (
{ refUrl, innerText, setisL, buttonsLang }) => {
const setOnline = async () => {
setisL(true);
const oldOnline = await checkContextPageOnline();
await setContextPageOnline({
...oldOnline,
lang: buttonsLang,
});
setisL(false);
}
return (
<Link replace href={refUrl} onClick={() => setisL(true)}>
<Link replace href={refUrl} onClick={() => { setOnline() }}>
<DropdownMenuContent className="flex w-48 h-12 align-center justify-center text-center text-md overflow-y-hidden">
<DropdownMenuLabel className="flex items-center justify-center">{innerText}</DropdownMenuLabel>
</DropdownMenuContent>
@@ -29,7 +40,7 @@ const LanguageSelectionItem: React.FC<{
}> = ({ activeLang, buttonsLang, refUrl, innerText }) => {
const [isL, setisL] = useState<boolean>(false);
const isC = buttonsLang !== activeLang
const RenderLinkProp = { refUrl, innerText, setisL }
const RenderLinkProp = { refUrl, innerText, setisL, buttonsLang }
return (
<>{isC && <>{isL ? <RenderLoadingComponent setisL={setisL} /> : <RenderLinkComponent {...RenderLinkProp} />}</>}</>
)

View File

@@ -1,14 +1,24 @@
import { LanguageTypes } from "@/validations/mutual/language/validations";
import { DynamicPage } from "@/validations/mutual/menu/menu";
import { managementAccountTenantMain } from "./management/account/tenantSomething/index";
import { managementAccountTenantMainSecond } from "./management/account/tenantSomethingSecond/index";
import { buildingPartsTenantSomething } from "./building/parts/tenantSomething/index";
// import { managementAccountTenantMainSecond } from "./management/account/tenantSomethingSecond/index";
// import { buildingPartsTenantSomething } from "./building/parts/tenantSomething/index";
const dynamicPagesIndex: Record<string, Record<LanguageTypes, DynamicPage>> = {
"main/pages/user/dashboard": managementAccountTenantMain,
"management/account/tenant/something": managementAccountTenantMain,
"management/account/tenant/somethingSecond": managementAccountTenantMainSecond,
"building/parts/tenant/something": buildingPartsTenantSomething,
"/main/pages/user/dashboard": managementAccountTenantMain,
"/definitions/identifications/people": managementAccountTenantMain,
"/definitions/identifications/users": managementAccountTenantMain,
"/definitions/building/parts": managementAccountTenantMain,
"/definitions/building/areas": managementAccountTenantMain,
"/building/accounts/managment/accounts": managementAccountTenantMain,
"/building/accounts/managment/budgets": managementAccountTenantMain,
"/building/accounts/parts/accounts": managementAccountTenantMain,
"/building/accounts/parts/budgets": managementAccountTenantMain,
"/building/meetings/regular/actions": managementAccountTenantMain,
"/building/meetings/regular/accounts": managementAccountTenantMain,
"/building/meetings/ergunt/actions": managementAccountTenantMain,
"/building/meetings/ergunt/accounts": managementAccountTenantMain,
"/building/meetings/invited/attendance": managementAccountTenantMain,
};
export { dynamicPagesIndex };

View File

@@ -1,11 +1,27 @@
const menuTranslationEn = {
"/management/account/something/something/something": "Account Third Layer",
"/management/account": "Account Second Layer",
"/management": "Management First Layer",
};
const menuIndex = [
"/management/account/something/something/something",
"/building/parts/something/something/something",
];
"/definitions": "Definitions",
"/definitions/identifications": "Identifications",
"/definitions/identifications/people": "People",
"/definitions/identifications/users": "Users",
export { menuTranslationEn, menuIndex };
"/definitions/building": "Building",
"/definitions/building/parts": "Build Parts",
"/definitions/building/areas": "Building Areas",
"/building": "Building",
"/building/accounts": "Account Actions",
"/building/accounts/managment/accounts": "Management Accounts",
"/building/accounts/managment/budgets": "Management Budgets",
"/building/accounts/parts/accounts": "Parts Accounts",
"/building/accounts/parts/budgets": "Parts Budgets",
"/building/meetings": "Meetings",
"/building/meetings/regular/actions": "Regular Meeting Actions",
"/building/meetings/regular/accounts": "Regular Meeting Accounts",
"/building/meetings/ergunt/actions": "Ergunt Meeting Actions",
"/building/meetings/ergunt/accounts": "Ergunt Meeting Accounts",
"/building/meetings/invited/attendance": "Meeting Invited Attendance",
};
export { menuTranslationEn };
// export { menuTranslationEn, menuIndex };

View File

@@ -1,3 +1,26 @@
const menuTranslationTr = {};
const menuTranslationTr = {
"/definitions": "Tanımlamalar",
"/definitions/identifications": "Tanımlamalar",
"/definitions/identifications/people": "Kişiler",
"/definitions/identifications/users": "Kullanıcılar",
"/definitions/building": "Bina",
"/definitions/building/parts": "Daireler",
"/definitions/building/areas": "Bina Alanları",
"/building": "Bina",
"/building/accounts": "Account Eylemleri",
"/building/accounts/managment/accounts": "Bina Hesapları",
"/building/accounts/managment/budgets": "Bina Bütçesi",
"/building/accounts/parts/accounts": "Daire Hesapları",
"/building/accounts/parts/budgets": "Daire Bütçesi",
"/building/meetings": "Toplantılar",
"/building/meetings/regular/actions": "Düzenli Toplantı Eylemleri",
"/building/meetings/regular/accounts": "Düzenli Toplantı Accounts",
"/building/meetings/ergunt/actions": "Ergunt Toplantı Eylemleri",
"/building/meetings/ergunt/accounts": "Ergunt Toplantı Accounts",
"/building/meetings/invited/attendance": "Toplantı Davetli Katılımlar",
};
export { menuTranslationTr };

View File

@@ -1,8 +1,5 @@
'use server';
import { FC } from "react";
import { joinPageUrlFromLayersArray, retrieveLayersOfUrlFromParams } from "@/lib/menuGet";
import { dynamicPagesIndex } from "@/languages/custom";
import { dynamicPageMenuWithLayersGet, dynamicRetrieveMenuFlattenGet, langDynamicPagesGet, langGet } from "@/lib/langGet";
import { DashboardLayoutProps, ModeTypes } from "@/validations/mutual/dashboard/props";
import HeaderComponent from "@/components/custom/header/component";
@@ -11,26 +8,18 @@ import ContentComponent from "@/components/custom/content/component";
import FooterComponent from "@/components/custom/footer/component";
const DashboardLayout: FC<DashboardLayoutProps> = async ({ params, searchParams, lang }) => {
const layersItems = retrieveLayersOfUrlFromParams(params.page);
const activePageUrl = joinPageUrlFromLayersArray(layersItems.data);
const mode = (searchParams?.mode as ModeTypes) || 'shortList';
const menuItems = await dynamicPageMenuWithLayersGet(lang);
const translations = langGet(lang, langDynamicPagesGet(activePageUrl, dynamicPagesIndex));
const menuTranslationsFlatten = dynamicRetrieveMenuFlattenGet(menuItems);
const headerProps = { translations: translations.header, lang, activePageUrl, prefix: "/panel" }
const menuProps = { lang, activePageUrl, menuTranslationsFlatten, menuItems }
const contentProps = { translations: translations.content, lang, activePageUrl, mode, isMulti: true }
const activePageUrl = `/${params.page?.join('/')}`;
const allProps = { lang, activePageUrl, mode, prefix: "/panel" }
return (
<div className="flex flex-col min-w-screen">
<HeaderComponent {...headerProps} />
<MenuComponent {...menuProps} />
<ContentComponent {...contentProps} />
<FooterComponent translations={translations.footer} />
<HeaderComponent {...allProps} />
<MenuComponent {...allProps} />
<ContentComponent {...allProps} />
<FooterComponent {...allProps} />
</div>
);
}
export { DashboardLayout };
export { DashboardLayout };

View File

@@ -1,21 +1,21 @@
import { ContentProps } from "@/validations/mutual/dashboard/props";
import superUserTenantSomething from "./management/account/tenantSomething/page";
import superUserTenantSomethingSecond from "./management/account/tenantSomethingSecond/page";
import superUserBuildingPartsTenantSomething from "./building/parts/tenantSomething/page";
const pageIndexMulti: Record<string, Record<string, React.FC<ContentProps>>> = {
"main/pages/user/dashboard": {
superUserTenantSomething: superUserTenantSomething,
},
"management/account/tenant/something": {
superUserTenantSomething: superUserTenantSomething,
},
"management/account/tenant/somethingSecond": {
superUserTenantSomething: superUserTenantSomethingSecond,
},
"building/parts/tenant/something": {
superUserTenantSomething: superUserBuildingPartsTenantSomething,
},
"/main/pages/user/dashboard": { superUserTenantSomething },
"/definitions/identifications/people": { superUserTenantSomething },
"/definitions/identifications/users": { superUserTenantSomething },
"/definitions/building/parts": { superUserTenantSomething },
"/definitions/building/areas": { superUserTenantSomething },
"/building/accounts/managment/accounts": { superUserTenantSomething },
"/building/accounts/managment/budgets": { superUserTenantSomething },
"/building/accounts/parts/accounts": { superUserTenantSomething },
"/building/accounts/parts/budgets": { superUserTenantSomething },
"/building/meetings/regular/actions": { superUserTenantSomething },
"/building/meetings/regular/accounts": { superUserTenantSomething },
"/building/meetings/ergunt/actions": { superUserTenantSomething },
"/building/meetings/ergunt/accounts": { superUserTenantSomething },
"/building/meetings/invited/attendance": { superUserTenantSomething },
};
export default pageIndexMulti;

View File

@@ -0,0 +1,187 @@
// From Redis objects
interface ClientOnline {
lastLogin: Date;
lastLogout: Date;
lastAction: Date;
lastPage: string;
userType: string;
lang: string;
timezone: string;
}
interface ClientPageConfig {
mode: string;
textFont: number;
theme: string;
}
interface ClientHeader {
header: any[];
activeDomain: string;
listOfDomains: string[];
connections: any[];
}
interface ClientMenu {
selectionList: string[];
activeSelection: string;
}
interface ClientSelection {
selectionList: any[];
activeSelection: Record<string, any>;
}
interface ClientUser {
uuid: string;
avatar: string;
email: string;
phone_number: string;
user_tag: string;
password_expiry_begins: string;
person: {
uuid: string;
firstname: string;
surname: string;
middle_name: string;
sex_code: string;
person_tag: string;
country_code: string;
birth_date: string;
};
}
interface ClientSettings {
lastOnline: Date;
token: string;
}
interface LinkList {
linkList: any[];
}
interface ClientRedisToken {
online: ClientOnline;
pageConfig: ClientPageConfig;
menu: ClientMenu;
header: ClientHeader;
selection: ClientSelection;
user: ClientUser;
settings: ClientSettings;
chatRoom: LinkList;
notifications: LinkList;
messages: LinkList;
}
const defaultClientOnline: ClientOnline = {
lastLogin: new Date(),
lastLogout: new Date(),
lastAction: new Date(),
lastPage: "/dashboard",
userType: "employee",
lang: "tr",
timezone: "GMT+3",
};
const defaultClientPageConfig: ClientPageConfig = {
mode: "light",
textFont: 14,
theme: "default",
};
const defaultClientMenu: ClientMenu = {
selectionList: [],
activeSelection: "/dashboard",
};
const defaultClientHeader: ClientHeader = {
header: [],
activeDomain: "",
listOfDomains: [],
connections: [],
};
const defaultClientSelection: ClientSelection = {
selectionList: [],
activeSelection: {},
};
const defaultClientUser: ClientUser = {
uuid: "",
avatar: "",
email: "",
phone_number: "",
user_tag: "",
password_expiry_begins: new Date().toISOString(),
person: {
uuid: "",
firstname: "",
surname: "",
middle_name: "",
sex_code: "",
person_tag: "",
country_code: "",
birth_date: "",
},
};
const defaultClientSettings: ClientSettings = {
lastOnline: new Date(),
token: "",
};
const defaultLinkList: LinkList = {
linkList: [],
};
const defaultClientRedisToken: ClientRedisToken = {
online: defaultClientOnline,
pageConfig: defaultClientPageConfig,
menu: defaultClientMenu,
header: defaultClientHeader,
selection: defaultClientSelection,
user: defaultClientUser,
settings: defaultClientSettings,
chatRoom: defaultLinkList,
notifications: defaultLinkList,
messages: defaultLinkList,
};
const generateRedisKey = (userType: string, uuId: string) => {
const userTypeToUpper = userType.toUpperCase();
if (!userTypeToUpper || !uuId) throw new Error("Invalid user type or uuId");
return `CLIENT:${userTypeToUpper}:${uuId}`;
};
const readRedisKey = (redisKey: string) => {
if (redisKey.split(":").length !== 2) throw new Error("Invalid redis key");
const userTypeToUpper = redisKey.split(":")[1];
const uuId = redisKey.split(":")[2];
if (!userTypeToUpper || !uuId) throw new Error("Invalid user type or uuId");
return { userType: userTypeToUpper.toLowerCase(), uuId };
};
export {
defaultClientOnline,
defaultClientPageConfig,
defaultClientMenu,
defaultClientHeader,
defaultClientSelection,
defaultClientUser,
defaultClientSettings,
defaultLinkList,
defaultClientRedisToken,
};
export type {
ClientOnline,
ClientPageConfig,
ClientMenu,
ClientHeader,
ClientSelection,
ClientUser,
ClientSettings,
LinkList,
ClientRedisToken,
};
export { generateRedisKey, readRedisKey };

View File

@@ -0,0 +1,44 @@
interface FetcherRequest {
url: string;
isNoCache: boolean;
}
interface PostFetcherRequest<T> extends FetcherRequest {
body: Record<string, T>;
}
interface GetFetcherRequest extends FetcherRequest {
url: string;
}
interface DeleteFetcherRequest extends GetFetcherRequest {}
interface PutFetcherRequest<T> extends PostFetcherRequest<T> {}
interface PatchFetcherRequest<T> extends PostFetcherRequest<T> {}
interface FetcherRespose {
success: boolean;
}
interface PaginationResponse {
onPage: number;
onPageCount: number;
totalPage: number;
totalCount: number;
next: boolean;
back: boolean;
}
interface FetcherDataResponse<T> extends FetcherRespose {
data: Record<string, T> | null;
pagination?: PaginationResponse;
}
export type {
FetcherRequest,
PostFetcherRequest,
GetFetcherRequest,
DeleteFetcherRequest,
PutFetcherRequest,
PatchFetcherRequest,
FetcherRespose,
FetcherDataResponse,
};

View File

@@ -17,28 +17,24 @@ const ModeTypesList = ["shortList", "fullList", "create", "update", "view"];
interface ContentProps {
lang: LanguageTypes;
translations: Record<string, string>;
activePageUrl: string;
isMulti?: boolean;
mode?: ModeTypes;
}
interface MenuProps {
lang: LanguageTypes;
menuItems: Record<string, Record<string, any>>;
availableApplications: string[];
activePageUrl: string;
menuTranslationsFlatten: Record<string, Record<string, any>>;
}
interface FooterProps {
translations: Record<string, string>;
}
interface FooterProps {}
interface HeaderProps {
translations: Record<string, string>;
interface AllProps {
lang: LanguageTypes;
activePageUrl: string;
prefix: string;
mode?: ModeTypes;
}
export type {
@@ -47,7 +43,7 @@ export type {
ContentProps,
MenuProps,
FooterProps,
HeaderProps,
AllProps,
ModeTypes,
};

View File

@@ -19,14 +19,12 @@ export function loginHook(
.then((response) => {
if (response.status === 200) {
response.json().then((data) => {
console.log("data", data); // setJsonText(JSON.stringify(data));
setTimeout(() => {
const userType =
data?.data?.user_type.toLowerCase() === "employee"
? "employee"
: "occupant";
const rediretUrl = `/auth/${lang}/select?type=${userType}`;
console.log("rediretUrl", rediretUrl);
const rediretUrl = `/auth/select?type=${userType}`;
Router.push(rediretUrl);
}, 100);
});

View File

@@ -1,30 +1,57 @@
"use client";
import React, { useTransition, useState } from "react";
import React, { useTransition, useState, useEffect } from "react";
import { useRouter } from "next/navigation";
import { Company } from "./types";
import { LoginEmployeeProps } from "./types";
import { selectEmployeeHook } from "./hook";
import { checkContextDashSelection } from "@/components/mutual/context/selection/context";
import { ClientSelection } from "@/types/mutual/context/validations";
const translation = {
en: {
companySelection: "Company Selection",
loggedInAs: "Logged in as",
duty: "Duty",
id: "ID",
noSelections: "No selections",
continue: "Continue",
select: "Select"
},
tr: {
companySelection: "Şirket Seçimi",
loggedInAs: "Giriş Yapan",
duty: "Görev",
id: "ID",
noSelections: "Seçim Yok",
continue: "Devam Et",
select: "Seç"
}
}
function LoginEmployee({
selectionList,
translation,
lang
}: LoginEmployeeProps) {
const isArrayLengthOne = Array.isArray(selectionList) && selectionList.length === 1;
const isArrayLengthZero = Array.isArray(selectionList) && selectionList.length === 0;
const isArrayMoreThanOne = Array.isArray(selectionList) && selectionList.length > 1;
const [selectionListCopy, setSelectionListCopy] = useState<ClientSelection>({ selectionList: [], activeSelection: {} });
useEffect(() => {
checkContextDashSelection().then((selectionList) => {
if (!selectionList) throw new Error("No selection list found");
setSelectionListCopy(selectionList)
})
}, [])
const isArrayLengthOne = Array.isArray(selectionListCopy.selectionList) && selectionListCopy.selectionList.length === 1;
const isArrayLengthZero = Array.isArray(selectionListCopy.selectionList) && selectionListCopy.selectionList.length === 0;
const isArrayMoreThanOne = Array.isArray(selectionListCopy.selectionList) && selectionListCopy.selectionList.length > 1;
const Router = useRouter();
const [isPending, startTransition] = useTransition();
const [error, setError] = useState<string | null>(null);
const [jsonText, setJsonText] = useState<string | null>(null);
const onSubmitEmployee = async (uu_id: string) => {
selectEmployeeHook(startTransition, { company_uu_id: uu_id }, setError, setJsonText, Router, lang)
};
const onSubmitEmployee = async (uu_id: string) => { selectEmployeeHook(startTransition, { uuid: uu_id }, setError, setJsonText, Router, lang) };
// Render a company card with consistent styling
const CompanyCard = ({ company, showButton = false }: { company: Company, showButton?: boolean }) => (
const CompanyCard = ({ company }: { company: Company }) => (
<div className="w-full p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md transition-all">
<div className="flex flex-col" onClick={() => onSubmitEmployee(company.uu_id)}>
{/* Company name and type */}
@@ -40,13 +67,13 @@ function LoginEmployee({
{/* Duty information */}
{company.duty && (
<div className="mb-2 text-sm text-gray-600">
<span className="font-medium">{translation.duty}:</span> {company.duty}
<span className="font-medium">{translation[lang].duty}:</span> {company.duty}
</div>
)}
{/* ID information */}
<div className="text-xs text-gray-500 mb-3">
<span className="font-medium">{translation.id}:</span> {company.uu_id}
<span className="font-medium">{translation[lang].id}:</span> {company.uu_id}
</div>
</div>
@@ -55,30 +82,26 @@ function LoginEmployee({
return (
<div className="w-full max-w-md mx-auto">
<h1 className="text-2xl font-bold text-gray-900 mb-2">{translation.companySelection}</h1>
<p className="text-sm text-gray-500 mb-6">{translation.loggedInAs}</p>
<h1 className="text-2xl font-bold text-gray-900 mb-2">{translation[lang].companySelection}</h1>
<p className="text-sm text-gray-500 mb-6">{translation[lang].loggedInAs}</p>
{/* No companies available */}
{isArrayLengthZero && (
<div className="text-center p-6 bg-gray-50 rounded-lg border border-gray-200">
<p className="text-gray-600">{translation.noSelections}</p>
<p className="text-gray-600">{translation[lang].noSelections}</p>
</div>
)}
{/* Single company */}
{isArrayLengthOne && <CompanyCard company={selectionList[0]} showButton={true} />}
{isArrayLengthOne && <CompanyCard company={selectionListCopy.activeSelection as Company} />}
{/* Multiple companies */}
{isArrayMoreThanOne && (
<div className="space-y-3">
{selectionList.map((company, index) => (
<div
key={company.uu_id || index}
onClick={() => onSubmitEmployee(company.uu_id)}
{selectionListCopy.selectionList.map((company, index) => (
<div key={company.uu_id || index} onClick={() => onSubmitEmployee(company.uu_id)}
className="cursor-pointer hover:translate-x-1 transition-transform"
>
<CompanyCard company={company} />
</div>
><CompanyCard company={company as Company} /></div>
))}
</div>
)}

View File

@@ -3,24 +3,38 @@ import React, { useState, useTransition, useEffect } from "react";
import { useRouter } from "next/navigation";
import { LoginOccupantProps } from "./types";
import { selectOccupantHook } from "./hook";
import { checkContextDashSelection } from "@/components/mutual/context/selection/context";
import { ClientSelection } from "@/types/mutual/context/validations";
function LoginOccupant({
selectionList,
translation,
lang
}: LoginOccupantProps) {
const translation = {
en: {
occupantSelection: "Occupant Selection",
loggedInAs: "Logged in as",
level: "Level",
noSelections: "No selections"
},
tr: {
occupantSelection: "İşçi Seçimi",
loggedInAs: "Giriş Yapan",
level: "Seviye",
noSelections: "Seçim Yok"
}
}
function LoginOccupant({ lang }: LoginOccupantProps) {
const Router = useRouter();
const [isPending, startTransition] = useTransition();
const [error, setError] = useState<string | null>(null);
const [jsonText, setJsonText] = useState<string | null>(null);
const [selectionList, setSelectionList] = useState<ClientSelection>({ selectionList: [], activeSelection: {} });
const onSubmitOccupant = async (data: any) => {
selectOccupantHook(startTransition, data, setError, setJsonText, Router, lang)
};
const isArrayLengthZero = Array.isArray(selectionList) && selectionList.length === 0;
// Render an occupant card with consistent styling
useEffect(() => {
checkContextDashSelection().then((selectionList) => {
if (!selectionList) throw new Error("No selection list found"); setSelectionList(selectionList);
})
}, [])
const onSubmitOccupant = async (data: any) => { selectOccupantHook(startTransition, data, setError, setJsonText, Router, lang) };
const isArrayLengthZero = Array.isArray(selectionList.selectionList) && selectionList.selectionList.length === 0;
const OccupantCard = ({ occupant, buildKey, idx }: { occupant: any, buildKey: string, idx: number }) => (
<div
key={`${buildKey}-${idx}`}
@@ -28,28 +42,21 @@ function LoginOccupant({
onClick={() => onSubmitOccupant({ build_living_space_uu_id: occupant.build_living_space_uu_id })}
>
<div className="flex flex-col">
{/* Occupant description and code */}
<div className="flex items-center justify-between mb-2">
<h3 className="text-lg font-semibold text-gray-800">{occupant.description}</h3>
<span className="px-2 py-1 text-xs font-medium bg-blue-100 text-blue-800 rounded-full">
{occupant.code}
</span>
</div>
{/* Part name */}
<div className="mb-1 text-sm text-gray-700 font-medium">
{occupant.part_name}
</div>
{/* Level information */}
<div className="text-xs text-gray-500">
<span className="font-medium">{translation.level}:</span> {occupant.part_level}
<span className="font-medium">{translation[lang].level}:</span> {occupant.part_level}
</div>
</div>
</div>
);
// Render a building section with its occupants
const BuildingSection = ({ building, buildKey }: { building: any, buildKey: string }) => (
<div key={buildKey} className="mb-6">
<div className="p-3 bg-gray-50 border border-gray-200 rounded-lg mb-3">
@@ -72,31 +79,25 @@ function LoginOccupant({
return (
<div className="w-full max-w-md mx-auto">
<h1 className="text-2xl font-bold text-gray-900 mb-2">{translation.occupantSelection}</h1>
<p className="text-sm text-gray-500 mb-6">{translation.loggedInAs}</p>
<h1 className="text-2xl font-bold text-gray-900 mb-2">{translation[lang].occupantSelection}</h1>
<p className="text-sm text-gray-500 mb-6">{translation[lang].loggedInAs}</p>
{/* No occupants available */}
{!isArrayLengthZero ? (
<div className="text-center p-6 bg-gray-50 rounded-lg border border-gray-200">
<p className="text-gray-600">{translation.noSelections}</p>
<p className="text-gray-600">{translation[lang].noSelections}</p>
</div>
) : (
/* Building sections with occupants */
<div>
{Object.keys(selectionList).map((buildKey: string) => (
{Object.keys(selectionList.selectionList).map((buildKey: string) => (
<BuildingSection
key={buildKey}
building={selectionList[buildKey]}
building={selectionList.activeSelection}
buildKey={buildKey}
/>
))}
</div>
)}
{/* Show error if any */}
{error && <p className="mt-4 text-sm text-red-600">{error}</p>}
{/* Loading indicator */}
{isPending && (
<div className="mt-4 flex justify-center">
<div className="animate-spin h-5 w-5 border-2 border-blue-600 rounded-full border-t-transparent"></div>

View File

@@ -1,7 +1,7 @@
import { LanguageTypes } from "@/validations/mutual/language/validations";
const afterLoginDirectUrl = (lang: LanguageTypes) => {
return `/panel/${lang}/main/pages/user/dashboard`;
const afterLoginDirectUrl = () => {
return `/panel/dashboard`;
};
function selectEmployeeHook(
@@ -25,7 +25,7 @@ function selectEmployeeHook(
response.json().then((data) => {
console.log("data", data);
setTimeout(() => {
Router.push(afterLoginDirectUrl(lang));
Router.push(afterLoginDirectUrl());
}, 100);
});
} else {
@@ -62,7 +62,7 @@ function selectOccupantHook(
response.json().then((data) => {
console.log("data", data);
setTimeout(() => {
Router.push(afterLoginDirectUrl(lang));
Router.push(afterLoginDirectUrl());
}, 100);
});
} else {

View File

@@ -1,39 +1,18 @@
"use client";
import { useState, useEffect } from "react";
import LoginOccupant from "./LoginOccupant";
import LoginEmployee from "./LoginEmployee";
import { Company, SelectListProps, BuildingMap } from "./types";
import { selectEmployeeTranslation, selectOccupantTranslation } from "./language";
const Select: React.FC<SelectListProps> = ({ selectionList, isEmployee, isOccupant, language, query }) => {
const isEmployeee = query?.isEmployee == "true";
const isOccupante = query?.isOccupant == "true";
const userType = isEmployeee || isOccupante ? isEmployeee ? "employee" : "occupant" : "employee";
const isEmployeeTrue = userType == "employee" && Array.isArray(selectionList)
const isOccupantTrue = userType == "occupant" && !Array.isArray(selectionList)
const initTranslation = userType == "employee" ? selectEmployeeTranslation[language] : selectOccupantTranslation[language]
const [translation, setTranslation] = useState(initTranslation);
const [listEmployeeSelection, setListEmployeeSelection] = useState<Company[]>(selectionList as Company[]);
const [listOccupantSelection, setListOccupantSelection] = useState<BuildingMap>(selectionList as BuildingMap);
useEffect(() => {
if (isEmployee) { setListEmployeeSelection(selectionList as Company[]) }
else if (isOccupant) { setListOccupantSelection(selectionList as BuildingMap) }
}, []);
useEffect(() => {
setTranslation(isEmployee ? selectEmployeeTranslation[language] : selectOccupantTranslation[language]);
}, [language]);
import { SelectListProps } from "./types";
const Select: React.FC<SelectListProps> = ({ language, query }) => {
const isEmployeee = query?.type == "employee";
const isOccupante = query?.type == "occupant";
return (
<>
<div className="flex h-full min-h-[inherit] flex-col items-center justify-center gap-4">
<div className="w-full max-w-md rounded-lg bg-white p-8 shadow-md">
{isEmployeeTrue && <LoginEmployee translation={translation} selectionList={listEmployeeSelection} lang={language} />}
{isOccupantTrue && <LoginOccupant translation={translation} selectionList={listOccupantSelection} lang={language} />}
{isEmployeee && <LoginEmployee lang={language} />}
{isOccupante && <LoginOccupant lang={language} />}
</div>
</div>
</>

View File

@@ -3,18 +3,15 @@ import React, { FC } from "react";
import Select from "./page";
import { redirect } from "next/navigation";
import { checkAccessTokenIsValid, retrieveUserType } from "@/apicalls/mutual/cookies/token";
import { AuthPageProps } from "@/validations/mutual/auth/props";
const SelectPage: FC<AuthPageProps> = async ({ query, language }) => {
const token_is_valid = await checkAccessTokenIsValid();
const selection = await retrieveUserType();
const isEmployee = selection?.userType == "employee";
const isOccupant = selection?.userType == "occupant";
const selectionList = selection?.selectionList;
if (!selectionList || !token_is_valid) { redirect("/auth/en/login") }
return <Select selectionList={selectionList} isEmployee={isEmployee} isOccupant={isOccupant} language={language} query={query} />
try {
return <Select language={language} query={query} />;
} catch (error) {
redirect("/auth/login");
return null;
}
}
export default SelectPage;

View File

@@ -1,3 +1,4 @@
import { ClientSelection } from "@/types/mutual/context/validations";
import { LanguageTypes } from "@/validations/mutual/language/validations";
interface Company {
@@ -30,22 +31,15 @@ interface BuildingMap {
}
interface SelectListProps {
selectionList: Company[] | BuildingMap;
isEmployee: boolean;
isOccupant: boolean;
language: LanguageTypes;
query?: { [key: string]: string | string[] | undefined };
}
interface LoginOccupantProps {
selectionList: BuildingMap;
translation: any;
lang: LanguageTypes;
}
interface LoginEmployeeProps {
selectionList: Company[];
translation: any;
lang: LanguageTypes;
}