tested client-fronted login session
This commit is contained in:
parent
82d16ed3c9
commit
6ce95b5df6
|
|
@ -44,10 +44,7 @@ async function coreFetch<T>(
|
|||
const { method = "POST", cache = false, timeout = DEFAULT_TIMEOUT } = options;
|
||||
|
||||
try {
|
||||
// Setup controller for timeout handling
|
||||
const controller = new AbortController();
|
||||
|
||||
// Prepare fetch options
|
||||
const fetchOptions: RequestInit = {
|
||||
method,
|
||||
headers,
|
||||
|
|
@ -55,26 +52,17 @@ async function coreFetch<T>(
|
|||
signal: controller.signal,
|
||||
};
|
||||
|
||||
// Add body for non-GET requests with payload
|
||||
if (method !== "GET" && payload) {
|
||||
fetchOptions.body = JSON.stringify(
|
||||
payload.payload ? payload.payload : payload
|
||||
);
|
||||
}
|
||||
|
||||
// Create timeout promise
|
||||
const timeoutPromise = createTimeoutPromise(timeout, controller);
|
||||
|
||||
// Execute request with timeout
|
||||
const response = await Promise.race([
|
||||
fetch(url, fetchOptions),
|
||||
timeoutPromise,
|
||||
]);
|
||||
|
||||
// Parse response
|
||||
const responseData = await response.json();
|
||||
|
||||
// Return standardized response
|
||||
return {
|
||||
status: response.status,
|
||||
data: responseData || ({} as T),
|
||||
|
|
@ -116,12 +104,8 @@ async function fetchDataWithToken<T>(
|
|||
cache: boolean = false,
|
||||
timeout: number = DEFAULT_TIMEOUT
|
||||
): Promise<ApiResponse<T>> {
|
||||
const accessToken = (await retrieveAccessToken());
|
||||
const headers = {
|
||||
...defaultHeaders,
|
||||
"eys-acs-tkn": accessToken,
|
||||
};
|
||||
|
||||
const accessToken = await retrieveAccessToken();
|
||||
const headers = { ...defaultHeaders, "eys-acs-tkn": accessToken };
|
||||
return coreFetch<T>(endpoint, { method, cache, timeout }, headers, payload);
|
||||
}
|
||||
|
||||
|
|
@ -136,12 +120,8 @@ async function updateDataWithToken<T>(
|
|||
cache: boolean = false,
|
||||
timeout: number = DEFAULT_TIMEOUT
|
||||
): Promise<ApiResponse<T>> {
|
||||
const accessToken = (await retrieveAccessToken()) || "";
|
||||
const headers = {
|
||||
...defaultHeaders,
|
||||
"eys-acs-tkn": accessToken,
|
||||
};
|
||||
|
||||
const accessToken = await retrieveAccessToken();
|
||||
const headers = { ...defaultHeaders, "eys-acs-tkn": accessToken };
|
||||
return coreFetch<T>(
|
||||
`${endpoint}/${uuid}`,
|
||||
{ method, cache, timeout },
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { redis } from "@/lib/redis";
|
||||
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
|
||||
import { ClientRedisToken } from "@/types/mutual/context/validations";
|
||||
import { AuthError } from "@/types/mutual/context/validations";
|
||||
|
||||
// Redis operation timeout (5 seconds)
|
||||
const REDIS_TIMEOUT = 5000;
|
||||
|
|
@ -76,51 +77,20 @@ const defaultValues: ClientRedisToken = {
|
|||
const getCompleteFromRedis = async (): Promise<ClientRedisToken> => {
|
||||
try {
|
||||
let decrpytUserSelection;
|
||||
try {
|
||||
decrpytUserSelection = await functionRetrieveUserSelection();
|
||||
} catch (error) {
|
||||
console.error('Error retrieving user selection:', error);
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
try { decrpytUserSelection = await functionRetrieveUserSelection() } catch (error) { return defaultValues }
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
|
||||
if (!redisKey) {
|
||||
console.error("No redis key found in user selection");
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
if (redisKey === "default") {
|
||||
return defaultValues;
|
||||
}
|
||||
if (!redisKey) { return defaultValues }
|
||||
if (redisKey === "default") { return defaultValues }
|
||||
|
||||
try {
|
||||
const timeoutPromise = new Promise<string | null>((_, reject) => {
|
||||
setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT);
|
||||
});
|
||||
|
||||
// Race the Redis operation against the timeout
|
||||
const result = await Promise.race([
|
||||
redis.get(`${redisKey}`),
|
||||
timeoutPromise
|
||||
]);
|
||||
|
||||
if (!result) {
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
try {
|
||||
const parsedResult = JSON.parse(result);
|
||||
return parsedResult;
|
||||
} catch (parseError) {
|
||||
return defaultValues;
|
||||
}
|
||||
} catch (redisError) {
|
||||
return defaultValues;
|
||||
}
|
||||
} catch (error) {
|
||||
return defaultValues;
|
||||
}
|
||||
const result = await Promise.race([redis.get(`${redisKey}`), timeoutPromise]);
|
||||
if (!result) { return defaultValues }
|
||||
try { const parsedResult = JSON.parse(result); return parsedResult } catch (parseError) { return defaultValues }
|
||||
} catch (redisError) { return defaultValues }
|
||||
} catch (error) { return defaultValues }
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -130,41 +100,18 @@ const getCompleteFromRedis = async (): Promise<ClientRedisToken> => {
|
|||
*/
|
||||
const setCompleteToRedis = async (completeObject: ClientRedisToken): Promise<boolean> => {
|
||||
try {
|
||||
if (!completeObject) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!completeObject) { return false }
|
||||
let decrpytUserSelection;
|
||||
try {
|
||||
decrpytUserSelection = await functionRetrieveUserSelection();
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!decrpytUserSelection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try { decrpytUserSelection = await functionRetrieveUserSelection() } catch (error) { return false }
|
||||
if (!decrpytUserSelection) { return false }
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (!redisKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!redisKey) { return false }
|
||||
try {
|
||||
const timeoutPromise = new Promise((_, reject) => {
|
||||
setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT);
|
||||
});
|
||||
await Promise.race([
|
||||
redis.set(redisKey, JSON.stringify(completeObject)),
|
||||
timeoutPromise
|
||||
]);
|
||||
const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT) });
|
||||
await Promise.race([redis.set(redisKey, JSON.stringify(completeObject)), timeoutPromise]);
|
||||
return true;
|
||||
} catch (redisError) {
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
} catch (redisError) { return false }
|
||||
} catch (error) { return false }
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -175,29 +122,14 @@ const setCompleteToRedis = async (completeObject: ClientRedisToken): Promise<boo
|
|||
*/
|
||||
const setNewCompleteToRedis = async (completeObject: ClientRedisToken, redisKey: string): Promise<boolean> => {
|
||||
try {
|
||||
if (!redisKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!completeObject) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!redisKey) { return false }
|
||||
if (!completeObject) { return false }
|
||||
try {
|
||||
const timeoutPromise = new Promise((_, reject) => {
|
||||
setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT);
|
||||
});
|
||||
await Promise.race([
|
||||
redis.set(redisKey, JSON.stringify(completeObject)),
|
||||
timeoutPromise
|
||||
]);
|
||||
const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT) });
|
||||
await Promise.race([redis.set(redisKey, JSON.stringify(completeObject)), timeoutPromise])
|
||||
return true;
|
||||
} catch (redisError) {
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
} catch (redisError) { return false }
|
||||
} catch (error) { return false }
|
||||
}
|
||||
|
||||
export { getCompleteFromRedis, setCompleteToRedis, setNewCompleteToRedis };
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ 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";
|
||||
import { AuthError } from "@/types/mutual/context/validations";
|
||||
|
||||
const getSelectionFromRedis = async (): Promise<ClientSelection> => {
|
||||
try {
|
||||
|
|
@ -18,15 +19,28 @@ const getSelectionFromRedis = async (): Promise<ClientSelection> => {
|
|||
}
|
||||
|
||||
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;
|
||||
try {
|
||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||
if (!decrpytUserSelection) throw new AuthError("No user selection found");
|
||||
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (!redisKey) throw new AuthError("No redis key found");
|
||||
|
||||
if (!selectionObject) throw new AuthError("No selection object provided");
|
||||
|
||||
const oldData = await getCompleteFromRedis();
|
||||
if (!oldData) throw new AuthError("No old data found in redis");
|
||||
|
||||
await setCompleteToRedis({ ...oldData, selection: selectionObject })
|
||||
return true;
|
||||
} catch (error) {
|
||||
// Re-throw AuthError instances, wrap other errors as AuthError
|
||||
if (error instanceof AuthError) {
|
||||
throw error;
|
||||
} else {
|
||||
throw new AuthError(error instanceof Error ? error.message : "Unknown error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { getSelectionFromRedis, setSelectionToRedis };
|
||||
|
|
|
|||
|
|
@ -3,28 +3,46 @@ 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";
|
||||
import { AuthError } from "@/types/mutual/context/validations";
|
||||
|
||||
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;
|
||||
try {
|
||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (!redisKey) throw new AuthError("No redis key found");
|
||||
|
||||
const result = await redis.get(`${redisKey}`);
|
||||
if (!result) throw new AuthError("No data found in redis");
|
||||
|
||||
const parsedResult = JSON.parse(result);
|
||||
if (!parsedResult.settings) throw new AuthError("No settings found in redis");
|
||||
|
||||
return parsedResult.settings;
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) { throw error }
|
||||
throw new AuthError(error instanceof Error ? error.message : "Unknown error");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
try {
|
||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||
if (!decrpytUserSelection) throw new AuthError("No user selection found");
|
||||
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (!redisKey) throw new AuthError("No redis key found");
|
||||
|
||||
if (!settingsObject) throw new AuthError("No settings object provided");
|
||||
|
||||
const oldData = await getCompleteFromRedis();
|
||||
if (!oldData) throw new AuthError("No old data found in redis");
|
||||
|
||||
await setCompleteToRedis({ ...oldData, settings: settingsObject })
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) { throw error }
|
||||
throw new AuthError(error instanceof Error ? error.message : "Unknown error");
|
||||
}
|
||||
}
|
||||
|
||||
export { getSettingsFromRedis, setSettingsToRedis };
|
||||
|
|
|
|||
|
|
@ -3,28 +3,46 @@ 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";
|
||||
import { AuthError } from "@/types/mutual/context/validations";
|
||||
|
||||
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;
|
||||
try {
|
||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (!redisKey) throw new AuthError("No redis key found");
|
||||
|
||||
const result = await redis.get(`${redisKey}`);
|
||||
if (!result) throw new AuthError("No data found in redis");
|
||||
|
||||
const parsedResult = JSON.parse(result);
|
||||
if (!parsedResult.user) throw new AuthError("No user found in redis");
|
||||
|
||||
return parsedResult.user;
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) { throw error }
|
||||
throw new AuthError(error instanceof Error ? error.message : "Unknown error");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
try {
|
||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||
if (!decrpytUserSelection) throw new AuthError("No user selection found");
|
||||
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (!redisKey) throw new AuthError("No redis key found");
|
||||
|
||||
if (!userObject) throw new AuthError("No user object provided");
|
||||
|
||||
const oldData = await getCompleteFromRedis();
|
||||
if (!oldData) throw new AuthError("No old data found in redis");
|
||||
|
||||
await setCompleteToRedis({ ...oldData, user: userObject });
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) { throw error }
|
||||
throw new AuthError(error instanceof Error ? error.message : "Unknown error");
|
||||
}
|
||||
}
|
||||
|
||||
export { getUserFromRedis, setUserToRedis };
|
||||
|
|
|
|||
|
|
@ -3,28 +3,39 @@ 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";
|
||||
import { AuthError } from "@/types/mutual/context/validations";
|
||||
|
||||
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;
|
||||
try {
|
||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (!redisKey) throw new AuthError("No redis key found");
|
||||
const result = await redis.get(`${redisKey}`);
|
||||
if (!result) throw new AuthError("No data found in redis");
|
||||
const parsedResult = JSON.parse(result);
|
||||
if (!parsedResult.settings) throw new AuthError("No settings found in redis");
|
||||
return parsedResult.settings;
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) { throw error }
|
||||
throw new AuthError(error instanceof Error ? error.message : "Unknown error");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
try {
|
||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||
if (!decrpytUserSelection) throw new AuthError("No user selection found");
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (!redisKey) throw new AuthError("No redis key found");
|
||||
if (!settingsObject) throw new AuthError("No settings object provided");
|
||||
const oldData = await getCompleteFromRedis();
|
||||
if (!oldData) throw new AuthError("No old data found in redis");
|
||||
await setCompleteToRedis({ ...oldData, settings: settingsObject });
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) { throw error }
|
||||
throw new AuthError(error instanceof Error ? error.message : "Unknown error");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,28 +3,33 @@ 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";
|
||||
import { AuthError } from "@/types/mutual/context/validations";
|
||||
|
||||
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;
|
||||
try {
|
||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (!redisKey) throw new AuthError("No redis key found");
|
||||
const result = await redis.get(`${redisKey}`);
|
||||
if (!result) throw new AuthError("No data found in redis");
|
||||
const parsedResult = JSON.parse(result);
|
||||
if (!parsedResult.menu) throw new AuthError("No menu found in redis");
|
||||
return parsedResult.menu;
|
||||
} catch (error) { if (error instanceof AuthError) { throw error } else { throw new AuthError(error instanceof Error ? error.message : "Unknown error") } }
|
||||
}
|
||||
|
||||
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;
|
||||
try {
|
||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||
if (!decrpytUserSelection) throw new AuthError("No user selection found");
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (!redisKey) throw new AuthError("No redis key found");
|
||||
if (!menuObject) throw new AuthError("No menu object provided");
|
||||
const oldData = await getCompleteFromRedis();
|
||||
if (!oldData) throw new AuthError("No old data found in redis");
|
||||
await setCompleteToRedis({ ...oldData, menu: menuObject });
|
||||
return true;
|
||||
} catch (error) { if (error instanceof AuthError) { throw error } else { throw new AuthError(error instanceof Error ? error.message : "Unknown error") } }
|
||||
}
|
||||
|
||||
export { getMenuFromRedis, setMenuToRedis };
|
||||
|
|
|
|||
|
|
@ -3,17 +3,7 @@ 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";
|
||||
|
||||
// Default online object to use as fallback
|
||||
const defaultOnlineObject: ClientOnline = {
|
||||
lang: "en",
|
||||
userType: "occupant",
|
||||
lastLogin: new Date(),
|
||||
lastLogout: new Date(),
|
||||
lastAction: new Date(),
|
||||
lastPage: "/auth/login",
|
||||
timezone: "GMT+3"
|
||||
};
|
||||
import { AuthError } from "@/types/mutual/context/validations";
|
||||
|
||||
// Redis operation timeout (5 seconds)
|
||||
const REDIS_TIMEOUT = 5000;
|
||||
|
|
@ -24,72 +14,25 @@ const REDIS_TIMEOUT = 5000;
|
|||
*/
|
||||
const getOnlineFromRedis = async (): Promise<ClientOnline> => {
|
||||
try {
|
||||
console.log('Getting online state from Redis...');
|
||||
|
||||
// Get user selection with default fallback
|
||||
let decrpytUserSelection;
|
||||
try {
|
||||
decrpytUserSelection = await functionRetrieveUserSelection();
|
||||
console.log('User selection retrieved successfully');
|
||||
} catch (error) {
|
||||
console.error('Error retrieving user selection:', error);
|
||||
return defaultOnlineObject;
|
||||
}
|
||||
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
console.log('Redis key:', redisKey);
|
||||
|
||||
// If we have a default redisKey, return a default online object
|
||||
if (!redisKey || redisKey === "default") {
|
||||
console.log('Using default online object due to default/missing redisKey');
|
||||
return defaultOnlineObject;
|
||||
}
|
||||
|
||||
// Try to get data from Redis with timeout
|
||||
let result;
|
||||
let decrpytUserSelection;
|
||||
try { decrpytUserSelection = await functionRetrieveUserSelection() } catch (error) { throw new AuthError('Failed to retrieve user selection') }
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (!redisKey) { throw new AuthError('No redis key found') }
|
||||
if (redisKey === "default") { throw new AuthError('Invalid redis key') }
|
||||
try {
|
||||
// Create a promise that rejects after the timeout
|
||||
const timeoutPromise = new Promise((_, reject) => {
|
||||
setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT);
|
||||
});
|
||||
|
||||
// Race the Redis operation against the timeout
|
||||
result = await Promise.race([
|
||||
redis.get(`${redisKey}`),
|
||||
timeoutPromise
|
||||
]) as string | null;
|
||||
|
||||
console.log('Redis get operation completed');
|
||||
} catch (redisError) {
|
||||
console.error('Error accessing Redis:', redisError);
|
||||
return defaultOnlineObject;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
console.log('No data found in Redis for key:', redisKey);
|
||||
return defaultOnlineObject;
|
||||
}
|
||||
const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT) });
|
||||
result = await Promise.race([redis.get(`${redisKey}`), timeoutPromise]) as string | null;
|
||||
} catch (redisError) { throw new AuthError('Failed to access Redis data') }
|
||||
|
||||
if (!result) { throw new AuthError('No data found in redis') }
|
||||
|
||||
// Parse the result
|
||||
try {
|
||||
const parsedResult = JSON.parse(result);
|
||||
console.log('Successfully parsed Redis result');
|
||||
|
||||
if (!parsedResult.online) {
|
||||
console.warn('No online object in parsed result');
|
||||
return defaultOnlineObject;
|
||||
}
|
||||
|
||||
console.log('Returning online object from Redis');
|
||||
if (!parsedResult.online) { throw new AuthError('No online data found in redis') }
|
||||
return parsedResult.online;
|
||||
} catch (parseError) {
|
||||
console.error('Error parsing Redis result:', parseError);
|
||||
return defaultOnlineObject;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Unexpected error in getOnlineFromRedis:', error);
|
||||
return defaultOnlineObject;
|
||||
}
|
||||
} catch (parseError) { throw new AuthError('Invalid data format in redis') }
|
||||
} catch (error) { if (error instanceof AuthError) { throw error } else { throw new AuthError(error instanceof Error ? error.message : 'Unknown error') } }
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -99,75 +42,23 @@ const getOnlineFromRedis = async (): Promise<ClientOnline> => {
|
|||
*/
|
||||
const setOnlineToRedis = async (onlineObject: ClientOnline): Promise<boolean> => {
|
||||
try {
|
||||
console.log('Setting online state in Redis:', onlineObject);
|
||||
|
||||
// Validate input
|
||||
if (!onlineObject) {
|
||||
console.error('No online object provided');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get user selection
|
||||
if (!onlineObject) { throw new AuthError('No online object provided') }
|
||||
|
||||
let decrpytUserSelection;
|
||||
try {
|
||||
decrpytUserSelection = await functionRetrieveUserSelection();
|
||||
console.log('User selection retrieved successfully');
|
||||
} catch (error) {
|
||||
console.error('Error retrieving user selection:', error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!decrpytUserSelection) {
|
||||
console.error('No user selection found');
|
||||
return false;
|
||||
}
|
||||
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (!redisKey) {
|
||||
console.error('No redis key found in user selection');
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('Using Redis key:', redisKey);
|
||||
|
||||
// Get existing data from Redis
|
||||
let oldData;
|
||||
|
||||
try { decrpytUserSelection = await functionRetrieveUserSelection() } catch (error) { throw new AuthError('Failed to retrieve user selection') }
|
||||
if (!decrpytUserSelection) { throw new AuthError('No user selection found') }
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (!redisKey) { throw new AuthError('No redis key found') }
|
||||
try { oldData = await getCompleteFromRedis() } catch (error) { throw new AuthError('Failed to retrieve existing data from Redis') }
|
||||
if (!oldData) { throw new AuthError('No old data found in redis') }
|
||||
try {
|
||||
oldData = await getCompleteFromRedis();
|
||||
console.log('Retrieved existing data from Redis');
|
||||
} catch (error) {
|
||||
console.error('Error getting complete data from Redis:', error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!oldData) {
|
||||
console.error('No existing data found in Redis');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update Redis with timeout
|
||||
try {
|
||||
// Create a promise that rejects after the timeout
|
||||
const timeoutPromise = new Promise((_, reject) => {
|
||||
setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT);
|
||||
});
|
||||
|
||||
// Race the Redis operation against the timeout
|
||||
await Promise.race([
|
||||
setCompleteToRedis({ ...oldData, online: onlineObject }),
|
||||
timeoutPromise
|
||||
]);
|
||||
|
||||
console.log('Successfully updated online state in Redis');
|
||||
const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT) });
|
||||
await Promise.race([setCompleteToRedis({ ...oldData, online: onlineObject }), timeoutPromise]);
|
||||
return true;
|
||||
} catch (redisError) {
|
||||
console.error('Error updating Redis:', redisError);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Unexpected error in setOnlineToRedis:', error);
|
||||
return false;
|
||||
}
|
||||
} catch (redisError) { throw new AuthError('Failed to update Redis data') }
|
||||
} catch (error) { if (error instanceof AuthError) throw error; throw new AuthError(error instanceof Error ? error.message : 'Unknown error') }
|
||||
}
|
||||
|
||||
export { getOnlineFromRedis, setOnlineToRedis };
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import NextCrypto from "next-crypto";
|
|||
import { fetchDataWithToken } from "@/apifetchers/api-fetcher";
|
||||
import { baseUrlAuth, baseUrlRestriction, tokenSecret } from "@/apifetchers/basics";
|
||||
import { cookies } from "next/headers";
|
||||
import { AuthError } from "@/types/mutual/context/validations";
|
||||
|
||||
const checkToken = `${baseUrlAuth}/authentication/token/check`;
|
||||
const pageValid = `${baseUrlRestriction}/restrictions/page/valid`;
|
||||
|
|
@ -18,10 +19,7 @@ async function checkAccessTokenIsValid() {
|
|||
try {
|
||||
const response = await fetchDataWithToken(checkToken, {}, "GET", false);
|
||||
return fetchResponseStatus(response);
|
||||
} catch (error) {
|
||||
console.error("Error checking token validity:", error);
|
||||
return false;
|
||||
}
|
||||
} catch (error) { throw new AuthError("No access token found") }
|
||||
}
|
||||
|
||||
async function retrievePageList() {
|
||||
|
|
@ -40,8 +38,7 @@ async function retrieveAccessToken() {
|
|||
const encrpytAccessToken = cookieStore.get("eys-zzz")?.value || "";
|
||||
return await nextCrypto.decrypt(encrpytAccessToken) || "";
|
||||
}
|
||||
catch (error) { console.error("Error retrieving access token:", error) }
|
||||
return "";
|
||||
catch (error) { throw new AuthError("No access token found") }
|
||||
}
|
||||
|
||||
async function retrieveAccessObjects() {
|
||||
|
|
@ -50,8 +47,7 @@ async function retrieveAccessObjects() {
|
|||
const encrpytAccessObject = cookieStore.get("eys-yyy")?.value || "";
|
||||
return await nextCrypto.decrypt(encrpytAccessObject) || "";
|
||||
}
|
||||
catch (error) { console.error("Error retrieving access objects:", error) }
|
||||
return "";
|
||||
catch (error) { throw new AuthError("No access objects found") }
|
||||
}
|
||||
|
||||
export {
|
||||
|
|
|
|||
|
|
@ -13,51 +13,20 @@ const functionRetrieveUserSelection = async () => {
|
|||
try {
|
||||
const cookieStore = await cookies();
|
||||
const encrpytUserSelection = cookieStore.get("eys-sel")?.value || "";
|
||||
|
||||
if (!encrpytUserSelection) {
|
||||
return {
|
||||
redisKey: "default",
|
||||
uuid: "",
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
|
||||
if (!encrpytUserSelection) { return { redisKey: "default", uuid: "", timestamp: new Date().toISOString() } }
|
||||
try {
|
||||
const decrpytUserSelection = await nextCrypto.decrypt(encrpytUserSelection);
|
||||
if (!decrpytUserSelection) {
|
||||
return {
|
||||
redisKey: "default",
|
||||
uuid: "",
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
|
||||
if (!decrpytUserSelection) { return { redisKey: "default", uuid: "", timestamp: new Date().toISOString() } }
|
||||
return JSON.parse(decrpytUserSelection);
|
||||
} catch (decryptError) {
|
||||
return {
|
||||
redisKey: "default",
|
||||
uuid: "",
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
redisKey: "default",
|
||||
uuid: "",
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
} catch (decryptError) { return { redisKey: "default", uuid: "", timestamp: new Date().toISOString() } }
|
||||
} catch (error) { return { redisKey: "default", uuid: "", timestamp: new Date().toISOString() } }
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
cookieStore.set({ name: "eys-sel", value: encrpytUserSelection, ...cookieObject });
|
||||
}
|
||||
|
||||
const functionRemoveUserSelection = async () => {
|
||||
|
|
|
|||
|
|
@ -3,19 +3,17 @@ import { AuthLayout } from "@/layouts/auth/layout";
|
|||
import { AuthServerProps } from "@/validations/mutual/pages/props";
|
||||
import { LanguageTypes } from "@/validations/mutual/language/validations";
|
||||
import { checkAccessTokenIsValid } from "@/apifetchers/mutual/cookies/token";
|
||||
import Login from "@/webPages/auth/login/page";
|
||||
import Select from "@/webPages/auth/select/page";
|
||||
import { getOnlineFromRedis } from "@/apifetchers/mutual/context/page/online/fetch";
|
||||
import { redirect } from "next/navigation";
|
||||
import Login from "@/webPages/auth/login/page";
|
||||
|
||||
const AuthPageSSR = async ({ params, searchParams }: AuthServerProps) => {
|
||||
const awaitedParams = await params;
|
||||
const awaitedSearchParams = await searchParams;
|
||||
const pageUrlFromParams = `/${awaitedParams.page?.join("/")}` || "/login";
|
||||
const tokenValid = await checkAccessTokenIsValid();
|
||||
let FoundPage = <Login language={"en"} query={awaitedSearchParams} />
|
||||
const online = await getOnlineFromRedis();
|
||||
if (tokenValid && online) { FoundPage = <Select language={online?.lang as LanguageTypes} type={online?.userType} /> }
|
||||
return <div className="flex flex-col items-center justify-center"><AuthLayout lang={online?.lang as LanguageTypes} page={FoundPage} activePageUrl={pageUrlFromParams} /></div>
|
||||
try { const online = await getOnlineFromRedis(); if (tokenValid && online) { redirect("/panel/dashboard") } } catch (error) { }
|
||||
return <div className="flex flex-col items-center justify-center"><AuthLayout lang={"en"} page={<Login language={"en"} query={awaitedSearchParams} />} activePageUrl={pageUrlFromParams} /></div>
|
||||
}
|
||||
|
||||
export default AuthPageSSR;
|
||||
|
|
|
|||
|
|
@ -2,25 +2,12 @@
|
|||
import { MaindasboardPageProps } from "@/validations/mutual/dashboard/props";
|
||||
import { DashboardLayout } from "@/layouts/dashboard/layout";
|
||||
import { redirect } from "next/navigation";
|
||||
import { fetchDataWithToken } from "@/apifetchers/api-fetcher";
|
||||
import { baseUrlAuth } from "@/apifetchers/basics";
|
||||
|
||||
// Function to check token validity without trying to delete cookies
|
||||
async function isTokenValid() {
|
||||
try {
|
||||
const checkToken = `${baseUrlAuth}/authentication/token/check`;
|
||||
const response = await fetchDataWithToken(checkToken, {}, "GET", false);
|
||||
return response?.status >= 200 && response?.status < 300;
|
||||
} catch (error) {
|
||||
console.error("Error checking token validity:", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
import { checkAccessTokenIsValid } from "@/apifetchers/mutual/cookies/token";
|
||||
|
||||
const MainEnPage: React.FC<MaindasboardPageProps> = async ({ params, searchParams }) => {
|
||||
const parameters = await params;
|
||||
const searchParameters = await searchParams;
|
||||
const tokenValid = await isTokenValid()
|
||||
const tokenValid = await checkAccessTokenIsValid()
|
||||
if (!tokenValid) { redirect("/auth/login") }
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
|
|
|
|||
|
|
@ -2,21 +2,74 @@ import {
|
|||
getSelectionFromRedis,
|
||||
setSelectionToRedis,
|
||||
} from "@/apifetchers/mutual/context/dash/selection/fetch";
|
||||
import { AuthError } from "@/types/mutual/context/validations";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
const selection = await getSelectionFromRedis();
|
||||
return NextResponse.json({
|
||||
status: 200,
|
||||
data: selection || null,
|
||||
});
|
||||
try {
|
||||
const selection = await getSelectionFromRedis();
|
||||
return NextResponse.json({
|
||||
status: 200,
|
||||
data: selection || null,
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
// Return 401 Unauthorized for authentication errors
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
status: 401,
|
||||
error: error.message,
|
||||
}),
|
||||
{
|
||||
status: 401,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
// For other errors, return 500 Internal Server Error
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
status: 500,
|
||||
error: "Internal server error",
|
||||
}),
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const selection = await request.json();
|
||||
await setSelectionToRedis(selection);
|
||||
return NextResponse.json({
|
||||
status: 200,
|
||||
data: selection || null,
|
||||
});
|
||||
try {
|
||||
const selection = await request.json();
|
||||
await setSelectionToRedis(selection);
|
||||
return NextResponse.json({
|
||||
status: 200,
|
||||
data: selection || null,
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
status: 401,
|
||||
error: error.message,
|
||||
}),
|
||||
{
|
||||
status: 401,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
status: 500,
|
||||
error: "Internal server error",
|
||||
}),
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,15 +2,50 @@ import {
|
|||
getSettingsFromRedis,
|
||||
setSettingsToRedis,
|
||||
} from "@/apifetchers/mutual/context/dash/settings/fetch";
|
||||
import { AuthError } from "@/types/mutual/context/validations";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
const settings = await getSettingsFromRedis();
|
||||
return NextResponse.json(settings);
|
||||
try {
|
||||
const settings = await getSettingsFromRedis();
|
||||
return NextResponse.json(settings);
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
// Return 401 Unauthorized for authentication errors
|
||||
return new NextResponse(JSON.stringify({ error: error.message }), {
|
||||
status: 401,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
// For other errors, return 500 Internal Server Error
|
||||
return new NextResponse(
|
||||
JSON.stringify({ error: "Internal server error" }),
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const settings = await request.json();
|
||||
await setSettingsToRedis(settings);
|
||||
return NextResponse.json(settings);
|
||||
try {
|
||||
const settings = await request.json();
|
||||
await setSettingsToRedis(settings);
|
||||
return NextResponse.json(settings);
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return new NextResponse(JSON.stringify({ error: error.message }), {
|
||||
status: 401,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
return new NextResponse(
|
||||
JSON.stringify({ error: "Internal server error" }),
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,15 +2,50 @@ import {
|
|||
getUserFromRedis,
|
||||
setUserToRedis,
|
||||
} from "@/apifetchers/mutual/context/dash/user/fetch";
|
||||
import { AuthError } from "@/types/mutual/context/validations";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
const user = await getUserFromRedis();
|
||||
return NextResponse.json(user);
|
||||
try {
|
||||
const user = await getUserFromRedis();
|
||||
return NextResponse.json(user);
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
// Return 401 Unauthorized for authentication errors
|
||||
return new NextResponse(JSON.stringify({ error: error.message }), {
|
||||
status: 401,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
// For other errors, return 500 Internal Server Error
|
||||
return new NextResponse(
|
||||
JSON.stringify({ error: "Internal server error" }),
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const user = await request.json();
|
||||
await setUserToRedis(user);
|
||||
return NextResponse.json(user);
|
||||
try {
|
||||
const user = await request.json();
|
||||
await setUserToRedis(user);
|
||||
return NextResponse.json(user);
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return new NextResponse(JSON.stringify({ error: error.message }), {
|
||||
status: 401,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
return new NextResponse(
|
||||
JSON.stringify({ error: "Internal server error" }),
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,15 +2,50 @@ import {
|
|||
getConfigFromRedis,
|
||||
setConfigToRedis,
|
||||
} from "@/apifetchers/mutual/context/page/config/fetch";
|
||||
import { AuthError } from "@/types/mutual/context/validations";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
const config = await getConfigFromRedis();
|
||||
return NextResponse.json(config);
|
||||
try {
|
||||
const config = await getConfigFromRedis();
|
||||
return NextResponse.json(config);
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
// Return 401 Unauthorized for authentication errors
|
||||
return new NextResponse(JSON.stringify({ error: error.message }), {
|
||||
status: 401,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
// For other errors, return 500 Internal Server Error
|
||||
return new NextResponse(
|
||||
JSON.stringify({ error: "Internal server error" }),
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const config = await request.json();
|
||||
await setConfigToRedis(config);
|
||||
return NextResponse.json(config);
|
||||
try {
|
||||
const config = await request.json();
|
||||
await setConfigToRedis(config);
|
||||
return NextResponse.json(config);
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return new NextResponse(JSON.stringify({ error: error.message }), {
|
||||
status: 401,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
return new NextResponse(
|
||||
JSON.stringify({ error: "Internal server error" }),
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,21 +2,74 @@ import {
|
|||
getMenuFromRedis,
|
||||
setMenuToRedis,
|
||||
} from "@/apifetchers/mutual/context/page/menu/fetch";
|
||||
import { AuthError } from "@/types/mutual/context/validations";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
const menu = await getMenuFromRedis();
|
||||
return NextResponse.json({
|
||||
status: 200,
|
||||
data: menu,
|
||||
});
|
||||
try {
|
||||
const menu = await getMenuFromRedis();
|
||||
return NextResponse.json({
|
||||
status: 200,
|
||||
data: menu,
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
// Return 401 Unauthorized for authentication errors
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
status: 401,
|
||||
error: error.message,
|
||||
}),
|
||||
{
|
||||
status: 401,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
// For other errors, return 500 Internal Server Error
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
status: 500,
|
||||
error: "Internal server error",
|
||||
}),
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const menu = await request.json();
|
||||
await setMenuToRedis(menu);
|
||||
return NextResponse.json({
|
||||
status: 200,
|
||||
data: menu,
|
||||
});
|
||||
try {
|
||||
const menu = await request.json();
|
||||
await setMenuToRedis(menu);
|
||||
return NextResponse.json({
|
||||
status: 200,
|
||||
data: menu,
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
status: 401,
|
||||
error: error.message,
|
||||
}),
|
||||
{
|
||||
status: 401,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
status: 500,
|
||||
error: "Internal server error",
|
||||
}),
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,21 +2,74 @@ import {
|
|||
getOnlineFromRedis,
|
||||
setOnlineToRedis,
|
||||
} from "@/apifetchers/mutual/context/page/online/fetch";
|
||||
import { AuthError } from "@/types/mutual/context/validations";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
const online = await getOnlineFromRedis();
|
||||
return NextResponse.json({
|
||||
status: 200,
|
||||
data: online,
|
||||
});
|
||||
try {
|
||||
const online = await getOnlineFromRedis();
|
||||
return NextResponse.json({
|
||||
status: 200,
|
||||
data: online,
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
// Return 401 Unauthorized for authentication errors
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
status: 401,
|
||||
error: error.message,
|
||||
}),
|
||||
{
|
||||
status: 401,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
// For other errors, return 500 Internal Server Error
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
status: 500,
|
||||
error: "Internal server error",
|
||||
}),
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const online = await request.json();
|
||||
await setOnlineToRedis(online);
|
||||
return NextResponse.json({
|
||||
status: 200,
|
||||
data: online,
|
||||
});
|
||||
try {
|
||||
const online = await request.json();
|
||||
await setOnlineToRedis(online);
|
||||
return NextResponse.json({
|
||||
status: 200,
|
||||
data: online,
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
status: 401,
|
||||
error: error.message,
|
||||
}),
|
||||
{
|
||||
status: 401,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
status: 500,
|
||||
error: "Internal server error",
|
||||
}),
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const translations = {
|
|||
|
||||
const HeaderComponent: FC<HeaderProps> = ({
|
||||
lang, activePageUrl, prefix, mode,
|
||||
onlineData, onlineLoading, onlineError,
|
||||
onlineData, onlineLoading, onlineError, refreshOnline, updateOnline,
|
||||
userData, userLoading, userError,
|
||||
}) => {
|
||||
return (
|
||||
|
|
@ -32,7 +32,10 @@ const HeaderComponent: FC<HeaderProps> = ({
|
|||
<span className="font-semibold">{onlineData.lang || lang}</span>
|
||||
<span className="ml-2 text-xs bg-green-100 text-green-800 px-2 py-1 rounded-full">{onlineData.userType}</span>
|
||||
</div>
|
||||
)}<LanguageSelectionComponent lang={lang} activePage={activePageUrl} prefix={prefix} />
|
||||
)}<LanguageSelectionComponent
|
||||
lang={lang} activePage={activePageUrl} prefix={prefix}
|
||||
onlineData={onlineData} onlineLoading={onlineLoading} onlineError={onlineError} refreshOnline={refreshOnline} updateOnline={updateOnline}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -139,7 +139,6 @@ interface UseOnlineResult {
|
|||
// Wrapper hook that adapts the generic hook to the expected interface
|
||||
export function useOnline(): UseOnlineResult {
|
||||
const { data, isLoading, error, refresh, update } = useContextOnline();
|
||||
|
||||
return {
|
||||
onlineData: data,
|
||||
isLoading,
|
||||
|
|
|
|||
|
|
@ -10,9 +10,14 @@ interface LanguageSelectionComponentProps {
|
|||
lang: LanguageTypes;
|
||||
activePage: string;
|
||||
prefix: string;
|
||||
onlineData: any;
|
||||
onlineLoading: boolean;
|
||||
onlineError: any;
|
||||
refreshOnline: () => Promise<void>;
|
||||
updateOnline: (newOnline: any) => Promise<boolean>;
|
||||
}
|
||||
|
||||
const LanguageSelectionComponent: React.FC<LanguageSelectionComponentProps> = ({ lang, activePage, prefix }) => {
|
||||
const LanguageSelectionComponent: React.FC<LanguageSelectionComponentProps> = ({ lang, activePage, prefix, onlineData, onlineLoading, onlineError, refreshOnline, updateOnline }) => {
|
||||
const translations = langGet(lang, languageSelectionTranslation);
|
||||
const getPageWithLocale = (locale: LanguageTypes): string => { return `${prefix}/${activePage}` }
|
||||
const languageButtons = [
|
||||
|
|
@ -27,7 +32,8 @@ const LanguageSelectionComponent: React.FC<LanguageSelectionComponentProps> = ({
|
|||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
{languageButtons.map((props, index) => (
|
||||
<LanguageSelectionItem key={props.buttonsLang} {...props} />
|
||||
<LanguageSelectionItem key={props.buttonsLang} {...props} onlineData={onlineData}
|
||||
onlineLoading={onlineLoading} onlineError={onlineError} refreshOnline={refreshOnline} updateOnline={updateOnline} />
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
|
|
|||
|
|
@ -1,25 +1,26 @@
|
|||
'use client';
|
||||
import { FC } from "react";
|
||||
import { DropdownMenuItem } from "@/components/mutual/shadcnui/dropdown-menu";
|
||||
import { useRouter, usePathname, useSearchParams } from "next/navigation";
|
||||
// Import the useOnline hook from the context file instead of the provider
|
||||
import { useOnline } from "@/components/mutual/context/online/context";
|
||||
import { ClientOnline } from "@/types/mutual/context/validations";
|
||||
import Link from "next/link";
|
||||
|
||||
const RenderButtonComponent: FC<{ refUrl: string, innerText: string, buttonsLang: string }> = (
|
||||
{ refUrl, innerText, buttonsLang }) => {
|
||||
const router = useRouter();
|
||||
// Use the new hook properties: onlineData instead of online, refreshOnline and updateOnline
|
||||
const { onlineData, isLoading, error, refreshOnline, updateOnline } = useOnline();
|
||||
interface LanguageSelectionItemProps {
|
||||
activeLang: string,
|
||||
buttonsLang: string,
|
||||
refUrl: string,
|
||||
innerText: string,
|
||||
onlineData: any,
|
||||
onlineLoading: boolean,
|
||||
onlineError: any,
|
||||
refreshOnline: () => Promise<void>,
|
||||
updateOnline: (newOnline: any) => Promise<boolean>
|
||||
}
|
||||
|
||||
const RenderButtonComponent: FC<LanguageSelectionItemProps> = (
|
||||
{ activeLang, buttonsLang, refUrl, innerText, onlineData, onlineLoading, onlineError, refreshOnline, updateOnline }) => {
|
||||
const setOnlineObject = async () => {
|
||||
if (!onlineData || isLoading) return;
|
||||
if (!onlineData || onlineLoading) return;
|
||||
|
||||
try {
|
||||
console.log("Updating language to:", buttonsLang);
|
||||
// Use the context hook to update online state
|
||||
// This will update Redis, context API, and trigger re-renders
|
||||
const success = await updateOnline({
|
||||
...onlineData,
|
||||
lang: buttonsLang,
|
||||
|
|
@ -28,10 +29,7 @@ const RenderButtonComponent: FC<{ refUrl: string, innerText: string, buttonsLang
|
|||
|
||||
if (success) {
|
||||
console.log("Language updated successfully");
|
||||
// Refresh the online data to get the latest state
|
||||
await refreshOnline();
|
||||
// Navigate to the new URL
|
||||
router.push(refUrl);
|
||||
} else {
|
||||
console.error("Failed to update language");
|
||||
}
|
||||
|
|
@ -49,27 +47,20 @@ const RenderButtonComponent: FC<{ refUrl: string, innerText: string, buttonsLang
|
|||
)
|
||||
}
|
||||
|
||||
const LanguageSelectionItem: React.FC<LanguageSelectionItemProps> = ({ activeLang, buttonsLang, refUrl, innerText, onlineData, onlineLoading, onlineError, refreshOnline, updateOnline }) => {
|
||||
|
||||
|
||||
const LanguageSelectionItem: React.FC<{
|
||||
activeLang: string, buttonsLang: string, refUrl: string, innerText: string
|
||||
}> = ({ activeLang, buttonsLang, refUrl, innerText }) => {
|
||||
// Get the current online state to determine the actual current language
|
||||
const { onlineData } = useOnline();
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
const currentUrl = pathname + (searchParams.toString() ? `?${searchParams.toString()}` : "");
|
||||
|
||||
// Use the language from the online state if available, otherwise use the prop
|
||||
const currentLang = onlineData?.lang || activeLang;
|
||||
|
||||
// Determine if this button should be active (not the current language)
|
||||
const isActive = buttonsLang !== currentLang;
|
||||
|
||||
const RenderButtonProp = {
|
||||
refUrl,
|
||||
innerText,
|
||||
buttonsLang
|
||||
activeLang,
|
||||
buttonsLang,
|
||||
onlineData,
|
||||
onlineLoading,
|
||||
onlineError,
|
||||
refreshOnline,
|
||||
updateOnline
|
||||
}
|
||||
|
||||
// Only render the button if it's not the current language
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
'use server';
|
||||
import { FC, Suspense } from "react";
|
||||
import { AuthLayoutProps } from "@/validations/mutual/auth/props";
|
||||
import LanguageSelectionComponent from "@/components/mutual/languageSelection/component";
|
||||
|
||||
const AuthLayout: FC<AuthLayoutProps> = async ({ lang, page, activePageUrl }) => {
|
||||
return (
|
||||
|
|
@ -13,7 +12,6 @@ const AuthLayout: FC<AuthLayoutProps> = async ({ lang, page, activePageUrl }) =>
|
|||
</div>
|
||||
</div>
|
||||
<div className="w-3/4 text-black">
|
||||
<LanguageSelectionComponent lang={lang} activePage={activePageUrl} prefix={"/auth"} />
|
||||
<Suspense fallback={<div>Loading...</div>}>{page}</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -35,87 +35,31 @@ interface ClientLayoutProps {
|
|||
}
|
||||
|
||||
const ClientLayout: FC<ClientLayoutProps> = ({ allProps }) => {
|
||||
const { onlineData, isLoading: onlineLoading, error: onlineError } = useOnline();
|
||||
const { onlineData, isLoading: onlineLoading, error: onlineError, refreshOnline, updateOnline } = useOnline();
|
||||
const { userData, isLoading: userLoading, error: userError } = useUser();
|
||||
const { availableApplications, isLoading: menuLoading, error: menuError, menuData, refreshMenu } = useMenu();
|
||||
const { selectionData, isLoading: selectionLoading, error: selectionError } = useSelection();
|
||||
const { configData, isLoading: configLoading, error: configError } = useConfig();
|
||||
|
||||
console.log("RedisData", {
|
||||
onlineData: {
|
||||
isLoading: onlineLoading,
|
||||
error: onlineError,
|
||||
data: onlineData
|
||||
},
|
||||
userData: {
|
||||
isLoading: userLoading,
|
||||
error: userError,
|
||||
data: userData
|
||||
},
|
||||
menuData: {
|
||||
isLoading: menuLoading,
|
||||
error: menuError,
|
||||
data: menuData
|
||||
},
|
||||
selectionData: {
|
||||
isLoading: selectionLoading,
|
||||
error: selectionError,
|
||||
data: selectionData
|
||||
},
|
||||
configData: {
|
||||
isLoading: configLoading,
|
||||
error: configError,
|
||||
data: configData
|
||||
}
|
||||
})
|
||||
useEffect(() => {
|
||||
console.log('ClientLayout rendered with context providers');
|
||||
return () => { console.log('ClientLayout unmounted'); };
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
console.log('OnlineData changed with context providers');
|
||||
return () => { console.log('ClientLayout unmounted'); };
|
||||
}, [onlineData]);
|
||||
useEffect(() => {
|
||||
console.log('UserData changed with context providers');
|
||||
return () => { console.log('ClientLayout unmounted'); };
|
||||
}, [userData]);
|
||||
useEffect(() => {
|
||||
console.log('MenuData changed with context providers');
|
||||
return () => { console.log('ClientLayout unmounted'); };
|
||||
}, [menuData]);
|
||||
useEffect(() => {
|
||||
console.log('SelectionData changed with context providers');
|
||||
return () => { console.log('ClientLayout unmounted'); };
|
||||
}, [selectionData]);
|
||||
useEffect(() => {
|
||||
console.log('ConfigData changed with context providers');
|
||||
return () => { console.log('ClientLayout unmounted'); };
|
||||
}, [configData]);
|
||||
const useReloadWindow = () => { window.location.reload() }
|
||||
|
||||
return (
|
||||
<ClientProviders>
|
||||
<div className="flex flex-col min-w-screen">
|
||||
<HeaderComponent {...allProps}
|
||||
useReloadWindow={useReloadWindow}
|
||||
onlineData={onlineData} onlineLoading={onlineLoading} onlineError={onlineError}
|
||||
refreshOnline={refreshOnline} updateOnline={updateOnline}
|
||||
userData={userData} userLoading={userLoading} userError={userError}
|
||||
/>
|
||||
<MenuComponent {...allProps}
|
||||
useReloadWindow={useReloadWindow}
|
||||
availableApplications={availableApplications}
|
||||
onlineData={onlineData} onlineLoading={onlineLoading} onlineError={onlineError}
|
||||
userData={userData} userLoading={userLoading} userError={userError}
|
||||
selectionData={selectionData} selectionLoading={selectionLoading} selectionError={selectionError}
|
||||
menuData={menuData} menuLoading={menuLoading} menuError={menuError} />
|
||||
<ContentComponent {...allProps}
|
||||
useReloadWindow={useReloadWindow}
|
||||
userData={userData} userLoading={userLoading} userError={userError}
|
||||
selectionData={selectionData} selectionLoading={selectionLoading} selectionError={selectionError}
|
||||
/>
|
||||
<FooterComponent {...allProps}
|
||||
useReloadWindow={useReloadWindow}
|
||||
availableApplications={availableApplications}
|
||||
configData={configData} configLoading={configLoading} configError={configError}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
// From Redis objects
|
||||
export class AuthError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'AuthError';
|
||||
}
|
||||
}
|
||||
|
||||
interface ClientOnline {
|
||||
lastLogin: Date;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ interface ContentProps {
|
|||
lang: LanguageTypes;
|
||||
activePageUrl: string;
|
||||
mode?: ModeTypes;
|
||||
useReloadWindow?: () => void;
|
||||
userData: any;
|
||||
userLoading: boolean;
|
||||
userError: any;
|
||||
|
|
@ -32,7 +31,6 @@ interface MenuProps {
|
|||
lang: LanguageTypes;
|
||||
availableApplications: string[];
|
||||
activePageUrl: string;
|
||||
useReloadWindow?: () => void;
|
||||
onlineData: any;
|
||||
onlineLoading: boolean;
|
||||
onlineError: any;
|
||||
|
|
@ -51,7 +49,6 @@ interface FooterProps {
|
|||
lang: LanguageTypes;
|
||||
availableApplications: string[];
|
||||
activePageUrl: string;
|
||||
useReloadWindow?: () => void;
|
||||
configData: any;
|
||||
configLoading: boolean;
|
||||
configError: any;
|
||||
|
|
@ -62,10 +59,11 @@ interface HeaderProps {
|
|||
activePageUrl: string;
|
||||
prefix: string;
|
||||
mode?: ModeTypes;
|
||||
useReloadWindow?: () => void;
|
||||
onlineData: any;
|
||||
onlineLoading: boolean;
|
||||
onlineError: any;
|
||||
refreshOnline: () => Promise<void>;
|
||||
updateOnline: (newOnline: any) => Promise<boolean>;
|
||||
userData: any;
|
||||
userLoading: boolean;
|
||||
userError: any;
|
||||
|
|
|
|||
|
|
@ -20,12 +20,7 @@ export function loginHook(
|
|||
if (response.status === 200) {
|
||||
response.json().then((data) => {
|
||||
setTimeout(() => {
|
||||
const userType =
|
||||
data?.data?.user_type.toLowerCase() === "employee"
|
||||
? "employee"
|
||||
: "occupant";
|
||||
const rediretUrl = `/auth/select?type=${userType}`;
|
||||
Router.push(rediretUrl);
|
||||
Router.push(`/panel/dashboard`);
|
||||
}, 100);
|
||||
});
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,122 +0,0 @@
|
|||
"use client";
|
||||
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({
|
||||
lang
|
||||
}: LoginEmployeeProps) {
|
||||
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, { uuid: uu_id }, setError, setJsonText, Router, lang) };
|
||||
|
||||
// Render a company card with consistent styling
|
||||
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 */}
|
||||
<div className="flex items-center mb-2">
|
||||
<h3 className="text-xl font-semibold text-gray-800">{company.public_name}</h3>
|
||||
{company.company_type && (
|
||||
<span className="ml-2 px-2 py-1 text-xs font-medium bg-blue-100 text-blue-800 rounded-full">
|
||||
{company.company_type}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Duty information */}
|
||||
{company.duty && (
|
||||
<div className="mb-2 text-sm text-gray-600">
|
||||
<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[lang].id}:</span> {company.uu_id}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="w-full max-w-md mx-auto">
|
||||
<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[lang].noSelections}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Single company */}
|
||||
{isArrayLengthOne && <CompanyCard company={selectionListCopy.activeSelection as Company} />}
|
||||
|
||||
{/* Multiple companies */}
|
||||
{isArrayMoreThanOne && (
|
||||
<div className="space-y-3">
|
||||
{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 as Company} /></div>
|
||||
))}
|
||||
</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>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default LoginEmployee;
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
"use client";
|
||||
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";
|
||||
|
||||
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: {} });
|
||||
|
||||
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}`}
|
||||
className="w-full p-4 mb-3 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md transition-all cursor-pointer hover:translate-x-1"
|
||||
onClick={() => onSubmitOccupant({ build_living_space_uu_id: occupant.build_living_space_uu_id })}
|
||||
>
|
||||
<div className="flex flex-col">
|
||||
<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>
|
||||
<div className="mb-1 text-sm text-gray-700 font-medium">
|
||||
{occupant.part_name}
|
||||
</div>
|
||||
<div className="text-xs text-gray-500">
|
||||
<span className="font-medium">{translation[lang].level}:</span> {occupant.part_level}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
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">
|
||||
<h2 className="text-lg font-semibold text-gray-800 flex items-center">
|
||||
<svg className="w-5 h-5 mr-2 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
||||
</svg>
|
||||
<span>{building.build_name}</span>
|
||||
<span className="ml-2 px-2 py-0.5 text-xs bg-blue-100 text-blue-800 rounded-full">No: {building.build_no}</span>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
{building.occupants.map((occupant: any, idx: number) => (
|
||||
<OccupantCard key={idx} occupant={occupant} buildKey={buildKey} idx={idx} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="w-full max-w-md mx-auto">
|
||||
<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>
|
||||
|
||||
{!isArrayLengthZero ? (
|
||||
<div className="text-center p-6 bg-gray-50 rounded-lg border border-gray-200">
|
||||
<p className="text-gray-600">{translation[lang].noSelections}</p>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
{Object.keys(selectionList.selectionList).map((buildKey: string) => (
|
||||
<BuildingSection
|
||||
key={buildKey}
|
||||
building={selectionList.activeSelection}
|
||||
buildKey={buildKey}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{error && <p className="mt-4 text-sm text-red-600">{error}</p>}
|
||||
{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>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default LoginOccupant;
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
import { LanguageTypes } from "@/validations/mutual/language/validations";
|
||||
|
||||
const afterLoginDirectUrl = () => {
|
||||
return `/panel/dashboard`;
|
||||
};
|
||||
|
||||
function selectEmployeeHook(
|
||||
startTransition: any,
|
||||
data: any,
|
||||
setError: any,
|
||||
setJsonText: any,
|
||||
Router: any,
|
||||
lang: LanguageTypes
|
||||
) {
|
||||
try {
|
||||
const sendData = { ...data };
|
||||
startTransition(() => {
|
||||
fetch("/api/selection/employee", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(sendData),
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
response.json().then((data) => {
|
||||
console.log("data", data);
|
||||
setTimeout(() => {
|
||||
Router.push(afterLoginDirectUrl());
|
||||
}, 100);
|
||||
});
|
||||
} else {
|
||||
response.json().then((data) => {
|
||||
setError(data?.message);
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
});
|
||||
} catch (error) {
|
||||
setError("An error occurred during login");
|
||||
}
|
||||
}
|
||||
|
||||
function selectOccupantHook(
|
||||
startTransition: any,
|
||||
data: any,
|
||||
setError: any,
|
||||
setJsonText: any,
|
||||
Router: any,
|
||||
lang: LanguageTypes
|
||||
) {
|
||||
try {
|
||||
const sendData = { ...data };
|
||||
startTransition(() => {
|
||||
fetch("/api/selection/occupant", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(sendData),
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
response.json().then((data) => {
|
||||
console.log("data", data);
|
||||
setTimeout(() => {
|
||||
Router.push(afterLoginDirectUrl());
|
||||
}, 100);
|
||||
});
|
||||
} else {
|
||||
response.json().then((data) => {
|
||||
setError(data?.message);
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
});
|
||||
} catch (error) {
|
||||
setError("An error occurred during login");
|
||||
}
|
||||
}
|
||||
|
||||
export { selectEmployeeHook, selectOccupantHook };
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
export const selectEmployeeTranslation = {
|
||||
tr: {
|
||||
companySelection: "Şirket Seçimi",
|
||||
loggedInAs: "Çalışan olarak giriş yaptınız",
|
||||
duty: "Görev",
|
||||
id: "Kimlik",
|
||||
noSelections: "Seçenek bulunamadı",
|
||||
continue: "Devam et",
|
||||
select: "Konut Seçimi",
|
||||
|
||||
},
|
||||
en: {
|
||||
companySelection: "Select your company",
|
||||
loggedInAs: "You are logged in as an employee",
|
||||
duty: "Duty",
|
||||
id: "ID",
|
||||
noSelections: "No selections available",
|
||||
continue: "Continue",
|
||||
select: "Select Occupant",
|
||||
|
||||
},
|
||||
};
|
||||
|
||||
export const selectOccupantTranslation = {
|
||||
tr: {
|
||||
occupantSelection: "Daire Seçimi",
|
||||
loggedInAs: "Kiracı olarak giriş yaptınız",
|
||||
buildingInfo: "Bina Bilgisi",
|
||||
level: "Kat",
|
||||
noSelections: "Seçenek bulunamadı",
|
||||
continue: "Devam et",
|
||||
select: "Şirket Seçimi",
|
||||
|
||||
},
|
||||
en: {
|
||||
occupantSelection: "Select your occupant type",
|
||||
loggedInAs: "You are logged in as an occupant",
|
||||
buildingInfo: "Building Info",
|
||||
level: "Level",
|
||||
continue: "Continue",
|
||||
noSelections: "No selections available",
|
||||
select: "Select Company",
|
||||
},
|
||||
};
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
"use client";
|
||||
import LoginOccupant from "./LoginOccupant";
|
||||
import LoginEmployee from "./LoginEmployee";
|
||||
|
||||
import { SelectListProps } from "./types";
|
||||
|
||||
const Select: React.FC<SelectListProps> = ({ language, type }) => {
|
||||
const isEmployeee = type.toLowerCase() == "employee";
|
||||
const isOccupante = type.toLowerCase() == "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">
|
||||
{isEmployeee && <LoginEmployee lang={language} />}
|
||||
{isOccupante && <LoginOccupant lang={language} />}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Select;
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
import { ClientSelection } from "@/types/mutual/context/validations";
|
||||
import { LanguageTypes } from "@/validations/mutual/language/validations";
|
||||
|
||||
interface Company {
|
||||
uu_id: string;
|
||||
public_name: string;
|
||||
company_type?: string;
|
||||
company_address?: any;
|
||||
duty?: string;
|
||||
}
|
||||
|
||||
interface Occupant {
|
||||
build_living_space_uu_id: string;
|
||||
part_uu_id: string;
|
||||
part_name: string;
|
||||
part_level: number;
|
||||
occupant_uu_id: string;
|
||||
description: string;
|
||||
code: string;
|
||||
}
|
||||
|
||||
interface Building {
|
||||
build_uu_id: string;
|
||||
build_name: string;
|
||||
build_no: string;
|
||||
occupants: Occupant[];
|
||||
}
|
||||
|
||||
interface BuildingMap {
|
||||
[key: string]: Building;
|
||||
}
|
||||
|
||||
interface SelectListProps {
|
||||
language: LanguageTypes;
|
||||
type: string;
|
||||
}
|
||||
|
||||
interface LoginOccupantProps {
|
||||
lang: LanguageTypes;
|
||||
}
|
||||
|
||||
interface LoginEmployeeProps {
|
||||
lang: LanguageTypes;
|
||||
}
|
||||
|
||||
export type {
|
||||
Company,
|
||||
Occupant,
|
||||
Building,
|
||||
BuildingMap,
|
||||
SelectListProps,
|
||||
LoginOccupantProps,
|
||||
LoginEmployeeProps,
|
||||
};
|
||||
Loading…
Reference in New Issue