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']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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::post('/addMutilple', [TimekeepingController::class, 'addWorkingTimeForMultipleUser'])->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-working-days', [TimekeepingController::class, 'saveWorkingDays'])->middleware('check.permission:admin.hr');
 | 
			
		||||
            });
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,7 @@ class Notes extends Model
 | 
			
		|||
            ->where('n_month', $month)
 | 
			
		||||
            ->where('n_year', $year)
 | 
			
		||||
            ->select(
 | 
			
		||||
                'notes.id as n_id',
 | 
			
		||||
                'n_user_id',
 | 
			
		||||
                'n_day',
 | 
			
		||||
                'n_month',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,6 +72,7 @@ trait AnalyzeData
 | 
			
		|||
                    if (count($hasNotes) > 0) {
 | 
			
		||||
                        foreach ($hasNotes as $k_Note => $value_Note) {
 | 
			
		||||
                            $notes[$k_Note] = [
 | 
			
		||||
                                'id' => $value_Note->n_id,
 | 
			
		||||
                                'timeType' => $value_Note->n_time_type,
 | 
			
		||||
                                'timeTypeName' => $value_Note->time_type_name,
 | 
			
		||||
                                'reason' => $value_Note->n_reason,
 | 
			
		||||
| 
						 | 
				
			
			@ -86,6 +87,7 @@ trait AnalyzeData
 | 
			
		|||
                        $notes = [];
 | 
			
		||||
                        foreach ($hasNotes as $k_Note => $value_Note) {
 | 
			
		||||
                            $notes[$k_Note] = [
 | 
			
		||||
                                'id' => $value_Note->n_id,
 | 
			
		||||
                                'timeType' => $value_Note->n_time_type,
 | 
			
		||||
                                'timeTypeName' => $value_Note->time_type_name,
 | 
			
		||||
                                '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 updateMultipleUserWorkingTime = API_URL + 'v1/admin/timekeeping/addMutilple'
 | 
			
		||||
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'
 | 
			
		||||
 | 
			
		||||
//Category
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,13 +1,16 @@
 | 
			
		|||
import {
 | 
			
		||||
  deleteNote,
 | 
			
		||||
  getListMaster,
 | 
			
		||||
  getTheTimesheet,
 | 
			
		||||
  updateCacheMonth,
 | 
			
		||||
  updateMultipleUserWorkingTime,
 | 
			
		||||
  updateNote,
 | 
			
		||||
  updateWorkingDays,
 | 
			
		||||
} from '@/api/Admin'
 | 
			
		||||
import { update } from '@/rtk/helpers/CRUD'
 | 
			
		||||
import { update, Xdelete } from '@/rtk/helpers/CRUD'
 | 
			
		||||
import { get } from '@/rtk/helpers/apiService'
 | 
			
		||||
import {
 | 
			
		||||
  Avatar,
 | 
			
		||||
  Box,
 | 
			
		||||
  Button,
 | 
			
		||||
  Drawer,
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +23,7 @@ import {
 | 
			
		|||
  Textarea,
 | 
			
		||||
  TextInput,
 | 
			
		||||
  Tooltip,
 | 
			
		||||
  TypographyStylesProvider,
 | 
			
		||||
} from '@mantine/core'
 | 
			
		||||
import { useDisclosure } from '@mantine/hooks'
 | 
			
		||||
import { notifications } from '@mantine/notifications'
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +31,8 @@ import {
 | 
			
		|||
  IconCheck,
 | 
			
		||||
  IconExclamationMark,
 | 
			
		||||
  IconPointFilled,
 | 
			
		||||
  IconX
 | 
			
		||||
  IconTrash,
 | 
			
		||||
  IconX,
 | 
			
		||||
} from '@tabler/icons-react'
 | 
			
		||||
import moment from 'moment'
 | 
			
		||||
import { useEffect, useState } from 'react'
 | 
			
		||||
| 
						 | 
				
			
			@ -69,6 +74,7 @@ interface HistoryValue {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
interface NoteValue {
 | 
			
		||||
  id: number
 | 
			
		||||
  note: string
 | 
			
		||||
  reason: string
 | 
			
		||||
  timeType: string
 | 
			
		||||
| 
						 | 
				
			
			@ -113,6 +119,7 @@ const Timekeeping = () => {
 | 
			
		|||
    reason: string
 | 
			
		||||
    note: string
 | 
			
		||||
    day: number
 | 
			
		||||
    notes: NoteValue[]
 | 
			
		||||
  }>({
 | 
			
		||||
    user: {
 | 
			
		||||
      id: 0,
 | 
			
		||||
| 
						 | 
				
			
			@ -122,6 +129,7 @@ const Timekeeping = () => {
 | 
			
		|||
    reason: '',
 | 
			
		||||
    note: '',
 | 
			
		||||
    day: 0,
 | 
			
		||||
    notes: [],
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  const [workingDays, setWorkingDays] = useState(30)
 | 
			
		||||
| 
						 | 
				
			
			@ -175,6 +183,23 @@ const Timekeeping = () => {
 | 
			
		|||
        setData(
 | 
			
		||||
          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(
 | 
			
		||||
          Array.from({ length: getDaysInMonth() }, (_, index) => index + 1),
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			@ -283,6 +308,20 @@ const Timekeeping = () => {
 | 
			
		|||
      console.log(error)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  const handleUpdateCacheMonth = async () => {
 | 
			
		||||
    try {
 | 
			
		||||
      await update(
 | 
			
		||||
        updateCacheMonth,
 | 
			
		||||
        {
 | 
			
		||||
          year: date.year,
 | 
			
		||||
          month: date.month,
 | 
			
		||||
        },
 | 
			
		||||
        getTimeSheet,
 | 
			
		||||
      )
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      console.log(error)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    getTimeSheet()
 | 
			
		||||
| 
						 | 
				
			
			@ -369,6 +408,19 @@ const Timekeeping = () => {
 | 
			
		|||
      </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 (
 | 
			
		||||
    <div>
 | 
			
		||||
      <div className={classes.title}>
 | 
			
		||||
| 
						 | 
				
			
			@ -510,6 +562,50 @@ const Timekeeping = () => {
 | 
			
		|||
        >
 | 
			
		||||
          Save
 | 
			
		||||
        </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>
 | 
			
		||||
      <Box display={'flex'}>
 | 
			
		||||
        <Box style={{ display: 'flex', flexFlow: 'column' }} w={'30%'}>
 | 
			
		||||
| 
						 | 
				
			
			@ -785,7 +881,11 @@ const Timekeeping = () => {
 | 
			
		|||
                          right={-3}
 | 
			
		||||
                          display={notes && notes.length > 0 ? 'block' : 'none'}
 | 
			
		||||
                        >
 | 
			
		||||
                          <IconPointFilled width={15} height={15} style={{color:"#2767e1"}} />
 | 
			
		||||
                          <IconPointFilled
 | 
			
		||||
                            width={15}
 | 
			
		||||
                            height={15}
 | 
			
		||||
                            style={{ color: '#2767e1' }}
 | 
			
		||||
                          />
 | 
			
		||||
                        </Box>
 | 
			
		||||
                        {total / 60 / 60 < 7 &&
 | 
			
		||||
                        user.history.find(
 | 
			
		||||
| 
						 | 
				
			
			@ -902,6 +1002,13 @@ const Timekeeping = () => {
 | 
			
		|||
                                        id: user.user.id,
 | 
			
		||||
                                        name: user.user.name,
 | 
			
		||||
                                      },
 | 
			
		||||
                                      notes:
 | 
			
		||||
                                        user.history.find(
 | 
			
		||||
                                          (h) =>
 | 
			
		||||
                                            h.day === d &&
 | 
			
		||||
                                            h.notes &&
 | 
			
		||||
                                            h.notes.length > 0,
 | 
			
		||||
                                        )?.notes ?? [],
 | 
			
		||||
                                    })
 | 
			
		||||
                                  }}
 | 
			
		||||
                                />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue