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")} + -
+ - + setReportName(e.target.value)} + /> {t("reportOverlay.trafficLightColor")} - setTrafficLightColor(e.target.value)} + > + + {t("reportOverlay.error")} + + + {t("reportOverlay.warning")} + + + {t("reportOverlay.success")} + @@ -91,11 +186,10 @@ export const ReportOverlay: React.FC = ({ isOpen, onClose }) fullWidth label={t("reportOverlay.startDate")} type="datetime-local" - InputLabelProps={{ - shrink: true, - }} + InputLabelProps={{ shrink: true }} variant="outlined" - defaultValue={dayjs().format("YYYY-MM-DDTHH:mm")} + value={startDate} + onChange={(e) => setStartDate(e.target.value)} /> @@ -103,11 +197,10 @@ export const ReportOverlay: React.FC = ({ isOpen, onClose }) fullWidth label={t("reportOverlay.endDate")} type="datetime-local" - InputLabelProps={{ - shrink: true, - }} + InputLabelProps={{ shrink: true }} variant="outlined" - defaultValue={dayjs().add(1, "day").format("YYYY-MM-DDTHH:mm")} + value={endDate} + onChange={(e) => setEndDate(e.target.value)} /> @@ -133,6 +226,8 @@ export const ReportOverlay: React.FC = ({ isOpen, onClose }) variant="outlined" label={t("reportOverlay.colorValue")} fullWidth + value={colorValues.red} + onChange={(e) => handleColorChange("red", e.target.value)} /> @@ -141,6 +236,8 @@ export const ReportOverlay: React.FC = ({ isOpen, onClose }) variant="outlined" label={t("reportOverlay.colorValue")} fullWidth + value={colorValues.orange} + onChange={(e) => handleColorChange("orange", e.target.value)} /> @@ -149,6 +246,8 @@ export const ReportOverlay: React.FC = ({ isOpen, onClose }) variant="outlined" label={t("reportOverlay.colorValue")} fullWidth + value={colorValues.green} + onChange={(e) => handleColorChange("green", e.target.value)} /> @@ -193,7 +292,11 @@ export const ReportOverlay: React.FC = ({ isOpen, onClose }) - + )} @@ -202,16 +305,26 @@ export const ReportOverlay: React.FC = ({ isOpen, onClose }) + {isEditMode && onDelete && ( + + )} diff --git a/application/frontend/src/components/ReportsTable/ReportsTable.tsx b/application/frontend/src/components/ReportsTable/ReportsTable.tsx index 6a9c0f9..d748df8 100644 --- a/application/frontend/src/components/ReportsTable/ReportsTable.tsx +++ b/application/frontend/src/components/ReportsTable/ReportsTable.tsx @@ -1,8 +1,11 @@ import dayjs from "dayjs" +import { Report } from "~pages/report/Report" -import React from "react" +import React, { useEffect, useState } from "react" import { useTranslation } from "react-i18next" +import ArrowDropDownOutlinedIcon from "@mui/icons-material/ArrowDropDownOutlined" +import ArrowDropUpOutlinedIcon from "@mui/icons-material/ArrowDropUpOutlined" import { Table, TableBody, TableHead } from "@mui/material" import StatusChipComponent from "../StatusChip/StatusChip" @@ -17,22 +20,29 @@ import { TableHeaderRow, } from "./ReportsTable.styled" -export interface Report { - id: number - name: string - status: "Error" | "Success" | "In Progress" | string - author: string - authorAvatar: string - startDate: string - endDate: string -} - interface ReportsTableProps { reports: Report[] + onReportClick: (report: Report) => void } -export const ReportsTable: React.FC = ({ reports }) => { +const ReportsTable: React.FC = ({ reports, onReportClick }) => { const { t } = useTranslation() + const [sortOrder, setSortOrder] = useState<"asc" | "desc">("asc") + const [sortedReports, setSortedReports] = useState(reports) + + useEffect(() => { + setSortedReports( + [...reports].sort((a, b) => { + const aDate = dayjs(a.endDate).valueOf() + const bDate = dayjs(b.endDate).valueOf() + return sortOrder === "asc" ? aDate - bDate : bDate - aDate + }), + ) + }, [reports, sortOrder]) + + const handleSort = () => { + setSortOrder((prevOrder) => (prevOrder === "asc" ? "desc" : "asc")) + } return ( @@ -42,15 +52,27 @@ export const ReportsTable: React.FC = ({ reports }) => { {t("reportsTable.name")} {t("reportsTable.status")} {t("reportsTable.author")} - {t("reportsTable.startDate")} + + {t("reportsTable.startDate")} + {sortOrder === "asc" ? ( + + ) : ( + + )} + {t("reportsTable.endDate")} - {reports.map((report) => ( + {sortedReports.map((report) => ( - {report.name} + onReportClick(report)} style={{ cursor: "pointer" }}> + {report.name} + diff --git a/application/frontend/src/components/UserSelectModal/UserSelectModal.tsx b/application/frontend/src/components/UserSelectModal/UserSelectModal.tsx new file mode 100644 index 0000000..88f6d63 --- /dev/null +++ b/application/frontend/src/components/UserSelectModal/UserSelectModal.tsx @@ -0,0 +1,51 @@ +import { User } from "context/UserContext" +import { ProfileCard } from "~components/ProfileCard" + +import React from "react" + +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + Typography, +} from "@mui/material" + +interface UserSelectModalProps { + open: boolean + onClose: () => void + profiles: User[] + onSelectProfile: (profileId: number) => void +} + +const UserSelectModal: React.FC = ({ + open, + onClose, + profiles, + onSelectProfile, +}) => { + return ( + + Select User + + {profiles.length > 0 ? ( + profiles.map((profile) => ( + onSelectProfile(profile.id)} + /> + )) + ) : ( + No users available + )} + + + + + + ) +} + +export default UserSelectModal diff --git a/application/frontend/src/components/UserSelectModal/index.ts b/application/frontend/src/components/UserSelectModal/index.ts new file mode 100644 index 0000000..add7e10 --- /dev/null +++ b/application/frontend/src/components/UserSelectModal/index.ts @@ -0,0 +1 @@ +export { UserSelectModal } from "./UserSelectModal" diff --git a/application/frontend/src/context/UserContext.tsx b/application/frontend/src/context/UserContext.tsx new file mode 100644 index 0000000..bc02edb --- /dev/null +++ b/application/frontend/src/context/UserContext.tsx @@ -0,0 +1,37 @@ +import React, { ReactNode, createContext, useState } from "react" + +export interface User { + id: number + name: string + avatar?: string +} + +interface UserContextType { + selectedUser: User | null + selectUser: (user: User) => void + users: User[] + setUsers: React.Dispatch> +} + +const UserContext = createContext(undefined) + +export const UserProvider: React.FC<{ children: ReactNode }> = ({ children }) => { + const [selectedUser, setSelectedUser] = useState(null) + const [users, setUsers] = useState([]) + + const selectUser = (user: User) => setSelectedUser(user) + + return ( + + {children} + + ) +} + +export const useUser = () => { + const context = React.useContext(UserContext) + if (context === undefined) { + throw new Error("useUser must be used within a UserProvider") + } + return context +} diff --git a/application/frontend/src/pages/Home/Home.tsx b/application/frontend/src/pages/Home/Home.tsx index 378ab05..722138c 100644 --- a/application/frontend/src/pages/Home/Home.tsx +++ b/application/frontend/src/pages/Home/Home.tsx @@ -1,3 +1,4 @@ +import { useUser } from "context/UserContext" import { ProfileCard } from "~components/ProfileCard" import { SearchBar } from "~components/SearchBar" @@ -20,6 +21,7 @@ import { export const Home: React.FC = () => { const [searchQuery, setSearchQuery] = useState("") const { t } = useTranslation() + const { selectUser } = useUser() const handleSearchChange = (e: React.ChangeEvent) => { setSearchQuery(e.target.value) @@ -39,10 +41,13 @@ export const Home: React.FC = () => { profile.name.toLowerCase().includes(searchQuery.toLowerCase()), ) + const handleProfileClick = (profile: { id: number; name: string; avatar: string }) => { + selectUser(profile) + } + return ( - @@ -62,7 +67,11 @@ export const Home: React.FC = () => { {filteredProfiles.map((profile) => ( - + handleProfileClick(profile)} + /> ))} diff --git a/application/frontend/src/pages/report/Report.tsx b/application/frontend/src/pages/report/Report.tsx index 6234b1c..b66703d 100644 --- a/application/frontend/src/pages/report/Report.tsx +++ b/application/frontend/src/pages/report/Report.tsx @@ -4,10 +4,11 @@ import { NavButton } from "~components/NavButton" import ReportOverlay from "~components/ReportOverlay/ReportOverlay" import ReportsTable from "~components/ReportsTable/ReportsTable" import { SearchBar } from "~components/SearchBar" -import { ViewModeToggle } from "~components/ViewModeToggle" +import { Report } from "~types/types" import React, { useState } from "react" import { useTranslation } from "react-i18next" +import { useParams } from "react-router-dom" import HomeIcon from "@mui/icons-material/Home" @@ -22,20 +23,7 @@ import { TitleSection, } from "./Report.styled" -type ReportStage = "Initial" | "Onboarding" | "In progress" | "In review" | "In test" - -type Report = { - id: number - name: string - status: string - author: string - authorAvatar: string - startDate: string - endDate: string - stage: ReportStage -} - -const reports: Report[] = [ +const initialReports: Report[] = [ { id: 1, name: "Report 1", @@ -58,7 +46,7 @@ const reports: Report[] = [ }, { id: 3, - name: "Report 3", + name: "aboba", status: "Warning", author: "Jane Smith", authorAvatar: "/path/to/avatar2.jpg", @@ -70,9 +58,12 @@ const reports: Report[] = [ export const ReportPage: React.FC = () => { const { t } = useTranslation() + const { userId, projectId } = useParams<{ userId: string; projectId: string }>() const [searchQuery, setSearchQuery] = useState("") const [viewMode, setViewMode] = useState<"list" | "timeline">("list") const [isOverlayOpen, setOverlayOpen] = useState(false) + const [selectedReport, setSelectedReport] = useState(null) + const [reports, setReports] = useState(initialReports) const handleSearchChange = (e: React.ChangeEvent) => { setSearchQuery(e.target.value) @@ -87,6 +78,7 @@ export const ReportPage: React.FC = () => { } const handleCreateReport = () => { + setSelectedReport(null) setOverlayOpen(true) } @@ -94,6 +86,15 @@ export const ReportPage: React.FC = () => { setOverlayOpen(false) } + const handleReportClick = (report: Report) => { + setSelectedReport(report) + setOverlayOpen(true) + } + + const handleDeleteReport = (report: Report) => { + setReports((prevReports) => prevReports.filter((r) => r.id !== report.id)) + } + const filteredReports = reports.filter((report) => report.name.toLowerCase().includes(searchQuery.toLowerCase()), ) @@ -102,10 +103,12 @@ export const ReportPage: React.FC = () => { - }> + }> {t("projectList")} - {t("projectName", { name: "Название проекта" })} + + {t("projectName", { name: "Название проекта" })} + @@ -123,12 +126,17 @@ export const ReportPage: React.FC = () => { variant="standard" placeholder={t("searchPlaceholder")} /> - - + - + ) } diff --git a/application/frontend/src/routes/routes.tsx b/application/frontend/src/routes/routes.tsx index a850da0..761b76e 100644 --- a/application/frontend/src/routes/routes.tsx +++ b/application/frontend/src/routes/routes.tsx @@ -12,8 +12,8 @@ const routes: RouteObject[] = [ element: , children: [ { index: true, element: }, - { path: "projects", element: }, - { path: "reports", element: }, + { path: ":userId/projects", element: }, + { path: ":userId/projects/:projectId/reports", element: }, ], }, { diff --git a/application/frontend/src/types/bar-task.ts b/application/frontend/src/types/bar-task.ts deleted file mode 100644 index 1be75e8..0000000 --- a/application/frontend/src/types/bar-task.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Task, TaskType } from "./public-types"; - -export interface BarTask extends Task { - index: number; - typeInternal: TaskTypeInternal; - x1: number; - x2: number; - y: number; - height: number; - progressX: number; - progressWidth: number; - barCornerRadius: number; - handleWidth: number; - barChildren: BarTask[]; - styles: { - backgroundColor: string; - backgroundSelectedColor: string; - progressColor: string; - progressSelectedColor: string; - }; -} - -export type TaskTypeInternal = TaskType | "smalltask"; diff --git a/application/frontend/src/types/date-setup.ts b/application/frontend/src/types/date-setup.ts deleted file mode 100644 index 81115ec..0000000 --- a/application/frontend/src/types/date-setup.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { ViewMode } from "./public-types"; - -export interface DateSetup { - dates: Date[]; - viewMode: ViewMode; -} diff --git a/application/frontend/src/types/gantt-task-actions.ts b/application/frontend/src/types/gantt-task-actions.ts deleted file mode 100644 index 01e1292..0000000 --- a/application/frontend/src/types/gantt-task-actions.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { BarTask } from "./bar-task"; - -export type BarMoveAction = "progress" | "end" | "start" | "move"; -export type GanttContentMoveAction = - | "mouseenter" - | "mouseleave" - | "delete" - | "dblclick" - | "click" - | "select" - | "" - | BarMoveAction; - -export type GanttEvent = { - changedTask?: BarTask; - originalSelectedTask?: BarTask; - action: GanttContentMoveAction; -}; diff --git a/application/frontend/src/types/public-types.ts b/application/frontend/src/types/public-types.ts deleted file mode 100644 index cc44ff1..0000000 --- a/application/frontend/src/types/public-types.ts +++ /dev/null @@ -1,145 +0,0 @@ -export enum ViewMode { - Hour = "Hour", - QuarterDay = "Quarter Day", - HalfDay = "Half Day", - Day = "Day", - /** ISO-8601 week */ - Week = "Week", - Month = "Month", - QuarterYear = "QuarterYear", - Year = "Year", -} -export type TaskType = "task" | "milestone" | "project"; -export interface Task { - id: string; - type: TaskType; - name: string; - start: Date; - end: Date; - /** - * From 0 to 100 - */ - progress: number; - styles?: { - backgroundColor?: string; - backgroundSelectedColor?: string; - progressColor?: string; - progressSelectedColor?: string; - }; - isDisabled?: boolean; - project?: string; - dependencies?: string[]; - hideChildren?: boolean; - displayOrder?: number; -} - -export interface EventOption { - /** - * Time step value for date changes. - */ - timeStep?: number; - /** - * Invokes on bar select on unselect. - */ - onSelect?: (task: Task, isSelected: boolean) => void; - /** - * Invokes on bar double click. - */ - onDoubleClick?: (task: Task) => void; - /** - * Invokes on bar click. - */ - onClick?: (task: Task) => void; - /** - * Invokes on end and start time change. Chart undoes operation if method return false or error. - */ - onDateChange?: ( - task: Task, - children: Task[] - ) => void | boolean | Promise | Promise; - /** - * Invokes on progress change. Chart undoes operation if method return false or error. - */ - onProgressChange?: ( - task: Task, - children: Task[] - ) => void | boolean | Promise | Promise; - /** - * Invokes on delete selected task. Chart undoes operation if method return false or error. - */ - onDelete?: (task: Task) => void | boolean | Promise | Promise; - /** - * Invokes on expander on task list - */ - onExpanderClick?: (task: Task) => void; -} - -export interface DisplayOption { - viewMode?: ViewMode; - viewDate?: Date; - preStepsCount?: number; - /** - * Specifies the month name language. Able formats: ISO 639-2, Java Locale - */ - locale?: string; - rtl?: boolean; -} - -export interface StylingOption { - headerHeight?: number; - columnWidth?: number; - listCellWidth?: string; - rowHeight?: number; - ganttHeight?: number; - barCornerRadius?: number; - handleWidth?: number; - fontFamily?: string; - fontSize?: string; - /** - * How many of row width can be taken by task. - * From 0 to 100 - */ - barFill?: number; - barProgressColor?: string; - barProgressSelectedColor?: string; - barBackgroundColor?: string; - barBackgroundSelectedColor?: string; - projectProgressColor?: string; - projectProgressSelectedColor?: string; - projectBackgroundColor?: string; - projectBackgroundSelectedColor?: string; - milestoneBackgroundColor?: string; - milestoneBackgroundSelectedColor?: string; - arrowColor?: string; - arrowIndent?: number; - todayColor?: string; - TooltipContent?: React.FC<{ - task: Task; - fontSize: string; - fontFamily: string; - }>; - TaskListHeader?: React.FC<{ - headerHeight: number; - rowWidth: string; - fontFamily: string; - fontSize: string; - }>; - TaskListTable?: React.FC<{ - rowHeight: number; - rowWidth: string; - fontFamily: string; - fontSize: string; - locale: string; - tasks: Task[]; - selectedTaskId: string; - /** - * Sets selected task by id - */ - setSelectedTask: (taskId: string) => void; - onExpanderClick: (task: Task) => void; - }>; -} - -export interface GanttProps extends EventOption, DisplayOption, StylingOption { - tasks: Task[]; -} diff --git a/application/frontend/src/types/types.ts b/application/frontend/src/types/types.ts new file mode 100644 index 0000000..b211234 --- /dev/null +++ b/application/frontend/src/types/types.ts @@ -0,0 +1,26 @@ +export interface Report { + id: number + name: string + status: "Error" | "Success" | "In Progress" | string + author: string + authorAvatar: string + startDate: string + endDate: string + stage: ReportStage + goals?: Goal[] + onVacation?: string + reporterOnVacation?: string + colorValues?: { + red?: string + orange?: string + green?: string + } +} + +export interface Goal { + title: string + status: string + description: string +} + +export type ReportStage = "Initial" | "Onboarding" | "In progress" | "In review" | "In test"