UPDATE AuthController to return user details with APIResponse; ADD user fetching logic in MainLayout and Topbar
This commit is contained in:
@@ -1,17 +1,18 @@
|
||||
import { Menu, X } from 'lucide-react';
|
||||
import MenuButton from "./buttons/MenuButton.tsx";
|
||||
import clsx from "clsx";
|
||||
import type {User} from "../utils/types.ts";
|
||||
|
||||
type props = {
|
||||
sidebarToggled: boolean;
|
||||
setSidebarToggled: Function;
|
||||
user: User | null;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const Topbar = ({sidebarToggled, setSidebarToggled, className}: props) => {
|
||||
const Topbar = ({sidebarToggled, setSidebarToggled, user, className}: props) => {
|
||||
const apiUrl = import.meta.env.VITE_API_URL;
|
||||
const redirectUri = encodeURIComponent(window.location.href);
|
||||
const loginUrl = `${apiUrl}/oauth2/authorization/google?redirect_uri=${redirectUri}`;
|
||||
const loginUrl = `${apiUrl}/oauth2/authorization/google`;
|
||||
|
||||
return (
|
||||
<div className={clsx(className, "flex justify-between")}>
|
||||
@@ -19,9 +20,9 @@ const Topbar = ({sidebarToggled, setSidebarToggled, className}: props) => {
|
||||
{sidebarToggled ? <Menu size={24}/> : <X size={24}/>}
|
||||
</MenuButton>
|
||||
|
||||
<MenuButton className={"w-20 text-gray-600"}
|
||||
<MenuButton className={"w-40 text-gray-600"}
|
||||
onClick={() => globalThis.location.href = loginUrl}>
|
||||
Login
|
||||
{ user ? user.name : "Login" }
|
||||
</MenuButton>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -2,10 +2,26 @@
|
||||
import Sidebar from '../components/Sidebar'
|
||||
import Topbar from '../components/Topbar'
|
||||
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 [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 (
|
||||
<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
|
||||
className="transition-all duration-300"
|
||||
sidebarToggled={sidebarToggled}
|
||||
setSidebarToggled={setSidebarToggled}/>
|
||||
setSidebarToggled={setSidebarToggled}
|
||||
user={user}/>
|
||||
<div className="overflow-auto">
|
||||
<Outlet />
|
||||
</div>
|
||||
|
||||
@@ -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.
|
||||
@@ -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 {
|
||||
uploadFile,
|
||||
editFile,
|
||||
processFile,
|
||||
getProgress,
|
||||
getMetadata,
|
||||
getUser
|
||||
};
|
||||
@@ -13,7 +13,13 @@ type APIResponse = {
|
||||
message: string
|
||||
}
|
||||
|
||||
type User = {
|
||||
name: string,
|
||||
email: string
|
||||
}
|
||||
|
||||
export type {
|
||||
APIResponse,
|
||||
VideoMetadata
|
||||
VideoMetadata,
|
||||
User
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.ddf.vodsystem.configuration;
|
||||
|
||||
import com.ddf.vodsystem.security.CustomOAuth2UserService;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -46,4 +47,4 @@ public class SecurityConfig {
|
||||
return (request, response, authentication) -> response.sendRedirect(frontendUrl);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
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.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -13,7 +16,21 @@ import java.util.Map;
|
||||
public class AuthController {
|
||||
|
||||
@GetMapping("/user")
|
||||
public Map<String, Object> user(@AuthenticationPrincipal OAuth2User principal) {
|
||||
return principal.getAttributes();
|
||||
public ResponseEntity<APIResponse<Map<String, Object>>> user(@AuthenticationPrincipal OAuth2User principal) {
|
||||
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"))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.ddf.vodsystem.configuration;
|
||||
package com.ddf.vodsystem.security;
|
||||
import com.ddf.vodsystem.entities.User;
|
||||
import com.ddf.vodsystem.repositories.UserRepository;
|
||||
|
||||
Reference in New Issue
Block a user