mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 05:22:02 +00:00
refactor(FE): Refactor project flock api & implement approval component in project flock details
This commit is contained in:
@@ -33,12 +33,18 @@ import toast from 'react-hot-toast';
|
||||
import TextInput from '@/components/input/TextInput';
|
||||
import { Kandang } from '@/types/api/master-data/kandang';
|
||||
import Collapse from '@/components/Collapse';
|
||||
import { ProjectFlockApi } from '@/services/api/production';
|
||||
import { ProjectFlockApi } from '@/services/api/production/project-flock';
|
||||
import { BaseApiResponse } from '@/types/api/api-general';
|
||||
import { FLOCK_CATEGORY_OPTIONS } from '@/config/constant';
|
||||
import { APPROVAL_WORKFLOWS, FLOCK_CATEGORY_OPTIONS } from '@/config/constant';
|
||||
import { useModal } from '@/components/Modal';
|
||||
import ConfirmationModal from '@/components/modal/ConfirmationModal';
|
||||
import ProjectFlockKandangTable from './ProjectFlockKandangTable';
|
||||
import ApprovalSteps from '@/components/pages/ApprovalSteps';
|
||||
import Steps from '@/components/steps/Steps';
|
||||
import StepItem from '@/components/steps/StepItem';
|
||||
import Tooltip from '@/components/Tooltip';
|
||||
import { id, is } from 'react-day-picker/locale';
|
||||
import { formatDate } from '@/lib/helper';
|
||||
|
||||
interface ProjectFlockFormProps {
|
||||
formType?: 'add' | 'edit' | 'detail';
|
||||
@@ -55,20 +61,22 @@ const ProjectFlockForm = ({
|
||||
}: ProjectFlockFormProps) => {
|
||||
// State
|
||||
const router = useRouter();
|
||||
|
||||
const projectFlockSteps = APPROVAL_WORKFLOWS.find(
|
||||
(step) => step.key === 'PROJECT_FLOCKS'
|
||||
);
|
||||
|
||||
const [projectFlockFormErrorMessage, setProjectFlockFormErrorMessage] =
|
||||
useState('');
|
||||
const [selectedArea, setSelectedArea] = useState('');
|
||||
|
||||
const [selectedLocation, setSelectedLocation] = useState('');
|
||||
const [disabledLocation, setDisabledLocation] = useState(true);
|
||||
|
||||
const [openSelectKandangs, setOpenSelectKandangs] = useState(
|
||||
initialValues?.kandangs && initialValues?.kandangs?.length > 0
|
||||
);
|
||||
const [optionsKandang, setOptionsKandang] = useState<Kandang[]>(
|
||||
initialValues?.kandangs ?? []
|
||||
);
|
||||
|
||||
const [selectedFlock, setSelectedFlock] = useState<number>(
|
||||
initialValues?.flock?.id ?? 0
|
||||
);
|
||||
@@ -141,15 +149,14 @@ const ProjectFlockForm = ({
|
||||
mutate: refreshKandang,
|
||||
} = useSWR(kandangUrl, KandangApi.getAllFetcher);
|
||||
|
||||
const getPeriodFlocksUrl = `flocks/${selectedFlock}/periods`;
|
||||
|
||||
const { data: periodFlocks, isLoading: isLoadingPeriodFlocks } = useSWR(
|
||||
getPeriodFlocksUrl,
|
||||
() =>
|
||||
ProjectFlockApi.customRequest<BaseApiResponse<PeriodFlock>, 'GET'>(
|
||||
getPeriodFlocksUrl,
|
||||
{ method: 'GET' }
|
||||
)
|
||||
`${selectedFlock.toString()}/periods`,
|
||||
(id: string) => ProjectFlockApi.getNextPeriod(id)
|
||||
);
|
||||
|
||||
const { data: approvalLines, isLoading: isLoadingApprovalLines } = useSWR(
|
||||
selectedFlock.toString(),
|
||||
(id: number) => ProjectFlockApi.getApprovalLines(id)
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -387,7 +394,10 @@ const ProjectFlockForm = ({
|
||||
if (isResponseSuccess(periodFlocks)) {
|
||||
formik.setFieldValue('period', periodFlocks.data.next_period);
|
||||
}
|
||||
}, [periodFlocks]);
|
||||
if (isResponseError(periodFlocks)) {
|
||||
console.log(periodFlocks?.message as string);
|
||||
}
|
||||
}, [periodFlocks, toast]);
|
||||
|
||||
useEffect(() => {
|
||||
const selectedRowIds = Object.keys(rowSelection)
|
||||
@@ -485,6 +495,80 @@ const ProjectFlockForm = ({
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{formType == 'detail' && isResponseSuccess(approvalLines) && (
|
||||
<div className='w-full flex items-center gap-2 my-4'>
|
||||
<Steps className='w-full'>
|
||||
{projectFlockSteps?.steps.map((step, idx) => {
|
||||
const approvalLogs = approvalLines.data.find(
|
||||
(approve) => approve.step_number == step.step_number
|
||||
);
|
||||
return (
|
||||
<StepItem
|
||||
key={step.step_number}
|
||||
color={
|
||||
step.step_number <=
|
||||
(initialValues?.approval.step_number ?? 0)
|
||||
? 'success'
|
||||
: undefined
|
||||
}
|
||||
icon={
|
||||
<Tooltip
|
||||
color={
|
||||
step.step_number <=
|
||||
(initialValues?.approval.step_number ?? 0)
|
||||
? 'success'
|
||||
: undefined
|
||||
}
|
||||
position='bottom'
|
||||
content={
|
||||
<ul>
|
||||
{approvalLogs &&
|
||||
approvalLogs.approvals.map((approval, idx) => {
|
||||
return (
|
||||
<li className='mb-2' key={`key-logs-${idx}`}>
|
||||
<div className='flex flex-col w-full text-start text-base'>
|
||||
<span>Status: {approval.step_name}</span>
|
||||
<span>
|
||||
Oleh: {approval.action_by.name}
|
||||
</span>
|
||||
<span>
|
||||
Tanggal:{' '}
|
||||
{formatDate(
|
||||
approval.action_at,
|
||||
'DD-MM-yyyy HH:mm:ss'
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
}
|
||||
>
|
||||
{step.step_number <=
|
||||
(initialValues?.approval.step_number ?? 0) ? (
|
||||
<Icon
|
||||
icon='material-symbols:check-rounded'
|
||||
width={24}
|
||||
height={24}
|
||||
/>
|
||||
) : (
|
||||
<Icon
|
||||
icon='material-symbols:check-rounded'
|
||||
width={24}
|
||||
height={24}
|
||||
/>
|
||||
)}
|
||||
</Tooltip>
|
||||
}
|
||||
>
|
||||
{step.step_name}
|
||||
</StepItem>
|
||||
);
|
||||
})}
|
||||
</Steps>
|
||||
</div>
|
||||
)}
|
||||
{formType == 'detail' && (
|
||||
<div className='w-full flex flex-col sm:flex-row gap-2 py-4'>
|
||||
<Button
|
||||
|
||||
@@ -231,3 +231,36 @@ export const RECORDING_FLAG_OPTIONS = [
|
||||
{ label: 'Ayam Culling', value: 'Ayam Culling' },
|
||||
{ label: 'Ayam Mati', value: 'Ayam Mati' },
|
||||
];
|
||||
|
||||
export const APPROVAL_WORKFLOWS = [
|
||||
{
|
||||
key: 'PROJECT_FLOCKS',
|
||||
steps: [
|
||||
{
|
||||
step_number: 1,
|
||||
step_name: 'Pengajuan',
|
||||
},
|
||||
{
|
||||
step_number: 2,
|
||||
step_name: 'Aktif',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'RECORDINGS',
|
||||
steps: [
|
||||
{
|
||||
step_number: 1,
|
||||
step_name: 'Grading-Telur',
|
||||
},
|
||||
{
|
||||
step_number: 2,
|
||||
step_name: 'Pengajuan',
|
||||
},
|
||||
{
|
||||
step_number: 3,
|
||||
step_name: 'Disetujui',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -4,10 +4,19 @@ import {
|
||||
UpdateProjectFlockPayload,
|
||||
} from '@/types/api/production/project-flock';
|
||||
import { BaseApiService } from '../base';
|
||||
import { BaseApiResponse } from '@/types/api/api-general';
|
||||
import {
|
||||
BaseApiResponse,
|
||||
BaseGroupedApproval,
|
||||
ErrorApiResponse,
|
||||
GroupedApprovals,
|
||||
SuccessApiResponse,
|
||||
} from '@/types/api/api-general';
|
||||
import { sleep } from '@/lib/helper';
|
||||
import { httpClient } from '@/services/http/client';
|
||||
import axios from 'axios';
|
||||
import { Flock } from '@/types/api/master-data/flock';
|
||||
import { Kandang } from '@/types/api/master-data/kandang';
|
||||
import { RequestOptions } from '@/services/http/base';
|
||||
|
||||
export class ProjectFlockService extends BaseApiService<
|
||||
ProjectFlock,
|
||||
@@ -17,14 +26,183 @@ export class ProjectFlockService extends BaseApiService<
|
||||
constructor(basePath: string = '') {
|
||||
super(basePath);
|
||||
}
|
||||
async getSingleProjectFlockKandang(): Promise<BaseApiResponse | undefined> {
|
||||
/**
|
||||
* Get Approval Lines
|
||||
*/
|
||||
async getApprovalLines(
|
||||
id: number
|
||||
): Promise<
|
||||
| BaseApiResponse<BaseGroupedApproval[]>
|
||||
| ErrorApiResponse
|
||||
| SuccessApiResponse<BaseGroupedApproval[]>
|
||||
| undefined
|
||||
> {
|
||||
const path = `/approvals`;
|
||||
try {
|
||||
console.log({
|
||||
module_id: id,
|
||||
module_name: 'PROJECT_FLOCKS',
|
||||
group_step_number: true,
|
||||
});
|
||||
return await httpClient<SuccessApiResponse<BaseGroupedApproval[]>>(path, {
|
||||
method: 'GET',
|
||||
query: {
|
||||
module_id: id,
|
||||
module_name: 'PROJECT_FLOCKS',
|
||||
group_step_number: true,
|
||||
},
|
||||
} as RequestOptions);
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError<BaseApiResponse>(error)) {
|
||||
return error.response?.data;
|
||||
return error.response?.data as ErrorApiResponse;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
/**
|
||||
* Lookup for Project Flock Kandang
|
||||
*/
|
||||
async lookupProjectFlockKandang(
|
||||
projectFlockId: number,
|
||||
kandangId: number
|
||||
): Promise<
|
||||
| BaseApiResponse<
|
||||
| ErrorApiResponse
|
||||
| SuccessApiResponse<{
|
||||
id: number;
|
||||
kandang_id: Kandang;
|
||||
project_flock: ProjectFlock;
|
||||
available_quantity: number;
|
||||
}>
|
||||
>
|
||||
| undefined
|
||||
> {
|
||||
try {
|
||||
const path = `${this.basePath}/kandangs/lookup`;
|
||||
return await httpClient<
|
||||
BaseApiResponse<
|
||||
SuccessApiResponse<{
|
||||
id: number;
|
||||
kandang_id: Kandang;
|
||||
project_flock: ProjectFlock;
|
||||
available_quantity: number;
|
||||
}>
|
||||
>
|
||||
>(path, {
|
||||
method: 'GET',
|
||||
body: {
|
||||
project_flock_id: projectFlockId,
|
||||
kandang_id: kandangId,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError<BaseApiResponse<ErrorApiResponse>>(error)) {
|
||||
return error.response?.data;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Next Period of Project Flock
|
||||
*/
|
||||
async getNextPeriod(id: string): Promise<
|
||||
| BaseApiResponse<{
|
||||
flock: Flock;
|
||||
next_period: number;
|
||||
}>
|
||||
| ErrorApiResponse
|
||||
| SuccessApiResponse<{
|
||||
flock: Flock;
|
||||
next_period: number;
|
||||
}>
|
||||
| undefined
|
||||
> {
|
||||
try {
|
||||
const path = `${this.basePath}/kandangs/${id}`;
|
||||
return await httpClient<
|
||||
SuccessApiResponse<{
|
||||
flock: Flock;
|
||||
next_period: number;
|
||||
}>
|
||||
>(path, {
|
||||
method: 'GET',
|
||||
});
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError<BaseApiResponse<ErrorApiResponse>>(error)) {
|
||||
return error.response?.data as ErrorApiResponse;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Approve single Project Flock
|
||||
*/
|
||||
async approve(
|
||||
id: number
|
||||
): Promise<BaseApiResponse<{ message: string }> | undefined> {
|
||||
return await this.bulkApprovalAction([id], 'APPROVED');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reject single Project Flock
|
||||
*/
|
||||
async reject(
|
||||
id: number
|
||||
): Promise<BaseApiResponse<{ message: string }> | undefined> {
|
||||
return await this.bulkApprovalAction([id], 'REJECTED');
|
||||
}
|
||||
|
||||
/**
|
||||
* Approve Bulk Project Flock
|
||||
*/
|
||||
async bulkApprove(
|
||||
ids: number[]
|
||||
): Promise<BaseApiResponse<{ message: string }> | undefined> {
|
||||
return await this.bulkApprovalAction(ids, 'APPROVED');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reject Bulk Project Flock
|
||||
*/
|
||||
async bulkReject(
|
||||
ids: number[]
|
||||
): Promise<BaseApiResponse<{ message: string }> | undefined> {
|
||||
return await this.bulkApprovalAction(ids, 'REJECTED');
|
||||
}
|
||||
|
||||
/**
|
||||
* Approve Bulk Project Flock
|
||||
*/
|
||||
async bulkApprovalAction(
|
||||
ids: number[],
|
||||
action: 'APPROVED' | 'REJECTED'
|
||||
): Promise<BaseApiResponse<{ message: string }> | undefined> {
|
||||
try {
|
||||
const path = `${this.basePath}/approvals`;
|
||||
return await httpClient<BaseApiResponse<{ message: string }>>(path, {
|
||||
method: 'POST',
|
||||
body: {
|
||||
action: action,
|
||||
approvable_ids: ids,
|
||||
notes: `Bulk ${action} Project Flock ${ids.join(', ')}`,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError<BaseApiResponse<{ message: string }>>(error)) {
|
||||
return error.response?.data;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const ProjectFlockApi = new ProjectFlockService(
|
||||
'/production/project-flocks'
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user