mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-25 07:45:47 +00:00
feat(FE-170,174,175): implement approval steps in RecordingForm and remove unused form step status
This commit is contained in:
@@ -23,6 +23,7 @@ import {
|
|||||||
} from '@/services/api/production';
|
} from '@/services/api/production';
|
||||||
import { LocationApi } from '@/services/api/master-data';
|
import { LocationApi } from '@/services/api/master-data';
|
||||||
import { ProductWarehouseApi } from '@/services/api/inventory';
|
import { ProductWarehouseApi } from '@/services/api/inventory';
|
||||||
|
import { ApprovalApi } from '@/services/api/approval';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CreateGrowingRecordingPayload,
|
CreateGrowingRecordingPayload,
|
||||||
@@ -31,7 +32,11 @@ import {
|
|||||||
UpdateLayingRecordingPayload,
|
UpdateLayingRecordingPayload,
|
||||||
Recording,
|
Recording,
|
||||||
} from '@/types/api/production/recording';
|
} from '@/types/api/production/recording';
|
||||||
import { type BaseApiResponse, FormStepStatus } from '@/types/api/api-general';
|
import {
|
||||||
|
type BaseApiResponse,
|
||||||
|
BaseApproval,
|
||||||
|
BaseGroupedApproval,
|
||||||
|
} from '@/types/api/api-general';
|
||||||
import { ProjectFlockKandangLookup } from '@/types/api/production/project-flock';
|
import { ProjectFlockKandangLookup } from '@/types/api/production/project-flock';
|
||||||
import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang';
|
import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang';
|
||||||
import { Kandang } from '@/types/api/master-data/kandang';
|
import { Kandang } from '@/types/api/master-data/kandang';
|
||||||
@@ -50,7 +55,8 @@ import {
|
|||||||
import { isResponseSuccess, isResponseError } from '@/lib/api-helper';
|
import { isResponseSuccess, isResponseError } from '@/lib/api-helper';
|
||||||
import { formatDate } from '@/lib/helper';
|
import { formatDate } from '@/lib/helper';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
import StepItem from '@/components/steps/StepItem';
|
import ApprovalSteps from '@/components/pages/ApprovalSteps';
|
||||||
|
import { RECORDING_APPROVAL_LINE } from '@/config/approval-line';
|
||||||
|
|
||||||
interface RecordingFormProps {
|
interface RecordingFormProps {
|
||||||
type?: 'add' | 'edit' | 'detail';
|
type?: 'add' | 'edit' | 'detail';
|
||||||
@@ -85,7 +91,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
|
|
||||||
const [isApproveLoading, setIsApproveLoading] = useState(false);
|
const [isApproveLoading, setIsApproveLoading] = useState(false);
|
||||||
const [isRejectLoading, setIsRejectLoading] = useState(false);
|
const [isRejectLoading, setIsRejectLoading] = useState(false);
|
||||||
const [formSteps, setFormSteps] = useState<FormStepStatus[] | null>(null);
|
|
||||||
const [recordingFormErrorMessage, setRecordingFormErrorMessage] =
|
const [recordingFormErrorMessage, setRecordingFormErrorMessage] =
|
||||||
useState('');
|
useState('');
|
||||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||||
@@ -330,7 +335,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
location_id: selectedLocation.value.toString(),
|
location_id: selectedLocation.value.toString(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add kandang_id parameter if available from lookup
|
|
||||||
if (projectFlockKandangLookup?.kandang?.id) {
|
if (projectFlockKandangLookup?.kandang?.id) {
|
||||||
params.append(
|
params.append(
|
||||||
'kandang_id',
|
'kandang_id',
|
||||||
@@ -351,7 +355,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
location_id: selectedLocation.value.toString(),
|
location_id: selectedLocation.value.toString(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add kandang_id parameter if available from lookup
|
|
||||||
if (projectFlockKandangLookup?.kandang?.id) {
|
if (projectFlockKandangLookup?.kandang?.id) {
|
||||||
params.append(
|
params.append(
|
||||||
'kandang_id',
|
'kandang_id',
|
||||||
@@ -366,7 +369,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
|
|
||||||
const today = new Date().toISOString().split('T')[0];
|
const today = new Date().toISOString().split('T')[0];
|
||||||
const existingRecordingsUrl = useMemo(() => {
|
const existingRecordingsUrl = useMemo(() => {
|
||||||
return `${RecordingApi.basePath}?record_date=${today}`;
|
const params = new URLSearchParams({
|
||||||
|
record_date: today,
|
||||||
|
});
|
||||||
|
return `${RecordingApi.basePath}?${params.toString()}`;
|
||||||
}, [today]);
|
}, [today]);
|
||||||
|
|
||||||
const { data: existingRecordings } = useSWR(
|
const { data: existingRecordings } = useSWR(
|
||||||
@@ -407,6 +413,231 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
ProductWarehouseApi.getAllFetcher
|
ProductWarehouseApi.getAllFetcher
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ===== APPROVAL DATA FETCHING =====
|
||||||
|
const approvalHistoryUrl = useMemo(() => {
|
||||||
|
if (!initialValues?.id || type !== 'detail') return null;
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
module_name: 'RECORDINGS',
|
||||||
|
module_id: initialValues.id.toString(),
|
||||||
|
group_step_number: 'true',
|
||||||
|
});
|
||||||
|
return `${ApprovalApi.basePath}?${params.toString()}`;
|
||||||
|
}, [initialValues?.id, type]);
|
||||||
|
|
||||||
|
const { data: approvalHistoryData } = useSWR(
|
||||||
|
approvalHistoryUrl,
|
||||||
|
approvalHistoryUrl ? ApprovalApi.getAllFetcher : null
|
||||||
|
);
|
||||||
|
|
||||||
|
// Helper functions for approval data processing
|
||||||
|
const groupApprovalsByStep = useCallback(
|
||||||
|
(approvals: BaseApproval[]): BaseGroupedApproval[] => {
|
||||||
|
const groups: Record<number, BaseGroupedApproval> = {};
|
||||||
|
for (const approval of approvals) {
|
||||||
|
if (!groups[approval.step_number]) {
|
||||||
|
groups[approval.step_number] = {
|
||||||
|
step_number: approval.step_number,
|
||||||
|
step_name: approval.step_name,
|
||||||
|
approvals: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
groups[approval.step_number].approvals.push(approval);
|
||||||
|
}
|
||||||
|
return Object.values(groups);
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
const isGroupedApprovalData = useCallback(
|
||||||
|
(
|
||||||
|
data: BaseApproval[] | BaseGroupedApproval[]
|
||||||
|
): data is BaseGroupedApproval[] => {
|
||||||
|
if (!data || data.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const firstElement = data[0];
|
||||||
|
return (
|
||||||
|
typeof firstElement === 'object' &&
|
||||||
|
firstElement !== null &&
|
||||||
|
'approvals' in firstElement &&
|
||||||
|
Array.isArray(firstElement.approvals)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Process approval data
|
||||||
|
const { groupedApprovals, latestApproval } = useMemo(() => {
|
||||||
|
const latest = initialValues?.approval;
|
||||||
|
|
||||||
|
const rawData = isResponseSuccess(approvalHistoryData)
|
||||||
|
? approvalHistoryData.data
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
let processedGroupedApprovals: BaseGroupedApproval[] = [];
|
||||||
|
|
||||||
|
if (rawData) {
|
||||||
|
if (isGroupedApprovalData(rawData)) {
|
||||||
|
processedGroupedApprovals = rawData as BaseGroupedApproval[];
|
||||||
|
} else {
|
||||||
|
processedGroupedApprovals = groupApprovalsByStep(
|
||||||
|
rawData as BaseApproval[]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
latest &&
|
||||||
|
!processedGroupedApprovals.find(
|
||||||
|
(g) => g.step_number === latest.step_number
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
processedGroupedApprovals.push({
|
||||||
|
step_number: latest.step_number,
|
||||||
|
step_name: latest.step_name,
|
||||||
|
approvals: [latest],
|
||||||
|
});
|
||||||
|
|
||||||
|
processedGroupedApprovals.sort((a, b) => a.step_number - b.step_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
groupedApprovals: processedGroupedApprovals,
|
||||||
|
latestApproval: latest,
|
||||||
|
};
|
||||||
|
}, [
|
||||||
|
approvalHistoryData,
|
||||||
|
initialValues?.approval,
|
||||||
|
isGroupedApprovalData,
|
||||||
|
groupApprovalsByStep,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Format approval steps for display
|
||||||
|
const approvalStepsData = useMemo(() => {
|
||||||
|
if (type !== 'detail') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return RECORDING_APPROVAL_LINE.map(
|
||||||
|
(
|
||||||
|
approvalLineItem
|
||||||
|
): {
|
||||||
|
name: string;
|
||||||
|
status: 'APPROVED' | 'REJECTED' | 'WAITING' | 'IDLE';
|
||||||
|
logs: Array<{
|
||||||
|
action_by?: string;
|
||||||
|
date?: string;
|
||||||
|
notes?: string | null;
|
||||||
|
}>;
|
||||||
|
} => {
|
||||||
|
const approvalGroup = groupedApprovals.find(
|
||||||
|
(approvalGroupItem) =>
|
||||||
|
approvalGroupItem.step_number === approvalLineItem.step_number
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!latestApproval) {
|
||||||
|
return {
|
||||||
|
name: approvalLineItem.step_name,
|
||||||
|
status: 'IDLE',
|
||||||
|
logs: approvalGroup
|
||||||
|
? approvalGroup.approvals.map((approval) => ({
|
||||||
|
action_by: approval.action_by.name,
|
||||||
|
date: approval.action_at,
|
||||||
|
notes: approval.notes,
|
||||||
|
}))
|
||||||
|
: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentStepNumber = approvalLineItem.step_number;
|
||||||
|
const latestStepNumber = latestApproval.step_number;
|
||||||
|
|
||||||
|
if (!approvalGroup) {
|
||||||
|
if (currentStepNumber === latestStepNumber + 1) {
|
||||||
|
return {
|
||||||
|
name: approvalLineItem.step_name,
|
||||||
|
status: 'WAITING',
|
||||||
|
logs: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name: approvalLineItem.step_name,
|
||||||
|
status: 'IDLE',
|
||||||
|
logs: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let approvalStatus: 'APPROVED' | 'REJECTED' | 'WAITING' | 'IDLE' =
|
||||||
|
'IDLE';
|
||||||
|
|
||||||
|
if (currentStepNumber <= latestStepNumber) {
|
||||||
|
if (approvalGroup.approvals && approvalGroup.approvals.length > 0) {
|
||||||
|
const latestApprovalInGroup = approvalGroup.approvals.sort(
|
||||||
|
(a, b) =>
|
||||||
|
new Date(b.action_at).getTime() -
|
||||||
|
new Date(a.action_at).getTime()
|
||||||
|
)[0];
|
||||||
|
|
||||||
|
switch (latestApprovalInGroup.action) {
|
||||||
|
case 'CREATED':
|
||||||
|
case 'APPROVED':
|
||||||
|
approvalStatus = 'APPROVED';
|
||||||
|
break;
|
||||||
|
case 'REJECTED':
|
||||||
|
approvalStatus = 'REJECTED';
|
||||||
|
break;
|
||||||
|
case 'UPDATED':
|
||||||
|
if (currentStepNumber === latestStepNumber) {
|
||||||
|
switch (latestApproval.action) {
|
||||||
|
case 'CREATED':
|
||||||
|
case 'APPROVED':
|
||||||
|
approvalStatus = 'APPROVED';
|
||||||
|
break;
|
||||||
|
case 'REJECTED':
|
||||||
|
approvalStatus = 'REJECTED';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
approvalStatus = 'WAITING';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
approvalStatus = 'APPROVED';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
approvalStatus =
|
||||||
|
currentStepNumber === latestStepNumber
|
||||||
|
? 'WAITING'
|
||||||
|
: 'APPROVED';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (currentStepNumber === latestStepNumber + 1) {
|
||||||
|
approvalStatus = 'WAITING';
|
||||||
|
} else {
|
||||||
|
approvalStatus = 'IDLE';
|
||||||
|
}
|
||||||
|
|
||||||
|
const approvalLogs = approvalGroup.approvals.map((approval) => ({
|
||||||
|
action_by: approval.action_by.name,
|
||||||
|
date: approval.action_at,
|
||||||
|
notes: approval.notes,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: approvalGroup.step_name,
|
||||||
|
status: approvalStatus,
|
||||||
|
logs: approvalLogs,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Gagal memformat approval steps:', error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}, [groupedApprovals, latestApproval, type]);
|
||||||
|
|
||||||
// ===== DATA PROCESSING =====
|
// ===== DATA PROCESSING =====
|
||||||
const locationOptions = useMemo(() => {
|
const locationOptions = useMemo(() => {
|
||||||
let options: OptionType[] = [];
|
let options: OptionType[] = [];
|
||||||
@@ -1058,26 +1289,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
setIsRejectLoading(false);
|
setIsRejectLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isLayingCategory) {
|
|
||||||
const steps: FormStepStatus[] = [
|
|
||||||
{
|
|
||||||
name: 'Recording',
|
|
||||||
isCompleted: type === 'detail',
|
|
||||||
isCurrent: type !== 'detail',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Grading',
|
|
||||||
isCompleted: false,
|
|
||||||
isCurrent: type === 'detail',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
setFormSteps(steps);
|
|
||||||
} else {
|
|
||||||
setFormSteps(null);
|
|
||||||
}
|
|
||||||
}, [isLayingCategory, type]);
|
|
||||||
|
|
||||||
// Body Weights Handlers
|
// Body Weights Handlers
|
||||||
const addBodyWeight = () => {
|
const addBodyWeight = () => {
|
||||||
const newBodyWeights = [
|
const newBodyWeights = [
|
||||||
@@ -1311,23 +1522,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
}, [isLayingCategory, type]);
|
}, [isLayingCategory, type]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isLayingCategory) {
|
|
||||||
const steps: FormStepStatus[] = [
|
|
||||||
{
|
|
||||||
name: 'Recording',
|
|
||||||
isCompleted: type === 'detail',
|
|
||||||
isCurrent: type !== 'detail',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Grading',
|
|
||||||
isCompleted: false,
|
|
||||||
isCurrent: type === 'detail',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
setFormSteps(steps);
|
|
||||||
} else {
|
|
||||||
setFormSteps(null);
|
|
||||||
}
|
|
||||||
if (type !== 'add') {
|
if (type !== 'add') {
|
||||||
setNewRecordingData(null);
|
setNewRecordingData(null);
|
||||||
}
|
}
|
||||||
@@ -1434,38 +1628,31 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
{/* Project Flock Info Card */}
|
{/* Project Flock Info Card */}
|
||||||
{(projectFlockKandangLookup || projectFlockKandangDetail) && (
|
{(projectFlockKandangLookup || projectFlockKandangDetail) && (
|
||||||
<div className='flex items-center gap-2 mb-4'>
|
<div className='flex items-center gap-2 mb-4'>
|
||||||
{/* Form Steps for LAYING Category */}
|
{/* Approval Steps for all categories */}
|
||||||
{formSteps && (
|
{type === 'detail' && approvalStepsData.length > 0 && (
|
||||||
<div className='flex-1 mt-4'>
|
<div className='flex-1 mt-4'>
|
||||||
<div className='w-full'>
|
<ApprovalSteps approvals={approvalStepsData} />
|
||||||
<ul className='steps w-full'>
|
|
||||||
{formSteps.map((step, idx) => (
|
|
||||||
<StepItem
|
|
||||||
key={idx}
|
|
||||||
color={
|
|
||||||
step.isCompleted
|
|
||||||
? 'success'
|
|
||||||
: step.isCurrent
|
|
||||||
? 'primary'
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
icon={
|
|
||||||
step.isCompleted ? (
|
|
||||||
<Icon
|
|
||||||
icon='material-symbols:check-rounded'
|
|
||||||
width={24}
|
|
||||||
height={24}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
idx + 1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{step.name}
|
|
||||||
</StepItem>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
{/* Default approval steps for add/edit modes */}
|
||||||
|
{type !== 'detail' && (
|
||||||
|
<div className='flex-1 mt-4'>
|
||||||
|
<ApprovalSteps
|
||||||
|
approvals={[
|
||||||
|
{
|
||||||
|
name: RECORDING_APPROVAL_LINE[0].step_name,
|
||||||
|
status: 'APPROVED',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: RECORDING_APPROVAL_LINE[1].step_name,
|
||||||
|
status: 'WAITING',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: RECORDING_APPROVAL_LINE[2].step_name,
|
||||||
|
status: 'IDLE',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -1558,10 +1745,56 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className='grid grid-cols-2 md:grid-cols-4 gap-4'>
|
<div className='grid grid-cols-2 md:grid-cols-4 gap-4'>
|
||||||
|
{initialValues.approval && (
|
||||||
<div>
|
<div>
|
||||||
<span className='text-sm text-gray-600'>Recording ID</span>
|
<span className='text-sm text-gray-600'>
|
||||||
<p className='font-semibold'>#{initialValues.id}</p>
|
Status Approval
|
||||||
|
</span>
|
||||||
|
<div className='mt-1'>
|
||||||
|
<Badge
|
||||||
|
variant='soft'
|
||||||
|
color={
|
||||||
|
initialValues.approval.action === 'APPROVED'
|
||||||
|
? 'success'
|
||||||
|
: initialValues.approval.action === 'REJECTED'
|
||||||
|
? 'error'
|
||||||
|
: initialValues.approval.action === 'UPDATED'
|
||||||
|
? 'warning'
|
||||||
|
: 'info'
|
||||||
|
}
|
||||||
|
className={{
|
||||||
|
badge:
|
||||||
|
'whitespace-nowrap font-semibold text-xs px-2',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{(() => {
|
||||||
|
const actionText = (() => {
|
||||||
|
switch (initialValues.approval.action) {
|
||||||
|
case 'APPROVED':
|
||||||
|
return 'Disetujui';
|
||||||
|
case 'REJECTED':
|
||||||
|
return 'Ditolak';
|
||||||
|
case 'CREATED':
|
||||||
|
return 'Dibuat';
|
||||||
|
case 'UPDATED':
|
||||||
|
return 'Diperbarui';
|
||||||
|
default:
|
||||||
|
return initialValues.approval.action;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
const stepName = initialValues.approval.step_name;
|
||||||
|
|
||||||
|
if (stepName === actionText) {
|
||||||
|
return stepName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${stepName} - ${actionText}`;
|
||||||
|
})()}
|
||||||
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div>
|
<div>
|
||||||
<span className='text-sm text-gray-600'>Lokasi</span>
|
<span className='text-sm text-gray-600'>Lokasi</span>
|
||||||
<p className='font-semibold'>
|
<p className='font-semibold'>
|
||||||
|
|||||||
@@ -10,3 +10,18 @@ export const PROJECT_FLOCK_APPROVAL_LINE: ApprovalLine = [
|
|||||||
step_name: 'Aktif',
|
step_name: 'Aktif',
|
||||||
},
|
},
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
export const RECORDING_APPROVAL_LINE: ApprovalLine = [
|
||||||
|
{
|
||||||
|
step_number: 1,
|
||||||
|
step_name: 'Grading-Telur',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
step_number: 2,
|
||||||
|
step_name: 'Pengajuan',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
step_number: 3,
|
||||||
|
step_name: 'Disetujui',
|
||||||
|
},
|
||||||
|
] as const;
|
||||||
|
|||||||
Vendored
-6
@@ -112,12 +112,6 @@ export type BaseGroupedApproval = {
|
|||||||
approvals: BaseApproval[];
|
approvals: BaseApproval[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FormStepStatus = {
|
|
||||||
name: string;
|
|
||||||
isCompleted: boolean;
|
|
||||||
isCurrent: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Approvals = BaseApiResponse<BaseApproval>;
|
export type Approvals = BaseApiResponse<BaseApproval>;
|
||||||
|
|
||||||
export type GroupedApprovals = BaseApiResponse<BaseGroupedApproval[]>;
|
export type GroupedApprovals = BaseApiResponse<BaseGroupedApproval[]>;
|
||||||
|
|||||||
Reference in New Issue
Block a user