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;
|
const { method = "POST", cache = false, timeout = DEFAULT_TIMEOUT } = options;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Setup controller for timeout handling
|
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
|
|
||||||
// Prepare fetch options
|
|
||||||
const fetchOptions: RequestInit = {
|
const fetchOptions: RequestInit = {
|
||||||
method,
|
method,
|
||||||
headers,
|
headers,
|
||||||
|
|
@ -55,26 +52,17 @@ async function coreFetch<T>(
|
||||||
signal: controller.signal,
|
signal: controller.signal,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add body for non-GET requests with payload
|
|
||||||
if (method !== "GET" && payload) {
|
if (method !== "GET" && payload) {
|
||||||
fetchOptions.body = JSON.stringify(
|
fetchOptions.body = JSON.stringify(
|
||||||
payload.payload ? payload.payload : payload
|
payload.payload ? payload.payload : payload
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create timeout promise
|
|
||||||
const timeoutPromise = createTimeoutPromise(timeout, controller);
|
const timeoutPromise = createTimeoutPromise(timeout, controller);
|
||||||
|
|
||||||
// Execute request with timeout
|
|
||||||
const response = await Promise.race([
|
const response = await Promise.race([
|
||||||
fetch(url, fetchOptions),
|
fetch(url, fetchOptions),
|
||||||
timeoutPromise,
|
timeoutPromise,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Parse response
|
|
||||||
const responseData = await response.json();
|
const responseData = await response.json();
|
||||||
|
|
||||||
// Return standardized response
|
|
||||||
return {
|
return {
|
||||||
status: response.status,
|
status: response.status,
|
||||||
data: responseData || ({} as T),
|
data: responseData || ({} as T),
|
||||||
|
|
@ -116,12 +104,8 @@ async function fetchDataWithToken<T>(
|
||||||
cache: boolean = false,
|
cache: boolean = false,
|
||||||
timeout: number = DEFAULT_TIMEOUT
|
timeout: number = DEFAULT_TIMEOUT
|
||||||
): Promise<ApiResponse<T>> {
|
): Promise<ApiResponse<T>> {
|
||||||
const accessToken = (await retrieveAccessToken());
|
const accessToken = await retrieveAccessToken();
|
||||||
const headers = {
|
const headers = { ...defaultHeaders, "eys-acs-tkn": accessToken };
|
||||||
...defaultHeaders,
|
|
||||||
"eys-acs-tkn": accessToken,
|
|
||||||
};
|
|
||||||
|
|
||||||
return coreFetch<T>(endpoint, { method, cache, timeout }, headers, payload);
|
return coreFetch<T>(endpoint, { method, cache, timeout }, headers, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -136,12 +120,8 @@ async function updateDataWithToken<T>(
|
||||||
cache: boolean = false,
|
cache: boolean = false,
|
||||||
timeout: number = DEFAULT_TIMEOUT
|
timeout: number = DEFAULT_TIMEOUT
|
||||||
): Promise<ApiResponse<T>> {
|
): Promise<ApiResponse<T>> {
|
||||||
const accessToken = (await retrieveAccessToken()) || "";
|
const accessToken = await retrieveAccessToken();
|
||||||
const headers = {
|
const headers = { ...defaultHeaders, "eys-acs-tkn": accessToken };
|
||||||
...defaultHeaders,
|
|
||||||
"eys-acs-tkn": accessToken,
|
|
||||||
};
|
|
||||||
|
|
||||||
return coreFetch<T>(
|
return coreFetch<T>(
|
||||||
`${endpoint}/${uuid}`,
|
`${endpoint}/${uuid}`,
|
||||||
{ method, cache, timeout },
|
{ method, cache, timeout },
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
import { redis } from "@/lib/redis";
|
import { redis } from "@/lib/redis";
|
||||||
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
|
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
|
||||||
import { ClientRedisToken } from "@/types/mutual/context/validations";
|
import { ClientRedisToken } from "@/types/mutual/context/validations";
|
||||||
|
import { AuthError } from "@/types/mutual/context/validations";
|
||||||
|
|
||||||
// Redis operation timeout (5 seconds)
|
// Redis operation timeout (5 seconds)
|
||||||
const REDIS_TIMEOUT = 5000;
|
const REDIS_TIMEOUT = 5000;
|
||||||
|
|
@ -76,51 +77,20 @@ const defaultValues: ClientRedisToken = {
|
||||||
const getCompleteFromRedis = async (): Promise<ClientRedisToken> => {
|
const getCompleteFromRedis = async (): Promise<ClientRedisToken> => {
|
||||||
try {
|
try {
|
||||||
let decrpytUserSelection;
|
let decrpytUserSelection;
|
||||||
try {
|
try { decrpytUserSelection = await functionRetrieveUserSelection() } catch (error) { return defaultValues }
|
||||||
decrpytUserSelection = await functionRetrieveUserSelection();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error retrieving user selection:', error);
|
|
||||||
return defaultValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
const redisKey = decrpytUserSelection?.redisKey;
|
const redisKey = decrpytUserSelection?.redisKey;
|
||||||
|
if (!redisKey) { return defaultValues }
|
||||||
if (!redisKey) {
|
if (redisKey === "default") { return defaultValues }
|
||||||
console.error("No redis key found in user selection");
|
|
||||||
return defaultValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (redisKey === "default") {
|
|
||||||
return defaultValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const timeoutPromise = new Promise<string | null>((_, reject) => {
|
const timeoutPromise = new Promise<string | null>((_, reject) => {
|
||||||
setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT);
|
setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT);
|
||||||
});
|
});
|
||||||
|
const result = await Promise.race([redis.get(`${redisKey}`), timeoutPromise]);
|
||||||
// Race the Redis operation against the timeout
|
if (!result) { return defaultValues }
|
||||||
const result = await Promise.race([
|
try { const parsedResult = JSON.parse(result); return parsedResult } catch (parseError) { return defaultValues }
|
||||||
redis.get(`${redisKey}`),
|
} catch (redisError) { return defaultValues }
|
||||||
timeoutPromise
|
} catch (error) { return defaultValues }
|
||||||
]);
|
|
||||||
|
|
||||||
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> => {
|
const setCompleteToRedis = async (completeObject: ClientRedisToken): Promise<boolean> => {
|
||||||
try {
|
try {
|
||||||
if (!completeObject) {
|
if (!completeObject) { return false }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let decrpytUserSelection;
|
let decrpytUserSelection;
|
||||||
try {
|
try { decrpytUserSelection = await functionRetrieveUserSelection() } catch (error) { return false }
|
||||||
decrpytUserSelection = await functionRetrieveUserSelection();
|
if (!decrpytUserSelection) { return false }
|
||||||
} catch (error) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!decrpytUserSelection) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const redisKey = decrpytUserSelection?.redisKey;
|
const redisKey = decrpytUserSelection?.redisKey;
|
||||||
if (!redisKey) {
|
if (!redisKey) { return false }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const timeoutPromise = new Promise((_, reject) => {
|
const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT) });
|
||||||
setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT);
|
await Promise.race([redis.set(redisKey, JSON.stringify(completeObject)), timeoutPromise]);
|
||||||
});
|
|
||||||
await Promise.race([
|
|
||||||
redis.set(redisKey, JSON.stringify(completeObject)),
|
|
||||||
timeoutPromise
|
|
||||||
]);
|
|
||||||
return true;
|
return true;
|
||||||
} catch (redisError) {
|
} catch (redisError) { return false }
|
||||||
return false;
|
} catch (error) { 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> => {
|
const setNewCompleteToRedis = async (completeObject: ClientRedisToken, redisKey: string): Promise<boolean> => {
|
||||||
try {
|
try {
|
||||||
if (!redisKey) {
|
if (!redisKey) { return false }
|
||||||
return false;
|
if (!completeObject) { return false }
|
||||||
}
|
|
||||||
|
|
||||||
if (!completeObject) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const timeoutPromise = new Promise((_, reject) => {
|
const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT) });
|
||||||
setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT);
|
await Promise.race([redis.set(redisKey, JSON.stringify(completeObject)), timeoutPromise])
|
||||||
});
|
|
||||||
await Promise.race([
|
|
||||||
redis.set(redisKey, JSON.stringify(completeObject)),
|
|
||||||
timeoutPromise
|
|
||||||
]);
|
|
||||||
return true;
|
return true;
|
||||||
} catch (redisError) {
|
} catch (redisError) { return false }
|
||||||
return false;
|
} catch (error) { return false }
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { getCompleteFromRedis, setCompleteToRedis, setNewCompleteToRedis };
|
export { getCompleteFromRedis, setCompleteToRedis, setNewCompleteToRedis };
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { redis } from "@/lib/redis";
|
||||||
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
|
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
|
||||||
import { ClientSelection } from "@/types/mutual/context/validations";
|
import { ClientSelection } from "@/types/mutual/context/validations";
|
||||||
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
|
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
|
||||||
|
import { AuthError } from "@/types/mutual/context/validations";
|
||||||
|
|
||||||
const getSelectionFromRedis = async (): Promise<ClientSelection> => {
|
const getSelectionFromRedis = async (): Promise<ClientSelection> => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -18,15 +19,28 @@ const getSelectionFromRedis = async (): Promise<ClientSelection> => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const setSelectionToRedis = async (selectionObject: ClientSelection) => {
|
const setSelectionToRedis = async (selectionObject: ClientSelection) => {
|
||||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
try {
|
||||||
if (!decrpytUserSelection) throw new Error("No user selection found");
|
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||||
const redisKey = decrpytUserSelection?.redisKey;
|
if (!decrpytUserSelection) throw new AuthError("No user selection found");
|
||||||
if (!redisKey) throw new Error("No redis key found");
|
|
||||||
if (!selectionObject) throw new Error("No selection object provided");
|
const redisKey = decrpytUserSelection?.redisKey;
|
||||||
const oldData = await getCompleteFromRedis();
|
if (!redisKey) throw new AuthError("No redis key found");
|
||||||
if (!oldData) throw new Error("No old data found in redis");
|
|
||||||
await setCompleteToRedis({ ...oldData, selection: selectionObject })
|
if (!selectionObject) throw new AuthError("No selection object provided");
|
||||||
return true;
|
|
||||||
|
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 };
|
export { getSelectionFromRedis, setSelectionToRedis };
|
||||||
|
|
|
||||||
|
|
@ -3,28 +3,46 @@ import { redis } from "@/lib/redis";
|
||||||
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
|
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
|
||||||
import { ClientSettings } from "@/types/mutual/context/validations";
|
import { ClientSettings } from "@/types/mutual/context/validations";
|
||||||
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
|
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
|
||||||
|
import { AuthError } from "@/types/mutual/context/validations";
|
||||||
|
|
||||||
const getSettingsFromRedis = async (): Promise<ClientSettings> => {
|
const getSettingsFromRedis = async (): Promise<ClientSettings> => {
|
||||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
try {
|
||||||
const redisKey = decrpytUserSelection?.redisKey;
|
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||||
if (!redisKey) throw new Error("No redis key found");
|
const redisKey = decrpytUserSelection?.redisKey;
|
||||||
const result = await redis.get(`${redisKey}`);
|
if (!redisKey) throw new AuthError("No redis key found");
|
||||||
if (!result) throw new Error("No data found in redis");
|
|
||||||
const parsedResult = JSON.parse(result);
|
const result = await redis.get(`${redisKey}`);
|
||||||
if (!parsedResult.settings) throw new Error("No settings found in redis");
|
if (!result) throw new AuthError("No data found in redis");
|
||||||
return parsedResult.settings;
|
|
||||||
|
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 setSettingsToRedis = async (settingsObject: ClientSettings) => {
|
||||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
try {
|
||||||
if (!decrpytUserSelection) throw new Error("No user selection found");
|
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||||
const redisKey = decrpytUserSelection?.redisKey;
|
if (!decrpytUserSelection) throw new AuthError("No user selection found");
|
||||||
if (!redisKey) throw new Error("No redis key found");
|
|
||||||
if (!settingsObject) throw new Error("No settings object provided");
|
const redisKey = decrpytUserSelection?.redisKey;
|
||||||
const oldData = await getCompleteFromRedis();
|
if (!redisKey) throw new AuthError("No redis key found");
|
||||||
if (!oldData) throw new Error("No old data found in redis");
|
|
||||||
await setCompleteToRedis({ ...oldData, settings: settingsObject })
|
if (!settingsObject) throw new AuthError("No settings object provided");
|
||||||
return true;
|
|
||||||
|
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 };
|
export { getSettingsFromRedis, setSettingsToRedis };
|
||||||
|
|
|
||||||
|
|
@ -3,28 +3,46 @@ import { redis } from "@/lib/redis";
|
||||||
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
|
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
|
||||||
import { ClientUser } from "@/types/mutual/context/validations";
|
import { ClientUser } from "@/types/mutual/context/validations";
|
||||||
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
|
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
|
||||||
|
import { AuthError } from "@/types/mutual/context/validations";
|
||||||
|
|
||||||
const getUserFromRedis = async (): Promise<ClientUser> => {
|
const getUserFromRedis = async (): Promise<ClientUser> => {
|
||||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
try {
|
||||||
const redisKey = decrpytUserSelection?.redisKey;
|
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||||
if (!redisKey) throw new Error("No redis key found");
|
const redisKey = decrpytUserSelection?.redisKey;
|
||||||
const result = await redis.get(`${redisKey}`);
|
if (!redisKey) throw new AuthError("No redis key found");
|
||||||
if (!result) throw new Error("No data found in redis");
|
|
||||||
const parsedResult = JSON.parse(result);
|
const result = await redis.get(`${redisKey}`);
|
||||||
if (!parsedResult.user) throw new Error("No user found in redis");
|
if (!result) throw new AuthError("No data found in redis");
|
||||||
return parsedResult.user;
|
|
||||||
|
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 setUserToRedis = async (userObject: ClientUser) => {
|
||||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
try {
|
||||||
if (!decrpytUserSelection) throw new Error("No user selection found");
|
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||||
const redisKey = decrpytUserSelection?.redisKey;
|
if (!decrpytUserSelection) throw new AuthError("No user selection found");
|
||||||
if (!redisKey) throw new Error("No redis key found");
|
|
||||||
if (!userObject) throw new Error("No user object provided");
|
const redisKey = decrpytUserSelection?.redisKey;
|
||||||
const oldData = await getCompleteFromRedis();
|
if (!redisKey) throw new AuthError("No redis key found");
|
||||||
if (!oldData) throw new Error("No old data found in redis");
|
|
||||||
await setCompleteToRedis({ ...oldData, user: userObject });
|
if (!userObject) throw new AuthError("No user object provided");
|
||||||
return true;
|
|
||||||
|
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 };
|
export { getUserFromRedis, setUserToRedis };
|
||||||
|
|
|
||||||
|
|
@ -3,28 +3,39 @@ import { redis } from "@/lib/redis";
|
||||||
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
|
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
|
||||||
import { ClientSettings } from "@/types/mutual/context/validations";
|
import { ClientSettings } from "@/types/mutual/context/validations";
|
||||||
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
|
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
|
||||||
|
import { AuthError } from "@/types/mutual/context/validations";
|
||||||
|
|
||||||
const getConfigFromRedis = async (): Promise<ClientSettings> => {
|
const getConfigFromRedis = async (): Promise<ClientSettings> => {
|
||||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
try {
|
||||||
const redisKey = decrpytUserSelection?.redisKey;
|
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||||
if (!redisKey) throw new Error("No redis key found");
|
const redisKey = decrpytUserSelection?.redisKey;
|
||||||
const result = await redis.get(`${redisKey}`);
|
if (!redisKey) throw new AuthError("No redis key found");
|
||||||
if (!result) throw new Error("No data found in redis");
|
const result = await redis.get(`${redisKey}`);
|
||||||
const parsedResult = JSON.parse(result);
|
if (!result) throw new AuthError("No data found in redis");
|
||||||
if (!parsedResult.settings) throw new Error("No settings found in redis");
|
const parsedResult = JSON.parse(result);
|
||||||
return parsedResult.settings;
|
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 setConfigToRedis = async (settingsObject: ClientSettings) => {
|
||||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
try {
|
||||||
if (!decrpytUserSelection) throw new Error("No user selection found");
|
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||||
const redisKey = decrpytUserSelection?.redisKey;
|
if (!decrpytUserSelection) throw new AuthError("No user selection found");
|
||||||
if (!redisKey) throw new Error("No redis key found");
|
const redisKey = decrpytUserSelection?.redisKey;
|
||||||
if (!settingsObject) throw new Error("No settings object provided");
|
if (!redisKey) throw new AuthError("No redis key found");
|
||||||
const oldData = await getCompleteFromRedis();
|
if (!settingsObject) throw new AuthError("No settings object provided");
|
||||||
if (!oldData) throw new Error("No old data found in redis");
|
const oldData = await getCompleteFromRedis();
|
||||||
await setCompleteToRedis({ ...oldData, settings: settingsObject });
|
if (!oldData) throw new AuthError("No old data found in redis");
|
||||||
return true;
|
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 { functionRetrieveUserSelection } from "@/apifetchers/utils";
|
||||||
import { ClientMenu } from "@/types/mutual/context/validations";
|
import { ClientMenu } from "@/types/mutual/context/validations";
|
||||||
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
|
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
|
||||||
|
import { AuthError } from "@/types/mutual/context/validations";
|
||||||
|
|
||||||
const getMenuFromRedis = async (): Promise<ClientMenu> => {
|
const getMenuFromRedis = async (): Promise<ClientMenu> => {
|
||||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
try {
|
||||||
const redisKey = decrpytUserSelection?.redisKey;
|
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||||
if (!redisKey) throw new Error("No redis key found");
|
const redisKey = decrpytUserSelection?.redisKey;
|
||||||
const result = await redis.get(`${redisKey}`);
|
if (!redisKey) throw new AuthError("No redis key found");
|
||||||
if (!result) throw new Error("No data found in redis");
|
const result = await redis.get(`${redisKey}`);
|
||||||
const parsedResult = JSON.parse(result);
|
if (!result) throw new AuthError("No data found in redis");
|
||||||
if (!parsedResult.menu) throw new Error("No menu found in redis");
|
const parsedResult = JSON.parse(result);
|
||||||
return parsedResult.menu;
|
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 setMenuToRedis = async (menuObject: ClientMenu) => {
|
||||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
try {
|
||||||
if (!decrpytUserSelection) throw new Error("No user selection found");
|
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||||
const redisKey = decrpytUserSelection?.redisKey;
|
if (!decrpytUserSelection) throw new AuthError("No user selection found");
|
||||||
if (!redisKey) throw new Error("No redis key found");
|
const redisKey = decrpytUserSelection?.redisKey;
|
||||||
if (!menuObject) throw new Error("No menu object provided");
|
if (!redisKey) throw new AuthError("No redis key found");
|
||||||
const oldData = await getCompleteFromRedis();
|
if (!menuObject) throw new AuthError("No menu object provided");
|
||||||
if (!oldData) throw new Error("No old data found in redis");
|
const oldData = await getCompleteFromRedis();
|
||||||
await setCompleteToRedis({ ...oldData, menu: menuObject });
|
if (!oldData) throw new AuthError("No old data found in redis");
|
||||||
return true;
|
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 };
|
export { getMenuFromRedis, setMenuToRedis };
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,7 @@ import { redis } from "@/lib/redis";
|
||||||
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
|
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
|
||||||
import { ClientOnline } from "@/types/mutual/context/validations";
|
import { ClientOnline } from "@/types/mutual/context/validations";
|
||||||
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
|
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
|
||||||
|
import { AuthError } from "@/types/mutual/context/validations";
|
||||||
// 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"
|
|
||||||
};
|
|
||||||
|
|
||||||
// Redis operation timeout (5 seconds)
|
// Redis operation timeout (5 seconds)
|
||||||
const REDIS_TIMEOUT = 5000;
|
const REDIS_TIMEOUT = 5000;
|
||||||
|
|
@ -24,72 +14,25 @@ const REDIS_TIMEOUT = 5000;
|
||||||
*/
|
*/
|
||||||
const getOnlineFromRedis = async (): Promise<ClientOnline> => {
|
const getOnlineFromRedis = async (): Promise<ClientOnline> => {
|
||||||
try {
|
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 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 {
|
try {
|
||||||
// Create a promise that rejects after the timeout
|
const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT) });
|
||||||
const timeoutPromise = new Promise((_, reject) => {
|
result = await Promise.race([redis.get(`${redisKey}`), timeoutPromise]) as string | null;
|
||||||
setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT);
|
} catch (redisError) { throw new AuthError('Failed to access Redis data') }
|
||||||
});
|
|
||||||
|
|
||||||
// Race the Redis operation against the timeout
|
if (!result) { throw new AuthError('No data found in redis') }
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the result
|
|
||||||
try {
|
try {
|
||||||
const parsedResult = JSON.parse(result);
|
const parsedResult = JSON.parse(result);
|
||||||
console.log('Successfully parsed Redis result');
|
if (!parsedResult.online) { throw new AuthError('No online data found in redis') }
|
||||||
|
|
||||||
if (!parsedResult.online) {
|
|
||||||
console.warn('No online object in parsed result');
|
|
||||||
return defaultOnlineObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Returning online object from Redis');
|
|
||||||
return parsedResult.online;
|
return parsedResult.online;
|
||||||
} catch (parseError) {
|
} catch (parseError) { throw new AuthError('Invalid data format in redis') }
|
||||||
console.error('Error parsing Redis result:', parseError);
|
} catch (error) { if (error instanceof AuthError) { throw error } else { throw new AuthError(error instanceof Error ? error.message : 'Unknown error') } }
|
||||||
return defaultOnlineObject;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Unexpected error in getOnlineFromRedis:', error);
|
|
||||||
return defaultOnlineObject;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -99,75 +42,23 @@ const getOnlineFromRedis = async (): Promise<ClientOnline> => {
|
||||||
*/
|
*/
|
||||||
const setOnlineToRedis = async (onlineObject: ClientOnline): Promise<boolean> => {
|
const setOnlineToRedis = async (onlineObject: ClientOnline): Promise<boolean> => {
|
||||||
try {
|
try {
|
||||||
console.log('Setting online state in Redis:', onlineObject);
|
if (!onlineObject) { throw new AuthError('No online object provided') }
|
||||||
|
|
||||||
// Validate input
|
|
||||||
if (!onlineObject) {
|
|
||||||
console.error('No online object provided');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get user selection
|
|
||||||
let decrpytUserSelection;
|
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;
|
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 {
|
try {
|
||||||
oldData = await getCompleteFromRedis();
|
const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT) });
|
||||||
console.log('Retrieved existing data from Redis');
|
await Promise.race([setCompleteToRedis({ ...oldData, online: onlineObject }), timeoutPromise]);
|
||||||
} 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');
|
|
||||||
return true;
|
return true;
|
||||||
} catch (redisError) {
|
} catch (redisError) { throw new AuthError('Failed to update Redis data') }
|
||||||
console.error('Error updating Redis:', redisError);
|
} catch (error) { if (error instanceof AuthError) throw error; throw new AuthError(error instanceof Error ? error.message : 'Unknown error') }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Unexpected error in setOnlineToRedis:', error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { getOnlineFromRedis, setOnlineToRedis };
|
export { getOnlineFromRedis, setOnlineToRedis };
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import NextCrypto from "next-crypto";
|
||||||
import { fetchDataWithToken } from "@/apifetchers/api-fetcher";
|
import { fetchDataWithToken } from "@/apifetchers/api-fetcher";
|
||||||
import { baseUrlAuth, baseUrlRestriction, tokenSecret } from "@/apifetchers/basics";
|
import { baseUrlAuth, baseUrlRestriction, tokenSecret } from "@/apifetchers/basics";
|
||||||
import { cookies } from "next/headers";
|
import { cookies } from "next/headers";
|
||||||
|
import { AuthError } from "@/types/mutual/context/validations";
|
||||||
|
|
||||||
const checkToken = `${baseUrlAuth}/authentication/token/check`;
|
const checkToken = `${baseUrlAuth}/authentication/token/check`;
|
||||||
const pageValid = `${baseUrlRestriction}/restrictions/page/valid`;
|
const pageValid = `${baseUrlRestriction}/restrictions/page/valid`;
|
||||||
|
|
@ -18,10 +19,7 @@ async function checkAccessTokenIsValid() {
|
||||||
try {
|
try {
|
||||||
const response = await fetchDataWithToken(checkToken, {}, "GET", false);
|
const response = await fetchDataWithToken(checkToken, {}, "GET", false);
|
||||||
return fetchResponseStatus(response);
|
return fetchResponseStatus(response);
|
||||||
} catch (error) {
|
} catch (error) { throw new AuthError("No access token found") }
|
||||||
console.error("Error checking token validity:", error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function retrievePageList() {
|
async function retrievePageList() {
|
||||||
|
|
@ -40,8 +38,7 @@ async function retrieveAccessToken() {
|
||||||
const encrpytAccessToken = cookieStore.get("eys-zzz")?.value || "";
|
const encrpytAccessToken = cookieStore.get("eys-zzz")?.value || "";
|
||||||
return await nextCrypto.decrypt(encrpytAccessToken) || "";
|
return await nextCrypto.decrypt(encrpytAccessToken) || "";
|
||||||
}
|
}
|
||||||
catch (error) { console.error("Error retrieving access token:", error) }
|
catch (error) { throw new AuthError("No access token found") }
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function retrieveAccessObjects() {
|
async function retrieveAccessObjects() {
|
||||||
|
|
@ -50,8 +47,7 @@ async function retrieveAccessObjects() {
|
||||||
const encrpytAccessObject = cookieStore.get("eys-yyy")?.value || "";
|
const encrpytAccessObject = cookieStore.get("eys-yyy")?.value || "";
|
||||||
return await nextCrypto.decrypt(encrpytAccessObject) || "";
|
return await nextCrypto.decrypt(encrpytAccessObject) || "";
|
||||||
}
|
}
|
||||||
catch (error) { console.error("Error retrieving access objects:", error) }
|
catch (error) { throw new AuthError("No access objects found") }
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|
|
||||||
|
|
@ -13,51 +13,20 @@ const functionRetrieveUserSelection = async () => {
|
||||||
try {
|
try {
|
||||||
const cookieStore = await cookies();
|
const cookieStore = await cookies();
|
||||||
const encrpytUserSelection = cookieStore.get("eys-sel")?.value || "";
|
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 {
|
try {
|
||||||
const decrpytUserSelection = await nextCrypto.decrypt(encrpytUserSelection);
|
const decrpytUserSelection = await nextCrypto.decrypt(encrpytUserSelection);
|
||||||
if (!decrpytUserSelection) {
|
if (!decrpytUserSelection) { return { redisKey: "default", uuid: "", timestamp: new Date().toISOString() } }
|
||||||
return {
|
|
||||||
redisKey: "default",
|
|
||||||
uuid: "",
|
|
||||||
timestamp: new Date().toISOString()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return JSON.parse(decrpytUserSelection);
|
return JSON.parse(decrpytUserSelection);
|
||||||
} catch (decryptError) {
|
} catch (decryptError) { return { redisKey: "default", uuid: "", timestamp: new Date().toISOString() } }
|
||||||
return {
|
} catch (error) { return { redisKey: "default", uuid: "", timestamp: new Date().toISOString() } }
|
||||||
redisKey: "default",
|
|
||||||
uuid: "",
|
|
||||||
timestamp: new Date().toISOString()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return {
|
|
||||||
redisKey: "default",
|
|
||||||
uuid: "",
|
|
||||||
timestamp: new Date().toISOString()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const functionSetUserSelection = async (userSelection: any) => {
|
const functionSetUserSelection = async (userSelection: any) => {
|
||||||
const cookieStore = await cookies();
|
const cookieStore = await cookies();
|
||||||
const encrpytUserSelection = await nextCrypto.encrypt(JSON.stringify(userSelection));
|
const encrpytUserSelection = await nextCrypto.encrypt(JSON.stringify(userSelection));
|
||||||
if (!encrpytUserSelection) throw new Error("No user selection found");
|
if (!encrpytUserSelection) throw new Error("No user selection found");
|
||||||
cookieStore.set({
|
cookieStore.set({ name: "eys-sel", value: encrpytUserSelection, ...cookieObject });
|
||||||
name: "eys-sel",
|
|
||||||
value: encrpytUserSelection,
|
|
||||||
...cookieObject,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const functionRemoveUserSelection = async () => {
|
const functionRemoveUserSelection = async () => {
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,17 @@ import { AuthLayout } from "@/layouts/auth/layout";
|
||||||
import { AuthServerProps } from "@/validations/mutual/pages/props";
|
import { AuthServerProps } from "@/validations/mutual/pages/props";
|
||||||
import { LanguageTypes } from "@/validations/mutual/language/validations";
|
import { LanguageTypes } from "@/validations/mutual/language/validations";
|
||||||
import { checkAccessTokenIsValid } from "@/apifetchers/mutual/cookies/token";
|
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 { 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 AuthPageSSR = async ({ params, searchParams }: AuthServerProps) => {
|
||||||
const awaitedParams = await params;
|
const awaitedParams = await params;
|
||||||
const awaitedSearchParams = await searchParams;
|
const awaitedSearchParams = await searchParams;
|
||||||
const pageUrlFromParams = `/${awaitedParams.page?.join("/")}` || "/login";
|
const pageUrlFromParams = `/${awaitedParams.page?.join("/")}` || "/login";
|
||||||
const tokenValid = await checkAccessTokenIsValid();
|
const tokenValid = await checkAccessTokenIsValid();
|
||||||
let FoundPage = <Login language={"en"} query={awaitedSearchParams} />
|
try { const online = await getOnlineFromRedis(); if (tokenValid && online) { redirect("/panel/dashboard") } } catch (error) { }
|
||||||
const online = await getOnlineFromRedis();
|
return <div className="flex flex-col items-center justify-center"><AuthLayout lang={"en"} page={<Login language={"en"} query={awaitedSearchParams} />} activePageUrl={pageUrlFromParams} /></div>
|
||||||
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>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AuthPageSSR;
|
export default AuthPageSSR;
|
||||||
|
|
|
||||||
|
|
@ -2,25 +2,12 @@
|
||||||
import { MaindasboardPageProps } from "@/validations/mutual/dashboard/props";
|
import { MaindasboardPageProps } from "@/validations/mutual/dashboard/props";
|
||||||
import { DashboardLayout } from "@/layouts/dashboard/layout";
|
import { DashboardLayout } from "@/layouts/dashboard/layout";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { fetchDataWithToken } from "@/apifetchers/api-fetcher";
|
import { checkAccessTokenIsValid } from "@/apifetchers/mutual/cookies/token";
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const MainEnPage: React.FC<MaindasboardPageProps> = async ({ params, searchParams }) => {
|
const MainEnPage: React.FC<MaindasboardPageProps> = async ({ params, searchParams }) => {
|
||||||
const parameters = await params;
|
const parameters = await params;
|
||||||
const searchParameters = await searchParams;
|
const searchParameters = await searchParams;
|
||||||
const tokenValid = await isTokenValid()
|
const tokenValid = await checkAccessTokenIsValid()
|
||||||
if (!tokenValid) { redirect("/auth/login") }
|
if (!tokenValid) { redirect("/auth/login") }
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center justify-center">
|
<div className="flex flex-col items-center justify-center">
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,74 @@ import {
|
||||||
getSelectionFromRedis,
|
getSelectionFromRedis,
|
||||||
setSelectionToRedis,
|
setSelectionToRedis,
|
||||||
} from "@/apifetchers/mutual/context/dash/selection/fetch";
|
} from "@/apifetchers/mutual/context/dash/selection/fetch";
|
||||||
|
import { AuthError } from "@/types/mutual/context/validations";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
const selection = await getSelectionFromRedis();
|
try {
|
||||||
return NextResponse.json({
|
const selection = await getSelectionFromRedis();
|
||||||
status: 200,
|
return NextResponse.json({
|
||||||
data: selection || null,
|
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) {
|
export async function POST(request: Request) {
|
||||||
const selection = await request.json();
|
try {
|
||||||
await setSelectionToRedis(selection);
|
const selection = await request.json();
|
||||||
return NextResponse.json({
|
await setSelectionToRedis(selection);
|
||||||
status: 200,
|
return NextResponse.json({
|
||||||
data: selection || null,
|
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,
|
getSettingsFromRedis,
|
||||||
setSettingsToRedis,
|
setSettingsToRedis,
|
||||||
} from "@/apifetchers/mutual/context/dash/settings/fetch";
|
} from "@/apifetchers/mutual/context/dash/settings/fetch";
|
||||||
|
import { AuthError } from "@/types/mutual/context/validations";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
const settings = await getSettingsFromRedis();
|
try {
|
||||||
return NextResponse.json(settings);
|
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) {
|
export async function POST(request: Request) {
|
||||||
const settings = await request.json();
|
try {
|
||||||
await setSettingsToRedis(settings);
|
const settings = await request.json();
|
||||||
return NextResponse.json(settings);
|
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,
|
getUserFromRedis,
|
||||||
setUserToRedis,
|
setUserToRedis,
|
||||||
} from "@/apifetchers/mutual/context/dash/user/fetch";
|
} from "@/apifetchers/mutual/context/dash/user/fetch";
|
||||||
|
import { AuthError } from "@/types/mutual/context/validations";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
const user = await getUserFromRedis();
|
try {
|
||||||
return NextResponse.json(user);
|
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) {
|
export async function POST(request: Request) {
|
||||||
const user = await request.json();
|
try {
|
||||||
await setUserToRedis(user);
|
const user = await request.json();
|
||||||
return NextResponse.json(user);
|
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,
|
getConfigFromRedis,
|
||||||
setConfigToRedis,
|
setConfigToRedis,
|
||||||
} from "@/apifetchers/mutual/context/page/config/fetch";
|
} from "@/apifetchers/mutual/context/page/config/fetch";
|
||||||
|
import { AuthError } from "@/types/mutual/context/validations";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
const config = await getConfigFromRedis();
|
try {
|
||||||
return NextResponse.json(config);
|
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) {
|
export async function POST(request: Request) {
|
||||||
const config = await request.json();
|
try {
|
||||||
await setConfigToRedis(config);
|
const config = await request.json();
|
||||||
return NextResponse.json(config);
|
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,
|
getMenuFromRedis,
|
||||||
setMenuToRedis,
|
setMenuToRedis,
|
||||||
} from "@/apifetchers/mutual/context/page/menu/fetch";
|
} from "@/apifetchers/mutual/context/page/menu/fetch";
|
||||||
|
import { AuthError } from "@/types/mutual/context/validations";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
const menu = await getMenuFromRedis();
|
try {
|
||||||
return NextResponse.json({
|
const menu = await getMenuFromRedis();
|
||||||
status: 200,
|
return NextResponse.json({
|
||||||
data: menu,
|
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) {
|
export async function POST(request: Request) {
|
||||||
const menu = await request.json();
|
try {
|
||||||
await setMenuToRedis(menu);
|
const menu = await request.json();
|
||||||
return NextResponse.json({
|
await setMenuToRedis(menu);
|
||||||
status: 200,
|
return NextResponse.json({
|
||||||
data: menu,
|
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,
|
getOnlineFromRedis,
|
||||||
setOnlineToRedis,
|
setOnlineToRedis,
|
||||||
} from "@/apifetchers/mutual/context/page/online/fetch";
|
} from "@/apifetchers/mutual/context/page/online/fetch";
|
||||||
|
import { AuthError } from "@/types/mutual/context/validations";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
const online = await getOnlineFromRedis();
|
try {
|
||||||
return NextResponse.json({
|
const online = await getOnlineFromRedis();
|
||||||
status: 200,
|
return NextResponse.json({
|
||||||
data: online,
|
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) {
|
export async function POST(request: Request) {
|
||||||
const online = await request.json();
|
try {
|
||||||
await setOnlineToRedis(online);
|
const online = await request.json();
|
||||||
return NextResponse.json({
|
await setOnlineToRedis(online);
|
||||||
status: 200,
|
return NextResponse.json({
|
||||||
data: online,
|
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> = ({
|
const HeaderComponent: FC<HeaderProps> = ({
|
||||||
lang, activePageUrl, prefix, mode,
|
lang, activePageUrl, prefix, mode,
|
||||||
onlineData, onlineLoading, onlineError,
|
onlineData, onlineLoading, onlineError, refreshOnline, updateOnline,
|
||||||
userData, userLoading, userError,
|
userData, userLoading, userError,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
|
|
@ -32,7 +32,10 @@ const HeaderComponent: FC<HeaderProps> = ({
|
||||||
<span className="font-semibold">{onlineData.lang || lang}</span>
|
<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>
|
<span className="ml-2 text-xs bg-green-100 text-green-800 px-2 py-1 rounded-full">{onlineData.userType}</span>
|
||||||
</div>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,6 @@ interface UseOnlineResult {
|
||||||
// Wrapper hook that adapts the generic hook to the expected interface
|
// Wrapper hook that adapts the generic hook to the expected interface
|
||||||
export function useOnline(): UseOnlineResult {
|
export function useOnline(): UseOnlineResult {
|
||||||
const { data, isLoading, error, refresh, update } = useContextOnline();
|
const { data, isLoading, error, refresh, update } = useContextOnline();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
onlineData: data,
|
onlineData: data,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,14 @@ interface LanguageSelectionComponentProps {
|
||||||
lang: LanguageTypes;
|
lang: LanguageTypes;
|
||||||
activePage: string;
|
activePage: string;
|
||||||
prefix: 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 translations = langGet(lang, languageSelectionTranslation);
|
||||||
const getPageWithLocale = (locale: LanguageTypes): string => { return `${prefix}/${activePage}` }
|
const getPageWithLocale = (locale: LanguageTypes): string => { return `${prefix}/${activePage}` }
|
||||||
const languageButtons = [
|
const languageButtons = [
|
||||||
|
|
@ -27,7 +32,8 @@ const LanguageSelectionComponent: React.FC<LanguageSelectionComponentProps> = ({
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent>
|
<DropdownMenuContent>
|
||||||
{languageButtons.map((props, index) => (
|
{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>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,26 @@
|
||||||
'use client';
|
'use client';
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import { DropdownMenuItem } from "@/components/mutual/shadcnui/dropdown-menu";
|
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 }> = (
|
interface LanguageSelectionItemProps {
|
||||||
{ refUrl, innerText, buttonsLang }) => {
|
activeLang: string,
|
||||||
const router = useRouter();
|
buttonsLang: string,
|
||||||
// Use the new hook properties: onlineData instead of online, refreshOnline and updateOnline
|
refUrl: string,
|
||||||
const { onlineData, isLoading, error, refreshOnline, updateOnline } = useOnline();
|
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 () => {
|
const setOnlineObject = async () => {
|
||||||
if (!onlineData || isLoading) return;
|
if (!onlineData || onlineLoading) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log("Updating language to:", buttonsLang);
|
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({
|
const success = await updateOnline({
|
||||||
...onlineData,
|
...onlineData,
|
||||||
lang: buttonsLang,
|
lang: buttonsLang,
|
||||||
|
|
@ -28,10 +29,7 @@ const RenderButtonComponent: FC<{ refUrl: string, innerText: string, buttonsLang
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
console.log("Language updated successfully");
|
console.log("Language updated successfully");
|
||||||
// Refresh the online data to get the latest state
|
|
||||||
await refreshOnline();
|
await refreshOnline();
|
||||||
// Navigate to the new URL
|
|
||||||
router.push(refUrl);
|
|
||||||
} else {
|
} else {
|
||||||
console.error("Failed to update language");
|
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;
|
const currentLang = onlineData?.lang || activeLang;
|
||||||
|
|
||||||
// Determine if this button should be active (not the current language)
|
|
||||||
const isActive = buttonsLang !== currentLang;
|
const isActive = buttonsLang !== currentLang;
|
||||||
|
|
||||||
const RenderButtonProp = {
|
const RenderButtonProp = {
|
||||||
refUrl,
|
refUrl,
|
||||||
innerText,
|
innerText,
|
||||||
buttonsLang
|
activeLang,
|
||||||
|
buttonsLang,
|
||||||
|
onlineData,
|
||||||
|
onlineLoading,
|
||||||
|
onlineError,
|
||||||
|
refreshOnline,
|
||||||
|
updateOnline
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only render the button if it's not the current language
|
// Only render the button if it's not the current language
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
'use server';
|
'use server';
|
||||||
import { FC, Suspense } from "react";
|
import { FC, Suspense } from "react";
|
||||||
import { AuthLayoutProps } from "@/validations/mutual/auth/props";
|
import { AuthLayoutProps } from "@/validations/mutual/auth/props";
|
||||||
import LanguageSelectionComponent from "@/components/mutual/languageSelection/component";
|
|
||||||
|
|
||||||
const AuthLayout: FC<AuthLayoutProps> = async ({ lang, page, activePageUrl }) => {
|
const AuthLayout: FC<AuthLayoutProps> = async ({ lang, page, activePageUrl }) => {
|
||||||
return (
|
return (
|
||||||
|
|
@ -13,7 +12,6 @@ const AuthLayout: FC<AuthLayoutProps> = async ({ lang, page, activePageUrl }) =>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-3/4 text-black">
|
<div className="w-3/4 text-black">
|
||||||
<LanguageSelectionComponent lang={lang} activePage={activePageUrl} prefix={"/auth"} />
|
|
||||||
<Suspense fallback={<div>Loading...</div>}>{page}</Suspense>
|
<Suspense fallback={<div>Loading...</div>}>{page}</Suspense>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -35,87 +35,31 @@ interface ClientLayoutProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ClientLayout: FC<ClientLayoutProps> = ({ allProps }) => {
|
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 { userData, isLoading: userLoading, error: userError } = useUser();
|
||||||
const { availableApplications, isLoading: menuLoading, error: menuError, menuData, refreshMenu } = useMenu();
|
const { availableApplications, isLoading: menuLoading, error: menuError, menuData, refreshMenu } = useMenu();
|
||||||
const { selectionData, isLoading: selectionLoading, error: selectionError } = useSelection();
|
const { selectionData, isLoading: selectionLoading, error: selectionError } = useSelection();
|
||||||
const { configData, isLoading: configLoading, error: configError } = useConfig();
|
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 (
|
return (
|
||||||
<ClientProviders>
|
<ClientProviders>
|
||||||
<div className="flex flex-col min-w-screen">
|
<div className="flex flex-col min-w-screen">
|
||||||
<HeaderComponent {...allProps}
|
<HeaderComponent {...allProps}
|
||||||
useReloadWindow={useReloadWindow}
|
|
||||||
onlineData={onlineData} onlineLoading={onlineLoading} onlineError={onlineError}
|
onlineData={onlineData} onlineLoading={onlineLoading} onlineError={onlineError}
|
||||||
|
refreshOnline={refreshOnline} updateOnline={updateOnline}
|
||||||
userData={userData} userLoading={userLoading} userError={userError}
|
userData={userData} userLoading={userLoading} userError={userError}
|
||||||
/>
|
/>
|
||||||
<MenuComponent {...allProps}
|
<MenuComponent {...allProps}
|
||||||
useReloadWindow={useReloadWindow}
|
|
||||||
availableApplications={availableApplications}
|
availableApplications={availableApplications}
|
||||||
onlineData={onlineData} onlineLoading={onlineLoading} onlineError={onlineError}
|
onlineData={onlineData} onlineLoading={onlineLoading} onlineError={onlineError}
|
||||||
userData={userData} userLoading={userLoading} userError={userError}
|
userData={userData} userLoading={userLoading} userError={userError}
|
||||||
selectionData={selectionData} selectionLoading={selectionLoading} selectionError={selectionError}
|
selectionData={selectionData} selectionLoading={selectionLoading} selectionError={selectionError}
|
||||||
menuData={menuData} menuLoading={menuLoading} menuError={menuError} />
|
menuData={menuData} menuLoading={menuLoading} menuError={menuError} />
|
||||||
<ContentComponent {...allProps}
|
<ContentComponent {...allProps}
|
||||||
useReloadWindow={useReloadWindow}
|
|
||||||
userData={userData} userLoading={userLoading} userError={userError}
|
userData={userData} userLoading={userLoading} userError={userError}
|
||||||
selectionData={selectionData} selectionLoading={selectionLoading} selectionError={selectionError}
|
selectionData={selectionData} selectionLoading={selectionLoading} selectionError={selectionError}
|
||||||
/>
|
/>
|
||||||
<FooterComponent {...allProps}
|
<FooterComponent {...allProps}
|
||||||
useReloadWindow={useReloadWindow}
|
|
||||||
availableApplications={availableApplications}
|
availableApplications={availableApplications}
|
||||||
configData={configData} configLoading={configLoading} configError={configError}
|
configData={configData} configLoading={configLoading} configError={configError}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,10 @@
|
||||||
// From Redis objects
|
// From Redis objects
|
||||||
|
export class AuthError extends Error {
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message);
|
||||||
|
this.name = 'AuthError';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface ClientOnline {
|
interface ClientOnline {
|
||||||
lastLogin: Date;
|
lastLogin: Date;
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ interface ContentProps {
|
||||||
lang: LanguageTypes;
|
lang: LanguageTypes;
|
||||||
activePageUrl: string;
|
activePageUrl: string;
|
||||||
mode?: ModeTypes;
|
mode?: ModeTypes;
|
||||||
useReloadWindow?: () => void;
|
|
||||||
userData: any;
|
userData: any;
|
||||||
userLoading: boolean;
|
userLoading: boolean;
|
||||||
userError: any;
|
userError: any;
|
||||||
|
|
@ -32,7 +31,6 @@ interface MenuProps {
|
||||||
lang: LanguageTypes;
|
lang: LanguageTypes;
|
||||||
availableApplications: string[];
|
availableApplications: string[];
|
||||||
activePageUrl: string;
|
activePageUrl: string;
|
||||||
useReloadWindow?: () => void;
|
|
||||||
onlineData: any;
|
onlineData: any;
|
||||||
onlineLoading: boolean;
|
onlineLoading: boolean;
|
||||||
onlineError: any;
|
onlineError: any;
|
||||||
|
|
@ -51,7 +49,6 @@ interface FooterProps {
|
||||||
lang: LanguageTypes;
|
lang: LanguageTypes;
|
||||||
availableApplications: string[];
|
availableApplications: string[];
|
||||||
activePageUrl: string;
|
activePageUrl: string;
|
||||||
useReloadWindow?: () => void;
|
|
||||||
configData: any;
|
configData: any;
|
||||||
configLoading: boolean;
|
configLoading: boolean;
|
||||||
configError: any;
|
configError: any;
|
||||||
|
|
@ -62,10 +59,11 @@ interface HeaderProps {
|
||||||
activePageUrl: string;
|
activePageUrl: string;
|
||||||
prefix: string;
|
prefix: string;
|
||||||
mode?: ModeTypes;
|
mode?: ModeTypes;
|
||||||
useReloadWindow?: () => void;
|
|
||||||
onlineData: any;
|
onlineData: any;
|
||||||
onlineLoading: boolean;
|
onlineLoading: boolean;
|
||||||
onlineError: any;
|
onlineError: any;
|
||||||
|
refreshOnline: () => Promise<void>;
|
||||||
|
updateOnline: (newOnline: any) => Promise<boolean>;
|
||||||
userData: any;
|
userData: any;
|
||||||
userLoading: boolean;
|
userLoading: boolean;
|
||||||
userError: any;
|
userError: any;
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,7 @@ export function loginHook(
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
response.json().then((data) => {
|
response.json().then((data) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const userType =
|
Router.push(`/panel/dashboard`);
|
||||||
data?.data?.user_type.toLowerCase() === "employee"
|
|
||||||
? "employee"
|
|
||||||
: "occupant";
|
|
||||||
const rediretUrl = `/auth/select?type=${userType}`;
|
|
||||||
Router.push(rediretUrl);
|
|
||||||
}, 100);
|
}, 100);
|
||||||
});
|
});
|
||||||
} else {
|
} 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