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

Add nearing quota warning #896

Merged
merged 7 commits into from
Apr 2, 2025
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
20 changes: 15 additions & 5 deletions assets/src/dashboard/parts/components/Modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { close } from '@wordpress/icons';
import { useViewportMatch } from '@wordpress/compose';
import { Button, Icon, Modal as CoreModal } from '@wordpress/components';

export default function Modal({ icon, labels = {}, onRequestClose = () => {}, onConfirm = () => {}, variant = 'default' }) {
export default function Modal({ icon, labels = {}, onRequestClose = () => {}, onConfirm = () => {}, variant = 'default', onSecondaryAction = () => {} }) {

const isMobileViewport = useViewportMatch( 'small', '<' );

Expand Down Expand Up @@ -53,10 +53,20 @@ export default function Modal({ icon, labels = {}, onRequestClose = () => {}, on
className="text-center mx-0 my-4 text-gray-700"
dangerouslySetInnerHTML={ { __html: labels.description } }
/>

<Button variant="primary" className={ actionButtonClasses } onClick={ onConfirm }>
{ labels.action }
</Button>
<div class="flex gap-4">
<Button variant="primary" className={ actionButtonClasses } onClick={ onConfirm }>
{ labels.action }
</Button>
{ labels.secondaryAction && (
<Button
variant="default"
className="optml__button flex justify-center rounded font-bold min-h-40"
onClick={ onSecondaryAction }
>
{ labels.secondaryAction }
</Button>
) }
</div>
</div>
</CoreModal>
);
Expand Down
31 changes: 28 additions & 3 deletions assets/src/dashboard/parts/connected/settings/OffloadMedia.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ import Modal from '../../components/Modal';
import Logs from './Logs';

const OffloadMedia = ({ settings, canSave, setSettings, setCanSave }) => {
const { strings, cron_disabled } = optimoleDashboardApp;
const { strings, cron_disabled, show_exceed_plan_quota_notice } = optimoleDashboardApp;

const { conflicts, options_strings } = strings;

const MODAL_STATE_OFFLOAD = 'offload';
const MODAL_STATE_ROLLBACK = 'rollback';
const MODAL_STATE_STOP_OFFLOAD = 'stopOffload';
const MODAL_STATE_STOP_ROLLBACK = 'stopRollback';
const MODAL_STATE_EXCEED_PLAN_QUOTA_NOTICE = 'planQuotaNotice';

const {
offloadConflicts,
Expand Down Expand Up @@ -181,7 +183,7 @@ const OffloadMedia = ({ settings, canSave, setSettings, setCanSave }) => {
setCanSave( true );

if ( offloadEnabled ) {
setModal( MODAL_STATE_OFFLOAD );
setModal( show_exceed_plan_quota_notice ? MODAL_STATE_EXCEED_PLAN_QUOTA_NOTICE : MODAL_STATE_OFFLOAD );

return;
}
Expand Down Expand Up @@ -245,6 +247,29 @@ const OffloadMedia = ({ settings, canSave, setSettings, setCanSave }) => {
description: options_strings.rollback_stop_description,
action: options_strings.rollback_stop_action
}
},
[MODAL_STATE_EXCEED_PLAN_QUOTA_NOTICE]: {
variant: 'warning',
icon: warningAlt,
onConfirm: () => {
onOffloadMedia();
setModal( null );
},
onSecondaryAction: () => {
setModal( null );
const options = settings;
options.offload_media = 'disabled';
saveSettings( options );

// Remove "unsaved changes" warning
window.onbeforeunload = null;
},
labels: {
title: options_strings.exceed_plan_quota_notice_title,
description: options_strings.exceed_plan_quota_notice_description,
action: options_strings.exceed_plan_quota_notice_start_action,
secondaryAction: options_strings.exceed_plan_quota_notice_secondary_action
}
}
};

Expand All @@ -270,7 +295,7 @@ const OffloadMedia = ({ settings, canSave, setSettings, setCanSave }) => {
e.preventDefault();

if ( 'offload' === radioBoxValue ) {
setModal( MODAL_STATE_OFFLOAD );
setModal( show_exceed_plan_quota_notice ? MODAL_STATE_EXCEED_PLAN_QUOTA_NOTICE : MODAL_STATE_OFFLOAD );
}

if ( 'rollback' === radioBoxValue ) {
Expand Down
57 changes: 57 additions & 0 deletions inc/admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -1343,6 +1343,7 @@ private function localize_dashboard_app() {
],
'bf_notices' => $this->get_bf_notices(),
'spc_banner' => $this->get_spc_banner(),
'show_exceed_plan_quota_notice' => $this->should_show_exceed_quota_warning(),
];
}

Expand Down Expand Up @@ -1978,6 +1979,10 @@ private function get_dashboard_strings() {
'rollback_stop_action' => __( 'Cancel the transfer from Optimole', 'optimole-wp' ),
'cloud_library_btn_text' => __( 'Go to Cloud Library', 'optimole-wp' ),
'cloud_library_btn_link' => add_query_arg( 'page', 'optimole-dam', admin_url( 'admin.php' ) ),
'exceed_plan_quota_notice_title' => __( 'Your site has already reached over 50% of your monthly visits limit within just two weeks.', 'optimole-wp' ),
'exceed_plan_quota_notice_description' => sprintf( /* translators: 1 is the starting anchor tag, 2 is the ending anchor tag */ __( 'Based on this trend, you are likely to exceed your free quota before the month ends. To avoid any disruption in service, we strongly recommend %1$supgrading%2$s your plan or waiting until your traffic stabilizes before offloading your images. Do you still wish to proceed?', 'optimole-wp' ), '<a style="white-space: nowrap;" target=”_blank” href="https://dashboard.optimole.com/settings/billing/">', '</a>' ),
'exceed_plan_quota_notice_start_action' => __( 'Yes, Transfer to Optimole Cloud', 'optimole-wp' ),
'exceed_plan_quota_notice_secondary_action' => __( 'No, keep images on my website', 'optimole-wp' ),
],
'help' => [
'section_one_title' => __( 'Help and Support', 'optimole-wp' ),
Expand Down Expand Up @@ -2171,4 +2176,56 @@ public function survey_category( $value, $scale = 1 ) {

return 0;
}

/**
* Determines whether the exceed quota warning should be displayed to users.
*
* This function checks if the user's quota usage has exceeded a predefined limit
* and returns a boolean value indicating whether the warning should be shown.
*
* @return bool True if the exceed quota warning should be displayed, false otherwise.
*/
public function should_show_exceed_quota_warning() {
if ( ! $this->settings->is_connected() ) {
return false;
}
if ( get_option( 'optml_notice_hide_upg', 'no' ) === 'yes' ) {
return false;
}

$service_data = $this->settings->get( 'service_data' );

if ( ! isset( $service_data['plan'] ) ) {
return false;
}
if ( $service_data['plan'] !== 'free' ) {
return false;
}
if ( ! isset( $service_data['renews_on'] ) ) {
return false;
}
$renews_on = $service_data['renews_on'];
$timestamp_before_two_weeks = strtotime( '-2 weeks', $renews_on );
$today_timestamp = strtotime( 'today' );

if ( $timestamp_before_two_weeks < $today_timestamp ) {
return false;
}

$visitors_limit = isset( $service_data['visitors_limit'] ) ? (int) $service_data['visitors_limit'] : 0;
$visitors_left = isset( $service_data['visitors_left'] ) ? (int) $service_data['visitors_left'] : 0;

if ( ! $visitors_limit || ! $visitors_left ) {
return false;
}

$used_quota = $visitors_limit - $visitors_left;
$is_50_percent_used = ( $used_quota / $visitors_limit ) >= 0.5;

if ( ! $is_50_percent_used ) {
return false;
}

return true;
}
}
Loading