diff --git a/application/frontend/public/locales/translation/en.json b/application/frontend/public/locales/translation/en.json
index 07d2d7c..85b3a4e 100644
--- a/application/frontend/public/locales/translation/en.json
+++ b/application/frontend/public/locales/translation/en.json
@@ -51,7 +51,10 @@
"goals": "Goals",
"colorValue": "Value",
"yes":"Yes",
- "no":"No"
+ "no":"No",
+ "save":"Save",
+ "editReport":"Edit report",
+ "delete":"Delete"
},
"selectUser": "Select your user"
}
diff --git a/application/frontend/public/locales/translation/ru.json b/application/frontend/public/locales/translation/ru.json
index 485b749..8c217c3 100644
--- a/application/frontend/public/locales/translation/ru.json
+++ b/application/frontend/public/locales/translation/ru.json
@@ -16,9 +16,9 @@
"searchPlaceholder": "Поиск",
"createReport": "Создать отчет",
"status": {
- "Error": "Ошибка",
+ "Error": "Требует внимания",
"Success": "Успех",
- "Warning": "Предупреждение"
+ "Warning": "Обратить внимание"
},
"goalsTable": {
"title": "Название",
@@ -37,8 +37,8 @@
"reportName": "Название отчета",
"trafficLightColor": "Итоговый цвет светофора",
"success": "Успех",
- "error": "Ошибка",
- "warning": "Предупреждение",
+ "error": "Требует внимания",
+ "warning": "Обратить внимание",
"startDate": "Дата начала",
"endDate": "Дата окончания",
"colors": "Цвета светофора",
@@ -51,7 +51,10 @@
"goals": "Цели",
"colorValue": "Текст",
"yes":"Да",
- "no":"Нет"
+ "no":"Нет",
+ "save":"Сохранить",
+ "editReport":"Редактировать отчет",
+ "delete":"Удалить"
},
"selectUser": "Выберите своего пользователя"
}
diff --git a/application/frontend/src/App.tsx b/application/frontend/src/App.tsx
index e96d378..37c5c93 100644
--- a/application/frontend/src/App.tsx
+++ b/application/frontend/src/App.tsx
@@ -7,13 +7,16 @@ import "@fontsource/roboto/500.css"
import "@fontsource/roboto/700.css"
import { CONFIG } from "./configs"
+import { UserProvider } from "./context/UserContext"
import { AppRouter } from "./routes"
function App() {
return (
-
-
-
+
+
+
+
+
)
}
diff --git a/application/frontend/src/components/CustomMenuItem/CustomMenuItem.styled.ts b/application/frontend/src/components/CustomMenuItem/CustomMenuItem.styled.ts
new file mode 100644
index 0000000..e69de29
diff --git a/application/frontend/src/components/CustomMenuItem/CustomMenuItem.tsx b/application/frontend/src/components/CustomMenuItem/CustomMenuItem.tsx
new file mode 100644
index 0000000..d181e39
--- /dev/null
+++ b/application/frontend/src/components/CustomMenuItem/CustomMenuItem.tsx
@@ -0,0 +1,39 @@
+import React from "react"
+
+import CircleIcon from "@mui/icons-material/Circle"
+import { ListItemIcon, ListItemText, MenuItem } from "@mui/material"
+
+interface CustomMenuItemProps {
+ status: string
+ children: React.ReactNode
+ value: string
+}
+
+const getColor = (status: string) => {
+ switch (status) {
+ case "Success":
+ return "rgba(46, 125, 50, 1)"
+ case "Error":
+ return "rgba(211, 47, 47, 1)"
+ case "Warning":
+ return "rgba(239, 108, 0, 1)"
+ default:
+ return ""
+ }
+}
+
+export const CustomMenuItem: React.FC = ({
+ status,
+ children,
+ value,
+ ...props
+}) => (
+
+)
+
+export default CustomMenuItem
diff --git a/application/frontend/src/components/CustomMenuItem/index.ts b/application/frontend/src/components/CustomMenuItem/index.ts
new file mode 100644
index 0000000..092bfad
--- /dev/null
+++ b/application/frontend/src/components/CustomMenuItem/index.ts
@@ -0,0 +1 @@
+export { CustomMenuItem } from "./CustomMenuItem"
diff --git a/application/frontend/src/components/GoalsTable/GoalsTable.styled.ts b/application/frontend/src/components/GoalsTable/GoalsTable.styled.ts
index 92b331a..8014697 100644
--- a/application/frontend/src/components/GoalsTable/GoalsTable.styled.ts
+++ b/application/frontend/src/components/GoalsTable/GoalsTable.styled.ts
@@ -16,6 +16,24 @@ export const StyledTable = styled(Table)`
export const StyledTableCell = styled(TableCell)`
padding: 8px;
border: none;
+
+ &:first-of-type {
+ width: 200px;
+ }
+
+ &:nth-of-type(2) {
+ width: 150px;
+ }
+
+ &:nth-of-type(3) {
+ width: 300px;
+ }
+
+ &:last-of-type {
+ width: 48px;
+ padding: 0;
+ text-align: center;
+ }
`
export const StyledTableRow = styled(TableRow)`
diff --git a/application/frontend/src/components/GoalsTable/GoalsTable.tsx b/application/frontend/src/components/GoalsTable/GoalsTable.tsx
index 9441ca8..7dc3f2d 100644
--- a/application/frontend/src/components/GoalsTable/GoalsTable.tsx
+++ b/application/frontend/src/components/GoalsTable/GoalsTable.tsx
@@ -1,7 +1,8 @@
import React from "react"
import { useTranslation } from "react-i18next"
-import { TableBody, TableHead, TableRow } from "@mui/material"
+import DeleteIcon from "@mui/icons-material/Delete"
+import { IconButton, TableBody, TableHead, TableRow } from "@mui/material"
import { StatusSelector } from "../StatusSelector"
import {
@@ -21,9 +22,10 @@ interface Goal {
interface GoalsTableProps {
goals: Goal[]
onGoalChange: (index: number, field: keyof Goal, value: string) => void
+ onDeleteGoal: (index: number) => void
}
-export const GoalsTable: React.FC = ({ goals, onGoalChange }) => {
+export const GoalsTable: React.FC = ({ goals, onGoalChange, onDeleteGoal }) => {
const { t } = useTranslation()
return (
@@ -34,6 +36,7 @@ export const GoalsTable: React.FC = ({ goals, onGoalChange }) =
{t("goalsTable.title")}
{t("goalsTable.status")}
{t("goalsTable.description")}
+
@@ -63,6 +66,16 @@ export const GoalsTable: React.FC = ({ goals, onGoalChange }) =
variant="outlined"
/>
+
+ onDeleteGoal(index)}
+ aria-label={t("goalsTable.delete")}
+ style={{ padding: 8 }}
+ >
+
+
+
))}
diff --git a/application/frontend/src/components/Header/Header.tsx b/application/frontend/src/components/Header/Header.tsx
index 57b833d..2a09c0f 100644
--- a/application/frontend/src/components/Header/Header.tsx
+++ b/application/frontend/src/components/Header/Header.tsx
@@ -1,33 +1,45 @@
+import { useUser } from "context/UserContext"
import { UserController } from "~api/controllers/UserController"
import { useTheme } from "~components/Theme"
-import { ThemeEnum } from "~types/theme/enum"
+import UserSelectModal from "~components/UserSelectModal/UserSelectModal"
-import React, { useEffect } from "react"
+import React, { useEffect, useState } from "react"
import { useTranslation } from "react-i18next"
import { useNavigate } from "react-router-dom"
-import { AccountCircleOutlined, MoreVertOutlined, NotificationsOutlined } from "@mui/icons-material"
-import { Button, IconButton, Switch, Tooltip, Typography } from "@mui/material"
+import { Button, Switch, Tooltip, Typography } from "@mui/material"
-import {
- Container,
- IconButtons,
- LeftSection,
- Logo,
- NavButtons,
- RightSection,
- Switches,
-} from "./Header.styled"
+import { Container, LeftSection, Logo, NavButtons, RightSection, Switches } from "./Header.styled"
export const Header: React.FC = () => {
- const { theme, change } = useTheme()
+ const { theme } = useTheme()
const { t, i18n } = useTranslation()
const navigate = useNavigate()
+ const { selectedUser, users } = useUser()
+
+ const [isModalOpen, setModalOpen] = useState(false)
useEffect(() => {
UserController.get()
}, [])
+ const handleUserClick = () => {
+ setModalOpen(true)
+ }
+
+ const handleCloseModal = () => {
+ setModalOpen(false)
+ }
+
+ const handleSelectProfile = (profileId: number) => {
+ console.log("Selected Profile ID:", profileId)
+ setModalOpen(false)
+ }
+
+ useEffect(() => {
+ console.log("Loaded users:", users)
+ }, [users])
+
return (
@@ -38,7 +50,7 @@ export const Header: React.FC = () => {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ {selectedUser && (
+
+ {selectedUser.name}
+
+ )}
-
- {
- change(checked ? ThemeEnum.Dark : ThemeEnum.Light)
- }}
- />
-
@@ -139,6 +86,13 @@ export const Header: React.FC = () => {
+
+
)
}
diff --git a/application/frontend/src/components/ProfileCard/ProfileCard.tsx b/application/frontend/src/components/ProfileCard/ProfileCard.tsx
index f9a2019..a99a5da 100644
--- a/application/frontend/src/components/ProfileCard/ProfileCard.tsx
+++ b/application/frontend/src/components/ProfileCard/ProfileCard.tsx
@@ -26,16 +26,18 @@ interface ProfileCardProps {
name: string
avatar?: string
}
+ onClick?: () => void
}
-export const ProfileCard: React.FC = ({ profile }) => {
+export const ProfileCard: React.FC = ({ profile, onClick }) => {
const { id, name, avatar } = profile
const avatarLetter = name.charAt(0).toUpperCase()
const avatarColor = getAvatarColor(id)
const navigate = useNavigate()
const handleCardClick = () => {
- navigate("/projects")
+ onClick?.()
+ navigate(`${id}/projects`)
}
return (
diff --git a/application/frontend/src/components/ProjectCard/ProjectCard.tsx b/application/frontend/src/components/ProjectCard/ProjectCard.tsx
index 29adce0..e03fc5e 100644
--- a/application/frontend/src/components/ProjectCard/ProjectCard.tsx
+++ b/application/frontend/src/components/ProjectCard/ProjectCard.tsx
@@ -1,4 +1,5 @@
import React from "react"
+import { useNavigate } from "react-router-dom"
import ArrowForwardIcon from "@mui/icons-material/ArrowForward"
@@ -13,13 +14,23 @@ interface ProjectCardProps {
}
export const ProjectCard: React.FC = ({ project }) => {
+ const { id, name, avatar } = project
+ const navigate = useNavigate()
+
+ const handleCardClick = () => {
+ const userId = 1
+ navigate(`/${userId}/projects/${id}/reports`)
+ }
+
return (
-
-
- {project.name}
+
+
+ {name}
)
}
+
+export default ProjectCard
diff --git a/application/frontend/src/components/ReportOverlay/ReportOverlay.tsx b/application/frontend/src/components/ReportOverlay/ReportOverlay.tsx
index d71463f..00ed3df 100644
--- a/application/frontend/src/components/ReportOverlay/ReportOverlay.tsx
+++ b/application/frontend/src/components/ReportOverlay/ReportOverlay.tsx
@@ -1,6 +1,8 @@
import dayjs from "dayjs"
+import { CustomMenuItem } from "~components/CustomMenuItem"
+import { Goal, Report } from "~types/types"
-import React, { useState } from "react"
+import React, { useEffect, useState } from "react"
import { useTranslation } from "react-i18next"
import {
@@ -30,20 +32,65 @@ import {
interface ReportOverlayProps {
isOpen: boolean
onClose: () => void
+ report: Report | null
+ isEditMode: boolean
+ onDelete?: (report: Report) => void
}
-interface Goal {
- title: string
- status: string
- description: string
-}
-
-export const ReportOverlay: React.FC = ({ isOpen, onClose }) => {
+export const ReportOverlay: React.FC = ({
+ isOpen,
+ onClose,
+ report,
+ isEditMode,
+ onDelete,
+}) => {
const { t } = useTranslation()
const [tab, setTab] = useState(0)
+
+ const [reportName, setReportName] = useState("")
+ const [trafficLightColor, setTrafficLightColor] = useState("")
+ const [startDate, setStartDate] = useState("")
+ const [endDate, setEndDate] = useState("")
const [onVacation, setOnVacation] = useState("")
const [reporterOnVacation, setReporterOnVacation] = useState("")
const [goals, setGoals] = useState([])
+ const [colorValues, setColorValues] = useState<{ [key: string]: string }>({
+ red: "",
+ orange: "",
+ green: "",
+ })
+
+ useEffect(() => {
+ if (isEditMode && report) {
+ setReportName(report.name || "")
+ setTrafficLightColor(report.status || "")
+ setStartDate(dayjs(report.startDate).format("YYYY-MM-DDTHH:mm"))
+ setEndDate(dayjs(report.endDate).format("YYYY-MM-DDTHH:mm"))
+ setGoals(report.goals || [])
+ setOnVacation(report.onVacation || "")
+ setReporterOnVacation(report.reporterOnVacation || "")
+ setColorValues({
+ red: report.colorValues?.red || "",
+ orange: report.colorValues?.orange || "",
+ green: report.colorValues?.green || "",
+ })
+ }
+ }, [isEditMode, report])
+
+ const resetForm = () => {
+ setReportName("")
+ setTrafficLightColor("")
+ setStartDate("")
+ setEndDate("")
+ setOnVacation("")
+ setReporterOnVacation("")
+ setGoals([])
+ setColorValues({
+ red: "",
+ orange: "",
+ green: "",
+ })
+ }
const handleTabChange = (_event: React.SyntheticEvent, newValue: number) => {
setTab(newValue)
@@ -59,27 +106,75 @@ export const ReportOverlay: React.FC = ({ isOpen, onClose })
setGoals(updatedGoals)
}
+ const handleDeleteGoal = (index: number) => {
+ setGoals(goals.filter((_, i) => i !== index))
+ }
+
+ const handleColorChange = (color: string, value: string) => {
+ setColorValues((prev) => ({ ...prev, [color]: value }))
+ }
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault()
+ console.log({
+ reportName,
+ trafficLightColor,
+ startDate,
+ endDate,
+ onVacation,
+ reporterOnVacation,
+ goals,
+ colorValues,
+ })
+ onClose()
+ }
+
+ const handleCancel = () => {
+ if (!isEditMode) {
+ resetForm()
+ }
+ onClose()
+ }
+
return (
<>
- {t("reportOverlay.createReport")}
+
+ {isEditMode ? t("reportOverlay.editReport") : t("reportOverlay.createReport")}
+
-