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

Stats: Add new floating feedback panel #94129

Merged
merged 30 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
7eccdfa
Add FeedbackPanel component
a8ck3n Sep 3, 2024
b786252
Extract content UI to new component
a8ck3n Sep 3, 2024
59bd7fc
Reconnect button handler
a8ck3n Sep 3, 2024
c43dd77
Fix typo
a8ck3n Sep 3, 2024
defbdbe
Add shared content to floating panel
a8ck3n Sep 3, 2024
3673712
Add shared interface for props
a8ck3n Sep 3, 2024
655255c
Remove logging
a8ck3n Sep 3, 2024
c6ffc36
Move modal component up a level
a8ck3n Sep 3, 2024
831e554
Factor out the card from the wrapper
a8ck3n Sep 3, 2024
3444c2f
Rename top-level component
a8ck3n Sep 3, 2024
8f7ab1d
Support feedback actions per button
a8ck3n Sep 3, 2024
650d4ae
Update card-specific styles
a8ck3n Sep 3, 2024
98626c8
Add panel-specific styles
a8ck3n Sep 3, 2024
469e452
Refactor shared styles
a8ck3n Sep 3, 2024
472961a
Add close button to panel
a8ck3n Sep 3, 2024
ed4eb02
Add styles for close button
a8ck3n Sep 3, 2024
49b85ee
Wire up the close button
a8ck3n Sep 3, 2024
b299d57
Add state for panel visibility
a8ck3n Sep 3, 2024
584709b
Moving code around
a8ck3n Sep 3, 2024
ea64481
Fix panel positioning
a8ck3n Sep 3, 2024
56525a2
Update client/my-sites/stats/feedback/style.scss
kangzj Sep 3, 2024
2788c0e
Update client/my-sites/stats/feedback/style.scss
kangzj Sep 3, 2024
281ac59
Update client/my-sites/stats/feedback/style.scss
kangzj Sep 3, 2024
cd986a8
Update client/my-sites/stats/feedback/style.scss
kangzj Sep 3, 2024
032b639
Update client/my-sites/stats/feedback/style.scss
kangzj Sep 3, 2024
b1b4429
Update client/my-sites/stats/feedback/style.scss
kangzj Sep 3, 2024
d9f1891
Update client/my-sites/stats/feedback/style.scss
kangzj Sep 3, 2024
802df4a
Apply suggestions from code review
kangzj Sep 3, 2024
f1899a5
formatting
kangzj Sep 3, 2024
8d2f4f8
minor margin adjustment
kangzj Sep 3, 2024
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
106 changes: 86 additions & 20 deletions client/my-sites/stats/feedback/index.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,108 @@
import { Button } from '@wordpress/components';
import { close } from '@wordpress/icons';
import { useTranslate } from 'i18n-calypso';
import { useState } from 'react';
import FeedbackModal from './modal';

import './style.scss';

