Skip to content

Commit

Permalink
release(minor): v3.12.0
Browse files Browse the repository at this point in the history
### New Features
- **Handshake Mechanism**: Implemented a handshake mechanism to ensure that the website can use Optimole when connecting.
- **New Cloud Library UI/UX**: Introduced a new and improved UI and experience for the Cloud Library.

### Enhancements

- **Improved Optimole Dashboard UX**: Enhancements to improve the user experience of the Optimole dashboard.
- **Cohesive UI on Plugin Dashboard**: Improved the overall UI on the plugin dashboard for a more cohesive look and feel.
- **Revamped Offloading User Experience**: Revamped the UI/UX for offloading operations, making it more intuitive and user-friendly.
- **Cloud Library Access by Default**: Enabled Cloud Library access by default for all users, enhancing accessibility to Optimole's features.
- **Notice for Offloaded Images Limit**: Added a notice if the count of offloaded images exceeds the limit, keeping users informed.
  • Loading branch information
abaicus authored Dec 19, 2023
2 parents f6efcae + 8df86e1 commit 0c1cd75
Show file tree
Hide file tree
Showing 31 changed files with 2,789 additions and 29,392 deletions.
4 changes: 2 additions & 2 deletions assets/src/dashboard/parts/Main.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const Main = () => {


return (
<>
<div className="antialiased">
<Header
tab={ tab }
setTab={ setTab }
Expand Down Expand Up @@ -120,7 +120,7 @@ const Main = () => {
) }

<Toasts />
</>
</div>
);
};

Expand Down
62 changes: 62 additions & 0 deletions assets/src/dashboard/parts/components/Modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import classnames from 'classnames';

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' }) {

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

const iconClasses = classnames({
'bg-stale-yellow': 'warning' === variant,
'bg-light-blue': 'default' === variant
},
'p-3 rounded-full'
);

const actionButtonClasses = classnames(
{
'bg-mango-yellow': 'warning' === variant
},
'optml__button flex justify-center px-5 py-3 rounded font-bold min-h-40 basis-1/5'
);

return (
<CoreModal
__experimentalHideHeader={ true }
className="max-w-xl antialiased"
onRequestClose={ onRequestClose }
isFullScreen={ isMobileViewport }
>
<Button
icon={ close }
onClick={ onRequestClose }
label={ optimoleDashboardApp.strings.csat.close }
className="fixed right-3 top-3 cursor-pointer"
/>

<div className="flex flex-col items-center">
<Icon
icon={ icon }
size={ 24 }
className={iconClasses}
/>

<h2
className="mb-0"
dangerouslySetInnerHTML={ { __html: labels.title } }
/>

<p
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>
</CoreModal>
);
}
87 changes: 87 additions & 0 deletions assets/src/dashboard/parts/components/Notice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import classNames from 'classnames';
import { Icon, cancelCircleFilled, warning, info, check, closeSmall } from '@wordpress/icons';

import { checkmark } from '../../utils/icons';

