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 { 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>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
};
|
};
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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"))
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
Reference in New Issue
Block a user