Commit 941d4805 authored by ThinhNC's avatar ThinhNC

feat(ai): add AI accuracy warning modal and disclaimers for Zalo review compliance

parent 6a2f8c14
...@@ -629,8 +629,24 @@ export const ShieldCheckIcon: React.FC<IconProps> = ({ size = 18, ...props }) => ...@@ -629,8 +629,24 @@ export const ShieldCheckIcon: React.FC<IconProps> = ({ size = 18, ...props }) =>
</svg> </svg>
); );
// Info Icon
export const InfoIcon: React.FC<IconProps> = ({ size = 18, ...props }) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<circle cx="12" cy="12" r="10" />
<line x1="12" y1="16" x2="12" y2="12" />
<line x1="12" y1="8" x2="12.01" y2="8" />
</svg>
);
......
...@@ -1412,6 +1412,28 @@ ...@@ -1412,6 +1412,28 @@
"shortHeader": "AI Assistant", "shortHeader": "AI Assistant",
"liveBadge": "Live AI", "liveBadge": "Live AI",
"subtitle": "Smart analysis and personal finance guidance", "subtitle": "Smart analysis and personal finance guidance",
"disclaimer": {
"button": "AI Notice",
"title": "Notice & Disclaimer on AI Features",
"badge": "Important Notice",
"lead": "To ensure transparency and accuracy in managing your personal finances, please note the following when using AI features:",
"points": {
"accuracy": {
"title": "Possibility of AI Inaccuracies",
"desc": "The AI Assistant and Chatbot are powered by artificial intelligence models. AI-generated responses and analytics may contain inaccuracies or errors."
},
"advisory": {
"title": "Informational Purpose Only",
"desc": "All insights, trend analysis, recommendations, and receipt extractions are for reference purposes only and do not constitute professional financial, tax, or investment advice."
},
"responsibility": {
"title": "Verify Important Information",
"desc": "Users should always verify data against actual bank statements, receipts, and invoices before making any financial decisions."
}
},
"confirm": "I Understand",
"learnMore": "Learn more"
},
"tabs": { "tabs": {
"label": "AI Assistant features", "label": "AI Assistant features",
"chat": "Advisor", "chat": "Advisor",
...@@ -1420,6 +1442,7 @@ ...@@ -1420,6 +1442,7 @@
"chat": { "chat": {
"title": "FinWise AI Advisor", "title": "FinWise AI Advisor",
"subtitle": "Ask questions about income, expenses, budgets & saving goals", "subtitle": "Ask questions about income, expenses, budgets & saving goals",
"disclaimer": "AI assistant may make mistakes. Please verify important financial information.",
"placeholder": "Ask AI about your personal finances...", "placeholder": "Ask AI about your personal finances...",
"send": "Send", "send": "Send",
"clearHistory": "New conversation", "clearHistory": "New conversation",
...@@ -1442,6 +1465,7 @@ ...@@ -1442,6 +1465,7 @@
"insights": { "insights": {
"title": "AI Financial Insights & Recommendations", "title": "AI Financial Insights & Recommendations",
"subtitle": "Automated trend analysis, anomaly detection, and optimization advice", "subtitle": "Automated trend analysis, anomaly detection, and optimization advice",
"disclaimer": "Notice: AI-generated insights and recommendations are for reference purposes only and may contain inaccuracies. Please cross-check with your actual financial data.",
"period": "Analysis Period", "period": "Analysis Period",
"tabsLabel": "Financial insights and recommendations", "tabsLabel": "Financial insights and recommendations",
"analysisTab": "Analysis", "analysisTab": "Analysis",
...@@ -1490,6 +1514,7 @@ ...@@ -1490,6 +1514,7 @@
"ocr": { "ocr": {
"title": "AI Receipt Extraction (OCR)", "title": "AI Receipt Extraction (OCR)",
"subtitle": "Upload or take a photo of a receipt for automatic data extraction", "subtitle": "Upload or take a photo of a receipt for automatic data extraction",
"disclaimer": "Notice: Automatic AI receipt extraction may contain errors. Please review the details before saving.",
"uploadTitle": "Upload or capture a receipt", "uploadTitle": "Upload or capture a receipt",
"uploadHint": "Supports JPEG, PNG, WebP or PDF files (max 5 MB)", "uploadHint": "Supports JPEG, PNG, WebP or PDF files (max 5 MB)",
"selectFile": "Select Receipt File", "selectFile": "Select Receipt File",
...@@ -1519,6 +1544,7 @@ ...@@ -1519,6 +1544,7 @@
"preview": { "preview": {
"title": "AI summary and suggestions", "title": "AI summary and suggestions",
"subtitle": "The most important takeaways from the current report period", "subtitle": "The most important takeaways from the current report period",
"disclaimer": "AI-generated analysis is for informational purposes only and may contain errors.",
"summaryLabel": "Overview", "summaryLabel": "Overview",
"highlightsLabel": "{{count}} notable insights", "highlightsLabel": "{{count}} notable insights",
"scopeHint": "Detailed analysis will keep this report's date range and currency.", "scopeHint": "Detailed analysis will keep this report's date range and currency.",
......
...@@ -1513,6 +1513,28 @@ ...@@ -1513,6 +1513,28 @@
"shortHeader": "Trợ lý AI", "shortHeader": "Trợ lý AI",
"liveBadge": "AI trực tiếp", "liveBadge": "AI trực tiếp",
"subtitle": "Phân tích thông minh và tư vấn tài chính cá nhân", "subtitle": "Phân tích thông minh và tư vấn tài chính cá nhân",
"disclaimer": {
"button": "Lưu ý về AI",
"title": "Lưu ý & Khuyến cáo về Trợ lý AI",
"badge": "Thông tin quan trọng",
"lead": "Để đảm bảo an toàn và tính chính xác trong quá trình quản lý tài chính cá nhân, vui lòng lưu ý các điều sau khi sử dụng tính năng AI:",
"points": {
"accuracy": {
"title": "Khả năng sai sót của AI",
"desc": "Trợ lý AI và Chatbot được vận hành bởi mô hình trí tuệ nhân tạo. Phản hồi và phân tích của AI có thể không hoàn toàn chính xác hoặc có thể có sai sót trong việc nhận diện và tính toán."
},
"advisory": {
"title": "Chỉ mang tính chất tham khảo",
"desc": "Mọi câu trả lời, nhận định xu hướng chi tiêu, phân tích ngân sách hay bóc tách hóa đơn chỉ mang tính chất hỗ trợ và tham khảo, không cấu thành lời khuyên đầu tư, kế toán hay tài chính chuyên nghiệp."
},
"responsibility": {
"title": "Tự kiểm chứng dữ liệu",
"desc": "Người dùng cần luôn kiểm tra, đối chiếu lại với hóa đơn, sao kê ngân hàng và thực tế trước khi đưa ra các quyết định tài chính quan trọng."
}
},
"confirm": "Tôi đã hiểu",
"learnMore": "Xem lưu ý"
},
"tabs": { "tabs": {
"label": "Các chức năng của Trợ lý AI", "label": "Các chức năng của Trợ lý AI",
"chat": "Tư vấn", "chat": "Tư vấn",
...@@ -1521,6 +1543,7 @@ ...@@ -1521,6 +1543,7 @@
"chat": { "chat": {
"title": "FinWise AI Advisor", "title": "FinWise AI Advisor",
"subtitle": "Hỏi đáp thu chi, ngân sách & mục tiêu tiết kiệm", "subtitle": "Hỏi đáp thu chi, ngân sách & mục tiêu tiết kiệm",
"disclaimer": "Trợ lý AI có thể đưa ra câu trả lời không chính xác. Hãy kiểm chứng lại thông tin quan trọng.",
"placeholder": "Hỏi AI về tài chính cá nhân...", "placeholder": "Hỏi AI về tài chính cá nhân...",
"send": "Gửi", "send": "Gửi",
"clearHistory": "Cuộc trò chuyện mới", "clearHistory": "Cuộc trò chuyện mới",
...@@ -1543,6 +1566,7 @@ ...@@ -1543,6 +1566,7 @@
"insights": { "insights": {
"title": "Phân tích Tài chính và Đề xuất của AI", "title": "Phân tích Tài chính và Đề xuất của AI",
"subtitle": "Tự động phân tích xu hướng chi tiêu, phát hiện bất thường và đề xuất kế hoạch tài chính", "subtitle": "Tự động phân tích xu hướng chi tiêu, phát hiện bất thường và đề xuất kế hoạch tài chính",
"disclaimer": "Lưu ý: Các phân tích và gợi ý do AI tạo ra mang tính chất tham khảo và có thể có sai sót. Vui lòng đối chiếu với dữ liệu thực tế.",
"period": "Kỳ báo cáo", "period": "Kỳ báo cáo",
"tabsLabel": "Phân tích và đề xuất tài chính", "tabsLabel": "Phân tích và đề xuất tài chính",
"analysisTab": "Phân tích", "analysisTab": "Phân tích",
...@@ -1591,6 +1615,7 @@ ...@@ -1591,6 +1615,7 @@
"ocr": { "ocr": {
"title": "Trích xuất Hóa đơn bằng AI (OCR)", "title": "Trích xuất Hóa đơn bằng AI (OCR)",
"subtitle": "Tải hoặc chụp ảnh hóa đơn để AI tự động bóc tách thông tin giao dịch", "subtitle": "Tải hoặc chụp ảnh hóa đơn để AI tự động bóc tách thông tin giao dịch",
"disclaimer": "Lưu ý: Kết quả trích xuất tự động bằng AI có thể có sai sót. Vui lòng kiểm tra kỹ lại số tiền và hạng mục trước khi lưu.",
"uploadTitle": "Tải lên hoặc chụp ảnh hóa đơn", "uploadTitle": "Tải lên hoặc chụp ảnh hóa đơn",
"uploadHint": "Hỗ trợ tệp JPEG, PNG, WebP hoặc PDF (tối đa 5 MB)", "uploadHint": "Hỗ trợ tệp JPEG, PNG, WebP hoặc PDF (tối đa 5 MB)",
"selectFile": "Chọn tệp hóa đơn", "selectFile": "Chọn tệp hóa đơn",
...@@ -1620,6 +1645,7 @@ ...@@ -1620,6 +1645,7 @@
"preview": { "preview": {
"title": "Tóm tắt và đề xuất từ AI", "title": "Tóm tắt và đề xuất từ AI",
"subtitle": "Những điểm quan trọng nhất trong kỳ báo cáo hiện tại", "subtitle": "Những điểm quan trọng nhất trong kỳ báo cáo hiện tại",
"disclaimer": "Thông tin phân tích do AI tạo ra chỉ mang tính tham khảo và có thể có sai sót.",
"summaryLabel": "Nhận định tổng quan", "summaryLabel": "Nhận định tổng quan",
"highlightsLabel": "{{count}} điểm đáng chú ý", "highlightsLabel": "{{count}} điểm đáng chú ý",
"scopeHint": "Phân tích chi tiết sẽ tiếp tục sử dụng khoảng thời gian và tiền tệ của báo cáo này.", "scopeHint": "Phân tích chi tiết sẽ tiếp tục sử dụng khoảng thời gian và tiền tệ của báo cáo này.",
......
...@@ -4,6 +4,7 @@ import { Card } from "@/components/ui/Card"; ...@@ -4,6 +4,7 @@ import { Card } from "@/components/ui/Card";
import { Input } from "@/components/ui/Input"; import { Input } from "@/components/ui/Input";
import { import {
AIAssistantIcon, AIAssistantIcon,
AlertTriangleIcon,
ChevronRightIcon, ChevronRightIcon,
ClockIcon, ClockIcon,
LightbulbIcon, LightbulbIcon,
...@@ -16,7 +17,11 @@ import { useAIChat } from "@/hooks/use-ai-assistant"; ...@@ -16,7 +17,11 @@ import { useAIChat } from "@/hooks/use-ai-assistant";
import { AIAssistantError } from "@/services/ai-assistant.service"; import { AIAssistantError } from "@/services/ai-assistant.service";
import { AIChatMessage, useAIChatStore } from "@/stores/ai-chat-store"; import { AIChatMessage, useAIChatStore } from "@/stores/ai-chat-store";
export const AIChatView: React.FC = () => { export interface AIChatViewProps {
onOpenDisclaimer?: () => void;
}
export const AIChatView: React.FC<AIChatViewProps> = ({ onOpenDisclaimer }) => {
const { t } = useI18n(); const { t } = useI18n();
const chatMutation = useAIChat(); const chatMutation = useAIChat();
...@@ -344,6 +349,23 @@ export const AIChatView: React.FC = () => { ...@@ -344,6 +349,23 @@ export const AIChatView: React.FC = () => {
{chatMutation.isPending ? t("common.processing") : t("ai.chat.send")} {chatMutation.isPending ? t("common.processing") : t("ai.chat.send")}
</Button> </Button>
</Card> </Card>
{/* Permanent disclaimer notice for AI content accuracy compliant with Zalo review */}
<div className="flex items-center justify-center gap-1.5 px-2 text-center">
<AlertTriangleIcon size={12} className="shrink-0 text-clay-warning" />
<p className="font-nunito text-[11px] text-clay-text-muted leading-tight">
{t("ai.chat.disclaimer")}
{onOpenDisclaimer && (
<button
type="button"
onClick={onOpenDisclaimer}
className="ml-1 font-semibold text-clay-primary hover:underline inline-flex items-center"
>
{t("ai.disclaimer.learnMore")}
</button>
)}
</p>
</div>
</div> </div>
</div> </div>
); );
......
import React from "react";
import { Modal } from "@/components/ui/Modal";
import { Button } from "@/components/ui/Button";
import {
AlertTriangleIcon,
ShieldCheckIcon,
SparklesIcon,
} from "@/components/ui/icons";
import { useI18n } from "@/i18n";
export interface AIDisclaimerModalProps {
isOpen: boolean;
onClose: () => void;
}
export const AIDisclaimerModal: React.FC<AIDisclaimerModalProps> = ({
isOpen,
onClose,
}) => {
const { t } = useI18n();
return (
<Modal
isOpen={isOpen}
onClose={onClose}
title={t("ai.disclaimer.title")}
footer={
<Button
variant="primary"
className="w-full py-2.5 text-sm font-bold shadow-clay-button"
onClick={onClose}
>
{t("ai.disclaimer.confirm")}
</Button>
}
>
<div className="flex flex-col gap-3.5 text-left">
{/* Warning Badge Header */}
<div className="flex items-start gap-3 rounded-2xl border border-clay-warning/35 bg-clay-warning/10 p-3 shadow-clay-card">
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-xl bg-clay-warning/20 text-clay-warning">
<AlertTriangleIcon size={18} />
</div>
<div className="space-y-0.5">
<h4 className="font-baloo text-xs font-bold uppercase tracking-wider text-clay-warning">
{t("ai.disclaimer.badge")}
</h4>
<p className="font-nunito text-xs text-clay-text-muted leading-relaxed">
{t("ai.disclaimer.lead")}
</p>
</div>
</div>
{/* 3 Key Warning Points */}
<div className="space-y-2.5">
{/* Point 1: Possibility of AI Errors */}
<div className="flex items-start gap-3 rounded-xl border border-clay-highlight/40 bg-clay-surface p-3 shadow-clay-card">
<div className="flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-clay-expense/15 text-clay-expense">
<AlertTriangleIcon size={15} />
</div>
<div className="space-y-0.5">
<h5 className="font-baloo text-xs font-bold text-clay-text">
{t("ai.disclaimer.points.accuracy.title")}
</h5>
<p className="font-nunito text-xs text-clay-text-muted leading-relaxed">
{t("ai.disclaimer.points.accuracy.desc")}
</p>
</div>
</div>
{/* Point 2: Informational Purpose Only */}
<div className="flex items-start gap-3 rounded-xl border border-clay-highlight/40 bg-clay-surface p-3 shadow-clay-card">
<div className="flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-clay-primary/15 text-clay-primary">
<SparklesIcon size={15} />
</div>
<div className="space-y-0.5">
<h5 className="font-baloo text-xs font-bold text-clay-text">
{t("ai.disclaimer.points.advisory.title")}
</h5>
<p className="font-nunito text-xs text-clay-text-muted leading-relaxed">
{t("ai.disclaimer.points.advisory.desc")}
</p>
</div>
</div>
{/* Point 3: User Verification Responsibility */}
<div className="flex items-start gap-3 rounded-xl border border-clay-highlight/40 bg-clay-surface p-3 shadow-clay-card">
<div className="flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-clay-income/15 text-clay-income">
<ShieldCheckIcon size={15} />
</div>
<div className="space-y-0.5">
<h5 className="font-baloo text-xs font-bold text-clay-text">
{t("ai.disclaimer.points.responsibility.title")}
</h5>
<p className="font-nunito text-xs text-clay-text-muted leading-relaxed">
{t("ai.disclaimer.points.responsibility.desc")}
</p>
</div>
</div>
</div>
</div>
</Modal>
);
};
...@@ -5,6 +5,7 @@ import { Card } from "@/components/ui/Card"; ...@@ -5,6 +5,7 @@ import { Card } from "@/components/ui/Card";
import { Select } from "@/components/ui/Select"; import { Select } from "@/components/ui/Select";
import { import {
AIAssistantIcon, AIAssistantIcon,
AlertTriangleIcon,
BudgetIcon, BudgetIcon,
ChevronRightIcon, ChevronRightIcon,
NotificationIcon, NotificationIcon,
...@@ -127,6 +128,14 @@ export const AIInsightsView: React.FC<AIInsightsViewProps> = ({ ...@@ -127,6 +128,14 @@ export const AIInsightsView: React.FC<AIInsightsViewProps> = ({
return ( return (
<div className="flex flex-col gap-4 pb-8"> <div className="flex flex-col gap-4 pb-8">
{/* AI Accuracy Disclaimer Notice */}
<div className="flex items-center gap-2 rounded-xl border border-clay-warning/30 bg-clay-warning/10 p-2.5 px-3 text-left">
<AlertTriangleIcon size={15} className="shrink-0 text-clay-warning" />
<p className="font-nunito text-[11px] text-clay-text-muted leading-tight">
{t("ai.insights.disclaimer")}
</p>
</div>
{/* Sub-tab switcher */} {/* Sub-tab switcher */}
<div <div
className="flex rounded-clay border border-clay-highlight/30 bg-clay-bg p-1 shadow-clay-pressed" className="flex rounded-clay border border-clay-highlight/30 bg-clay-bg p-1 shadow-clay-pressed"
......
import React, { useEffect, useRef, useState } from "react"; import React, { useEffect, useRef, useState } from "react";
import api from "zmp-sdk"; import api from "zmp-sdk";
import { Button } from "@/components/ui/Button"; import { Button } from "@/components/ui/Button";
import { AlertTriangleIcon } from "@/components/ui/icons";
import { useI18n } from "@/i18n"; import { useI18n } from "@/i18n";
import { useExtractReceipt } from "@/hooks/use-ai-assistant"; import { useExtractReceipt } from "@/hooks/use-ai-assistant";
import { formatBusinessDate } from "@/lib/business-time"; import { formatBusinessDate } from "@/lib/business-time";
...@@ -378,6 +379,14 @@ export const ReceiptScannerView: React.FC<ReceiptScannerViewProps> = ({ onTransa ...@@ -378,6 +379,14 @@ export const ReceiptScannerView: React.FC<ReceiptScannerViewProps> = ({ onTransa
</div> </div>
)} )}
{/* AI Accuracy Disclaimer Notice */}
<div className="mt-4 flex items-center gap-2 rounded-xl border border-clay-warning/30 bg-clay-warning/10 p-2.5 px-3 text-left">
<AlertTriangleIcon size={15} className="shrink-0 text-clay-warning" />
<p className="font-nunito text-[11px] text-clay-text-muted leading-tight">
{t("ai.ocr.disclaimer")}
</p>
</div>
{/* Confirm Create Transaction Action */} {/* Confirm Create Transaction Action */}
<div className="mt-5 flex flex-col items-center justify-between gap-4 border-t border-clay-highlight/40 px-2 pb-2 pt-4 sm:flex-row"> <div className="mt-5 flex flex-col items-center justify-between gap-4 border-t border-clay-highlight/40 px-2 pb-2 pt-4 sm:flex-row">
<span className="clay-caption text-xs text-left">{t("ai.ocr.confirmHint")}</span> <span className="clay-caption text-xs text-left">{t("ai.ocr.confirmHint")}</span>
......
...@@ -4,19 +4,33 @@ import { Card } from "@/components/ui/Card"; ...@@ -4,19 +4,33 @@ import { Card } from "@/components/ui/Card";
import { import {
AIAssistantIcon, AIAssistantIcon,
IconGradients, IconGradients,
InfoIcon,
} from "@/components/ui/icons"; } from "@/components/ui/icons";
import { useI18n } from "@/i18n"; import { useI18n } from "@/i18n";
import { safeStorage } from "@/lib/storage";
import { FinWiseNavigationState, isFromReports } from "@/lib/navigation-state"; import { FinWiseNavigationState, isFromReports } from "@/lib/navigation-state";
import { AIChatView } from "./components/AIChatView"; import { AIChatView } from "./components/AIChatView";
import { AIInsightsView } from "./components/AIInsightsView"; import { AIInsightsView } from "./components/AIInsightsView";
import { AIDisclaimerModal } from "./components/AIDisclaimerModal";
type AITab = "chat" | "insights"; type AITab = "chat" | "insights";
const AI_DISCLAIMER_KEY = "finwise.aiDisclaimerAcknowledged";
const AIAssistantPage: React.FC = () => { const AIAssistantPage: React.FC = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation(); const location = useLocation();
const { t } = useI18n(); const { t } = useI18n();
const [isDisclaimerOpen, setIsDisclaimerOpen] = useState<boolean>(() => {
return safeStorage.getItem(AI_DISCLAIMER_KEY) !== "true";
});
const handleCloseDisclaimer = () => {
safeStorage.setItem(AI_DISCLAIMER_KEY, "true");
setIsDisclaimerOpen(false);
};
const navigationState = location.state as FinWiseNavigationState | null; const navigationState = location.state as FinWiseNavigationState | null;
const initialTab: AITab = navigationState?.tab === "insights" ? "insights" : "chat"; const initialTab: AITab = navigationState?.tab === "insights" ? "insights" : "chat";
const [activeTab, setActiveTab] = useState<AITab>(initialTab); const [activeTab, setActiveTab] = useState<AITab>(initialTab);
...@@ -50,19 +64,30 @@ const AIAssistantPage: React.FC = () => { ...@@ -50,19 +64,30 @@ const AIAssistantPage: React.FC = () => {
<Card className="relative overflow-hidden !bg-clay-primary p-5 !text-clay-on-primary shadow-clay-raised"> <Card className="relative overflow-hidden !bg-clay-primary p-5 !text-clay-on-primary shadow-clay-raised">
<div className="absolute -right-8 -top-8 h-32 w-32 rounded-full bg-clay-highlight/20" /> <div className="absolute -right-8 -top-8 h-32 w-32 rounded-full bg-clay-highlight/20" />
<div className="absolute -bottom-10 left-1/2 h-28 w-28 rounded-full bg-clay-info/20" /> <div className="absolute -bottom-10 left-1/2 h-28 w-28 rounded-full bg-clay-info/20" />
<div className="relative flex items-center gap-4"> <div className="relative flex items-center justify-between gap-4">
<div className="flex items-center gap-4 min-w-0">
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-clay bg-clay-surface text-clay-primary shadow-clay-raised"> <div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-clay bg-clay-surface text-clay-primary shadow-clay-raised">
<AIAssistantIcon size={28} /> <AIAssistantIcon size={28} />
</div> </div>
<div> <div className="min-w-0">
<h1 className="font-baloo text-xl font-bold leading-tight sm:text-2xl"> <h1 className="font-baloo text-xl font-bold leading-tight sm:text-2xl truncate">
{t("ai.header")} {t("ai.header")}
</h1> </h1>
<p className="mt-0.5 font-nunito text-xs text-clay-on-primary/80"> <p className="mt-0.5 font-nunito text-xs text-clay-on-primary/80 line-clamp-1">
{t("ai.subtitle")} {t("ai.subtitle")}
</p> </p>
</div> </div>
</div> </div>
<button
type="button"
onClick={() => setIsDisclaimerOpen(true)}
className="shrink-0 flex items-center gap-1.5 rounded-full bg-clay-surface/20 hover:bg-clay-surface/30 px-3 py-1.5 text-xs font-bold text-clay-on-primary backdrop-blur-sm transition-all focus:outline-none focus:ring-2 focus:ring-white/40 active:scale-95"
title={t("ai.disclaimer.title")}
>
<InfoIcon size={14} />
<span className="hidden sm:inline">{t("ai.disclaimer.button")}</span>
</button>
</div>
</Card> </Card>
{/* Tab Switcher */} {/* Tab Switcher */}
...@@ -104,7 +129,7 @@ const AIAssistantPage: React.FC = () => { ...@@ -104,7 +129,7 @@ const AIAssistantPage: React.FC = () => {
role="tabpanel" role="tabpanel"
aria-labelledby="ai-tab-chat" aria-labelledby="ai-tab-chat"
> >
<AIChatView /> <AIChatView onOpenDisclaimer={() => setIsDisclaimerOpen(true)} />
</div> </div>
)} )}
{visitedTabs.has("insights") && ( {visitedTabs.has("insights") && (
...@@ -122,6 +147,12 @@ const AIAssistantPage: React.FC = () => { ...@@ -122,6 +147,12 @@ const AIAssistantPage: React.FC = () => {
</div> </div>
)} )}
</main> </main>
{/* AI Accuracy Disclaimer Modal */}
<AIDisclaimerModal
isOpen={isDisclaimerOpen}
onClose={handleCloseDisclaimer}
/>
</Page> </Page>
); );
}; };
......
...@@ -215,9 +215,12 @@ export const AIInsightsPreview: React.FC<AIInsightsPreviewProps> = ({ context }) ...@@ -215,9 +215,12 @@ export const AIInsightsPreview: React.FC<AIInsightsPreviewProps> = ({ context })
)} )}
<div className="border-t border-clay-text/10 pt-1"> <div className="border-t border-clay-text/10 pt-1">
<p className="mb-3 text-center font-nunito text-[11px] font-semibold text-clay-text-muted"> <p className="mb-1 text-center font-nunito text-[11px] font-semibold text-clay-text-muted">
{t("ai.preview.scopeHint")} {t("ai.preview.scopeHint")}
</p> </p>
<p className="mb-3 text-center font-nunito text-[10px] text-clay-text-muted/80">
{t("ai.preview.disclaimer")}
</p>
<Button <Button
fullWidth fullWidth
className="gap-2 text-sm font-bold" className="gap-2 text-sm font-bold"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment