From 45ecb8b145b3734afa626bdc1cbb41065fb7226f Mon Sep 17 00:00:00 2001
From: Anna McPhee <30754158+annacmc@users.noreply.github.com>
Date: Mon, 16 Sep 2024 20:26:36 -0600
Subject: [PATCH] Calypso UI Components: DateRange: Refactor "header" and
"footer" areas of component (#94567)
* simplify
* move buttons to bottom
* add new dateRangeFooter
* refactor renderDateHelp into header
* refactor header content out of index
* styling header + footer
* add description to readme
* fix daterange styling regression
* fix button import
---
client/components/date-range/README.md | 1 +
client/components/date-range/footer.tsx | 49 ++++++++++++++
client/components/date-range/header.tsx | 87 ++++++++++++++++---------
client/components/date-range/index.js | 60 ++++-------------
client/components/date-range/style.scss | 8 ++-
5 files changed, 125 insertions(+), 80 deletions(-)
create mode 100644 client/components/date-range/footer.tsx
diff --git a/client/components/date-range/README.md b/client/components/date-range/README.md
index bc3460cc2a3da..09a5153d17003 100644
--- a/client/components/date-range/README.md
+++ b/client/components/date-range/README.md
@@ -47,6 +47,7 @@ These props utilise the [Render Props](https://reactjs.org/docs/render-props.htm
| ---------------------- | ---------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `renderTrigger(props)` | `Function` | undefined | render prop `Function` which will overide the default `DateRangeTrigger` component. Recieves same `props` object passed to `DateRangeTrigger` |
| `renderHeader(props)` | `Function` | undefined | render prop `Function` which will overide the default `DateRangeHeader` component. Recieves same `props` object passed to `DateRangeHeader` |
+| `renderFooter(props)` | `Function` | undefined | render prop `Function` which will overide the default `DateRangeFooter` component. Recieves same `props` object passed to `DateRangeFooter` |
| `renderInputs(props)` | `Function` | undefined | render prop `Function` which will overide the default `DateRangeInputs` component. Recieves same `props` object passed to `DateRangeInputs` |
### General guidelines
diff --git a/client/components/date-range/footer.tsx b/client/components/date-range/footer.tsx
new file mode 100644
index 0000000000000..2101dbc364f0d
--- /dev/null
+++ b/client/components/date-range/footer.tsx
@@ -0,0 +1,49 @@
+import { Button } from '@automattic/components';
+import { useTranslate } from 'i18n-calypso';
+import { FunctionComponent } from 'react';
+
+// eslint-disable-next-line @typescript-eslint/no-empty-function
+const noop = () => {};
+
+interface Props {
+ onApplyClick: () => void;
+ onCancelClick: () => void;
+ applyButtonText: string | null | undefined;
+ cancelButtonText: string | null | undefined;
+}
+
+const DateRangeFooter: FunctionComponent< Props > = ( {
+ onCancelClick = noop,
+ onApplyClick = noop,
+ cancelButtonText,
+ applyButtonText,
+} ) => {
+ const translate = useTranslate();
+
+ const cancelText = cancelButtonText || translate( 'Cancel' );
+ const applyText = applyButtonText || translate( 'Apply' );
+
+ return (
+
+
+
+
+ );
+};
+
+export default DateRangeFooter;
diff --git a/client/components/date-range/header.tsx b/client/components/date-range/header.tsx
index ae8f659c3a592..bb5e826954922 100644
--- a/client/components/date-range/header.tsx
+++ b/client/components/date-range/header.tsx
@@ -1,47 +1,72 @@
-import { Button } from '@automattic/components';
+import { Gridicon, Button } from '@automattic/components';
import { useTranslate } from 'i18n-calypso';
import { FunctionComponent } from 'react';
-// eslint-disable-next-line @typescript-eslint/no-empty-function
-const noop = () => {};
-
interface Props {
- onApplyClick: () => void;
- onCancelClick: () => void;
- applyButtonText: string | null | undefined;
- cancelButtonText: string | null | undefined;
+ customTitle?: string;
+ startDate: Date | null;
+ endDate: Date | null;
+ resetDates: () => void;
}
const DateRangeHeader: FunctionComponent< Props > = ( {
- onCancelClick = noop,
- onApplyClick = noop,
- cancelButtonText,
- applyButtonText,
+ customTitle,
+ startDate,
+ endDate,
+ resetDates,
} ) => {
const translate = useTranslate();
- const cancelText = cancelButtonText || translate( 'Cancel' );
- const applyText = applyButtonText || translate( 'Apply' );
+ // Add this check at the beginning of the component
+ if ( startDate === undefined || endDate === undefined || resetDates === undefined ) {
+ return null; // or return a loading state
+ }
+
+ const renderDateHelp = () => {
+ return (
+
+ { ! startDate &&
+ ! endDate &&
+ translate( '{{icon/}} Please select the {{em}}first{{/em}} day.', {
+ components: {
+ icon: ,
+ em: ,
+ },
+ } ) }
+ { startDate &&
+ ! endDate &&
+ translate( '{{icon/}} Please select the {{em}}last{{/em}} day.', {
+ components: {
+ icon: ,
+ em: ,
+ },
+ } ) }
+ { startDate && endDate && (
+
+ ) }
+
+ );
+ };
return (
-
-
+
+ { customTitle ? (
+
{ customTitle }
+ ) : (
+ renderDateHelp()
+ ) }
+
);
};
diff --git a/client/components/date-range/index.js b/client/components/date-range/index.js
index fe62ce71f5ecc..5c22b5cd194e5 100644
--- a/client/components/date-range/index.js
+++ b/client/components/date-range/index.js
@@ -1,4 +1,4 @@
-import { Button, Popover, Gridicon } from '@automattic/components';
+import { Popover } from '@automattic/components';
import clsx from 'clsx';
import { localize } from 'i18n-calypso';
import moment from 'moment';
@@ -6,6 +6,7 @@ import PropTypes from 'prop-types';
import { createRef, Component } from 'react';
import { withLocalizedMoment } from 'calypso/components/localized-moment';
import DateRangePicker from './date-range-picker';
+import DateRangeFooter from './footer';
import DateRangeHeader from './header';
import DateRangeInputs from './inputs';
import Shortcuts from './shortcuts';
@@ -44,6 +45,7 @@ export class DateRange extends Component {
showTriggerClear: PropTypes.bool,
renderTrigger: PropTypes.func,
renderHeader: PropTypes.func,
+ renderFooter: PropTypes.func,
renderInputs: PropTypes.func,
displayShortcuts: PropTypes.bool,
rootClass: PropTypes.string,
@@ -60,6 +62,7 @@ export class DateRange extends Component {
showTriggerClear: true,
renderTrigger: ( props ) => ,
renderHeader: ( props ) => ,
+ renderFooter: ( props ) => ,
renderInputs: ( props ) => ,
displayShortcuts: false,
rootClass: '',
@@ -413,50 +416,19 @@ export class DateRange extends Component {
this.handleDateRangeChange( startDate, endDate, 'custom_date_range' );
};
- renderDateHelp() {
- const { startDate, endDate } = this.state;
-
- return (
-
- { ! startDate &&
- ! endDate &&
- this.props.translate( '{{icon/}} Please select the {{em}}first{{/em}} day.', {
- components: {
- icon: ,
- em: ,
- },
- } ) }
- { startDate &&
- ! endDate &&
- this.props.translate( '{{icon/}} Please select the {{em}}last{{/em}} day.', {
- components: {
- icon: ,
- em: ,
- },
- } ) }
- { startDate && endDate && (
-
- ) }
-
- );
- }
-
/**
* Renders the Popover component
* @returns {import('react').Element} the Popover component
*/
renderPopover() {
const headerProps = {
+ customTitle: this.props.customTitle,
+ startDate: this.state.startDate,
+ endDate: this.state.endDate,
+ resetDates: this.resetDates,
+ };
+
+ const footerProps = {
onApplyClick: this.commitDates,
onCancelClick: this.closePopoverAndRevert,
};
@@ -486,16 +458,10 @@ export class DateRange extends Component {
{ this.props.overlay && (
{ this.props.overlay }
) }
-
- { this.props.customTitle ? (
-
{ this.props.customTitle }
- ) : (
- this.renderDateHelp()
- ) }
-
+ { this.props.renderHeader( headerProps ) }
{ this.props.renderInputs( inputsProps ) }
{ this.renderDatePicker() }
- { this.props.renderHeader( headerProps ) }
+ { this.props.renderFooter( footerProps ) }
{ /* Render shortcuts to the right of the calendar */ }
{ this.props.displayShortcuts && (
diff --git a/client/components/date-range/style.scss b/client/components/date-range/style.scss
index 54ced1ff11277..59e041b4e0614 100644
--- a/client/components/date-range/style.scss
+++ b/client/components/date-range/style.scss
@@ -96,6 +96,12 @@ $date-range-mobile-layout-switch: $break-small;
}
.date-range__popover-header {
+ order: 1;
+ display: flex;
+ justify-content: left;
+}
+
+.date-range__popover-footer {
order: 4;
display: flex;
justify-content: flex-end;
@@ -277,7 +283,6 @@ $date-range-mobile-layout-switch: $break-small;
}
}
}
-
.DayPicker-Day--range:not(.DayPicker-Day--disabled):not(.DayPicker-Day--outside) {
background-color: var(--date-range-picker-highlight-color);
.date-picker__day {
@@ -307,7 +312,6 @@ $date-range-mobile-layout-switch: $break-small;
border-radius: 200px !important;
}
}
-
.date-range__popover-content { // Styling to fit optional shortcuts sidebar
display: flex;
align-items: stretch; // Ensure children stretch to full height