Merge branch 'feat/FE/US-82/TASK-91-slicing-approval-steps-component' into 'feat/FE/US-82/approval-workflow-steps-component'

[FEAT/FE][US#82/TASK#91] Slicing Approval Steps component

See merge request mbugroup/lti-web-client!11
This commit is contained in:
Rivaldi A N S
2025-10-16 03:16:47 +00:00
7 changed files with 201 additions and 0 deletions
+1
View File
@@ -1,5 +1,6 @@
@import 'tailwindcss';
@plugin "daisyui";
@import '../styles/daisyui.css';
:root {
--color-primary: #1f74bf;
+60
View File
@@ -0,0 +1,60 @@
import { ReactNode } from 'react';
import { cn } from '@/lib/helper';
import { Color } from '@/types/theme';
interface TooltipProps {
children?: ReactNode;
content?: ReactNode;
className?: {
wrapper?: string;
content?: string;
};
open?: boolean;
color?: Color;
position?: 'top' | 'bottom' | 'left' | 'right';
}
const Tooltip = ({
children,
content,
className,
open,
color,
position,
}: TooltipProps) => {
const tooltipBaseClassName = cn('tooltip', {
'tooltip-open': typeof open === 'boolean' && open,
'tooltip-top': position === 'top',
'tooltip-bottom': position === 'bottom',
'tooltip-left': position === 'left',
'tooltip-right': position === 'right',
'tooltip-primary': color === 'primary',
'tooltip-secondary': color === 'secondary',
'tooltip-accent': color === 'accent',
'tooltip-neutral': color === 'neutral',
'tooltip-info': color === 'info',
'tooltip-success': color === 'success',
'tooltip-warning': color === 'warning',
'tooltip-error': color === 'error',
});
return (
<div className={cn(tooltipBaseClassName, className?.wrapper)}>
<div
className={cn(
'tooltip-content',
'max-w-60 sm:max-w-xs',
className?.content
)}
>
{content}
</div>
{children}
</div>
);
};
export default Tooltip;
+64
View File
@@ -0,0 +1,64 @@
import { Icon } from '@iconify/react';
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';
interface ApprovalStepsProps {
approvals: ApprovalsLine;
}
const ApprovalSteps = ({ approvals }: ApprovalStepsProps) => {
return (
<Steps direction='vertical' className='w-full md:steps-horizontal'>
{approvals.map((approval, idx) => {
const stepItemColor =
approval.status === 'approved'
? 'success'
: approval.status === 'rejected'
? 'error'
: undefined;
const stepItemIcon =
approval.status === 'approved'
? 'material-symbols:check-rounded'
: approval.status === 'rejected'
? 'material-symbols:close-rounded'
: 'bxs:hourglass';
return (
<StepItem
key={idx}
color={stepItemColor}
icon={
approval.status !== 'waiting' && (
<Tooltip
color={stepItemColor}
position='right'
className={{
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>
</div>
}
>
<Icon icon={stepItemIcon} width={24} height={24} />
</Tooltip>
)
}
>
{approval.role}
</StepItem>
);
})}
</Steps>
);
};
export default ApprovalSteps;
+34
View File
@@ -0,0 +1,34 @@
import { ReactNode } from 'react';
import { cn } from '@/lib/helper';
import { Color } from '@/types/theme';
interface StepItemProps {
children?: ReactNode;
icon?: ReactNode;
className?: string;
color?: Color;
}
const StepItem = ({ children, icon, className, color }: StepItemProps) => {
const stepItemBaseClassName = cn('step', {
'step-primary': color === 'primary',
'step-secondary': color === 'secondary',
'step-accent': color === 'accent',
'step-neutral': color === 'neutral',
'step-info': color === 'info',
'step-success': color === 'success',
'step-warning': color === 'warning',
'step-error': color === 'error',
});
return (
<li className={cn(stepItemBaseClassName, className)}>
<span className='step-icon'>{icon}</span>
<div>{children}</div>
</li>
);
};
export default StepItem;
+23
View File
@@ -0,0 +1,23 @@
import { ReactNode } from 'react';
import { cn } from '@/lib/helper';
interface StepsProps {
children?: ReactNode;
className?: string;
direction?: 'horizontal' | 'vertical';
}
const Steps = ({ children, className, direction }: StepsProps) => {
const stepsBaseClassName = cn('steps gap-2', {
'steps-horizontal': direction === 'horizontal',
'steps-vertical': direction === 'vertical',
});
return (
<ul className={cn(stepsBaseClassName, 'overflow-visible!', className)}>
{children}
</ul>
);
};
export default Steps;
+11
View File
@@ -0,0 +1,11 @@
@layer utilities {
.step.step-success::before {
--step-bg: var(--color-success);
--step-fg: var(--color-success-content);
}
.step.step-error::before {
--step-bg: var(--color-error);
--step-fg: var(--color-error-content);
}
}
+8
View File
@@ -66,3 +66,11 @@ export type flags =
| 'STARTER'
| 'FINISHER'
| 'OVK';
export type ApprovalsLine = {
action_by?: string;
date?: string;
notes?: string;
role?: string;
status: 'approved' | 'rejected' | 'waiting';
}[];