Skip to content

Commit

Permalink
Added UI in the projectTable (where useIsCourseAdmin is defined) so a…
Browse files Browse the repository at this point in the history
… course admin can easily check the visibility of projects
  • Loading branch information
arnedierick committed May 18, 2024
1 parent 23300f3 commit 355ff0b
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 45 deletions.
7 changes: 7 additions & 0 deletions frontend/src/i18n/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@
"showMore": "Show more",
"submit": "Submit",
"projectStatus": "Status",
"visibility": "Visibility",
"visibleStatus": {
"visible": "Visible",
"invisible": "Invisible",
"visibleFrom": "Visible from ",
"scheduled": "Scheduled"
},
"status": {
"completed": "Completed",
"failed": "Failed",
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/i18n/nl/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,14 @@
"deadline": "Deadline",
"deadlineNotPassed": "Toon enkel actieve projecten",
"showMore": "Toon meer",

"projectStatus": "Status",
"visibility": "Zichtbaarheid",
"visibleStatus": {
"visible": "Zichtbaar",
"invisible": "Onzichtbaar",
"visibleFrom": "Zichtbaar vanaf ",
"scheduled" : "gepland"
},
"status": {
"completed": "Voltooid",
"failed": "Verkeerd",
Expand Down
100 changes: 56 additions & 44 deletions frontend/src/pages/index/components/ProjectCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FC, useEffect, useState } from "react"
import ProjectTable, { ProjectType } from "./ProjectTable"
import ProjectTableCourse, { ProjectType } from "./ProjectTableCourse"
import ProjectTable, { ProjectType as NormalProjectType } from "./ProjectTable"
import { Button, Card } from "antd"
import { ApiRoutes } from "../../../@types/requests.d"
import { useTranslation } from "react-i18next"
Expand All @@ -8,53 +9,64 @@ import { useNavigate } from "react-router-dom"
import CourseAdminView from "../../../hooks/CourseAdminView"
import { PlusOutlined } from "@ant-design/icons"
import useApi from "../../../hooks/useApi"
import useIsCourseAdmin from "../../../hooks/useIsCourseAdmin";

const ProjectCard: FC<{ courseId?: number }> = ({ courseId }) => {
const [projects, setProjects] = useState<ProjectType[] | null>(null)
const { t } = useTranslation()
const navigate = useNavigate()
const API = useApi()
const [projects, setProjects] = useState<ProjectType[] | null>(null)
const { t } = useTranslation()
const navigate = useNavigate()
const API = useApi()
const isCourseAdmin = useIsCourseAdmin()

useEffect(() => {
if (courseId) {
API.GET(ApiRoutes.COURSE_PROJECTS, { pathValues: { id: courseId } }).then((res) => {
if (!res.success) return
setProjects(res.response.data)
})
}
}, [courseId])
useEffect(() => {
if (courseId) {
API.GET(ApiRoutes.COURSE_PROJECTS, { pathValues: { id: courseId } }).then((res) => {
if (!res.success) return
setProjects(res.response.data)
})
}
}, [courseId])

return (
<>
<CourseAdminView>
<div style={{ textAlign: "right", paddingBottom: "10px" }}>
<Button
onClick={() => navigate(AppRoutes.PROJECT_CREATE.replace(":courseId", String(courseId)))}
icon={<PlusOutlined />}
type="primary"
>
{t("project.newProject")}
</Button>
</div>
</CourseAdminView>
<Card
style={{
width: "100%",
overflow: "auto",
}}
styles={{
body: {
padding: "0",
},
}}
>
<ProjectTable
ignoreColumns={["course"] }
projects={projects}
/>
</Card>
</>
)
return (
<>
{isCourseAdmin && (
<CourseAdminView>
<div style={{ textAlign: "right", paddingBottom: "10px" }}>
<Button
onClick={() => navigate(AppRoutes.PROJECT_CREATE.replace(":courseId", String(courseId)))}
icon={<PlusOutlined />}
type="primary"
>
{t("project.newProject")}
</Button>
</div>
</CourseAdminView>
)}
<Card
style={{
width: "100%",
overflow: "auto",
}}
styles={{
body: {
padding: "0",
},
}}
>
{isCourseAdmin ? (
<ProjectTableCourse
ignoreColumns={["course"] }
projects={projects}
/>
) : (
<ProjectTable
ignoreColumns={["course"] }
projects={projects as NormalProjectType[]}
/>
)}
</Card>
</>
)
}

export default ProjectCard
138 changes: 138 additions & 0 deletions frontend/src/pages/index/components/ProjectTableCourse.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { Button, Table, TableProps, Tag, Tooltip } from "antd"
import { FC, useMemo } from "react"
import { ApiRoutes, GET_Responses } from "../../../@types/requests.d"
import { useTranslation } from "react-i18next"
import i18n from 'i18next'
import useAppApi from "../../../hooks/useAppApi"
import ProjectStatusTag from "./ProjectStatusTag"
import GroupProgress from "./GroupProgress"
import { Link } from "react-router-dom"
import { AppRoutes } from "../../../@types/routes"
import { ClockCircleOutlined } from "@ant-design/icons"
import useIsCourseAdmin from "../../../hooks/useIsCourseAdmin";

export type ProjectType = GET_Responses[ApiRoutes.PROJECT]

const ProjectTableCourse: FC<{ projects: ProjectType[] | null, ignoreColumns?: string[] }> = ({ projects, ignoreColumns }) => {
const { t } = useTranslation()
const { modal } = useAppApi()
const isCourseAdmin = useIsCourseAdmin()

const columns: TableProps<ProjectType>["columns"] = useMemo(
() => {
let columns: TableProps<ProjectType>["columns"] = [
{
title: t("home.projects.name"),
key: "name",
render: (project: ProjectType) => (
<Link to={AppRoutes.PROJECT.replace(":courseId", project.course.courseId + "").replace(":projectId", project.projectId + "")}>
<Button
type="link"
style={{ fontWeight: "bold" }}
>
{project.name}
</Button>
</Link>
)
},
{
title: t("home.projects.course"),
dataIndex: "course",
key: "course",
sorter: (a: ProjectType, b: ProjectType) => a.course.name.localeCompare(b.course.name),
sortDirections: ['ascend', 'descend'],
render: (course: ProjectType["course"]) => course.name
},
{
title: t("home.projects.deadline"),
dataIndex: "deadline",
key: "deadline",
sorter: (a: ProjectType, b: ProjectType) => new Date(a.deadline).getTime() - new Date(b.deadline).getTime(),
sortDirections: ['ascend', "descend"],
defaultSortOrder: "ascend",
filters: [{ text: t('home.projects.deadlineNotPassed'), value: 'notPassed' }],
onFilter: (value: any, record: any) => {
const currentTimestamp = new Date().getTime();
const deadlineTimestamp = new Date(record.deadline).getTime();
return value === 'notPassed' ? deadlineTimestamp >= currentTimestamp : true;
},
defaultFilteredValue: ["notPassed"],
render: (text: string) =>
new Date(text).toLocaleString(i18n.language, {
year: "numeric",
month: "long",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
}),
},
{
title: t("home.projects.groupProgress"),
key: "progress",
render: (project: ProjectType) => (
<GroupProgress
usersCompleted={project.progress.completed}
userCount={project.progress.total}
/>
),
}
]

if (ignoreColumns) {
columns = columns.filter((c) => !ignoreColumns.includes(c.key as string))
}

if (isCourseAdmin) {
columns = columns.filter((c) => c.key !== "status")
columns.push({
title: t("home.projects.visibility"),
key: "visible",
render: (project: ProjectType) => {
if (project.visible) {
return <Tag color="success">{t("home.projects.visibleStatus.visible")}</Tag>
} else if (project.visibleAfter) {
return (
<Tooltip title={`${t("home.projects.visibleStatus.visibleFrom")} ${new Date(project.visibleAfter).toLocaleString(i18n.language, {
year: "numeric",
month: "long",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
})}`}>
<Tag icon={<ClockCircleOutlined />} color="default">{t("home.projects.visibleStatus.scheduled")}</Tag>
</Tooltip>
)
} else {
return <Tag color="error">{t("home.projects.visibleStatus.invisible")}</Tag>
}
}
})
} else {
columns.push({
title: t("home.projects.projectStatus"),
key: "status",
render: (project: ProjectType) =>
project.status && <ProjectStatusTag status={project.status} />,
})
}

return columns
},
[t, modal, projects, isCourseAdmin]
)

return (
<Table
showSorterTooltip={{ mouseEnterDelay: 1 }}
locale={{
emptyText: t("home.projects.noProjects"),
}}
loading={projects == null}
dataSource={projects ?? []}
columns={columns}
rowKey={(project) => project.projectId}
/>
)
}

export default ProjectTableCourse

0 comments on commit 355ff0b

Please sign in to comment.