-
Notifications
You must be signed in to change notification settings - Fork 10
fix: initial contract form #41
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,47 @@ | ||||||
import { useTranslation } from 'react-i18next'; | ||||||
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from 'Components/ui/dropdown-menu'; | ||||||
import { useState } from 'react'; | ||||||
import DurationIndex from './duration/DurationIndex'; | ||||||
|
||||||
const DurationAndTimeout = () => { | ||||||
const { t } = useTranslation(); | ||||||
const [isDurationOpen, setDurationOpen] = useState(false); | ||||||
const [selectedDuration, setSelectedDuration] = useState(t('duration')); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should be using a key to keep track of the selection. It we use the translated value it won't work properly when we switch language. |
||||||
|
||||||
const handleDurationToggle = () => setDurationOpen(prev => !prev); | ||||||
|
||||||
const handleDurationSelect = (value: string) => setSelectedDuration(value); | ||||||
const dropDownValues = [t('duration'), t('end time')]; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
return ( | ||||||
<div className='flex items-center justify-start'> | ||||||
<DropdownMenu onOpenChange={handleDurationToggle}> | ||||||
<DropdownMenuTrigger className='drop-down-trigger w-40'> | ||||||
<div className='flex items-center justify-around'> | ||||||
<div>{selectedDuration}</div> | ||||||
|
||||||
<img | ||||||
src='/images/pages/header/ic-chevron-down.svg' | ||||||
alt='arrow' | ||||||
className={`ml-2 transition-transform ${isDurationOpen ? 'rotate-180' : ''}`} | ||||||
/> | ||||||
</div> | ||||||
</DropdownMenuTrigger> | ||||||
<DropdownMenuContent className='drop-down-content w-40'> | ||||||
{dropDownValues.map(value => ( | ||||||
<DropdownMenuItem | ||||||
key={value} | ||||||
className={value === selectedDuration ? 'drowdown-item-selected' : 'drowdown-item'} | ||||||
onClick={() => handleDurationSelect(value)} | ||||||
> | ||||||
<span>{value}</span> | ||||||
</DropdownMenuItem> | ||||||
))} | ||||||
</DropdownMenuContent> | ||||||
</DropdownMenu> | ||||||
{selectedDuration === 'duration' && <DurationIndex />} | ||||||
</div> | ||||||
); | ||||||
}; | ||||||
|
||||||
export default DurationAndTimeout; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import TimeDropDown from './TimeDropDown'; | ||
import DurationInputField from './DurationInputField'; | ||
import { useState } from 'react'; | ||
import { useTranslation } from 'react-i18next'; | ||
|
||
const DurationIndex = () => { | ||
const { t } = useTranslation(); | ||
|
||
const [selectedTimeFrame, setSelectedTimeFrame] = useState(t('minutes')); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. Use keys to keep track of the selection. |
||
return ( | ||
<> | ||
<DurationInputField selectedTimeFrame={selectedTimeFrame} /> | ||
<TimeDropDown selectedTimeFrame={selectedTimeFrame} setSelectedTimeFrame={setSelectedTimeFrame} /> | ||
</> | ||
); | ||
}; | ||
|
||
export default DurationIndex; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import { useTranslation } from 'react-i18next'; | ||
import { ChangeEvent, useEffect, useState } from 'react'; | ||
import Input from 'Components/ui/input'; | ||
|
||
type DurationInputFieldProps = { | ||
selectedTimeFrame: string; | ||
}; | ||
|
||
const DurationInputField = ({ selectedTimeFrame }: DurationInputFieldProps) => { | ||
const { t } = useTranslation(); | ||
|
||
type TTimeFrameConfig = Record<string, number>; | ||
|
||
type ThintValuesAndMessages = Record<string, TTimeFrameConfig>; | ||
|
||
const hintValuesAndMessages: ThintValuesAndMessages = { | ||
minutes: { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be created dynamically based on |
||
min: 15, | ||
max: 1440, | ||
}, | ||
hours: { | ||
min: 1, | ||
max: 24, | ||
}, | ||
days: { | ||
min: 1, | ||
max: 365, | ||
}, | ||
}; | ||
|
||
const [inputValue, setInputValue] = useState({ | ||
value: '', | ||
hasError: false, | ||
hintMessage: t('Minimum 15'), | ||
}); | ||
|
||
useEffect(() => { | ||
const timeFrameConfig: TTimeFrameConfig = hintValuesAndMessages?.[selectedTimeFrame] || { min: 0, max: 0 }; | ||
setInputValue({ value: '', hasError: false, hintMessage: t(`Minimum ${timeFrameConfig.min}`) }); | ||
}, [selectedTimeFrame]); | ||
|
||
const handleChange = (e: ChangeEvent<HTMLInputElement>) => { | ||
const inputValue = e.target.value; | ||
const isValidInput = /^$|^[0-9]{1,4}$/.test(inputValue); | ||
|
||
if (isValidInput) { | ||
const timeFrameConfig: TTimeFrameConfig = hintValuesAndMessages?.[selectedTimeFrame] || { min: 0, max: 0 }; | ||
const value = parseInt(inputValue); | ||
let hasError = false; | ||
let hintMessage = t(`Minimum ${timeFrameConfig.min}`); | ||
|
||
if (value < timeFrameConfig.min) { | ||
hasError = true; | ||
hintMessage = t(`Minimum ${timeFrameConfig.min}`); | ||
} else if (value > timeFrameConfig.max) { | ||
hasError = true; | ||
hintMessage = t(`Maximum ${timeFrameConfig.max}`); | ||
} | ||
|
||
setInputValue({ value: inputValue, hasError, hintMessage }); | ||
} | ||
}; | ||
return ( | ||
<div className='w-40'> | ||
<Input | ||
type='text' | ||
id='exampleInput' | ||
value={inputValue.value} | ||
onChange={handleChange} | ||
labelAlignment='left' | ||
hint={inputValue.hintMessage} | ||
error={inputValue.hasError} | ||
/> | ||
</div> | ||
); | ||
}; | ||
|
||
export default DurationInputField; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { useTranslation } from 'react-i18next'; | ||
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from 'Components/ui/dropdown-menu'; | ||
import { useState } from 'react'; | ||
|
||
type TimeDropDownProps = { | ||
selectedTimeFrame: string; | ||
setSelectedTimeFrame: React.Dispatch<React.SetStateAction<string>>; | ||
}; | ||
|
||
const TimeDropDown = ({ selectedTimeFrame, setSelectedTimeFrame }: TimeDropDownProps) => { | ||
const { t } = useTranslation(); | ||
const [isDropDownOpen, setDropDownOpen] = useState(false); | ||
|
||
const handleTimeToggle = () => setDropDownOpen(prev => !prev); | ||
|
||
const handleDurationSelect = (value: string) => setSelectedTimeFrame(value); | ||
|
||
const dropDownValues = [t('minutes'), t('hours'), t('days')]; | ||
|
||
return ( | ||
<DropdownMenu onOpenChange={handleTimeToggle}> | ||
<DropdownMenuTrigger className='drop-down-trigger w-40'> | ||
<div className='flex items-center justify-around'> | ||
<div>{selectedTimeFrame}</div> | ||
<img | ||
src='/images/pages/header/ic-chevron-down.svg' | ||
alt='arrow' | ||
className={`ml-2 transition-transform ${isDropDownOpen ? 'rotate-180' : ''}`} | ||
/> | ||
</div> | ||
</DropdownMenuTrigger> | ||
<DropdownMenuContent className='drop-down-content w-40'> | ||
{dropDownValues.map(value => ( | ||
<DropdownMenuItem | ||
key={value} | ||
className={value === selectedTimeFrame ? 'drowdown-item-selected' : 'drowdown-item'} | ||
onClick={() => handleDurationSelect(value)} | ||
> | ||
<span>{value}</span> | ||
</DropdownMenuItem> | ||
))} | ||
</DropdownMenuContent> | ||
</DropdownMenu> | ||
); | ||
}; | ||
|
||
export default TimeDropDown; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
const TimeOut = () => <div>Time out</div>; | ||
|
||
export default TimeOut; |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { useTranslation } from 'react-i18next'; | ||
import { | ||
DropdownMenu, | ||
DropdownMenuTrigger, | ||
DropdownMenuContent, | ||
DropdownMenuItem, | ||
DropdownMenuSeparator, | ||
} from 'Components/ui/dropdown-menu'; | ||
import { useState } from 'react'; | ||
|
||
const StartTime = () => { | ||
const { t } = useTranslation(); | ||
const [isDropDownOpen, setDropdownOpen] = useState(false); | ||
|
||
const handleDropdownToggle = () => { | ||
setDropdownOpen(prev => !prev); | ||
}; | ||
|
||
return ( | ||
<div className='flex items-center justify-start'> | ||
<span className='text-m mr-3 font-light'> {t('Start time')}</span> | ||
<DropdownMenu onOpenChange={handleDropdownToggle}> | ||
<DropdownMenuTrigger className='drop-down-trigger w-40'> | ||
<div className='flex items-center justify-around'> | ||
<div>Now</div> | ||
<img | ||
src='/images/pages/header/ic-chevron-down.svg' | ||
alt='arrow' | ||
className={`ml-2 transition-transform ${isDropDownOpen ? 'rotate-180' : ''}`} | ||
/> | ||
</div> | ||
</DropdownMenuTrigger> | ||
<DropdownMenuContent className='drop-down-content w-40'> | ||
<DropdownMenuItem className='drowdown-item-selected'> | ||
<span>Now</span> | ||
</DropdownMenuItem> | ||
<DropdownMenuItem className='drowdown-item'> | ||
<span>Item 2</span> | ||
</DropdownMenuItem> | ||
<DropdownMenuSeparator /> | ||
<DropdownMenuItem className='drowdown-item'> | ||
<span>Item 3</span> | ||
</DropdownMenuItem> | ||
</DropdownMenuContent> | ||
</DropdownMenu> | ||
</div> | ||
); | ||
}; | ||
|
||
export default StartTime; |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.