master #93

Merged
joseph merged 17 commits from master into dev 2024-09-25 11:03:08 +10:00
2 changed files with 337 additions and 306 deletions

View File

@ -21,6 +21,43 @@ import { useForm } from '@mantine/form'
import { Xdelete } from '@/rtk/helpers/CRUD'
import moment from 'moment'
function OrganizationSettings() {
const [activeTab, setActiveTab] = useState<string | null>('technical')
return (
<div>
<div className={classes.title}>
<h3>
<Text>Admin/</Text>
Organization Settings
</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">
<TechnicalSettingTab />
</Tabs.Panel>
<Tabs.Panel value="second" pt="xs">
Setting 2
</Tabs.Panel>
<Tabs.Panel value="third" pt="xs">
Setting 3
</Tabs.Panel>
</Tabs>
</Box>
</div>
)
}
interface DataTechnical {
id: number
name: string
@ -29,15 +66,13 @@ interface DataTechnical {
updated_at: string
}
function OrganizationSettings() {
const [activeTab, setActiveTab] = useState<string | null>('technical')
const TechnicalSettingTab = () => {
const [dataTechnical, setDataTechnical] = useState<DataTechnical[]>([])
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: '',
@ -169,77 +204,48 @@ function OrganizationSettings() {
}
return (
<div>
<div className={classes.title}>
<h3>
<Text>Admin/</Text>
Staff Evaluation
</h3>
</div>
<>
<Box mt={'md'} p={16}>
<Text fw={500}>Note: </Text>
<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>
<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>
<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 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>
<Modal
@ -320,7 +326,7 @@ function OrganizationSettings() {
</Group>
</Box>
</Dialog>
</div>
</>
)
}

View File

@ -27,6 +27,7 @@ import {
} from '@mantine/core'
import { notifications } from '@mantine/notifications'
import {
IconExchange,
IconPasswordUser,
IconUserCode,
IconUserCog,
@ -39,19 +40,6 @@ 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()
@ -70,14 +58,6 @@ const Profile = () => {
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()
@ -221,144 +201,6 @@ 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) => {
if (row?.updated_at) {
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}>
@ -491,79 +333,7 @@ const 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>
<UserTechnical />
) : (
<Box className={classes.projectInvolvement}>
<Title order={3}>Project Involved</Title>
@ -672,4 +442,259 @@ const Profile = () => {
)
}
// User Technical
interface DataTechnical {
id: number
name: string
level: number
point: number
updated_at: string
}
interface UpdateDataTechnical {
technical_id: number | string
point: number | string
}
const UserTechnical = () => {
const [dataTechnical, setDataTechnical] = useState<DataTechnical[]>([])
const [loadingTechnical, setLoadingTechnical] = useState(false)
const [isUpdateTechnical, setIsUpdateTechnical] = useState<
string[] | number[]
>([])
const [updatedDataTechnical, setUpdatedDataTechnical] = useState<
UpdateDataTechnical[]
>([])
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: '45%',
header: 'Name',
render: (row: any) => {
return <Text ta="start">{row?.name}</Text>
},
},
{
name: 'point',
size: '10%',
header: 'Point',
render: (row: any) => {
return (
<TextInput
mb={'md'}
value={
updatedDataTechnical.find(
(technicalItem: UpdateDataTechnical) =>
technicalItem.technical_id === row?.id,
)?.point
}
rightSection={
isUpdateTechnical.some(
(item: string | number) => item === row.id,
) ? (
<IconExchange size={16} color="#1c7ed6" />
) : (
''
)
}
onChange={(e) => {
const value = e.target.value
// Ensure the input is between 0 and 3
if (value === '' || (Number(value) >= 0 && Number(value) <= 3)) {
setUpdatedDataTechnical((prev: any) =>
prev.map((technicalItem: UpdateDataTechnical) => {
if (technicalItem.technical_id === row.id) {
return {
...technicalItem,
point: value,
}
}
return technicalItem
}),
)
setIsUpdateTechnical((prev) => [...prev, row?.id])
}
}}
onFocus={(e) => e.target.select()}
/>
)
},
},
{
name: 'updated_at',
size: '40%',
header: 'Last update',
render: (row: any) => {
if (row?.updated_at) {
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 handleUpdateUserTechnical = 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 (
<Box className={classes.projectInvolvement}>
<Flex justify="space-between" wrap="wrap">
{/* Level */}
<Box px={16} ta="start">
<Text fw={500}>Level: </Text>
<Flex gap={8} wrap="wrap">
<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>
{/* Point */}
<Box px={16} ta="start" mt={{ base: 8, lg: 0 }}>
<Text fw={500}>Point: </Text>
<Flex gap={8} wrap="wrap">
<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.length === 0}
onClick={handleUpdateUserTechnical}
>
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>
)
}
export default Profile