dev #130
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -369,7 +369,7 @@ class TicketController extends Controller
 | 
			
		|||
            );
 | 
			
		||||
            // Thêm kiểm tra null trước khi gửi mail
 | 
			
		||||
            if ($dataMasterStartPeriod && $dataMasterEndPeriod && $dataMasterType) {
 | 
			
		||||
                Mail::to($value->email)->send(new TicketMail($data));
 | 
			
		||||
            Mail::to($value->email)->send(new TicketMail($data));
 | 
			
		||||
            } else {
 | 
			
		||||
                Log::error("Missing category data for ticket ID: {$ticket->id}. Mail not sent.");
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -846,16 +846,16 @@ class TicketController extends Controller
 | 
			
		|||
            } else if ($ticket->type == "WFH") {
 | 
			
		||||
                $dataListPeriod = $this->getAllPeriod($ticket->start_date, $ticket->start_period, $ticket->end_date, $ticket->end_period);
 | 
			
		||||
                foreach ($dataListPeriod as $result) {
 | 
			
		||||
                    list($year, $month, $day) = explode('-', $result['date']);
 | 
			
		||||
                    Notes::create([
 | 
			
		||||
                        'n_user_id' => $ticket->user_id,
 | 
			
		||||
                        'n_day' => $day,
 | 
			
		||||
                        'n_month' => $month,
 | 
			
		||||
                        'n_year' => $year,
 | 
			
		||||
                        'n_time_type' => $result['period'],
 | 
			
		||||
                        'n_reason' => $ticket->type,
 | 
			
		||||
                        'n_note' => $ticket->reason
 | 
			
		||||
                    ]);
 | 
			
		||||
                list($year, $month, $day) = explode('-', $result['date']);
 | 
			
		||||
                Notes::create([
 | 
			
		||||
                    'n_user_id' => $ticket->user_id,
 | 
			
		||||
                    'n_day' => $day,
 | 
			
		||||
                    'n_month' => $month,
 | 
			
		||||
                    'n_year' => $year,
 | 
			
		||||
                    'n_time_type' => $result['period'],
 | 
			
		||||
                    'n_reason' => $ticket->type,
 | 
			
		||||
                    'n_note' => $ticket->reason
 | 
			
		||||
                ]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                    //WFH - start tracking
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,3 +60,37 @@
 | 
			
		|||
  padding-top: 5px;
 | 
			
		||||
  padding-bottom: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Thêm styles cho Modal xác nhận xóa */
 | 
			
		||||
.deleteModal {
 | 
			
		||||
  background-color: light-dark(white, #2d353c);
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  border: solid 1px #ff4646;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.deleteModalTitle {
 | 
			
		||||
  color: #ff4646;
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
  font-size: 1.2rem;
 | 
			
		||||
  margin-bottom: 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.deleteModalContent {
 | 
			
		||||
  color: light-dark(#2d353c, white);
 | 
			
		||||
  margin-bottom: 1.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.deleteModalFooter {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: flex-end;
 | 
			
		||||
  gap: 10px;
 | 
			
		||||
  margin-top: 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.deleteButton {
 | 
			
		||||
  background-color: #ff4646;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.deleteButton:hover {
 | 
			
		||||
  background-color: #ff6b6b;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,7 @@ import {
 | 
			
		|||
  TextInput,
 | 
			
		||||
  Tooltip,
 | 
			
		||||
  Modal,
 | 
			
		||||
  Group,
 | 
			
		||||
} from '@mantine/core'
 | 
			
		||||
import { useDisclosure } from '@mantine/hooks'
 | 
			
		||||
import { notifications } from '@mantine/notifications'
 | 
			
		||||
| 
						 | 
				
			
			@ -147,6 +148,9 @@ const Timekeeping = () => {
 | 
			
		|||
  const [exportModalOpened, setExportModalOpened] = useState(false)
 | 
			
		||||
  const [exportOption, setExportOption] = useState('default')
 | 
			
		||||
 | 
			
		||||
  const [isDeleteConfirmOpen, setIsDeleteConfirmOpen] = useState(false)
 | 
			
		||||
  const [noteToDelete, setNoteToDelete] = useState<any>(null)
 | 
			
		||||
 | 
			
		||||
  const getListMasterByType = async (type: string) => {
 | 
			
		||||
    try {
 | 
			
		||||
      const params = {
 | 
			
		||||
| 
						 | 
				
			
			@ -452,9 +456,9 @@ const Timekeeping = () => {
 | 
			
		|||
          month: date.month,
 | 
			
		||||
          year: date.year,
 | 
			
		||||
          working_days: workingDays,
 | 
			
		||||
          option: option
 | 
			
		||||
          option: option,
 | 
			
		||||
        },
 | 
			
		||||
        fileName
 | 
			
		||||
        fileName,
 | 
			
		||||
      )
 | 
			
		||||
      setExportModalOpened(false)
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
| 
						 | 
				
			
			@ -462,6 +466,58 @@ const Timekeeping = () => {
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const handleConfirmDelete = async () => {
 | 
			
		||||
    if (noteToDelete) {
 | 
			
		||||
      await handleDelete(noteToDelete.id)
 | 
			
		||||
      setIsDeleteConfirmOpen(false)
 | 
			
		||||
      setNoteToDelete(null)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const openDeleteConfirm = (note: any) => {
 | 
			
		||||
    setNoteToDelete(note)
 | 
			
		||||
    setIsDeleteConfirmOpen(true)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const DeleteConfirmModal = () => (
 | 
			
		||||
    <Modal
 | 
			
		||||
      opened={isDeleteConfirmOpen}
 | 
			
		||||
      onClose={() => {
 | 
			
		||||
        setIsDeleteConfirmOpen(false)
 | 
			
		||||
        setNoteToDelete(null)
 | 
			
		||||
      }}
 | 
			
		||||
      centered
 | 
			
		||||
      size="sm"
 | 
			
		||||
      classNames={{
 | 
			
		||||
        content: classes.deleteModal,
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <Text className={classes.deleteModalTitle}>
 | 
			
		||||
        Confirm Delete
 | 
			
		||||
      </Text>
 | 
			
		||||
      <Text className={classes.deleteModalContent}>
 | 
			
		||||
        Are you sure you want to delete this note?
 | 
			
		||||
      </Text>
 | 
			
		||||
      <Box className={classes.deleteModalFooter}>
 | 
			
		||||
        <Button
 | 
			
		||||
          variant="outline"
 | 
			
		||||
          onClick={() => {
 | 
			
		||||
            setIsDeleteConfirmOpen(false)
 | 
			
		||||
            setNoteToDelete(null)
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          Cancel
 | 
			
		||||
        </Button>
 | 
			
		||||
        <Button 
 | 
			
		||||
          className={classes.deleteButton}
 | 
			
		||||
          onClick={handleConfirmDelete}
 | 
			
		||||
        >
 | 
			
		||||
          Delete
 | 
			
		||||
        </Button>
 | 
			
		||||
      </Box>
 | 
			
		||||
    </Modal>
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div>
 | 
			
		||||
      <div className={classes.title}>
 | 
			
		||||
| 
						 | 
				
			
			@ -631,11 +687,7 @@ const Timekeeping = () => {
 | 
			
		|||
              >
 | 
			
		||||
                <IconTrash
 | 
			
		||||
                  className={classes.deleteIcon}
 | 
			
		||||
                  onClick={async () => {
 | 
			
		||||
                    await handleDelete(item.id)
 | 
			
		||||
                    // handleUpdateCacheMonth()
 | 
			
		||||
                    // close2()
 | 
			
		||||
                  }}
 | 
			
		||||
                  onClick={() => openDeleteConfirm(item)}
 | 
			
		||||
                  width={20}
 | 
			
		||||
                  height={20}
 | 
			
		||||
                />
 | 
			
		||||
| 
						 | 
				
			
			@ -655,7 +707,7 @@ const Timekeeping = () => {
 | 
			
		|||
              data={Array.from({ length: 12 }, (_, index) => {
 | 
			
		||||
                return {
 | 
			
		||||
                  value: (1 + index).toString(),
 | 
			
		||||
                  label: (1 + index).toString()
 | 
			
		||||
                  label: (1 + index).toString(),
 | 
			
		||||
                }
 | 
			
		||||
              })}
 | 
			
		||||
              onChange={(e) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -1074,20 +1126,19 @@ const Timekeeping = () => {
 | 
			
		|||
          placeholder="Choose an option"
 | 
			
		||||
          value={exportOption}
 | 
			
		||||
          onChange={(value) => setExportOption(value || 'default')}
 | 
			
		||||
          data={[
 | 
			
		||||
            { value: 'default', label: 'Default' }
 | 
			
		||||
          ]}
 | 
			
		||||
          data={[{ value: 'default', label: 'Default' }]}
 | 
			
		||||
          mb="md"
 | 
			
		||||
        />
 | 
			
		||||
        <Box style={{ display: 'flex', justifyContent: 'flex-end', gap: '10px' }}>
 | 
			
		||||
        <Box
 | 
			
		||||
          style={{ display: 'flex', justifyContent: 'flex-end', gap: '10px' }}
 | 
			
		||||
        >
 | 
			
		||||
          <Button variant="outline" onClick={() => setExportModalOpened(false)}>
 | 
			
		||||
            Close
 | 
			
		||||
          </Button>
 | 
			
		||||
          <Button onClick={() => handleExport(exportOption)}>
 | 
			
		||||
            Export
 | 
			
		||||
          </Button>
 | 
			
		||||
          <Button onClick={() => handleExport(exportOption)}>Export</Button>
 | 
			
		||||
        </Box>
 | 
			
		||||
      </Modal>
 | 
			
		||||
      <DeleteConfirmModal />
 | 
			
		||||
    </div>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue