Allow using acot.site to access

This commit is contained in:
2025-09-30 22:51:36 -04:00
parent c6e4fc9cff
commit 945e4a8cc3
9 changed files with 121 additions and 27 deletions

View File

@@ -35,7 +35,7 @@ global.pool = pool;
app.use(express.json()); app.use(express.json());
app.use(morgan('combined')); app.use(morgan('combined'));
app.use(cors({ app.use(cors({
origin: ['http://localhost:5175', 'http://localhost:5174', 'https://inventory.kent.pw'], origin: ['http://localhost:5175', 'http://localhost:5174', 'https://inventory.kent.pw', 'https://acot.site'],
credentials: true credentials: true
})); }));

View File

@@ -33,7 +33,7 @@ global.pool = pool;
app.use(express.json()); app.use(express.json());
app.use(morgan('combined')); app.use(morgan('combined'));
app.use(cors({ app.use(cors({
origin: ['http://localhost:5175', 'http://localhost:5174', 'https://inventory.kent.pw'], origin: ['http://localhost:5175', 'http://localhost:5174', 'https://inventory.kent.pw', 'https://acot.site'],
credentials: true credentials: true
})); }));

View File

@@ -5,6 +5,7 @@ const corsMiddleware = cors({
origin: [ origin: [
'https://inventory.kent.pw', 'https://inventory.kent.pw',
'http://localhost:5175', 'http://localhost:5175',
'https://acot.site',
/^http:\/\/192\.168\.\d+\.\d+(:\d+)?$/, /^http:\/\/192\.168\.\d+\.\d+(:\d+)?$/,
/^http:\/\/10\.\d+\.\d+\.\d+(:\d+)?$/ /^http:\/\/10\.\d+\.\d+\.\d+(:\d+)?$/
], ],
@@ -26,7 +27,7 @@ const corsErrorHandler = (err, req, res, next) => {
res.status(403).json({ res.status(403).json({
error: 'CORS not allowed', error: 'CORS not allowed',
origin: req.get('Origin'), origin: req.get('Origin'),
message: 'Origin not in allowed list: https://inventory.kent.pw, localhost:5175, 192.168.x.x, or 10.x.x.x' message: 'Origin not in allowed list: https://inventory.kent.pw, https://acot.site, localhost:5175, 192.168.x.x, or 10.x.x.x'
}); });
} else { } else {
next(err); next(err);

View File

@@ -103,8 +103,10 @@ function App() {
</RequireAuth> </RequireAuth>
}> }>
{/* Core inventory app routes - will be lazy loaded */} {/* Core inventory app routes - will be lazy loaded */}
<Route index element={ {/* Default route now prioritizes dashboard, then other pages */}
<Protected page="overview" fallback={<FirstAccessiblePage />}> <Route index element={<FirstAccessiblePage />} />
<Route path="/overview" element={
<Protected page="overview">
<Suspense fallback={<PageLoading />}> <Suspense fallback={<PageLoading />}>
<Overview /> <Overview />
</Suspense> </Suspense>

View File

@@ -3,7 +3,10 @@ import { Navigate } from "react-router-dom";
import { AuthContext } from "@/contexts/AuthContext"; import { AuthContext } from "@/contexts/AuthContext";
// Define available pages in order of priority // Define available pages in order of priority
// Dashboard is first so users with dashboard access default to it
const PAGES = [ const PAGES = [
{ path: "/dashboard", permission: "access:dashboard" },
{ path: "/overview", permission: "access:overview" },
{ path: "/products", permission: "access:products" }, { path: "/products", permission: "access:products" },
{ path: "/categories", permission: "access:categories" }, { path: "/categories", permission: "access:categories" },
{ path: "/vendors", permission: "access:vendors" }, { path: "/vendors", permission: "access:vendors" },

View File

@@ -4,7 +4,6 @@ import {
BarChart2, BarChart2,
Settings, Settings,
ClipboardList, ClipboardList,
LogOut,
Tags, Tags,
PackagePlus, PackagePlus,
ShoppingBag, ShoppingBag,
@@ -28,10 +27,11 @@ import {
SidebarSeparator, SidebarSeparator,
useSidebar useSidebar
} from "@/components/ui/sidebar"; } from "@/components/ui/sidebar";
import { useLocation, useNavigate, Link } from "react-router-dom"; import { useLocation, Link } from "react-router-dom";
import { Protected } from "@/components/auth/Protected"; import { Protected } from "@/components/auth/Protected";
import { useContext } from "react"; import { useContext } from "react";
import { AuthContext } from "@/contexts/AuthContext"; import { AuthContext } from "@/contexts/AuthContext";
import { NavUser } from "./NavUser";
const dashboardItems = [ const dashboardItems = [
{ {
@@ -46,7 +46,7 @@ const inventoryItems = [
{ {
title: "Overview", title: "Overview",
icon: Home, icon: Home,
url: "/", url: "/overview",
permission: "access:overview" permission: "access:overview"
}, },
{ {
@@ -122,16 +122,9 @@ const chatItems = [
export function AppSidebar() { export function AppSidebar() {
const location = useLocation(); const location = useLocation();
const navigate = useNavigate();
useSidebar(); useSidebar();
const { user } = useContext(AuthContext); const { user } = useContext(AuthContext);
const handleLogout = () => {
localStorage.removeItem('token');
sessionStorage.removeItem('isLoggedIn');
navigate('/login');
};
// Check if user has access to any items in a section // Check if user has access to any items in a section
const hasAccessToSection = (items: any[]): boolean => { const hasAccessToSection = (items: any[]): boolean => {
if (user?.is_admin) return true; if (user?.is_admin) return true;
@@ -140,6 +133,8 @@ export function AppSidebar() {
const renderMenuItems = (items: any[]) => { const renderMenuItems = (items: any[]) => {
return items.map((item) => { return items.map((item) => {
// Check if current path matches the item URL
// For root path ("/"), only highlight Overview when at exactly "/"
const isActive = const isActive =
location.pathname === item.url || location.pathname === item.url ||
(item.url !== "/" && item.url !== "#" && location.pathname.startsWith(item.url)); (item.url !== "/" && item.url !== "#" && location.pathname.startsWith(item.url));
@@ -284,16 +279,7 @@ export function AppSidebar() {
</SidebarContent> </SidebarContent>
<SidebarSeparator /> <SidebarSeparator />
<SidebarFooter> <SidebarFooter>
<SidebarMenu> <NavUser />
<SidebarMenuItem>
<SidebarMenuButton asChild tooltip="Logout" onClick={handleLogout}>
<button>
<LogOut className="h-4 w-4" />
<span className="group-data-[collapsible=icon]:hidden">Logout</span>
</button>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarFooter> </SidebarFooter>
</Sidebar> </Sidebar>
); );

View File

@@ -0,0 +1,102 @@
import {
ChevronsUpDown,
LogOut,
} from "lucide-react";
import {
Avatar,
AvatarFallback,
} from "@/components/ui/avatar";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
useSidebar,
} from "@/components/ui/sidebar";
import { useNavigate } from "react-router-dom";
import { useContext } from "react";
import { AuthContext } from "@/contexts/AuthContext";
export function NavUser() {
const { isMobile } = useSidebar();
const { user } = useContext(AuthContext);
const navigate = useNavigate();
const handleLogout = () => {
localStorage.removeItem('token');
sessionStorage.removeItem('isLoggedIn');
navigate('/login');
};
if (!user) {
return null;
}
const userInitial = user.username?.charAt(0).toUpperCase() || 'U';
return (
<SidebarMenu>
<SidebarMenuItem>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<SidebarMenuButton
size="lg"
className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
>
<Avatar className="h-8 w-8 rounded-lg">
<AvatarFallback className="rounded-lg bg-primary/10 text-primary font-semibold">
{userInitial}
</AvatarFallback>
</Avatar>
<div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-semibold">{user.username}</span>
{user.email && (
<span className="truncate text-xs text-muted-foreground">
{user.email}
</span>
)}
</div>
<ChevronsUpDown className="ml-auto size-4" />
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent
className="w-[--radix-dropdown-menu-trigger-width] min-w-56 rounded-lg"
side={isMobile ? "bottom" : "right"}
align="end"
sideOffset={4}
>
<DropdownMenuLabel className="p-0 font-normal">
<div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
<Avatar className="h-8 w-8 rounded-lg">
<AvatarFallback className="rounded-lg bg-primary/10 text-primary font-semibold">
{userInitial}
</AvatarFallback>
</Avatar>
<div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-semibold">{user.username}</span>
{user.email && (
<span className="truncate text-xs text-muted-foreground">
{user.email}
</span>
)}
</div>
</div>
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={handleLogout}>
<LogOut />
Log out
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
</SidebarMenu>
);
}

View File

@@ -2,7 +2,7 @@ const isDev = import.meta.env.DEV;
const isLocal = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'; const isLocal = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
// Use proxy paths when on inventory domains to avoid CORS // Use proxy paths when on inventory domains to avoid CORS
const useProxy = !isLocal && (window.location.hostname === 'inventory.kent.pw' || window.location.hostname === 'inventory.acot.site'); const useProxy = !isLocal && (window.location.hostname === 'inventory.kent.pw' || window.location.hostname === 'inventory.acot.site' || window.location.hostname === 'acot.site');
const liveDashboardConfig = { const liveDashboardConfig = {
auth: isDev || useProxy ? '/dashboard-auth' : 'https://dashboard.kent.pw/auth', auth: isDev || useProxy ? '/dashboard-auth' : 'https://dashboard.kent.pw/auth',

File diff suppressed because one or more lines are too long