export default function Notice({
text,
title,
disableIcon = false,
type = 'info',
className = '',
smallTitle = false,
children,
onDismiss
}) {
const noticeClasses = classNames({
'bg-yellow-50 text-yellow-700': 'warning' === type,
'bg-green-50 text-green-700': 'success' === type,
'bg-red-50 text-red-700': 'error' === type,
'bg-blue-50 text-blue-700': 'info' === type,
'bg-info text-white': 'primary' === type
},
`rounded-md my-5 text-sm p-4 om-notice om-notice-${type} relative` );

const iconClasses = classNames({
'fill-yellow-500': 'warning' === type,
'fill-green-500': 'success' === type,
'fill-red-500': 'error' === type,
'fill-blue-500': 'info' === type,
'fill-white': 'primary' === type,
'h-6 w-6': 'primary' !== type,
'h-12 w-12': 'primary' === type
});

const contentWrapClasses = classNames({
'ml-3 mt-0.5': ! disableIcon && ! title,
'mt-2 mx-1.5': title
});

const titleClasses = classNames({
'text-yellow-800': 'warning' === type,
'text-green-800': 'success' === type,
'text-red-800': 'error' === type,
'text-blue-800': 'info' === type,
'font-bold text-base': 'primary' !== type,
'text-white text-sm': 'primary' === type,
'text-s': smallTitle
}, 'm-0' );

const icons = {
'warning': warning,
'success': check,
'error': cancelCircleFilled,
'info': info,
'primary': checkmark
};


return (
<div className={noticeClasses}>

{onDismiss && (
<button
className="flex items-center justify-center absolute bg-transparent text-current right-1 top-1 border-0 rounded-full p-0 cursor-pointer hover:bg-white transition-all hover:text-info"
onClick={onDismiss}>
<Icon className="fill-current" icon={closeSmall}/>
</button>
)}

<div className={title ? 'grid' : 'flex'}>
<div className={classNames( 'flex-shrink-0 flex gap-2', { 'items-center': title })}>
{! disableIcon && (
<Icon icon={icons[type] || null} className={iconClasses} />
)}
{title && <div className={titleClasses} dangerouslySetInnerHTML={{ __html: title }} />}
</div>
{children || text && (
<div className={contentWrapClasses}>
{text && <p className="m-0" dangerouslySetInnerHTML={{ __html: text }} />}
{children}
</div>
)}
</div>
</div>
);

}
22 changes: 12 additions & 10 deletions assets/src/dashboard/parts/components/ProgressBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,30 @@ import classnames from 'classnames';

const ProgressBar = ({
value,
max,
max = 100,
className,
...props
}) => {
const progress = Math.floor( ( value / max ) * 100 );
const progress = Math.round( ( value / max ) * 100 );
const background = props.background || '#FFF';

const wrapClasses = classnames(
'w-full h-2.5 border rounded-md border-solid bg-white border-light-gray relative overflow-hidden',
className
);

return (
<div
className={ classnames(
'w-full h-2.5 border rounded-md border-solid bg-white border-light-gray',
className
) }
className={ wrapClasses }
role="progressbar"
aria-valuemin="0"
aria-valuemax={ max }
aria-valuenow={ value }
style={{
background: 'linear-gradient(90deg, var( --optml-progress ) ' + progress + '%, ' + background + ' ' + progress + '%)'
}}
{ ...props }
/>
>
<div className="absolute left-0 h-full bg-info" style={{ width: `${progress}%` }}></div>

</div>
);
};

Expand Down
23 changes: 23 additions & 0 deletions assets/src/dashboard/parts/components/ProgressTile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* global optimoleDashboardApp */

import ProgressBar from './ProgressBar';
import { sync } from '../../utils/icons';
import { Icon } from '@wordpress/icons';

export default function ProgressTile({ title, progress, description, onCancel, hideCancel = false }) {
const { strings } = optimoleDashboardApp;
return (
<div className="bg-gray-50 rounded-md p-4 space-y-4">
<div className="flex gap-3 items-center">
<Icon icon={sync} className="text-info animate-spin -scale-y-100"/>
{title && <p className="uppercase text-s font-semibold text-light-black m-0">{title}</p>}

{! hideCancel && <button onClick={onCancel} className="appearance-none border border-info text-info bg-transparent rounded px-4 py-2 ml-auto text-s hover:border-red-500 hover:bg-red-500 hover:text-white cursor-pointer">{strings.cancel}</button>}
</div>

<ProgressBar value={progress} />

{description && <p className="text-xs text-gray-500">{description}</p>}
</div>
);
}
74 changes: 74 additions & 0 deletions assets/src/dashboard/parts/components/RadioBoxes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import classNames from 'classnames';

