Merge pull request 'Sprint-4/MS-36-FE-Technical' (#63) from Sprint-4/MS-36-FE-Technical into master
Reviewed-on: #63
This commit is contained in:
commit
67516faa3d
|
|
@ -76,9 +76,17 @@ export const getProfilesData = API_URL + 'v1/admin/criterias/profiles-data'
|
|||
export const updateProfilesData =
|
||||
API_URL + 'v1/admin/criterias/profiles-data/update'
|
||||
|
||||
export const listUserTechnical = API_URL + 'v1/admin/technical/get-tech-of-user'
|
||||
export const updateUserTechnical = API_URL + 'v1/admin/technical/technicals-user/update'
|
||||
|
||||
export const getAllUser = API_URL + 'v1/admin/technical/get-all-user'
|
||||
export const getAllTechByUserId =
|
||||
API_URL + 'v1/admin/technical/get-tech-by-user-id'
|
||||
|
||||
export const evaluation = API_URL + 'v1/admin/evaluation/report'
|
||||
export const sprintReview = API_URL + 'v1/admin/evaluation/sprint-review'
|
||||
|
||||
//Technical
|
||||
export const listTechnical = API_URL + 'v1/admin/technical/get-all'
|
||||
export const createTechnical = API_URL + 'v1/admin/technical/create'
|
||||
export const deleteTechnical = API_URL + 'v1/admin/technical/delete'
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import {
|
|||
IconQrcode,
|
||||
IconReport,
|
||||
IconScan,
|
||||
IconSettings,
|
||||
IconSun,
|
||||
IconTicket,
|
||||
IconUsersGroup,
|
||||
|
|
@ -132,6 +133,12 @@ const data = [
|
|||
permissions: 'admin',
|
||||
group: 'admin',
|
||||
},
|
||||
{
|
||||
link: '/organization-settings',
|
||||
label: 'Organization Settings',
|
||||
icon: IconSettings,
|
||||
group: 'admin',
|
||||
},
|
||||
// { link: '/jira', label: 'Jira', icon: IconSubtask },
|
||||
// { link: '/custom-theme', label: 'Custom Theme', icon: IconBrush },
|
||||
// { link: '/general-setting', label: 'General Setting', icon: IconSettings },
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
.title {
|
||||
background-color: light-dark(var(white), var(--mantine-color-dark-7));
|
||||
z-index: 100;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 var(--mantine-spacing-sm) var(--mantine-spacing-lg)
|
||||
var(--mantine-spacing-sm);
|
||||
border-bottom: solid rgba(201, 201, 201, 0.377) 1px;
|
||||
}
|
||||
|
|
@ -0,0 +1,322 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Dialog,
|
||||
Flex,
|
||||
Group,
|
||||
Loader,
|
||||
Modal,
|
||||
Tabs,
|
||||
Text,
|
||||
TextInput,
|
||||
} from '@mantine/core'
|
||||
import classes from './OrganizationSettings.module.css'
|
||||
import DataTableAll from '@/components/DataTable/DataTable'
|
||||
import { get, post } from '@/rtk/helpers/apiService'
|
||||
import { notifications } from '@mantine/notifications'
|
||||
import { createTechnical, deleteTechnical, listTechnical } from '@/api/Admin'
|
||||
import { useForm } from '@mantine/form'
|
||||
import { Xdelete } from '@/rtk/helpers/CRUD'
|
||||
import moment from 'moment'
|
||||
|
||||
interface DataTechnical {
|
||||
id: number
|
||||
name: string
|
||||
level: number
|
||||
point: number
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
function OrganizationSettings() {
|
||||
const [activeTab, setActiveTab] = useState<string | null>('technical')
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [addTechnicalOpen, setAddTechnicalOpen] = useState(false)
|
||||
const [deleteTechnicalOpen, setDeleteTechnicalOpen] = useState(false)
|
||||
const [selectedId, setSelectedId] = useState(0)
|
||||
|
||||
const [dataTechnical, setDataTechnical] = useState<DataTechnical[]>([])
|
||||
|
||||
const form = useForm({
|
||||
initialValues: {
|
||||
name: '',
|
||||
level: '',
|
||||
},
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
await getListTechnical()
|
||||
}
|
||||
fetchData()
|
||||
}, [])
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: 'level',
|
||||
size: '5%',
|
||||
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: '40%',
|
||||
header: 'Name',
|
||||
},
|
||||
{
|
||||
name: 'created_at',
|
||||
size: '40%',
|
||||
header: 'Created at',
|
||||
render: (row: any) => {
|
||||
return (
|
||||
<Box>{moment(row?.created_at).format('HH:mm:ss DD/MM/YYYY')}</Box>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'action',
|
||||
size: '15%',
|
||||
header: 'Action',
|
||||
render: (row: any) => {
|
||||
return (
|
||||
<Flex justify="center">
|
||||
<Button
|
||||
color="red"
|
||||
onClick={() => {
|
||||
setDeleteTechnicalOpen(true)
|
||||
setSelectedId(row?.id)
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
</Flex>
|
||||
)
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const getListTechnical = async () => {
|
||||
try {
|
||||
setIsLoading(true)
|
||||
const params = {}
|
||||
const res = await get(listTechnical, params)
|
||||
if (res.status) {
|
||||
setDataTechnical(res.data)
|
||||
}
|
||||
} catch (error: any) {
|
||||
notifications.show({
|
||||
title: 'Error',
|
||||
message: error.message ?? error,
|
||||
color: 'red',
|
||||
})
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
const handleCreate = async (values: any) => {
|
||||
try {
|
||||
const { id, ...data } = values
|
||||
const res = await post(createTechnical, data)
|
||||
if (res.status === true) {
|
||||
setAddTechnicalOpen(false)
|
||||
form.reset()
|
||||
await getListTechnical()
|
||||
|
||||
notifications.show({
|
||||
title: 'Success',
|
||||
message: res.message,
|
||||
color: 'green',
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
const handleDelete = async (id: number) => {
|
||||
try {
|
||||
await Xdelete(deleteTechnical, { id: id }, getListTechnical)
|
||||
setSelectedId(0)
|
||||
setDeleteTechnicalOpen(false)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={classes.title}>
|
||||
<h3>
|
||||
<Text>Admin/</Text>
|
||||
Staff Evaluation
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<Box w="100%" display={'flex'} mt={15} ml={10}>
|
||||
<Tabs w="100%" value={activeTab} onChange={setActiveTab}>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab value="technical">Technical setting</Tabs.Tab>
|
||||
<Tabs.Tab value="second">Setting 2</Tabs.Tab>
|
||||
<Tabs.Tab value="third">Setting 3</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
|
||||
<Tabs.Panel value="technical" pt="xs">
|
||||
<Box mt={'md'} p={16}>
|
||||
<Text fw={500}>Note: </Text>
|
||||
|
||||
<Flex gap={8}>
|
||||
<Box p={8} bg="#d9d2e9">
|
||||
<span style={{ fontWeight: 500 }}>Level 1:</span> 3-12 Month
|
||||
</Box>
|
||||
<Box p={8} bg="#ffd966">
|
||||
<span style={{ fontWeight: 500 }}>Level 2:</span> 3-5 Year
|
||||
</Box>
|
||||
<Box p={8} bg="#cfe2f3">
|
||||
<span style={{ fontWeight: 500 }}>Level 3:</span> 5 -8 Year
|
||||
</Box>
|
||||
</Flex>
|
||||
</Box>
|
||||
|
||||
<Box mt={'md'}>
|
||||
{isLoading ? (
|
||||
<Box
|
||||
style={{
|
||||
marginTop: '10%',
|
||||
textAlign: 'center',
|
||||
display: 'block',
|
||||
}}
|
||||
>
|
||||
<Loader size={'sm'} color="green" type="bars" m={'0 auto'} />
|
||||
<Text fw={600} c={'gray'} mt={8}>
|
||||
Loading Technical...
|
||||
</Text>
|
||||
</Box>
|
||||
) : (
|
||||
<DataTableAll
|
||||
data={dataTechnical}
|
||||
columns={columns}
|
||||
size=""
|
||||
searchInput
|
||||
infoTotal={
|
||||
<Button onClick={() => setAddTechnicalOpen(true)}>
|
||||
+ Add
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Tabs.Panel>
|
||||
|
||||
<Tabs.Panel value="second" pt="xs">
|
||||
Setting 2
|
||||
</Tabs.Panel>
|
||||
|
||||
<Tabs.Panel value="third" pt="xs">
|
||||
Setting 3
|
||||
</Tabs.Panel>
|
||||
</Tabs>
|
||||
</Box>
|
||||
|
||||
<Modal
|
||||
opened={addTechnicalOpen}
|
||||
onClose={() => {
|
||||
setAddTechnicalOpen(false)
|
||||
form.reset()
|
||||
}}
|
||||
title={
|
||||
<Text pl={'sm'} fw={700} fz={'lg'}>
|
||||
Add Technical
|
||||
</Text>
|
||||
}
|
||||
>
|
||||
<form
|
||||
onSubmit={form.onSubmit(async (values) => {
|
||||
await handleCreate(values)
|
||||
})}
|
||||
>
|
||||
<Box pl={'md'} pr={'md'}>
|
||||
<TextInput
|
||||
label="Name"
|
||||
mb={'md'}
|
||||
value={form.values.name}
|
||||
error={form.errors.name}
|
||||
onChange={(e) => form.setFieldValue('name', e.target.value)}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label="Level"
|
||||
mb={'md'}
|
||||
value={form.values.level}
|
||||
error={form.errors.level}
|
||||
onChange={(e) => form.setFieldValue('level', e.target.value)}
|
||||
/>
|
||||
|
||||
<Box ta={'center'}>
|
||||
<Button mt={'lg'} bg={'green'} type="submit">
|
||||
Create
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</form>
|
||||
</Modal>
|
||||
|
||||
<Dialog
|
||||
opened={deleteTechnicalOpen}
|
||||
className={classes.dialog}
|
||||
withCloseButton
|
||||
onClose={() => setDeleteTechnicalOpen(false)}
|
||||
size="lg"
|
||||
radius="md"
|
||||
position={{ top: 30, right: 10 }}
|
||||
>
|
||||
<Box className={classes.dialogText} size="sm" mb="xs" fw={500}>
|
||||
Do you want to delete this technical?
|
||||
<Group justify="center" m={10}>
|
||||
<Button
|
||||
fw={700}
|
||||
size="xs"
|
||||
variant="filled"
|
||||
color="red"
|
||||
onClick={async () => handleDelete(selectedId)}
|
||||
>
|
||||
Yes
|
||||
</Button>
|
||||
<Button
|
||||
fw={700}
|
||||
size="xs"
|
||||
variant="filled"
|
||||
color="gray"
|
||||
onClick={() => setDeleteTechnicalOpen(false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</Group>
|
||||
</Box>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default OrganizationSettings
|
||||
|
|
@ -1,4 +1,9 @@
|
|||
import { getProfilesData, updateProfilesData } from '@/api/Admin'
|
||||
import {
|
||||
getProfilesData,
|
||||
listUserTechnical,
|
||||
updateProfilesData,
|
||||
updateUserTechnical,
|
||||
} from '@/api/Admin'
|
||||
import { changePassword } from '@/api/Auth'
|
||||
import PasswordRequirementInput from '@/components/PasswordRequirementInput/PasswordRequirementInput'
|
||||
import ProjectInvolvement from '@/components/ProjectInvolvement/ProjectInvolvement'
|
||||
|
|
@ -12,6 +17,8 @@ import {
|
|||
Avatar,
|
||||
Box,
|
||||
Button,
|
||||
Flex,
|
||||
Loader,
|
||||
Modal,
|
||||
PasswordInput,
|
||||
Text,
|
||||
|
|
@ -19,12 +26,32 @@ import {
|
|||
Title,
|
||||
} from '@mantine/core'
|
||||
import { notifications } from '@mantine/notifications'
|
||||
import { IconPasswordUser } from '@tabler/icons-react'
|
||||
import {
|
||||
IconPasswordUser,
|
||||
IconUserCode,
|
||||
IconUserCog,
|
||||
} from '@tabler/icons-react'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import classes from './Profile.module.css'
|
||||
import DataTableAll from '@/components/DataTable/DataTable'
|
||||
import moment from 'moment'
|
||||
|
||||
const isCompactMenu = false
|
||||
|
||||
interface DataTechnical {
|
||||
id: number
|
||||
name: string
|
||||
level: number
|
||||
point: number
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
interface UpdateDataTechnical {
|
||||
technical_id: number | string
|
||||
point: number | string
|
||||
}
|
||||
|
||||
const Profile = () => {
|
||||
const user = useAppSelector((state) => state.authentication.user)
|
||||
const userData = getUser()
|
||||
|
|
@ -35,11 +62,22 @@ const Profile = () => {
|
|||
new_password: '',
|
||||
confirm_password: '',
|
||||
})
|
||||
|
||||
const [swapTap, setSwapTab] = useState(false)
|
||||
|
||||
const [avatar, setAvatar] = useState(user.user.avatar)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [dataProfile, setDataProfile] = useState<any>([])
|
||||
const [countSpam, setCountSpam] = useState(0)
|
||||
|
||||
const [dataTechnical, setDataTechnical] = useState<DataTechnical[]>([])
|
||||
const [loadingTechnical, setLoadingTechnical] = useState(false)
|
||||
const [isUpdateTechnical, setIsUpdateTechnical] = useState(false)
|
||||
|
||||
const [updatedDataTechnical, setUpdatedDataTechnical] = useState<
|
||||
UpdateDataTechnical[]
|
||||
>([])
|
||||
|
||||
const [selectedAvatar, setSelectedAvatar] = useState<string | null>(null)
|
||||
const navigate = useNavigate()
|
||||
const dispatch = useAppDispatch()
|
||||
|
|
@ -183,6 +221,142 @@ const Profile = () => {
|
|||
dispatch(logout(navigate))
|
||||
}, [dispatch, navigate])
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
await getListUserTechnical()
|
||||
}
|
||||
fetchData()
|
||||
}, [])
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: 'level',
|
||||
size: '5%',
|
||||
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: '50%',
|
||||
header: 'Name',
|
||||
render: (row: any) => {
|
||||
return <Text ta="start">{row?.name}</Text>
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'point',
|
||||
size: '5%',
|
||||
header: 'Point',
|
||||
render: (row: any) => {
|
||||
return (
|
||||
<TextInput
|
||||
mb={'md'}
|
||||
value={
|
||||
updatedDataTechnical.find(
|
||||
(technicalItem: UpdateDataTechnical) =>
|
||||
technicalItem.technical_id === row?.id,
|
||||
)?.point
|
||||
}
|
||||
onChange={(e) => {
|
||||
setUpdatedDataTechnical((prev: any) =>
|
||||
prev.map((technicalItem: UpdateDataTechnical) => {
|
||||
if (technicalItem.technical_id === row.id) {
|
||||
return {
|
||||
...technicalItem,
|
||||
point: e.target.value,
|
||||
}
|
||||
}
|
||||
|
||||
return technicalItem
|
||||
}),
|
||||
)
|
||||
setIsUpdateTechnical(true)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'updated_at',
|
||||
size: '40%',
|
||||
header: 'Last update',
|
||||
render: (row: any) => {
|
||||
return (
|
||||
<Text ta="start">
|
||||
{moment(row?.updated_at).format('HH:mm:ss DD/MM/YYYY')}
|
||||
</Text>
|
||||
)
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const getListUserTechnical = async () => {
|
||||
try {
|
||||
setLoadingTechnical(true)
|
||||
const params = {}
|
||||
const res = await get(listUserTechnical, params)
|
||||
if (res.status) {
|
||||
setDataTechnical(res.data)
|
||||
setUpdatedDataTechnical(
|
||||
res.data?.map((technicalItem: DataTechnical) => {
|
||||
return {
|
||||
technical_id: technicalItem.id,
|
||||
point: technicalItem.point,
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
} catch (error: any) {
|
||||
notifications.show({
|
||||
title: 'Error',
|
||||
message: error.message ?? error,
|
||||
color: 'red',
|
||||
})
|
||||
} finally {
|
||||
setLoadingTechnical(false)
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
const handleUpdateTechnical = async () => {
|
||||
try {
|
||||
const res = await post(updateUserTechnical, {
|
||||
technicals: updatedDataTechnical,
|
||||
})
|
||||
if (res.status === true) {
|
||||
await getListUserTechnical()
|
||||
|
||||
notifications.show({
|
||||
title: 'Success',
|
||||
message: res.message,
|
||||
color: 'green',
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={classes.title}>
|
||||
|
|
@ -281,28 +455,119 @@ const Profile = () => {
|
|||
display: 'flex',
|
||||
flexFlow: 'column',
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
}}
|
||||
mt={10}
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
className={classes.link}
|
||||
<Button
|
||||
style={{ width: '50%' }}
|
||||
onClick={() => setOpened(true)}
|
||||
color="green"
|
||||
>
|
||||
<IconPasswordUser className={classes.linkIcon} stroke={1.5} />
|
||||
<span
|
||||
className={`${classes.itemLabel} ${classes.labelCompactMenu}`}
|
||||
<IconPasswordUser stroke={1.5} />
|
||||
Change password
|
||||
</Button>
|
||||
|
||||
{swapTap ? (
|
||||
<Button
|
||||
style={{ width: '50%' }}
|
||||
onClick={() => setSwapTab(!swapTap)}
|
||||
>
|
||||
Change password
|
||||
</span>
|
||||
</a>
|
||||
<IconUserCode stroke={1.5} />
|
||||
Project Involved
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
style={{ width: '50%' }}
|
||||
onClick={() => setSwapTab(!swapTap)}
|
||||
>
|
||||
<IconUserCog stroke={1.5} />
|
||||
Your Technical
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box className={classes.projectInvolvement}>
|
||||
<Title order={3}>Project Involved</Title>
|
||||
<ProjectInvolvement dataProfile={dataProfile} page="profile" />
|
||||
</Box>
|
||||
{swapTap ? (
|
||||
<Box className={classes.projectInvolvement}>
|
||||
<Flex justify="space-between" wrap="wrap">
|
||||
<Box px={16} ta="start">
|
||||
<Text fw={500}>Level: </Text>
|
||||
|
||||
<Flex gap={8}>
|
||||
<Box p={8} bg="#d9d2e9">
|
||||
<span style={{ fontWeight: 500 }}>1:</span> 3-12 Month
|
||||
</Box>
|
||||
<Box p={8} bg="#ffd966">
|
||||
<span style={{ fontWeight: 500 }}>2:</span> 3-5 Year
|
||||
</Box>
|
||||
<Box p={8} bg="#cfe2f3">
|
||||
<span style={{ fontWeight: 500 }}>3:</span> 5 -8 Year
|
||||
</Box>
|
||||
</Flex>
|
||||
</Box>
|
||||
|
||||
<Box px={16} ta="start">
|
||||
<Text fw={500}>Point: </Text>
|
||||
|
||||
<Flex gap={8}>
|
||||
<Box p={8} bg="#FFEA00">
|
||||
<span style={{ fontWeight: 500 }}>0:</span> Unknown
|
||||
</Box>
|
||||
<Box p={8} bg="#FFEA00">
|
||||
<span style={{ fontWeight: 500 }}>1:</span> Basic
|
||||
</Box>
|
||||
<Box p={8} bg="#FFEA00">
|
||||
<span style={{ fontWeight: 500 }}>2:</span> Advanced
|
||||
</Box>
|
||||
<Box p={8} bg="#FFEA00">
|
||||
<span style={{ fontWeight: 500 }}>3:</span> Master
|
||||
</Box>
|
||||
</Flex>
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
<Flex justify="space-between" mt={'lg'}>
|
||||
<div></div>
|
||||
<Title order={3}>Technicals</Title>
|
||||
|
||||
<Button
|
||||
disabled={loadingTechnical || !isUpdateTechnical}
|
||||
onClick={handleUpdateTechnical}
|
||||
>
|
||||
Update
|
||||
</Button>
|
||||
</Flex>
|
||||
|
||||
{loadingTechnical ? (
|
||||
<Box
|
||||
style={{
|
||||
width: '100%',
|
||||
marginTop: '10%',
|
||||
textAlign: 'center',
|
||||
display: 'block',
|
||||
}}
|
||||
>
|
||||
<Loader size={'sm'} color="green" type="bars" m={'0 auto'} />
|
||||
<Text fw={600} c={'gray'} mt={8}>
|
||||
Loading Technical...
|
||||
</Text>
|
||||
</Box>
|
||||
) : (
|
||||
<DataTableAll
|
||||
data={dataTechnical}
|
||||
columns={columns}
|
||||
size=""
|
||||
searchInput
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
) : (
|
||||
<Box className={classes.projectInvolvement}>
|
||||
<Title order={3}>Project Involved</Title>
|
||||
<ProjectInvolvement dataProfile={dataProfile} page="profile" />
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Modal
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import Allocation from '@/pages/Allocation/Allocation'
|
|||
import PageLogin from '@/pages/Auth/Login/Login'
|
||||
import LeaveManagement from '@/pages/LeaveManagement/LeaveManagement'
|
||||
import PageNotFound from '@/pages/NotFound/NotFound'
|
||||
import OrganizationSettings from '@/pages/OrganizationSettings/OrganizationSettings'
|
||||
import Profile from '@/pages/Profile/Profile'
|
||||
import SprintReview from '@/pages/SprintReview/SprintReview'
|
||||
import StaffEvaluation from '@/pages/StaffEvaluation/StaffEvaluation'
|
||||
|
|
@ -219,6 +220,20 @@ const mainRoutes = [
|
|||
</ProtectedRoute>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: '/organization-settings',
|
||||
element: (
|
||||
<ProtectedRoute mode="route" permission="admin">
|
||||
<BasePage
|
||||
main={
|
||||
<>
|
||||
<OrganizationSettings />
|
||||
</>
|
||||
}
|
||||
></BasePage>
|
||||
</ProtectedRoute>
|
||||
),
|
||||
},
|
||||
// {
|
||||
// path: '/packages',
|
||||
// element: (
|
||||
|
|
|
|||
Loading…
Reference in New Issue