-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #285 from humanmade/new-datetimecontrol
Add new DateTimeControl component
- Loading branch information
Showing
5 changed files
with
183 additions
and
0 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
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,27 @@ | ||
# DateTimeControl | ||
|
||
The `DateTimeControl` component provides a date and time picker with timezone information. | ||
|
||
## Props | ||
|
||
- `label` (string): The label for the date/time control. | ||
- `id` (string): The ID for the base control. | ||
- `onChange` (Function): Callback function to handle date/time change. | ||
- `value` (string): The current date/time value in UTC format. | ||
|
||
## Usage | ||
|
||
```js | ||
import DateTimeControl from './components/datetime-control'; | ||
|
||
... | ||
|
||
<DateTimeControl | ||
label={ __( 'Event Start time/date', 'my-project' ) } | ||
id="example-start-time-date" | ||
value={ eventStart } | ||
onChange={ ( newValue ) => | ||
setAttributes( { eventStart: newValue } ) | ||
} | ||
/> | ||
``` |
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,101 @@ | ||
import { | ||
DateTimePicker, | ||
BaseControl, | ||
Popover, | ||
Button, | ||
} from '@wordpress/components'; | ||
import { gmdate, date, getSettings as getDateSettings } from '@wordpress/date'; | ||
import { useState } from '@wordpress/element'; | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
import TimeZone from './timezone'; | ||
|
||
/** | ||
* DateTimeControl component. | ||
* | ||
* @param {object} props - Component properties. | ||
* @param {string} props.label - The label for the date/time control. | ||
* @param {string} props.id - The ID for the base control. | ||
* @param {Function} props.onChange - Callback function to handle date/time change. | ||
* @param {string} props.value - The current date/time value in UTC format. | ||
* | ||
* @returns {ReactNode|null} The DateTimeControl component. | ||
*/ | ||
function DateTimeControl( { label, id, onChange, value } ) { | ||
const [ isDatePickerVisible, setIsDatePickerVisible ] = useState( false ); | ||
const dateSettings = getDateSettings(); | ||
|
||
/** | ||
* Convert a date string in the current site local time into a UTC formatted as a MySQL date. | ||
* | ||
* @param {string} localDateString Local date. | ||
* @returns {string} UTC formatted as a MySQL date. | ||
*/ | ||
const convertToUTC = ( localDateString ) => { | ||
const localDate = wp.date.getDate( localDateString ); | ||
return gmdate( 'Y-m-d H:i:s', localDate ); | ||
}; | ||
|
||
/** | ||
* Convert a UTC date in MySQL format into a date string localised to the current site timezone. | ||
* | ||
* @param {string} utcDateString UTC date string. | ||
* @param {string} format Format of returned date. | ||
* @returns {string|null} Localised date string. | ||
*/ | ||
const convertFromUTC = ( utcDateString, format = 'Y-m-d H:i:s' ) => { | ||
const utcDate = new Date( utcDateString + ' +00:00' ); | ||
|
||
if ( utcDate instanceof Date && ! isNaN( utcDate ) ) { | ||
return date( format, utcDate ); | ||
} | ||
|
||
return null; | ||
}; | ||
|
||
return ( | ||
<BaseControl id={ id } label={ label }> | ||
{ value && ( | ||
<p> | ||
{ convertFromUTC( value, dateSettings.formats.datetime ) } | ||
<TimeZone /> | ||
</p> | ||
) } | ||
|
||
<Button | ||
variant="link" | ||
onClick={ () => | ||
setIsDatePickerVisible( ! isDatePickerVisible ) } | ||
> | ||
{ __( 'Edit webinar start time/date', 'block-editor-components' ) } | ||
</Button> | ||
|
||
{ isDatePickerVisible && ( | ||
<Popover | ||
onFocusOutside={ () => | ||
setIsDatePickerVisible( ! isDatePickerVisible ) } | ||
> | ||
<div style={ { padding: '1.5em' } }> | ||
<DateTimePicker | ||
currentDate={ convertFromUTC( value ) || '' } | ||
is12Hour={ false } | ||
onChange={ ( newValue ) => | ||
onChange( convertToUTC( newValue ) ) } | ||
/> | ||
<Button | ||
size="small" | ||
style={ { marginTop: '1em' } } | ||
variant="primary" | ||
onClick={ () => | ||
setIsDatePickerVisible( ! isDatePickerVisible ) } | ||
> | ||
{ __( 'Done', 'block-editor-components' ) } | ||
</Button> | ||
</div> | ||
</Popover> | ||
) } | ||
</BaseControl> | ||
); | ||
} | ||
|
||
export default DateTimeControl; |
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,53 @@ | ||
import { Tooltip } from '@wordpress/components'; | ||
import { getSettings as getDateSettings } from '@wordpress/date'; | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
/** | ||
* TimeZone component. | ||
* | ||
* This component determines the user's timezone offset and compares it with the system timezone offset. | ||
* If they match, it returns null. Otherwise, it displays the timezone abbreviation and details in a tooltip. | ||
* | ||
* @returns {ReactNode|null} The timezone abbreviation and details in a tooltip, or null if the user's timezone matches the system timezone. | ||
*/ | ||
const TimeZone = () => { | ||
const { timezone } = getDateSettings(); | ||
|
||
// Convert timezone offset to hours. | ||
const userTimezoneOffset = -1 * ( new Date().getTimezoneOffset() / 60 ); | ||
|
||
// System timezone and user timezone match, nothing needed. | ||
// Compare as numbers because it comes over as string. | ||
if ( Number( timezone.offset ) === userTimezoneOffset ) { | ||
return null; | ||
} | ||
|
||
const offsetSymbol = Number( timezone.offset ) >= 0 ? '+' : ''; | ||
const zoneAbbr = | ||
timezone.abbr !== '' && isNaN( Number( timezone.abbr ) ) | ||
? timezone.abbr | ||
: `UTC${ offsetSymbol }${ timezone.offsetFormatted }`; | ||
|
||
// Replace underscore with space in strings like `America/Costa_Rica`. | ||
const prettyTimezoneString = timezone.string.replace( '_', ' ' ); | ||
|
||
const timezoneDetail = | ||
timezone.string === 'UTC' | ||
? __( 'Coordinated Universal Time' ) | ||
: `(${ zoneAbbr }) ${ prettyTimezoneString }`; | ||
|
||
// When the prettyTimezoneString is empty, there is no additional timezone | ||
// detail information to show in a Tooltip. | ||
const hasNoAdditionalTimezoneDetail = | ||
prettyTimezoneString.trim().length === 0; | ||
|
||
return hasNoAdditionalTimezoneDetail ? ( | ||
<>{ zoneAbbr }</> | ||
) : ( | ||
<Tooltip placement="top" text={ timezoneDetail }> | ||
<span>{ zoneAbbr }</span> | ||
</Tooltip> | ||
); | ||
}; | ||
|
||
export default TimeZone; |
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