export default function RadioBoxes({ options, value, onChange, label, disabled = false, className }) {

const handleClick = ( e ) => {
onChange( e.target.value );
};

const fieldsetClasses = classNames({
'opacity-50': disabled
}, 'transition-all my-6 gap-6 grid opacity-100' );

return (
<fieldset
className={`my-6 gap-6 grid ${className}`}
onChange={handleClick}
>

{label && <legend className="uppercase font-semibold text-s text-light-black mb-6">{label}</legend>}

{options.map( ( option, index ) => {
const { title, value: buttonValue, description } = option;

const isActive = value === buttonValue;
const buttonClasses = classNames({
'outline-info': isActive,
'outline-transparent': ! isActive
}, 'flex gap-6 items-start bg-gray-50 rounded-md p-4 outline -outline-offset-3 outline-3 transition-all' );

return (
<label
htmlFor={buttonValue}
key={buttonValue}
className={buttonClasses}
>
<RadioDot isActive={isActive} />

<div className="grid space-y-2">
{title && <div className="text-base font-medium text-gray-700">{title}</div>}
{description && <div className="text-sm text-gray-500">{description}</div>}
</div>
<input
type="radio"
name="label"
value={buttonValue}
id={buttonValue}
className="!opacity-0 !w-0 !h-0 !overflow-hidden !absolute !pointer-events-none"
disabled={disabled}
/>
</label>
);

})}

</fieldset>
);
}

const RadioDot = ({ isActive }) => {
const wrapClasses = classNames({
'bg-white outline-info': isActive,
'bg-gray-200 outline-transparent': ! isActive
}, 'w-[24px] h-[24px] rounded-full flex items-center justify-center flex-shrink-0 outline outline-3 -outline-offset-3 transition-all' );

const dotClasses = classNames({
'bg-info': isActive
}, 'w-[12px] h-[12px] rounded-full background-info transition-all' );

return (
<div className={wrapClasses}>
{isActive && <div className={dotClasses} />}
</div>
);
};
2 changes: 1 addition & 1 deletion assets/src/dashboard/parts/connect/APIForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ const APIForm = ({
</div>

{ ! hasValidKey && undefined !== errors['error_connect'] && (
<p className="block text-xs mt-1 text-danger">{ errors['error_connect'] }</p>
<p className="block text-xs mt-1 text-danger" dangerouslySetInnerHTML={ { __html: errors['error_connect'] } }></p>
) }

<div className="text-center py-3">
Expand Down
7 changes: 7 additions & 0 deletions assets/src/dashboard/parts/connect/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ const ConnectLayout = () => {
return;
}


if ( 'domain_not_accessible' === response.code ) {
setErrors({
'domain_not_accessible': response.message
});
return;
}
if ( 'success' !== response.code ) {
setErrors({
'error_register': optimoleDashboardApp.strings.error_register
Expand Down
18 changes: 10 additions & 8 deletions assets/src/dashboard/parts/connected/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,17 @@ if ( 'undefined' !== typeof window && optimoleDashboardApp.user_data.plan ) {
formbricks.init({
environmentId: 'clo8wxwzj44orpm0gjchurujm',
apiHost: 'https://app.formbricks.com',
userId: 'optml_' + ( optimoleDashboardApp.user_data.id )
userId: 'optml_' + ( optimoleDashboardApp.user_data.id ),
attributes: {
plan: optimoleDashboardApp.user_data.plan,
status: optimoleDashboardApp.user_data.status,
cname_assigned: optimoleDashboardApp.user_data.is_cname_assigned || 'no',
connected_websites: optimoleDashboardApp.user_data.whitelist.length,
traffic: convertToCategory( optimoleDashboardApp.user_data.traffic, 500 ),
images_number: convertToCategory( optimoleDashboardApp.user_data.images_number, 100 ),
days_since_install: convertToCategory( optimoleDashboardApp.days_since_install )
}
});
formbricks.setAttribute( 'plan', optimoleDashboardApp.user_data.plan );
formbricks.setAttribute( 'status', optimoleDashboardApp.user_data.status );
formbricks.setAttribute( 'cname_assigned', optimoleDashboardApp.user_data.is_cname_assigned || 'no' );
formbricks.setAttribute( 'connected_websites', optimoleDashboardApp.user_data.whitelist.length );
formbricks.setAttribute( 'traffic', convertToCategory( optimoleDashboardApp.user_data.traffic, 500 ) );
formbricks.setAttribute( 'images_number', convertToCategory( optimoleDashboardApp.user_data.images_number, 100 ) );
formbricks.setAttribute( 'days_since_install', convertToCategory( optimoleDashboardApp.days_since_install ) );

}
function convertToCategory( number, scale = 1 ) {
Expand Down
Loading

0 comments on commit 0c1cd75

Please sign in to comment.