function StatsFeedbackCard() {
const FEEDBACK_ACTION_LEAVE_REVIEW = 'feedback-action-leave-review';
const FEEDBACK_ACTION_SEND_FEEDBACK = 'feedback-action-send-feedback';
const FEEDBACK_ACTION_DISMISS_FLOATING_PANEL = 'feedback-action-dismiss-floating-panel';

interface FeedbackProps {
clickHandler: ( action: string ) => void;
}

interface FeedbackPanelProps {
clickHandler: ( action: string ) => void;
isOpen: boolean;
}

function FeedbackContent( { clickHandler }: FeedbackProps ) {
const translate = useTranslate();
const [ isOpen, setIsOpen ] = useState( false );

const ctaText = translate( 'How do you rate your overall experience with Jetpack Stats?' );
const primaryButtonText = translate( 'Love it? Leave a review' );
const secondaryButtonText = translate( 'Not a fan? Help us improve' );

const handleClickWriteReview = () => {};
const handleLeaveReview = () => {
clickHandler( FEEDBACK_ACTION_LEAVE_REVIEW );
};

const handleClickSendFeedback = () => {
setIsOpen( true );
const handleSendFeedback = () => {
clickHandler( FEEDBACK_ACTION_SEND_FEEDBACK );
};

return (
<div className="stats-feedback-container">
<div className="stats-feedback-card">
<div className="stats-feedback-card__cta">{ ctaText }</div>
<div className="stats-feedback-card__actions">
<Button variant="secondary" onClick={ handleClickWriteReview }>
<span className="stats-feedback-card__emoji">😍</span>
{ primaryButtonText }
</Button>
<Button variant="secondary" onClick={ handleClickSendFeedback }>
<span className="stats-feedback-card__emoji">😠</span>
{ secondaryButtonText }
</Button>
</div>
<FeedbackModal isOpen={ isOpen } onClose={ () => setIsOpen( false ) } />
<div className="stats-feedback-content">
<div className="stats-feedback-content__cta">{ ctaText }</div>
<div className="stats-feedback-content__actions">
<Button variant="secondary" onClick={ handleLeaveReview }>
<span className="stats-feedback-content__emoji">😍</span>
{ primaryButtonText }
</Button>
<Button variant="secondary" onClick={ handleSendFeedback }>
<span className="stats-feedback-content__emoji">😠</span>
{ secondaryButtonText }
</Button>
</div>
</div>
);
}

export default StatsFeedbackCard;
function FeedbackPanel( { isOpen, clickHandler }: FeedbackPanelProps ) {
const translate = useTranslate();

const handleCloseButtonClicked = () => {
clickHandler( FEEDBACK_ACTION_DISMISS_FLOATING_PANEL );
};

if ( ! isOpen ) {
return null;
}

return (
<div className="stats-feedback-panel">
<Button
className="stats-feedback-panel__close-button"
onClick={ handleCloseButtonClicked }
icon={ close }
label={ translate( 'Close' ) }
/>
<FeedbackContent clickHandler={ clickHandler } />
</div>
);
}

function FeedbackCard( { clickHandler }: FeedbackProps ) {
return (
<div className="stats-feedback-card">
<FeedbackContent clickHandler={ clickHandler } />
</div>
);
}

function StatsFeedbackController() {
const [ isOpen, setIsOpen ] = useState( false );
const [ isFloatingPanelOpen, setIsFloatingPanelOpen ] = useState( true );

const handleButtonClick = ( action: string ) => {
a8ck3n marked this conversation as resolved.
Show resolved Hide resolved
if ( action === FEEDBACK_ACTION_SEND_FEEDBACK ) {
setIsOpen( true );
}
if ( action === FEEDBACK_ACTION_DISMISS_FLOATING_PANEL ) {
setIsFloatingPanelOpen( false );
}
};

return (
<div className="stats-feedback-container">
<FeedbackCard clickHandler={ handleButtonClick } />
<FeedbackPanel isOpen={ isFloatingPanelOpen } clickHandler={ handleButtonClick } />
<FeedbackModal isOpen={ isOpen } onClose={ () => setIsOpen( false ) } />
</div>
);
}

export default StatsFeedbackController;
101 changes: 69 additions & 32 deletions client/my-sites/stats/feedback/style.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
@import "@automattic/components/src/styles/typography";
@import "@wordpress/base-styles/breakpoints";

.stats-feedback-content {
font-family: $font-sf-pro-text;
font-size: $font-body-small;
font-weight: 400;
line-height: 21px;
letter-spacing: -0.24px;
}
kangzj marked this conversation as resolved.
Show resolved Hide resolved

.stats-feedback-content__actions {
display: flex;
flex-direction: column;

.components-button {
margin-bottom: 6px;
width: fit-content;
}
kangzj marked this conversation as resolved.
Show resolved Hide resolved
}

.stats-feedback-content__cta {
margin-bottom: 12px;
kangzj marked this conversation as resolved.
Show resolved Hide resolved
}

.stats-feedback-content__emoji {
font-size: larger;
margin-right: 6px;
}

.stats-feedback-card {
background: var(--studio-white);
border: 1px solid var(--studio-gray-5);
Expand All @@ -15,47 +42,57 @@
border-right: none;
}

display: flex;
flex-direction: column;
.stats-feedback-content {
display: flex;
flex-direction: column;

@media (min-width: $break-wide) {
flex-direction: row;
justify-content: space-between;
align-items: center;
@media (min-width: $break-wide) {
flex-direction: row;
justify-content: space-between;
align-items: center;
}
}

font-family: $font-sf-pro-text;
font-size: $font-body-small;
font-weight: 400;
line-height: 21px;
letter-spacing: -0.24px;
}

.stats-feedback-card__cta {
@media (max-width: $break-wide) {
margin-bottom: 12px;
.stats-feedback-content__cta {
@media (min-width: $break-wide) {
margin-right: 12px;
margin-bottom: 0;
}
}
}

.stats-feedback-card__actions {
display: flex;
flex-direction: column;
.stats-feedback-content__actions {
@media (min-width: $break-wide) {
flex-direction: row;

.components-button {
margin: 6px 0;
width: fit-content;
.components-button {
margin-left: 6px;
margin-bottom: 0;
}
}
}
}

@media (min-width: $break-wide) {
flex-direction: row;
.stats-feedback-panel {
position: fixed;
bottom: 16px;
kangzj marked this conversation as resolved.
Show resolved Hide resolved
right: 16px;
kangzj marked this conversation as resolved.
Show resolved Hide resolved
z-index: 10;

.components-button {
margin: 0 6px;
}
}
border: 1px solid var(--studio-gray-5);
border-radius: 10px; // stylelint-disable-line scales/radii
kangzj marked this conversation as resolved.
Show resolved Hide resolved
padding: 18px;
kangzj marked this conversation as resolved.
Show resolved Hide resolved
max-width: 230px;
kangzj marked this conversation as resolved.
Show resolved Hide resolved

background-color: var(--studio-white);
}

.stats-feedback-card__emoji {
font-size: larger;
margin-right: 6px;
.stats-feedback-panel__close-button {
position: absolute;
top: 6px;
kangzj marked this conversation as resolved.
Show resolved Hide resolved
right: 6px;
kangzj marked this conversation as resolved.
Show resolved Hide resolved

svg {
width: 14px;
height: 14px;
}
}
6 changes: 3 additions & 3 deletions client/my-sites/stats/site.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ import StatsModuleSearch from './features/modules/stats-search';
import StatsModuleTopPosts from './features/modules/stats-top-posts';
import StatsModuleUTM, { StatsModuleUTMOverlay } from './features/modules/stats-utm';
import StatsModuleVideos from './features/modules/stats-videos';
import StatsFeedbackCard from './feedback';
import StatsFeedbackController from './feedback';
import HighlightsSection from './highlights-section';
import { shouldGateStats } from './hooks/use-should-gate-stats';
import MiniCarousel from './mini-carousel';
Expand Down Expand Up @@ -242,7 +242,7 @@ class StatsSite extends Component {
shouldForceDefaultDateRange,
} = this.props;
const isNewStateEnabled = config.isEnabled( 'stats/empty-module-traffic' );
const isFeedbackCardEnabled = config.isEnabled( 'stats/user-feedback' );
const isUserFeedbackEnabled = config.isEnabled( 'stats/user-feedback' );
let defaultPeriod = PAST_SEVEN_DAYS;

const shouldShowUpsells = isOdysseyStats && ! isAtomic;
Expand Down Expand Up @@ -810,7 +810,7 @@ class StatsSite extends Component {
<AsyncLoad require="calypso/my-sites/stats/jetpack-upsell-section" />
) }
<PromoCards isOdysseyStats={ isOdysseyStats } pageSlug="traffic" slug={ slug } />
{ isFeedbackCardEnabled && <StatsFeedbackCard /> }
{ isUserFeedbackEnabled && <StatsFeedbackController /> }
<JetpackColophon />
<AsyncLoad require="calypso/lib/analytics/track-resurrections" placeholder={ null } />
{ this.props.upsellModalView && <StatsUpsellModal siteId={ siteId } /> }
Expand Down
Loading