Compare commits
No commits in common. "ai-dev" and "master" have entirely different histories.
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,8 +1,3 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
*/node_modules/
|
*/node_modules/
|
||||||
*/build/
|
*/build/
|
||||||
|
|
||||||
**/node_modules/
|
|
||||||
**/build/
|
|
||||||
.DS_Store
|
|
||||||
.env
|
|
||||||
File diff suppressed because one or more lines are too long
@ -114,10 +114,10 @@ app.enable('trust proxy');
|
|||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
'/api/users',
|
'/api/users',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
usersRoutes,
|
usersRoutes,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
'/api/demo_requests',
|
'/api/demo_requests',
|
||||||
passport.authenticate('jwt', { session: false }),
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
|||||||
@ -12,6 +12,7 @@ const { parse } = require('json2csv');
|
|||||||
|
|
||||||
const { checkCrudPermissions } = require('../middlewares/check-permissions');
|
const { checkCrudPermissions } = require('../middlewares/check-permissions');
|
||||||
|
|
||||||
|
router.use(checkCrudPermissions('users'));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
@ -306,8 +307,9 @@ router.get(
|
|||||||
wrapAsync(async (req, res) => {
|
wrapAsync(async (req, res) => {
|
||||||
const filetype = req.query.filetype;
|
const filetype = req.query.filetype;
|
||||||
|
|
||||||
const globalAccess = req.currentUser?.app_role?.globalAccess || false;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
const currentUser = req.currentUser || null;
|
|
||||||
|
const currentUser = req.currentUser;
|
||||||
const payload = await UsersDBApi.findAll(req.query, globalAccess, {
|
const payload = await UsersDBApi.findAll(req.query, globalAccess, {
|
||||||
currentUser,
|
currentUser,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
{}
|
|
||||||
@ -50,11 +50,6 @@ const nextConfig = {
|
|||||||
source: '/pricing',
|
source: '/pricing',
|
||||||
destination: '/web_pages/pricing',
|
destination: '/web_pages/pricing',
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
|
||||||
source: '/users',
|
|
||||||
destination: '/web_pages/users',
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,8 +6,6 @@ import NavBarItemPlain from './NavBarItemPlain';
|
|||||||
import NavBarMenuList from './NavBarMenuList';
|
import NavBarMenuList from './NavBarMenuList';
|
||||||
import { MenuNavBarItem } from '../interfaces';
|
import { MenuNavBarItem } from '../interfaces';
|
||||||
import { useAppSelector } from '../stores/hooks';
|
import { useAppSelector } from '../stores/hooks';
|
||||||
import { ThemeSwitcher } from './ThemeSwitcher';
|
|
||||||
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
menu: MenuNavBarItem[];
|
menu: MenuNavBarItem[];
|
||||||
@ -44,10 +42,6 @@ export default function NavBar({ menu, className = '', children }: Props) {
|
|||||||
isScrolled && `border-b border-pavitra-400 dark:border-dark-700`
|
isScrolled && `border-b border-pavitra-400 dark:border-dark-700`
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="hidden lg:flex items-center px-4 h-14">
|
|
||||||
<ThemeSwitcher />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='flex flex-1 items-stretch h-14'>{children}</div>
|
<div className='flex flex-1 items-stretch h-14'>{children}</div>
|
||||||
<div className='flex-none items-stretch flex h-14 lg:hidden'>
|
<div className='flex-none items-stretch flex h-14 lg:hidden'>
|
||||||
<NavBarItemPlain onClick={handleMenuNavBarToggleClick}>
|
<NavBarItemPlain onClick={handleMenuNavBarToggleClick}>
|
||||||
|
|||||||
@ -1,52 +0,0 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
import { useAppDispatch } from '../stores/hooks';
|
|
||||||
import { setStyle } from '../stores/styleSlice';
|
|
||||||
import { StyleKey } from '../interfaces';
|
|
||||||
import { localStorageStyleKey } from '../config';
|
|
||||||
|
|
||||||
const availableThemes: { key: StyleKey; label: string }[] = [
|
|
||||||
{ key: 'white', label: 'White' },
|
|
||||||
{ key: 'basic', label: 'Basic' },
|
|
||||||
{ key: 'minimized', label: 'Min.' },
|
|
||||||
{ key: 'facebook', label: 'FB' },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const ThemeSwitcher = (): JSX.Element => {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const [theme, setThemeState] = useState<StyleKey>('minimized');
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (typeof localStorage !== 'undefined') {
|
|
||||||
const saved = (localStorage.getItem(localStorageStyleKey) as StyleKey) || 'minimized';
|
|
||||||
setThemeState(saved);
|
|
||||||
dispatch(setStyle(saved));
|
|
||||||
}
|
|
||||||
}, [dispatch]);
|
|
||||||
|
|
||||||
const handleSelect = (key: StyleKey) => {
|
|
||||||
setThemeState(key);
|
|
||||||
localStorage.setItem(localStorageStyleKey, key);
|
|
||||||
dispatch(setStyle(key));
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex items-center">
|
|
||||||
<div className="bg-white dark:bg-dark-700 rounded-full shadow px-1 py-1 flex space-x-1">
|
|
||||||
{availableThemes.map(({ key, label }) => (
|
|
||||||
<button
|
|
||||||
key={key}
|
|
||||||
onClick={() => handleSelect(key)}
|
|
||||||
className={`rounded-full px-3 py-1 text-xs font-medium transition-colors focus:outline-none
|
|
||||||
${
|
|
||||||
theme === key
|
|
||||||
? 'bg-blue-500 text-white'
|
|
||||||
: 'bg-transparent text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-dark-600'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{label}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -114,7 +114,7 @@ export interface User {
|
|||||||
notes: any[];
|
notes: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type StyleKey = 'white' | 'basic' | 'minimized' | 'facebook';
|
export type StyleKey = 'white' | 'basic';
|
||||||
|
|
||||||
export type UserForm = {
|
export type UserForm = {
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
@ -67,11 +67,6 @@ export const webPagesNavBar = [
|
|||||||
href: '/pricing',
|
href: '/pricing',
|
||||||
label: 'pricing',
|
label: 'pricing',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
href: '/users',
|
|
||||||
label: 'users',
|
|
||||||
},
|
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export default menuNavBar;
|
export default menuNavBar;
|
||||||
|
|||||||
@ -15,8 +15,8 @@ import { hasPermission } from '../helpers/userPermissions';
|
|||||||
import { fetchWidgets } from '../stores/roles/rolesSlice';
|
import { fetchWidgets } from '../stores/roles/rolesSlice';
|
||||||
import { WidgetCreator } from '../components/WidgetCreator/WidgetCreator';
|
import { WidgetCreator } from '../components/WidgetCreator/WidgetCreator';
|
||||||
import { SmartWidget } from '../components/SmartWidget/SmartWidget';
|
import { SmartWidget } from '../components/SmartWidget/SmartWidget';
|
||||||
import { useAppDispatch, useAppSelector } from '../stores/hooks';
|
|
||||||
|
|
||||||
|
import { useAppDispatch, useAppSelector } from '../stores/hooks';
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
const { t } = useTranslation('common');
|
const { t } = useTranslation('common');
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
@ -24,17 +24,11 @@ const Dashboard = () => {
|
|||||||
const corners = useAppSelector((state) => state.style.corners);
|
const corners = useAppSelector((state) => state.style.corners);
|
||||||
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
|
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
|
||||||
|
|
||||||
{/* Theme switcher relocated to NavBar */}
|
const loadingMessage = t('pages.dashboard.loading', {
|
||||||
<div className='mb-4 flex items-center'>
|
defaultValue: 'Loading...',
|
||||||
<h2 className='text-xl font-semibold text-gray-800 dark:text-gray-200 flex-1'>
|
});
|
||||||
{t('Your workspaces')}
|
|
||||||
</h2>
|
|
||||||
{/* <ThemeSwitcher /> */}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
const loadingMessage: number | string | null = null;
|
|
||||||
const [users, setUsers] = React.useState<number | string | null>(loadingMessage);
|
|
||||||
|
|
||||||
|
const [users, setUsers] = React.useState(loadingMessage);
|
||||||
const [demo_requests, setDemo_requests] = React.useState(loadingMessage);
|
const [demo_requests, setDemo_requests] = React.useState(loadingMessage);
|
||||||
const [notifications, setNotifications] = React.useState(loadingMessage);
|
const [notifications, setNotifications] = React.useState(loadingMessage);
|
||||||
const [reports, setReports] = React.useState(loadingMessage);
|
const [reports, setReports] = React.useState(loadingMessage);
|
||||||
|
|||||||
@ -1,70 +0,0 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
import type { ReactElement } from 'react';
|
|
||||||
import Head from 'next/head';
|
|
||||||
import LayoutGuest from '../../layouts/Guest';
|
|
||||||
import WebSiteHeader from '../../components/WebPageComponents/Header';
|
|
||||||
import WebSiteFooter from '../../components/WebPageComponents/Footer';
|
|
||||||
|
|
||||||
type User = {
|
|
||||||
id: string;
|
|
||||||
firstName: string;
|
|
||||||
lastName: string;
|
|
||||||
email: string;
|
|
||||||
avatar?: { url: string }[];
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function Users() {
|
|
||||||
const [users, setUsers] = useState<User[]>([]);
|
|
||||||
const [loading, setLoading] = useState(true);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetch('/api/users')
|
|
||||||
.then((res) => res.json())
|
|
||||||
.then((data) => {
|
|
||||||
setUsers(data.rows);
|
|
||||||
setLoading(false);
|
|
||||||
})
|
|
||||||
.catch(() => setLoading(false));
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col min-h-screen">
|
|
||||||
<Head>
|
|
||||||
<title>Users - Strategic Intelligence Engine</title>
|
|
||||||
<meta
|
|
||||||
name="description"
|
|
||||||
content="Public list of users for the Strategic Intelligence Engine."
|
|
||||||
/>
|
|
||||||
</Head>
|
|
||||||
|
|
||||||
<WebSiteHeader projectName="IntelliLedger Consulting" />
|
|
||||||
|
|
||||||
<main className="flex-grow bg-white px-4 py-8">
|
|
||||||
<section className="max-w-4xl mx-auto">
|
|
||||||
<h1 className="text-4xl font-bold mb-4">Users</h1>
|
|
||||||
{loading ? (
|
|
||||||
<p>Loading users...</p>
|
|
||||||
) : (
|
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
|
|
||||||
|
|
||||||
{users.map((user) => (
|
|
||||||
<div key={user.id} className="bg-white shadow p-4 rounded-lg">
|
|
||||||
<img src={user.avatar?.[0]?.url || '/favicon.svg'} alt={`${user.firstName} ${user.lastName}`} className="w-12 h-12 rounded-full mb-2 object-cover" />
|
|
||||||
<p className="font-medium text-lg">{user.firstName} {user.lastName}</p>
|
|
||||||
<p className="text-sm text-gray-500">{user.email}</p>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</section>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<WebSiteFooter projectName="IntelliLedger Consulting" />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Users.getLayout = function getLayout(page: ReactElement) {
|
|
||||||
return <LayoutGuest>{page}</LayoutGuest>;
|
|
||||||
};
|
|
||||||
@ -31,30 +31,30 @@ interface StyleState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const initialState: StyleState = {
|
const initialState: StyleState = {
|
||||||
asideStyle: styles.minimized.aside,
|
asideStyle: styles.white.aside,
|
||||||
asideScrollbarsStyle: styles.minimized.asideScrollbars,
|
asideScrollbarsStyle: styles.white.asideScrollbars,
|
||||||
asideBrandStyle: styles.minimized.asideBrand,
|
asideBrandStyle: styles.white.asideBrand,
|
||||||
asideMenuItemStyle: styles.minimized.asideMenuItem,
|
asideMenuItemStyle: styles.white.asideMenuItem,
|
||||||
asideMenuItemActiveStyle: styles.minimized.asideMenuItemActive,
|
asideMenuItemActiveStyle: styles.white.asideMenuItemActive,
|
||||||
asideMenuDropdownStyle: styles.minimized.asideMenuDropdown,
|
asideMenuDropdownStyle: styles.white.asideMenuDropdown,
|
||||||
navBarItemLabelStyle: styles.minimized.navBarItemLabel,
|
navBarItemLabelStyle: styles.white.navBarItemLabel,
|
||||||
navBarItemLabelHoverStyle: styles.minimized.navBarItemLabelHover,
|
navBarItemLabelHoverStyle: styles.white.navBarItemLabelHover,
|
||||||
navBarItemLabelActiveColorStyle: styles.minimized.navBarItemLabelActiveColor,
|
navBarItemLabelActiveColorStyle: styles.white.navBarItemLabelActiveColor,
|
||||||
overlayStyle: styles.minimized.overlay,
|
overlayStyle: styles.white.overlay,
|
||||||
darkMode: false,
|
darkMode: false,
|
||||||
bgLayoutColor: styles.minimized.bgLayoutColor,
|
bgLayoutColor: styles.white.bgLayoutColor,
|
||||||
iconsColor: styles.minimized.iconsColor,
|
iconsColor: styles.white.iconsColor,
|
||||||
activeLinkColor: styles.minimized.activeLinkColor,
|
activeLinkColor: styles.white.activeLinkColor,
|
||||||
cardsColor: styles.minimized.cardsColor,
|
cardsColor: styles.white.cardsColor,
|
||||||
focusRingColor: styles.minimized.focusRingColor,
|
focusRingColor: styles.white.focusRingColor,
|
||||||
corners: styles.minimized.corners,
|
corners: styles.white.corners,
|
||||||
cardsStyle: styles.minimized.cardsStyle,
|
cardsStyle: styles.white.cardsStyle,
|
||||||
linkColor: styles.minimized.linkColor,
|
linkColor: styles.white.linkColor,
|
||||||
websiteHeder: styles.minimized.websiteHeder,
|
websiteHeder: styles.white.websiteHeder,
|
||||||
borders: styles.minimized.borders,
|
borders: styles.white.borders,
|
||||||
shadow: styles.minimized.shadow,
|
shadow: styles.white.shadow,
|
||||||
websiteSectionStyle: styles.minimized.websiteSectionStyle,
|
websiteSectionStyle: styles.white.websiteSectionStyle,
|
||||||
textSecondary: styles.minimized.textSecondary,
|
textSecondary: styles.white.textSecondary,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const styleSlice = createSlice({
|
export const styleSlice = createSlice({
|
||||||
|
|||||||
@ -104,55 +104,3 @@ export const basic: StyleObject = {
|
|||||||
websiteSectionStyle: '',
|
websiteSectionStyle: '',
|
||||||
textSecondary: '',
|
textSecondary: '',
|
||||||
};
|
};
|
||||||
export const minimized: StyleObject = {
|
|
||||||
aside: 'bg-gray-50 dark:bg-gray-900 dark:text-gray-400 p-1',
|
|
||||||
asideScrollbars: 'aside-scrollbars-light',
|
|
||||||
asideBrand: '',
|
|
||||||
asideMenuItem: 'text-gray-600 dark:text-gray-400 p-0.5 hover:bg-gray-100 dark:hover:bg-dark-800',
|
|
||||||
asideMenuItemActive: 'font-medium text-gray-800 dark:text-gray-100',
|
|
||||||
asideMenuDropdown: 'bg-gray-100/50',
|
|
||||||
navBarItemLabel: 'text-gray-600 text-xs',
|
|
||||||
navBarItemLabelHover: 'hover:text-gray-700',
|
|
||||||
navBarItemLabelActiveColor: 'text-gray-900',
|
|
||||||
overlay: '',
|
|
||||||
activeLinkColor: 'bg-gray-50/20',
|
|
||||||
bgLayoutColor: 'bg-gray-50',
|
|
||||||
iconsColor: 'text-gray-700',
|
|
||||||
cardsColor: 'bg-gray-50',
|
|
||||||
focusRingColor: 'focus:outline-none focus:ring-1 focus:ring-gray-500',
|
|
||||||
corners: 'rounded-sm',
|
|
||||||
cardsStyle: 'bg-gray-50 border border-gray-200 !p-2',
|
|
||||||
linkColor: 'text-gray-700',
|
|
||||||
websiteHeder: 'border-b border-gray-100',
|
|
||||||
borders: 'border-gray-100',
|
|
||||||
shadow: '',
|
|
||||||
websiteSectionStyle: '',
|
|
||||||
textSecondary: 'text-gray-600 text-xs',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const facebook: StyleObject = {
|
|
||||||
aside: 'bg-[#F0F2F5] text-[#050505]',
|
|
||||||
asideScrollbars: 'aside-scrollbars-light',
|
|
||||||
asideBrand: '',
|
|
||||||
asideMenuItem: 'text-[#050505] hover:bg-[#e4e6eb]',
|
|
||||||
asideMenuItemActive: 'font-bold text-[#1877F2]',
|
|
||||||
asideMenuDropdown: 'bg-[#e4e6eb]',
|
|
||||||
navBarItemLabel: 'text-[#1877F2]',
|
|
||||||
navBarItemLabelHover: 'hover:text-[#155DB2]',
|
|
||||||
navBarItemLabelActiveColor: 'text-[#155DB2]',
|
|
||||||
overlay: '',
|
|
||||||
activeLinkColor: 'bg-[#e4e6eb]',
|
|
||||||
bgLayoutColor: 'bg-[#F0F2F5]',
|
|
||||||
iconsColor: 'text-[#1877F2]',
|
|
||||||
cardsColor: 'bg-white',
|
|
||||||
focusRingColor: 'focus:ring focus:ring-[#1877F2] focus:border-[#1877F2]',
|
|
||||||
corners: 'rounded',
|
|
||||||
cardsStyle: 'bg-white border border-[#e4e6eb]',
|
|
||||||
linkColor: 'text-[#1877F2]',
|
|
||||||
websiteHeder: 'border-b border-[#e4e6eb]',
|
|
||||||
borders: 'border-[#e4e6eb]',
|
|
||||||
shadow: '',
|
|
||||||
websiteSectionStyle: '',
|
|
||||||
textSecondary: 'text-[#65676B]',
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user