| /> | /> | ||||
| <Route path="api/auth/:provider/callback" element={<AuthCallback />} /> | <Route path="api/auth/:provider/callback" element={<AuthCallback />} /> | ||||
| <Route element={<RequireAuth />} errorElement={<Error />}> | <Route element={<RequireAuth />} errorElement={<Error />}> | ||||
| <Route path={PAGES.HOME.route} element={<HomePage />} /> | |||||
| <Route path={PAGES.BASE.route} element={<HomePage />} /> | <Route path={PAGES.BASE.route} element={<HomePage />} /> | ||||
| <Route path="/profile/*" element={<ProfilePage />} /> | <Route path="/profile/*" element={<ProfilePage />} /> | ||||
| <Route path="settings" element={<SettingsPage />} /> | <Route path="settings" element={<SettingsPage />} /> |
| import { HeaderContainer } from "./Header.styled"; | import { HeaderContainer } from "./Header.styled"; | ||||
| import { useSelector } from "react-redux"; | import { useSelector } from "react-redux"; | ||||
| import { selectBreadcrumbs } from "features/app/appSlice"; | import { selectBreadcrumbs } from "features/app/appSlice"; | ||||
| import { selectCurrentUser } from "features/auth/authSlice"; | |||||
| import HeaderNavigation from "./HeaderNavigation/HeaderNavigation"; | |||||
| const Header = () => { | const Header = () => { | ||||
| const breadcrumbs = useSelector(selectBreadcrumbs); | const breadcrumbs = useSelector(selectBreadcrumbs); | ||||
| console.log(breadcrumbs) | |||||
| const user = useSelector(selectCurrentUser); | |||||
| console.log(user); | |||||
| console.log(breadcrumbs); | |||||
| return ( | return ( | ||||
| <HeaderContainer> | <HeaderContainer> | ||||
| <div>nesto</div> | |||||
| <HeaderNavigation /> | |||||
| <div>brate</div> | <div>brate</div> | ||||
| </HeaderContainer> | </HeaderContainer> | ||||
| ); | ); |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { headerNavigationConstants } from "constants/navigationConstants"; | |||||
| import { HeaderNavigationContainer } from "./HeaderNavigation.styled"; | |||||
| import HeaderNavigationItem from "./HeaderNavigationItem/HeaderNavigationItem"; | |||||
| const HeaderNavigation = () => { | |||||
| return ( | |||||
| <HeaderNavigationContainer> | |||||
| {headerNavigationConstants.map?.((singleNavigationItem, index) => ( | |||||
| <HeaderNavigationItem | |||||
| key={index} | |||||
| route={singleNavigationItem} | |||||
| /> | |||||
| ))} | |||||
| </HeaderNavigationContainer> | |||||
| ); | |||||
| }; | |||||
| HeaderNavigation.propTypes = { | |||||
| children: PropTypes.node, | |||||
| }; | |||||
| export default HeaderNavigation; |
| flex-direction: row; | flex-direction: row; | ||||
| align-items: center; | align-items: center; | ||||
| gap: 16px; | gap: 16px; | ||||
| height: 100%; | |||||
| ` | ` |
| import React from "react"; | |||||
| import React, { useMemo } from "react"; | |||||
| import PropTypes from "prop-types"; | import PropTypes from "prop-types"; | ||||
| import { | import { | ||||
| HeaderNavigationItemContainer, | HeaderNavigationItemContainer, | ||||
| } from "./HeaderNavigationItem.styled"; | } from "./HeaderNavigationItem.styled"; | ||||
| const HeaderNavigationItem = (props) => { | const HeaderNavigationItem = (props) => { | ||||
| const singleRoutePath = useMemo(() => { | |||||
| const pathArray = props?.route?.route?.split("/"); | |||||
| if (pathArray?.[pathArray?.length - 1] === "*") | |||||
| pathArray.splice(pathArray?.length - 1, 1); | |||||
| return pathArray.join("/"); | |||||
| }, [props?.route]); | |||||
| return ( | return ( | ||||
| <HeaderNavigationItemContainer> | |||||
| <HeaderNavigationItemContainer | |||||
| {...props} | |||||
| to={singleRoutePath} | |||||
| > | |||||
| {props?.route?.icon && ( | {props?.route?.icon && ( | ||||
| <HeaderNavigationItemIconContainer> | <HeaderNavigationItemIconContainer> | ||||
| {props?.route?.icon} | {props?.route?.icon} | ||||
| icon: PropTypes.oneOfType([PropTypes.node, PropTypes.element]), | icon: PropTypes.oneOfType([PropTypes.node, PropTypes.element]), | ||||
| title: PropTypes.string, | title: PropTypes.string, | ||||
| subroutes: PropTypes.array, | subroutes: PropTypes.array, | ||||
| route: PropTypes.string, | |||||
| }), | }), | ||||
| }; | }; | ||||
| import { Box } from "@mui/material"; | import { Box } from "@mui/material"; | ||||
| import { NavLink } from "react-router-dom"; | |||||
| import styled from "styled-components"; | import styled from "styled-components"; | ||||
| import selectedTheme from "themes"; | |||||
| export const HeaderNavigationItemContainer = styled(Box)` | |||||
| export const HeaderNavigationItemContainer = styled(NavLink)` | |||||
| display: flex; | display: flex; | ||||
| justify-content: center; | justify-content: center; | ||||
| text-decoration: none; | |||||
| align-items: center; | align-items: center; | ||||
| width: fit-content; | width: fit-content; | ||||
| padding: 2px 6px; | padding: 2px 6px; | ||||
| cursor: pointer; | |||||
| height: 100%; | |||||
| transition-duration: 0.1s; | |||||
| &:hover { | |||||
| background-color: ${selectedTheme.colors.primaryLightLighter}; | |||||
| } | |||||
| &[aria-checked=true] ${HeaderNavigationItemIconTitle} { | |||||
| font-weight: 700; | |||||
| } | |||||
| `; | `; | ||||
| export const HeaderNavigationItemIconContainer = styled(Box)``; | export const HeaderNavigationItemIconContainer = styled(Box)``; | ||||
| export const HeaderNavigationItemIconTitle = styled(Box)` | export const HeaderNavigationItemIconTitle = styled(Box)` | ||||
| font-size: 14px; | font-size: 14px; | ||||
| line-height: 20px; | line-height: 20px; | ||||
| font-weight: ${(props) => props?.$isActive && 600}; | font-weight: ${(props) => props?.$isActive && 600}; | ||||
| color: white; | |||||
| font-weight: 500; | |||||
| `; | `; |
| import { PAGES } from "./pages"; | |||||
| export const headerNavigationConstants = [ | |||||
| PAGES.HOME, | |||||
| PAGES.PROFILE, | |||||
| PAGES.SETTINGS, | |||||
| ]; |
| route: "/profile", | route: "/profile", | ||||
| title: i18n.t("pages.profile"), | title: i18n.t("pages.profile"), | ||||
| }, | }, | ||||
| SETTINGS: { | |||||
| route: "/settings", | |||||
| title: i18n.t("pages.settings"), | |||||
| }, | |||||
| }; | }; |
| import { createSlice } from "@reduxjs/toolkit"; | import { createSlice } from "@reduxjs/toolkit"; | ||||
| import { createSelector } from "reselect"; | |||||
| const authSlice = createSlice({ | const authSlice = createSlice({ | ||||
| name: "auth", | name: "auth", | ||||
| export const { setCredetnials, logOut } = authSlice.actions; | export const { setCredetnials, logOut } = authSlice.actions; | ||||
| export default authSlice.reducer; | export default authSlice.reducer; | ||||
| export const selectCurrentUser = (state) => state.auth.user; | |||||
| export const selectCurrentToken = (state) => state.auth.token; | |||||
| export const authSelector = (state) => state.auth; | |||||
| export const selectCurrentUser = createSelector( | |||||
| authSelector, | |||||
| (state) => state.user | |||||
| ); | |||||
| export const selectCurrentToken = createSelector( | |||||
| authSelector, | |||||
| (state) => state.token | |||||
| ); |
| error: "Pogrešna stranica", | error: "Pogrešna stranica", | ||||
| notFound: "Nije pronađena stranica", | notFound: "Nije pronađena stranica", | ||||
| profile: "Profilna stranica", | profile: "Profilna stranica", | ||||
| settings: "Podešavanja", | |||||
| }, | }, | ||||
| register: { | register: { | ||||
| registerTitle: "Register", | registerTitle: "Register", |
| export const primaryThemeColors = { | export const primaryThemeColors = { | ||||
| primaryLight: "#673ab7", | primaryLight: "#673ab7", | ||||
| primaryLightLighter: "#845ccb", | |||||
| primaryDark: "#009688", | primaryDark: "#009688", | ||||
| secondaryLight: "#212121", | secondaryLight: "#212121", | ||||
| secondaryDark: "#f5f5f5", | secondaryDark: "#f5f5f5", |