UPDATE AuthController to return user details with APIResponse; ADD user fetching logic in MainLayout and Topbar

This commit is contained in:
2025-06-24 20:00:05 +02:00
parent 0237ec57db
commit 8ab0472ac7
7 changed files with 69 additions and 14 deletions

View File

@@ -1,17 +1,18 @@
import { Menu, X } from 'lucide-react'; import { Menu, X } from 'lucide-react';
import MenuButton from "./buttons/MenuButton.tsx"; import MenuButton from "./buttons/MenuButton.tsx";
import clsx from "clsx"; import clsx from "clsx";
import type {User} from "../utils/types.ts";
type props = { type props = {
sidebarToggled: boolean; sidebarToggled: boolean;
setSidebarToggled: Function; setSidebarToggled: Function;
user: User | null;
className?: string; className?: string;
} }
const Topbar = ({sidebarToggled, setSidebarToggled, className}: props) => { const Topbar = ({sidebarToggled, setSidebarToggled, user, className}: props) => {
const apiUrl = import.meta.env.VITE_API_URL; const apiUrl = import.meta.env.VITE_API_URL;
const redirectUri = encodeURIComponent(window.location.href); const loginUrl = `${apiUrl}/oauth2/authorization/google`;
const loginUrl = `${apiUrl}/oauth2/authorization/google?redirect_uri=${redirectUri}`;
return ( return (
<div className={clsx(className, "flex justify-between")}> <div className={clsx(className, "flex justify-between")}>
@@ -19,9 +20,9 @@ const Topbar = ({sidebarToggled, setSidebarToggled, className}: props) => {
{sidebarToggled ? <Menu size={24}/> : <X size={24}/>} {sidebarToggled ? <Menu size={24}/> : <X size={24}/>}
</MenuButton> </MenuButton>
<MenuButton className={"w-20 text-gray-600"} <MenuButton className={"w-40 text-gray-600"}
onClick={() => globalThis.location.href = loginUrl}> onClick={() => globalThis.location.href = loginUrl}>
Login { user ? user.name : "Login" }
</MenuButton> </MenuButton>
</div> </div>
) )

View File

@@ -2,10 +2,26 @@
import Sidebar from '../components/Sidebar' import Sidebar from '../components/Sidebar'
import Topbar from '../components/Topbar' import Topbar from '../components/Topbar'
import { Outlet } from 'react-router-dom'; import { Outlet } from 'react-router-dom';
import {useState} from "react"; import {useEffect, useState} from "react";
import type {User} from "../utils/types";
import { getUser } from "../utils/endpoints";
const MainLayout = () => { const MainLayout = () => {
const [sidebarToggled, setSidebarToggled] = useState(false); const [sidebarToggled, setSidebarToggled] = useState(false);
const [user, setUser] = useState<null | User>(null);
useEffect(() => {
const fetchUser = async () => {
try {
const userData = await getUser();
setUser(userData);
} catch (error) {
console.error('Failed to fetch user:', error);
}
};
fetchUser();
}, []);
return ( return (
<div className={`transition-all duration-300 grid h-screen ${sidebarToggled ? "grid-cols-[0px_1fr]" : "grid-cols-[240px_1fr]"} grid-rows-[auto_1fr]`}> <div className={`transition-all duration-300 grid h-screen ${sidebarToggled ? "grid-cols-[0px_1fr]" : "grid-cols-[240px_1fr]"} grid-rows-[auto_1fr]`}>
@@ -14,7 +30,8 @@ const MainLayout = () => {
<Topbar <Topbar
className="transition-all duration-300" className="transition-all duration-300"
sidebarToggled={sidebarToggled} sidebarToggled={sidebarToggled}
setSidebarToggled={setSidebarToggled}/> setSidebarToggled={setSidebarToggled}
user={user}/>
<div className="overflow-auto"> <div className="overflow-auto">
<Outlet /> <Outlet />
</div> </div>

View File

@@ -1,4 +1,4 @@
import type {VideoMetadata, APIResponse} from "./types.ts"; import type {VideoMetadata, APIResponse, User} from "./types.ts";
/** /**
* Uploads a file to the backend. * Uploads a file to the backend.
@@ -129,10 +129,23 @@ const getMetadata = async (uuid: string): Promise<VideoMetadata> => {
} }
}; };
const getUser = async (): Promise<null | User > => {
try {
const response = await fetch('/api/v1/auth/user', {credentials: "include",});
const result = await response.json();
return result.data;
} catch (error: unknown) {
console.error('Error fetching user:', error);
return null;
}
}
export { export {
uploadFile, uploadFile,
editFile, editFile,
processFile, processFile,
getProgress, getProgress,
getMetadata, getMetadata,
getUser
}; };

View File

@@ -13,7 +13,13 @@ type APIResponse = {
message: string message: string
} }
type User = {
name: string,
email: string
}
export type { export type {
APIResponse, APIResponse,
VideoMetadata VideoMetadata,
User
} }

View File

@@ -1,5 +1,6 @@
package com.ddf.vodsystem.configuration; package com.ddf.vodsystem.configuration;
import com.ddf.vodsystem.security.CustomOAuth2UserService;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;

View File

@@ -1,5 +1,8 @@
package com.ddf.vodsystem.controllers; package com.ddf.vodsystem.controllers;
import com.ddf.vodsystem.entities.APIResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@@ -13,7 +16,21 @@ import java.util.Map;
public class AuthController { public class AuthController {
@GetMapping("/user") @GetMapping("/user")
public Map<String, Object> user(@AuthenticationPrincipal OAuth2User principal) { public ResponseEntity<APIResponse<Map<String, Object>>> user(@AuthenticationPrincipal OAuth2User principal) {
return principal.getAttributes(); if (principal == null) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).
body(new APIResponse<>(
"error",
"User not authenticated",
null
));
}
return ResponseEntity.ok(
new APIResponse<>("success", "User details retrieved successfully", Map.of(
"name", principal.getAttribute("name"),
"email", principal.getAttribute("email"))
)
);
} }
} }

View File

@@ -1,4 +1,4 @@
package com.ddf.vodsystem.configuration; package com.ddf.vodsystem.security;
import com.ddf.vodsystem.entities.User; import com.ddf.vodsystem.entities.User;
import com.ddf.vodsystem.repositories.UserRepository; import com.ddf.vodsystem.repositories.UserRepository;