Skip to content

Commit

Permalink
Feat/admin-dropdown (#107)
Browse files Browse the repository at this point in the history
  • Loading branch information
Akzuu authored Jan 27, 2025
1 parent 04a2ecd commit cdf59bc
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 14 deletions.
2 changes: 1 addition & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const Content: React.FC = () => {
</Route>

{/* Admin only views */}
<Route element={<PrivateContent adminOnly />}>
<Route path="admin" element={<PrivateContent adminOnly />}>
<Route path="invoice" element={<InvoicePage />} />
</Route>

Expand Down
57 changes: 57 additions & 0 deletions src/components/Navbar/AdminDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { useCallback, useRef, useState, type PropsWithChildren } from 'react';
import { ButtonType } from '../common/Button/Buttons';
import styles from './Navbar.module.scss';
import { useMatch, useResolvedPath } from 'react-router-dom';

type AdminDropdownButtonProps = PropsWithChildren & {
disabled?: boolean;
key?: string;
text: string;
};

export const AdminDropdown: React.FC<AdminDropdownButtonProps> = ({
children,
disabled,
key,
text,
}) => {
const resolvedPath = useResolvedPath('/admin/*');

const [isOpen, setIsOpen] = useState(false);
const isActive = !!useMatch({ path: resolvedPath.pathname });

const onDropdownButtonClick = useCallback(() => {
setIsOpen(!isOpen);
}, [isOpen]);

const dropdownRef = useRef<HTMLDivElement>(null);

const handleMouseLeave = useCallback(() => {
setIsOpen(false);
}, []);

return (
<div
className="dropdown show"
ref={dropdownRef}
onMouseLeave={handleMouseLeave}
>
<button
id={'dropdownMenuLink'}
className={`
${styles.dropdownButton} dropdown-toggle
${isActive ? styles.active : ''}
${isOpen ? styles.open : ''}
`}
disabled={disabled}
key={key}
onClick={onDropdownButtonClick}
type={ButtonType.button}
>
{text}
</button>

{isOpen && <div className={styles.dropdownMenu}>{children}</div>}
</div>
);
};
4 changes: 3 additions & 1 deletion src/components/Navbar/CustomLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ import { Link, useMatch, useResolvedPath } from 'react-router-dom';
import styles from './Navbar.module.scss';

export const CustomLink = ({
className,
to,
children,
...props
}: {
className?: string;
to: string;
children: string | JSX.Element;
}): JSX.Element => {
const resolvedPath = useResolvedPath(to);
const isActive = useMatch({ path: resolvedPath.pathname, end: true });

return (
<li className={isActive !== null ? styles.active : ''}>
<li className={`${isActive !== null ? styles.active : ''} ${className}`}>
<Link to={to} {...props}>
{children}
</Link>
Expand Down
65 changes: 63 additions & 2 deletions src/components/Navbar/Navbar.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ nav {
}

.active {
background: $white-smoke;
color: $black;
background: $white-smoke !important;
color: $black !important;

:hover {
color: $black;
Expand All @@ -78,6 +78,67 @@ nav {
align-self: center;
}

.dropdownButton {
align-items: center;
background-color: $blue;
border-radius: 0;
border: none;
color: $white;
display: flex;
position: relative;
flex-direction: row;
font-weight: 500;
font-family: roboto;
justify-content: center;
padding: 0.5rem 1rem;
height: 100%;

&:disabled {
background-color: $grey;
}

&:hover:not(.active) {
background-color: $blue-hover;
color: $white;
}

&.open {
background-color: $blue-hover;
}
}

.dropdownMenu {
background: $white-smoke;
border: 1px solid $grey;
border-top: none;
border-radius: 0 0 8px 8px;
color: $grey;
position: absolute;

li {
color: $black;
}

li:last-child {
border-radius: 0 0 8px 8px;
}

li:hover:not(.active) {
background-color: $blue-hover;
color: $white;

a {
color: inherit;
}
}
}

.dropdownLink {
&.active {
background-color: $timberwolf !important;
}
}

@media (max-width: 780px) {
nav {
a {
Expand Down
21 changes: 20 additions & 1 deletion src/components/Navbar/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { getUserRoles } from '../../lib/utils';
import styles from './Navbar.module.scss';
import { Navbar as BootNavbar, Container, Nav } from 'react-bootstrap';
import { CustomLink } from './CustomLink';
import { AdminDropdown } from './AdminDropdown';

export const Navbar: React.FC = () => {
const navigate = useNavigate();
Expand Down Expand Up @@ -44,7 +45,25 @@ export const Navbar: React.FC = () => {

<CustomLink to="/fill-events">Täyttöhistoria</CustomLink>

{isAdmin && <CustomLink to="/invoice">Laskutus</CustomLink>}
{isAdmin && (
<AdminDropdown text="Ylläpito">
<CustomLink
className={styles.dropdownLink}
to="/admin/invoice"
>
Laskutus
</CustomLink>
{/* <CustomLink className={styles.dropdownLink} to="/admin/users">
Käyttäjät
</CustomLink>
<CustomLink
className={styles.dropdownLink}
to="/admin/filling-history"
>
Täyttöhistoria
</CustomLink> */}
</AdminDropdown>
)}
</Nav>
<Nav>
<div className={styles.user}>
Expand Down
4 changes: 3 additions & 1 deletion src/components/common/Button/Buttons.module.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@import '../../../variables.scss';

// Tayttopaikka specific
$primaryBlue: #0d4d7b;
$primaryBlueHover: #1971b1;
Expand All @@ -10,7 +12,7 @@ $transparent: rgba(0, 0, 0, 0);
$grey: #c7c7cd;
$white: #ffffff;

#commonButton {
.commonButton {
align-items: center;
border-radius: 8px;
border: none;
Expand Down
21 changes: 13 additions & 8 deletions src/components/common/Button/Buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type CommonButtonProps = {
className?: string;
disabled?: boolean;
key?: string;
id?: string;
onClick?: React.MouseEventHandler;
type?: ButtonType;
};
Expand All @@ -29,6 +30,7 @@ export const ElementButton: React.FC<ElementButtonProps> = ({
disabled,
key,
element,
id,
onClick,
tooltip,
type = ButtonType.button,
Expand All @@ -41,11 +43,11 @@ export const ElementButton: React.FC<ElementButtonProps> = ({
return (
<>
<button
className={styles.elementButton}
className={`${styles.commonButton} ${styles.elementButton}`}
data-tooltip-id={tooltipId}
data-tooltip-content={tooltip}
disabled={disabled}
id={styles.commonButton}
id={id}
key={key}
onClick={onClick}
type={type}
Expand All @@ -61,12 +63,13 @@ export const PrimaryButton: React.FC<TextButtonProps> = ({
disabled,
key,
onClick,
id,
text,
type = ButtonType.button,
}) => (
<button
id={styles.commonButton}
className={styles.primaryButton}
id={id}
className={`${styles.commonButton} ${styles.primaryButton}`}
disabled={disabled}
key={key}
onClick={onClick}
Expand All @@ -80,12 +83,13 @@ export const SecondaryButton: React.FC<TextButtonProps> = ({
disabled,
key,
onClick,
id,
text,
type = ButtonType.button,
}) => (
<button
id={styles.commonButton}
className={styles.secondaryButton}
id={id}
className={`${styles.commonButton} ${styles.secondaryButton}`}
disabled={disabled}
key={key}
onClick={onClick}
Expand All @@ -99,12 +103,13 @@ export const TertiaryButton: React.FC<TextButtonProps> = ({
disabled,
key,
onClick,
id,
text,
type = ButtonType.button,
}) => (
<button
id={styles.commonButton}
className={styles.tertiaryButton}
id={id}
className={`${styles.commonButton} ${styles.tertiaryButton}`}
disabled={disabled}
key={key}
onClick={onClick}
Expand Down

0 comments on commit cdf59bc

Please sign in to comment.