Skip to content

Commit

Permalink
Changes:
Browse files Browse the repository at this point in the history
feat:
- added new components for routing specific states including unfinished and generic error

- useCurrentApp is a new hook to work out which "app" you are on based on the route tree
- removed the need for a redux reducer
- added unfinished component for routes that are unfinished

fix:
- authentication.controller.ts handles conflicts

chore:
- refactored how types are handled in forge
- refactored the redux reducers and redux folder
  • Loading branch information
Sampiiiii committed Apr 13, 2024
1 parent a35af1d commit 047ffbf
Show file tree
Hide file tree
Showing 48 changed files with 1,442 additions and 1,370 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { User } from "@ignis/types/users";
import {
BadRequestException,
Body,
ConflictException,
Controller,
Get,
Post,
Expand All @@ -19,6 +20,7 @@ import { Throttle } from "@nestjs/throttler";
import { Request, Response } from "express";
import { AuthenticationService } from "./authentication.service";
import { BlacklistService } from "./blacklist/blacklist.service";
import { CardinalityViolationError } from "edgedb";

@Controller("authentication")
export class AuthenticationController {
Expand Down Expand Up @@ -80,7 +82,11 @@ export class AuthenticationController {

// Add the token to the blacklist
const expiryDate = new Date();
await this.blacklistService.addToBlacklist(refreshToken, expiryDate);
try {
await this.blacklistService.addToBlacklist(refreshToken, expiryDate);
} catch (error) {
throw new ConflictException("Refresh token is invalid or expired");
}

this.authService.clearAuthCookies(res);

Expand Down
10 changes: 3 additions & 7 deletions apps/forge/src/api/axiosInstance.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import axios from "axios";
import { useDispatch } from "react-redux";
import useLogout from "@/services/auth/useLogout.ts";

const axiosInstance = axios.create({
baseURL: import.meta.env.VITE_API_URL,
Expand All @@ -14,16 +12,14 @@ const RETRY_DELAY = 1000; // Starting retry delay in milliseconds
axiosInstance.interceptors.response.use(
(response) => response,
async (error) => {
const dispatch = useDispatch();
const logout = useLogout(dispatch);
const originalRequest = error.config;
if (error.response && error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
originalRequest._retryCount = originalRequest._retryCount || 0;

if (originalRequest._retryCount >= RETRY_LIMIT) {
await logout;
return Promise.reject("Retry limit reached. Logging out...");
//TODO WORK OUT HOW TO LOGOUT / WORK THIS BIT OUT IM NOT SURE EXACTLY WHAT IM DOING HERE RN
}

originalRequest._retryCount++;
Expand All @@ -34,11 +30,11 @@ axiosInstance.interceptors.response.use(
await axiosInstance.post("/authentication/refresh");
return axiosInstance(originalRequest);
} catch (refreshError) {
await logout;
return Promise.reject(refreshError);
}
} else {
return Promise.reject(error);
}
return Promise.reject(error);
},
);

Expand Down
47 changes: 21 additions & 26 deletions apps/forge/src/components/auth-provider/index.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,38 @@
import * as React from "react";
import {User} from "@ignis/types/users.ts";
import {useVerifyAuthentication} from "@/hooks/useVerifyAuthentication.tsx";
import {Loader} from "@ui/components/ui/loader.tsx";
import { User } from "@ignis/types/users.ts";
import { useVerifyAuthentication } from "@/hooks/useVerifyAuthentication.ts";
import { Loader } from "@ui/components/ui/loader.tsx";

export interface AuthContext {
isAuthenticated: boolean;
user: User | null;
logout: () => void;
isAuthenticated: boolean;
user: User | null;
logout: () => void;
}

const AuthContext = React.createContext<AuthContext | null>(null);

export function AuthProvider({ children }: { children: React.ReactNode }) {
const { user, loading, setUser } = useVerifyAuthentication();
const { user, loading, setUser } = useVerifyAuthentication();

if (loading) {
return <Loader />;
}
if (loading) {
return <Loader />;
}

const isAuthenticated = !!user;
const isAuthenticated = !!user;

const logout = () => {
setUser(null);
};

const logout = () => {
setUser(null)
}
const contextValue = { isAuthenticated, user, logout };

const contextValue = { isAuthenticated, user, logout };

return (
<AuthContext.Provider value={contextValue}>
{children}
</AuthContext.Provider>
);
return <AuthContext.Provider value={contextValue}>{children}</AuthContext.Provider>;
}

export function useAuth() {
const context = React.useContext(AuthContext);
if (!context) {
throw new Error("useAuth must be used within an AuthProvider");
}
return context;
const context = React.useContext(AuthContext);
if (!context) {
throw new Error("useAuth must be used within an AuthProvider");
}
return context;
}
88 changes: 47 additions & 41 deletions apps/forge/src/components/navbar/appNav/appLinks.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,56 @@
// appLinks.ts
import {Apps} from "@/redux/app/app.types.ts";
import { Apps } from "@/types/app.ts";

export type AppLink = {
app: Apps; // Identifier for the app
displayName: string; // User-facing name
path?: string; // Path for the link
children?: AppLink[]; // Nested links, specific to the same app
index?: number; // Index of the link in the navbar (PER LEVEL)
id: string; // Unique identifier for the link
app: Apps; // Identifier for the app
displayName: string; // User-facing name
path?: string; // Path for the link
children?: AppLink[]; // Nested links, specific to the same app
index?: number; // Index of the link in the navbar (PER LEVEL)
id: string; // Unique identifier for the link
};

export const appLinks: AppLink[] = [
{app: "Main", displayName: "Home", path: "/", index: 0, id: "home"},
{app: "Sign In", displayName: "Sign In Home", path: "/signin", index: 0, id: "signin_root"},
{
{ app: "Main", displayName: "Home", path: "/", index: 0, id: "home" },
{ app: "Sign In", displayName: "Sign In Home", path: "/signin", index: 0, id: "signin_root" },
{
app: "Sign In",
displayName: "Agreements",
path: "/signin/agreements",
index: 1,
id: "signin_agreements",
},
{
app: "Sign In",
displayName: "Actions",
path: "/signin/actions",
index: 2,
id: "signin_actions_root",
children: [
{
app: "Sign In",
displayName: "Agreements",
path: "/signin/agreements",
index: 1,
id: "signin_agreements"
},
{
displayName: "Sign In",
path: "/signin/actions/in",
index: 0,
id: "signin_actions_in",
},
{ app: "Sign In", displayName: "Sign Out", path: "/signin/actions/out", id: "signin_actions_out", index: 1 },
{
app: "Sign In",
displayName: "Actions",
path: "/signin/actions",
displayName: "Register",
path: "/signin/actions/register",
id: "signin_actions_register",
index: 2,
id: "signin_actions_root",
children: [
{
app: "Sign In",
displayName: "Sign In",
path: "/signin/actions/in",
index: 0,
id: "signin_actions_in",
},
{app: "Sign In", displayName: "Sign Out", path: "/signin/actions/out", id: "signin_actions_out", index: 1},
{app: "Sign In", displayName: "Register", path: "/signin/actions/register", id: "signin_actions_register", index: 2},
{
app: "Sign In",
displayName: "Enqueue",
path: "/signin/actions/enqueue",
id: "signin_actions_enqueue",
index: 3,
},
]
},
{app: "Sign In", displayName: "Dashboard", path: "/signin/dashboard", index: 1, id: "signin_status"},
{app: "Printing", displayName: "Printing", path: "/printing", id: "printing_root", index: 0},
];
},
{
app: "Sign In",
displayName: "Enqueue",
path: "/signin/actions/enqueue",
id: "signin_actions_enqueue",
index: 3,
},
],
},
{ app: "Sign In", displayName: "Dashboard", path: "/signin/dashboard", index: 1, id: "signin_status" },
{ app: "Printing", displayName: "Printing", path: "/printing", id: "printing_root", index: 0 },
];
52 changes: 27 additions & 25 deletions apps/forge/src/components/navbar/appNav/index.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@
// NavBar.tsx
import {Link} from "@tanstack/react-router";
import {useSelector} from "react-redux";
import {AppRootState} from "@/redux/store";
import {appLinks} from "./appLinks";
import {AppLinkDropdown} from './appLinkDropdown.tsx';
import { Link } from "@tanstack/react-router";
import { appLinks } from "./appLinks";
import { AppLinkDropdown } from "./appLinkDropdown.tsx";

export default function AppNav() {
const currentApp = useSelector((state: AppRootState) => state.app.current_app);
const sortedAppLinks = appLinks.sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
import useCurrentApp from "@/hooks/useCurrentApp.ts";

return (
<div className="p-2 flex flex-row align-middle justify-items-center justify-center">
{sortedAppLinks.map((link) => {
if (link.app === currentApp) {
return link.children && link.children.length > 0 ? (
<AppLinkDropdown key={link.id} link={link} />
) : (
<Link key={link.displayName} to={link.path ?? '#'}
className="inline-flex items-center px-4 py-2 text-sm font-medium rounded-md text-navbar-foreground hover:bg-accent">
{link.displayName}
</Link>
);
}
return null;
})}
</div>
);
export default function AppNav() {
const currentApp = useCurrentApp();
const sortedAppLinks = appLinks.sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
return (
<div className="p-2 flex flex-row align-middle justify-items-center justify-center">
{sortedAppLinks.map((link) => {
if (link.app === currentApp) {
return link.children && link.children.length > 0 ? (
<AppLinkDropdown key={link.id} link={link} />
) : (
<Link
key={link.displayName}
to={link.path ?? "#"}
className="inline-flex items-center px-4 py-2 text-sm font-medium rounded-md text-navbar-foreground hover:bg-accent"
>
{link.displayName}
</Link>
);
}
return null;
})}
</div>
);
}
29 changes: 7 additions & 22 deletions apps/forge/src/components/navbar/appSwitcher/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import ContextMenuWrapper from "@/components/navbar/appSwitcher/ContextMenu.tsx";
import ListItem from "@/components/navbar/appSwitcher/ListItem";
import { appActions } from "@/redux/app/app.slice";
import { Apps } from "@/redux/app/app.types";
import { AppRootState } from "@/redux/store";
import { Link } from "@tanstack/react-router";
import {
NavigationMenu,
Expand All @@ -13,23 +10,17 @@ import {
NavigationMenuTrigger,
} from "@ui/components/ui/navigation-menu";
import { PenLine, Printer, Share2 } from "lucide-react";
import { useDispatch, useSelector } from "react-redux";
import useCurrentApp from "@/hooks/useCurrentApp.ts";

export default function AppSwitcher() {
const dispatch = useDispatch();
const app = useSelector((state: AppRootState) => state.app.current_app);

// Function to handle app change
const handleAppChange = (newApp: Apps) => {
dispatch(appActions.setApp(newApp));
};
const currentapp = useCurrentApp();

return (
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<ContextMenuWrapper>
<NavigationMenuTrigger className="bg-navbar">iForge | {app}</NavigationMenuTrigger>
<NavigationMenuTrigger className="bg-navbar">iForge | {currentapp}</NavigationMenuTrigger>
</ContextMenuWrapper>
<NavigationMenuContent>
<ul className="grid gap-3 p-4 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]">
Expand All @@ -38,7 +29,6 @@ export default function AppSwitcher() {
<Link
className="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-primary/50 to-background p-6 no-underline outline-none focus:shadow-md"
to="/"
onClick={() => handleAppChange("Main")}
>
<div className="mb-2 mt-4 text-lg font-medium">iForge</div>
<p className="text-sm leading-tight text-muted-foreground">
Expand All @@ -47,19 +37,14 @@ export default function AppSwitcher() {
</Link>
</NavigationMenuLink>
</li>
<ListItem to={"/signin"} title="Sign In" icon={<PenLine />} onClick={() => handleAppChange("Sign In")}>
<ListItem to={"/signin"} title="Sign In" icon={<PenLine />}>
Remote queue and space access for easy sign-in.
</ListItem>
<ListItem to={"/training"} title="Training" icon={<Share2 />} onClick={() => handleAppChange("Training")}>
<ListItem to={"/training"} title="Training" icon={<Share2 />}>
Handle your iForge training here.
</ListItem>
<ListItem
to={"/printing"}
title="Printing"
icon={<Printer />}
onClick={() => handleAppChange("Printing")}
>
Advanced 3D printing to realize your creative designs.
<ListItem to={"/printing"} title="Printing" icon={<Printer />}>
3D Printing WIP
</ListItem>
</ul>
</NavigationMenuContent>
Expand Down
33 changes: 17 additions & 16 deletions apps/forge/src/components/navbar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import AppSwitcher from "@/components/navbar/appSwitcher";
import {ThemeSwitcher} from "@/components/navbar/themeSwitcher";
import {UserNav} from "@/components/navbar/userNav";
import { ThemeSwitcher } from "@/components/navbar/themeSwitcher";
import { UserNav } from "@/components/navbar/userNav";
import AppNav from "@/components/navbar/appNav";

export default function NavBar() {
return (
<div
className="flex items-center justify-between h-[60px] p-3 w-full bg-navbar backdrop-filter shadow-lg dark:shadow-none">
<div className="flex flex-1">
<AppSwitcher/>
</div>
<div className="flex-1 text-center"><AppNav/></div>
<div className="flex flex-1 justify-end pr-1">
<div className="flex items-center space-x-4">
<ThemeSwitcher/>
<UserNav/>
</div>
</div>
return (
<div className="flex items-center justify-between h-[60px] p-3 w-full bg-navbar backdrop-filter shadow-lg dark:shadow-none">
<div className="flex flex-1">
<AppSwitcher />
</div>
<div className="flex-1 text-center">
<AppNav />
</div>
<div className="flex flex-1 justify-end pr-1">
<div className="flex items-center space-x-4">
<ThemeSwitcher />
<UserNav />
</div>
);
</div>
</div>
);
}
Loading

0 comments on commit 047ffbf

Please sign in to comment.