update custom add worklog
This commit is contained in:
parent
e7e81dead7
commit
0ea97cb0c5
|
|
@ -86,7 +86,7 @@ class TimekeepingController extends Controller
|
|||
]
|
||||
]);
|
||||
}
|
||||
|
||||
$this->createOrUpdateRecordForCurrentMonth($month, $year);
|
||||
return response()->json(['status' => true, 'message' => 'Add successfully']);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,29 @@
|
|||
import { getTheTimesheet, updateMultipleUserWorkingTime, updateWorkingDays } from '@/api/Admin'
|
||||
import {
|
||||
getTheTimesheet,
|
||||
updateMultipleUserWorkingTime,
|
||||
updateWorkingDays,
|
||||
} from '@/api/Admin'
|
||||
import { update } from '@/rtk/helpers/CRUD'
|
||||
import { get } from '@/rtk/helpers/apiService'
|
||||
import { Box, Button, Image, Menu, Select, Table, Text, TextInput, Tooltip } from '@mantine/core'
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Drawer,
|
||||
Image,
|
||||
Menu,
|
||||
MultiSelect,
|
||||
Select,
|
||||
Table,
|
||||
Text,
|
||||
TextInput,
|
||||
Tooltip
|
||||
} from '@mantine/core'
|
||||
import { useDisclosure } from '@mantine/hooks'
|
||||
import { notifications } from '@mantine/notifications'
|
||||
import { IconCheck, IconExclamationMark, IconX } from '@tabler/icons-react'
|
||||
import moment from 'moment'
|
||||
import { useEffect, useState } from 'react'
|
||||
import classes from './Timekeeping.module.css'
|
||||
import moment from 'moment'
|
||||
|
||||
interface User {
|
||||
id: number
|
||||
|
|
@ -42,9 +59,15 @@ interface UserData {
|
|||
}
|
||||
|
||||
const Timekeeping = () => {
|
||||
const [opened, { open, close }] = useDisclosure(false)
|
||||
const [daysInMonth, setDaysInMonth] = useState(
|
||||
Array.from({ length: 31 }, (_, index) => index + 1),
|
||||
)
|
||||
const [customAddData, setCustomAddData] = useState<{data:string[], type: string, day: number}>({
|
||||
data: [],
|
||||
type: '',
|
||||
day: 0
|
||||
})
|
||||
const [workingDays, setWorkingDays] = useState(30)
|
||||
const [data, setData] = useState<UserData[]>([])
|
||||
const [date, setDate] = useState({
|
||||
|
|
@ -60,9 +83,7 @@ const Timekeeping = () => {
|
|||
})
|
||||
if (res.status) {
|
||||
setData(
|
||||
res.data.filter((u: UserData) =>
|
||||
u.user.permission.includes('staff'),
|
||||
),
|
||||
res.data.filter((u: UserData) => u.user.permission.includes('staff')),
|
||||
)
|
||||
setDaysInMonth(
|
||||
Array.from({ length: getDaysInMonth() }, (_, index) => index + 1),
|
||||
|
|
@ -102,27 +123,39 @@ const Timekeeping = () => {
|
|||
return days.getDate()
|
||||
}
|
||||
|
||||
const updateMultipleUser = async(users:number[], day:number, type:string)=>{
|
||||
const updateMultipleUser = async (
|
||||
users: number[],
|
||||
day: number,
|
||||
type: string,
|
||||
) => {
|
||||
try {
|
||||
await update(updateMultipleUserWorkingTime, {
|
||||
users: users,
|
||||
year: date.year,
|
||||
month: date.month,
|
||||
day:day,
|
||||
type: type
|
||||
}, getTimeSheet)
|
||||
await update(
|
||||
updateMultipleUserWorkingTime,
|
||||
{
|
||||
users: users,
|
||||
year: date.year,
|
||||
month: date.month,
|
||||
day: day,
|
||||
type: type,
|
||||
},
|
||||
getTimeSheet,
|
||||
)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
const handleUpdateWorkingDays = async()=>{
|
||||
const handleUpdateWorkingDays = async () => {
|
||||
try {
|
||||
await update(updateWorkingDays, {
|
||||
working_days: workingDays,
|
||||
year: date.year,
|
||||
month: date.month
|
||||
}, getTimeSheet)
|
||||
await update(
|
||||
updateWorkingDays,
|
||||
{
|
||||
working_days: workingDays,
|
||||
year: date.year,
|
||||
month: date.month,
|
||||
},
|
||||
getTimeSheet,
|
||||
)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
|
|
@ -132,6 +165,7 @@ const Timekeeping = () => {
|
|||
getTimeSheet()
|
||||
}, [date])
|
||||
|
||||
console.log(customAddData)
|
||||
return (
|
||||
<div>
|
||||
<div className={classes.title}>
|
||||
|
|
@ -140,24 +174,58 @@ const Timekeeping = () => {
|
|||
Timekeeping
|
||||
</h3>
|
||||
</div>
|
||||
<Drawer
|
||||
opened={opened}
|
||||
onClose={close}
|
||||
position="right"
|
||||
title={<strong>Add custom worklog</strong>}
|
||||
>
|
||||
<MultiSelect
|
||||
mb={'md'}
|
||||
searchable
|
||||
label="User(s)"
|
||||
data={data.map((user) => {
|
||||
return { value: user.user.id.toString(), label: user.user.name }
|
||||
})}
|
||||
onChange={(e)=>{setCustomAddData({...customAddData, data: e})}}
|
||||
/>
|
||||
<Select
|
||||
mb={'md'}
|
||||
label="Type"
|
||||
data={[
|
||||
{ value: 'half', label: 'Half day' },
|
||||
{ value: 'one', label: 'A day' },
|
||||
]}
|
||||
onChange={(e)=>{setCustomAddData({...customAddData, type: e!})}}
|
||||
/>
|
||||
<Button onClick={()=>{
|
||||
if(customAddData.type === "" || customAddData.data.length === 0 || customAddData.day === 0){
|
||||
notifications.show({
|
||||
title: 'Error',
|
||||
message: "Input data required",
|
||||
color: 'red',
|
||||
})
|
||||
}else{
|
||||
updateMultipleUser(customAddData.data.map((u)=>parseInt(u)), customAddData.day, customAddData.type)
|
||||
}
|
||||
}}>Submit</Button>
|
||||
</Drawer>
|
||||
<Box display={'flex'}>
|
||||
<Box style={{display:"flex", flexFlow:"column"}} w={'30%'}>
|
||||
<Box style={{ display: 'flex', flexFlow: 'column' }} w={'30%'}>
|
||||
<Box w="100%" display={'flex'}>
|
||||
<Select
|
||||
w="50%"
|
||||
value={date.month}
|
||||
size="xs"
|
||||
label="Month"
|
||||
data={Array.from({ length: 12 }, (_, index) =>
|
||||
{
|
||||
return {
|
||||
value: (1 + index).toString(),
|
||||
label:(1 + index).toString(),
|
||||
disabled: (1 + index) > parseInt(moment(Date.now()).format('MM'))
|
||||
}
|
||||
data={Array.from({ length: 12 }, (_, index) => {
|
||||
return {
|
||||
value: (1 + index).toString(),
|
||||
label: (1 + index).toString(),
|
||||
disabled:
|
||||
1 + index > parseInt(moment(Date.now()).format('MM')),
|
||||
}
|
||||
|
||||
)}
|
||||
})}
|
||||
onChange={(e) => {
|
||||
setDate({ ...date, month: e! })
|
||||
}}
|
||||
|
|
@ -168,29 +236,60 @@ const Timekeeping = () => {
|
|||
size="xs"
|
||||
ml={'sm'}
|
||||
label="Year"
|
||||
data={Array.from({ length: 10 }, (_, index) =>
|
||||
{
|
||||
return {
|
||||
value: (parseInt(moment(Date.now()).format('YYYY')) - 3 + index).toString(),
|
||||
label:(parseInt(moment(Date.now()).format('YYYY')) - 3 + index).toString(),
|
||||
disabled: (parseInt(moment(Date.now()).format('YYYY')) - 3 + index) > parseInt(moment(Date.now()).format('YYYY'))
|
||||
}
|
||||
data={Array.from({ length: 10 }, (_, index) => {
|
||||
return {
|
||||
value: (
|
||||
parseInt(moment(Date.now()).format('YYYY')) -
|
||||
3 +
|
||||
index
|
||||
).toString(),
|
||||
label: (
|
||||
parseInt(moment(Date.now()).format('YYYY')) -
|
||||
3 +
|
||||
index
|
||||
).toString(),
|
||||
disabled:
|
||||
parseInt(moment(Date.now()).format('YYYY')) - 3 + index >
|
||||
parseInt(moment(Date.now()).format('YYYY')),
|
||||
}
|
||||
)}
|
||||
})}
|
||||
onChange={(e) => {
|
||||
setDate({ ...date, year: e! })
|
||||
}}
|
||||
></Select>
|
||||
</Box>
|
||||
<Box display={'flex'} style={{alignItems:'end'}}>
|
||||
<TextInput type='number' size='xs' label="Working days" w={"20%"} value={workingDays} onChange={(e)=>{
|
||||
<Box display={'flex'} style={{ alignItems: 'end' }}>
|
||||
<TextInput
|
||||
type="number"
|
||||
size="xs"
|
||||
label="Working days"
|
||||
w={'20%'}
|
||||
value={workingDays}
|
||||
onChange={(e) => {
|
||||
setWorkingDays(parseFloat(e.target.value))
|
||||
}}/>
|
||||
<Tooltip label="Save working days"><Button size='xs' ml={'sm'} onClick={()=>handleUpdateWorkingDays()}>Save</Button></Tooltip>
|
||||
</Box>
|
||||
}}
|
||||
/>
|
||||
<Tooltip label="Save working days">
|
||||
<Button
|
||||
size="xs"
|
||||
ml={'sm'}
|
||||
onClick={() => handleUpdateWorkingDays()}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box w="70%" pl={200} style={{display:'flex', alignItems:'end', justifyContent:"space-evenly"}}>
|
||||
<Box style={{display:'flex', alignItems:'center'}}>
|
||||
<Box
|
||||
w="70%"
|
||||
pl={200}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'end',
|
||||
justifyContent: 'space-evenly',
|
||||
}}
|
||||
>
|
||||
<Box style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<IconCheck
|
||||
size={20}
|
||||
style={{
|
||||
|
|
@ -201,9 +300,11 @@ const Timekeeping = () => {
|
|||
fontWeight: 700,
|
||||
}}
|
||||
/>
|
||||
<Text ml={'sm'} fz='14px'>Work over 7 hours</Text>
|
||||
<Text ml={'sm'} fz="14px">
|
||||
Work over 7 hours
|
||||
</Text>
|
||||
</Box>
|
||||
<Box style={{display:'flex', alignItems:'center'}}>
|
||||
<Box style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<IconCheck
|
||||
size={20}
|
||||
style={{
|
||||
|
|
@ -214,9 +315,11 @@ const Timekeeping = () => {
|
|||
fontWeight: 700,
|
||||
}}
|
||||
/>
|
||||
<Text ml={'sm'} fz='14px'>Work over 3.5 hours</Text>
|
||||
<Text ml={'sm'} fz="14px">
|
||||
Work over 3.5 hours
|
||||
</Text>
|
||||
</Box>
|
||||
<Box style={{display:'flex', alignItems:'center'}}>
|
||||
<Box style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<IconExclamationMark
|
||||
size={20}
|
||||
style={{
|
||||
|
|
@ -227,9 +330,11 @@ const Timekeeping = () => {
|
|||
fontWeight: 700,
|
||||
}}
|
||||
/>
|
||||
<Text ml={'sm'} fz='14px'>Checked in</Text>
|
||||
<Text ml={'sm'} fz="14px">
|
||||
Checked in
|
||||
</Text>
|
||||
</Box>
|
||||
<Box style={{display:'flex', alignItems:'center'}}>
|
||||
<Box style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<IconX
|
||||
size={20}
|
||||
style={{
|
||||
|
|
@ -240,7 +345,9 @@ const Timekeeping = () => {
|
|||
fontWeight: 700,
|
||||
}}
|
||||
/>
|
||||
<Text ml={'sm'} fz='14px'>Off</Text>
|
||||
<Text ml={'sm'} fz="14px">
|
||||
Off
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
|
|
@ -260,23 +367,49 @@ const Timekeeping = () => {
|
|||
{daysInMonth.map((d) => {
|
||||
return (
|
||||
<Menu width={200} shadow="md">
|
||||
<Menu.Target>
|
||||
<Table.Th key={d} ta={'center'} style={{cursor:"pointer"}}>
|
||||
<Menu.Target>
|
||||
<Table.Th
|
||||
key={d}
|
||||
ta={'center'}
|
||||
style={{ cursor: 'pointer' }}
|
||||
>
|
||||
<span>{d}</span>
|
||||
</Table.Th>
|
||||
</Menu.Target>
|
||||
</Table.Th>
|
||||
</Menu.Target>
|
||||
|
||||
<Menu.Dropdown>
|
||||
<Menu.Item onClick={()=>updateMultipleUser(data.map((u)=>u.user.id), d, 'half')}>
|
||||
+ Add half a day's work
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
onClick={()=>updateMultipleUser(data.map((u)=>u.user.id), d, 'one')}
|
||||
>
|
||||
+ Add 1 day of work
|
||||
</Menu.Item>
|
||||
</Menu.Dropdown>
|
||||
</Menu>
|
||||
<Menu.Dropdown>
|
||||
<Menu.Item
|
||||
onClick={() =>
|
||||
updateMultipleUser(
|
||||
data.map((u) => u.user.id),
|
||||
d,
|
||||
'half',
|
||||
)
|
||||
}
|
||||
>
|
||||
+ Add half a day's work
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
onClick={() =>
|
||||
updateMultipleUser(
|
||||
data.map((u) => u.user.id),
|
||||
d,
|
||||
'one',
|
||||
)
|
||||
}
|
||||
>
|
||||
+ Add 1 day of work
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<Text size="sm" onClick={()=>{
|
||||
open()
|
||||
setCustomAddData({...customAddData, day: d})
|
||||
}}>
|
||||
+ Add custom worklog
|
||||
</Text>
|
||||
</Menu.Item>
|
||||
</Menu.Dropdown>
|
||||
</Menu>
|
||||
)
|
||||
})}
|
||||
</Table.Tr>
|
||||
|
|
@ -286,7 +419,16 @@ const Timekeeping = () => {
|
|||
<Table.Th ta={'center'}>Off</Table.Th>
|
||||
{daysInMonth.map((d) => {
|
||||
return (
|
||||
<Table.Th key={d} ta={'center'} bg={(getDayName(`${date.year}-${date.month}-${d}`)=== "Su" || getDayName(`${date.year}-${date.month}-${d}`) === "Sa") ? 'rgb(251 255 196 / 78%)' : ''}>
|
||||
<Table.Th
|
||||
key={d}
|
||||
ta={'center'}
|
||||
bg={
|
||||
getDayName(`${date.year}-${date.month}-${d}`) === 'Su' ||
|
||||
getDayName(`${date.year}-${date.month}-${d}`) === 'Sa'
|
||||
? 'rgb(251 255 196 / 78%)'
|
||||
: ''
|
||||
}
|
||||
>
|
||||
{getDayName(`${date.year}-${date.month}-${d}`)}
|
||||
</Table.Th>
|
||||
)
|
||||
|
|
@ -295,19 +437,35 @@ const Timekeeping = () => {
|
|||
</Table.Thead>
|
||||
<Table.Tbody>
|
||||
{data.map((user) => {
|
||||
let totalDays = user.history.filter((h) => h.total / 60 / 60 >= 7).length + (user.history.filter((h) => h.total / 60 / 60 < 7 && h.total / 60 / 60 >= 3.5).length / 2)
|
||||
let totalDays =
|
||||
user.history.filter((h) => h.total / 60 / 60 >= 7).length +
|
||||
user.history.filter(
|
||||
(h) => h.total / 60 / 60 < 7 && h.total / 60 / 60 >= 3.5,
|
||||
).length /
|
||||
2
|
||||
return (
|
||||
<Table.Tr key={user.user.id} className={classes.tableTr}>
|
||||
<Table.Td>{user.user.name}</Table.Td>
|
||||
<Table.Td ta={'center'}>{totalDays}</Table.Td>
|
||||
<Table.Td ta={'center'}>{workingDays-totalDays}</Table.Td>
|
||||
<Table.Td ta={'center'}>{workingDays - totalDays}</Table.Td>
|
||||
{daysInMonth.map((d) => {
|
||||
var total =
|
||||
user.history.find((h) => h.day === d)?.total ?? 0
|
||||
return (
|
||||
<Table.Td key={d} ta={'center'} bg={(getDayName(`${date.year}-${date.month}-${d}`)=== "Su" || getDayName(`${date.year}-${date.month}-${d}`) === "Sa") ? 'rgb(251 255 196 / 78%)' : ''}>
|
||||
{total / 60 / 60 < 7 && user.history.find((h) => h.day === d) ?
|
||||
total / 60 / 60 >= 3.5 ?
|
||||
<Table.Td
|
||||
key={d}
|
||||
ta={'center'}
|
||||
bg={
|
||||
getDayName(`${date.year}-${date.month}-${d}`) ===
|
||||
'Su' ||
|
||||
getDayName(`${date.year}-${date.month}-${d}`) === 'Sa'
|
||||
? 'rgb(251 255 196 / 78%)'
|
||||
: ''
|
||||
}
|
||||
>
|
||||
{total / 60 / 60 < 7 &&
|
||||
user.history.find((h) => h.day === d) ? (
|
||||
total / 60 / 60 >= 3.5 ? (
|
||||
<Tooltip
|
||||
multiline
|
||||
label={
|
||||
|
|
@ -325,7 +483,9 @@ const Timekeeping = () => {
|
|||
}}
|
||||
key={v.id}
|
||||
>
|
||||
<p>{v.status + ': ' + v.time_string}</p>{' '}
|
||||
<p>
|
||||
{v.status + ': ' + v.time_string}
|
||||
</p>{' '}
|
||||
{v.image && (
|
||||
<Image
|
||||
w={100}
|
||||
|
|
@ -335,13 +495,13 @@ const Timekeeping = () => {
|
|||
'local',
|
||||
)
|
||||
? import.meta.env
|
||||
.VITE_BACKEND_URL +
|
||||
'storage/' +
|
||||
v.image
|
||||
.VITE_BACKEND_URL +
|
||||
'storage/' +
|
||||
v.image
|
||||
: import.meta.env
|
||||
.VITE_BACKEND_URL +
|
||||
'image/storage/' +
|
||||
v.image
|
||||
.VITE_BACKEND_URL +
|
||||
'image/storage/' +
|
||||
v.image
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
|
@ -362,7 +522,8 @@ const Timekeeping = () => {
|
|||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
: <Tooltip
|
||||
) : (
|
||||
<Tooltip
|
||||
multiline
|
||||
label={
|
||||
<div>
|
||||
|
|
@ -379,7 +540,9 @@ const Timekeeping = () => {
|
|||
}}
|
||||
key={v.id}
|
||||
>
|
||||
<p>{v.status + ': ' + v.time_string}</p>{' '}
|
||||
<p>
|
||||
{v.status + ': ' + v.time_string}
|
||||
</p>{' '}
|
||||
{v.image && (
|
||||
<Image
|
||||
w={100}
|
||||
|
|
@ -389,13 +552,13 @@ const Timekeeping = () => {
|
|||
'local',
|
||||
)
|
||||
? import.meta.env
|
||||
.VITE_BACKEND_URL +
|
||||
'storage/' +
|
||||
v.image
|
||||
.VITE_BACKEND_URL +
|
||||
'storage/' +
|
||||
v.image
|
||||
: import.meta.env
|
||||
.VITE_BACKEND_URL +
|
||||
'image/storage/' +
|
||||
v.image
|
||||
.VITE_BACKEND_URL +
|
||||
'image/storage/' +
|
||||
v.image
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
|
@ -416,72 +579,72 @@ const Timekeeping = () => {
|
|||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
: total >= 7 ? (
|
||||
<Tooltip
|
||||
multiline
|
||||
label={
|
||||
<div>
|
||||
{`Total: ${(total / 60 / 60).toFixed(1)}h`}
|
||||
{user.history
|
||||
.find((h) => h.day === d)
|
||||
?.values.map((v) => {
|
||||
return (
|
||||
<Box
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
key={v.id}
|
||||
>
|
||||
<p>{v.status + ': ' + v.time_string}</p>{' '}
|
||||
{v.image && (
|
||||
<Image
|
||||
w={100}
|
||||
h={100}
|
||||
src={
|
||||
import.meta.env.VITE_BACKEND_URL.includes(
|
||||
'local',
|
||||
)
|
||||
? import.meta.env
|
||||
)
|
||||
) : total >= 7 ? (
|
||||
<Tooltip
|
||||
multiline
|
||||
label={
|
||||
<div>
|
||||
{`Total: ${(total / 60 / 60).toFixed(1)}h`}
|
||||
{user.history
|
||||
.find((h) => h.day === d)
|
||||
?.values.map((v) => {
|
||||
return (
|
||||
<Box
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
key={v.id}
|
||||
>
|
||||
<p>{v.status + ': ' + v.time_string}</p>{' '}
|
||||
{v.image && (
|
||||
<Image
|
||||
w={100}
|
||||
h={100}
|
||||
src={
|
||||
import.meta.env.VITE_BACKEND_URL.includes(
|
||||
'local',
|
||||
)
|
||||
? import.meta.env
|
||||
.VITE_BACKEND_URL +
|
||||
'storage/' +
|
||||
v.image
|
||||
: import.meta.env
|
||||
: import.meta.env
|
||||
.VITE_BACKEND_URL +
|
||||
'image/storage/' +
|
||||
v.image
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<IconCheck
|
||||
size={20}
|
||||
style={{
|
||||
backgroundColor: 'green',
|
||||
color: 'white',
|
||||
borderRadius: '5px',
|
||||
padding: '2px',
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : (
|
||||
|
||||
<IconX
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<IconCheck
|
||||
size={20}
|
||||
style={{
|
||||
backgroundColor: '#ff4646',
|
||||
backgroundColor: 'green',
|
||||
color: 'white',
|
||||
borderRadius: '5px',
|
||||
padding: '2px',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Tooltip>
|
||||
) : (
|
||||
<IconX
|
||||
size={20}
|
||||
style={{
|
||||
backgroundColor: '#ff4646',
|
||||
color: 'white',
|
||||
borderRadius: '5px',
|
||||
padding: '2px',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Table.Td>
|
||||
)
|
||||
})}
|
||||
|
|
|
|||
Loading…
Reference in New Issue