Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions react_fe/src/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ReactNode, useEffect, useRef, useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import { useAuth } from "../context/AuthContext";
import { PermissionRole } from "../models/dto/PermissionsDto";
import ThemeToggleButton from "./ThemeToggleButton";

interface NavItem {
label: string;
Expand Down Expand Up @@ -80,6 +81,7 @@ function Navbar({ children }: { children: ReactNode }) {
</div>
)}
</div>
<ThemeToggleButton />
<button className="navbar-logout" onClick={logout}>Logout</button>
</div>
</nav>
Expand Down
39 changes: 39 additions & 0 deletions react_fe/src/components/ThemeToggleButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useEffect, useState } from 'react';
import { LocalStorageNames } from '../constants/LocalStorageNames';

function ThemeToggleButton() {
const [darkMode, setDarkMode] = useState<boolean>(() => {
return localStorage.getItem(LocalStorageNames.THEME) === 'dark';
});

useEffect(() => {
const theme = darkMode ? 'dark' : 'light';
if (darkMode) {
localStorage.setItem(LocalStorageNames.THEME, theme);
} else {
localStorage.removeItem(LocalStorageNames.THEME);
}
document.documentElement.setAttribute('data-theme', theme);
}, [darkMode]);

return (
<button
className="navbar-theme-toggle"
onClick={() => setDarkMode(d => !d)}
aria-label={darkMode ? 'Switch to light mode' : 'Switch to dark mode'}
>
{darkMode ? (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="12" r="4"/>
<path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/>
</svg>
) : (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/>
</svg>
)}
</button>
);
}

export default ThemeToggleButton;
1 change: 1 addition & 0 deletions react_fe/src/constants/LocalStorageNames.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export class LocalStorageNames {
static readonly REFRESH_TOKEN = 'refreshToken';
static readonly CHOSEN_TENANT_ID = 'chosenTenantId';
static readonly THEME = 'theme';
}
56 changes: 38 additions & 18 deletions react_fe/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

font: 18px/145% var(--sans);
letter-spacing: 0.18px;
color-scheme: light dark;
color-scheme: light;
color: var(--text);
background: var(--bg);
font-synthesis: none;
Expand All @@ -30,24 +30,23 @@
}
}

@media (prefers-color-scheme: dark) {
:root {
--text: #9ca3af;
--text-h: #f3f4f6;
--bg: #16171d;
--border: #2e303a;
--code-bg: #1f2028;
--accent: #c084fc;
--accent-bg: rgba(192, 132, 252, 0.15);
--accent-border: rgba(192, 132, 252, 0.5);
--social-bg: rgba(47, 48, 58, 0.5);
--shadow:
rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px;
}
[data-theme="dark"] {
color-scheme: dark;
--text: #9ca3af;
--text-h: #f3f4f6;
--bg: #16171d;
--border: #2e303a;
--code-bg: #1f2028;
--accent: #c084fc;
--accent-bg: rgba(192, 132, 252, 0.15);
--accent-border: rgba(192, 132, 252, 0.5);
--social-bg: rgba(47, 48, 58, 0.5);
--shadow:
rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px;
}

#social .button-icon {
filter: invert(1) brightness(2);
}
[data-theme="dark"] #social .button-icon {
filter: invert(1) brightness(2);
}

body {
Expand Down Expand Up @@ -157,6 +156,27 @@ p {
border-color: var(--accent-border);
}

.navbar-theme-toggle {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
padding: 0;
border-radius: 6px;
border: 1px solid var(--border);
background: transparent;
color: var(--text);
cursor: pointer;
transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.navbar-theme-toggle:hover {
background: var(--accent-bg);
color: var(--accent);
border-color: var(--accent-border);
}

.navbar-right {
display: flex;
align-items: center;
Expand Down
16 changes: 2 additions & 14 deletions react_fe/src/pages/IssueDetailsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
import { useNavigate, useParams } from "react-router-dom";
import { useAuth } from "../context/AuthContext";
import { useEffect, useState } from "react";
import { useEffect } from "react";
import { useAlert } from "../context/AlertContext";
import { IssueDto } from "../models/dto/IssueDto";
import { issuesApi } from "../api/issues";

function IssueDetailsPage() {
const { tenantId, id } = useParams<{ tenantId: string, id: string }>();
const { permissions } = useAuth();
const {info} = useAlert();
const navigate = useNavigate();
const [paginationSize, setPaginationSize] = useState(10);
const [currentPage, setCurrentPage] = useState(1);
const [issues, setIssues] = useState<IssueDto[] | null>(null);

useEffect(() => {
if (hasFaultyParams() || !permissions) {
Expand All @@ -24,14 +19,7 @@ function IssueDetailsPage() {
info("You do not have permissions for this tenant");
navigate('/');
}

issuesApi.getIssues(parseInt(tenantId!), { page: currentPage, size: paginationSize })
.then(response => setIssues(response.content))
.catch(error => {
info("Failed to fetch issues");
navigate('/');
});
}, [permissions, tenantId, navigate, currentPage, paginationSize]);
}, [permissions, tenantId]);

function hasFaultyParams() {
return !tenantId || isNaN(parseInt(tenantId)) || !id || isNaN(parseInt(id));
Expand Down
6 changes: 5 additions & 1 deletion react_fe/src/pages/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Link, useNavigate } from 'react-router-dom'
import { useAuth } from '../context/AuthContext'
import { AuthRequest } from '../models/dto/AuthRequest'
import { useAlert } from '../context/AlertContext';
import ThemeToggleButton from '../components/ThemeToggleButton';

interface FormErrors {
email?: string;
Expand Down Expand Up @@ -60,7 +61,10 @@ function LoginPage() {
return (
<div style={styles.page}>
<div style={styles.card}>
<h2 style={styles.title}>Welcome back</h2>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<h2 style={styles.title}>Welcome back</h2>
<ThemeToggleButton />
</div>
<p style={styles.subtitle}>Sign in to your account</p>

<form onSubmit={handleSubmit} noValidate style={styles.form}>
Expand Down
6 changes: 5 additions & 1 deletion react_fe/src/pages/Register.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useState } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import { useAuth } from '../context/AuthContext'
import { useAlert } from '../context/AlertContext'
import ThemeToggleButton from '../components/ThemeToggleButton'

interface FormErrors {
username?: string
Expand Down Expand Up @@ -77,7 +78,10 @@ function RegisterPage() {
return (
<div style={styles.page}>
<div style={styles.card}>
<h2 style={styles.title}>Create an account</h2>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<h2 style={styles.title}>Create an account</h2>
<ThemeToggleButton />
</div>
<p style={styles.subtitle}>Get started with Task Planner</p>

<form onSubmit={handleSubmit} noValidate style={styles.form}>
Expand Down
18 changes: 18 additions & 0 deletions task_planner/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,24 @@
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-javaagent:${org.mockito:mockito-core:jar}</argLine>
</configuration>
</plugin>
</plugins>
</build>

Expand Down
Loading