mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
Merge branch 'development' of https://gitlab.com/mbugroup/lti-web-client into dev/randy
This commit is contained in:
@@ -3,11 +3,24 @@ import Steps from '@/components/steps/Steps';
|
||||
import StepItem from '@/components/steps/StepItem';
|
||||
import Tooltip from '@/components/Tooltip';
|
||||
|
||||
import { formatDate } from '@/lib/helper';
|
||||
import { ApprovalsLine } from '@/types/api/api-general';
|
||||
import { cn, formatDate } from '@/lib/helper';
|
||||
import { BaseApproval, BaseGroupedApproval } from '@/types/api/api-general';
|
||||
import { ApprovalLine } from '@/types/config/constant';
|
||||
|
||||
export type ApprovalStepStatus = 'APPROVED' | 'REJECTED' | 'WAITING' | 'IDLE';
|
||||
|
||||
export type ApprovalStepLog = {
|
||||
action_by?: string;
|
||||
date?: string;
|
||||
notes?: string | null;
|
||||
};
|
||||
|
||||
interface ApprovalStepsProps {
|
||||
approvals: ApprovalsLine;
|
||||
approvals: {
|
||||
name?: string;
|
||||
status: ApprovalStepStatus;
|
||||
logs?: ApprovalStepLog[];
|
||||
}[];
|
||||
}
|
||||
|
||||
const ApprovalSteps = ({ approvals }: ApprovalStepsProps) => {
|
||||
@@ -15,17 +28,23 @@ const ApprovalSteps = ({ approvals }: ApprovalStepsProps) => {
|
||||
<Steps direction='vertical' className='w-full md:steps-horizontal'>
|
||||
{approvals.map((approval, idx) => {
|
||||
const stepItemColor =
|
||||
approval.status === 'approved'
|
||||
approval.status === 'APPROVED'
|
||||
? 'success'
|
||||
: approval.status === 'rejected'
|
||||
: approval.status === 'REJECTED'
|
||||
? 'error'
|
||||
: approval.status === 'WAITING'
|
||||
? 'warning'
|
||||
: undefined;
|
||||
|
||||
const stepItemIcon =
|
||||
approval.status === 'approved'
|
||||
approval.status === 'APPROVED'
|
||||
? 'material-symbols:check-rounded'
|
||||
: approval.status === 'rejected'
|
||||
: approval.status === 'REJECTED'
|
||||
? 'material-symbols:close-rounded'
|
||||
: approval.status === 'WAITING'
|
||||
? 'pajamas:dash-circle'
|
||||
: approval.logs && approval.logs.length > 0
|
||||
? 'material-symbols:info-outline-rounded'
|
||||
: 'bxs:hourglass';
|
||||
|
||||
return (
|
||||
@@ -33,7 +52,6 @@ const ApprovalSteps = ({ approvals }: ApprovalStepsProps) => {
|
||||
key={idx}
|
||||
color={stepItemColor}
|
||||
icon={
|
||||
approval.status !== 'waiting' && (
|
||||
<Tooltip
|
||||
color={stepItemColor}
|
||||
position='right'
|
||||
@@ -41,19 +59,46 @@ const ApprovalSteps = ({ approvals }: ApprovalStepsProps) => {
|
||||
wrapper: 'md:tooltip-bottom',
|
||||
}}
|
||||
content={
|
||||
<div className='flex flex-col text-base'>
|
||||
<span>{formatDate(approval.date, 'YYYY-MM-DD')}</span>
|
||||
<span>Oleh: {approval.action_by}</span>
|
||||
<span>Catatan: {approval.notes}</span>
|
||||
<>
|
||||
{approval.logs && approval.logs.length > 0 && (
|
||||
<div className='flex flex-col gap-2'>
|
||||
{approval.logs?.map((approvalLog, logIdx) => (
|
||||
<div
|
||||
key={logIdx}
|
||||
className='flex flex-col text-base text-start'
|
||||
>
|
||||
{approvalLog.date && (
|
||||
<span>
|
||||
{formatDate(
|
||||
approvalLog.date,
|
||||
'YYYY-MM-DD, HH:mm:ss'
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
<span>Oleh: {approvalLog.action_by ?? '-'}</span>
|
||||
<span>Catatan: {approvalLog.notes ?? '-'}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Icon icon={stepItemIcon} width={24} height={24} />
|
||||
<Icon
|
||||
icon={stepItemIcon}
|
||||
width={24}
|
||||
height={24}
|
||||
className={cn({
|
||||
invisible:
|
||||
approval.status === 'IDLE' &&
|
||||
(!approval.logs ||
|
||||
(approval.logs && approval.logs.length === 0)),
|
||||
})}
|
||||
/>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
>
|
||||
{approval.role}
|
||||
{approval.name}
|
||||
</StepItem>
|
||||
);
|
||||
})}
|
||||
@@ -61,4 +106,76 @@ const ApprovalSteps = ({ approvals }: ApprovalStepsProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const formatGroupedApprovalsToApprovalSteps = (
|
||||
approvalLine: ApprovalLine,
|
||||
groupedApprovals: BaseGroupedApproval[],
|
||||
latestApproval: BaseApproval
|
||||
): ApprovalStepsProps['approvals'] => {
|
||||
const formattedApprovalSteps: ApprovalStepsProps['approvals'] =
|
||||
approvalLine.map((approvalLineItem) => {
|
||||
const approvalGroup = groupedApprovals.find(
|
||||
(approvalGroupItem) =>
|
||||
approvalGroupItem.step_number === approvalLineItem.step_number
|
||||
);
|
||||
|
||||
const currentStepNumber = approvalLineItem.step_number;
|
||||
const lastStepNumber =
|
||||
groupedApprovals[groupedApprovals.length - 1].step_number;
|
||||
|
||||
if (!approvalGroup && currentStepNumber <= lastStepNumber) {
|
||||
throw new Error(
|
||||
`Approval dengan ${approvalLineItem.step_name} tidak ditemukan!`
|
||||
);
|
||||
}
|
||||
|
||||
if (!approvalGroup) {
|
||||
const isWaiting = currentStepNumber === latestApproval.step_number + 1;
|
||||
|
||||
return {
|
||||
name: approvalLineItem.step_name,
|
||||
status: isWaiting ? 'WAITING' : 'IDLE',
|
||||
};
|
||||
}
|
||||
|
||||
let approvalStatus: ApprovalStepStatus;
|
||||
|
||||
if (approvalGroup.step_number <= latestApproval.step_number) {
|
||||
switch (approvalGroup.approvals[0].action) {
|
||||
case 'CREATED':
|
||||
case 'APPROVED':
|
||||
approvalStatus = 'APPROVED';
|
||||
break;
|
||||
|
||||
case 'REJECTED':
|
||||
approvalStatus = 'REJECTED';
|
||||
break;
|
||||
|
||||
default:
|
||||
approvalStatus = 'IDLE';
|
||||
break;
|
||||
}
|
||||
} else if (approvalGroup.step_number === latestApproval.step_number + 1) {
|
||||
approvalStatus = 'WAITING';
|
||||
} else {
|
||||
approvalStatus = 'IDLE';
|
||||
}
|
||||
|
||||
const approvalLogs: ApprovalStepLog[] = 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,
|
||||
};
|
||||
});
|
||||
|
||||
return formattedApprovalSteps;
|
||||
};
|
||||
|
||||
export default ApprovalSteps;
|
||||
|
||||
@@ -24,7 +24,14 @@ const StepItem = ({ children, icon, className, color }: StepItemProps) => {
|
||||
|
||||
return (
|
||||
<li className={cn(stepItemBaseClassName, className)}>
|
||||
<span className='step-icon'>{icon}</span>
|
||||
<span
|
||||
className={cn('step-icon', {
|
||||
'transition-shadow shadow-[0_0_10px_2px_var(--color-warning)] hover:shadow-[0_0_15px_5px_var(--color-warning)]':
|
||||
color === 'warning',
|
||||
})}
|
||||
>
|
||||
{icon}
|
||||
</span>
|
||||
|
||||
<div>{children}</div>
|
||||
</li>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { ApprovalLine } from '@/types/config/constant';
|
||||
|
||||
export const PROJECT_FLOCK_APPROVAL_LINE: ApprovalLine = [
|
||||
{
|
||||
step_number: 1,
|
||||
step_name: 'Pengajuan',
|
||||
},
|
||||
{
|
||||
step_number: 2,
|
||||
step_name: 'Aktif',
|
||||
},
|
||||
] as const;
|
||||
+3
-4
@@ -19,7 +19,7 @@ export const cn = (...inputs: ClassValue[]) => {
|
||||
|
||||
export const formatNumber = (
|
||||
value: number | bigint | Intl.StringNumericLiteral,
|
||||
locale = 'en-US',
|
||||
locale = 'id-ID',
|
||||
minimumFractionDigits = 0,
|
||||
maximumFractionDigits = 2
|
||||
) => {
|
||||
@@ -29,11 +29,10 @@ export const formatNumber = (
|
||||
}).format(value);
|
||||
};
|
||||
|
||||
|
||||
export const formatCurrency = (
|
||||
value: number | bigint | Intl.StringNumericLiteral,
|
||||
currency = 'USD',
|
||||
locale = 'en-US',
|
||||
currency = 'IDR',
|
||||
locale = 'id-ID',
|
||||
minimumFractionDigits = 0,
|
||||
maximumFractionDigits = 2
|
||||
) => {
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
--step-fg: var(--color-error-content);
|
||||
}
|
||||
|
||||
.step.step-warning::before {
|
||||
--step-bg: var(--color-warning);
|
||||
--step-fg: var(--color-warning-content);
|
||||
}
|
||||
|
||||
.table :where(th, td) {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
Vendored
+10
-10
@@ -97,21 +97,21 @@ export type flags =
|
||||
| 'FINISHER'
|
||||
| 'OVK';
|
||||
|
||||
export type ApprovalsLine = {
|
||||
action_by?: string;
|
||||
date?: string;
|
||||
notes?: string;
|
||||
role?: string;
|
||||
status: 'approved' | 'rejected' | 'waiting';
|
||||
}[];
|
||||
|
||||
export type BaseApproval = {
|
||||
step_number: number;
|
||||
step_name: string;
|
||||
action: string;
|
||||
notes: string | null;
|
||||
notes?: string | null;
|
||||
action_by: CreatedUser;
|
||||
action_at: string;
|
||||
};
|
||||
|
||||
export type ApproveAction = 'APPROVED' | 'REJECTED';
|
||||
export type BaseGroupedApproval = {
|
||||
step_number: number;
|
||||
step_name: string;
|
||||
approvals: BaseApproval[];
|
||||
};
|
||||
|
||||
export type Approvals = BaseApiResponse<BaseApproval>;
|
||||
|
||||
export type GroupedApprovals = BaseApiResponse<BaseGroupedApproval[]>;
|
||||
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
export type ApprovalLine = {
|
||||
step_number: number;
|
||||
step_name: string;
|
||||
}[];
|
||||
Reference in New Issue
Block a user