feat: create TimeSelector time range component
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
export { TimeSelector } from './time-selector'
|
||||
export type { TimeSelectorProps } from './time-selector'
|
||||
@@ -0,0 +1,42 @@
|
||||
.time-selector {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.time-selector__group {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.time-selector__label {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: #666;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.time-selector__inputs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.time-selector__input {
|
||||
width: 60px;
|
||||
text-align: center;
|
||||
|
||||
:global {
|
||||
.p-inputnumber-input {
|
||||
padding: 8px 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.time-selector__separator {
|
||||
font-weight: 600;
|
||||
color: #666;
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import React from 'react'
|
||||
import { InputNumber } from 'primereact/inputnumber'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import './time-selector.scss'
|
||||
|
||||
export interface TimeSelectorProps {
|
||||
startTime?: string
|
||||
endTime?: string
|
||||
onStartTimeChange?: (time: string) => void
|
||||
onEndTimeChange?: (time: string) => void
|
||||
'data-testid'?: string
|
||||
}
|
||||
|
||||
export const TimeSelector: React.FC<TimeSelectorProps> = ({
|
||||
startTime = '00:00',
|
||||
endTime = '23:59',
|
||||
onStartTimeChange,
|
||||
onEndTimeChange,
|
||||
'data-testid': dataTestId,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const parseTime = (timeStr: string): { hours: number; minutes: number } => {
|
||||
const [h, m] = timeStr.split(':').map(Number)
|
||||
return { hours: h || 0, minutes: m || 0 }
|
||||
}
|
||||
|
||||
const formatTime = (hours: number, minutes: number): string => {
|
||||
return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`
|
||||
}
|
||||
|
||||
const handleStartHoursChange = (value: number | null | undefined) => {
|
||||
if (onStartTimeChange && value !== null && value !== undefined) {
|
||||
const { minutes } = parseTime(startTime)
|
||||
onStartTimeChange(formatTime(value, minutes))
|
||||
}
|
||||
}
|
||||
|
||||
const handleStartMinutesChange = (value: number | null | undefined) => {
|
||||
if (onStartTimeChange && value !== null && value !== undefined) {
|
||||
const { hours } = parseTime(startTime)
|
||||
onStartTimeChange(formatTime(hours, value))
|
||||
}
|
||||
}
|
||||
|
||||
const handleEndHoursChange = (value: number | null | undefined) => {
|
||||
if (onEndTimeChange && value !== null && value !== undefined) {
|
||||
const { minutes } = parseTime(endTime)
|
||||
onEndTimeChange(formatTime(value, minutes))
|
||||
}
|
||||
}
|
||||
|
||||
const handleEndMinutesChange = (value: number | null | undefined) => {
|
||||
if (onEndTimeChange && value !== null && value !== undefined) {
|
||||
const { hours } = parseTime(endTime)
|
||||
onEndTimeChange(formatTime(hours, value))
|
||||
}
|
||||
}
|
||||
|
||||
const startParsed = parseTime(startTime)
|
||||
const endParsed = parseTime(endTime)
|
||||
|
||||
return (
|
||||
<div className="time-selector" data-testid={dataTestId || 'time-selector'}>
|
||||
<div className="time-selector__group">
|
||||
<label className="time-selector__label">{t('SHARED.FROM')}</label>
|
||||
<div className="time-selector__inputs">
|
||||
<InputNumber
|
||||
value={startParsed.hours}
|
||||
onValueChange={(e) => handleStartHoursChange(e.value)}
|
||||
min={0}
|
||||
max={23}
|
||||
className="time-selector__input"
|
||||
data-testid="time-selector-start-hours"
|
||||
/>
|
||||
<span className="time-selector__separator">:</span>
|
||||
<InputNumber
|
||||
value={startParsed.minutes}
|
||||
onValueChange={(e) => handleStartMinutesChange(e.value)}
|
||||
min={0}
|
||||
max={59}
|
||||
className="time-selector__input"
|
||||
data-testid="time-selector-start-minutes"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="time-selector__group">
|
||||
<label className="time-selector__label">{t('SHARED.TO')}</label>
|
||||
<div className="time-selector__inputs">
|
||||
<InputNumber
|
||||
value={endParsed.hours}
|
||||
onValueChange={(e) => handleEndHoursChange(e.value)}
|
||||
min={0}
|
||||
max={23}
|
||||
className="time-selector__input"
|
||||
data-testid="time-selector-end-hours"
|
||||
/>
|
||||
<span className="time-selector__separator">:</span>
|
||||
<InputNumber
|
||||
value={endParsed.minutes}
|
||||
onValueChange={(e) => handleEndMinutesChange(e.value)}
|
||||
min={0}
|
||||
max={59}
|
||||
className="time-selector__input"
|
||||
data-testid="time-selector-end-minutes"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user