Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue / 8863 Adjust CTA & New Badge Positions for Mobile & Tablet #9182

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 30 additions & 54 deletions assets/js/googlesitekit/widgets/components/WidgetAreaRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
*/
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { useWindowWidth } from '@react-hook/window-size/throttled';

/**
* WordPress dependencies
Expand All @@ -30,7 +31,7 @@ import { useEffect, useRef, useState } from '@wordpress/element';
/**
* Internal dependencies
*/
import { useDispatch, useSelect } from 'googlesitekit-data';
import { useSelect } from 'googlesitekit-data';
import { getWidgetLayout, combineWidgets, HIDDEN_CLASS } from '../util';
import { getStickyHeaderHeight } from '../../../util/scroll';
import { CORE_WIDGETS, WIDGET_AREA_STYLES } from '../datastore/constants';
Expand All @@ -50,8 +51,7 @@ import WidgetCellWrapper from './WidgetCellWrapper';
import useViewOnly from '../../../hooks/useViewOnly';
import { CORE_USER } from '../../datastore/user/constants';
import useLatestIntersection from '../../../hooks/useLatestIntersection';
import NewBadge from '../../../components/NewBadge';
import { WEEK_IN_SECONDS } from '../../../util';
import WidgetNewBadge from './WidgetNewBadge';

/**
* Gets root margin value for the intersection hook.
Expand Down Expand Up @@ -86,6 +86,7 @@ export default function WidgetAreaRenderer( { slug, contextID } ) {
return select( CORE_USER ).getViewableModules();
} );

const windowWidth = useWindowWidth();
const breakpoint = useBreakpoint();

const widgetAreaRef = useRef();
Expand All @@ -98,8 +99,7 @@ export default function WidgetAreaRenderer( { slug, contextID } ) {
select( CORE_WIDGETS ).getWidgetArea( slug )
);

const { Icon, title, style, subtitle, hasNewBadge, CTA, Footer } =
widgetArea;
const { Icon, title, style, subtitle, CTA, Footer } = widgetArea;

const widgets = useSelect( ( select ) =>
select( CORE_WIDGETS ).getWidgets( slug, {
Expand Down Expand Up @@ -135,46 +135,8 @@ export default function WidgetAreaRenderer( { slug, contextID } ) {
} );
}, [ intersectionEntry, slug, activeContextID, contextID ] );

// NewBadge Expirable Item
const expirableBadgeSlug = `widget-area-expirable-new-badge-${ slug }`;

const hasBadgeBeenSeen = useSelect( ( select ) =>
select( CORE_USER ).hasExpirableItem( expirableBadgeSlug )
);
const isExpiredBadgeActive = useSelect( ( select ) =>
select( CORE_USER ).isExpirableItemActive( expirableBadgeSlug )
);

// Show the new badge if this widget area allows new badges, it's new badge
// has not been seen yet, or the badge has been seen and is still active.
const showNewBadge =
hasNewBadge && ( hasBadgeBeenSeen === false || isExpiredBadgeActive );

const { setExpirableItemTimers } = useDispatch( CORE_USER );

useEffect( () => {
// Wait until the selectors have resolved.
if (
hasBadgeBeenSeen !== undefined &&
isExpiredBadgeActive !== undefined
) {
// Only set the expirable item if the badge is new and the user is viewing it for the first time.
if ( hasNewBadge && ! hasBadgeBeenSeen ) {
setExpirableItemTimers( [
{
slug: expirableBadgeSlug,
expiresInSeconds: WEEK_IN_SECONDS * 4,
},
] );
}
}
}, [
hasNewBadge,
expirableBadgeSlug,
hasBadgeBeenSeen,
isExpiredBadgeActive,
setExpirableItemTimers,
] );
const ctaWithSmallWindow = CTA && windowWidth <= 782;
const ctaWithLargeWindow = CTA && windowWidth >= 783;

if ( viewableModules === undefined ) {
return null;
Expand Down Expand Up @@ -245,7 +207,7 @@ export default function WidgetAreaRenderer( { slug, contextID } ) {
{ title && (
<h3 className="googlesitekit-widget-area-header__title googlesitekit-heading-3">
{ title }
{ showNewBadge && <NewBadge /> }
<WidgetNewBadge slug={ slug } />
</h3>
) }

Expand All @@ -254,13 +216,13 @@ export default function WidgetAreaRenderer( { slug, contextID } ) {
{ subtitle && (
<h4 className="googlesitekit-widget-area-header__subtitle">
{ subtitle }
{ showNewBadge && ! title && (
<NewBadge />
{ ! title && (
<WidgetNewBadge slug={ slug } />
) }
</h4>
) }

{ CTA && (
{ ctaWithLargeWindow && (
<div className="googlesitekit-widget-area-header__cta">
<CTA />
</div>
Expand All @@ -283,16 +245,30 @@ export default function WidgetAreaRenderer( { slug, contextID } ) {
) }
</Row>
</div>
{ Footer && (
<Row>
<Row>
{ ctaWithSmallWindow && (
<Cell
className="googlesitekit-widget-area-footer"
size={ 12 }
lgSize={ 12 }
mdSize={ 4 }
smSize={ 2 }
>
<div className="googlesitekit-widget-area-footer__cta">
<CTA />
</div>
</Cell>
) }
{ Footer && (
<Cell
className="googlesitekit-widget-area-footer"
lgSize={ 12 }
mdSize={ ctaWithSmallWindow ? 4 : 8 }
smSize={ ctaWithSmallWindow ? 2 : 4 }
>
<Footer />
</Cell>
</Row>
) }
) }
</Row>
</Grid>
) }
{
Expand Down
96 changes: 96 additions & 0 deletions assets/js/googlesitekit/widgets/components/WidgetNewBadge.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/**
* WidgetNewBadge component.
*
* Site Kit by Google, Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* External dependencies
*/
import PropTypes from 'prop-types';

