/**
* External dependencies
*/
import { Button } from '@wordpress/components';
import { createInterpolateElement } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import { Icon, check } from '@wordpress/icons';
import { Link } from '@wordpress/ui';
import clsx from 'clsx';
/**
* Internal dependencies
*/
import './style.scss';
import errorExclamation from '../../icons/error-exclamation.tsx';
import { ERROR_QUOTA_EXCEEDED } from '../../types.ts';
import AiFeedbackThumbs from '../ai-feedback/index.tsx';
/**
* Types
*/
import type { SuggestionErrorCode } from '../../types.ts';
import type { MouseEvent, ReactElement, ReactNode } from 'react';
export const MESSAGE_SEVERITY_WARNING = 'warning';
export const MESSAGE_SEVERITY_ERROR = 'error';
export const MESSAGE_SEVERITY_SUCCESS = 'success';
export const MESSAGE_SEVERITY_INFO = 'info';
export type MessageSeverityProp =
| typeof MESSAGE_SEVERITY_WARNING
| typeof MESSAGE_SEVERITY_ERROR
| typeof MESSAGE_SEVERITY_SUCCESS
| typeof MESSAGE_SEVERITY_INFO
| null;
type AiFeedbackThumbsOptions = {
showAIFeedbackThumbs?: boolean;
ratedItem?: string;
prompt?: string;
block?: string | null;
onRate?: ( rating: string ) => void;
};
export type MessageProps = {
icon?: ReactNode;
severity?: MessageSeverityProp;
aiFeedbackThumbsOptions?: AiFeedbackThumbsOptions;
children: ReactNode;
};
export type GuidelineMessageProps = {
aiFeedbackThumbsOptions?: AiFeedbackThumbsOptions;
};
export type OnUpgradeClick = ( event?: MouseEvent< HTMLButtonElement > ) => void;
export type UpgradeMessageProps = {
requestsRemaining: number;
severity?: MessageSeverityProp;
onUpgradeClick: OnUpgradeClick;
upgradeUrl?: string;
};
export type ErrorMessageProps = {
error?: string;
code?: SuggestionErrorCode;
onTryAgainClick: () => void;
onUpgradeClick: OnUpgradeClick;
upgradeUrl?: string;
};
const messageIconsMap = {
[ MESSAGE_SEVERITY_INFO ]: null,
[ MESSAGE_SEVERITY_WARNING ]: null,
[ MESSAGE_SEVERITY_ERROR ]: errorExclamation,
[ MESSAGE_SEVERITY_SUCCESS ]: check,
};
/**
* React component to render a block message.
*
* @param {MessageProps} props - Component props.
* @return {ReactElement} Banner component.
*/
export default function Message( {
severity = MESSAGE_SEVERITY_INFO,
icon = null,
aiFeedbackThumbsOptions = {
showAIFeedbackThumbs: false,
ratedItem: '',
prompt: '',
block: null,
onRate: () => {},
},
children,
}: MessageProps ): ReactElement {
return (
{ ( messageIconsMap[ severity ] || icon ) && (
) }
{
{ children }
}
{ aiFeedbackThumbsOptions.showAIFeedbackThumbs && aiFeedbackThumbsOptions.prompt && (
) }
);
}
/**
* React component to render a learn more link.
*
* @return {ReactElement} - Learn more link component.
*/
function LearnMoreLink(): ReactElement {
return (
{ __( 'Learn more', 'jetpack-ai-client' ) }
);
}
/**
* React component to render a guideline message.
*
* @param {GuidelineMessageProps} props - Component props.
* @return {ReactElement} - Message component.
*/
export function GuidelineMessage( {
aiFeedbackThumbsOptions = {
showAIFeedbackThumbs: false,
ratedItem: '',
prompt: '',
block: null,
onRate: () => {},
},
}: GuidelineMessageProps ): ReactElement {
return (
{ __( 'AI-generated content could be inaccurate or biased.', 'jetpack-ai-client' ) }
);
}
/**
* React component to render a fair usage limit message.
*
* @return {ReactElement} - Message component.
*/
export function FairUsageLimitMessage(): ReactElement {
const message = __(
"You've reached this month's request limit, per our fair usage policy",
'jetpack-ai-client'
);
const element = createInterpolateElement( message, {
link: (
),
} );
return { element };
}
/**
* React component to render an upgrade message for free tier users
*
* @param {number} requestsRemaining - Number of requests remaining.
* @return {ReactElement} - Message component.
*/
export function UpgradeMessage( {
requestsRemaining,
severity,
onUpgradeClick,
upgradeUrl,
}: UpgradeMessageProps ): ReactElement {
let messageSeverity = severity;
if ( messageSeverity == null ) {
messageSeverity = requestsRemaining > 0 ? MESSAGE_SEVERITY_INFO : MESSAGE_SEVERITY_WARNING;
}
return (
{ sprintf(
// translators: %1$d: number of requests remaining
__( 'You have %1$d requests remaining.', 'jetpack-ai-client' ),
requestsRemaining
) }
);
}
/**
* React component to render an error message
*
* @param {number} requestsRemaining - Number of requests remaining.
* @return {ReactElement} - Message component.
*/
export function ErrorMessage( {
error,
code,
onTryAgainClick,
onUpgradeClick,
upgradeUrl,
}: ErrorMessageProps ): ReactElement {
const errorMessage = error || __( 'Something went wrong', 'jetpack-ai-client' );
return (
{ sprintf(
// translators: %1$d: A dynamic error message
__( 'Error: %1$s', 'jetpack-ai-client' ),
errorMessage
) }
{ code === ERROR_QUOTA_EXCEEDED ? (
) : (
) }
);
}