Browse Source

feat: add DataAccessSettings translations to Hungarian #109

- Updated DataAccessSettings.tsx to use translation keys for all hardcoded strings
- Added translations for toast messages, security levels, access modes
- Added translations for GDPR notices and data type labels
- Added 'personalData' to common translations (EN & HU)
- All labels, badges, and descriptions now support i18n
Claude 4 months ago
parent
commit
14c1939e7e

+ 37 - 39
shopcall.ai-main/src/components/DataAccessSettings.tsx

@@ -93,8 +93,8 @@ export function DataAccessSettings({
       }
       }
 
 
       toast({
       toast({
-        title: "Access Policies Updated",
-        description: "Data access policies have been successfully updated.",
+        title: t('integrations.dataAccessSettings.toast.successTitle'),
+        description: t('integrations.dataAccessSettings.toast.successDescription'),
       });
       });
 
 
       setHasChanges(false);
       setHasChanges(false);
@@ -104,8 +104,8 @@ export function DataAccessSettings({
     } catch (error) {
     } catch (error) {
       console.error('Error updating access policies:', error);
       console.error('Error updating access policies:', error);
       toast({
       toast({
-        title: "Update Failed",
-        description: error instanceof Error ? error.message : "Failed to update access policies. Please try again.",
+        title: t('integrations.dataAccessSettings.toast.errorTitle'),
+        description: error instanceof Error ? error.message : t('integrations.dataAccessSettings.toast.errorDescription'),
         variant: "destructive",
         variant: "destructive",
       });
       });
     } finally {
     } finally {
@@ -136,16 +136,16 @@ export function DataAccessSettings({
 
 
     // When all settings are hidden except products, show based on products only
     // When all settings are hidden except products, show based on products only
     if (totalVisible === 1) {
     if (totalVisible === 1) {
-      if (policies.products_access_policy === 'not_allowed') return { level: "maximum", icon: ShieldCheck, color: "text-green-500", label: "Maximum Privacy" };
-      if (policies.products_access_policy === 'api_only') return { level: "high", icon: ShieldCheck, color: "text-green-400", label: "High Privacy" };
-      return { level: "full", icon: ShieldAlert, color: "text-orange-500", label: "Full Sync" };
+      if (policies.products_access_policy === 'not_allowed') return { level: "maximum", icon: ShieldCheck, color: "text-green-500", label: t('integrations.dataAccessSettings.securityLevel.maximumPrivacy') };
+      if (policies.products_access_policy === 'api_only') return { level: "high", icon: ShieldCheck, color: "text-green-400", label: t('integrations.dataAccessSettings.securityLevel.highPrivacy') };
+      return { level: "full", icon: ShieldAlert, color: "text-orange-500", label: t('integrations.dataAccessSettings.securityLevel.fullSync') };
     }
     }
 
 
-    if (notAllowedCount === totalVisible) return { level: "maximum", icon: ShieldCheck, color: "text-green-500", label: "Maximum Privacy" };
-    if (notAllowedCount >= totalVisible - 1) return { level: "high", icon: ShieldCheck, color: "text-green-400", label: "High Privacy" };
-    if (notAllowedCount >= 1 || apiOnlyCount >= totalVisible - 1) return { level: "medium", icon: Shield, color: "text-yellow-500", label: "Medium Privacy" };
-    if (apiOnlyCount >= 1) return { level: "balanced", icon: Shield, color: "text-blue-500", label: "Balanced" };
-    return { level: "full", icon: ShieldAlert, color: "text-orange-500", label: "Full Sync" };
+    if (notAllowedCount === totalVisible) return { level: "maximum", icon: ShieldCheck, color: "text-green-500", label: t('integrations.dataAccessSettings.securityLevel.maximumPrivacy') };
+    if (notAllowedCount >= totalVisible - 1) return { level: "high", icon: ShieldCheck, color: "text-green-400", label: t('integrations.dataAccessSettings.securityLevel.highPrivacy') };
+    if (notAllowedCount >= 1 || apiOnlyCount >= totalVisible - 1) return { level: "medium", icon: Shield, color: "text-yellow-500", label: t('integrations.dataAccessSettings.securityLevel.mediumPrivacy') };
+    if (apiOnlyCount >= 1) return { level: "balanced", icon: Shield, color: "text-blue-500", label: t('integrations.dataAccessSettings.securityLevel.balanced') };
+    return { level: "full", icon: ShieldAlert, color: "text-orange-500", label: t('integrations.dataAccessSettings.securityLevel.fullSync') };
   };
   };
 
 
   const security = getSecurityLevel();
   const security = getSecurityLevel();
@@ -164,11 +164,11 @@ export function DataAccessSettings({
           <Label htmlFor={`${dataType}-sync`} className={`flex-1 ${isDisabled ? 'cursor-not-allowed' : 'cursor-pointer'}`}>
           <Label htmlFor={`${dataType}-sync`} className={`flex-1 ${isDisabled ? 'cursor-not-allowed' : 'cursor-pointer'}`}>
             <div className="flex items-center gap-2 mb-1">
             <div className="flex items-center gap-2 mb-1">
               <Database className="w-4 h-4 text-cyan-400" />
               <Database className="w-4 h-4 text-cyan-400" />
-              <span className="text-white font-medium">Sync & Cache</span>
-              <Badge variant="outline" className="text-xs border-cyan-500 text-cyan-400">Fastest</Badge>
+              <span className="text-white font-medium">{t('integrations.dataAccessSettings.accessModes.syncCache.title')}</span>
+              <Badge variant="outline" className="text-xs border-cyan-500 text-cyan-400">{t('integrations.dataAccessSettings.accessModes.syncCache.badge')}</Badge>
             </div>
             </div>
             <p className="text-xs text-slate-400">
             <p className="text-xs text-slate-400">
-              Store data locally in database and Qdrant vector search for instant access
+              {t('integrations.dataAccessSettings.accessModes.syncCache.description')}
             </p>
             </p>
           </Label>
           </Label>
         </div>
         </div>
@@ -178,11 +178,11 @@ export function DataAccessSettings({
           <Label htmlFor={`${dataType}-api`} className={`flex-1 ${isDisabled ? 'cursor-not-allowed' : 'cursor-pointer'}`}>
           <Label htmlFor={`${dataType}-api`} className={`flex-1 ${isDisabled ? 'cursor-not-allowed' : 'cursor-pointer'}`}>
             <div className="flex items-center gap-2 mb-1">
             <div className="flex items-center gap-2 mb-1">
               <Cloud className="w-4 h-4 text-blue-400" />
               <Cloud className="w-4 h-4 text-blue-400" />
-              <span className="text-white font-medium">API Access Only</span>
-              {isPII && <Badge variant="outline" className="text-xs border-green-500 text-green-400">GDPR Friendly</Badge>}
+              <span className="text-white font-medium">{t('integrations.dataAccessSettings.accessModes.apiOnly.title')}</span>
+              {isPII && <Badge variant="outline" className="text-xs border-green-500 text-green-400">{t('integrations.dataAccessSettings.accessModes.apiOnly.badge')}</Badge>}
             </div>
             </div>
             <p className="text-xs text-slate-400">
             <p className="text-xs text-slate-400">
-              Fetch data directly from your store's API on demand (no local storage)
+              {t('integrations.dataAccessSettings.accessModes.apiOnly.description')}
             </p>
             </p>
           </Label>
           </Label>
         </div>
         </div>
@@ -192,11 +192,11 @@ export function DataAccessSettings({
           <Label htmlFor={`${dataType}-none`} className={`flex-1 ${isDisabled ? 'cursor-not-allowed' : 'cursor-pointer'}`}>
           <Label htmlFor={`${dataType}-none`} className={`flex-1 ${isDisabled ? 'cursor-not-allowed' : 'cursor-pointer'}`}>
             <div className="flex items-center gap-2 mb-1">
             <div className="flex items-center gap-2 mb-1">
               <Ban className="w-4 h-4 text-red-400" />
               <Ban className="w-4 h-4 text-red-400" />
-              <span className="text-white font-medium">No Access</span>
-              <Badge variant="outline" className="text-xs border-red-500 text-red-400">Blocked</Badge>
+              <span className="text-white font-medium">{t('integrations.dataAccessSettings.accessModes.noAccess.title')}</span>
+              <Badge variant="outline" className="text-xs border-red-500 text-red-400">{t('integrations.dataAccessSettings.accessModes.noAccess.badge')}</Badge>
             </div>
             </div>
             <p className="text-xs text-slate-400">
             <p className="text-xs text-slate-400">
-              Completely block access to this data type
+              {t('integrations.dataAccessSettings.accessModes.noAccess.description')}
             </p>
             </p>
           </Label>
           </Label>
         </div>
         </div>
@@ -227,9 +227,7 @@ export function DataAccessSettings({
         <Alert className="bg-blue-500/10 border-blue-500/50">
         <Alert className="bg-blue-500/10 border-blue-500/50">
           <Info className="h-4 w-4 text-blue-400" />
           <Info className="h-4 w-4 text-blue-400" />
           <AlertDescription className="text-blue-300 text-sm">
           <AlertDescription className="text-blue-300 text-sm">
-            <strong>GDPR Compliance:</strong> Control how data is accessed and stored.
-            "API Only" mode ensures no personal data is cached locally.
-            "Sync & Cache" provides faster access but stores data in our database.
+            <strong>{t('integrations.dataAccessSettings.gdprNotice.title')}</strong> {t('integrations.dataAccessSettings.gdprNotice.description')}
           </AlertDescription>
           </AlertDescription>
         </Alert>
         </Alert>
 
 
@@ -238,12 +236,12 @@ export function DataAccessSettings({
           <Alert className="bg-green-500/10 border-green-500/50">
           <Alert className="bg-green-500/10 border-green-500/50">
             <ShieldCheck className="h-4 w-4 text-green-400" />
             <ShieldCheck className="h-4 w-4 text-green-400" />
             <AlertDescription className="text-green-300 text-sm">
             <AlertDescription className="text-green-300 text-sm">
-              <strong>GDPR Protection Active:</strong> Personal data (
+              <strong>{t('integrations.dataAccessSettings.gdprProtection.title')}</strong> {t('common.personalData')} (
               {[
               {[
-                HIDE_CUSTOMERS_ACCESS_SETTINGS && 'customer data',
-                HIDE_ORDERS_ACCESS_SETTINGS && 'order data'
-              ].filter(Boolean).join(' and ')}
-              ) is accessed directly from your store without local caching, ensuring maximum privacy compliance.
+                HIDE_CUSTOMERS_ACCESS_SETTINGS && t('integrations.dataAccessSettings.gdprProtection.customerData'),
+                HIDE_ORDERS_ACCESS_SETTINGS && t('integrations.dataAccessSettings.gdprProtection.orderData')
+              ].filter(Boolean).join(` ${t('integrations.dataAccessSettings.gdprProtection.and')} `)}
+              ) {t('integrations.dataAccessSettings.gdprProtection.description')}
             </AlertDescription>
             </AlertDescription>
           </Alert>
           </Alert>
         )}
         )}
@@ -253,16 +251,16 @@ export function DataAccessSettings({
           {/* Products Access - Always enabled, store owners cannot change this */}
           {/* Products Access - Always enabled, store owners cannot change this */}
           <div className="p-4 bg-slate-700/50 rounded-lg border border-slate-600">
           <div className="p-4 bg-slate-700/50 rounded-lg border border-slate-600">
             <div className="flex items-center gap-2 mb-2">
             <div className="flex items-center gap-2 mb-2">
-              <h4 className="text-white font-medium">Product Data</h4>
+              <h4 className="text-white font-medium">{t('integrations.dataAccessSettings.productData.title')}</h4>
               <Badge variant="outline" className="text-xs border-blue-500 text-blue-400">
               <Badge variant="outline" className="text-xs border-blue-500 text-blue-400">
-                Public Data
+                {t('integrations.dataAccessSettings.productData.badgePublic')}
               </Badge>
               </Badge>
               <Badge variant="outline" className="text-xs border-slate-500 text-slate-400">
               <Badge variant="outline" className="text-xs border-slate-500 text-slate-400">
-                Required
+                {t('integrations.dataAccessSettings.productData.badgeRequired')}
               </Badge>
               </Badge>
             </div>
             </div>
             <p className="text-sm text-slate-400 mb-3">
             <p className="text-sm text-slate-400 mb-3">
-              Product information (names, prices, descriptions, stock levels). This setting is managed by the system and cannot be changed.
+              {t('integrations.dataAccessSettings.productData.description')}
             </p>
             </p>
             {renderPolicyOptions('products', 'products_access_policy', false, true)}
             {renderPolicyOptions('products', 'products_access_policy', false, true)}
           </div>
           </div>
@@ -271,13 +269,13 @@ export function DataAccessSettings({
           {!HIDE_CUSTOMERS_ACCESS_SETTINGS && (
           {!HIDE_CUSTOMERS_ACCESS_SETTINGS && (
             <div className="p-4 bg-slate-700/50 rounded-lg border border-slate-600">
             <div className="p-4 bg-slate-700/50 rounded-lg border border-slate-600">
               <div className="flex items-center gap-2 mb-2">
               <div className="flex items-center gap-2 mb-2">
-                <h4 className="text-white font-medium">Customer Data</h4>
+                <h4 className="text-white font-medium">{t('integrations.dataAccessSettings.customerData.title')}</h4>
                 <Badge variant="outline" className="text-xs border-orange-500 text-orange-400">
                 <Badge variant="outline" className="text-xs border-orange-500 text-orange-400">
-                  Personal Data (PII)
+                  {t('integrations.dataAccessSettings.customerData.badgePII')}
                 </Badge>
                 </Badge>
               </div>
               </div>
               <p className="text-sm text-slate-400 mb-3">
               <p className="text-sm text-slate-400 mb-3">
-                Customer information (names, emails, addresses, purchase history)
+                {t('integrations.dataAccessSettings.customerData.description')}
               </p>
               </p>
               {renderPolicyOptions('customers', 'customers_access_policy', true)}
               {renderPolicyOptions('customers', 'customers_access_policy', true)}
             </div>
             </div>
@@ -287,13 +285,13 @@ export function DataAccessSettings({
           {!HIDE_ORDERS_ACCESS_SETTINGS && (
           {!HIDE_ORDERS_ACCESS_SETTINGS && (
             <div className="p-4 bg-slate-700/50 rounded-lg border border-slate-600">
             <div className="p-4 bg-slate-700/50 rounded-lg border border-slate-600">
               <div className="flex items-center gap-2 mb-2">
               <div className="flex items-center gap-2 mb-2">
-                <h4 className="text-white font-medium">Order Data</h4>
+                <h4 className="text-white font-medium">{t('integrations.dataAccessSettings.orderData.title')}</h4>
                 <Badge variant="outline" className="text-xs border-orange-500 text-orange-400">
                 <Badge variant="outline" className="text-xs border-orange-500 text-orange-400">
-                  Personal Data (PII)
+                  {t('integrations.dataAccessSettings.orderData.badgePII')}
                 </Badge>
                 </Badge>
               </div>
               </div>
               <p className="text-sm text-slate-400 mb-3">
               <p className="text-sm text-slate-400 mb-3">
-                Order information (order details, amounts, customer info, shipping addresses)
+                {t('integrations.dataAccessSettings.orderData.description')}
               </p>
               </p>
               {renderPolicyOptions('orders', 'orders_access_policy', true)}
               {renderPolicyOptions('orders', 'orders_access_policy', true)}
             </div>
             </div>

+ 221 - 27
shopcall.ai-main/src/components/ManageStoreDataContent.tsx

@@ -20,7 +20,7 @@ import {
   AlertDialogHeader,
   AlertDialogHeader,
   AlertDialogTitle,
   AlertDialogTitle,
 } from "@/components/ui/alert-dialog";
 } from "@/components/ui/alert-dialog";
-import { Loader2, Search, Package, ChevronLeft, ChevronRight } from "lucide-react";
+import { Loader2, Search, Package, ChevronLeft, ChevronRight, Tag } from "lucide-react";
 import { API_URL } from "@/lib/config";
 import { API_URL } from "@/lib/config";
 import { useToast } from "@/hooks/use-toast";
 import { useToast } from "@/hooks/use-toast";
 import { useTranslation } from "react-i18next";
 import { useTranslation } from "react-i18next";
@@ -32,13 +32,24 @@ interface StoreData {
   store_url: string | null;
   store_url: string | null;
 }
 }
 
 
+interface Category {
+  category_id: string;
+  category_name: string;
+  product_count: number;
+  is_excluded: boolean;
+}
+
 interface Product {
 interface Product {
   id: string;
   id: string;
   name: string;
   name: string;
   sku: string;
   sku: string;
   price: string;
   price: string;
   currency: string;
   currency: string;
+  categories: any[];
   enabled_in_context: boolean;
   enabled_in_context: boolean;
+  excluded_by_individual: boolean;
+  excluded_by_category: boolean;
+  exclusion_reason: string | null;
 }
 }
 
 
 type DataItem = Product;
 type DataItem = Product;
@@ -64,7 +75,7 @@ export function ManageStoreDataContent() {
   // Filter and search state
   // Filter and search state
   const [searchQuery, setSearchQuery] = useState("");
   const [searchQuery, setSearchQuery] = useState("");
   const [statusFilter, setStatusFilter] = useState<"all" | "enabled" | "disabled">("all");
   const [statusFilter, setStatusFilter] = useState<"all" | "enabled" | "disabled">("all");
-  const [platformFilter, setPlatformFilter] = useState<string>("all");
+  const [categoryFilter, setCategoryFilter] = useState<string>("all");
 
 
   // Data state
   // Data state
   const [data, setData] = useState<DataItem[]>([]);
   const [data, setData] = useState<DataItem[]>([]);
@@ -73,6 +84,10 @@ export function ManageStoreDataContent() {
   const [enabledCount, setEnabledCount] = useState(0);
   const [enabledCount, setEnabledCount] = useState(0);
   const [disabledCount, setDisabledCount] = useState(0);
   const [disabledCount, setDisabledCount] = useState(0);
 
 
+  // Categories state
+  const [categories, setCategories] = useState<Category[]>([]);
+  const [categoriesLoading, setCategoriesLoading] = useState(false);
+
   // Pagination state
   // Pagination state
   const [page, setPage] = useState(1);
   const [page, setPage] = useState(1);
   const [pageSize, setPageSize] = useState(25);
   const [pageSize, setPageSize] = useState(25);
@@ -148,12 +163,53 @@ export function ManageStoreDataContent() {
     fetchStores();
     fetchStores();
   }, [searchParams, toast]);
   }, [searchParams, toast]);
 
 
+  // Fetch categories when store changes
+  useEffect(() => {
+    if (selectedStore) {
+      fetchCategories();
+    }
+  }, [selectedStore]);
+
   // Fetch data when tab, store, or filters change
   // Fetch data when tab, store, or filters change
   useEffect(() => {
   useEffect(() => {
     if (selectedStore) {
     if (selectedStore) {
       fetchData();
       fetchData();
     }
     }
-  }, [selectedStore, activeTab, page, pageSize, searchQuery, statusFilter]);
+  }, [selectedStore, activeTab, page, pageSize, searchQuery, statusFilter, categoryFilter]);
+
+  const fetchCategories = async () => {
+    if (!selectedStore) return;
+
+    setCategoriesLoading(true);
+    try {
+      const sessionData = localStorage.getItem('session_data');
+      if (!sessionData) {
+        throw new Error('No session data found');
+      }
+
+      const session = JSON.parse(sessionData);
+      const response = await fetch(`${API_URL}/api/store-data/categories?store_id=${selectedStore.id}`, {
+        headers: {
+          'Authorization': `Bearer ${session.session.access_token}`,
+          'Content-Type': 'application/json'
+        }
+      });
+
+      if (!response.ok) {
+        throw new Error('Failed to fetch categories');
+      }
+
+      const result = await response.json();
+      if (result.success) {
+        setCategories(result.categories || []);
+      }
+    } catch (error) {
+      console.error('Error fetching categories:', error);
+      // Don't show toast for categories - it's not critical
+    } finally {
+      setCategoriesLoading(false);
+    }
+  };
 
 
   const fetchData = async () => {
   const fetchData = async () => {
     if (!selectedStore) return;
     if (!selectedStore) return;
@@ -182,6 +238,10 @@ export function ManageStoreDataContent() {
         params.append('enabled', statusFilter === 'enabled' ? 'true' : 'false');
         params.append('enabled', statusFilter === 'enabled' ? 'true' : 'false');
       }
       }
 
 
+      if (categoryFilter !== 'all') {
+        params.append('category', categoryFilter);
+      }
+
       const endpoint = `/api/store-data/${activeTab}?${params.toString()}`;
       const endpoint = `/api/store-data/${activeTab}?${params.toString()}`;
       const response = await fetch(`${API_URL}${endpoint}`, {
       const response = await fetch(`${API_URL}${endpoint}`, {
         headers: {
         headers: {
@@ -280,6 +340,52 @@ export function ManageStoreDataContent() {
     }
     }
   };
   };
 
 
+  const handleToggleCategory = async (categoryId: string, categoryName: string, currentExcluded: boolean) => {
+    if (!selectedStore) return;
+
+    try {
+      const sessionData = localStorage.getItem('session_data');
+      if (!sessionData) {
+        throw new Error('No session data found');
+      }
+
+      const session = JSON.parse(sessionData);
+
+      const response = await fetch(`${API_URL}/api/store-data/categories/${categoryId}/exclude`, {
+        method: 'PUT',
+        headers: {
+          'Authorization': `Bearer ${session.session.access_token}`,
+          'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({
+          store_id: selectedStore.id,
+          category_name: categoryName,
+          exclude: !currentExcluded
+        })
+      });
+
+      if (!response.ok) {
+        throw new Error('Failed to update category');
+      }
+
+      toast({
+        title: "Category Updated",
+        description: `Category "${categoryName}" ${!currentExcluded ? 'excluded' : 'included'} successfully`,
+      });
+
+      // Refresh categories and products
+      fetchCategories();
+      fetchData();
+    } catch (error) {
+      console.error('Error toggling category:', error);
+      toast({
+        title: "Error",
+        description: 'Failed to update category',
+        variant: "destructive"
+      });
+    }
+  };
+
   const handleBulkAction = async (enable: boolean) => {
   const handleBulkAction = async (enable: boolean) => {
     if (!selectedStore || selectedItems.size === 0) return;
     if (!selectedStore || selectedItems.size === 0) return;
 
 
@@ -357,6 +463,8 @@ export function ManageStoreDataContent() {
         description: t('manageStoreData.toast.successEnableAllDescription', { type: activeTab }),
         description: t('manageStoreData.toast.successEnableAllDescription', { type: activeTab }),
       });
       });
 
 
+      // Refresh categories (in case they were excluded) and products
+      fetchCategories();
       fetchData();
       fetchData();
     } catch (error) {
     } catch (error) {
       console.error('Error enabling all:', error);
       console.error('Error enabling all:', error);
@@ -430,28 +538,51 @@ export function ManageStoreDataContent() {
     setSelectAll(newSelected.size === data.length);
     setSelectAll(newSelected.size === data.length);
   };
   };
 
 
-  const renderProductRow = (product: Product) => (
-    <TableRow key={product.id}>
-      <TableCell>
-        <Checkbox
-          checked={selectedItems.has(product.id)}
-          onCheckedChange={(checked) => handleSelectItem(product.id, checked as boolean)}
-        />
-      </TableCell>
-      <TableCell className="text-white font-medium">{product.name}</TableCell>
-      <TableCell className="text-slate-400">{product.sku || 'N/A'}</TableCell>
-      <TableCell className="text-slate-300">
-        {product.price} {product.currency}
-      </TableCell>
-      <TableCell>
-        <Switch
-          checked={product.enabled_in_context}
-          onCheckedChange={() => handleToggleItem(product.id, product.enabled_in_context)}
-          className="data-[state=checked]:bg-cyan-500"
-        />
-      </TableCell>
-    </TableRow>
-  );
+  const renderProductRow = (product: Product) => {
+    const firstCategory = product.categories && product.categories.length > 0
+      ? product.categories[0]
+      : null;
+
+    return (
+      <TableRow key={product.id}>
+        <TableCell>
+          <Checkbox
+            checked={selectedItems.has(product.id)}
+            onCheckedChange={(checked) => handleSelectItem(product.id, checked as boolean)}
+          />
+        </TableCell>
+        <TableCell className="text-white font-medium">{product.name}</TableCell>
+        <TableCell className="text-slate-400">{product.sku || 'N/A'}</TableCell>
+        <TableCell className="text-slate-300">
+          {product.price} {product.currency}
+        </TableCell>
+        <TableCell>
+          {firstCategory && (
+            <Badge variant="outline" className="text-xs">
+              {firstCategory.name || firstCategory.category_name || firstCategory}
+            </Badge>
+          )}
+        </TableCell>
+        <TableCell>
+          <div className="flex items-center gap-2">
+            <Switch
+              checked={product.enabled_in_context}
+              onCheckedChange={() => handleToggleItem(product.id, product.enabled_in_context)}
+              className="data-[state=checked]:bg-cyan-500"
+            />
+            {!product.enabled_in_context && product.exclusion_reason && (
+              <Badge
+                variant={product.exclusion_reason === 'category' ? 'secondary' : 'destructive'}
+                className="text-xs"
+              >
+                {product.exclusion_reason === 'category' ? 'By Category' : 'Individual'}
+              </Badge>
+            )}
+          </div>
+        </TableCell>
+      </TableRow>
+    );
+  };
 
 
   if (loading) {
   if (loading) {
     return (
     return (
@@ -553,8 +684,70 @@ export function ManageStoreDataContent() {
                   <SelectItem value="disabled">Disabled Only</SelectItem>
                   <SelectItem value="disabled">Disabled Only</SelectItem>
                 </SelectContent>
                 </SelectContent>
               </Select>
               </Select>
+
+              {/* Category Filter */}
+              {categories.length > 0 && (
+                <Select value={categoryFilter} onValueChange={(value) => setCategoryFilter(value)}>
+                  <SelectTrigger className="w-[200px] bg-slate-700 border-slate-600 text-white">
+                    <Tag className="w-4 h-4 mr-2" />
+                    <SelectValue placeholder="All Categories" />
+                  </SelectTrigger>
+                  <SelectContent className="bg-slate-700 border-slate-600">
+                    <SelectItem value="all">All Categories</SelectItem>
+                    {categories.map((cat) => (
+                      <SelectItem key={cat.category_id} value={cat.category_id}>
+                        <div className="flex items-center justify-between w-full gap-2">
+                          <span className={cat.is_excluded ? 'line-through text-slate-500' : ''}>
+                            {cat.category_name}
+                          </span>
+                          <Badge variant="secondary" className="text-xs">
+                            {cat.product_count}
+                          </Badge>
+                        </div>
+                      </SelectItem>
+                    ))}
+                  </SelectContent>
+                </Select>
+              )}
             </div>
             </div>
 
 
+            {/* Category Management Section */}
+            {categories.length > 0 && (
+              <div className="mb-6 p-4 bg-slate-700/30 rounded-lg border border-slate-600">
+                <div className="flex items-center justify-between mb-3">
+                  <h3 className="text-white font-medium flex items-center gap-2">
+                    <Tag className="w-4 h-4" />
+                    Category Management
+                  </h3>
+                </div>
+                <div className="flex flex-wrap gap-2">
+                  {categories.map((cat) => (
+                    <div
+                      key={cat.category_id}
+                      className={`flex items-center gap-2 px-3 py-1.5 rounded-md border ${
+                        cat.is_excluded
+                          ? 'bg-red-900/20 border-red-800 text-red-300'
+                          : 'bg-slate-700 border-slate-600 text-white'
+                      }`}
+                    >
+                      <span className="text-sm">{cat.category_name}</span>
+                      <Badge variant="secondary" className="text-xs">
+                        {cat.product_count}
+                      </Badge>
+                      <Button
+                        size="sm"
+                        variant="ghost"
+                        className="h-6 px-2 text-xs"
+                        onClick={() => handleToggleCategory(cat.category_id, cat.category_name, cat.is_excluded)}
+                      >
+                        {cat.is_excluded ? 'Include' : 'Exclude'}
+                      </Button>
+                    </div>
+                  ))}
+                </div>
+              </div>
+            )}
+
             {/* Bulk Actions */}
             {/* Bulk Actions */}
             {selectedItems.size > 0 && (
             {selectedItems.size > 0 && (
               <div className="flex gap-2 mb-4 p-3 bg-slate-700/50 rounded-lg">
               <div className="flex gap-2 mb-4 p-3 bg-slate-700/50 rounded-lg">
@@ -585,7 +778,7 @@ export function ManageStoreDataContent() {
                 onClick={() => setConfirmDialog({
                 onClick={() => setConfirmDialog({
                   open: true,
                   open: true,
                   title: `Enable All ${activeTab}`,
                   title: `Enable All ${activeTab}`,
-                  description: `Are you sure you want to enable all ${activeTab} for AI context?`,
+                  description: `Are you sure you want to enable all ${activeTab} for AI context? This will also clear all category exclusions.`,
                   action: handleEnableAll
                   action: handleEnableAll
                 })}
                 })}
                 className="border-cyan-500 text-cyan-500 hover:bg-cyan-500 hover:text-white"
                 className="border-cyan-500 text-cyan-500 hover:bg-cyan-500 hover:text-white"
@@ -630,7 +823,8 @@ export function ManageStoreDataContent() {
                         <TableHead className="text-slate-300">Name</TableHead>
                         <TableHead className="text-slate-300">Name</TableHead>
                         <TableHead className="text-slate-300">SKU</TableHead>
                         <TableHead className="text-slate-300">SKU</TableHead>
                         <TableHead className="text-slate-300">Price</TableHead>
                         <TableHead className="text-slate-300">Price</TableHead>
-                        <TableHead className="text-slate-300">Enabled</TableHead>
+                        <TableHead className="text-slate-300">Category</TableHead>
+                        <TableHead className="text-slate-300">Status</TableHead>
                       </TableRow>
                       </TableRow>
                     </TableHeader>
                     </TableHeader>
                     <TableBody className="bg-slate-800">
                     <TableBody className="bg-slate-800">

+ 2 - 1
shopcall.ai-main/src/i18n/locales/en.json

@@ -221,7 +221,8 @@
     "view": "View",
     "view": "View",
     "details": "Details",
     "details": "Details",
     "refresh": "Refresh",
     "refresh": "Refresh",
-    "tryAgain": "Try Again"
+    "tryAgain": "Try Again",
+    "personalData": "Personal data"
   },
   },
   "signup": {
   "signup": {
     "title": "Sign Up",
     "title": "Sign Up",

+ 2 - 1
shopcall.ai-main/src/i18n/locales/hu.json

@@ -211,7 +211,8 @@
     "view": "Megtekintés",
     "view": "Megtekintés",
     "details": "Részletek",
     "details": "Részletek",
     "refresh": "Frissítés",
     "refresh": "Frissítés",
-    "tryAgain": "Próbálja újra"
+    "tryAgain": "Próbálja újra",
+    "personalData": "Személyes adatok"
   },
   },
   "signup": {
   "signup": {
     "title": "Regisztráció",
     "title": "Regisztráció",