pos-dashboard-v2/src/components/StatusFilterTab.tsx
2025-09-10 14:24:18 +07:00

250 lines
6.6 KiB
TypeScript

// React Imports
import React, { useState } from 'react'
// MUI Imports
import Button from '@mui/material/Button'
import Menu from '@mui/material/Menu'
import MenuItem from '@mui/material/MenuItem'
import { styled } from '@mui/material/styles'
const DropdownButton = styled(Button)(({ theme }) => ({
textTransform: 'none',
fontWeight: 400,
borderRadius: '8px',
borderColor: '#e0e0e0',
color: '#666',
'&:hover': {
borderColor: '#ccc',
backgroundColor: 'rgba(0, 0, 0, 0.04)'
}
}))
interface StatusFilterTabsProps {
/**
* Array of status options to display as filter tabs
*/
statusOptions: string[]
/**
* Currently selected status filter
*/
selectedStatus: string
/**
* Callback function when a status is selected
*/
onStatusChange: (status: string) => void
/**
* Custom className for the container
*/
className?: string
/**
* Custom styles for the container
*/
containerStyle?: React.CSSProperties
/**
* Size of the buttons
*/
buttonSize?: 'small' | 'medium' | 'large'
/**
* Maximum number of status options to show as buttons before switching to dropdown
*/
maxButtonsBeforeDropdown?: number
/**
* Label for the dropdown when there are many options
*/
dropdownLabel?: string
}
const StatusFilterTabs: React.FC<StatusFilterTabsProps> = ({
statusOptions,
selectedStatus,
onStatusChange,
className = '',
containerStyle = {},
buttonSize = 'small',
maxButtonsBeforeDropdown = 5,
dropdownLabel = 'Lainnya'
}) => {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null)
const open = Boolean(anchorEl)
const handleDropdownClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget)
}
const handleDropdownClose = () => {
setAnchorEl(null)
}
const handleDropdownItemClick = (status: string) => {
onStatusChange(status)
handleDropdownClose()
}
// If status options are <= maxButtonsBeforeDropdown, show all as buttons
if (statusOptions.length <= maxButtonsBeforeDropdown) {
return (
<div className='flex flex-wrap gap-2'>
{statusOptions.map(status => (
<Button
key={status}
variant={selectedStatus === status ? 'contained' : 'outlined'}
color={selectedStatus === status ? 'primary' : 'inherit'}
onClick={() => onStatusChange(status)}
size={buttonSize}
className='rounded-lg'
sx={{
textTransform: 'none',
fontWeight: selectedStatus === status ? 600 : 400,
borderRadius: '8px',
...(selectedStatus !== status && {
borderColor: '#e0e0e0',
color: '#666'
})
}}
>
{status}
</Button>
))}
</div>
)
}
// If more than maxButtonsBeforeDropdown, show first few as buttons and rest in dropdown
const buttonStatuses = statusOptions.slice(0, maxButtonsBeforeDropdown - 1)
const dropdownStatuses = statusOptions.slice(maxButtonsBeforeDropdown - 1)
const isDropdownItemSelected = dropdownStatuses.includes(selectedStatus)
return (
<div className='flex flex-wrap gap-2'>
{/* Regular buttons for first few statuses */}
{buttonStatuses.map(status => (
<Button
key={status}
variant={selectedStatus === status ? 'contained' : 'outlined'}
color={selectedStatus === status ? 'primary' : 'inherit'}
onClick={() => onStatusChange(status)}
size={buttonSize}
className='rounded-lg'
sx={{
textTransform: 'none',
fontWeight: selectedStatus === status ? 600 : 400,
borderRadius: '8px',
...(selectedStatus !== status && {
borderColor: '#e0e0e0',
color: '#666'
})
}}
>
{status}
</Button>
))}
{/* Dropdown button for remaining statuses */}
<DropdownButton
variant='outlined'
onClick={handleDropdownClick}
size={buttonSize}
endIcon={<i className='tabler-chevron-down' />}
sx={{
...(isDropdownItemSelected && {
backgroundColor: 'primary.main',
color: 'primary.contrastText',
borderColor: 'primary.main',
fontWeight: 600,
'&:hover': {
backgroundColor: 'primary.dark',
borderColor: 'primary.dark'
}
})
}}
>
{isDropdownItemSelected ? selectedStatus : dropdownLabel}
</DropdownButton>
<Menu
anchorEl={anchorEl}
open={open}
onClose={handleDropdownClose}
PaperProps={{
elevation: 3,
sx: {
mt: 1,
borderRadius: '8px',
minWidth: '160px'
}
}}
transformOrigin={{ horizontal: 'left', vertical: 'top' }}
anchorOrigin={{ horizontal: 'left', vertical: 'bottom' }}
>
{dropdownStatuses.map(status => (
<MenuItem
key={status}
onClick={() => handleDropdownItemClick(status)}
selected={selectedStatus === status}
sx={{
fontSize: '14px',
fontWeight: selectedStatus === status ? 600 : 400,
color: selectedStatus === status ? 'primary.main' : 'text.primary'
}}
>
{status}
</MenuItem>
))}
</Menu>
</div>
)
}
export default StatusFilterTabs
// Example usage:
/*
import StatusFilterTabs from '@/components/StatusFilterTabs'
// In your component:
const [statusFilter, setStatusFilter] = useState('Semua')
// For few statuses (will show all as buttons)
const expenseStatusOptions = ['Semua', 'Belum Dibayar', 'Dibayar Sebagian', 'Lunas']
// For many statuses (will show some buttons + dropdown)
const manyStatusOptions = [
'Semua',
'Belum Dibayar',
'Dibayar Sebagian',
'Lunas',
'Void',
'Retur',
'Jatuh Tempo',
'Transaksi Berulang',
'Ditangguhkan',
'Dibatalkan'
]
<StatusFilterTabs
statusOptions={expenseStatusOptions}
selectedStatus={statusFilter}
onStatusChange={setStatusFilter}
/>
// With many options (will automatically use dropdown)
<StatusFilterTabs
statusOptions={manyStatusOptions}
selectedStatus={statusFilter}
onStatusChange={setStatusFilter}
maxButtonsBeforeDropdown={4} // Show 3 buttons + dropdown
dropdownLabel="Status Lain"
/>
// Custom configuration
<StatusFilterTabs
statusOptions={manyStatusOptions}
selectedStatus={statusFilter}
onStatusChange={setStatusFilter}
maxButtonsBeforeDropdown={3}
dropdownLabel="Lainnya"
buttonSize="medium"
showBorder={false}
/>
*/