Merge pull request 'truong-sprint-1' (#9) from truong-sprint-1 into master
Reviewed-on: #9
This commit is contained in:
commit
4f492df167
|
|
@ -13,8 +13,10 @@ use Carbon\Carbon;
|
||||||
use Carbon\CarbonPeriod;
|
use Carbon\CarbonPeriod;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Modules\Admin\app\Models\Admin;
|
||||||
use Modules\Admin\app\Models\Category;
|
use Modules\Admin\app\Models\Category;
|
||||||
use Modules\Admin\app\Models\Ticket;
|
use Modules\Admin\app\Models\Ticket;
|
||||||
|
use Modules\Admin\app\Models\Tracking;
|
||||||
|
|
||||||
class TicketController extends Controller
|
class TicketController extends Controller
|
||||||
{
|
{
|
||||||
|
|
@ -288,7 +290,7 @@ class TicketController extends Controller
|
||||||
// Update updated_by and admin_note in tickets table
|
// Update updated_by and admin_note in tickets table
|
||||||
|
|
||||||
// Send notification email to users
|
// Send notification email to users
|
||||||
|
$user = Admin::find($ticket->user_id);
|
||||||
if ($action == "confirm") {
|
if ($action == "confirm") {
|
||||||
foreach ($results as $result) {
|
foreach ($results as $result) {
|
||||||
list($year, $month, $day) = explode('-', $result['date']);
|
list($year, $month, $day) = explode('-', $result['date']);
|
||||||
|
|
@ -301,6 +303,38 @@ class TicketController extends Controller
|
||||||
'n_reason' => $ticket->type,
|
'n_reason' => $ticket->type,
|
||||||
'n_note' => $ticket->reason
|
'n_note' => $ticket->reason
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if ($ticket->type == "WFH") {
|
||||||
|
$type = $result['period'];
|
||||||
|
$date = Carbon::create($year, $month, $day)->setTimezone(env('TIME_ZONE'));
|
||||||
|
|
||||||
|
//Default: ALL
|
||||||
|
$start = $date->copy()->setTime(7, 31, 11);
|
||||||
|
$end = $date->copy()->setTime(17, 1, 11);
|
||||||
|
|
||||||
|
if ($type == 'S') {
|
||||||
|
$end = $date->copy()->setTime(11, 31, 11);
|
||||||
|
} else if ($type == 'C') {
|
||||||
|
$start = $date->copy()->setTime(11, 31, 11);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tracking::insert([
|
||||||
|
[
|
||||||
|
'name' => $user->name,
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'status' => 'check in',
|
||||||
|
'time_string' => $start->format('Y-m-d H:i:s'),
|
||||||
|
'created_at' => $start->setTimezone('UTC')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => $user->name,
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'status' => 'check out',
|
||||||
|
'time_string' => $end->format('Y-m-d H:i:s'),
|
||||||
|
'created_at' => $end->setTimezone('UTC')
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$ticket['updated_by'] = $admin->name;
|
$ticket['updated_by'] = $admin->name;
|
||||||
|
|
|
||||||
|
|
@ -161,4 +161,27 @@ class TimekeepingController extends Controller
|
||||||
return response()->json(['status' => true, 'message' => 'Update successfully']);
|
return response()->json(['status' => true, 'message' => 'Update successfully']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function deleteNote(Request $request)
|
||||||
|
{
|
||||||
|
$rules = [
|
||||||
|
'id' => 'required'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Validate the request
|
||||||
|
$request->validate($rules);
|
||||||
|
|
||||||
|
$id = $request->input('id');
|
||||||
|
|
||||||
|
$month = $request->month;
|
||||||
|
$year = $request->year;
|
||||||
|
|
||||||
|
$note = Notes::find($id);
|
||||||
|
if ($note) {
|
||||||
|
$note->delete();
|
||||||
|
$this->createOrUpdateRecordForCurrentMonth($month, $year);
|
||||||
|
return response()->json(['message' => 'Delete success', 'status' => true]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Delete fail', 'status' => false]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,7 @@ Route::middleware('api')
|
||||||
Route::get('/', [TimekeepingController::class, 'get'])->middleware('check.permission:admin.hr.staff');
|
Route::get('/', [TimekeepingController::class, 'get'])->middleware('check.permission:admin.hr.staff');
|
||||||
Route::post('/addMutilple', [TimekeepingController::class, 'addWorkingTimeForMultipleUser'])->middleware('check.permission:admin.hr');
|
Route::post('/addMutilple', [TimekeepingController::class, 'addWorkingTimeForMultipleUser'])->middleware('check.permission:admin.hr');
|
||||||
Route::post('/addNote', [TimekeepingController::class, 'addNoteForUser'])->middleware('check.permission:admin.hr');
|
Route::post('/addNote', [TimekeepingController::class, 'addNoteForUser'])->middleware('check.permission:admin.hr');
|
||||||
|
Route::get('/delete', [TimekeepingController::class, 'deleteNote'])->middleware('check.permission:admin.hr');
|
||||||
Route::post('/update-cache-month', [TimekeepingController::class, 'updateCacheMonth'])->middleware('check.permission:admin');
|
Route::post('/update-cache-month', [TimekeepingController::class, 'updateCacheMonth'])->middleware('check.permission:admin');
|
||||||
Route::post('/update-working-days', [TimekeepingController::class, 'saveWorkingDays'])->middleware('check.permission:admin.hr');
|
Route::post('/update-working-days', [TimekeepingController::class, 'saveWorkingDays'])->middleware('check.permission:admin.hr');
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ class Notes extends Model
|
||||||
->where('n_month', $month)
|
->where('n_month', $month)
|
||||||
->where('n_year', $year)
|
->where('n_year', $year)
|
||||||
->select(
|
->select(
|
||||||
|
'notes.id as n_id',
|
||||||
'n_user_id',
|
'n_user_id',
|
||||||
'n_day',
|
'n_day',
|
||||||
'n_month',
|
'n_month',
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ trait AnalyzeData
|
||||||
if (count($hasNotes) > 0) {
|
if (count($hasNotes) > 0) {
|
||||||
foreach ($hasNotes as $k_Note => $value_Note) {
|
foreach ($hasNotes as $k_Note => $value_Note) {
|
||||||
$notes[$k_Note] = [
|
$notes[$k_Note] = [
|
||||||
|
'id' => $value_Note->n_id,
|
||||||
'timeType' => $value_Note->n_time_type,
|
'timeType' => $value_Note->n_time_type,
|
||||||
'timeTypeName' => $value_Note->time_type_name,
|
'timeTypeName' => $value_Note->time_type_name,
|
||||||
'reason' => $value_Note->n_reason,
|
'reason' => $value_Note->n_reason,
|
||||||
|
|
@ -86,6 +87,7 @@ trait AnalyzeData
|
||||||
$notes = [];
|
$notes = [];
|
||||||
foreach ($hasNotes as $k_Note => $value_Note) {
|
foreach ($hasNotes as $k_Note => $value_Note) {
|
||||||
$notes[$k_Note] = [
|
$notes[$k_Note] = [
|
||||||
|
'id' => $value_Note->n_id,
|
||||||
'timeType' => $value_Note->n_time_type,
|
'timeType' => $value_Note->n_time_type,
|
||||||
'timeTypeName' => $value_Note->time_type_name,
|
'timeTypeName' => $value_Note->time_type_name,
|
||||||
'reason' => $value_Note->n_reason,
|
'reason' => $value_Note->n_reason,
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,8 @@ export const getAllUserWorklogs = API_URL + 'v1/admin/jira/worklogs'
|
||||||
export const getTheTimesheet = API_URL + 'v1/admin/timekeeping'
|
export const getTheTimesheet = API_URL + 'v1/admin/timekeeping'
|
||||||
export const updateMultipleUserWorkingTime = API_URL + 'v1/admin/timekeeping/addMutilple'
|
export const updateMultipleUserWorkingTime = API_URL + 'v1/admin/timekeeping/addMutilple'
|
||||||
export const updateNote = API_URL + 'v1/admin/timekeeping/addNote'
|
export const updateNote = API_URL + 'v1/admin/timekeeping/addNote'
|
||||||
|
export const deleteNote = API_URL + 'v1/admin/timekeeping/delete'
|
||||||
|
export const updateCacheMonth = API_URL + 'v1/admin/timekeeping/update-cache-month'
|
||||||
export const updateWorkingDays = API_URL + 'v1/admin/timekeeping/update-working-days'
|
export const updateWorkingDays = API_URL + 'v1/admin/timekeeping/update-working-days'
|
||||||
|
|
||||||
//Category
|
//Category
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
Code,
|
Code,
|
||||||
|
Divider,
|
||||||
Group,
|
Group,
|
||||||
Modal,
|
Modal,
|
||||||
PasswordInput,
|
PasswordInput,
|
||||||
|
|
@ -38,19 +39,36 @@ import classes from './NavbarSimpleColored.module.css'
|
||||||
|
|
||||||
const data = [
|
const data = [
|
||||||
// { link: '/dashboard', label: 'Dashboard', icon: IconHome },
|
// { link: '/dashboard', label: 'Dashboard', icon: IconHome },
|
||||||
{ link: '/timekeeping', label: 'Timekeeping', icon: IconCalendar },
|
{
|
||||||
{ link: '/tracking', label: 'Check in/out', icon: IconScan },
|
link: '/timekeeping',
|
||||||
{ link: '/worklogs', label: 'Worklogs', icon: IconReport },
|
label: 'Timekeeping',
|
||||||
|
icon: IconCalendar,
|
||||||
|
group: 'normal',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
link: '/tracking',
|
||||||
|
label: 'Check in/out',
|
||||||
|
icon: IconScan,
|
||||||
|
group: 'normal',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
link: '/worklogs',
|
||||||
|
label: 'Worklogs',
|
||||||
|
icon: IconReport,
|
||||||
|
group: 'normal',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
link: '/leave-management',
|
link: '/leave-management',
|
||||||
label: 'Leave Management',
|
label: 'Leave Management',
|
||||||
icon: IconCalendarClock,
|
icon: IconCalendarClock,
|
||||||
|
group: 'normal',
|
||||||
},
|
},
|
||||||
{ link: '/tickets', label: 'Tickets', icon: IconTicket },
|
{ link: '/tickets', label: 'Tickets', icon: IconTicket, group: 'normal' },
|
||||||
{
|
{
|
||||||
link: '/tickets-management',
|
link: '/tickets-management',
|
||||||
label: 'Tickets Management',
|
label: 'Tickets Management',
|
||||||
icon: IconDevices,
|
icon: IconDevices,
|
||||||
|
group: 'admin',
|
||||||
},
|
},
|
||||||
// { link: '/jira', label: 'Jira', icon: IconSubtask },
|
// { link: '/jira', label: 'Jira', icon: IconSubtask },
|
||||||
// { link: '/custom-theme', label: 'Custom Theme', icon: IconBrush },
|
// { link: '/custom-theme', label: 'Custom Theme', icon: IconBrush },
|
||||||
|
|
@ -106,31 +124,90 @@ const Navbar = ({
|
||||||
getInitialValueInEffect: true,
|
getInitialValueInEffect: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const links = data.map((item) => {
|
// const links = data.map((item) => {
|
||||||
if (user?.user?.permission !== 'admin' && item.link === '/tickets-management')
|
// if (
|
||||||
return null
|
// user?.user?.permission !== 'admin' &&
|
||||||
|
// item.link === '/tickets-management'
|
||||||
|
// )
|
||||||
|
// return null
|
||||||
|
// return (
|
||||||
|
// <a
|
||||||
|
// className={classes.link}
|
||||||
|
// data-active={item.label === active || undefined}
|
||||||
|
// key={item.label}
|
||||||
|
// onClick={() => {
|
||||||
|
// // setHeader(item.label);
|
||||||
|
// setActive(active)
|
||||||
|
// if (active !== item.label) {
|
||||||
|
// navigate(item.link)
|
||||||
|
// }
|
||||||
|
// }}
|
||||||
|
// >
|
||||||
|
// <item.icon className={classes.linkIcon} stroke={1.5} />
|
||||||
|
// <span
|
||||||
|
// className={`${classes.itemLabel} ${
|
||||||
|
// isCompactMenu ? classes.labelCompactMenu : ''
|
||||||
|
// } `}
|
||||||
|
// >
|
||||||
|
// {item.label}
|
||||||
|
// </span>
|
||||||
|
// </a>
|
||||||
|
// )
|
||||||
|
// })
|
||||||
|
|
||||||
|
const group = [
|
||||||
|
{ name: 'normal', label: 'Normal' },
|
||||||
|
{ name: 'admin', label: 'Admin' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const links = group.map((g) => {
|
||||||
return (
|
return (
|
||||||
<a
|
<div key={g.name}>
|
||||||
className={classes.link}
|
<Divider
|
||||||
data-active={item.label === active || undefined}
|
display={
|
||||||
key={item.label}
|
g.name === 'normal'
|
||||||
onClick={() => {
|
? 'block'
|
||||||
// setHeader(item.label);
|
: user?.user?.permission === g.name
|
||||||
setActive(active)
|
? 'block'
|
||||||
if (active !== item.label) {
|
: 'none'
|
||||||
navigate(item.link)
|
|
||||||
}
|
}
|
||||||
}}
|
my="xs"
|
||||||
>
|
label={
|
||||||
<item.icon className={classes.linkIcon} stroke={1.5} />
|
<span style={{ color: 'white', fontWeight: 700 }}>{g.label}</span>
|
||||||
<span
|
}
|
||||||
className={`${classes.itemLabel} ${
|
labelPosition="center"
|
||||||
isCompactMenu ? classes.labelCompactMenu : ''
|
/>
|
||||||
} `}
|
{data
|
||||||
>
|
.filter((i) => {
|
||||||
{item.label}
|
return (
|
||||||
</span>
|
i.group === g.name &&
|
||||||
</a>
|
(user?.user?.permission === 'admin' || g.name !== 'admin')
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map((item) => (
|
||||||
|
<a
|
||||||
|
className={classes.link}
|
||||||
|
data-active={item.label === active || undefined}
|
||||||
|
key={item.link}
|
||||||
|
onClick={() => {
|
||||||
|
// setHeader(item.label);
|
||||||
|
setActive(active)
|
||||||
|
if (active !== item.label) {
|
||||||
|
navigate(item.link)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<item.icon className={classes.linkIcon} stroke={1.5} />
|
||||||
|
<span
|
||||||
|
className={`${classes.itemLabel} ${
|
||||||
|
isCompactMenu ? classes.labelCompactMenu : ''
|
||||||
|
} `}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import { IconCheckbox, IconSquareXFilled } from '@tabler/icons-react'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import classes from './TicketsManagement.module.css'
|
import classes from './TicketsManagement.module.css'
|
||||||
|
import { DateInput } from '@mantine/dates'
|
||||||
|
|
||||||
type TTickets = {
|
type TTickets = {
|
||||||
ticket_id: number
|
ticket_id: number
|
||||||
|
|
@ -52,17 +53,38 @@ interface DataReason {
|
||||||
c_name: string
|
c_name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface DataTimeType {
|
||||||
|
id: number
|
||||||
|
c_code: string
|
||||||
|
c_name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FilterInfo {
|
||||||
|
key: string
|
||||||
|
name: string
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
|
||||||
const TicketsManagement = () => {
|
const TicketsManagement = () => {
|
||||||
const [listTickets, setListTiskets] = useState<TListTickets>({
|
const [listTickets, setListTiskets] = useState<TListTickets>({
|
||||||
data: [],
|
data: [],
|
||||||
})
|
})
|
||||||
const [action, setAction] = useState('')
|
const [action, setAction] = useState('')
|
||||||
const [item, setItem] = useState({ id: 0 })
|
const [item, setItem] = useState({
|
||||||
|
id: 0,
|
||||||
|
start_date: '',
|
||||||
|
start_period: '',
|
||||||
|
end_date: '',
|
||||||
|
end_period: '',
|
||||||
|
reason: '',
|
||||||
|
type: '',
|
||||||
|
})
|
||||||
const [disableBtn, setDisableBtn] = useState(false)
|
const [disableBtn, setDisableBtn] = useState(false)
|
||||||
const [filter, setFilter] = useState({
|
const [filter, setFilter] = useState({
|
||||||
typeReason: '',
|
typeReason: '',
|
||||||
statusFilter: '',
|
statusFilter: '',
|
||||||
})
|
})
|
||||||
|
const [dataTimeType, setDataTimeType] = useState<DataTimeType[]>([])
|
||||||
const [dataReason, setDataReason] = useState<DataReason[]>([])
|
const [dataReason, setDataReason] = useState<DataReason[]>([])
|
||||||
|
|
||||||
const getListMasterByType = async (type: string) => {
|
const getListMasterByType = async (type: string) => {
|
||||||
|
|
@ -86,6 +108,11 @@ const TicketsManagement = () => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
|
const resultTimeType = await getListMasterByType('TIME_TYPE')
|
||||||
|
setDataTimeType(
|
||||||
|
resultTimeType.filter((item: DataTimeType) => item.c_code !== 'ALL'),
|
||||||
|
)
|
||||||
|
|
||||||
const resultReason = await getListMasterByType('REASON')
|
const resultReason = await getListMasterByType('REASON')
|
||||||
setDataReason(resultReason)
|
setDataReason(resultReason)
|
||||||
}
|
}
|
||||||
|
|
@ -369,7 +396,7 @@ const TicketsManagement = () => {
|
||||||
label="Status"
|
label="Status"
|
||||||
data={[
|
data={[
|
||||||
{ value: 'WAITING', label: 'WAITING' },
|
{ value: 'WAITING', label: 'WAITING' },
|
||||||
{ value: 'CONFIRM', label: 'CONFIRM' },
|
{ value: 'CONFIRMED', label: 'CONFIRMED' },
|
||||||
{ value: 'REFUSED', label: 'REFUSED' },
|
{ value: 'REFUSED', label: 'REFUSED' },
|
||||||
]}
|
]}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
|
|
@ -411,6 +438,78 @@ const TicketsManagement = () => {
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Box pl={'md'} pr={'md'}>
|
<Box pl={'md'} pr={'md'}>
|
||||||
|
<Box display={'flex'}>
|
||||||
|
<Box style={{ display: 'flex', flexFlow: 'column' }} w={'40%'}>
|
||||||
|
<DateInput
|
||||||
|
variant="unstyled"
|
||||||
|
readOnly
|
||||||
|
mb={'md'}
|
||||||
|
label={'From Date'}
|
||||||
|
value={new Date(item.start_date)}
|
||||||
|
valueFormat="DD/MM/YYYY"
|
||||||
|
></DateInput>
|
||||||
|
|
||||||
|
<Select
|
||||||
|
style={{ border: 'none' }}
|
||||||
|
variant="unstyled"
|
||||||
|
mb={'md'}
|
||||||
|
label={'Start Period'}
|
||||||
|
data={dataTimeType.map((item) => {
|
||||||
|
return { value: item.c_code.toString(), label: item.c_name }
|
||||||
|
})}
|
||||||
|
value={item.start_period}
|
||||||
|
error={form.errors.start_period}
|
||||||
|
onChange={(e) => form.setFieldValue('start_period', e!)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Select
|
||||||
|
variant="unstyled"
|
||||||
|
mb={'md'}
|
||||||
|
searchable
|
||||||
|
label="Type"
|
||||||
|
data={dataReason.map((user) => ({
|
||||||
|
value: user.c_code.toString(),
|
||||||
|
label: user.c_name,
|
||||||
|
}))}
|
||||||
|
value={item.type}
|
||||||
|
error={form.errors.type}
|
||||||
|
onChange={(e) => form.setFieldValue('type', e!)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
style={{ display: 'flex', flexFlow: 'column' }}
|
||||||
|
w={'20%'}
|
||||||
|
></Box>
|
||||||
|
<Box style={{ display: 'flex', flexFlow: 'column' }} w={'40%'}>
|
||||||
|
<DateInput
|
||||||
|
variant="unstyled"
|
||||||
|
mb={'md'}
|
||||||
|
label={'End Date'}
|
||||||
|
value={new Date(item.end_date)}
|
||||||
|
valueFormat="DD/MM/YYYY"
|
||||||
|
onChange={(e) => form.setFieldValue('end_date', e!)}
|
||||||
|
></DateInput>
|
||||||
|
<Select
|
||||||
|
variant="unstyled"
|
||||||
|
mb={'md'}
|
||||||
|
label={'End Period'}
|
||||||
|
data={dataTimeType.map((item) => {
|
||||||
|
return { value: item.c_code.toString(), label: item.c_name }
|
||||||
|
})}
|
||||||
|
value={item.end_period}
|
||||||
|
error={form.errors.end_period}
|
||||||
|
onChange={(e) => form.setFieldValue('end_period', e!)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Textarea
|
||||||
|
label="Reason"
|
||||||
|
variant="unstyled"
|
||||||
|
value={item.reason}
|
||||||
|
onChange={(e) => form.setFieldValue('reason', e.target.value)}
|
||||||
|
/>
|
||||||
|
|
||||||
<Textarea
|
<Textarea
|
||||||
label="Admin Notes"
|
label="Admin Notes"
|
||||||
required
|
required
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
import {
|
import {
|
||||||
|
deleteNote,
|
||||||
getListMaster,
|
getListMaster,
|
||||||
getTheTimesheet,
|
getTheTimesheet,
|
||||||
updateMultipleUserWorkingTime,
|
updateMultipleUserWorkingTime,
|
||||||
updateNote,
|
updateNote,
|
||||||
updateWorkingDays,
|
updateWorkingDays
|
||||||
} from '@/api/Admin'
|
} from '@/api/Admin'
|
||||||
import { update } from '@/rtk/helpers/CRUD'
|
import { update, Xdelete } from '@/rtk/helpers/CRUD'
|
||||||
import { get } from '@/rtk/helpers/apiService'
|
import { get } from '@/rtk/helpers/apiService'
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
|
|
@ -19,7 +20,7 @@ import {
|
||||||
Text,
|
Text,
|
||||||
Textarea,
|
Textarea,
|
||||||
TextInput,
|
TextInput,
|
||||||
Tooltip,
|
Tooltip
|
||||||
} from '@mantine/core'
|
} from '@mantine/core'
|
||||||
import { useDisclosure } from '@mantine/hooks'
|
import { useDisclosure } from '@mantine/hooks'
|
||||||
import { notifications } from '@mantine/notifications'
|
import { notifications } from '@mantine/notifications'
|
||||||
|
|
@ -27,7 +28,8 @@ import {
|
||||||
IconCheck,
|
IconCheck,
|
||||||
IconExclamationMark,
|
IconExclamationMark,
|
||||||
IconPointFilled,
|
IconPointFilled,
|
||||||
IconX
|
IconTrash,
|
||||||
|
IconX,
|
||||||
} from '@tabler/icons-react'
|
} from '@tabler/icons-react'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
@ -69,6 +71,7 @@ interface HistoryValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NoteValue {
|
interface NoteValue {
|
||||||
|
id: number
|
||||||
note: string
|
note: string
|
||||||
reason: string
|
reason: string
|
||||||
timeType: string
|
timeType: string
|
||||||
|
|
@ -113,6 +116,7 @@ const Timekeeping = () => {
|
||||||
reason: string
|
reason: string
|
||||||
note: string
|
note: string
|
||||||
day: number
|
day: number
|
||||||
|
notes: NoteValue[]
|
||||||
}>({
|
}>({
|
||||||
user: {
|
user: {
|
||||||
id: 0,
|
id: 0,
|
||||||
|
|
@ -122,6 +126,7 @@ const Timekeeping = () => {
|
||||||
reason: '',
|
reason: '',
|
||||||
note: '',
|
note: '',
|
||||||
day: 0,
|
day: 0,
|
||||||
|
notes: [],
|
||||||
})
|
})
|
||||||
|
|
||||||
const [workingDays, setWorkingDays] = useState(30)
|
const [workingDays, setWorkingDays] = useState(30)
|
||||||
|
|
@ -175,6 +180,23 @@ const Timekeeping = () => {
|
||||||
setData(
|
setData(
|
||||||
res.data.filter((u: UserData) => u.user.permission.includes('staff')),
|
res.data.filter((u: UserData) => u.user.permission.includes('staff')),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
res.data.find(
|
||||||
|
(item: UserData) => item.user.id === customAddNotes.user.id,
|
||||||
|
)?.user.id
|
||||||
|
) {
|
||||||
|
setCustomAddNotes({
|
||||||
|
...customAddNotes,
|
||||||
|
notes: (res.data
|
||||||
|
.find((item: UserData) => item.user.id === customAddNotes.user.id)
|
||||||
|
?.history?.find(
|
||||||
|
(itemHistory: History) =>
|
||||||
|
itemHistory.day === customAddNotes.day,
|
||||||
|
)?.notes ?? []) as NoteValue[],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
setDaysInMonth(
|
setDaysInMonth(
|
||||||
Array.from({ length: getDaysInMonth() }, (_, index) => index + 1),
|
Array.from({ length: getDaysInMonth() }, (_, index) => index + 1),
|
||||||
)
|
)
|
||||||
|
|
@ -283,6 +305,20 @@ const Timekeeping = () => {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// const handleUpdateCacheMonth = async () => {
|
||||||
|
// try {
|
||||||
|
// await update(
|
||||||
|
// updateCacheMonth,
|
||||||
|
// {
|
||||||
|
// year: date.year,
|
||||||
|
// month: date.month,
|
||||||
|
// },
|
||||||
|
// getTimeSheet,
|
||||||
|
// )
|
||||||
|
// } catch (error) {
|
||||||
|
// console.log(error)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getTimeSheet()
|
getTimeSheet()
|
||||||
|
|
@ -369,6 +405,19 @@ const Timekeeping = () => {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleDelete = async (id: number) => {
|
||||||
|
try {
|
||||||
|
await Xdelete(
|
||||||
|
deleteNote,
|
||||||
|
{ id: id, month: date.month, year: date.year },
|
||||||
|
getTimeSheet,
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className={classes.title}>
|
<div className={classes.title}>
|
||||||
|
|
@ -510,6 +559,50 @@ const Timekeeping = () => {
|
||||||
>
|
>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
|
{customAddNotes.notes.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
key={index}
|
||||||
|
display="flex"
|
||||||
|
className="text-muted"
|
||||||
|
style={{
|
||||||
|
marginTop: '10px',
|
||||||
|
border: '1px solid #ccc',
|
||||||
|
borderRadius: '5px',
|
||||||
|
marginBottom: '10px',
|
||||||
|
padding: '10px',
|
||||||
|
justifyContent: 'space-around',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box w={'90%'}>
|
||||||
|
<TextInput
|
||||||
|
readOnly
|
||||||
|
variant="unstyled"
|
||||||
|
type="text"
|
||||||
|
size="xs"
|
||||||
|
label={`${item.reasonName} - ${item.timeTypeName}`}
|
||||||
|
w={'100%'}
|
||||||
|
value={item.note}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
className={classes.optionIcon}
|
||||||
|
style={{ alignItems: 'center' }}
|
||||||
|
>
|
||||||
|
<IconTrash
|
||||||
|
className={classes.deleteIcon}
|
||||||
|
onClick={async () => {
|
||||||
|
await handleDelete(item.id)
|
||||||
|
// handleUpdateCacheMonth()
|
||||||
|
// close2()
|
||||||
|
}}
|
||||||
|
width={20}
|
||||||
|
height={20}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
})}
|
||||||
</Drawer>
|
</Drawer>
|
||||||
<Box display={'flex'}>
|
<Box display={'flex'}>
|
||||||
<Box style={{ display: 'flex', flexFlow: 'column' }} w={'30%'}>
|
<Box style={{ display: 'flex', flexFlow: 'column' }} w={'30%'}>
|
||||||
|
|
@ -785,7 +878,11 @@ const Timekeeping = () => {
|
||||||
right={-3}
|
right={-3}
|
||||||
display={notes && notes.length > 0 ? 'block' : 'none'}
|
display={notes && notes.length > 0 ? 'block' : 'none'}
|
||||||
>
|
>
|
||||||
<IconPointFilled width={15} height={15} style={{color:"#2767e1"}} />
|
<IconPointFilled
|
||||||
|
width={15}
|
||||||
|
height={15}
|
||||||
|
style={{ color: '#2767e1' }}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
{total / 60 / 60 < 7 &&
|
{total / 60 / 60 < 7 &&
|
||||||
user.history.find(
|
user.history.find(
|
||||||
|
|
@ -814,6 +911,13 @@ const Timekeeping = () => {
|
||||||
id: user.user.id,
|
id: user.user.id,
|
||||||
name: user.user.name,
|
name: user.user.name,
|
||||||
},
|
},
|
||||||
|
notes:
|
||||||
|
user.history.find(
|
||||||
|
(h) =>
|
||||||
|
h.day === d &&
|
||||||
|
h.notes &&
|
||||||
|
h.notes.length > 0,
|
||||||
|
)?.notes ?? [],
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -841,6 +945,13 @@ const Timekeeping = () => {
|
||||||
id: user.user.id,
|
id: user.user.id,
|
||||||
name: user.user.name,
|
name: user.user.name,
|
||||||
},
|
},
|
||||||
|
notes:
|
||||||
|
user.history.find(
|
||||||
|
(h) =>
|
||||||
|
h.day === d &&
|
||||||
|
h.notes &&
|
||||||
|
h.notes.length > 0,
|
||||||
|
)?.notes ?? [],
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -869,6 +980,13 @@ const Timekeeping = () => {
|
||||||
id: user.user.id,
|
id: user.user.id,
|
||||||
name: user.user.name,
|
name: user.user.name,
|
||||||
},
|
},
|
||||||
|
notes:
|
||||||
|
user.history.find(
|
||||||
|
(h) =>
|
||||||
|
h.day === d &&
|
||||||
|
h.notes &&
|
||||||
|
h.notes.length > 0,
|
||||||
|
)?.notes ?? [],
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -902,6 +1020,13 @@ const Timekeeping = () => {
|
||||||
id: user.user.id,
|
id: user.user.id,
|
||||||
name: user.user.name,
|
name: user.user.name,
|
||||||
},
|
},
|
||||||
|
notes:
|
||||||
|
user.history.find(
|
||||||
|
(h) =>
|
||||||
|
h.day === d &&
|
||||||
|
h.notes &&
|
||||||
|
h.notes.length > 0,
|
||||||
|
)?.notes ?? [],
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -925,6 +1050,13 @@ const Timekeeping = () => {
|
||||||
id: user.user.id,
|
id: user.user.id,
|
||||||
name: user.user.name,
|
name: user.user.name,
|
||||||
},
|
},
|
||||||
|
notes:
|
||||||
|
user.history.find(
|
||||||
|
(h) =>
|
||||||
|
h.day === d &&
|
||||||
|
h.notes &&
|
||||||
|
h.notes.length > 0,
|
||||||
|
)?.notes ?? [],
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue