Commit 0c51fca2 authored by Fachri's avatar Fachri

Refetch when upload,delete,cancel and adjust minor wording panduanRekam

parent da120cfd
......@@ -78,7 +78,7 @@ export const navData: NavSectionProps['data'] = [
{
title: 'e-Bupot Unifikasi',
path: paths.unifikasi.dn,
icon: ICONS.banking,
icon: ICONS.blank,
children: [
{ title: 'Bupot Unifikasi', path: paths.unifikasi.dn },
{ title: 'Bupot Non Residen', path: paths.unifikasi.nr },
......
......@@ -30,6 +30,7 @@ interface ModalCancelDigunggungProps {
isOpenDialogCancel: boolean;
setIsOpenDialogCancel: (v: boolean) => void;
successMessage?: string;
onConfirmCancel?: () => Promise<void> | void;
}
const ModalCancelDigunggung: React.FC<ModalCancelDigunggungProps> = ({
......@@ -39,6 +40,7 @@ const ModalCancelDigunggung: React.FC<ModalCancelDigunggungProps> = ({
isOpenDialogCancel,
setIsOpenDialogCancel,
successMessage = 'Data berhasil dibatalkan',
onConfirmCancel,
}) => {
const queryClient = useQueryClient();
......@@ -123,6 +125,8 @@ const ModalCancelDigunggung: React.FC<ModalCancelDigunggungProps> = ({
if (success.length > 0) {
enqueueSnackbar(successMessage, { variant: 'success' });
processSuccess();
await onConfirmCancel?.();
}
// ✅ update cache data lokal agar status langsung berubah
......
......@@ -14,6 +14,7 @@ interface ModalDeleteDigunggungProps {
isOpenDialogDelete: boolean;
setIsOpenDialogDelete: (v: boolean) => void;
successMessage?: string;
onConfirmDelete?: () => Promise<void> | void;
}
/**
......@@ -51,6 +52,7 @@ const ModalDeleteDigunggung: React.FC<ModalDeleteDigunggungProps> = ({
isOpenDialogDelete,
setIsOpenDialogDelete,
successMessage = 'Data berhasil dihapus',
onConfirmDelete,
}) => {
const queryClient = useQueryClient();
......@@ -99,6 +101,9 @@ const ModalDeleteDigunggung: React.FC<ModalDeleteDigunggungProps> = ({
setIsOpenDialogProgressBar(true);
await handleMultipleDelete();
enqueueSnackbar(successMessage, { variant: 'success' });
await onConfirmDelete?.();
handleCloseModal();
clearSelection();
} catch (error: any) {
......
......@@ -66,7 +66,7 @@ const ModalUploadDigunggung: React.FC<ModalUploadDigunggungProps> = ({
}) => {
const queryClient = useQueryClient();
const uploadNr = useUpload();
const uploadDigunggung = useUpload();
// custom hooks for progress state
const {
numberOfData,
......@@ -94,8 +94,9 @@ const ModalUploadDigunggung: React.FC<ModalUploadDigunggungProps> = ({
signer: signer || '',
},
});
// fungsi multiple delete -- gunakan normalized array of ids
const handleMultipleDelete = async () => {
// fungsi multiple upload -- gunakan normalized array of ids
const handleMultipleUpload = async () => {
const ids = normalizeSelection(dataSelected);
return Promise.allSettled(ids.map(async (id) => mutateAsync({ id: String(id) })));
};
......@@ -116,8 +117,12 @@ const ModalUploadDigunggung: React.FC<ModalUploadDigunggungProps> = ({
const onSubmit = async () => {
try {
setIsOpenDialogProgressBar(true);
await handleMultipleDelete();
await handleMultipleUpload();
enqueueSnackbar(successMessage, { variant: 'success' });
// ✅ refetch langsung setelah sukses
await onConfirmUpload?.();
handleCloseModal();
clearSelection();
} catch (error: any) {
......@@ -158,17 +163,8 @@ const ModalUploadDigunggung: React.FC<ModalUploadDigunggungProps> = ({
<Button
type="button"
disabled={!isCheckedAgreement}
onClick={async () => {
if (onConfirmUpload) {
await onConfirmUpload();
setIsOpenDialogUpload(false);
return;
}
await onSubmit();
}}
loading={uploadNr.isPending}
onClick={onSubmit}
loading={uploadDigunggung.isPending}
variant="contained"
sx={{ background: '#143B88' }}
>
......
......@@ -3,7 +3,7 @@ import { Fragment, memo } from 'react';
import { Box, Button, Card, CardContent, CardHeader, IconButton, Typography } from '@mui/material';
import { ChevronRightRounded, CloseRounded } from '@mui/icons-material';
import { m } from 'framer-motion';
import { PANDUAN_REKAM_SSP } from '../../constant';
import { PANDUAN_REKAM_DIGUNGGUNG } from '../../constant';
interface PanduanDnRekamProps {
handleOpen: () => void;
......@@ -95,13 +95,13 @@ const PanduanSspRekam: FC<PanduanDnRekamProps> = ({ handleOpen, isOpen }) => (
<Typography variant="body2" sx={{ mb: 2, whiteSpace: 'pre-line' }}>
<strong>Deskripsi Form:</strong>
<br />
{PANDUAN_REKAM_SSP.description.intro}
{PANDUAN_REKAM_DIGUNGGUNG.description.intro}
</Typography>
<Typography variant="body2">{PANDUAN_REKAM_SSP.description.textList}</Typography>
<Typography variant="body2">{PANDUAN_REKAM_DIGUNGGUNG.description.textList}</Typography>
<Box component="ol" sx={{ pl: 3, mb: 2 }}>
{PANDUAN_REKAM_SSP.description.list.map((item, idx) => (
{PANDUAN_REKAM_DIGUNGGUNG.description.list.map((item, idx) => (
<Typography key={`desc-${idx}`} variant="body2" component="li">
{item}
</Typography>
......@@ -109,11 +109,11 @@ const PanduanSspRekam: FC<PanduanDnRekamProps> = ({ handleOpen, isOpen }) => (
</Box>
<Typography variant="body2" sx={{ mb: 2 }}>
{PANDUAN_REKAM_SSP.description.closing}
{PANDUAN_REKAM_DIGUNGGUNG.description.closing}
</Typography>
{/* Bagian-bagian */}
{PANDUAN_REKAM_SSP.sections.map((section, i) => (
{PANDUAN_REKAM_DIGUNGGUNG.sections.map((section, i) => (
<Box key={`section-${i}`} sx={{ mb: 2 }}>
<Typography
variant="body2"
......
......@@ -632,7 +632,7 @@ export const JENIS_DOKUMEN = [
},
];
export const PANDUAN_REKAM_SSP = {
export const PANDUAN_REKAM_DIGUNGGUNG = {
description: {
intro:
'Form ini digunakan untuk melakukan perekaman/perubahan data Bukti Setor atas PPh yang disetor sendiri.\n',
......
......@@ -38,7 +38,7 @@ import useAdvancedFilter from '../hooks/useAdvancedFilterDigunggung';
import { CustomToolbar } from '../components/CustomToolbar';
import { useSelector } from 'react-redux';
import type { RootState } from 'src/store';
import useGetSsp from '../hooks/useGetDigunggung';
import useGetDigunggung from '../hooks/useGetDigunggung';
import ModalDeleteDigunggung from '../components/dialog/ModalDeleteDigunggung';
import ModalUploadDigunggung from '../components/dialog/ModalUploadDigunggung';
import ModalCancelDigunggung from '../components/dialog/ModalCancelDigunggung';
......@@ -168,7 +168,7 @@ export function DigunggungListView() {
return buildRequestParams(baseParams, advanced);
}, [page, pageSize, sortModel, filterModel.items, buildAdvancedFilter, buildRequestParams]);
const { data, isFetching, refetch } = useGetSsp({
const { data, isFetching, refetch } = useGetDigunggung({
params,
});
const idStatusMapRef = useRef<Map<string | number, string>>(new Map());
......@@ -519,6 +519,12 @@ export function DigunggungListView() {
},
'& .MuiDataGrid-columnHeaders': { borderColor: 'divider' },
}}
onColumnVisibilityModelChange={(newModel) => {
if (newModel['__check__'] === false) {
newModel['__check__'] = true; // paksa tetap tampil
}
apiRef.current?.setColumnVisibilityModel(newModel);
}}
disableVirtualization
/>
</DashboardContent>
......@@ -531,6 +537,9 @@ export function DigunggungListView() {
isOpenDialogDelete={isDeleteModalOpen}
setIsOpenDialogDelete={setIsDeleteModalOpen}
successMessage="Data berhasil dihapus"
onConfirmDelete={async () => {
await refetch();
}}
/>
)}
......@@ -542,6 +551,9 @@ export function DigunggungListView() {
isOpenDialogUpload={isUploadModalOpen}
setIsOpenDialogUpload={setIsUploadModalOpen}
successMessage="Data berhasil diupload"
onConfirmUpload={async () => {
await refetch();
}}
/>
)}
......@@ -553,6 +565,9 @@ export function DigunggungListView() {
isOpenDialogCancel={isCancelModalOpen}
setIsOpenDialogCancel={setIsCancelModalOpen}
successMessage="Data berhasil diupload"
onConfirmCancel={async () => {
await refetch();
}}
/>
)}
......
......@@ -16,7 +16,7 @@ import useGetKodeObjekPajak from '../hooks/useGetKodeObjekPajakDigunggung';
import DokumenReferensi from '../components/rekamDigunggung/DokumenReferensi';
import Agreement from 'src/shared/components/agreement/Agreement';
import Stack from '@mui/material/Stack';
import PanduanSspRekam from '../components/rekamDigunggung/PanduanSspRekam';
import PanduanDigunggungRekam from '../components/rekamDigunggung/PanduanDigunggungRekam';
import useSaveSsp from '../hooks/useSaveDigunggung';
import { enqueueSnackbar } from 'notistack';
import { useNavigate, useParams } from 'react-router';
......@@ -329,7 +329,7 @@ const DigunggungRekamView = () => {
</FormProvider>
</Grid>
<Grid size={{ xs: isOpenPanduan ? 4 : 1 }}>
<PanduanSspRekam handleOpen={handleOpenPanduan} isOpen={isOpenPanduan} />
<PanduanDigunggungRekam handleOpen={handleOpenPanduan} isOpen={isOpenPanduan} />
</Grid>
</Grid>
......
// import React, { useMemo, useState } from 'react';
// import { Stack, Button, Typography } from '@mui/material';
// import { useQueryClient } from '@tanstack/react-query';
// import { enqueueSnackbar } from 'notistack';
// import { DatePicker } from '@mui/x-date-pickers/DatePicker';
// import dayjs, { Dayjs } from 'dayjs';
// import minMax from 'dayjs/plugin/minMax';
// import DialogUmum from 'src/shared/components/dialog/DialogUmum';
// import DialogProgressBar from 'src/shared/components/dialog/DialogProgressBar';
// import useDialogProgressBar from 'src/shared/hooks/useDialogProgressBar';
// import useCancelDn from '../../hooks/useCancelDn';
// import { GridRowSelectionModel } from '@mui/x-data-grid-premium';
// dayjs.extend(minMax);
// // Helper format tanggal ke format API (DDMMYYYY)
// const formatDateDDMMYYYY = (d: Date) => {
// const dd = String(d.getDate()).padStart(2, '0');
// const mm = String(d.getMonth() + 1).padStart(2, '0');
// const yyyy = d.getFullYear();
// return `${dd}${mm}${yyyy}`;
// };
// interface ModalCancelDnProps {
// dataSelected?: any[]; // ✅ array of full row data (dari dataSelectedRef.current)
// setSelectionModel?: React.Dispatch<React.SetStateAction<GridRowSelectionModel | undefined>>;
// tableApiRef?: React.MutableRefObject<any>;
// isOpenDialogCancel: boolean;
// setIsOpenDialogCancel: (v: boolean) => void;
// successMessage?: string;
// }
// const ModalCancelDn: React.FC<ModalCancelDnProps> = ({
// dataSelected = [],
// setSelectionModel,
// tableApiRef,
// isOpenDialogCancel,
// setIsOpenDialogCancel,
// successMessage = 'Data berhasil dibatalkan',
// }) => {
// const queryClient = useQueryClient();
// const [tglPembatalan, setTglPembatalan] = useState<Dayjs | null>(null);
// const [isOpenDialogProgressBar, setIsOpenDialogProgressBar] = useState(false);
// const {
// numberOfData,
// numberOfDataFail,
// numberOfDataProcessed,
// numberOfDataSuccess,
// processSuccess,
// processFail,
// resetToDefault,
// status,
// } = useDialogProgressBar();
// const { mutateAsync } = useCancelDn({
// onSuccess: () => processSuccess(),
// onError: () => processFail(),
// });
// // ✅ Ambil tanggal pemotongan paling awal (minDate untuk DatePicker)
// const minPembatalanDate = useMemo(() => {
// if (!dataSelected.length) return null;
// const dates = dataSelected
// .map((d) => {
// const tgl = d.tglPemotongan || d.tglpemotongan;
// return tgl ? dayjs(tgl, ['YYYY-MM-DD', 'DD/MM/YYYY']) : null;
// })
// .filter((d): d is Dayjs => !!d && d.isValid());
// return dates.length > 0 ? dayjs.min(dates) : null;
// }, [dataSelected]);
// const handleCloseModal = () => {
// setIsOpenDialogCancel(false);
// resetToDefault();
// };
// const clearSelection = () => {
// tableApiRef?.current?.setRowSelectionModel?.([]);
// setSelectionModel?.(undefined);
// };
// const handleSubmit = async () => {
// if (!tglPembatalan) {
// enqueueSnackbar('Tanggal pembatalan harus diisi', { variant: 'warning' });
// return;
// }
// const formattedDate = formatDateDDMMYYYY(tglPembatalan.toDate());
// const ids = dataSelected.map((item) => String(item.id ?? item.internal_id));
// try {
// setIsOpenDialogProgressBar(true);
// const results = await Promise.allSettled(
// ids.map((id) => mutateAsync({ id, tglPembatalan: formattedDate }))
// );
// const rejected = results.filter((r) => r.status === 'rejected');
// const success = results.filter((r) => r.status === 'fulfilled');
// if (rejected.length > 0) {
// const errorMessages = rejected
// .map((r) => (r.status === 'rejected' ? r.reason?.message : ''))
// .filter(Boolean)
// .join('\n');
// enqueueSnackbar(
// <span style={{ whiteSpace: 'pre-line' }}>
// {errorMessages || `${rejected.length} dari ${ids.length} data gagal dibatalkan.`}
// </span>,
// { variant: 'error' }
// );
// processFail();
// } else {
// enqueueSnackbar(successMessage, { variant: 'success' });
// processSuccess();
// }
// // ✅ Langkah penting:
// // tunggu sampai React Query benar-benar refetch data baru
// await queryClient.invalidateQueries({ queryKey: ['unifikasi', 'dn'] });
// // ✅ lalu clear selection di DataGrid
// tableApiRef?.current?.setRowSelectionModel?.([]);
// setSelectionModel?.(undefined);
// handleCloseModal();
// } catch (error: any) {
// enqueueSnackbar(error?.message || 'Gagal membatalkan data', { variant: 'error' });
// } finally {
// setIsOpenDialogProgressBar(false);
// }
// };
// return (
// <>
// {/* ✅ Dialog reusable */}
// <DialogUmum
// isOpen={isOpenDialogCancel}
// onClose={handleCloseModal}
// title="Batal Bukti Pemotongan/Pemungutan PPh Unifikasi"
// >
// <Stack spacing={2}>
// <Typography>
// Silakan isi tanggal pembatalan. Tanggal tidak boleh sebelum tanggal pemotongan.
// </Typography>
// <DatePicker
// label="Tanggal Pembatalan"
// format="DD/MM/YYYY"
// value={tglPembatalan}
// maxDate={dayjs()} // tanggal maksimal = hari ini
// minDate={minPembatalanDate || undefined} // 🔹 minDate sesuai tglPemotongan
// onChange={(newValue) => setTglPembatalan(newValue)}
// slotProps={{
// textField: {
// size: 'medium',
// fullWidth: true,
// helperText:
// minPembatalanDate && `Tanggal minimal: ${minPembatalanDate.format('DD/MM/YYYY')}`,
// InputLabelProps: { shrink: true },
// sx: {
// '& .MuiOutlinedInput-root': {
// borderRadius: 1.5,
// backgroundColor: '#fff',
// '&:hover fieldset': {
// borderColor: '#123375 !important',
// },
// '&.Mui-focused fieldset': {
// borderColor: '#123375 !important',
// borderWidth: '1px',
// },
// },
// },
// },
// }}
// />
// <Stack direction="row" justifyContent="flex-end" spacing={1} mt={1}>
// <Button variant="outlined" onClick={handleCloseModal}>
// Batal
// </Button>
// <Button
// variant="contained"
// color="error"
// onClick={handleSubmit}
// disabled={!tglPembatalan}
// >
// Batalkan
// </Button>
// </Stack>
// </Stack>
// </DialogUmum>
// {/* ✅ Dialog progress bar */}
// <DialogProgressBar
// isOpen={isOpenDialogProgressBar}
// handleClose={() => {
// handleCloseModal();
// setIsOpenDialogProgressBar(false);
// }}
// numberOfData={numberOfData}
// numberOfDataProcessed={numberOfDataProcessed}
// numberOfDataFail={numberOfDataFail}
// numberOfDataSuccess={numberOfDataSuccess}
// status={status}
// />
// </>
// );
// };
// export default ModalCancelDn;
import React, { useEffect, useMemo, useState } from 'react';
import { Stack, Button, Typography } from '@mui/material';
import { useQueryClient } from '@tanstack/react-query';
......@@ -246,6 +29,7 @@ interface ModalCancelDnProps {
isOpenDialogCancel: boolean;
setIsOpenDialogCancel: (v: boolean) => void;
successMessage?: string;
onConfirmCancel?: () => Promise<void> | void;
}
const ModalCancelDn: React.FC<ModalCancelDnProps> = ({
......@@ -255,6 +39,7 @@ const ModalCancelDn: React.FC<ModalCancelDnProps> = ({
isOpenDialogCancel,
setIsOpenDialogCancel,
successMessage = 'Data berhasil dibatalkan',
onConfirmCancel,
}) => {
const queryClient = useQueryClient();
......@@ -339,6 +124,8 @@ const ModalCancelDn: React.FC<ModalCancelDnProps> = ({
if (success.length > 0) {
enqueueSnackbar(successMessage, { variant: 'success' });
processSuccess();
await onConfirmCancel?.();
}
// ✅ update cache data lokal agar status langsung berubah
......
......@@ -14,6 +14,7 @@ interface ModalDeleteDnProps {
isOpenDialogDelete: boolean;
setIsOpenDialogDelete: (v: boolean) => void;
successMessage?: string;
onConfirmDelete?: () => Promise<void> | void;
}
/**
......@@ -51,6 +52,7 @@ const ModalDeleteDn: React.FC<ModalDeleteDnProps> = ({
isOpenDialogDelete,
setIsOpenDialogDelete,
successMessage = 'Data berhasil dihapus',
onConfirmDelete,
}) => {
const queryClient = useQueryClient();
......@@ -99,6 +101,9 @@ const ModalDeleteDn: React.FC<ModalDeleteDnProps> = ({
setIsOpenDialogProgressBar(true);
await handleMultipleDelete();
enqueueSnackbar(successMessage, { variant: 'success' });
await onConfirmDelete?.();
handleCloseModal();
clearSelection();
} catch (error: any) {
......
......@@ -118,6 +118,10 @@ const ModalUploadDn: React.FC<ModalUploadDnProps> = ({
setIsOpenDialogProgressBar(true);
await handleMultipleDelete();
enqueueSnackbar(successMessage, { variant: 'success' });
// ✅ refetch langsung setelah sukses
await onConfirmUpload?.();
handleCloseModal();
clearSelection();
} catch (error: any) {
......@@ -158,16 +162,7 @@ const ModalUploadDn: React.FC<ModalUploadDnProps> = ({
<Button
type="button"
disabled={!isCheckedAgreement}
// onClick={onSubmit}
onClick={async () => {
if (onConfirmUpload) {
await onConfirmUpload();
setIsOpenDialogUpload(false);
return;
}
await onSubmit();
}}
onClick={onSubmit}
loading={uploadDn.isPending}
variant="contained"
sx={{ background: '#143B88' }}
......
......@@ -585,6 +585,9 @@ export function DnListView() {
isOpenDialogDelete={isDeleteModalOpen}
setIsOpenDialogDelete={setIsDeleteModalOpen}
successMessage="Data berhasil dihapus"
onConfirmDelete={async () => {
await refetch();
}}
/>
)}
......@@ -596,6 +599,9 @@ export function DnListView() {
isOpenDialogUpload={isUploadModalOpen}
setIsOpenDialogUpload={setIsUploadModalOpen}
successMessage="Data berhasil diupload"
onConfirmUpload={async () => {
await refetch();
}}
/>
)}
......@@ -607,6 +613,9 @@ export function DnListView() {
isOpenDialogCancel={isCancelModalOpen}
setIsOpenDialogCancel={setIsCancelModalOpen}
successMessage="Data berhasil diupload"
onConfirmCancel={async () => {
await refetch();
}}
/>
)}
......
......@@ -22,22 +22,24 @@ const formatDateDDMMYYYY = (d: Date) => {
return `${dd}${mm}${yyyy}`;
};
interface ModalCancelDnProps {
interface ModalCancelNrProps {
dataSelected?: any[];
setSelectionModel?: React.Dispatch<React.SetStateAction<GridRowSelectionModel | undefined>>;
tableApiRef?: React.MutableRefObject<any>;
isOpenDialogCancel: boolean;
setIsOpenDialogCancel: (v: boolean) => void;
successMessage?: string;
onConfirmCancel?: () => Promise<void> | void;
}
const ModalCancelNr: React.FC<ModalCancelDnProps> = ({
const ModalCancelNr: React.FC<ModalCancelNrProps> = ({
dataSelected = [],
setSelectionModel,
tableApiRef,
isOpenDialogCancel,
setIsOpenDialogCancel,
successMessage = 'Data berhasil dibatalkan',
onConfirmCancel,
}) => {
const queryClient = useQueryClient();
......@@ -122,6 +124,8 @@ const ModalCancelNr: React.FC<ModalCancelDnProps> = ({
if (success.length > 0) {
enqueueSnackbar(successMessage, { variant: 'success' });
processSuccess();
await onConfirmCancel?.();
}
// ✅ update cache data lokal agar status langsung berubah
......
......@@ -14,6 +14,7 @@ interface ModalDeleteDnProps {
isOpenDialogDelete: boolean;
setIsOpenDialogDelete: (v: boolean) => void;
successMessage?: string;
onConfirmDelete?: () => Promise<void> | void;
}
/**
......@@ -51,6 +52,7 @@ const ModalDeleteNr: React.FC<ModalDeleteDnProps> = ({
isOpenDialogDelete,
setIsOpenDialogDelete,
successMessage = 'Data berhasil dihapus',
onConfirmDelete,
}) => {
const queryClient = useQueryClient();
......@@ -99,6 +101,9 @@ const ModalDeleteNr: React.FC<ModalDeleteDnProps> = ({
setIsOpenDialogProgressBar(true);
await handleMultipleDelete();
enqueueSnackbar(successMessage, { variant: 'success' });
await onConfirmDelete?.();
handleCloseModal();
clearSelection();
} catch (error: any) {
......
......@@ -23,7 +23,6 @@ interface ModalUploadNrProps {
isOpenDialogUpload: boolean;
setIsOpenDialogUpload: (v: boolean) => void;
successMessage?: string;
// onConfirmUpload?: () => void;
onConfirmUpload?: () => Promise<void> | void;
}
......@@ -118,6 +117,10 @@ const ModalUploadNr: React.FC<ModalUploadNrProps> = ({
setIsOpenDialogProgressBar(true);
await handleMultipleDelete();
enqueueSnackbar(successMessage, { variant: 'success' });
// ✅ refetch langsung setelah sukses
await onConfirmUpload?.();
handleCloseModal();
clearSelection();
} catch (error: any) {
......@@ -158,16 +161,7 @@ const ModalUploadNr: React.FC<ModalUploadNrProps> = ({
<Button
type="button"
disabled={!isCheckedAgreement}
onClick={async () => {
if (onConfirmUpload) {
await onConfirmUpload();
setIsOpenDialogUpload(false);
return;
}
await onSubmit();
}}
onClick={onSubmit}
loading={uploadNr.isPending}
variant="contained"
sx={{ background: '#143B88' }}
......
import type { FC} from 'react';
import type { FC } from 'react';
import { Fragment, memo } from 'react';
import { Box, Button, Card, CardContent, CardHeader, IconButton, Typography } from '@mui/material';
import { ChevronRightRounded, CloseRounded } from '@mui/icons-material';
import { m } from 'framer-motion';
import { PANDUAN_REKAM_DN } from '../../constant';
import { PANDUAN_REKAM_NR } from '../../constant';
interface PanduanDnRekamProps {
handleOpen: () => void;
......@@ -95,13 +95,13 @@ const PanduanDnRekam: FC<PanduanDnRekamProps> = ({ handleOpen, isOpen }) => (
<Typography variant="body2" sx={{ mb: 2, whiteSpace: 'pre-line' }}>
<strong>Deskripsi Form:</strong>
<br />
{PANDUAN_REKAM_DN.description.intro}
{PANDUAN_REKAM_NR.description.intro}
</Typography>
<Typography variant="body2">{PANDUAN_REKAM_DN.description.textList}</Typography>
<Typography variant="body2">{PANDUAN_REKAM_NR.description.textList}</Typography>
<Box component="ol" sx={{ pl: 3, mb: 2 }}>
{PANDUAN_REKAM_DN.description.list.map((item, idx) => (
{PANDUAN_REKAM_NR.description.list.map((item, idx) => (
<Typography key={`desc-${idx}`} variant="body2" component="li">
{item}
</Typography>
......@@ -109,11 +109,11 @@ const PanduanDnRekam: FC<PanduanDnRekamProps> = ({ handleOpen, isOpen }) => (
</Box>
<Typography variant="body2" sx={{ mb: 2 }}>
{PANDUAN_REKAM_DN.description.closing}
{PANDUAN_REKAM_NR.description.closing}
</Typography>
{/* Bagian-bagian */}
{PANDUAN_REKAM_DN.sections.map((section, i) => (
{PANDUAN_REKAM_NR.sections.map((section, i) => (
<Box key={`section-${i}`} sx={{ mb: 2 }}>
<Typography
variant="body2"
......
......@@ -646,7 +646,7 @@ export const JENIS_DOKUMEN = [
},
];
export const PANDUAN_REKAM_DN = {
export const PANDUAN_REKAM_NR = {
description: {
intro:
'Form ini digunakan untuk melakukan perekaman data baru Bukti Pemotongan PPh Unifikasi serta perubahannya.\n',
......@@ -665,31 +665,43 @@ export const PANDUAN_REKAM_DN = {
title: 'BAGIAN I, Identitas Wajib Pajak yang Dipotong/Dipungut',
items: [
{
text: 'Tahun Pajak, Tentukan tahun pajak saat melakukan pemotongan Pajak Penghasilan, tahun paling awal adalah 2022.',
text: 'Tentukan tahun pajak saat melakukan pemotongan Pajak Penghasilan, tahun paling awal adalah 2022.',
subItems: [],
},
{
text: 'Masa Pajak, Tentukan Masa Pajak yang sesuai untuk transaksi pemotongan Pajak Penghasilan, pilihan terdiri dari masa Januari s.d. Desember bergantung pada tahun pajak yang Anda pilih.',
text: 'Tentukan Masa Pajak yang sesuai untuk transaksi pemotongan Pajak Penghasilan, pilihan terdiri dari masa Januari s.d. Februari bergantung pada tahun pajak yang Anda Pilih.',
subItems: [],
},
{
text: 'Identitas, isikan sesuai dengan nomor identitas, identitas yang diperbolehkan digunakan hanya NPWP atau NIK (KTP), jika tidak memiliki, maka tidak diperbolehkan untuk dilakukan perekaman data dengan ketentuan yang berlaku.',
text: 'Nomor Bukti Potong, isikan nomor bukti potong sesuai dengan ketentuan yang berlaku.',
subItems: [],
},
{
text: 'Tidak diperbolehkan menggunakan identitas yang tidak valid.',
text: 'Tax ID Number (TIN), Id ini harus diisi dengan data yang valid, tidak diperbolehkan mengisi dengan nilai "0000."',
subItems: [],
},
{
text: 'Nama, isikan dengan nama Wajib Pajak sesuai dengan nomor identitas yang dimasukkan.',
text: 'Isikan nama wajib pajak sesuai dengan yang tertera pada dokumen kewarganegaraan atau Paspor.',
subItems: [],
},
{
text: 'Jika terdapat transaksi perwakilan, centang kolom QQ dan isikan nama Wajib Pajak yang diwakili.',
text: 'Isikan alamat wajib pajak sesuai dengan dokumen kewarganegaraannya.',
subItems: [],
},
{
text: 'Jika menggunakan NIK, isikan kolom Alasan pengisian NIK tanpa validasi.',
text: 'Isi asal negara yang sesuai dari pilihan yang tersedia.',
subItems: [],
},
{
text: 'Isikan tanggal lahir sesuai dengan dokumen kewarganegaraannya.',
subItems: [],
},
{
text: 'No Paspor, cukup jelas.',
subItems: [],
},
{
text: 'No KITAS/KITAP, cukup jelas.',
subItems: [],
},
],
......@@ -698,24 +710,24 @@ export const PANDUAN_REKAM_DN = {
title: 'BAGIAN II, Penghasilan yang Dipotong/Dipungut',
items: [
{
text: 'Pilih Kode Objek Pajak dari pilihan yang tersedia, Anda dapat mengetikkan kata kunci untuk mempercepat pencarian objek pajak.',
text: 'Pilihlah Kode Objek Pajak dari pilihan yang tersedia, Anda dapat mengetikkankata kunci untuk mempercepat pencarian objek pajak. Dengan memilih Kode Objek Pajak, sistem akan melakukan pencarian secara otomatis terhadap fasilitas yang dimiliki oleh Wajib Pajak.',
subItems: [],
},
{
text: 'Pilihlah fasilitas yang dimiliki oleh Wajib Pajak:',
subItems: [
'Jika tidak memiliki fasilitas, maka pilihlah pilihan tanpa fasilitas pada pilihan yang tersedia. Tidak memiliki fasilitas akan menjadi pilihan utama (default).',
'Jika memiliki fasilitas berupa Surat Keterangan Bebas (SKB), masukkan nomor SKB yang dimiliki.',
'Jika memiliki fasilitas DTP, masukkan Nomor Dokumen Pendukung.',
'Jika tidak memiliki fasilitas, maka pilihlah pilihan tanpa fasilitas pada pilihan yang tersedia.',
'Jika memiliki fasilitas berupa dikenakan tarif sesuai Perjanjian Penghindaran Pajak Berganda (P3B), masukan nomor tanda terima SKD WPLN.',
'Jika memiliki fasilitas DTP, masukkan Nomor Dokumen Pendukungnya serta NTPN atas pembayaran Penghasilan yang Ditanggung Pemerintah.',
'Jika memiliki fasilitas lainnya, masukkan Nomor Dokumen Fasilitas lainnya.',
],
},
{
text: 'Dengan memilih Kode Objek Pajak, Sistem akan melakukan pencarian secara otomatis tarif dari jenis objek pajak.',
text: 'Secara default tarif terisi otomatis berdasarkan Kode Objek Pajak yang dipilih, tetapi jika menggunakan fasilitas SKD WPLN atau Fasilitas Lainnya, maka Wajib Pajak harus mengisikan tarif secara manual.',
subItems: [],
},
{
text: 'Isikan nilai nominal Penghasilan Bruto pada kotak yang tersedia, Sistem akan menghitung secara otomatis nilai Pajak Penghasilan yang Dipotong/Dipungut.',
text: 'Isikan nilai nominal Penghasilan Bruto pada kotak yang tersedia, Sistem akan menghitung secara otomatis nilai Pajak Penghasilan yang dipotong.',
subItems: [],
},
],
......@@ -724,7 +736,7 @@ export const PANDUAN_REKAM_DN = {
title: 'BAGIAN III, Dokumen Pendukung',
items: [
{
text: 'Anda diharuskan mengisi minimal 1 (satu) dokumen pendukung untuk pemotongan penghasilan. Untuk mengisi dokumen pendukung, klik tombol tambah, kemudian, isilah data dokumen pendukung yang sesuai.',
text: 'Anda diharuskan mengisi minimal 1(satu) dokumen pendukung untuk pemotongan penghasilan. Untuk mengisi dokumen pendukung, klik tombol tambah, kemudian, isilah data dokumen pendukung yang sesuai.',
subItems: [],
},
],
......@@ -737,11 +749,15 @@ export const PANDUAN_REKAM_DN = {
subItems: [],
},
{
text: 'Pada bagian ini, Anda harus menentukan, pihak yang akan menandatangani dokumen bukti pemotongan ini apakah Wakil Wajib Pajak/Pengurus atau Kuasa.',
text: 'Pada bagian ini, Anda harus menentukan, pihak yang akan menandatangani dokumen bukti pemotongan ini apakah Wajib Pajak/Wakil Wajib Pajak atau Kuasa.',
subItems: [],
},
{
text: 'Tanggal Pemotongan adalah secara otomatis tanggal dari Sistem pada saat direkam Bukti Pemotongan.',
subItems: [],
},
{
text: 'Pastikan isian Anda telah lengkap dan benar, kemudian centang pernyataan yang disediakan yang menunjukkan Anda telah dengan seksama memastikan kebenaran isi dari bukti pemotongan yang dibuat, kemudian klik tombol simpan untuk menyimpan data.',
text: 'Pastikan isian Anda telah lengkap dan benar, kemudian checklist pernyataan yang disediakan yang menunjukkan Anda telah dengan seksama memastikan kebenaran isi dari bukti pemotongan yang dibuat, kemudian klik tombol simpan untuk menyimpan data.',
subItems: [],
},
],
......
......@@ -571,6 +571,9 @@ export function NrListView() {
isOpenDialogDelete={isDeleteModalOpen}
setIsOpenDialogDelete={setIsDeleteModalOpen}
successMessage="Data berhasil dihapus"
onConfirmDelete={async () => {
await refetch();
}}
/>
)}
......@@ -582,6 +585,9 @@ export function NrListView() {
isOpenDialogUpload={isUploadModalOpen}
setIsOpenDialogUpload={setIsUploadModalOpen}
successMessage="Data berhasil diupload"
onConfirmUpload={async () => {
await refetch();
}}
/>
)}
......@@ -593,6 +599,9 @@ export function NrListView() {
isOpenDialogCancel={isCancelModalOpen}
setIsOpenDialogCancel={setIsCancelModalOpen}
successMessage="Data berhasil diupload"
onConfirmCancel={async () => {
await refetch();
}}
/>
)}
......
......@@ -16,7 +16,7 @@ import useGetKodeObjekPajak from '../hooks/useGetKodeObjekPajakNr';
import DokumenReferensi from '../components/rekamNr/DokumenReferensi';
import Agreement from 'src/shared/components/agreement/Agreement';
import Stack from '@mui/material/Stack';
import PanduanDnRekam from '../components/rekamNr/PanduanDnRekam';
import PanduanNrRekam from '../components/rekamNr/PanduanNrRekam';
import useSaveNr from '../hooks/useSaveNr';
import { enqueueSnackbar } from 'notistack';
import { useNavigate, useParams } from 'react-router';
......@@ -367,7 +367,7 @@ const NrRekamView = () => {
</FormProvider>
</Grid>
<Grid size={{ xs: isOpenPanduan ? 4 : 1 }}>
<PanduanDnRekam handleOpen={handleOpenPanduan} isOpen={isOpenPanduan} />
<PanduanNrRekam handleOpen={handleOpenPanduan} isOpen={isOpenPanduan} />
</Grid>
</Grid>
......
......@@ -29,6 +29,7 @@ interface ModalCancelSspProps {
isOpenDialogCancel: boolean;
setIsOpenDialogCancel: (v: boolean) => void;
successMessage?: string;
onConfirmCancel?: () => Promise<void> | void;
}
const ModalCancelSsp: React.FC<ModalCancelSspProps> = ({
......@@ -38,6 +39,7 @@ const ModalCancelSsp: React.FC<ModalCancelSspProps> = ({
isOpenDialogCancel,
setIsOpenDialogCancel,
successMessage = 'Data berhasil dibatalkan',
onConfirmCancel,
}) => {
const queryClient = useQueryClient();
......@@ -122,6 +124,8 @@ const ModalCancelSsp: React.FC<ModalCancelSspProps> = ({
if (success.length > 0) {
enqueueSnackbar(successMessage, { variant: 'success' });
processSuccess();
await onConfirmCancel?.();
}
// ✅ update cache data lokal agar status langsung berubah
......
......@@ -14,6 +14,7 @@ interface ModalDeleteSspProps {
isOpenDialogDelete: boolean;
setIsOpenDialogDelete: (v: boolean) => void;
successMessage?: string;
onConfirmDelete?: () => Promise<void> | void;
}
/**
......@@ -51,6 +52,7 @@ const ModalDeleteSsp: React.FC<ModalDeleteSspProps> = ({
isOpenDialogDelete,
setIsOpenDialogDelete,
successMessage = 'Data berhasil dihapus',
onConfirmDelete,
}) => {
const queryClient = useQueryClient();
......@@ -99,6 +101,9 @@ const ModalDeleteSsp: React.FC<ModalDeleteSspProps> = ({
setIsOpenDialogProgressBar(true);
await handleMultipleDelete();
enqueueSnackbar(successMessage, { variant: 'success' });
await onConfirmDelete?.();
handleCloseModal();
clearSelection();
} catch (error: any) {
......
......@@ -23,7 +23,6 @@ interface ModalUploadSspProps {
isOpenDialogUpload: boolean;
setIsOpenDialogUpload: (v: boolean) => void;
successMessage?: string;
// onConfirmUpload?: () => void;
onConfirmUpload?: () => Promise<void> | void;
}
......@@ -66,7 +65,7 @@ const ModalUploadSsp: React.FC<ModalUploadSspProps> = ({
}) => {
const queryClient = useQueryClient();
const uploadNr = useUpload();
const uploadSsp = useUpload();
// custom hooks for progress state
const {
numberOfData,
......@@ -118,6 +117,10 @@ const ModalUploadSsp: React.FC<ModalUploadSspProps> = ({
setIsOpenDialogProgressBar(true);
await handleMultipleDelete();
enqueueSnackbar(successMessage, { variant: 'success' });
// ✅ refetch langsung setelah sukses
await onConfirmUpload?.();
handleCloseModal();
clearSelection();
} catch (error: any) {
......@@ -158,17 +161,8 @@ const ModalUploadSsp: React.FC<ModalUploadSspProps> = ({
<Button
type="button"
disabled={!isCheckedAgreement}
onClick={async () => {
if (onConfirmUpload) {
await onConfirmUpload();
setIsOpenDialogUpload(false);
return;
}
await onSubmit();
}}
loading={uploadNr.isPending}
onClick={onSubmit}
loading={uploadSsp.isPending}
variant="contained"
sx={{ background: '#143B88' }}
>
......
......@@ -531,6 +531,9 @@ export function SspListView() {
isOpenDialogDelete={isDeleteModalOpen}
setIsOpenDialogDelete={setIsDeleteModalOpen}
successMessage="Data berhasil dihapus"
onConfirmDelete={async () => {
await refetch();
}}
/>
)}
......@@ -542,6 +545,9 @@ export function SspListView() {
isOpenDialogUpload={isUploadModalOpen}
setIsOpenDialogUpload={setIsUploadModalOpen}
successMessage="Data berhasil diupload"
onConfirmUpload={async () => {
await refetch();
}}
/>
)}
......@@ -553,6 +559,9 @@ export function SspListView() {
isOpenDialogCancel={isCancelModalOpen}
setIsOpenDialogCancel={setIsCancelModalOpen}
successMessage="Data berhasil diupload"
onConfirmCancel={async () => {
await refetch();
}}
/>
)}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment