diff --git a/src/blog/Blog.tsx b/src/blog/Blog.tsx index f04840c..7b14258 100644 --- a/src/blog/Blog.tsx +++ b/src/blog/Blog.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { useEffect } from 'react'; import CssBaseline from '@mui/material/CssBaseline'; import Container from '@mui/material/Container'; import Box from '@mui/material/Box'; @@ -15,10 +16,17 @@ import Profile from './components/Profile'; import { useArticles } from './providers/Article'; import { useAuth } from './providers/Author'; import { View, useViewRouter } from "./types/views"; -import { ArticlesModel } from "./types/models"; +import { ArticleModel, ArticlesModel } from "./types/models"; import { ArticleViewProps, ArticleEditorProps } from "./types/props"; -function HomeView({ currentUser, open_login, open_profile, open_create, articles, openArticle }: any) { +function HomeView({ + currentUser, + open_login, + open_profile, + open_create, + articles, + openArticle +}: any) { return ( <> @@ -47,10 +55,29 @@ export default function Blog(props: { disableCustomTheme?: boolean }) { const { currentUser } = useAuth(); const [ui, setUI] = React.useState({ - selectedArticle: null as number | null, + selectedArticle: null as ArticleModel | null, view: "home" as View, }); + useEffect(() => { + if (loading) return; + + const path = window.location.pathname; + const parts = path.split('/').filter(Boolean); + + if (parts[0] === 'articles' && parts[1]) { + const id = parts[1]; + const article = articles.readById(id); + + if (article) { + setUI({ + selectedArticle: article, + view: 'article', + }); + } + } + }, [loading]); + const { goBack, navigateToChildren, @@ -61,7 +88,7 @@ export default function Blog(props: { disableCustomTheme?: boolean }) { ui: any; articles: ArticlesModel; currentUser: any; - openArticle: (index: number) => void; + openArticle: (article: ArticleModel) => void; }; type ViewComponentEntry

= { diff --git a/src/blog/types/views.ts b/src/blog/types/views.ts index ded0e8c..cb0d394 100644 --- a/src/blog/types/views.ts +++ b/src/blog/types/views.ts @@ -1,3 +1,5 @@ +import {ArticleModel} from "./models"; + export type View = | "home" | "login" @@ -39,9 +41,31 @@ export const VIEW_TREE: Record = { }, }; +export const VIEW_URL: Record string> = { + home: () => "/", + login: () => "/login", + register: () => "/register", + profile: () => "/profile", + create: () => "/create", + article: (ui) => `/articles/${ui.selectedArticle._id ?? ""}`, + editor: (ui) => `/articles/${ui.selectedArticle._id ?? ""}/edit`, +}; + export function useViewRouter(setUI: any) { - const navigate = (view: View) => { - setUI((prev: any) => ({ ...prev, view })); + const navigate = ( + view: View, + nextState?: any + ) => { + setUI((prev: any) => { + const newState = { ...prev, ...nextState, view }; + + // update URL + const url = VIEW_URL[view](newState); + window.history.pushState(newState, "", url); + + return newState; + }); + window.scrollTo({ top: 0, behavior: "smooth" }); }; @@ -51,8 +75,19 @@ export function useViewRouter(setUI: any) { if (parent) navigate(parent); }; - const openArticle = (i: number) => { - setUI({ selectedArticle: i, view: "article" }); + const openArticle = (article: ArticleModel) => { + setUI((prev: any) => { + const newState = { + ...prev, + selectedArticle: article, + view: "article", + }; + + const url = `/articles/${article._id}`; + window.history.pushState(newState, "", url); + + return newState; + }); window.scrollTo({ top: 0, behavior: "smooth" }); };