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

Dashboard layout improvements & bf banner #853

Merged
merged 3 commits into from
Nov 8, 2024
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
Binary file added assets/img/bf-bg.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
62 changes: 62 additions & 0 deletions assets/src/dashboard/parts/components/BlackFridayBanner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Button } from '@wordpress/components';
import { close } from '@wordpress/icons';
import { useEffect, useState } from '@wordpress/element';
import classNames from 'classnames';
import { dismissNotice } from '../../utils/api';

export default () => {
const { urgency, title, subtitle, cta_link, cta_text, dismiss_key } = optimoleDashboardApp.bf_notices.banner;
const [ isVisible, setIsVisible ] = useState( true );
const [ shouldRender, setShouldRender ] = useState( true );

const onClose = () => {
dismissNotice( dismiss_key, () => {
setIsVisible( false );
});
};

useEffect( () => {
if ( ! isVisible ) {
const timer = setTimeout( () => {
setShouldRender( false );
}, 300 );
return () => clearTimeout( timer );
}
}, [ isVisible ]);

const wrapClasses = classNames(
'relative flex flex-col items-center text-center xl:flex-row gap-5 justify-between xl:items-center bg-black text-white p-5 py-4 pr-7 box-border rounded-lg mt-5 bg-no-repeat transition-all duration-300',
{
'opacity-0': ! isVisible,
'opacity-100': isVisible
}
);

if ( ! shouldRender ) {
return null;
}

return (
<div className={wrapClasses}
style={{
backgroundImage: `url(${optimoleDashboardApp.assets_url}/img/bf-bg.jpg)`,
backgroundPosition: 'right 0',
backgroundSize: 'auto 100%'
}}
>
<Button
icon={close}
onClick={onClose}
label={optimoleDashboardApp.strings.csat.close}
className="absolute right-1 top-1 cursor-pointer text-white hover:text-promo-orange"
/>
<div className="flex flex-col gap-3 xl:items-start items-center">
<div className="text-sm lg:text-base border-b border-0 border-dashed uppercase pb-1 font-semibold">{urgency}</div>
<div className="text-4xl lg:text-5xl italic uppercase font-extrabold" dangerouslySetInnerHTML={{ __html: title }}/>
<div className="text-sm lg:text-base font-extrabold" dangerouslySetInnerHTML={{ __html: subtitle }}/>
</div>

<a href={cta_link} target="_blank" className="bg-promo-orange text-white px-7 py-3 uppercase text-base font-bold grow flex justify-center max-w-[150px] text-center cursor-pointer hover:bg-white hover:text-orange-400 transition-colors">{cta_text}</a>
</div>
);
};
58 changes: 32 additions & 26 deletions assets/src/dashboard/parts/connected/Sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,7 @@ const Sidebar = () => {
});

