ManagementSystem/FRONTEND/src/pages/StaffEvaluation/StaffEvaluation.tsx

1342 lines
37 KiB
TypeScript

import {
evaluation,
getAllTechByUserId,
getAllUser,
projectReview,
sprintReview,
projectReviewAdd,
projectReviewUpdate,
projectReviewDelete,
evaluationReportAllUsers,
getListTrackingSummary,
getPJParticipating,
} from '@/api/Admin'
import DataTableAll from '@/components/DataTable/DataTable'
import ProjectInvolvement from '@/components/ProjectInvolvement/ProjectInvolvement'
import { get, getDownloadFile, post } from '@/rtk/helpers/apiService'
import {
Box,
Button,
Dialog,
Group,
Loader,
Modal,
Select,
Tabs,
Text,
Textarea,
TextInput,
Title,
} from '@mantine/core'
import { DateInput } from '@mantine/dates'
import { notifications } from '@mantine/notifications'
import moment from 'moment'
import { useEffect, useState } from 'react'
import classes from './StaffEvaluation.module.css'
import {
IconClearAll,
IconEdit,
IconPresentationAnalytics,
IconReportAnalytics,
IconX,
} from '@tabler/icons-react'
import { useForm } from '@mantine/form'
import { update, Xdelete } from '@/rtk/helpers/CRUD'
import { PieChart } from '@mantine/charts'
interface User {
id: number
name: string
email: string
email_verified_at: string | null
permission: string
remember_token: string | null
created_at: string | null
updated_at: string | null
}
interface Filter {
userID: string
fromDate: Date | null
toDate: Date | null
// other properties of the filter object
}
interface DataTechnical {
id: number
name: string
level: number
point: number
updated_at: string
}
interface DataProjectReview {
id: number
name: string
role: string
note: string
user_id: number
created_at: string
updated_at: string
}
interface DataPJParticipating {
name: string
total_task: number
total_time_spent: number
}
type TLog = {
id: number
name: string
status: string
time_string: Date
}
interface DataSummaryTracking {
on_time_morning: number
late_morning: number
on_time_afternoon: number
late_afternoon: number
value: TLog[]
}
const StaffEvaluation = () => {
const [loading, setLoading] = useState(false)
const [loadingReview, setLoadingReview] = useState(false)
const [loadingWorkingStyle, setLoadingWorkingStyle] = useState(false)
const [loadingPJParticipating, setLoadingPJParticipating] = useState(false)
const [loadingTechnical, setLoadingTechnical] = useState(false)
const [dataProfile, setDataProfile] = useState<any>([])
const [dataTechnical, setDataTechnical] = useState<DataTechnical[]>([])
const [dataProjectReview, setDataProjectReview] = useState<
DataProjectReview[]
>([])
const [listUsers, setListUsers] = useState<User[]>([])
const [filter, setFilter] = useState<Filter>({
userID: '',
fromDate: null,
toDate: null,
})
const [action, setAction] = useState('')
const [item, setItem] = useState({ id: 0 })
const [disableBtn, setDisableBtn] = useState(false)
const [activeBtn, setActiveBtn] = useState(false)
const [loadingExport, setLoadingExport] = useState(false)
const [loadingExportAll, setLoadingExportAll] = useState(false)
const [dataPJParticipating, setDataPJParticipating] = useState<
DataPJParticipating[]
>([])
const [dataSummaryTracking, setDataSummaryTracking] =
useState<DataSummaryTracking>({
on_time_morning: 0,
late_morning: 0,
on_time_afternoon: 0,
late_afternoon: 0,
value: [],
})
const form = useForm({
initialValues: {
id: 0,
name: '',
role: '',
note: '',
user_id: 0,
created_at: '',
updated_at: '',
},
validate: {
name: (value) =>
value.length === 0 ? 'Please enter project name' : null,
role: (value) => (value.length === 0 ? 'Please enter role' : null),
note: (value) => (value.length === 0 ? 'Please enter note' : null),
},
})
const getListUser = async () => {
try {
const params = {}
const res = await get(getAllUser, params)
if (res.status) {
return res.data
}
} catch (error: any) {
notifications.show({
title: 'Error',
message: error.message ?? error,
color: 'red',
})
}
return []
}
function getFormattedDateTime(): string {
const now = new Date()
const year = now.getFullYear()
const month = String(now.getMonth() + 1).padStart(2, '0') // Tháng bắt đầu từ 0
const day = String(now.getDate()).padStart(2, '0')
const hours = String(now.getHours()).padStart(2, '0')
const minutes = String(now.getMinutes()).padStart(2, '0')
const seconds = String(now.getSeconds()).padStart(2, '0')
return `${year}${month}${day}${hours}${minutes}${seconds}`
}
const downloadFile = async (filterSearch: Filter) => {
try {
const params = {
userID: filterSearch.userID ?? '',
fromDate: filterSearch.fromDate
? moment(filterSearch.fromDate).format('YYYY-MM-DD')
: null,
toDate: filterSearch.toDate
? moment(filterSearch.toDate).format('YYYY-MM-DD')
: null,
}
const user = listUsers.find(
(el) => el.id.toString() === filterSearch.userID,
)
setLoadingExport(true)
const res = await getDownloadFile(evaluation, params)
if (res.status) {
const fileURL = window.URL.createObjectURL(new Blob([res.data]))
const fileLink = document.createElement('a')
const fileName = `STAFF_EVALUATION_${user?.name
?.split(' ')
.join('_')}_${getFormattedDateTime()}.docx`
fileLink.href = fileURL
fileLink.setAttribute('download', fileName)
document.body.appendChild(fileLink)
fileLink.click()
fileLink.remove()
}
setLoadingExport(false)
} catch (error: any) {
notifications.show({
title: 'Error',
message: error.message ?? error,
color: 'red',
})
}
return []
}
const downloadFileAll = async (filterSearch: Filter) => {
try {
const params = {
fromDate: filterSearch.fromDate
? moment(filterSearch.fromDate).format('YYYY-MM-DD')
: null,
toDate: filterSearch.toDate
? moment(filterSearch.toDate).format('YYYY-MM-DD')
: null,
}
setLoadingExportAll(true)
const res = await getDownloadFile(evaluationReportAllUsers, params)
if (res.status) {
const fileURL = window.URL.createObjectURL(new Blob([res.data]))
const fileLink = document.createElement('a')
const fileName = `STAFF_EVALUATION_All_USERS_${getFormattedDateTime()}.docx`
fileLink.href = fileURL
fileLink.setAttribute('download', fileName)
document.body.appendChild(fileLink)
fileLink.click()
fileLink.remove()
}
setLoadingExportAll(false)
} catch (error: any) {
notifications.show({
title: 'Error',
message: error.message ?? error,
color: 'red',
})
}
return []
}
useEffect(() => {
const fetchData = async () => {
const result = await getListUser()
setListUsers(result ?? [])
}
fetchData()
}, [])
const getListProfilesData = async (filterSearch: Filter) => {
try {
const params = {
userID: filterSearch.userID ?? '',
fromDate: filterSearch.fromDate
? moment(filterSearch.fromDate).format('YYYY-MM-DD')
: null,
toDate: filterSearch.toDate
? moment(filterSearch.toDate).format('YYYY-MM-DD')
: null,
}
const res = await get(sprintReview, params)
if (res.status) {
return res.data
}
} catch (error: any) {
notifications.show({
title: 'Error',
message: error.message ?? error,
color: 'red',
})
}
return []
}
const getListTechnicalByUserId = async (id: string) => {
try {
const params = {}
const res = await get(`${getAllTechByUserId}/${id}`, params)
if (res.status) {
return res.data
}
} catch (error: any) {
notifications.show({
title: 'Error',
message: error.message ?? error,
color: 'red',
})
}
return []
}
const getListProjectReview = async (filterSearch: Filter) => {
try {
const params = {
userID: filterSearch.userID ?? '',
fromDate: filterSearch.fromDate
? moment(filterSearch.fromDate).format('YYYY-MM-DD')
: null,
toDate: filterSearch.toDate
? moment(filterSearch.toDate).format('YYYY-MM-DD')
: null,
}
const res = await get(projectReview, params)
if (res.status) {
return res.data
}
} catch (error: any) {
notifications.show({
title: 'Error',
message: error.message ?? error,
color: 'red',
})
}
return []
}
const getListSummaryTracking = async (filterSearch: Filter) => {
try {
const params = {
userID: filterSearch.userID ?? '',
fromDate: filterSearch.fromDate
? moment(filterSearch.fromDate).format('YYYY-MM-DD')
: null,
toDate: filterSearch.toDate
? moment(filterSearch.toDate).format('YYYY-MM-DD')
: null,
}
const res = await get(getListTrackingSummary, params)
if (res.status) {
return res.data
}
} catch (error: any) {
notifications.show({
title: 'Error',
message: error.message ?? error,
color: 'red',
})
}
return []
}
const getListProjectParticipating = async (filterSearch: Filter) => {
try {
const fromDate = filterSearch.fromDate
? moment(filterSearch.fromDate).format('YYYY-MM-DD')
: moment(new Date()).format('YYYY-MM-DD')
const toDate = filterSearch.toDate
? moment(filterSearch.toDate).format('YYYY-MM-DD')
: moment(new Date()).format('YYYY-MM-DD')
const params = {
userID: filterSearch.userID ?? '',
fromDate: fromDate,
toDate: toDate,
}
const res = await get(getPJParticipating, params)
if (res.status) {
const value = processJiraData(res.data, fromDate, toDate, res.accountId)
return value
}
} catch (error: any) {
notifications.show({
title: 'Error',
message: error.message ?? error,
color: 'red',
})
}
return []
}
function processJiraData(
data: any,
startDate: any,
endDate: any,
accountId: string,
) {
const projectSummary: any = {}
const start = new Date(startDate)
const end = new Date(endDate)
data.issues.forEach((issue: any) => {
const projectName = issue.fields.project.name
const worklogs = issue.fields.worklog.worklogs
// Filter worklogs based on 'started' date range
const filteredWorklogs = worklogs.filter((log: any) => {
const logDate = new Date(log.started)
return (
logDate >= start &&
logDate <= end &&
accountId === log?.updateAuthor?.accountId
)
})
if (filteredWorklogs.length === 0) return // Skip if no worklogs in range
if (!projectSummary[projectName]) {
projectSummary[projectName] = {
project_name: projectName,
total_task: 0,
total_time_spent: 0,
}
}
// Get unique issueIds within the filtered worklogs
const uniqueIssues = new Set(
filteredWorklogs.map((log: any) => log.issueId),
)
// Sum up total time spent from filtered worklogs
const totalTimeSpent = filteredWorklogs.reduce(
(sum: number, log: any) => sum + log.timeSpentSeconds,
0,
)
projectSummary[projectName].total_task += uniqueIssues.size
projectSummary[projectName].total_time_spent += totalTimeSpent
})
const returnValue: DataPJParticipating[] = Object.values(projectSummary)
return returnValue
}
useEffect(() => {
if (filter?.userID) {
setLoading(true)
setLoadingReview(true)
setLoadingWorkingStyle(true)
const fetchData = async () => {
const result = await getListProfilesData(filter)
setDataProfile(result ?? [])
setLoading(false)
}
const fetchDataProject = async () => {
const result = await getListProfilesData(filter)
const resultProject = await getListProjectReview(filter)
setDataProfile(result ?? [])
setDataProjectReview(resultProject ?? [])
setLoadingReview(false)
}
const fetchDataTracking = async () => {
const resultTracking = await getListSummaryTracking(filter)
setDataSummaryTracking(resultTracking ?? [])
setLoadingWorkingStyle(false)
}
const fetchDataPJParticipating = async () => {
const resultPJParticipating = await getListProjectParticipating(filter)
setDataPJParticipating(resultPJParticipating ?? [])
setLoadingPJParticipating(false)
}
fetchData()
fetchDataProject()
fetchDataTracking()
if (filter?.fromDate && filter?.toDate) {
setLoadingPJParticipating(true)
fetchDataPJParticipating()
}
}
}, [filter])
useEffect(() => {
if (filter?.userID) {
setLoadingTechnical(true)
const fetchData = async () => {
const result = await getListTechnicalByUserId(filter?.userID)
setDataTechnical(result ?? [])
setLoadingTechnical(false)
}
fetchData()
}
}, [filter?.userID])
const columns = [
{
name: 'level',
size: '10%',
header: 'Level',
render: (row: any) => {
return (
<Box
style={
row?.level
? row?.level === 1
? { backgroundColor: '#d9d2e9' }
: row?.level === 2
? { backgroundColor: '#ffd966' }
: { backgroundColor: '#cfe2f3' }
: { backgroundColor: '' }
}
fw={500}
ta="center"
p={4}
>
{row?.level ? row.level : ''}
</Box>
)
},
},
{
name: 'name',
size: '',
header: 'Name',
},
{
name: 'point',
size: '10%',
header: 'Point',
render: (row: any) => {
if (row?.point > 0)
return (
<div
style={{
display: 'flex',
justifyContent: 'center',
}}
>
{row?.point}
</div>
)
},
},
{
name: 'updated_at',
size: '25%',
header: 'Last update',
render: (row: any) => {
if (row?.updated_at)
return (
<div
style={{
display: 'flex',
justifyContent: 'center',
}}
>
{moment(row?.updated_at).format('DD/MM/YYYY HH:mm:ss')}
</div>
)
},
},
]
const infoTotal = () => {
// Tính tổng point và số lượng point > 0
let totalPoint = 0
let count = 0
dataTechnical.forEach((item) => {
if (item.point > 0) {
totalPoint += item.point
count++
}
})
const averagePoint = count > 0 ? (totalPoint / count).toFixed(2) : '0.00'
return (
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<Text mr={20} fs={'italic'}>
Avg: {averagePoint}
</Text>
<Text fs={'italic'}>Total: {totalPoint}</Text>
</div>
)
}
const columnsProjectReview = [
// {
// name: 'id',
// size: '5%',
// header: 'Num',
// render: (row: any) => {
// return (
// <Box fw={500} ta="center" p={4}>
// {row?.id ? row.id : ''}
// </Box>
// )
// },
// },
{
name: 'name',
size: '15%',
header: 'Name',
},
{
name: 'role',
size: '15%',
header: 'Role',
},
{
name: 'note',
size: '',
header: 'Note',
},
{
name: 'created_at',
size: '10%',
header: 'Created at',
render: (row: any) => {
if (row?.created_at)
return (
<div
style={{
display: 'flex',
justifyContent: 'center',
}}
>
{moment(row?.created_at).format('DD/MM/YYYY HH:mm:ss')}
</div>
)
},
},
{
name: 'updated_at',
size: '10%',
header: 'Last update',
render: (row: any) => {
if (row?.updated_at)
return (
<div
style={{
display: 'flex',
justifyContent: 'center',
}}
>
{moment(row?.updated_at).format('DD/MM/YYYY HH:mm:ss')}
</div>
)
},
},
{
name: '#',
size: '5%',
header: 'Action',
render: (row: DataProjectReview) => {
return (
<Box className={classes.optionIcon}>
<IconEdit
className={classes.editIcon}
onClick={() => {
setAction('edit')
form.setValues(row)
}}
width={20}
height={20}
/>
<IconX
className={classes.deleteIcon}
onClick={() => {
setAction('delete')
setItem(row)
}}
width={20}
height={20}
/>
</Box>
)
},
},
]
const columnsPJParticipating = [
{
name: 'project_name',
size: '50%',
header: 'Name',
},
{
name: 'total_task',
size: '25%',
header: 'Total task',
},
{
name: 'total_time_spent',
size: '25%',
header: 'Total time spent',
render: (row: any) => {
return <div>{row?.total_time_spent / 60 / 60}h</div>
},
},
]
const columnsDetailWorking = [
{
name: 'name',
size: '40%',
header: 'Name',
},
{
name: 'time_string',
size: '40%',
header: 'Time',
render: (row: any) => {
return moment(row.time_string).format('YYYY/MM/DD - HH:mm:ss')
},
},
{
name: 'status',
size: '20%',
header: 'Status',
},
]
const handleCreate = async (values: DataProjectReview) => {
try {
const res = await post(projectReviewAdd, {
name: values.name,
role: values.role,
note: values.note,
user_id: filter.userID,
})
if (res.id) {
setAction('')
form.reset()
const resultProject = await getListProjectReview(filter)
setDataProjectReview(resultProject ?? [])
}
} catch (error) {
console.log(error)
}
}
const handleUpdate = async (values: DataProjectReview) => {
try {
const res = await update(projectReviewUpdate, {
id: values.id,
name: values.name,
role: values.role,
note: values.note,
user_id: filter.userID,
})
if (res) {
setAction('')
form.reset()
const resultProject = await getListProjectReview(filter)
setDataProjectReview(resultProject ?? [])
}
} catch (error) {
console.log(error)
}
}
const handleDelete = async (id: number) => {
try {
await Xdelete(projectReviewDelete, { id: id }, async () => {
const resultProject = await getListProjectReview(filter)
setDataProjectReview(resultProject ?? [])
})
} catch (error) {
console.log(error)
}
}
return (
<div>
<div className={classes.title}>
<h3>
<Text>Admin/</Text>
Staff Evaluation
</h3>
<Box
w="20%"
display={'flex'}
style={{ justifyContent: 'flex-end' }}
mr={10}
>
{loadingExportAll ? (
<Button
disabled
style={{
display: 'flex',
justifyContent: 'center',
width: '135px',
}}
onClick={() => {}}
>
<Loader size={'sm'} color="green" type="oval" m={'0 auto'} />
</Button>
) : (
<Button
// m={5}
style={{ display: 'flex', width: '135px' }}
onClick={() => downloadFileAll(filter)}
>
Export all user
</Button>
)}
</Box>
</div>
<Box w="100%" display={'flex'} mt={15} ml={10}>
<Box w="80%" display={'flex'} style={{ alignItems: 'center' }}>
<Text
mr={'xs'}
style={{ alignContent: 'center' }}
fw={600}
size={'md'}
>
User:
</Text>
<Select
style={{ width: '20%' }}
label={''}
placeholder="Select user"
maxLength={255}
size={'xs'}
required
data={listUsers.map((i: User) => ({
value: i.id.toString(),
label: i.name,
}))}
value={filter.userID}
onChange={(e) => setFilter({ ...filter, userID: e! })}
/>
<Box
display={'flex'}
mr={10}
ms={10}
style={{ alignItems: 'center' }}
>
<Text
mr={'xs'}
style={{ alignContent: 'center' }}
fw={600}
size={'md'}
>
From Date:
</Text>
<DateInput
placeholder="Select date"
clearable
size="xs"
required
label={''}
value={filter.fromDate ? new Date(filter.fromDate) : null}
valueFormat="DD/MM/YYYY"
onChange={(e) => setFilter({ ...filter, fromDate: e! })}
></DateInput>
</Box>
<Box display={'flex'} mr={10} style={{ alignItems: 'center' }}>
<Text
mr={'xs'}
style={{ alignContent: 'center' }}
fw={600}
size={'md'}
>
To Date:
</Text>
<DateInput
placeholder="Select date"
clearable
size="xs"
required
label={''}
value={filter.toDate ? new Date(filter.toDate) : null}
valueFormat="DD/MM/YYYY"
onChange={(e) => setFilter({ ...filter, toDate: e! })}
></DateInput>
</Box>
</Box>
<Box
w="20%"
display={'flex'}
style={{ justifyContent: 'flex-end' }}
mr={10}
>
{loadingExport ? (
<Button
disabled
style={{
display: 'flex',
justifyContent: 'center',
width: '80px',
}}
onClick={() => {}}
>
<Loader size={'sm'} color="green" type="oval" m={'0 auto'} />
</Button>
) : (
<Button
// m={5}
style={{
display: filter.userID != '' ? 'flex' : 'none',
width: '80px',
}}
onClick={() => downloadFile(filter)}
>
Export
</Button>
)}
</Box>
</Box>
<Tabs mt={8} variant="outline" defaultValue="general">
<Tabs.List>
<Tabs.Tab
value="general"
leftSection={<IconClearAll size={16} color="teal" />}
>
<span style={{ fontSize: '16px' }}>General</span>
</Tabs.Tab>
<Tabs.Tab
value="project_review"
leftSection={<IconPresentationAnalytics size={16} color="blue" />}
>
<span style={{ fontSize: '16px' }}>Project review</span>
</Tabs.Tab>
<Tabs.Tab
value="working_style"
leftSection={<IconReportAnalytics size={16} color="#fab005" />}
>
<span style={{ fontSize: '16px' }}>Working review</span>
</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="general">
<Box className={classes.userInfoSection} display="flex">
<Box className={classes.projectInvolvement}>
<Box
style={{
marginTop: '10%',
textAlign: 'center',
display: loading ? 'block' : 'none',
// display: 'none',
}}
>
<Loader size={'sm'} color="green" type="bars" m={'0 auto'} />
<Text fw={600} c={'gray'}>
Loading . . .
</Text>
</Box>
{!loading && dataProfile.length == 0 && (
<Box
style={{
marginTop: '10%',
textAlign: 'center',
display: 'block',
}}
>
<Text fw={600} c={'gray'}>
No Data Sprint
</Text>
</Box>
)}
{!loading && (
<ProjectInvolvement dataProfile={dataProfile} page="admin" />
)}
</Box>
<Box className={classes.sidebar}>
<Title order={3} className={classes.titleSidebar}>
Technicals
</Title>
{loadingTechnical ? (
<Box
style={{
marginTop: '10%',
textAlign: 'center',
display: 'block',
}}
>
<Loader size={'sm'} color="green" type="bars" m={'0 auto'} />
<Text fw={600} c={'gray'}>
Loading . . .
</Text>
</Box>
) : (
<DataTableAll
data={dataTechnical}
columns={columns}
size=""
searchInput
infoTotal={infoTotal()}
/>
)}
</Box>
</Box>
</Tabs.Panel>
<Tabs.Panel value="project_review">
<Box className={classes.userInfoSection} display="flex">
{loadingReview ? (
<Box
style={{
width: '100%',
display: loadingReview ? 'block' : 'none',
}}
>
<Box
style={{
marginTop: '10%',
textAlign: 'center',
// display: 'none',
}}
>
<Loader size={'sm'} color="green" type="bars" m={'0 auto'} />
<Text fw={600} c={'gray'}>
Loading . . .
</Text>
</Box>
</Box>
) : (
<DataTableAll
data={dataProjectReview}
columns={columnsProjectReview}
size=""
searchInput
// infoTotal={infoTotal()}
componentRight={
<Box
w="100%"
display={'flex'}
style={{ justifyContent: 'flex-end' }}
mr={10}
>
<Button
color="teal"
style={{ display: filter.userID != '' ? 'flex' : 'none' }}
onClick={() => {
setAction('add')
form.reset()
}}
>
Add
</Button>
</Box>
}
/>
)}
</Box>
</Tabs.Panel>
<Tabs.Panel value="working_style">
{loadingWorkingStyle ? (
<Box
style={{
width: '100%',
display: loadingWorkingStyle ? 'block' : 'none',
}}
>
<Box
style={{
marginTop: '10%',
textAlign: 'center',
// display: 'none',
}}
>
<Loader size={'sm'} color="green" type="bars" m={'0 auto'} />
<Text fw={600} c={'gray'}>
Loading . . .
</Text>
</Box>
</Box>
) : (
<Box>
<Tabs defaultValue="overview" orientation="vertical">
<Tabs.List justify="center">
<Tabs.Tab value="overview">Overview</Tabs.Tab>
<Tabs.Tab value="detail">Detail</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="overview">
<Box style={{ height: 350, marginTop: 8 }}>
<Box className={classes.chartContainer} display="flex">
<PieChart
withLabelsLine
labelsPosition="outside"
labelsType="value"
withLabels={dataSummaryTracking.value.length > 0}
withTooltip
data={
dataSummaryTracking.value.length > 0
? [
{
name: 'On time morning',
value:
dataSummaryTracking?.on_time_morning ?? 0,
color: 'lime',
},
{
name: 'Late morning',
value: dataSummaryTracking?.late_morning ?? 0,
color: 'red',
},
{
name: 'On time afternoon',
value:
dataSummaryTracking?.on_time_afternoon ?? 0,
color: 'teal',
},
{
name: 'Late afternoon',
value:
dataSummaryTracking?.late_afternoon ?? 0,
color: 'orange',
},
]
: [
{
name: 'No data',
value: 1,
color: 'gray.6',
},
]
}
/>
</Box>
<Box className={classes.boxContainer} display="flex">
<Box className={classes.boxContainer} display="flex">
<div className={classes.boxColorLime}></div>
<div
style={{ paddingLeft: '10px', paddingRight: '20px' }}
>
On time morning
</div>
</Box>
<Box className={classes.boxContainer} display="flex">
<div className={classes.boxColorRed}></div>
<div
style={{ paddingLeft: '10px', paddingRight: '20px' }}
>
Late morning
</div>
</Box>
<Box className={classes.boxContainer} display="flex">
<div className={classes.boxColorTeal}></div>
<div
style={{ paddingLeft: '10px', paddingRight: '20px' }}
>
On time afternoon
</div>
</Box>
<Box className={classes.boxContainer} display="flex">
<div className={classes.boxColorOrange}></div>
<div style={{ paddingLeft: '10px' }}>
Late afternoon
</div>
</Box>
</Box>
</Box>
</Tabs.Panel>
<Tabs.Panel value="detail">
<Box style={{ marginTop: 8 }}>
<DataTableAll
data={dataSummaryTracking.value}
columns={columnsDetailWorking}
size=""
height={300}
keyHighlight={'isLate'}
/>
</Box>
</Tabs.Panel>
</Tabs>
</Box>
)}
<Box className={classes.pjParticipatingContainer}>
<Title order={4}>Project Participating</Title>
</Box>
<Box className={classes.boxContainer} display="flex">
{loadingPJParticipating ? (
<Box
style={{
width: '100%',
display: loadingPJParticipating ? 'block' : 'none',
}}
>
<Box
style={{
marginTop: '10%',
textAlign: 'center',
// display: 'none',
}}
>
<Loader size={'sm'} color="green" type="bars" m={'0 auto'} />
<Text fw={600} c={'gray'}>
Analyzing . . .
</Text>
</Box>
</Box>
) : (
<DataTableAll
data={dataPJParticipating}
columns={columnsPJParticipating}
size=""
height={300}
/>
)}
</Box>
</Tabs.Panel>
</Tabs>
{/* Add/Edit User modal */}
<Modal
opened={action === 'add' || action === 'edit'}
onClose={() => {
setAction('')
form.reset()
}}
title={
<Text pl={'sm'} fw={700} fz={'lg'}>
{action === 'add' ? 'Add Review' : 'Update Review'}
</Text>
}
>
<form
onSubmit={form.onSubmit(async (values) => {
setDisableBtn(true)
action === 'edit'
? await handleUpdate(values)
: await handleCreate(values)
setDisableBtn(false)
})}
>
<Box pl={'md'} pr={'md'}>
<TextInput
placeholder="Input name"
label={
<span>
Name project: <span style={{ color: 'red' }}>*</span>
</span>
}
mb={'md'}
value={form.values.name}
error={form.errors.name}
onChange={(e) => form.setFieldValue('name', e.target.value)}
/>
<TextInput
placeholder="Input role"
label={
<span>
Role: <span style={{ color: 'red' }}>*</span>
</span>
}
mb={'md'}
value={form.values.role}
error={form.errors.role}
onChange={(e) => form.setFieldValue('role', e.target.value)}
/>
<Textarea
placeholder="Input notes"
rows={4}
label={
<span>
Note: <span style={{ color: 'red' }}>*</span>
</span>
}
mb={'md'}
value={form.values.note}
error={form.errors.note}
onChange={(e) => form.setFieldValue('note', e.target.value)}
/>
<Box ta={'center'}>
{action === 'add' ? (
<Button
mt={'lg'}
bg={'green'}
type="submit"
disabled={disableBtn}
>
Create
</Button>
) : (
<Button
mt={'lg'}
bg={'green'}
type="submit"
disabled={disableBtn}
>
Save
</Button>
)}
</Box>
</Box>
</form>
</Modal>
<Dialog
className={classes.dialog}
opened={action === 'delete'}
withCloseButton
onClose={() => setAction('')}
size="lg"
radius="md"
position={{ top: 30, right: 10 }}
>
<Text className={classes.dialogText} size="sm" mb="xs" fw={500}>
Do you want to delete this review?
<Group justify="center" m={10}>
<Button
disabled={activeBtn}
fw={700}
size="xs"
variant="light"
onClick={async () => {
setActiveBtn(true)
await handleDelete(item.id)
setActiveBtn(false)
setAction('')
}}
>
Yes
</Button>
<Button
fw={700}
size="xs"
variant="light"
onClick={() => setAction('')}
>
Cancel
</Button>
</Group>
</Text>
</Dialog>
</div>
)
}
export default StaffEvaluation