Browse Source

fix(webshops): add i18n translations and fix modal state reset

- Add translations for Shopify, WooCommerce, and ShopRenter connection modals
- Fix modal state persistence: reset selectedPlatform when dialog closes
- All hardcoded strings in connect components now use t() translations

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fszontagh 4 months ago
parent
commit
d5fc57e842

+ 7 - 0
shopcall.ai-main/src/components/IntegrationsContent.tsx

@@ -86,6 +86,13 @@ export function IntegrationsContent() {
   const [selectedStore, setSelectedStore] = useState<ConnectedStore | null>(null);
   const { toast } = useToast();
 
+  // Reset selected platform when dialog closes (handles all close methods: X button, outside click, etc.)
+  useEffect(() => {
+    if (!showConnectDialog) {
+      setSelectedPlatform(null);
+    }
+  }, [showConnectDialog]);
+
   const fetchStores = async () => {
     try {
       const sessionData = localStorage.getItem('session_data');

+ 22 - 20
shopcall.ai-main/src/components/ShopRenterConnect.tsx

@@ -1,21 +1,24 @@
 import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
 import { Button } from "@/components/ui/button";
 import { Store, ExternalLink, Info, CheckCircle2 } from "lucide-react";
+import { useTranslation } from "react-i18next";
 
 interface ShopRenterConnectProps {
   onClose?: () => void;
 }
 
 export function ShopRenterConnect({ onClose }: ShopRenterConnectProps) {
+  const { t } = useTranslation();
+
   return (
     <Card className="bg-slate-800 border-slate-700 max-w-2xl mx-auto shadow-none border-0">
       <CardHeader>
         <div className="flex items-center gap-3">
           <Store className="w-8 h-8 text-cyan-500" />
           <div>
-            <CardTitle className="text-white text-2xl">Connect ShopRenter Store</CardTitle>
+            <CardTitle className="text-white text-2xl">{t('integrations.shoprenterConnect.title')}</CardTitle>
             <CardDescription className="text-slate-400">
-              Link your ShopRenter shop to start managing AI-powered customer calls
+              {t('integrations.shoprenterConnect.description')}
             </CardDescription>
           </div>
         </div>
@@ -26,10 +29,9 @@ export function ShopRenterConnect({ onClose }: ShopRenterConnectProps) {
           <div className="flex items-start gap-3">
             <Info className="w-5 h-5 text-cyan-500 mt-0.5 flex-shrink-0" />
             <div className="space-y-2">
-              <h4 className="text-white font-medium">Install from ShopRenter App Store</h4>
+              <h4 className="text-white font-medium">{t('integrations.shoprenterConnect.installInfo')}</h4>
               <p className="text-sm text-slate-300">
-                ShopRenter stores can only be connected through the ShopRenter admin panel.
-                Please install our application from the ShopRenter App Store to connect your store.
+                {t('integrations.shoprenterConnect.installDescription')}
               </p>
             </div>
           </div>
@@ -39,63 +41,63 @@ export function ShopRenterConnect({ onClose }: ShopRenterConnectProps) {
         <div className="bg-slate-700/50 rounded-lg p-4 space-y-3">
           <h4 className="text-white font-medium flex items-center gap-2">
             <ExternalLink className="w-4 h-4 text-cyan-500" />
-            How to connect your store
+            {t('integrations.shoprenterConnect.howToConnect')}
           </h4>
           <ul className="space-y-2 text-sm text-slate-300">
             <li className="flex items-start gap-2">
               <span className="text-cyan-500 mt-0.5">1.</span>
-              <span>Log in to your ShopRenter admin panel</span>
+              <span>{t('integrations.shoprenterConnect.step1')}</span>
             </li>
             <li className="flex items-start gap-2">
               <span className="text-cyan-500 mt-0.5">2.</span>
-              <span>Navigate to the App Store section</span>
+              <span>{t('integrations.shoprenterConnect.step2')}</span>
             </li>
             <li className="flex items-start gap-2">
               <span className="text-cyan-500 mt-0.5">3.</span>
-              <span>Search for "ShopCall.ai" and click Install</span>
+              <span>{t('integrations.shoprenterConnect.step3')}</span>
             </li>
             <li className="flex items-start gap-2">
               <span className="text-cyan-500 mt-0.5">4.</span>
-              <span>Grant the necessary permissions for AI caller integration</span>
+              <span>{t('integrations.shoprenterConnect.step4')}</span>
             </li>
             <li className="flex items-start gap-2">
               <span className="text-cyan-500 mt-0.5">5.</span>
-              <span>You'll be redirected back to ShopCall.ai to complete the setup</span>
+              <span>{t('integrations.shoprenterConnect.step5')}</span>
             </li>
           </ul>
         </div>
 
         {/* Required Permissions */}
         <div className="bg-slate-700/50 rounded-lg p-4 space-y-3">
-          <h4 className="text-white font-medium">Required Permissions</h4>
+          <h4 className="text-white font-medium">{t('integrations.shoprenterConnect.permissionsTitle')}</h4>
           <div className="grid grid-cols-2 gap-2 text-sm text-slate-300">
             <div className="flex items-center gap-2">
               <CheckCircle2 className="w-4 h-4 text-green-500" />
-              <span>Read Products</span>
+              <span>{t('integrations.shoprenterConnect.readProducts')}</span>
             </div>
             <div className="flex items-center gap-2">
               <CheckCircle2 className="w-4 h-4 text-green-500" />
-              <span>Write Products</span>
+              <span>{t('integrations.shoprenterConnect.writeProducts')}</span>
             </div>
             <div className="flex items-center gap-2">
               <CheckCircle2 className="w-4 h-4 text-green-500" />
-              <span>Read Orders</span>
+              <span>{t('integrations.shoprenterConnect.readOrders')}</span>
             </div>
             <div className="flex items-center gap-2">
               <CheckCircle2 className="w-4 h-4 text-green-500" />
-              <span>Write Orders</span>
+              <span>{t('integrations.shoprenterConnect.writeOrders')}</span>
             </div>
             <div className="flex items-center gap-2">
               <CheckCircle2 className="w-4 h-4 text-green-500" />
-              <span>Read Customers</span>
+              <span>{t('integrations.shoprenterConnect.readCustomers')}</span>
             </div>
             <div className="flex items-center gap-2">
               <CheckCircle2 className="w-4 h-4 text-green-500" />
-              <span>Write Customers</span>
+              <span>{t('integrations.shoprenterConnect.writeCustomers')}</span>
             </div>
           </div>
           <p className="text-xs text-slate-400">
-            These permissions allow our AI assistant to access your store data and provide accurate customer support.
+            {t('integrations.shoprenterConnect.permissionsNote')}
           </p>
         </div>
 
@@ -116,7 +118,7 @@ export function ShopRenterConnect({ onClose }: ShopRenterConnectProps) {
             onClick={onClose}
             className="w-full border-slate-600 text-slate-300 hover:bg-slate-700"
           >
-            Close
+            {t('integrations.shoprenterConnect.close')}
           </Button>
         )}
       </CardContent>

+ 33 - 36
shopcall.ai-main/src/components/ShopifyConnect.tsx

@@ -7,12 +7,14 @@ import { Alert, AlertDescription } from "@/components/ui/alert";
 import { Loader2, Store, ExternalLink, CheckCircle2, AlertCircle, Shield } from "lucide-react";
 import { API_URL } from "@/lib/config";
 import { PhoneNumberSelector } from "./PhoneNumberSelector";
+import { useTranslation } from "react-i18next";
 
 interface ShopifyConnectProps {
   onClose?: () => void;
 }
 
 export function ShopifyConnect({ onClose }: ShopifyConnectProps) {
+  const { t } = useTranslation();
   const [shopDomain, setShopDomain] = useState("");
   const [phoneNumberId, setPhoneNumberId] = useState("");
   const [isConnecting, setIsConnecting] = useState(false);
@@ -27,14 +29,14 @@ export function ShopifyConnect({ onClose }: ShopifyConnectProps) {
 
     // Validate shop domain
     if (!shopDomain.trim()) {
-      setError("Please enter your Shopify store domain");
+      setError(t('integrations.shopifyConnect.errors.domainRequired'));
       return;
     }
 
     // Validate phone number
     if (!phoneNumberId) {
-      setPhoneNumberError("Please select a phone number for this store");
-      setError("Please select a phone number before connecting");
+      setPhoneNumberError(t('integrations.shopifyConnect.errors.phoneRequired'));
+      setError(t('integrations.shopifyConnect.errors.phoneRequiredError'));
       return;
     }
 
@@ -57,7 +59,7 @@ export function ShopifyConnect({ onClose }: ShopifyConnectProps) {
     // Validate format
     const shopPattern = /^[a-zA-Z0-9][a-zA-Z0-9-]*\.myshopify\.com$/;
     if (!shopPattern.test(normalizedDomain)) {
-      setError("Please enter a valid Shopify domain (e.g., your-store.myshopify.com)");
+      setError(t('integrations.shopifyConnect.errors.invalidDomain'));
       return;
     }
 
@@ -67,7 +69,7 @@ export function ShopifyConnect({ onClose }: ShopifyConnectProps) {
       // Get auth token
       const sessionData = localStorage.getItem('session_data');
       if (!sessionData) {
-        setError("Authentication required. Please log in again.");
+        setError(t('integrations.shopifyConnect.errors.authRequired'));
         setIsConnecting(false);
         return;
       }
@@ -105,7 +107,7 @@ export function ShopifyConnect({ onClose }: ShopifyConnectProps) {
 
     } catch (err) {
       console.error("Connection error:", err);
-      setError(err instanceof Error ? err.message : "Failed to connect to Shopify. Please try again.");
+      setError(err instanceof Error ? err.message : t('integrations.shopifyConnect.errors.connectionFailed'));
       setIsConnecting(false);
     }
   };
@@ -122,9 +124,9 @@ export function ShopifyConnect({ onClose }: ShopifyConnectProps) {
         <div className="flex items-center gap-3">
           <Store className="w-8 h-8 text-green-500" />
           <div>
-            <CardTitle className="text-white text-2xl">Connect Shopify Store</CardTitle>
+            <CardTitle className="text-white text-2xl">{t('integrations.shopifyConnect.title')}</CardTitle>
             <CardDescription className="text-slate-400">
-              Link your Shopify shop to enable AI-powered customer support
+              {t('integrations.shopifyConnect.description')}
             </CardDescription>
           </div>
         </div>
@@ -135,7 +137,7 @@ export function ShopifyConnect({ onClose }: ShopifyConnectProps) {
           <Alert className="bg-green-500/10 border-green-500/50">
             <CheckCircle2 className="h-4 w-4 text-green-500" />
             <AlertDescription className="text-green-500">
-              Redirecting to Shopify for authorization...
+              {t('integrations.shopifyConnect.redirecting')}
             </AlertDescription>
           </Alert>
         )}
@@ -154,12 +156,12 @@ export function ShopifyConnect({ onClose }: ShopifyConnectProps) {
         <div className="space-y-4">
           <div className="space-y-2">
             <Label htmlFor="shopDomain" className="text-white">
-              Shopify Store Domain
+              {t('integrations.shopifyConnect.domainLabel')}
             </Label>
             <Input
               id="shopDomain"
               type="text"
-              placeholder="your-store.myshopify.com"
+              placeholder={t('integrations.shopifyConnect.domainPlaceholder')}
               value={shopDomain}
               onChange={(e) => setShopDomain(e.target.value)}
               onKeyPress={handleKeyPress}
@@ -167,7 +169,7 @@ export function ShopifyConnect({ onClose }: ShopifyConnectProps) {
               disabled={isConnecting}
             />
             <p className="text-sm text-slate-400">
-              Enter your Shopify store domain (e.g., your-store.myshopify.com)
+              {t('integrations.shopifyConnect.domainHint')}
             </p>
           </div>
 
@@ -186,12 +188,12 @@ export function ShopifyConnect({ onClose }: ShopifyConnectProps) {
             {isConnecting ? (
               <>
                 <Loader2 className="w-4 h-4 mr-2 animate-spin" />
-                Connecting...
+                {t('integrations.shopifyConnect.connecting')}
               </>
             ) : (
               <>
                 <Store className="w-4 h-4 mr-2" />
-                Connect to Shopify
+                {t('integrations.shopifyConnect.connectButton')}
               </>
             )}
           </Button>
@@ -201,24 +203,24 @@ export function ShopifyConnect({ onClose }: ShopifyConnectProps) {
         <div className="bg-slate-700/50 rounded-lg p-4 space-y-3">
           <h4 className="text-white font-medium flex items-center gap-2">
             <ExternalLink className="w-4 h-4 text-green-500" />
-            What happens next?
+            {t('integrations.shopifyConnect.whatHappensNext')}
           </h4>
           <ul className="space-y-2 text-sm text-slate-300">
             <li className="flex items-start gap-2">
               <span className="text-green-500 mt-0.5">1.</span>
-              <span>You'll be redirected to your Shopify admin panel</span>
+              <span>{t('integrations.shopifyConnect.step1')}</span>
             </li>
             <li className="flex items-start gap-2">
               <span className="text-green-500 mt-0.5">2.</span>
-              <span>Review the requested permissions and approve the app</span>
+              <span>{t('integrations.shopifyConnect.step2')}</span>
             </li>
             <li className="flex items-start gap-2">
               <span className="text-green-500 mt-0.5">3.</span>
-              <span>Shopify will securely authorize ShopCall.ai</span>
+              <span>{t('integrations.shopifyConnect.step3')}</span>
             </li>
             <li className="flex items-start gap-2">
               <span className="text-green-500 mt-0.5">4.</span>
-              <span>Return to ShopCall.ai to complete your setup</span>
+              <span>{t('integrations.shopifyConnect.step4')}</span>
             </li>
           </ul>
         </div>
@@ -228,11 +230,9 @@ export function ShopifyConnect({ onClose }: ShopifyConnectProps) {
           <div className="flex items-start gap-2">
             <Shield className="w-5 h-5 text-blue-500 mt-0.5 flex-shrink-0" />
             <div className="space-y-1">
-              <h4 className="text-white font-medium">Secure & GDPR Compliant</h4>
+              <h4 className="text-white font-medium">{t('integrations.shopifyConnect.securityTitle')}</h4>
               <p className="text-sm text-slate-300">
-                ShopCall.ai uses Shopify OAuth 2.0 with HMAC verification for maximum security.
-                Your credentials are encrypted and stored securely. We comply with all GDPR
-                requirements including customer data requests and deletion.
+                {t('integrations.shopifyConnect.securityDescription')}
               </p>
             </div>
           </div>
@@ -240,32 +240,31 @@ export function ShopifyConnect({ onClose }: ShopifyConnectProps) {
 
         {/* Required Permissions */}
         <div className="bg-slate-700/50 rounded-lg p-4 space-y-3">
-          <h4 className="text-white font-medium">Required Permissions (Read-only)</h4>
+          <h4 className="text-white font-medium">{t('integrations.shopifyConnect.permissionsTitle')}</h4>
           <div className="grid grid-cols-2 gap-2 text-sm text-slate-300">
             <div className="flex items-center gap-2">
               <CheckCircle2 className="w-4 h-4 text-green-500" />
-              <span>Read Products</span>
+              <span>{t('integrations.shopifyConnect.readProducts')}</span>
             </div>
             <div className="flex items-center gap-2">
               <CheckCircle2 className="w-4 h-4 text-green-500" />
-              <span>Read Orders</span>
+              <span>{t('integrations.shopifyConnect.readOrders')}</span>
             </div>
             <div className="flex items-center gap-2">
               <CheckCircle2 className="w-4 h-4 text-green-500" />
-              <span>Read Customers</span>
+              <span>{t('integrations.shopifyConnect.readCustomers')}</span>
             </div>
             <div className="flex items-center gap-2">
               <CheckCircle2 className="w-4 h-4 text-green-500" />
-              <span>Read Inventory</span>
+              <span>{t('integrations.shopifyConnect.readInventory')}</span>
             </div>
             <div className="flex items-center gap-2">
               <CheckCircle2 className="w-4 h-4 text-green-500" />
-              <span>Read Price Rules</span>
+              <span>{t('integrations.shopifyConnect.readPriceRules')}</span>
             </div>
           </div>
           <p className="text-xs text-slate-400">
-            These read-only permissions allow our AI to access your store data and provide accurate,
-            personalized customer support without modifying anything.
+            {t('integrations.shopifyConnect.permissionsNote')}
           </p>
         </div>
 
@@ -274,11 +273,9 @@ export function ShopifyConnect({ onClose }: ShopifyConnectProps) {
           <div className="flex items-start gap-2">
             <CheckCircle2 className="w-5 h-5 text-green-500 mt-0.5 flex-shrink-0" />
             <div className="space-y-1">
-              <h4 className="text-white font-medium">GDPR & Shopify App Store Ready</h4>
+              <h4 className="text-white font-medium">{t('integrations.shopifyConnect.gdprTitle')}</h4>
               <p className="text-sm text-slate-300">
-                Our integration includes mandatory GDPR webhooks for customer data requests,
-                customer data deletion, and shop data deletion. Fully compliant with Shopify
-                App Store requirements.
+                {t('integrations.shopifyConnect.gdprDescription')}
               </p>
             </div>
           </div>
@@ -292,7 +289,7 @@ export function ShopifyConnect({ onClose }: ShopifyConnectProps) {
             className="w-full border-slate-600 text-slate-300 hover:bg-slate-700"
             disabled={isConnecting}
           >
-            Cancel
+            {t('integrations.shopifyConnect.cancel')}
           </Button>
         )}
       </CardContent>

+ 60 - 61
shopcall.ai-main/src/components/WooCommerceConnect.tsx

@@ -7,6 +7,7 @@ import { Alert, AlertDescription } from "@/components/ui/alert";
 import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
 import { Loader2, ShoppingBag, ExternalLink, CheckCircle2, AlertCircle, Key, Phone } from "lucide-react";
 import { API_URL } from "@/lib/config";
+import { useTranslation } from "react-i18next";
 
 interface PhoneNumber {
   id: string;
@@ -29,6 +30,7 @@ interface WooCommerceConnectProps {
 }
 
 export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
+  const { t } = useTranslation();
   const [storeUrl, setStoreUrl] = useState("");
   const [consumerKey, setConsumerKey] = useState("");
   const [consumerSecret, setConsumerSecret] = useState("");
@@ -241,23 +243,23 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
 
     // Validate inputs
     if (!storeUrl.trim()) {
-      setError("Please enter your WooCommerce store URL");
+      setError(t('integrations.woocommerceConnect.errors.urlRequired'));
       return;
     }
 
     if (!consumerKey.trim()) {
-      setError("Please enter your Consumer Key");
+      setError(t('integrations.woocommerceConnect.errors.consumerKeyRequired'));
       return;
     }
 
     if (!consumerSecret.trim()) {
-      setError("Please enter your Consumer Secret");
+      setError(t('integrations.woocommerceConnect.errors.consumerSecretRequired'));
       return;
     }
 
     if (!selectedPhoneNumber) {
-      setPhoneNumberError("Please select a phone number for this store");
-      setError("Please select a country, city, and phone number before connecting");
+      setPhoneNumberError(t('integrations.woocommerceConnect.errors.phoneRequired'));
+      setError(t('integrations.woocommerceConnect.errors.phoneRequiredError'));
       return;
     }
 
@@ -276,11 +278,11 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
     try {
       const url = new URL(normalizedUrl);
       if (url.protocol !== 'https:') {
-        setError("Store URL must use HTTPS for security");
+        setError(t('integrations.woocommerceConnect.errors.httpsRequired'));
         return;
       }
     } catch (e) {
-      setError("Please enter a valid store URL (e.g., https://yourstore.com)");
+      setError(t('integrations.woocommerceConnect.errors.invalidUrl'));
       return;
     }
 
@@ -290,7 +292,7 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
       // Get auth token
       const sessionData = localStorage.getItem('session_data');
       if (!sessionData) {
-        setError("Authentication required. Please log in again.");
+        setError(t('integrations.woocommerceConnect.errors.authRequired'));
         setIsConnecting(false);
         return;
       }
@@ -324,7 +326,7 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
 
       if (data.success) {
         setSuccess(true);
-        setSuccessMessage(`Store "${data.storeName}" connected successfully!`);
+        setSuccessMessage(t('integrations.woocommerceConnect.storeConnected', { storeName: data.storeName }));
 
         // Redirect to webshops page after a short delay
         setTimeout(() => {
@@ -339,7 +341,7 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
 
     } catch (err) {
       console.error("Connection error:", err);
-      setError(err instanceof Error ? err.message : "Failed to connect to WooCommerce. Please try again.");
+      setError(err instanceof Error ? err.message : t('integrations.woocommerceConnect.errors.connectionFailed'));
       setIsConnecting(false);
     }
   };
@@ -350,9 +352,9 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
         <div className="flex items-center gap-3">
           <ShoppingBag className="w-8 h-8 text-purple-500" />
           <div>
-            <CardTitle className="text-white text-2xl">Connect WooCommerce Store</CardTitle>
+            <CardTitle className="text-white text-2xl">{t('integrations.woocommerceConnect.title')}</CardTitle>
             <CardDescription className="text-slate-400">
-              Link your WooCommerce shop to enable AI-powered customer support
+              {t('integrations.woocommerceConnect.description')}
             </CardDescription>
           </div>
         </div>
@@ -383,30 +385,30 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
           <div className="space-y-4">
             <div className="space-y-2">
               <Label htmlFor="manualStoreUrl" className="text-white">
-                WooCommerce Store URL
+                {t('integrations.woocommerceConnect.storeUrlLabel')}
               </Label>
               <Input
                 id="manualStoreUrl"
                 type="text"
-                placeholder="https://yourstore.com"
+                placeholder={t('integrations.woocommerceConnect.storeUrlPlaceholder')}
                 value={storeUrl}
                 onChange={(e) => setStoreUrl(e.target.value)}
                 className="bg-slate-700 border-slate-600 text-white placeholder:text-slate-400"
                 disabled={isConnecting}
               />
               <p className="text-sm text-slate-400">
-                Enter your WooCommerce store URL (must use HTTPS)
+                {t('integrations.woocommerceConnect.storeUrlHint')}
               </p>
             </div>
 
             <div className="space-y-2">
               <Label htmlFor="consumerKey" className="text-white">
-                Consumer Key
+                {t('integrations.woocommerceConnect.consumerKeyLabel')}
               </Label>
               <Input
                 id="consumerKey"
                 type="text"
-                placeholder="ck_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+                placeholder={t('integrations.woocommerceConnect.consumerKeyPlaceholder')}
                 value={consumerKey}
                 onChange={(e) => setConsumerKey(e.target.value)}
                 className="bg-slate-700 border-slate-600 text-white placeholder:text-slate-400 font-mono text-sm"
@@ -416,12 +418,12 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
 
             <div className="space-y-2">
               <Label htmlFor="consumerSecret" className="text-white">
-                Consumer Secret
+                {t('integrations.woocommerceConnect.consumerSecretLabel')}
               </Label>
               <Input
                 id="consumerSecret"
                 type="password"
-                placeholder="cs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+                placeholder={t('integrations.woocommerceConnect.consumerSecretPlaceholder')}
                 value={consumerSecret}
                 onChange={(e) => setConsumerSecret(e.target.value)}
                 onKeyPress={(e) => e.key === "Enter" && !isConnecting && handleManualConnect()}
@@ -434,23 +436,23 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
             <div className="space-y-4 border border-slate-600 rounded-lg p-4 bg-slate-700/30">
               <h4 className="text-white font-medium flex items-center gap-2">
                 <Phone className="w-4 h-4 text-cyan-500" />
-                Select Phone Number
+                {t('integrations.woocommerceConnect.selectPhoneTitle')}
               </h4>
 
               {/* Country Selector */}
               <div className="space-y-2">
                 <Label className="text-slate-300">
-                  Country <span className="text-red-400">*</span>
+                  {t('integrations.woocommerceConnect.countryLabel')} <span className="text-red-400">{t('integrations.woocommerceConnect.countryRequired')}</span>
                 </Label>
                 {loadingCountries ? (
                   <div className="flex items-center justify-center py-3">
                     <Loader2 className="w-5 h-5 text-cyan-500 animate-spin" />
-                    <span className="ml-2 text-sm text-slate-400">Loading countries...</span>
+                    <span className="ml-2 text-sm text-slate-400">{t('integrations.woocommerceConnect.loadingCountries')}</span>
                   </div>
                 ) : countries.length > 0 ? (
                   <Select value={selectedCountry} onValueChange={setSelectedCountry} disabled={isConnecting}>
                     <SelectTrigger className={`bg-slate-700 border-slate-600 text-white ${!selectedCountry ? 'border-red-500/50' : ''}`}>
-                      <SelectValue placeholder="Select a country" />
+                      <SelectValue placeholder={t('integrations.woocommerceConnect.selectCountryPlaceholder')} />
                     </SelectTrigger>
                     <SelectContent className="bg-slate-700 border-slate-600">
                       {countries.map((country) => (
@@ -463,7 +465,7 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
                 ) : (
                   <div className="bg-red-500/10 border border-red-500/30 rounded-md p-3">
                     <p className="text-sm text-red-400">
-                      No countries with available phone numbers.
+                      {t('integrations.woocommerceConnect.noCountriesError')}
                     </p>
                   </div>
                 )}
@@ -473,17 +475,17 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
               {selectedCountry && (
                 <div className="space-y-2">
                   <Label className="text-slate-300">
-                    City <span className="text-red-400">*</span>
+                    {t('integrations.woocommerceConnect.cityLabel')} <span className="text-red-400">{t('integrations.woocommerceConnect.countryRequired')}</span>
                   </Label>
                   {loadingCities ? (
                     <div className="flex items-center justify-center py-3">
                       <Loader2 className="w-5 h-5 text-cyan-500 animate-spin" />
-                      <span className="ml-2 text-sm text-slate-400">Loading cities...</span>
+                      <span className="ml-2 text-sm text-slate-400">{t('integrations.woocommerceConnect.loadingCities')}</span>
                     </div>
                   ) : cities.length > 0 ? (
                     <Select value={selectedCity} onValueChange={setSelectedCity} disabled={isConnecting}>
                       <SelectTrigger className={`bg-slate-700 border-slate-600 text-white ${!selectedCity ? 'border-red-500/50' : ''}`}>
-                        <SelectValue placeholder="Select a city" />
+                        <SelectValue placeholder={t('integrations.woocommerceConnect.selectCityPlaceholder')} />
                       </SelectTrigger>
                       <SelectContent className="bg-slate-700 border-slate-600">
                         {cities.map((city) => (
@@ -496,7 +498,7 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
                   ) : (
                     <div className="bg-yellow-500/10 border border-yellow-500/30 rounded-md p-3">
                       <p className="text-sm text-yellow-400">
-                        No cities with available phone numbers in this country.
+                        {t('integrations.woocommerceConnect.noCitiesError')}
                       </p>
                     </div>
                   )}
@@ -507,18 +509,18 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
               {selectedCity && (
                 <div className="space-y-2">
                   <Label className="text-slate-300">
-                    Phone Number <span className="text-red-400">*</span>
+                    {t('integrations.woocommerceConnect.phoneNumberLabel')} <span className="text-red-400">{t('integrations.woocommerceConnect.countryRequired')}</span>
                   </Label>
                   {loadingPhoneNumbers ? (
                     <div className="flex items-center justify-center py-3">
                       <Loader2 className="w-5 h-5 text-cyan-500 animate-spin" />
-                      <span className="ml-2 text-sm text-slate-400">Loading phone numbers...</span>
+                      <span className="ml-2 text-sm text-slate-400">{t('integrations.woocommerceConnect.loadingPhoneNumbers')}</span>
                     </div>
                   ) : phoneNumbers.length > 0 ? (
                     <>
                       <Select value={selectedPhoneNumber} onValueChange={setSelectedPhoneNumber} disabled={isConnecting}>
                         <SelectTrigger className={`bg-slate-700 border-slate-600 text-white ${!selectedPhoneNumber ? 'border-red-500/50' : ''} ${phoneNumberError ? 'border-red-500' : ''}`}>
-                          <SelectValue placeholder="Select a phone number" />
+                          <SelectValue placeholder={t('integrations.woocommerceConnect.selectPhonePlaceholder')} />
                         </SelectTrigger>
                         <SelectContent className="bg-slate-700 border-slate-600">
                           {phoneNumbers.map((phone) => (
@@ -526,7 +528,7 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
                               <div className="flex items-center justify-between w-full">
                                 <span>{phone.phone_number}</span>
                                 <span className="ml-2 text-sm text-slate-400">
-                                  {phone.price > 0 ? `$${phone.price}/mo` : 'Free'}
+                                  {phone.price > 0 ? t('integrations.woocommerceConnect.perMonth', { price: phone.price }) : t('integrations.woocommerceConnect.free')}
                                 </span>
                               </div>
                             </SelectItem>
@@ -540,7 +542,7 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
                   ) : (
                     <div className="bg-red-500/10 border border-red-500/30 rounded-md p-3">
                       <p className="text-sm text-red-400">
-                        No phone numbers available in this city.
+                        {t('integrations.woocommerceConnect.noPhoneNumbersError')}
                       </p>
                     </div>
                   )}
@@ -550,7 +552,7 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
               {/* Show message when not all selections made */}
               {!selectedPhoneNumber && countries.length > 0 && (
                 <p className="text-xs text-slate-400">
-                  Please select a country, city, and phone number to continue.
+                  {t('integrations.woocommerceConnect.selectionRequired')}
                 </p>
               )}
             </div>
@@ -564,12 +566,12 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
             {isConnecting ? (
               <>
                 <Loader2 className="w-4 h-4 mr-2 animate-spin" />
-                Connecting...
+                {t('integrations.woocommerceConnect.connecting')}
               </>
             ) : (
               <>
                 <Key className="w-4 h-4 mr-2" />
-                Connect WooCommerce Store
+                {t('integrations.woocommerceConnect.connectButton')}
               </>
             )}
           </Button>
@@ -577,44 +579,44 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
           <div className="bg-blue-500/10 border border-blue-500/50 rounded-lg p-4 space-y-3">
             <h4 className="text-white font-medium flex items-center gap-2">
               <ExternalLink className="w-4 h-4 text-blue-500" />
-              How to generate WooCommerce API keys
+              {t('integrations.woocommerceConnect.howToGenerateKeys')}
             </h4>
             <ol className="space-y-2 text-sm text-slate-300">
               <li className="flex items-start gap-2">
                 <span className="text-blue-500 font-semibold min-w-[20px]">1.</span>
-                <span>Log into your WooCommerce admin panel</span>
+                <span>{t('integrations.woocommerceConnect.keyStep1')}</span>
               </li>
               <li className="flex items-start gap-2">
                 <span className="text-blue-500 font-semibold min-w-[20px]">2.</span>
-                <span>Navigate to <strong>WooCommerce → Settings → Advanced → REST API</strong></span>
+                <span dangerouslySetInnerHTML={{ __html: t('integrations.woocommerceConnect.keyStep2') }} />
               </li>
               <li className="flex items-start gap-2">
                 <span className="text-blue-500 font-semibold min-w-[20px]">3.</span>
-                <span>Click <strong>"Add key"</strong> button</span>
+                <span dangerouslySetInnerHTML={{ __html: t('integrations.woocommerceConnect.keyStep3') }} />
               </li>
               <li className="flex items-start gap-2">
                 <span className="text-blue-500 font-semibold min-w-[20px]">4.</span>
-                <span>Fill in the form:
+                <span>{t('integrations.woocommerceConnect.keyStep4')}
                   <ul className="ml-4 mt-1 space-y-1">
-                    <li>• Description: <code className="text-purple-400">ShopCall.ai</code></li>
-                    <li>• User: <em>(select your admin user)</em></li>
-                    <li>• Permissions: <code className="text-purple-400">Read</code></li>
+                    <li>• Description: <code className="text-purple-400">{t('integrations.woocommerceConnect.keyStep4Description')}</code></li>
+                    <li>• User: <em>{t('integrations.woocommerceConnect.keyStep4User')}</em></li>
+                    <li>• Permissions: <code className="text-purple-400">{t('integrations.woocommerceConnect.keyStep4Permissions')}</code></li>
                   </ul>
                 </span>
               </li>
               <li className="flex items-start gap-2">
                 <span className="text-blue-500 font-semibold min-w-[20px]">5.</span>
-                <span>Click <strong>"Generate API key"</strong></span>
+                <span dangerouslySetInnerHTML={{ __html: t('integrations.woocommerceConnect.keyStep5') }} />
               </li>
               <li className="flex items-start gap-2">
                 <span className="text-blue-500 font-semibold min-w-[20px]">6.</span>
-                <span>Copy both the <strong>Consumer Key</strong> and <strong>Consumer Secret</strong></span>
+                <span dangerouslySetInnerHTML={{ __html: t('integrations.woocommerceConnect.keyStep6') }} />
               </li>
             </ol>
             <Alert className="bg-yellow-500/10 border-yellow-500/50 mt-3">
               <AlertCircle className="h-4 w-4 text-yellow-500" />
               <AlertDescription className="text-yellow-500 text-xs">
-                Important: WooCommerce shows the Consumer Secret only once! Make sure to copy it before closing the page.
+                {t('integrations.woocommerceConnect.keyWarning')}
               </AlertDescription>
             </Alert>
           </div>
@@ -625,11 +627,9 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
           <div className="flex items-start gap-2">
             <CheckCircle2 className="w-5 h-5 text-blue-500 mt-0.5 flex-shrink-0" />
             <div className="space-y-1">
-              <h4 className="text-white font-medium">Secure Connection</h4>
+              <h4 className="text-white font-medium">{t('integrations.woocommerceConnect.securityTitle')}</h4>
               <p className="text-sm text-slate-300">
-                ShopCall.ai uses WooCommerce REST API with read-only access to your store data.
-                Your API credentials are encrypted and stored securely. We never have access to your
-                WordPress admin password. All connections use HTTPS for maximum security.
+                {t('integrations.woocommerceConnect.securityDescription')}
               </p>
             </div>
           </div>
@@ -637,36 +637,35 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
 
         {/* Required Permissions */}
         <div className="bg-slate-700/50 rounded-lg p-4 space-y-3">
-          <h4 className="text-white font-medium">Required Permissions (Read-only)</h4>
+          <h4 className="text-white font-medium">{t('integrations.woocommerceConnect.permissionsTitle')}</h4>
           <div className="grid grid-cols-2 gap-2 text-sm text-slate-300">
             <div className="flex items-center gap-2">
               <CheckCircle2 className="w-4 h-4 text-green-500" />
-              <span>Read Products</span>
+              <span>{t('integrations.woocommerceConnect.readProducts')}</span>
             </div>
             <div className="flex items-center gap-2">
               <CheckCircle2 className="w-4 h-4 text-green-500" />
-              <span>Read Orders</span>
+              <span>{t('integrations.woocommerceConnect.readOrders')}</span>
             </div>
             <div className="flex items-center gap-2">
               <CheckCircle2 className="w-4 h-4 text-green-500" />
-              <span>Read Customers</span>
+              <span>{t('integrations.woocommerceConnect.readCustomers')}</span>
             </div>
             <div className="flex items-center gap-2">
               <CheckCircle2 className="w-4 h-4 text-green-500" />
-              <span>Read Coupons</span>
+              <span>{t('integrations.woocommerceConnect.readCoupons')}</span>
             </div>
             <div className="flex items-center gap-2">
               <CheckCircle2 className="w-4 h-4 text-green-500" />
-              <span>Read Reports</span>
+              <span>{t('integrations.woocommerceConnect.readReports')}</span>
             </div>
             <div className="flex items-center gap-2">
               <CheckCircle2 className="w-4 h-4 text-green-500" />
-              <span>View Settings</span>
+              <span>{t('integrations.woocommerceConnect.viewSettings')}</span>
             </div>
           </div>
           <p className="text-xs text-slate-400">
-            These read-only permissions allow our AI to access your store data and provide accurate,
-            personalized customer support without modifying anything.
+            {t('integrations.woocommerceConnect.permissionsNote')}
           </p>
         </div>
 
@@ -678,7 +677,7 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
             className="w-full border-slate-600 text-slate-300 hover:bg-slate-700"
             disabled={isConnecting}
           >
-            Cancel
+            {t('integrations.woocommerceConnect.cancel')}
           </Button>
         )}
       </CardContent>

+ 122 - 0
shopcall.ai-main/src/i18n/locales/en.json

@@ -731,6 +731,128 @@
       "comingSoon": "{{platform}} integration coming soon!",
       "close": "Close"
     },
+    "shopifyConnect": {
+      "title": "Connect Shopify Store",
+      "description": "Link your Shopify shop to enable AI-powered customer support",
+      "redirecting": "Redirecting to Shopify for authorization...",
+      "domainLabel": "Shopify Store Domain",
+      "domainPlaceholder": "your-store.myshopify.com",
+      "domainHint": "Enter your Shopify store domain (e.g., your-store.myshopify.com)",
+      "connectButton": "Connect to Shopify",
+      "connecting": "Connecting...",
+      "whatHappensNext": "What happens next?",
+      "step1": "You'll be redirected to your Shopify admin panel",
+      "step2": "Review the requested permissions and approve the app",
+      "step3": "Shopify will securely authorize ShopCall.ai",
+      "step4": "Return to ShopCall.ai to complete your setup",
+      "securityTitle": "Secure & GDPR Compliant",
+      "securityDescription": "ShopCall.ai uses Shopify OAuth 2.0 with HMAC verification for maximum security. Your credentials are encrypted and stored securely. We comply with all GDPR requirements including customer data requests and deletion.",
+      "permissionsTitle": "Required Permissions (Read-only)",
+      "readProducts": "Read Products",
+      "readOrders": "Read Orders",
+      "readCustomers": "Read Customers",
+      "readInventory": "Read Inventory",
+      "readPriceRules": "Read Price Rules",
+      "permissionsNote": "These read-only permissions allow our AI to access your store data and provide accurate, personalized customer support without modifying anything.",
+      "gdprTitle": "GDPR & Shopify App Store Ready",
+      "gdprDescription": "Our integration includes mandatory GDPR webhooks for customer data requests, customer data deletion, and shop data deletion. Fully compliant with Shopify App Store requirements.",
+      "cancel": "Cancel",
+      "errors": {
+        "domainRequired": "Please enter your Shopify store domain",
+        "phoneRequired": "Please select a phone number for this store",
+        "phoneRequiredError": "Please select a phone number before connecting",
+        "invalidDomain": "Please enter a valid Shopify domain (e.g., your-store.myshopify.com)",
+        "authRequired": "Authentication required. Please log in again.",
+        "connectionFailed": "Failed to connect to Shopify. Please try again."
+      }
+    },
+    "woocommerceConnect": {
+      "title": "Connect WooCommerce Store",
+      "description": "Link your WooCommerce shop to enable AI-powered customer support",
+      "storeConnected": "Store \"{{storeName}}\" connected successfully!",
+      "storeUrlLabel": "WooCommerce Store URL",
+      "storeUrlPlaceholder": "https://yourstore.com",
+      "storeUrlHint": "Enter your WooCommerce store URL (must use HTTPS)",
+      "consumerKeyLabel": "Consumer Key",
+      "consumerKeyPlaceholder": "ck_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+      "consumerSecretLabel": "Consumer Secret",
+      "consumerSecretPlaceholder": "cs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+      "selectPhoneTitle": "Select Phone Number",
+      "countryLabel": "Country",
+      "countryRequired": "*",
+      "loadingCountries": "Loading countries...",
+      "selectCountryPlaceholder": "Select a country",
+      "noCountriesError": "No countries with available phone numbers.",
+      "cityLabel": "City",
+      "loadingCities": "Loading cities...",
+      "selectCityPlaceholder": "Select a city",
+      "noCitiesError": "No cities with available phone numbers in this country.",
+      "phoneNumberLabel": "Phone Number",
+      "loadingPhoneNumbers": "Loading phone numbers...",
+      "selectPhonePlaceholder": "Select a phone number",
+      "noPhoneNumbersError": "No phone numbers available in this city.",
+      "selectionRequired": "Please select a country, city, and phone number to continue.",
+      "free": "Free",
+      "perMonth": "${{price}}/mo",
+      "connectButton": "Connect WooCommerce Store",
+      "connecting": "Connecting...",
+      "howToGenerateKeys": "How to generate WooCommerce API keys",
+      "keyStep1": "Log into your WooCommerce admin panel",
+      "keyStep2": "Navigate to <strong>WooCommerce → Settings → Advanced → REST API</strong>",
+      "keyStep3": "Click <strong>\"Add key\"</strong> button",
+      "keyStep4": "Fill in the form:",
+      "keyStep4Description": "ShopCall.ai",
+      "keyStep4User": "(select your admin user)",
+      "keyStep4Permissions": "Read",
+      "keyStep5": "Click <strong>\"Generate API key\"</strong>",
+      "keyStep6": "Copy both the <strong>Consumer Key</strong> and <strong>Consumer Secret</strong>",
+      "keyWarning": "Important: WooCommerce shows the Consumer Secret only once! Make sure to copy it before closing the page.",
+      "securityTitle": "Secure Connection",
+      "securityDescription": "ShopCall.ai uses WooCommerce REST API with read-only access to your store data. Your API credentials are encrypted and stored securely. We never have access to your WordPress admin password. All connections use HTTPS for maximum security.",
+      "permissionsTitle": "Required Permissions (Read-only)",
+      "readProducts": "Read Products",
+      "readOrders": "Read Orders",
+      "readCustomers": "Read Customers",
+      "readCoupons": "Read Coupons",
+      "readReports": "Read Reports",
+      "viewSettings": "View Settings",
+      "permissionsNote": "These read-only permissions allow our AI to access your store data and provide accurate, personalized customer support without modifying anything.",
+      "cancel": "Cancel",
+      "errors": {
+        "urlRequired": "Please enter your WooCommerce store URL",
+        "invalidUrl": "Please enter a valid store URL",
+        "httpsRequired": "WooCommerce requires HTTPS. Please use https:// for your store URL.",
+        "consumerKeyRequired": "Please enter your Consumer Key",
+        "invalidConsumerKey": "Consumer Key should start with 'ck_'",
+        "consumerSecretRequired": "Please enter your Consumer Secret",
+        "invalidConsumerSecret": "Consumer Secret should start with 'cs_'",
+        "phoneRequired": "Please select a phone number for this store",
+        "phoneRequiredError": "Please select a phone number before connecting",
+        "authRequired": "Authentication required. Please log in again.",
+        "connectionFailed": "Failed to connect to WooCommerce. Please try again."
+      }
+    },
+    "shoprenterConnect": {
+      "title": "Connect ShopRenter Store",
+      "description": "Link your ShopRenter shop to start managing AI-powered customer calls",
+      "installInfo": "Install from ShopRenter App Store",
+      "installDescription": "ShopRenter stores can only be connected through the ShopRenter admin panel. Please install our application from the ShopRenter App Store to connect your store.",
+      "howToConnect": "How to connect your store",
+      "step1": "Log in to your ShopRenter admin panel",
+      "step2": "Navigate to the App Store section",
+      "step3": "Search for \"ShopCall.ai\" and click Install",
+      "step4": "Grant the necessary permissions for AI caller integration",
+      "step5": "You'll be redirected back to ShopCall.ai to complete the setup",
+      "permissionsTitle": "Required Permissions",
+      "readProducts": "Read Products",
+      "writeProducts": "Write Products",
+      "readOrders": "Read Orders",
+      "writeOrders": "Write Orders",
+      "readCustomers": "Read Customers",
+      "writeCustomers": "Write Customers",
+      "permissionsNote": "These permissions allow our AI assistant to access your store data and provide accurate customer support.",
+      "close": "Close"
+    },
     "quickSetup": {
       "title": "Quick Setup Wizard",
       "subtitle": "Set up AI and phone numbers for new webshops in minutes",