/**
* WordPress dependencies
*/
import { useEffect } from '@wordpress/element';

/**
* Internal dependencies
*/
import { useDispatch, useSelect } from 'googlesitekit-data';
import { CORE_USER } from '../../datastore/user/constants';
import NewBadge from '../../../components/NewBadge';
import { WEEK_IN_SECONDS } from '../../../util';
import { CORE_WIDGETS } from '../datastore/constants';

export default function WidgetNewBadge( { slug } ) {
const widgetArea = useSelect( ( select ) =>
select( CORE_WIDGETS ).getWidgetArea( slug )
);

const { hasNewBadge } = widgetArea;

// WidgetNewBadge Expirable Item
const expirableBadgeSlug = `widget-area-expirable-new-badge-${ slug }`;

const hasBadgeBeenSeen = useSelect( ( select ) =>
select( CORE_USER ).hasExpirableItem( expirableBadgeSlug )
);

const isExpiredBadgeActive = useSelect( ( select ) =>
select( CORE_USER ).isExpirableItemActive( expirableBadgeSlug )
);

// Show the new badge if this widget area allows new badges, it's new badge
// has not been seen yet, or the badge has been seen and is still active.
const showNewBadge =
hasNewBadge && ( hasBadgeBeenSeen === false || isExpiredBadgeActive );

const { setExpirableItemTimers } = useDispatch( CORE_USER );

useEffect( () => {
// Wait until the selectors have resolved.
if (
hasBadgeBeenSeen !== undefined &&
isExpiredBadgeActive !== undefined
) {
// Only set the expirable item if the badge is new and the user is viewing it for the first time.
if ( hasNewBadge && ! hasBadgeBeenSeen ) {
setExpirableItemTimers( [
{
slug: expirableBadgeSlug,
expiresInSeconds: WEEK_IN_SECONDS * 4,
},
] );
}
}
}, [
hasNewBadge,
expirableBadgeSlug,
hasBadgeBeenSeen,
isExpiredBadgeActive,
setExpirableItemTimers,
] );

if ( ! showNewBadge ) {
return false;
}

return <NewBadge />;
}

WidgetNewBadge.propTypes = {
slug: PropTypes.string.isRequired,
};
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ exports[`WidgetContextRenderer should render the registered widget areas 1`] = `
</div>
</div>
</div>
<div
class="mdc-layout-grid__inner"
/>
</div>
<div
class="mdc-layout-grid googlesitekit-widget-area googlesitekit-widget-area--TestArea2 googlesitekit-widget-area--composite"
Expand Down Expand Up @@ -125,6 +128,9 @@ exports[`WidgetContextRenderer should render the registered widget areas 1`] = `
</div>
</div>
</div>
<div
class="mdc-layout-grid__inner"
/>
</div>
</div>
`;
14 changes: 14 additions & 0 deletions assets/sass/widgets/_widget-area.scss
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,22 @@

.googlesitekit-widget-area-header__subtitle {
color: $c-surfaces-on-background;
display: flex;
flex-grow: 1;
font-family: $f-primary;
font-size: $fs-body-md;
font-weight: $fw-normal;
justify-content: space-between;
letter-spacing: $ls-s;
line-height: $lh-body-md;
margin: 0;

@media (min-width: $bp-tablet) {
display: block;
}

.googlesitekit-new-badge {
height: 24px;
margin-left: 14px;
}
}
Expand All @@ -70,3 +78,9 @@
white-space: nowrap;
}
}

.googlesitekit-widget-area-footer__cta {
font-size: $fs-label-md;
font-weight: $fw-medium;
margin: 12px 0;
}
Loading