-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(web): date time field input (#767)
- Loading branch information
1 parent
fe3e6af
commit 466362e
Showing
14 changed files
with
365 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
web/src/beta/components/fields/DateTimeField/EditPanel/hooks.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import moment from "moment-timezone"; | ||
import { useCallback, useEffect, useMemo, useState } from "react"; | ||
|
||
import { getUniqueTimezones } from "@reearth/beta/utils/moment-timezone"; | ||
|
||
type Props = { | ||
value?: string; | ||
onChange?: (value?: string | undefined) => void; | ||
setDateTime?: (value?: string | undefined) => void; | ||
}; | ||
|
||
type TimezoneInfo = { | ||
timezone: string; | ||
offset: string; | ||
}; | ||
|
||
export default ({ value, onChange, setDateTime }: Props) => { | ||
const [date, setDate] = useState(""); | ||
const [time, setTime] = useState(""); | ||
const [selectedTimezone, setSelectedTimezone] = useState<TimezoneInfo>({ | ||
offset: "+0:00", | ||
timezone: "Africa/Abidjan", | ||
}); | ||
|
||
const handleTimeChange = useCallback((newValue: string | undefined) => { | ||
if (newValue === undefined) return; | ||
setTime(newValue); | ||
}, []); | ||
|
||
const handleDateChange = useCallback((newValue: string | undefined) => { | ||
if (newValue === undefined) return; | ||
setDate(newValue); | ||
}, []); | ||
|
||
const offsetFromUTC: TimezoneInfo[] = useMemo(() => { | ||
return getUniqueTimezones(moment.tz.names()); | ||
}, []); | ||
|
||
const handleApplyChange = useCallback(() => { | ||
const selectedTimezoneInfo = offsetFromUTC.find( | ||
info => info.timezone === selectedTimezone.timezone, | ||
); | ||
if (selectedTimezoneInfo) { | ||
const formattedDateTime = `${date}T${time}:00${selectedTimezoneInfo.offset}`; | ||
setDateTime?.(formattedDateTime); | ||
onChange?.(formattedDateTime); | ||
} | ||
}, [offsetFromUTC, selectedTimezone, date, time, setDateTime, onChange]); | ||
|
||
const handleTimezoneSelect = useCallback( | ||
(newValue: string) => { | ||
const updatedTimezone = offsetFromUTC.find(info => info.timezone === newValue); | ||
setSelectedTimezone(updatedTimezone || selectedTimezone); | ||
}, | ||
[offsetFromUTC, selectedTimezone], | ||
); | ||
|
||
useEffect(() => { | ||
if (value) { | ||
const [parsedDate, timeWithOffset] = value.split("T"); | ||
const [parsedTime, timezoneOffset] = timeWithOffset.split(/[-+]/); | ||
|
||
setDate(parsedDate); | ||
setTime(parsedTime); | ||
|
||
const updatedTimezone = offsetFromUTC.find( | ||
info => | ||
info.offset === | ||
(timeWithOffset.includes("-") ? `-${timezoneOffset}` : `+${timezoneOffset}`), | ||
); | ||
updatedTimezone && setSelectedTimezone(updatedTimezone); | ||
} else { | ||
setDate(""); | ||
setTime(""); | ||
setSelectedTimezone({ offset: "+0:00", timezone: "Africa/Abidjan" }); | ||
} | ||
}, [value, offsetFromUTC]); | ||
|
||
return { | ||
date, | ||
time, | ||
selectedTimezone, | ||
offsetFromUTC, | ||
onTimeChange: handleTimeChange, | ||
onTimezoneSelect: handleTimezoneSelect, | ||
onDateChange: handleDateChange, | ||
onDateTimeApply: handleApplyChange, | ||
}; | ||
}; |
120 changes: 120 additions & 0 deletions
120
web/src/beta/components/fields/DateTimeField/EditPanel/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import { useMemo } from "react"; | ||
|
||
import Button from "@reearth/beta/components/Button"; | ||
import PanelCommon from "@reearth/beta/components/fields/common/PanelCommon"; | ||
import { useT } from "@reearth/services/i18n"; | ||
import { styled } from "@reearth/services/theme"; | ||
|
||
import TextInput from "../../common/TextInput"; | ||
import SelectField from "../../SelectField"; | ||
|
||
import useHooks from "./hooks"; | ||
|
||
type Props = { | ||
onChange?: (value?: string | undefined) => void; | ||
onClose: () => void; | ||
value?: string; | ||
setDateTime?: (value?: string | undefined) => void; | ||
}; | ||
|
||
const EditPanel: React.FC<Props> = ({ onChange, onClose, value, setDateTime }) => { | ||
const t = useT(); | ||
|
||
const { | ||
date, | ||
time, | ||
selectedTimezone, | ||
offsetFromUTC, | ||
onDateChange, | ||
onTimeChange, | ||
onTimezoneSelect, | ||
onDateTimeApply, | ||
} = useHooks({ value, onChange, setDateTime }); | ||
|
||
const isButtonDisabled = useMemo(() => { | ||
return date.trim() === "" || time.trim() === ""; | ||
}, [date, time]); | ||
|
||
return ( | ||
<PanelCommon title={t("Set Time")} onClose={onClose}> | ||
<FieldGroup> | ||
<TextWrapper> | ||
<Label>{t("Date")}</Label> | ||
<Input type="date" value={date} onChange={onDateChange} /> | ||
</TextWrapper> | ||
<TextWrapper> | ||
<Label>{t("Time")}</Label> | ||
|
||
<Input type="time" value={time} onChange={onTimeChange} /> | ||
</TextWrapper> | ||
<SelectWrapper> | ||
<Label>{t("Time Zone")}</Label> | ||
<CustomSelect | ||
value={selectedTimezone.timezone} | ||
options={offsetFromUTC.map(timezone => ({ | ||
key: timezone.timezone, | ||
label: timezone?.offset, | ||
}))} | ||
onChange={onTimezoneSelect} | ||
/> | ||
</SelectWrapper> | ||
</FieldGroup> | ||
<Divider /> | ||
<ButtonWrapper> | ||
<StyledButton text={t("Cancel")} size="small" onClick={onClose} /> | ||
<StyledButton | ||
text={t("Apply")} | ||
size="small" | ||
buttonType="primary" | ||
onClick={() => { | ||
onDateTimeApply(), onClose(); | ||
}} | ||
disabled={isButtonDisabled} | ||
/> | ||
</ButtonWrapper> | ||
</PanelCommon> | ||
); | ||
}; | ||
|
||
const TextWrapper = styled.div` | ||
margin-left: 8px; | ||
width: 88%; | ||
`; | ||
|
||
const Input = styled(TextInput)` | ||
width: 100%; | ||
`; | ||
|
||
const FieldGroup = styled.div` | ||
padding-bottom: 8px; | ||
`; | ||
|
||
const Label = styled.div` | ||
font-size: 12px; | ||
padding: 10px 0; | ||
`; | ||
|
||
const Divider = styled.div` | ||
border-top: 1px solid ${({ theme }) => theme.outline.weak}; | ||
`; | ||
|
||
const ButtonWrapper = styled.div` | ||
display: flex; | ||
gap: 8px; | ||
padding: 8px; | ||
`; | ||
|
||
const StyledButton = styled(Button)` | ||
flex: 1; | ||
`; | ||
|
||
const SelectWrapper = styled.div` | ||
margin-left: 8px; | ||
width: 95%; | ||
`; | ||
const CustomSelect = styled(SelectField)` | ||
height: 120px; | ||
overflow-y: auto; | ||
width: 100%; | ||
`; | ||
export default EditPanel; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
Oops, something went wrong.