updated user selection via select response return
This commit is contained in:
parent
b73417a625
commit
0806ce9d65
|
|
@ -346,7 +346,7 @@ class LoginHandler:
|
|||
).join(EndpointRestriction, EndpointRestriction.id == Events.endpoint_id).filter().all()
|
||||
|
||||
# Get reachable applications
|
||||
reachable_app_codes = Application2Employee.get_application_codes(employee_id=int(result_with_keys_dict['Employees.id']), db=db_session)
|
||||
# reachable_app_codes = Application2Employee.get_application_codes(employee_id=int(result_with_keys_dict['Employees.id']), db=db_session)
|
||||
# Get reachable events
|
||||
reachable_event_codes = {endpoint_name: function_code for endpoint_name, function_code in filter_endpoints_and_events}
|
||||
|
||||
|
|
@ -361,6 +361,11 @@ class LoginHandler:
|
|||
redis_handler = RedisHandlers()
|
||||
user_uu_id = Users.query.filter(Users.person_id == result_with_keys_dict['People.id']).first().uu_id
|
||||
redis_result = redis_handler.update_token_at_redis(token=access_token, add_payload=add_company, user_uuid=user_uu_id)
|
||||
reachable_app_codes = []
|
||||
if result := RedisHandlers.get_object_from_redis(access_token=access_token):
|
||||
if result.is_employee and result.selected_company:
|
||||
if reachable_app_codes_dict := result.reachable_app_codes:
|
||||
reachable_app_codes = list(reachable_app_codes_dict.get(data.uuid, {}).keys())
|
||||
return {"selected_uu_id": data.uuid, "reachable_app_codes": reachable_app_codes}
|
||||
|
||||
@classmethod
|
||||
|
|
@ -396,10 +401,7 @@ class LoginHandler:
|
|||
reachable_event_codes = {endpoint_name: function_code for endpoint_name, function_code in filter_endpoints_and_events}
|
||||
|
||||
# Get reachable applications
|
||||
print('selected_build_living_space_first', selected_build_living_space_first.id)
|
||||
reachable_app_codes = Application2Occupant.get_application_codes(build_living_space_id=selected_build_living_space_first.id, db=db)
|
||||
print('reachable_app_codes', reachable_app_codes)
|
||||
|
||||
# reachable_app_codes = Application2Occupant.get_application_codes(build_living_space_id=selected_build_living_space_first.id, db=db)
|
||||
build_part = BuildParts.query.filter(BuildParts.id == result_with_keys_dict['BuildParts.id']).first()
|
||||
if not build_part:
|
||||
raise ValueError("EYS_0013")
|
||||
|
|
@ -414,10 +416,16 @@ class LoginHandler:
|
|||
"code": result_with_keys_dict['OccupantTypes.occupant_code']
|
||||
}
|
||||
redis_handler = RedisHandlers()
|
||||
|
||||
user_uu_id = Users.query.filter(Users.person_id == result_with_keys_dict['People.id']).first().uu_id
|
||||
redis_handler.update_token_at_redis(token=access_token, add_payload=add_build_living_space, user_uuid=user_uu_id)
|
||||
return {"selected_uu_id": data.uuid, "reachable_app_codes": reachable_app_codes}
|
||||
reachable_app_codes = []
|
||||
|
||||
if result := RedisHandlers.get_object_from_redis(access_token=access_token):
|
||||
if result.is_occupant and result.selected_occupant:
|
||||
if reachable_app_codes_dict := result.reachable_app_codes:
|
||||
reachable_app_codes = list(reachable_app_codes_dict.get(data.uuid, {}).keys())
|
||||
print('reachable_app_codes', reachable_app_codes)
|
||||
return {"selected_uu_id": data.uuid, "reachable_app_codes": reachable_app_codes or []}
|
||||
|
||||
@classmethod
|
||||
def authentication_select_company_or_occupant_type(cls, request: Any, data: Any):
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@
|
|||
"@radix-ui/react-tabs": "^1.1.12",
|
||||
"@radix-ui/react-toggle": "^1.1.9",
|
||||
"@radix-ui/react-tooltip": "^1.2.7",
|
||||
"@tanstack/react-query": "^5.80.7",
|
||||
"@tanstack/react-table": "^8.21.3",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
|
|
@ -2657,6 +2659,65 @@
|
|||
"tailwindcss": "4.1.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/query-core": {
|
||||
"version": "5.80.7",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.80.7.tgz",
|
||||
"integrity": "sha512-s09l5zeUKC8q7DCCCIkVSns8zZrK4ZDT6ryEjxNBFi68G4z2EBobBS7rdOY3r6W1WbUDpc1fe5oY+YO/+2UVUg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/react-query": {
|
||||
"version": "5.80.7",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.80.7.tgz",
|
||||
"integrity": "sha512-u2F0VK6+anItoEvB3+rfvTO9GEh2vb00Je05OwlUe/A0lkJBgW1HckiY3f9YZa+jx6IOe4dHPh10dyp9aY3iRQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tanstack/query-core": "5.80.7"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18 || ^19"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/react-table": {
|
||||
"version": "8.21.3",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.3.tgz",
|
||||
"integrity": "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tanstack/table-core": "8.21.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8",
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/table-core": {
|
||||
"version": "8.21.3",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.21.3.tgz",
|
||||
"integrity": "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
}
|
||||
},
|
||||
"node_modules/@tybys/wasm-util": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz",
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@
|
|||
"@radix-ui/react-tabs": "^1.1.12",
|
||||
"@radix-ui/react-toggle": "^1.1.9",
|
||||
"@radix-ui/react-tooltip": "^1.2.7",
|
||||
"@tanstack/react-query": "^5.80.7",
|
||||
"@tanstack/react-table": "^8.21.3",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
|
|
|
|||
|
|
@ -21,14 +21,13 @@ export async function POST(req: Request): Promise<NextResponse> {
|
|||
message: validatedLoginBody.error.message,
|
||||
});
|
||||
}
|
||||
|
||||
const userLogin = await loginViaAccessKeys(dataValidated);
|
||||
console.log("userLogin", userLogin);
|
||||
await initFirstSelection(
|
||||
userLogin.data?.firstSelection,
|
||||
userLogin.data?.userType
|
||||
);
|
||||
if (userLogin.status === 200 || userLogin.status === 202) {
|
||||
await initFirstSelection(
|
||||
userLogin.data?.firstSelection,
|
||||
userLogin.data?.userType
|
||||
);
|
||||
return NextResponse.json({
|
||||
status: 200,
|
||||
message: "Login successfully completed",
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@ import type { Metadata } from "next";
|
|||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
|
||||
// Import EventEmitter configuration to increase max listeners
|
||||
import "../utils/eventEmitterConfig";
|
||||
// Import Redis-specific configuration to fix Commander EventEmitter warning
|
||||
import "../utils/configureRedis";
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,491 @@
|
|||
'use client';
|
||||
|
||||
import { FC, useState } from 'react';
|
||||
import {
|
||||
useQuery,
|
||||
QueryClient,
|
||||
QueryClientProvider,
|
||||
} from '@tanstack/react-query';
|
||||
import {
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
SortingState,
|
||||
createColumnHelper,
|
||||
ColumnDef,
|
||||
Row,
|
||||
Cell,
|
||||
Header,
|
||||
Table,
|
||||
} from '@tanstack/react-table';
|
||||
|
||||
|
||||
interface DashboardPageProps {
|
||||
searchParams: Record<string, any>;
|
||||
activePageUrl?: string;
|
||||
|
||||
userData?: any;
|
||||
userLoading?: boolean;
|
||||
userError?: any;
|
||||
refreshUser?: () => void;
|
||||
updateUser?: (data: any) => void;
|
||||
|
||||
onlineData?: any;
|
||||
onlineLoading?: boolean;
|
||||
onlineError?: any;
|
||||
refreshOnline?: () => void;
|
||||
updateOnline?: (data: any) => void;
|
||||
}
|
||||
|
||||
// Wrap the component with QueryClientProvider
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
const DPage: FC<DashboardPageProps> = ({
|
||||
searchParams,
|
||||
userData,
|
||||
userLoading,
|
||||
onlineData,
|
||||
activePageUrl
|
||||
}) => {
|
||||
// Sample data for the dashboard
|
||||
const statCardsData = [
|
||||
{
|
||||
title: 'Users',
|
||||
count: '36.5k',
|
||||
icon: 'bx bx-user',
|
||||
iconColor: 'text-blue-500',
|
||||
percentage: '4.65%',
|
||||
isPositive: true
|
||||
},
|
||||
{
|
||||
title: 'Companies',
|
||||
count: '4.5k',
|
||||
icon: 'bx bx-building',
|
||||
iconColor: 'text-yellow-500',
|
||||
percentage: '1.25%',
|
||||
isPositive: false
|
||||
},
|
||||
{
|
||||
title: 'Blogs',
|
||||
count: '12.5k',
|
||||
icon: 'bx bxl-blogger',
|
||||
iconColor: 'text-green-500',
|
||||
percentage: '2.15%',
|
||||
isPositive: true
|
||||
},
|
||||
{
|
||||
title: 'Revenue',
|
||||
count: '$35.5k',
|
||||
icon: 'bx bx-dollar',
|
||||
iconColor: 'text-pink-500',
|
||||
percentage: '3.75%',
|
||||
isPositive: true
|
||||
}
|
||||
];
|
||||
|
||||
const userRolesColumns = [
|
||||
{ header: 'Name', accessor: 'name' },
|
||||
{ header: 'Email', accessor: 'email' },
|
||||
{
|
||||
header: 'Role', accessor: 'role',
|
||||
cell: (value: string) => (
|
||||
<span className={`py-1 px-2 rounded-md text-xs ${value === 'Admin' ? 'bg-blue-500/10 text-blue-500' : value === 'Editor' ? 'bg-yellow-500/10 text-yellow-500' : 'bg-emerald-500/10 text-emerald-500'}`}>
|
||||
{value}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
const userRolesData = [
|
||||
{ name: 'John Doe', email: 'john@example.com', role: 'Admin' },
|
||||
{ name: 'Jane Smith', email: 'jane@example.com', role: 'Editor' },
|
||||
{ name: 'Robert Johnson', email: 'robert@example.com', role: 'Customer' },
|
||||
{ name: 'Emily Davis', email: 'emily@example.com', role: 'Customer' },
|
||||
{ name: 'Michael Brown', email: 'michael@example.com', role: 'Editor' }
|
||||
];
|
||||
|
||||
const activitiesColumns = [
|
||||
{ header: 'Name', accessor: 'name' },
|
||||
{ header: 'Date', accessor: 'date' },
|
||||
{ header: 'Time', accessor: 'time' }
|
||||
];
|
||||
|
||||
const activitiesData = [
|
||||
{ name: 'Lorem Ipsum', date: '02-02-2024', time: '17.45' },
|
||||
{ name: 'Lorem Ipsum', date: '02-02-2024', time: '17.45' },
|
||||
{ name: 'Lorem Ipsum', date: '02-02-2024', time: '17.45' },
|
||||
{ name: 'Lorem Ipsum', date: '02-02-2024', time: '17.45' },
|
||||
{ name: 'Lorem Ipsum', date: '02-02-2024', time: '17.45' }
|
||||
];
|
||||
|
||||
const earningsData = [
|
||||
{ service: 'Create landing page', imageUrl: 'https://placehold.co/32x32', amount: '$235', isPositive: true, status: 'Pending' },
|
||||
{ service: 'Create landing page', imageUrl: 'https://placehold.co/32x32', amount: '$235', isPositive: false, status: 'Withdrawn' },
|
||||
{ service: 'Create landing page', imageUrl: 'https://placehold.co/32x32', amount: '$235', isPositive: true, status: 'Pending' },
|
||||
{ service: 'Create landing page', imageUrl: 'https://placehold.co/32x32', amount: '$235', isPositive: false, status: 'Withdrawn' },
|
||||
{ service: 'Create landing page', imageUrl: 'https://placehold.co/32x32', amount: '$235', isPositive: true, status: 'Pending' }
|
||||
];
|
||||
|
||||
return (
|
||||
<div className='p-6'>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<TanStackTableExample />
|
||||
</QueryClientProvider>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// TanStack Table Example component
|
||||
|
||||
type Person = {
|
||||
id: number
|
||||
firstName: string
|
||||
lastName: string
|
||||
age: number
|
||||
visits: number
|
||||
status: string
|
||||
progress: number
|
||||
}
|
||||
|
||||
const TanStackTableExample: FC = () => {
|
||||
// Column definitions using columnHelper
|
||||
const columnHelper = createColumnHelper<Person>();
|
||||
|
||||
const columns = [
|
||||
columnHelper.accessor('firstName', {
|
||||
cell: (info) => info.getValue(),
|
||||
header: () => 'First Name',
|
||||
footer: (info) => info.column.id,
|
||||
}),
|
||||
columnHelper.accessor((row) => row.lastName, {
|
||||
id: 'lastName',
|
||||
cell: (info) => info.getValue(),
|
||||
header: () => 'Last Name',
|
||||
footer: (info) => info.column.id,
|
||||
}),
|
||||
columnHelper.accessor('age', {
|
||||
header: () => 'Age',
|
||||
cell: (info) => info.renderValue(),
|
||||
footer: (info) => info.column.id,
|
||||
}),
|
||||
columnHelper.accessor('visits', {
|
||||
header: () => 'Visits',
|
||||
footer: (info) => info.column.id,
|
||||
}),
|
||||
columnHelper.accessor('status', {
|
||||
header: 'Status',
|
||||
cell: (info) => (
|
||||
<span className={`py-1 px-2 rounded-md text-xs ${info.getValue() === 'Active' ? 'bg-green-500/10 text-green-500' :
|
||||
info.getValue() === 'Pending' ? 'bg-yellow-500/10 text-yellow-500' :
|
||||
'bg-red-500/10 text-red-500'
|
||||
}`}>
|
||||
{info.getValue()}
|
||||
</span>
|
||||
),
|
||||
footer: (info) => info.column.id,
|
||||
}),
|
||||
columnHelper.accessor('progress', {
|
||||
header: 'Profile Progress',
|
||||
cell: (info) => (
|
||||
<div className="w-full bg-gray-200 rounded-full h-2.5 dark:bg-gray-700">
|
||||
<div
|
||||
className="bg-blue-600 h-2.5 rounded-full"
|
||||
style={{ width: `${info.getValue()}%` }}
|
||||
></div>
|
||||
</div>
|
||||
),
|
||||
}),
|
||||
] as ColumnDef<Person>[];
|
||||
|
||||
// Fetch data using React Query
|
||||
const fetchPeople = async (): Promise<Person[]> => {
|
||||
// In a real app, this would be an API call
|
||||
// For this example, we'll return mock data
|
||||
return [
|
||||
{
|
||||
id: 1,
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
age: 28,
|
||||
visits: 10,
|
||||
status: 'Active',
|
||||
progress: 80,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
firstName: 'Jane',
|
||||
lastName: 'Smith',
|
||||
age: 32,
|
||||
visits: 5,
|
||||
status: 'Pending',
|
||||
progress: 45,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
firstName: 'Robert',
|
||||
lastName: 'Johnson',
|
||||
age: 45,
|
||||
visits: 20,
|
||||
status: 'Inactive',
|
||||
progress: 30,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
firstName: 'Emily',
|
||||
lastName: 'Davis',
|
||||
age: 27,
|
||||
visits: 15,
|
||||
status: 'Active',
|
||||
progress: 95,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
firstName: 'Michael',
|
||||
lastName: 'Brown',
|
||||
age: 39,
|
||||
visits: 8,
|
||||
status: 'Pending',
|
||||
progress: 60,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
firstName: 'Sarah',
|
||||
lastName: 'Wilson',
|
||||
age: 34,
|
||||
visits: 12,
|
||||
status: 'Active',
|
||||
progress: 75,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
firstName: 'David',
|
||||
lastName: 'Miller',
|
||||
age: 41,
|
||||
visits: 7,
|
||||
status: 'Inactive',
|
||||
progress: 25,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
firstName: 'Jennifer',
|
||||
lastName: 'Taylor',
|
||||
age: 29,
|
||||
visits: 18,
|
||||
status: 'Active',
|
||||
progress: 88,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
firstName: 'James',
|
||||
lastName: 'Anderson',
|
||||
age: 36,
|
||||
visits: 9,
|
||||
status: 'Pending',
|
||||
progress: 52,
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
firstName: 'Lisa',
|
||||
lastName: 'Thomas',
|
||||
age: 31,
|
||||
visits: 14,
|
||||
status: 'Active',
|
||||
progress: 70,
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
firstName: 'Richard',
|
||||
lastName: 'Jackson',
|
||||
age: 47,
|
||||
visits: 6,
|
||||
status: 'Inactive',
|
||||
progress: 15,
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
firstName: 'Mary',
|
||||
lastName: 'White',
|
||||
age: 25,
|
||||
visits: 22,
|
||||
status: 'Active',
|
||||
progress: 92,
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
firstName: 'Thomas',
|
||||
lastName: 'Harris',
|
||||
age: 38,
|
||||
visits: 11,
|
||||
status: 'Pending',
|
||||
progress: 48,
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
firstName: 'Patricia',
|
||||
lastName: 'Martin',
|
||||
age: 33,
|
||||
visits: 16,
|
||||
status: 'Active',
|
||||
progress: 83,
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
firstName: 'Charles',
|
||||
lastName: 'Thompson',
|
||||
age: 42,
|
||||
visits: 4,
|
||||
status: 'Inactive',
|
||||
progress: 22,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
const { data = [], isLoading, error } = useQuery({
|
||||
queryKey: ['people'],
|
||||
queryFn: fetchPeople,
|
||||
});
|
||||
|
||||
const [sorting, setSorting] = useState<SortingState>([]);
|
||||
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns,
|
||||
state: {
|
||||
sorting,
|
||||
},
|
||||
onSortingChange: setSorting,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
});
|
||||
|
||||
if (isLoading) return <div className="text-center py-4">Loading data...</div>;
|
||||
if (error) return <div className="text-center py-4 text-red-500">Error loading data</div>;
|
||||
|
||||
return (
|
||||
<div className="bg-white rounded-lg shadow-md overflow-hidden">
|
||||
<div className="p-4 border-b border-gray-200">
|
||||
<h2 className="text-lg font-semibold text-gray-800">People Data</h2>
|
||||
<p className="text-sm text-gray-500">TanStack React Query Table Example</p>
|
||||
</div>
|
||||
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-full divide-y divide-gray-200">
|
||||
<thead className="bg-gray-50">
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<tr key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => (
|
||||
<th
|
||||
key={header.id}
|
||||
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer"
|
||||
onClick={header.column.getToggleSortingHandler()}
|
||||
>
|
||||
<div className="flex items-center space-x-1">
|
||||
{flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
<span>
|
||||
{{
|
||||
asc: ' 🔼',
|
||||
desc: ' 🔽',
|
||||
}[header.column.getIsSorted() as string] ?? null}
|
||||
</span>
|
||||
</div>
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</thead>
|
||||
<tbody className="bg-white divide-y divide-gray-200">
|
||||
{table.getRowModel().rows.map((row) => (
|
||||
<tr key={row.id} className="hover:bg-gray-50">
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<td key={cell.id} className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div className="px-4 py-3 flex items-center justify-between border-t border-gray-200 sm:px-6">
|
||||
<div className="flex-1 flex justify-between sm:hidden">
|
||||
<button
|
||||
onClick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
className="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 disabled:opacity-50"
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
<button
|
||||
onClick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}
|
||||
className="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 disabled:opacity-50"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
<div className="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-gray-700">
|
||||
Showing{' '}
|
||||
<span className="font-medium">{table.getState().pagination.pageIndex * table.getState().pagination.pageSize + 1}</span>{' '}
|
||||
to{' '}
|
||||
<span className="font-medium">
|
||||
{Math.min(
|
||||
(table.getState().pagination.pageIndex + 1) * table.getState().pagination.pageSize,
|
||||
table.getRowCount()
|
||||
)}
|
||||
</span>{' '}
|
||||
of <span className="font-medium">{table.getRowCount()}</span> results
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<nav className="relative z-0 inline-flex rounded-md shadow-sm -space-x-px" aria-label="Pagination">
|
||||
<button
|
||||
onClick={() => table.setPageIndex(0)}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
className="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 disabled:opacity-50"
|
||||
>
|
||||
<span className="sr-only">First</span>
|
||||
⏮️
|
||||
</button>
|
||||
<button
|
||||
onClick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
className="relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 disabled:opacity-50"
|
||||
>
|
||||
<span className="sr-only">Previous</span>
|
||||
◀️
|
||||
</button>
|
||||
<button
|
||||
onClick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}
|
||||
className="relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 disabled:opacity-50"
|
||||
>
|
||||
<span className="sr-only">Next</span>
|
||||
▶️
|
||||
</button>
|
||||
<button
|
||||
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
||||
disabled={!table.getCanNextPage()}
|
||||
className="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 disabled:opacity-50"
|
||||
>
|
||||
<span className="sr-only">Last</span>
|
||||
⏭️
|
||||
</button>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { DPage }
|
||||
|
|
@ -9,20 +9,22 @@ import EarningsTable from '@/components/custom/EarningsTable';
|
|||
|
||||
interface DashboardPageProps {
|
||||
searchParams: Record<string, any>;
|
||||
activePageUrl?: string;
|
||||
|
||||
userData?: any;
|
||||
userLoading?: boolean;
|
||||
userError?: any;
|
||||
refreshUser?: () => void;
|
||||
updateUser?: (data: any) => void;
|
||||
|
||||
onlineData?: any;
|
||||
onlineLoading?: boolean;
|
||||
onlineError?: any;
|
||||
refreshOnline?: () => void;
|
||||
updateOnline?: (data: any) => void;
|
||||
activePageUrl?: string;
|
||||
}
|
||||
|
||||
export const DashboardPage: FC<DashboardPageProps> = ({
|
||||
const DashboardPage: FC<DashboardPageProps> = ({
|
||||
searchParams,
|
||||
userData,
|
||||
userLoading,
|
||||
|
|
@ -165,3 +167,8 @@ export const DashboardPage: FC<DashboardPageProps> = ({
|
|||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export {
|
||||
DashboardPage
|
||||
}
|
||||
|
|
@ -11,7 +11,6 @@ import {
|
|||
MenuStructure,
|
||||
MenuItemsSectionProps,
|
||||
} from "./types";
|
||||
import MenuEmptyState from "./menuEmptyState";
|
||||
|
||||
const menuStaticTranslation = {
|
||||
tr: { menu: "Menü" },
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
"use server";
|
||||
import { redis } from "@/lib/redis";
|
||||
import { functionRetrieveUserSelection } from "@/fetchers/fecther";
|
||||
import { ClientRedisToken, defaultClientRedisToken } from "@/fetchers/types/context";
|
||||
import { REDIS_TIMEOUT } from "@/fetchers/base";
|
||||
import { safeRedisGet, safeRedisSet, safeJsonParse } from "@/utils/redisOperations";
|
||||
|
||||
/**
|
||||
* Gets the complete data from Redis with improved error handling and timeouts
|
||||
|
|
@ -16,14 +16,12 @@ const getCompleteFromRedis = async (): Promise<ClientRedisToken> => {
|
|||
if (!redisKey) { return defaultClientRedisToken }
|
||||
if (redisKey === "default") { return defaultClientRedisToken }
|
||||
|
||||
try {
|
||||
const timeoutPromise = new Promise<string | null>((_, reject) => {
|
||||
setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT);
|
||||
});
|
||||
const result = await Promise.race([redis.get(`${redisKey}`), timeoutPromise]);
|
||||
if (!result) { return defaultClientRedisToken }
|
||||
try { const parsedResult = JSON.parse(result); return parsedResult } catch (parseError) { return defaultClientRedisToken }
|
||||
} catch (redisError) { return defaultClientRedisToken }
|
||||
// Use safe Redis get operation with proper connection handling
|
||||
const result = await safeRedisGet(`${redisKey}`, REDIS_TIMEOUT);
|
||||
if (!result) { return defaultClientRedisToken }
|
||||
|
||||
// Use safe JSON parsing
|
||||
return safeJsonParse<ClientRedisToken>(result, defaultClientRedisToken);
|
||||
} catch (error) { return defaultClientRedisToken }
|
||||
}
|
||||
|
||||
|
|
@ -40,11 +38,8 @@ const setCompleteToRedis = async (completeObject: ClientRedisToken): Promise<boo
|
|||
if (!decrpytUserSelection) { return false }
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (!redisKey) { return false }
|
||||
try {
|
||||
const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT) });
|
||||
await Promise.race([redis.set(redisKey, JSON.stringify(completeObject)), timeoutPromise]);
|
||||
return true;
|
||||
} catch (redisError) { return false }
|
||||
// Use safe Redis set operation with proper connection handling
|
||||
return await safeRedisSet(redisKey, JSON.stringify(completeObject), REDIS_TIMEOUT);
|
||||
} catch (error) { return false }
|
||||
}
|
||||
|
||||
|
|
@ -58,11 +53,8 @@ const setNewCompleteToRedis = async (completeObject: ClientRedisToken, redisKey:
|
|||
try {
|
||||
if (!redisKey) { return false }
|
||||
if (!completeObject) { return false }
|
||||
try {
|
||||
const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT) });
|
||||
await Promise.race([redis.set(redisKey, JSON.stringify(completeObject)), timeoutPromise])
|
||||
return true;
|
||||
} catch (redisError) { return false }
|
||||
// Use safe Redis set operation with proper connection handling
|
||||
return await safeRedisSet(redisKey, JSON.stringify(completeObject), REDIS_TIMEOUT);
|
||||
} catch (error) { return false }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,27 @@
|
|||
"use server";
|
||||
import { redis } from "@/lib/redis";
|
||||
import { functionRetrieveUserSelection } from "@/fetchers/fecther";
|
||||
import { ClientSelection, AuthError } from "@/fetchers/types/context";
|
||||
import { defaultValuesSelection } from "@/fetchers/types/context/selection/validations";
|
||||
import { getCompleteFromRedis, setCompleteToRedis } from "@/fetchers/custom/context/complete/fetch";
|
||||
import { loginSelectEmployee, loginSelectOccupant } from "@/fetchers/custom/login/login";
|
||||
import { safeRedisGet, safeJsonParse } from "@/utils/redisOperations";
|
||||
import { REDIS_TIMEOUT } from "@/fetchers/base";
|
||||
|
||||
const getSelectionFromRedis = async (): Promise<ClientSelection> => {
|
||||
try {
|
||||
const decrpytUserSelection = await functionRetrieveUserSelection();
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (redisKey === "default") { return { selectionList: [], activeSelection: {} } }
|
||||
const result = await redis.get(`${redisKey}`);
|
||||
if (!result) { return { selectionList: [], activeSelection: {} } }
|
||||
const parsedResult = JSON.parse(result);
|
||||
if (!parsedResult.selection) { return { selectionList: [], activeSelection: {} } }
|
||||
if (redisKey === "default") { return defaultValuesSelection }
|
||||
|
||||
// Use safe Redis get operation with proper connection handling
|
||||
const result = await safeRedisGet(`${redisKey}`, REDIS_TIMEOUT);
|
||||
if (!result) { return defaultValuesSelection }
|
||||
|
||||
// Use safe JSON parsing with proper default object type
|
||||
const parsedResult = safeJsonParse(result, { selection: defaultValuesSelection });
|
||||
if (!parsedResult.selection) { return defaultValuesSelection }
|
||||
return parsedResult.selection;
|
||||
} catch (error) { return { selectionList: [], activeSelection: {} } }
|
||||
} catch (error) { return defaultValuesSelection }
|
||||
}
|
||||
|
||||
const setActiveSelectionToRedis = async (selectionObject: any) => {
|
||||
|
|
@ -37,11 +43,11 @@ const setActiveSelectionToRedis = async (selectionObject: any) => {
|
|||
activeSelection: selectionObject
|
||||
}
|
||||
})
|
||||
console.log("oldData", oldData)
|
||||
if (oldData.online.userType.toUpperCase() === "EMPLOYEE") {
|
||||
console.log("selectionObject", selectionObject)
|
||||
await loginSelectEmployee({ uuid: selectionObject.uu_id });
|
||||
} else if (oldData.online.userType.toUpperCase() === "OCCUPANT") {
|
||||
console.log("selectionObject", selectionObject.build_living_space_uu_id)
|
||||
await loginSelectOccupant({ uuid: selectionObject.build_living_space_uu_id });
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,22 @@
|
|||
"use server";
|
||||
import { redis } from "@/lib/redis";
|
||||
import { functionRetrieveUserSelection } from "@/fetchers/fecther";
|
||||
import { ClientSettings, AuthError } from "@/fetchers/types/context";
|
||||
import { defaultValuesSettings } from "@/fetchers/types/context/settings/validations";
|
||||
import { getCompleteFromRedis, setCompleteToRedis } from "@/fetchers/custom/context/complete/fetch";
|
||||
import { safeRedisGet, safeJsonParse } from "@/utils/redisOperations";
|
||||
import { REDIS_TIMEOUT } from "@/fetchers/base";
|
||||
|
||||
const getSettingsFromRedis = async (): Promise<ClientSettings> => {
|
||||
try {
|
||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (!redisKey) throw new AuthError("No redis key found");
|
||||
const result = await redis.get(`${redisKey}`);
|
||||
// Use safe Redis get operation with proper connection handling
|
||||
const result = await safeRedisGet(`${redisKey}`, REDIS_TIMEOUT);
|
||||
if (!result) throw new AuthError("No data found in redis");
|
||||
const parsedResult = JSON.parse(result);
|
||||
|
||||
// Use safe JSON parsing with proper default object type
|
||||
const parsedResult = safeJsonParse(result, { settings: defaultValuesSettings });
|
||||
if (!parsedResult.settings) throw new AuthError("No settings found in redis");
|
||||
return parsedResult.settings;
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,22 @@
|
|||
"use server";
|
||||
import { redis } from "@/lib/redis";
|
||||
import { functionRetrieveUserSelection } from "@/fetchers/fecther";
|
||||
import { ClientUser, AuthError } from "@/fetchers/types/context";
|
||||
import { defaultValuesUser } from "@/fetchers/types/context/user/validations";
|
||||
import { getCompleteFromRedis, setCompleteToRedis } from "@/fetchers/custom/context/complete/fetch";
|
||||
import { safeRedisGet, safeJsonParse } from "@/utils/redisOperations";
|
||||
import { REDIS_TIMEOUT } from "@/fetchers/base";
|
||||
|
||||
const getUserFromRedis = async (): Promise<ClientUser> => {
|
||||
try {
|
||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (!redisKey) throw new AuthError("No redis key found");
|
||||
const result = await redis.get(`${redisKey}`);
|
||||
// Use safe Redis get operation with proper connection handling
|
||||
const result = await safeRedisGet(`${redisKey}`, REDIS_TIMEOUT);
|
||||
if (!result) throw new AuthError("No data found in redis");
|
||||
const parsedResult = JSON.parse(result);
|
||||
|
||||
// Use safe JSON parsing with proper default object type
|
||||
const parsedResult = safeJsonParse(result, { user: defaultValuesUser });
|
||||
if (!parsedResult.user) throw new AuthError("No user found in redis");
|
||||
return parsedResult.user;
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,22 @@
|
|||
"use server";
|
||||
import { redis } from "@/lib/redis";
|
||||
import { functionRetrieveUserSelection } from "@/fetchers/fecther";
|
||||
import { ClientSettings, AuthError } from "@/fetchers/types/context";
|
||||
import { defaultValuesSettings } from "@/fetchers/types/context/settings/validations";
|
||||
import { getCompleteFromRedis, setCompleteToRedis } from "@/fetchers/custom/context/complete/fetch";
|
||||
import { safeRedisGet, safeJsonParse } from "@/utils/redisOperations";
|
||||
import { REDIS_TIMEOUT } from "@/fetchers/base";
|
||||
|
||||
const getConfigFromRedis = async (): Promise<ClientSettings> => {
|
||||
try {
|
||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (!redisKey) throw new AuthError("No redis key found");
|
||||
const result = await redis.get(`${redisKey}`);
|
||||
// Use safe Redis get operation with proper connection handling
|
||||
const result = await safeRedisGet(`${redisKey}`, REDIS_TIMEOUT);
|
||||
if (!result) throw new AuthError("No data found in redis");
|
||||
const parsedResult = JSON.parse(result);
|
||||
|
||||
// Use safe JSON parsing with proper default object type
|
||||
const parsedResult = safeJsonParse(result, { settings: defaultValuesSettings });
|
||||
if (!parsedResult.settings) throw new AuthError("No settings found in redis");
|
||||
return parsedResult.settings;
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,22 @@
|
|||
"use server";
|
||||
import { redis } from "@/lib/redis";
|
||||
import { functionRetrieveUserSelection } from "@/fetchers/fecther";
|
||||
import { ClientMenu, AuthError } from "@/fetchers/types/context";
|
||||
import { defaultValuesMenu } from "@/fetchers/types/context/menu/validations";
|
||||
import { getCompleteFromRedis, setCompleteToRedis } from "@/fetchers/custom/context/complete/fetch";
|
||||
import { safeRedisGet, safeJsonParse } from "@/utils/redisOperations";
|
||||
import { REDIS_TIMEOUT } from "@/fetchers/base";
|
||||
|
||||
const getMenuFromRedis = async (): Promise<ClientMenu> => {
|
||||
try {
|
||||
const decrpytUserSelection = await functionRetrieveUserSelection()
|
||||
const redisKey = decrpytUserSelection?.redisKey;
|
||||
if (!redisKey) throw new AuthError("No redis key found");
|
||||
const result = await redis.get(`${redisKey}`);
|
||||
// Use safe Redis get operation with proper connection handling
|
||||
const result = await safeRedisGet(`${redisKey}`, REDIS_TIMEOUT);
|
||||
if (!result) throw new AuthError("No data found in redis");
|
||||
const parsedResult = JSON.parse(result);
|
||||
|
||||
// Use safe JSON parsing with proper default object type
|
||||
const parsedResult = safeJsonParse(result, { menu: defaultValuesMenu });
|
||||
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") } }
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
"use server";
|
||||
import { redis } from "@/lib/redis";
|
||||
import { functionRetrieveUserSelection } from "@/fetchers/fecther";
|
||||
import { ClientOnline, AuthError } from "@/fetchers/types/context";
|
||||
import { defaultValuesOnline } from "@/fetchers/types/context/online/validations";
|
||||
import { getCompleteFromRedis, setCompleteToRedis } from "@/fetchers/custom/context/complete/fetch";
|
||||
import { safeRedisGet, safeJsonParse } from "@/utils/redisOperations";
|
||||
import { REDIS_TIMEOUT } from "@/fetchers/base";
|
||||
|
||||
/**
|
||||
|
|
@ -18,14 +19,15 @@ const getOnlineFromRedis = async (): Promise<ClientOnline> => {
|
|||
if (!redisKey) { throw new AuthError('No redis key found') }
|
||||
if (redisKey === "default") { throw new AuthError('Invalid redis key') }
|
||||
try {
|
||||
const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT) });
|
||||
result = await Promise.race([redis.get(`${redisKey}`), timeoutPromise]) as string | null;
|
||||
// Use safe Redis get operation with proper connection handling
|
||||
result = await safeRedisGet(`${redisKey}`, REDIS_TIMEOUT);
|
||||
} catch (redisError) { throw new AuthError('Failed to access Redis data') }
|
||||
|
||||
if (!result) { throw new AuthError('No data found in redis') }
|
||||
|
||||
try {
|
||||
const parsedResult = JSON.parse(result);
|
||||
// Use safe JSON parsing with proper default object type
|
||||
const parsedResult = safeJsonParse(result, { online: defaultValuesOnline });
|
||||
if (!parsedResult.online) { throw new AuthError('No online data found in redis') }
|
||||
return parsedResult.online;
|
||||
} catch (parseError) { throw new AuthError('Invalid data format in redis') }
|
||||
|
|
@ -51,8 +53,8 @@ const setOnlineToRedis = async (onlineObject: ClientOnline): Promise<boolean> =>
|
|||
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 {
|
||||
const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT) });
|
||||
await Promise.race([setCompleteToRedis({ ...oldData, online: onlineObject }), timeoutPromise]);
|
||||
// Use the setCompleteToRedis function which already uses safe Redis operations
|
||||
await setCompleteToRedis({ ...oldData, online: onlineObject });
|
||||
return true;
|
||||
} catch (redisError) { throw new AuthError('Failed to update Redis data') }
|
||||
} catch (error) { if (error instanceof AuthError) throw error; throw new AuthError(error instanceof Error ? error.message : 'Unknown error') }
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ async function initRedis(loginRespone: any, firstSelection: any, accessToken: st
|
|||
async function initFirstSelection(firstSelection: any, userType: string) {
|
||||
if (userType === "EMPLOYEE") {
|
||||
const uuid = firstSelection.uu_id;
|
||||
console.log("uuid", uuid)
|
||||
await loginSelectEmployee({ uuid });
|
||||
} else if (userType === "OCCUPANT") {
|
||||
const uuid = firstSelection.build_living_space_uu_id;
|
||||
|
|
@ -99,8 +100,6 @@ async function loginViaAccessKeys(payload: LoginViaAccessKeys) {
|
|||
const redisKeyAccess = await nextCrypto.encrypt(redisKey);
|
||||
const usersSelection = await nextCrypto.encrypt(JSON.stringify({ selected: firstSelection, userType, redisKey }));
|
||||
|
||||
await initRedis(loginRespone, firstSelection, accessToken, redisKey);
|
||||
|
||||
cookieStore.set({
|
||||
name: "eys-zzz",
|
||||
value: accessToken,
|
||||
|
|
@ -117,6 +116,8 @@ async function loginViaAccessKeys(payload: LoginViaAccessKeys) {
|
|||
...cookieObject,
|
||||
});
|
||||
|
||||
await initRedis(loginRespone, firstSelection, accessToken, redisKey);
|
||||
|
||||
try {
|
||||
return {
|
||||
completed: true,
|
||||
|
|
@ -156,11 +157,7 @@ async function loginSelectEmployee(payload: LoginSelect) {
|
|||
const employeeUUID = payload.uuid;
|
||||
const selectResponse: any = await fetchDataWithToken(urlLoginSelectEndpoint, { uuid: employeeUUID }, "POST", false);
|
||||
if (selectResponse.status === 200 || selectResponse.status === 202) {
|
||||
try {
|
||||
console.log("selectResponse", selectResponse) // Get Menu URL's of Employee
|
||||
const validUrls = await retrieveValidUrlsOfRestriction()
|
||||
setMenuToRedis(validUrls)
|
||||
} catch (error) { }
|
||||
try { setMenuToRedis(selectResponse.data.reachable_app_codes || []) } catch (error) { }
|
||||
}
|
||||
return selectResponse;
|
||||
}
|
||||
|
|
@ -169,11 +166,7 @@ async function loginSelectOccupant(payload: LoginSelect) {
|
|||
const livingSpaceUUID = payload.uuid;
|
||||
const selectResponse: any = await fetchDataWithToken(urlLoginSelectEndpoint, { uuid: livingSpaceUUID }, "POST", false);
|
||||
if (selectResponse.status === 200 || selectResponse.status === 202) {
|
||||
try {
|
||||
console.log("selectResponse", selectResponse) // Get Menu URL's of Occupant
|
||||
const validUrls = await retrieveValidUrlsOfRestriction()
|
||||
setMenuToRedis(validUrls)
|
||||
} catch (error) { }
|
||||
try { setMenuToRedis(selectResponse.data.reachable_app_codes || []) } catch (error) { }
|
||||
}
|
||||
return selectResponse;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import { DashboardPage } from "@/components/custom/content/DashboardPage";
|
||||
// import { DashboardPage } from "@/components/custom/content/DashboardPage";
|
||||
import { DPage } from "@/components/custom/content/DPage";
|
||||
|
||||
const pageIndexMulti: Record<string, Record<string, React.FC<any>>> = {
|
||||
"/dashboard": { DashboardPage: DashboardPage },
|
||||
"/dashboard": { DashboardPage: DPage },
|
||||
};
|
||||
|
||||
export { pageIndexMulti };
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
// Configure Redis client to prevent EventEmitter memory leak warnings
|
||||
import { EventEmitter } from "events";
|
||||
|
||||
// Increase the default maximum listeners for all EventEmitter instances
|
||||
EventEmitter.defaultMaxListeners = 20;
|
||||
|
||||
// This file will be imported in layout.tsx to configure Redis early in the app lifecycle
|
||||
export const configureRedisEmitters = () => {
|
||||
try {
|
||||
// Attempt to dynamically import the Redis client
|
||||
import("@/lib/redis")
|
||||
.then((redisModule) => {
|
||||
const redis = redisModule.redis;
|
||||
|
||||
if (!redis) return;
|
||||
|
||||
// Use type assertion to access any potential EventEmitter methods
|
||||
const redisAny = redis as any;
|
||||
|
||||
// Configure Redis client's EventEmitter interfaces
|
||||
if (typeof redisAny.setMaxListeners === "function") {
|
||||
redisAny.setMaxListeners(20);
|
||||
}
|
||||
|
||||
// Many Redis clients have internal EventEmitter instances with different names
|
||||
// Check for common patterns like 'command', 'commander', etc.
|
||||
const possibleEmitterProps = [
|
||||
"command",
|
||||
"commander",
|
||||
"connector",
|
||||
"connection",
|
||||
"client",
|
||||
"subscriber",
|
||||
];
|
||||
|
||||
possibleEmitterProps.forEach((prop) => {
|
||||
if (
|
||||
redisAny[prop] &&
|
||||
typeof redisAny[prop].setMaxListeners === "function"
|
||||
) {
|
||||
redisAny[prop].setMaxListeners(20);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle any nested emitters that might be causing the warning
|
||||
if (
|
||||
redisAny._events &&
|
||||
Object.keys(redisAny._events).includes("connect")
|
||||
) {
|
||||
console.log(
|
||||
"Found connect event listeners, likely source of warning"
|
||||
);
|
||||
}
|
||||
|
||||
console.log("Redis EventEmitter configured successfully");
|
||||
})
|
||||
.catch((err) => {
|
||||
console.warn("Failed to configure Redis EventEmitter:", err);
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn("Error configuring Redis EventEmitter:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// Execute configuration immediately
|
||||
configureRedisEmitters();
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// Increase the default maximum listeners for EventEmitter instances
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
// Set a higher limit for all EventEmitter instances
|
||||
EventEmitter.defaultMaxListeners = 20;
|
||||
|
||||
// Export a function to set max listeners for a specific emitter instance
|
||||
export const setMaxListeners = (emitter: EventEmitter, max: number = 20): void => {
|
||||
if (emitter && typeof emitter.setMaxListeners === 'function') {
|
||||
emitter.setMaxListeners(max);
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// Helper functions for Redis client management
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
/**
|
||||
* Safely increases max listeners for any EventEmitter instance
|
||||
* This is particularly useful for Redis clients that may create many listeners
|
||||
*/
|
||||
export function configureRedisEventEmitter(emitter: any, maxListeners: number = 20): void {
|
||||
if (emitter && typeof emitter.setMaxListeners === 'function') {
|
||||
emitter.setMaxListeners(maxListeners);
|
||||
}
|
||||
|
||||
// If the emitter has a commander property (common in Redis clients)
|
||||
if (emitter && emitter.commander && typeof emitter.commander.setMaxListeners === 'function') {
|
||||
emitter.commander.setMaxListeners(maxListeners);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a singleton wrapper for Redis clients to prevent connection duplication
|
||||
* @param createClientFn Function that creates a Redis client
|
||||
* @returns A singleton Redis client
|
||||
*/
|
||||
export function createRedisSingleton<T>(createClientFn: () => T): () => T {
|
||||
let instance: T | null = null;
|
||||
|
||||
return () => {
|
||||
if (!instance) {
|
||||
instance = createClientFn();
|
||||
|
||||
// Configure event emitters if applicable
|
||||
if (instance && typeof (instance as any).setMaxListeners === 'function') {
|
||||
configureRedisEventEmitter(instance);
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// Redis operations with proper connection management
|
||||
import { redis } from "@/lib/redis";
|
||||
|
||||
/**
|
||||
* Safely executes a Redis get operation with proper connection handling
|
||||
* @param key Redis key to retrieve
|
||||
* @param timeoutMs Timeout in milliseconds
|
||||
* @returns The value from Redis or null
|
||||
*/
|
||||
export async function safeRedisGet(key: string, timeoutMs: number = 5000): Promise<string | null> {
|
||||
try {
|
||||
// Create timeout promise
|
||||
const timeoutPromise = new Promise<string | null>((_, reject) => {
|
||||
setTimeout(() => reject(new Error('Redis operation timed out')), timeoutMs);
|
||||
});
|
||||
|
||||
// Execute the Redis get operation with timeout
|
||||
const result = await Promise.race([redis.get(key), timeoutPromise]);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('Redis get operation failed:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely executes a Redis set operation with proper connection handling
|
||||
* @param key Redis key to set
|
||||
* @param value Value to store
|
||||
* @param timeoutMs Timeout in milliseconds
|
||||
* @returns True if successful, false otherwise
|
||||
*/
|
||||
export async function safeRedisSet(key: string, value: string, timeoutMs: number = 5000): Promise<boolean> {
|
||||
try {
|
||||
// Create timeout promise
|
||||
const timeoutPromise = new Promise<string>((_, reject) => {
|
||||
setTimeout(() => reject(new Error('Redis operation timed out')), timeoutMs);
|
||||
});
|
||||
|
||||
// Execute the Redis set operation with timeout
|
||||
await Promise.race([redis.set(key, value), timeoutPromise]);
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Redis set operation failed:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely parses JSON from Redis
|
||||
* @param jsonString JSON string to parse
|
||||
* @param defaultValue Default value to return if parsing fails
|
||||
* @returns Parsed object or default value
|
||||
*/
|
||||
export function safeJsonParse<T>(jsonString: string | null, defaultValue: T): T {
|
||||
if (!jsonString) return defaultValue;
|
||||
|
||||
try {
|
||||
return JSON.parse(jsonString) as T;
|
||||
} catch (error) {
|
||||
console.error('Failed to parse JSON from Redis:', error);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"name": "production-evyos-systems-and-services-3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@tanstack/react-query": "^5.80.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/query-core": {
|
||||
"version": "5.80.7",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.80.7.tgz",
|
||||
"integrity": "sha512-s09l5zeUKC8q7DCCCIkVSns8zZrK4ZDT6ryEjxNBFi68G4z2EBobBS7rdOY3r6W1WbUDpc1fe5oY+YO/+2UVUg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/react-query": {
|
||||
"version": "5.80.7",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.80.7.tgz",
|
||||
"integrity": "sha512-u2F0VK6+anItoEvB3+rfvTO9GEh2vb00Je05OwlUe/A0lkJBgW1HckiY3f9YZa+jx6IOe4dHPh10dyp9aY3iRQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tanstack/query-core": "5.80.7"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18 || ^19"
|
||||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "19.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
|
||||
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"@tanstack/react-query": "^5.80.7"
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue