global update and global fix
This commit is contained in:
122
apps/frontend/components/chat/bot-inline-keyboard.tsx
Normal file
122
apps/frontend/components/chat/bot-inline-keyboard.tsx
Normal file
@@ -0,0 +1,122 @@
|
||||
'use client';
|
||||
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import { InlineKeyboardButton, parseInlineKeyboardMarkup } from '@/lib/bot-reply-markup';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
export function buildInlineButtonKey(messageId: number, rowIndex: number, buttonIndex: number) {
|
||||
return `${messageId}:${rowIndex}:${buttonIndex}`;
|
||||
}
|
||||
|
||||
interface BotInlineKeyboardProps {
|
||||
markup: unknown;
|
||||
messageId: number;
|
||||
loadingButtonKey?: string | null;
|
||||
disabled?: boolean;
|
||||
onCallbackClick?: (callbackData: string, buttonKey: string) => void | Promise<void>;
|
||||
onOpenMiniApp?: (url: string) => void;
|
||||
onOpenUrl?: (url: string) => void;
|
||||
}
|
||||
|
||||
export function BotInlineKeyboard({
|
||||
markup,
|
||||
messageId,
|
||||
loadingButtonKey = null,
|
||||
disabled = false,
|
||||
onCallbackClick,
|
||||
onOpenMiniApp,
|
||||
onOpenUrl
|
||||
}: BotInlineKeyboardProps) {
|
||||
const rows = parseInlineKeyboardMarkup(markup);
|
||||
if (!rows.length) return null;
|
||||
|
||||
return (
|
||||
<div className="mt-2 space-y-1.5">
|
||||
{rows.map((row, rowIndex) => (
|
||||
<div
|
||||
key={`row-${rowIndex}`}
|
||||
className={cn('flex gap-1.5', row.length === 1 ? 'flex-col' : 'flex-row flex-wrap')}
|
||||
>
|
||||
{row.map((button, buttonIndex) => (
|
||||
<InlineKeyboardButtonView
|
||||
key={`btn-${rowIndex}-${buttonIndex}`}
|
||||
button={button}
|
||||
buttonKey={buildInlineButtonKey(messageId, rowIndex, buttonIndex)}
|
||||
fullWidth={row.length === 1}
|
||||
loading={loadingButtonKey === buildInlineButtonKey(messageId, rowIndex, buttonIndex)}
|
||||
disabled={disabled || (loadingButtonKey !== null && loadingButtonKey !== buildInlineButtonKey(messageId, rowIndex, buttonIndex))}
|
||||
onCallbackClick={onCallbackClick}
|
||||
onOpenMiniApp={onOpenMiniApp}
|
||||
onOpenUrl={onOpenUrl}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function InlineKeyboardButtonView({
|
||||
button,
|
||||
buttonKey,
|
||||
fullWidth,
|
||||
loading,
|
||||
disabled,
|
||||
onCallbackClick,
|
||||
onOpenMiniApp,
|
||||
onOpenUrl
|
||||
}: {
|
||||
button: InlineKeyboardButton;
|
||||
buttonKey: string;
|
||||
fullWidth: boolean;
|
||||
loading: boolean;
|
||||
disabled: boolean;
|
||||
onCallbackClick?: (callbackData: string, buttonKey: string) => void | Promise<void>;
|
||||
onOpenMiniApp?: (url: string) => void;
|
||||
onOpenUrl?: (url: string) => void;
|
||||
}) {
|
||||
const webAppUrl = button.web_app?.url;
|
||||
const callbackData = button.callback_data ?? button.callbackData;
|
||||
|
||||
async function handleClick(event: React.MouseEvent<HTMLButtonElement>) {
|
||||
event.preventDefault();
|
||||
if (disabled || loading) return;
|
||||
|
||||
if (webAppUrl) {
|
||||
if (onOpenMiniApp) {
|
||||
onOpenMiniApp(webAppUrl);
|
||||
} else {
|
||||
window.open(webAppUrl, '_blank', 'noopener,noreferrer');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (button.url) {
|
||||
if (onOpenUrl) {
|
||||
onOpenUrl(button.url);
|
||||
} else {
|
||||
window.open(button.url, '_blank', 'noopener,noreferrer');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (callbackData && onCallbackClick) {
|
||||
await onCallbackClick(callbackData, buttonKey);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
disabled={disabled || loading}
|
||||
className={cn(
|
||||
'inline-flex min-h-9 items-center justify-center rounded-xl border border-[#dce3ec] bg-[#f4f7fb] px-3 py-2 text-xs font-medium text-[#1f2430] transition',
|
||||
'hover:bg-[#e8eef6] disabled:cursor-not-allowed disabled:opacity-60',
|
||||
fullWidth ? 'w-full' : 'min-w-0 flex-1'
|
||||
)}
|
||||
onClick={(event) => void handleClick(event)}
|
||||
>
|
||||
{loading ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : button.text}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user