Bổ sugn check admin navbar + view thông tin ticket management + delete note timekeeping
This commit is contained in:
		
							parent
							
								
									9b8945aa21
								
							
						
					
					
						commit
						5703804e5c
					
				| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,16 @@
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
 | 
					  deleteNote,
 | 
				
			||||||
  getListMaster,
 | 
					  getListMaster,
 | 
				
			||||||
  getTheTimesheet,
 | 
					  getTheTimesheet,
 | 
				
			||||||
 | 
					  updateCacheMonth,
 | 
				
			||||||
  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 {
 | 
				
			||||||
 | 
					  Avatar,
 | 
				
			||||||
  Box,
 | 
					  Box,
 | 
				
			||||||
  Button,
 | 
					  Button,
 | 
				
			||||||
  Drawer,
 | 
					  Drawer,
 | 
				
			||||||
| 
						 | 
					@ -20,6 +23,7 @@ import {
 | 
				
			||||||
  Textarea,
 | 
					  Textarea,
 | 
				
			||||||
  TextInput,
 | 
					  TextInput,
 | 
				
			||||||
  Tooltip,
 | 
					  Tooltip,
 | 
				
			||||||
 | 
					  TypographyStylesProvider,
 | 
				
			||||||
} 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 +31,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 +74,7 @@ interface HistoryValue {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface NoteValue {
 | 
					interface NoteValue {
 | 
				
			||||||
 | 
					  id: number
 | 
				
			||||||
  note: string
 | 
					  note: string
 | 
				
			||||||
  reason: string
 | 
					  reason: string
 | 
				
			||||||
  timeType: string
 | 
					  timeType: string
 | 
				
			||||||
| 
						 | 
					@ -113,6 +119,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 +129,7 @@ const Timekeeping = () => {
 | 
				
			||||||
    reason: '',
 | 
					    reason: '',
 | 
				
			||||||
    note: '',
 | 
					    note: '',
 | 
				
			||||||
    day: 0,
 | 
					    day: 0,
 | 
				
			||||||
 | 
					    notes: [],
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [workingDays, setWorkingDays] = useState(30)
 | 
					  const [workingDays, setWorkingDays] = useState(30)
 | 
				
			||||||
| 
						 | 
					@ -175,6 +183,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 +308,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 +408,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 +562,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 +881,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(
 | 
				
			||||||
| 
						 | 
					@ -902,6 +1002,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