From 413896c54b53d8ed019e60f29f9738cba9ffc08e Mon Sep 17 00:00:00 2001 From: hzhang Date: Wed, 4 Dec 2024 16:53:35 +0000 Subject: [PATCH] markdown editor --- src/App.js | 7 +- src/AuthProvider.js | 44 +++++---- src/components/Markdowns/MarkdownEditor.js | 97 +++++++++++++++++++ .../{ => Navigations}/MainNavigation.css | 0 .../{ => Navigations}/MainNavigation.js | 2 +- .../{ => Navigations}/SideNavigation.css | 0 .../{ => Navigations}/SideNavigation.js | 11 ++- src/components/PermissionGuard.js | 15 +++ src/confs/appConfig.js | 3 +- 9 files changed, 155 insertions(+), 24 deletions(-) create mode 100644 src/components/Markdowns/MarkdownEditor.js rename src/components/{ => Navigations}/MainNavigation.css (100%) rename src/components/{ => Navigations}/MainNavigation.js (96%) rename src/components/{ => Navigations}/SideNavigation.css (100%) rename src/components/{ => Navigations}/SideNavigation.js (84%) create mode 100644 src/components/PermissionGuard.js diff --git a/src/App.js b/src/App.js index 005815d..575ffff 100644 --- a/src/App.js +++ b/src/App.js @@ -1,8 +1,9 @@ import React from "react"; import { BrowserRouter as Router, Route, Routes } from "react-router-dom"; -import MainNavigation from "./components/MainNavigation"; -import SideNavigation from "./components/SideNavigation"; +import MainNavigation from "./components/Navigations/MainNavigation"; +import SideNavigation from "./components/Navigations/SideNavigation"; import MarkdownContent from "./components/MarkdownContent"; +import MarkdownEditor from "./components/Markdowns/MarkdownEditor"; import "./App.css"; import Callback from "./Callback"; import {config} from "./confs/appConfig"; @@ -20,6 +21,8 @@ const App = () => { } /> } /> TEST}> + }> + }> diff --git a/src/AuthProvider.js b/src/AuthProvider.js index dce3ca0..d44367f 100644 --- a/src/AuthProvider.js +++ b/src/AuthProvider.js @@ -7,33 +7,43 @@ export const AuthContext = createContext({ user: null, login: () => {}, logout: () => {}, + roles: [], }); const AuthProvider = ({ children }) => { const [user, setUser] = useState(null); + const [roles, setRoles] = useState([]); const userManager = new UserManager(appConfig.oidcConfig); useEffect(() => { userManager.getUser() .then((user) => { - if (user && !user.expired) { - setUser(user); - localStorage.setItem("accessToken", user.access_token); - } else if (user && user.expired) { - userManager.signinSilent() - .then((newUser) => { - setUser(newUser); - localStorage.setItem("accessToken", newUser.access_token); - }) - .catch((err) => { - console.error(err); - }) - } - }); - }, [userManager]); + if (user && !user.expired) { + setUser(user); + localStorage.setItem("accessToken", user.access_token); + const clientRoles = user?.profile?.resource_access?.[appConfig.kc_client_id]?.roles || []; + setRoles(clientRoles); + } else if (user && user.expired) { + userManager.signinSilent() + .then((newUser) => { + setUser(newUser); + localStorage.setItem("accessToken", newUser.access_token); + const clientRoles = + newUser?.profile?.resource_access?.[appConfig.kc_client_id]?.roles || []; + setRoles(clientRoles); + }) + .catch((err) => { + console.error(err); + }) + } + }); + }, [userManager]); const login = () => { - userManager.signinRedirect().catch((err) => { + userManager + .signinRedirect() + .catch( + (err) => { console.log(appConfig); console.log(err); }); @@ -41,7 +51,7 @@ const AuthProvider = ({ children }) => { const logout = () => userManager.signoutRedirect(); return ( - + {children} ); diff --git a/src/components/Markdowns/MarkdownEditor.js b/src/components/Markdowns/MarkdownEditor.js new file mode 100644 index 0000000..3fa9c64 --- /dev/null +++ b/src/components/Markdowns/MarkdownEditor.js @@ -0,0 +1,97 @@ +import React, {useContext, useEffect, useState} from "react"; +import {AuthContext} from "../../AuthProvider"; +import {useNavigate, useParams} from "react-router-dom"; +import {fetchWithCache} from "../../utils/fetchWithCache"; + +const MarkdownEditor = () => { + const {roles} = useContext(AuthContext); + const navigate = useNavigate(); + const {id} = useParams() + const [title, setTitle] = useState(""); + const [content, setContent] = useState(""); + const [path, setPath] = useState(""); + + useEffect(() => { + if(id){ + fetchWithCache(`/api/markdown/${id}`) + .then((data) => { + setTitle(data.title); + setContent(data.content); + setPath(data.path); + }) + .catch((err) => {console.error("failed to load markdown", err)}); + } + }, [id]); + + const handleSave = () => { + const url = id ? `/api/markdown/${id}` : "/api/markdown"; + const method = id ? "PUT" : "POST"; + fetch (url, { + method, + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${localStorage.getItem("accessToken")}`, + }, + body: JSON.stringify({title, content, path}), + }) + .then((res) => { + if (res.ok) { + navigate("/"); + }else { + return res.json().then((data) => { + throw new Error(data.error || "Failed to save markdown"); + }) + } + }) + .catch((err) => {console.error("failed to load markdown", err)}); + }; + + const hasPermission = roles.includes("admin") || roles.includes("creator"); + if(! hasPermission) + return ( +
Can not crete(Permission Denied)
+ ); + return ( +
+

{id ? "Edit Markdown" : "Create Markdown"}

+
+
+ +
+
+ +
+
+