From aa54eb65b130688ef049b7c2a18509bb0485a68b Mon Sep 17 00:00:00 2001 From: opencode Date: Wed, 29 Jul 2026 14:34:24 +0530 Subject: [PATCH] feat: add language toggle to Dashboard and Chat pages (#144) - Create reusable LanguageToggle component (compact/full variants) - Add language toggle to Dashboard and AutoResolveChat headers - Persist language preference across sessions via localStorage - Fixes #144 --- .../src/components/shared/LanguageToggle.jsx | 95 +++++++++++++++++++ Frontend/src/user/pages/AutoResolveChat.jsx | 17 +++- Frontend/src/user/pages/CreateTicket.jsx | 2 +- Frontend/src/user/pages/Dashboard.jsx | 22 ++++- 4 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 Frontend/src/components/shared/LanguageToggle.jsx diff --git a/Frontend/src/components/shared/LanguageToggle.jsx b/Frontend/src/components/shared/LanguageToggle.jsx new file mode 100644 index 000000000..52fee5c3d --- /dev/null +++ b/Frontend/src/components/shared/LanguageToggle.jsx @@ -0,0 +1,95 @@ +import React, { useState, useRef, useEffect } from 'react'; +import { motion, AnimatePresence } from 'framer-motion'; +import { Globe, ChevronDown, CheckCircle2 } from 'lucide-react'; +import { SUPPORTED_LANGUAGES } from '../../services/translationService'; + +const LanguageToggle = ({ selectedLanguage, onLanguageChange, compact = false }) => { + const [isOpen, setIsOpen] = useState(false); + const ref = useRef(null); + + useEffect(() => { + const handleClickOutside = (e) => { + if (ref.current && !ref.current.contains(e.target)) setIsOpen(false); + }; + document.addEventListener('mousedown', handleClickOutside); + return () => document.removeEventListener('mousedown', handleClickOutside); + }, []); + + const currentLang = SUPPORTED_LANGUAGES.find(l => l.code === selectedLanguage); + + if (compact) { + return ( +
+ + + {isOpen && ( + + {SUPPORTED_LANGUAGES.map(lang => ( + + ))} + + )} + +
+ ); + } + + return ( +
+ + + {isOpen && ( + +
+ {SUPPORTED_LANGUAGES.map(lang => ( + + ))} +
+
+ )} +
+
+ ); +}; + +export default LanguageToggle; diff --git a/Frontend/src/user/pages/AutoResolveChat.jsx b/Frontend/src/user/pages/AutoResolveChat.jsx index d8863209b..6b9c82dc3 100644 --- a/Frontend/src/user/pages/AutoResolveChat.jsx +++ b/Frontend/src/user/pages/AutoResolveChat.jsx @@ -14,6 +14,8 @@ import useTicketStore from '../../store/ticketStore'; import { Card, CardContent } from "../../components/ui/card"; import { askAI } from '../../services/aiAssistant'; import useToastStore from '../../store/toastStore'; +import LanguageToggle from "../../components/shared/LanguageToggle"; +import { translateText } from '../../services/translationService'; const AutoResolveChat = () => { const { aiTicket } = useTicketStore(); @@ -26,6 +28,14 @@ const AutoResolveChat = () => { const { showToast } = useToastStore(); const scrollRef = useRef(null); const fileInputRef = useRef(null); + const [selectedLanguage, setSelectedLanguage] = useState('en'); + + const handleLanguageChange = (langCode) => { + setSelectedLanguage(langCode); + if (langCode !== 'en') { + localStorage.setItem('preferredLanguage', langCode); + } + }; // Initial Plan Generation useEffect(() => { @@ -238,7 +248,12 @@ const AutoResolveChat = () => { {/* "Escalate Anyway" Integrated Option */} -
+
+