return (
<div
className="flex flex-col mt-8 mb-5 p-0 transition-all ease-in-out duration-700 gap-5 basis-3/12"
>
<div className="grid md:grid-cols-2 xl:flex xl:flex-col xl:mt-8 xl:mb-5 p-0 transition-all ease-in-out duration-700 gap-5 basis-4/12 2xl:basis-3/12">
<div className="bg-white gap-5 flex flex-col text-gray-700 border-0 rounded-lg shadow-md p-8">
<TextControl
label={ optimoleDashboardApp.strings.logged_in_as }
Expand Down Expand Up @@ -73,33 +71,41 @@ const Sidebar = () => {

{ 'free' === plan ? (
<div
className="bg-info flex flex-col text-white border-0 rounded-lg shadow-md p-8 bg-promo bg-no-repeat"
className="bg-info flex flex-col text-white border-0 rounded-lg overflow-hidden shadow-md bg-promo bg-no-repeat"
style={ {
backgroundImage: `url( ${ optimoleDashboardApp.assets_url }/img/logo2.png )`
} }
>
<h3 className="mt-0 text-white text-lg">{ optimoleDashboardApp.strings.upgrade.title_long }</h3>

<ul>
{ reasons.map( ( reason, index ) => (
<li
key={ index }
className="flex items-center gap-2"
>
<Icon icon="yes-alt" className="text-white" />
<span className="text-white font-normal text-base">{ reason }</span>
</li>
) ) }
</ul>

<Button
variant="link"
className="optml__button flex w-full justify-center font-bold min-h-40 !no-underline !text-white !bg-opaque-black !rounded"
href={ optimoleDashboardApp.optimoleHome + 'pricing' }
target="_blank"
>
{ optimoleDashboardApp.strings.upgrade.cta }
</Button>
{optimoleDashboardApp?.bf_notices?.sidebar && (
<a href={optimoleDashboardApp.bf_notices.sidebar.cta_link} className="flex flex-col gap-3 p-3 bg-black !no-underline text-center cursor-pointer hover:opacity-90 transition-opacity" target="_blank">
<span className="font-extrabold text-[17px] uppercase italic" dangerouslySetInnerHTML={{ __html: optimoleDashboardApp.bf_notices.sidebar.title }}/>
<span className="text-[11px] font-bold" dangerouslySetInnerHTML={{ __html: optimoleDashboardApp.bf_notices.sidebar.subtitle }}/>
</a>
)}

<div className="p-8 flex flex-col">
<h3 className="mt-0 text-white text-lg">{ optimoleDashboardApp.strings.upgrade.title_long }</h3>
<ul>
{ reasons.map( ( reason, index ) => (
<li
key={ index }
className="flex items-center gap-2"
>
<Icon icon="yes-alt" className="text-white" />
<span className="text-white font-normal text-base">{ reason }</span>
</li>
) ) }
</ul>

<Button
variant="link"
className="optml__button flex w-full justify-center font-bold min-h-40 !no-underline !text-white !bg-opaque-black !rounded"
href={ optimoleDashboardApp.optimoleHome + 'pricing' }
target="_blank"
>
{ optimoleDashboardApp.strings.upgrade.cta }
</Button>
</div>
</div>
) : (
<Button
Expand Down
11 changes: 7 additions & 4 deletions assets/src/dashboard/parts/connected/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import Sidebar from './Sidebar';
import CSAT from './CSAT';
import { retrieveConflicts } from '../../utils/api';
import formbricks from '@formbricks/js/app';
import BlackFridayBanner from '../components/BlackFridayBanner';
if ( 'undefined' !== typeof window && optimoleDashboardApp.user_data.plan ) {
formbricks.init({
environmentId: 'clo8wxwzj44orpm0gjchurujm',
Expand Down Expand Up @@ -144,10 +145,12 @@ const ConnectedLayout = ({
}, [ canSave ]);

return (
<>
<div className="optml-connected max-w-screen-xl flex flex-col lg:flex-row mx-auto gap-5">
<div className="optml-connected 2xl:max-w-screen-xl max-w-screen px-4 mx-auto">
{optimoleDashboardApp?.bf_notices?.banner && <BlackFridayBanner/>}

<div className="flex flex-col xl:flex-row mx-auto gap-5">
<div
className="flex flex-col justify-between mt-8 mb-5 p-0 transition-all ease-in-out duration-700 relative text-gray-700 basis-9/12"
className="flex flex-col justify-between mt-8 xl:mb-5 p-0 transition-all ease-in-out duration-700 relative text-gray-700 basis-8/12 2xl:basis-9/12"
>
{ 'dashboard' === tab && <Dashboard /> }

Expand All @@ -171,7 +174,7 @@ const ConnectedLayout = ({
</div>

<CSAT />
</>
</div>
);
};

Expand Down
22 changes: 22 additions & 0 deletions assets/src/dashboard/utils/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -603,4 +603,26 @@ export const addNotice = ( text ) => {
);
};

export const dismissNotice = ( key, callback = () => {}) => {
apiFetch({
path: optimoleDashboardApp.routes[ 'dismiss_notice' ],
method: 'POST',
data: {
key
}
}).then( response => {
if ( 'success' !== response.code ) {
addNotice( response?.data?.error || optimoleDashboardApp.strings.options_strings.settings_saved_error );

return;
}

if ( callback ) {
callback( response );
}
}).catch( err => {
addNotice( optimoleDashboardApp.strings.options_strings.settings_saved_error );
});
};


59 changes: 59 additions & 0 deletions inc/admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class Optml_Admin {
const IMAGE_DATA_COLLECTED = 'optml_image_data_collected';

const IMAGE_DATA_COLLECTED_BATCH = 100;

const BF_PROMO_DISMISS_KEY = 'optml_bf24_notice_dismiss';
/**
* Hold the settings object.
*
Expand Down Expand Up @@ -1333,9 +1335,66 @@ private function localize_dashboard_app() {
'hash' => '#settings',
],
],
'bf_notices' => $this->get_bf_notices(),
];
}

/**
* Get the black friday notices.
*
* @return array
*/
public function get_bf_notices() {
$date = new DateTime();

$now = time();
$start = strtotime( '2024-11-25 00:00:00' );
$end = strtotime( '2024-12-03 23:59:59' );

if ( $now < $start || $now > $end ) {
return [];
}

$notices = [
'sidebar' => [
'title' => sprintf(
'<span class="text-promo-orange">%1$s:</span> %2$s',
__( 'Private Sale', 'optimole-wp' ),
__( '25 Nov - 03 Dec', 'optimole-wp' )
),
'subtitle' => sprintf(
/* translators: 1 is the promo code, 2 is the discount amount ('25 off') */
__( 'Use code %1$s for %2$s on yearly plans.', 'optimole-wp' ),
'<span class="border-b border-0 border-white border-dashed text-promo-orange">BFCM2425</span>',
'<span class="text-promo-orange uppercase">' . __( '25% off', 'optimole-wp' ) . '</span>'
),
'cta_link' => esc_url_raw( tsdk_utmify( tsdk_translate_link( 'https://optimole.com/pricing' ), 'bfcm24', 'sidebarnotice' ) ),
],
];

if ( get_option( self::BF_PROMO_DISMISS_KEY ) === 'yes' ) {
return $notices;
}

$notices['banner'] = [
/* translators: number of days left */
'urgency' => sprintf( __( 'Hurry up! only %s left', 'optimole-wp' ), human_time_diff( $end, $now ) ),
/* translators: private sale */
'title' => sprintf( __( 'Black Friday %s', 'optimole-wp' ), '<span class="text-promo-orange">' . __( 'private sale' ) . '</span>' ),
'subtitle' => sprintf(
/* translators: 1 is the promo code, 2 is the discount amount ('25 off') */
__( 'Use coupon code %1$s for an instant %2$s on Optimole yearly plans', 'optimole-wp' ),
'<span class="border-b border-0 border-white border-dashed text-promo-orange">BFCM2425</span>',
'<span class="text-promo-orange">' . __( '25% discount', 'optimole-wp' ) . '</span>'
),
'cta_text' => __( 'Claim now', 'optimole-wp' ),
'cta_link' => esc_url_raw( tsdk_utmify( tsdk_translate_link( 'https://optimole.com/pricing' ), 'bfcm24', 'dismissiblenotice' ) ),
'dismiss_key' => self::BF_PROMO_DISMISS_KEY,
];

return $notices;
}

/**
* Get all dashboard strings.
*
Expand Down
46 changes: 46 additions & 0 deletions inc/rest.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@ class Optml_Rest {
'permission_callback' => 'upload_files',
],
],
'notification_dismiss_routes' => [
'dismiss_notice' => [
'POST',
'args' => [
'key' => [
'type' => 'string',
'required' => true,
],
],
],
],
];

/**
Expand Down Expand Up @@ -168,6 +179,7 @@ public function register() {
$this->register_cache_routes();
$this->register_media_offload_routes();
$this->register_dam_routes();
$this->register_notification_routes();
}

/**
Expand Down Expand Up @@ -244,6 +256,17 @@ public function register_dam_routes() {
}
}

/**
* Register notification dismiss routes.
*
* @return void
*/
public function register_notification_routes() {
foreach ( self::$rest_routes['notification_dismiss_routes'] as $route => $details ) {
$this->reqister_route( $route, $details[0], isset( $details['args'] ) ? $details['args'] : [] );
}
}

/**
* Clear Cache request.
*
Expand Down Expand Up @@ -887,4 +910,27 @@ public function insert_images( WP_REST_Request $request ) {

return $this->response( $insert );
}

/**
* Dismiss a notification (set the notification key to 'yes').
*
* @param WP_REST_Request $request the incoming request.
*
* @return WP_REST_Response
*/
public function dismiss_notice( WP_REST_Request $request ) {
$key = $request->get_param( 'key' );

if ( empty( $key ) ) {
return $this->response( [ 'error' => 'Invalid key' ], 'error' );
}

$result = update_option( $key, 'yes' );

if ( ! $result ) {
return $this->response( [ 'error' => 'Could not dismiss notice' ], 'error' );
}

return $this->response( [ 'success' => 'Notice dismissed' ] );
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
},
"scripts": {
"build:dashboard": "wp-scripts build assets/src/dashboard/index.js --output-path=assets/build/dashboard",
"dev:dashboard": "wp-scripts start assets/src/dashboard/index.js --output-path=assets/build/dashboard",
"dev:dashboard": "wp-scripts start assets/src/dashboard/index.js --output-path=assets/build/dashboard --hot --allowed-hosts all",
"build-dev:dashboard": "NODE_ENV=development wp-scripts build assets/src/dashboard/index.js --output-path=assets/build/dashboard",
"build:media": "wp-scripts build assets/src/media/*.js --output-path=assets/build/media",
"dev:media": "wp-scripts start assets/src/media/*.js --output-path=assets/build/media",
Expand Down
4 changes: 3 additions & 1 deletion tailwind.config.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./assets/src/**/*.js'
'./assets/src/**/*.js',
'./inc/admin.php'
],
theme: {
extend: {
backgroundPosition: {
'promo': '90% 70%'
},
colors: {
'promo-orange': '#FF8811',
'primary': '#EF686B',
'success': '#5F9D61',
'danger': '#E77777',
Expand Down
Loading
Loading