diff --git a/client/src/app/loginSlice.ts b/client/src/app/loginSlice.ts
index 35b5d6b..0d2285e 100644
--- a/client/src/app/loginSlice.ts
+++ b/client/src/app/loginSlice.ts
@@ -5,9 +5,9 @@ import {
AuthSignupPostRequest,
AuthenticationApi,
Configuration,
+ UsersApi,
} from "../api";
import { AppThunk } from "./store";
-import { Axios, AxiosError } from "axios";
interface loginState {
loggedIn: boolean;
@@ -15,6 +15,7 @@ interface loginState {
error: string | null;
userInfo: {
firstName: string;
+ lastName: string;
jwt: string;
};
}
@@ -25,6 +26,7 @@ const initialState: loginState = {
error: null,
userInfo: {
firstName: "",
+ lastName: "",
jwt: "",
},
};
@@ -35,7 +37,9 @@ export const loginSlice = createSlice({
reducers: {
login: (state, action) => {
state.loggedIn = true;
- state.userInfo.jwt = action.payload;
+ state.userInfo.jwt = action.payload.jwt;
+ state.userInfo.firstName = action.payload.firstName;
+ state.userInfo.lastName = action.payload.lastName;
},
logoff: (state) => {
state.loggedIn = false;
@@ -50,7 +54,7 @@ export const loginSlice = createSlice({
},
});
-const api = new AuthenticationApi(
+const authApi = new AuthenticationApi(
new Configuration({
basePath: process.env.REACT_APP_BACKEND_URL,
})
@@ -59,15 +63,30 @@ const api = new AuthenticationApi(
export const postLogin =
(params: AuthLoginPostRequest): AppThunk =>
async (dispatch) => {
- let response;
+ let response, userResponse;
try {
dispatch(setStatus(Status.loading));
- response = await api.authLoginPost(params);
+ response = await authApi.authLoginPost(params);
- dispatch(login(response.data.token));
await addJWT(response.data.token || "");
- dispatch(setError(""));
+ // Get user info
+ const userApi = new UsersApi(
+ new Configuration({
+ basePath: process.env.REACT_APP_BACKEND_URL,
+ accessToken: response.data.token,
+ })
+ );
+
+ userResponse = await userApi.usersMeGet();
+
+ dispatch(
+ login({
+ jwt: response.data.token,
+ firstName: userResponse.data.firstName,
+ lastName: userResponse.data.lastName,
+ })
+ );
dispatch(setStatus(Status.succeeded));
} catch (error) {
dispatch(setStatus(Status.failed));
@@ -83,7 +102,7 @@ export const postSignup =
console.log(params);
try {
dispatch(setStatus(Status.loading));
- response = await api.authSignupPost(params);
+ response = await authApi.authSignupPost(params);
dispatch(postLogin({ email: params.email, password: params.password }));
} catch (error) {
@@ -97,7 +116,7 @@ export const postLogout = (): AppThunk => async (dispatch) => {
localStorage.removeItem("jwt");
sessionStorage.removeItem("jwt");
dispatch(logoff());
- await api.authLogoutGet();
+ await authApi.authLogoutGet();
};
const addJWT = async (token: string) => {
diff --git a/client/src/app/postSlice.ts b/client/src/app/postSlice.ts
new file mode 100644
index 0000000..b3cb600
--- /dev/null
+++ b/client/src/app/postSlice.ts
@@ -0,0 +1,68 @@
+import { Store, createSlice } from "@reduxjs/toolkit";
+import { Configuration, Post, PostsApi } from "../api";
+import { Status } from "../util/types";
+import { store } from "./store";
+
+interface postSlice {
+ status: Status;
+ followedPosts: Post[];
+ globalPosts: Post[];
+}
+
+const initialState: postSlice = {
+ status: Status.idle,
+ followedPosts: [],
+ globalPosts: [],
+};
+
+export const postSlice = createSlice({
+ name: "post",
+ initialState,
+ reducers: {
+ setStatus: (state, action) => {
+ state.status = action.payload;
+ },
+ setFollowedPosts: (state, action) => {
+ state.followedPosts = action.payload;
+ },
+ setGlobalPosts: (state, action) => {
+ state.globalPosts = action.payload;
+ },
+ },
+});
+
+export const fetchFollowedPosts = () => async (dispatch: any) => {
+ const postApi = createApi(store);
+
+ dispatch(setStatus(Status.loading));
+ const response = await postApi.getFollowedPosts();
+ dispatch(setFollowedPosts(response.data));
+ dispatch(setStatus(Status.idle));
+};
+
+export const fetchGlobalPosts = () => async (dispatch: any) => {
+ const postApi = createApi(store);
+
+ dispatch(setStatus(Status.loading));
+ const response = await postApi.getAllPosts();
+ dispatch(setGlobalPosts(response.data));
+ dispatch(setStatus(Status.idle));
+};
+
+export const { setFollowedPosts, setGlobalPosts, setStatus } =
+ postSlice.actions;
+
+export default postSlice.reducer;
+
+export const selectFollowedPosts = (state: any) => state.post.followedPosts;
+export const selectAllPosts = (state: any) => state.post.globalPosts;
+export const selectStatus = (state: any) => state.post.status;
+
+function createApi(store: Store) {
+ return new PostsApi(
+ new Configuration({
+ basePath: process.env.REACT_APP_BACKEND_URL,
+ accessToken: store.getState().login.userInfo.jwt,
+ })
+ );
+}
diff --git a/client/src/app/store.ts b/client/src/app/store.ts
index 68ccd64..089d197 100644
--- a/client/src/app/store.ts
+++ b/client/src/app/store.ts
@@ -1,10 +1,12 @@
import { Action, ThunkAction, configureStore } from "@reduxjs/toolkit";
import { useDispatch } from "react-redux";
import loginReducer from "./loginSlice";
+import postReducer from "./postSlice";
export const store = configureStore({
reducer: {
login: loginReducer,
+ post: postReducer,
},
});
diff --git a/client/src/components/bottomAppBar.tsx b/client/src/components/bottomAppBar.tsx
index 101898f..a94ff78 100644
--- a/client/src/components/bottomAppBar.tsx
+++ b/client/src/components/bottomAppBar.tsx
@@ -4,10 +4,15 @@ import FeedIcon from "@mui/icons-material/Feed";
import GlobalIcon from "@mui/icons-material/Public";
import AddIcon from "@mui/icons-material/Add";
import SearchIcon from "@mui/icons-material/Search";
+import { useNavigate } from "react-router-dom";
export default function BottomAppBar() {
const [value, setValue] = useState(0);
+ const navigate = useNavigate();
+ const handleClick = (to: string) => () => {
+ navigate(to);
+ };
return (
- } />
- } />
- } />
- } />
+ }
+ onClick={handleClick("feed")}
+ />
+ }
+ onClick={handleClick("global")}
+ />
+ }
+ onClick={handleClick("newpost")}
+ />
+ }
+ onClick={handleClick("search")}
+ />
);
diff --git a/client/src/components/postListItem.tsx b/client/src/components/postListItem.tsx
new file mode 100644
index 0000000..1e77f2c
--- /dev/null
+++ b/client/src/components/postListItem.tsx
@@ -0,0 +1,19 @@
+import { ListItem, ListItemText } from "@mui/material";
+import { Post } from "../api";
+
+interface PostListItemProps {
+ post: Post;
+}
+
+export default function PostListItem(props: PostListItemProps) {
+ console.log(props.post);
+
+ return (
+
+
+
+ );
+}
diff --git a/client/src/components/sideAppBar.tsx b/client/src/components/sideAppBar.tsx
index a9c82d6..9b095cc 100644
--- a/client/src/components/sideAppBar.tsx
+++ b/client/src/components/sideAppBar.tsx
@@ -13,6 +13,7 @@ import FeedIcon from "@mui/icons-material/Feed";
import GlobalIcon from "@mui/icons-material/Public";
import AddIcon from "@mui/icons-material/Add";
import SearchIcon from "@mui/icons-material/Search";
+import { Link, useNavigate } from "react-router-dom";
export interface SideAppBarProps {
drawerWidth: number;
@@ -20,6 +21,12 @@ export interface SideAppBarProps {
export default function SideAppBar(props: SideAppBarProps) {
const { drawerWidth } = props;
+ const navigate = useNavigate();
+
+ const handleClick = (to: string) => () => {
+ navigate(to);
+ };
+
return (
-
+
@@ -46,7 +53,11 @@ export default function SideAppBar(props: SideAppBarProps) {
-
+
@@ -55,7 +66,11 @@ export default function SideAppBar(props: SideAppBarProps) {
-
+
@@ -64,7 +79,7 @@ export default function SideAppBar(props: SideAppBarProps) {
-
+
@@ -72,7 +87,6 @@ export default function SideAppBar(props: SideAppBarProps) {
-
);
diff --git a/client/src/components/topAppBar.tsx b/client/src/components/topAppBar.tsx
index 02eff6b..4d13a55 100644
--- a/client/src/components/topAppBar.tsx
+++ b/client/src/components/topAppBar.tsx
@@ -11,18 +11,21 @@ import Tooltip from "@mui/material/Tooltip";
import MenuItem from "@mui/material/MenuItem";
import NotificationBell from "./notificationBell";
import {useSelector} from "react-redux";
-import {selectUserInfo} from "../app/loginSlice";
+import { postLogout, selectUserInfo } from "../app/loginSlice";
+import { useAppDispatch } from "../app/store";
+import { useNavigate } from "react-router-dom";
const settings = ["Profile", "Account", "Dashboard", "Logout"];
function TopAppBar() {
-
- const userInfo = useSelector(selectUserInfo);
- const [anchorElUser, setAnchorElUser] = React.useState(
+ const dispatch = useAppDispatch();
+ const navigate = useNavigate();
+ const userInfo = useSelector(selectUserInfo);
+ const [anchorElUser, setAnchorElUser] = React.useState(
null
);
- console.log(userInfo)
+ console.log(userInfo);
const handleOpenUserMenu = (event: React.MouseEvent) => {
setAnchorElUser(event.currentTarget);
@@ -32,6 +35,11 @@ function TopAppBar() {
setAnchorElUser(null);
};
+ const handleLogout = () => {
+ dispatch(postLogout());
+ setAnchorElUser(null);
+ };
+
return (
@@ -67,7 +75,10 @@ function TopAppBar() {
-
+
diff --git a/client/src/index.tsx b/client/src/index.tsx
index 13737ff..1d23b5f 100644
--- a/client/src/index.tsx
+++ b/client/src/index.tsx
@@ -12,6 +12,11 @@ import Register from "./routes/Auth/register";
import AuthRoot from "./routes/Auth/authRoot";
import { Provider } from "react-redux";
import { store } from "./app/store";
+import PostList from "./routes/postList";
+import Profile from "./routes/profile";
+import Post from "./routes/post";
+import NewPost from "./routes/newPost";
+import Search from "./routes/search";
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
@@ -28,6 +33,36 @@ const router = createBrowserRouter([
path: "/",
element: ,
errorElement: ,
+ children: [
+ {
+ path: "feed",
+ element: ,
+ },
+ {
+ path: "global",
+ element: ,
+ },
+ {
+ path: "me",
+ element: ,
+ },
+ {
+ path: "user/:id",
+ element: ,
+ },
+ {
+ path: "post/:id",
+ element: ,
+ },
+ {
+ path: "search",
+ element: ,
+ },
+ {
+ path: "newpost",
+ element: ,
+ },
+ ],
},
{
path: "/auth",
diff --git a/client/src/routes/newPost.tsx b/client/src/routes/newPost.tsx
new file mode 100644
index 0000000..46ac5ce
--- /dev/null
+++ b/client/src/routes/newPost.tsx
@@ -0,0 +1,3 @@
+export default function NewPost() {
+ return <>New Post>;
+}
diff --git a/client/src/routes/notification.tsx b/client/src/routes/notification.tsx
new file mode 100644
index 0000000..9e98dfc
--- /dev/null
+++ b/client/src/routes/notification.tsx
@@ -0,0 +1,3 @@
+export default function Notification() {
+ return <>Notification>;
+}
diff --git a/client/src/routes/post.tsx b/client/src/routes/post.tsx
new file mode 100644
index 0000000..b0a457c
--- /dev/null
+++ b/client/src/routes/post.tsx
@@ -0,0 +1,3 @@
+export default function Post() {
+ return <>Post>;
+}
diff --git a/client/src/routes/postList.tsx b/client/src/routes/postList.tsx
new file mode 100644
index 0000000..a6f98dc
--- /dev/null
+++ b/client/src/routes/postList.tsx
@@ -0,0 +1,41 @@
+import { useSelector } from "react-redux";
+import {
+ fetchFollowedPosts,
+ fetchGlobalPosts,
+ selectAllPosts,
+ selectFollowedPosts,
+} from "../app/postSlice";
+import { store, useAppDispatch } from "../app/store";
+import { useEffect } from "react";
+import { List, ListItem, ListItemText } from "@mui/material";
+import { Post } from "../api";
+import PostListItem from "../components/postListItem";
+
+interface PostListProps {
+ type: "all" | "user";
+}
+
+export default function PostList(props: PostListProps) {
+ const dispatch = useAppDispatch();
+ const followedPosts = useSelector(selectFollowedPosts);
+ const globalPosts = useSelector(selectAllPosts);
+
+ useEffect(() => {
+ if (props.type === "all") dispatch(fetchGlobalPosts());
+ if (props.type === "user") dispatch(fetchFollowedPosts());
+ }, []);
+
+ console.log(globalPosts);
+ return (
+ <>
+ {props.type === "all" && (
+
+ {globalPosts.map((post: Post) => (
+
+ ))}
+
+ )}
+ {props.type === "user" &&
}
+ >
+ );
+}
diff --git a/client/src/routes/profile.tsx b/client/src/routes/profile.tsx
new file mode 100644
index 0000000..ba4f76f
--- /dev/null
+++ b/client/src/routes/profile.tsx
@@ -0,0 +1,12 @@
+import { useParams } from "react-router-dom";
+
+export interface ProfileProps {
+ selfProfile?: boolean;
+}
+
+export default function Profile(props: ProfileProps) {
+ const { selfProfile } = props;
+ const userId = useParams<{ userId: string }>().userId;
+
+ return <>Profile>;
+}
diff --git a/client/src/routes/search.tsx b/client/src/routes/search.tsx
new file mode 100644
index 0000000..935588d
--- /dev/null
+++ b/client/src/routes/search.tsx
@@ -0,0 +1,3 @@
+export default function Search() {
+ return <>Search>;
+}