|
|
@@ -95,26 +95,26 @@ export function IntegrationsContent() {
|
|
|
// Show completion notification
|
|
|
if (store.sync_status === 'completed') {
|
|
|
const stats = store.alt_data?.last_sync_stats;
|
|
|
- let description = `${store.store_name || 'Store'} data synchronized successfully.`;
|
|
|
+ let description = t('integrations.syncCompleteDescription', { storeName: store.store_name || 'Store' });
|
|
|
|
|
|
if (stats) {
|
|
|
const items = [];
|
|
|
- if (stats.products?.synced) items.push(`${stats.products.synced} products`);
|
|
|
- if (stats.orders?.synced) items.push(`${stats.orders.synced} orders`);
|
|
|
- if (stats.customers?.synced) items.push(`${stats.customers.synced} customers`);
|
|
|
+ if (stats.products?.synced) items.push(`${stats.products.synced} ${t('integrations.products').toLowerCase()}`);
|
|
|
+ if (stats.orders?.synced) items.push(`${stats.orders.synced} ${t('integrations.orders').toLowerCase()}`);
|
|
|
+ if (stats.customers?.synced) items.push(`${stats.customers.synced} ${t('integrations.customers').toLowerCase()}`);
|
|
|
if (items.length > 0) {
|
|
|
- description = `Synced: ${items.join(', ')}`;
|
|
|
+ description = t('integrations.syncedItems', { items: items.join(', ') });
|
|
|
}
|
|
|
}
|
|
|
|
|
|
toast({
|
|
|
- title: "Sync Complete",
|
|
|
+ title: t('integrations.syncComplete'),
|
|
|
description,
|
|
|
});
|
|
|
} else if (store.sync_status === 'error') {
|
|
|
toast({
|
|
|
- title: "Sync Failed",
|
|
|
- description: store.sync_error || "An error occurred during synchronization.",
|
|
|
+ title: t('integrations.syncFailed'),
|
|
|
+ description: store.sync_error || t('integrations.syncFailedDescription'),
|
|
|
variant: "destructive",
|
|
|
});
|
|
|
}
|
|
|
@@ -138,10 +138,10 @@ export function IntegrationsContent() {
|
|
|
if (params.get('wc_connected') === 'true') {
|
|
|
const storeName = params.get('store');
|
|
|
toast({
|
|
|
- title: "WooCommerce Connected!",
|
|
|
+ title: t('integrations.oauth.woocommerceConnected'),
|
|
|
description: storeName
|
|
|
- ? `Successfully connected ${decodeURIComponent(storeName)}`
|
|
|
- : "Your WooCommerce store has been connected successfully.",
|
|
|
+ ? t('integrations.oauth.woocommerceConnectedDescription', { storeName: decodeURIComponent(storeName) })
|
|
|
+ : t('integrations.oauth.woocommerceConnectedDefault'),
|
|
|
});
|
|
|
// Clean up URL
|
|
|
window.history.replaceState({}, '', '/webshops');
|
|
|
@@ -153,10 +153,10 @@ export function IntegrationsContent() {
|
|
|
if (params.get('shopify_connected') === 'true') {
|
|
|
const storeName = params.get('store');
|
|
|
toast({
|
|
|
- title: "Shopify Connected!",
|
|
|
+ title: t('integrations.oauth.shopifyConnected'),
|
|
|
description: storeName
|
|
|
- ? `Successfully connected ${decodeURIComponent(storeName)}`
|
|
|
- : "Your Shopify store has been connected successfully.",
|
|
|
+ ? t('integrations.oauth.shopifyConnectedDescription', { storeName: decodeURIComponent(storeName) })
|
|
|
+ : t('integrations.oauth.shopifyConnectedDefault'),
|
|
|
});
|
|
|
// Clean up URL
|
|
|
window.history.replaceState({}, '', '/webshops');
|
|
|
@@ -167,25 +167,9 @@ export function IntegrationsContent() {
|
|
|
// Handle errors
|
|
|
const error = params.get('error');
|
|
|
if (error) {
|
|
|
- const errorMessages: Record<string, string> = {
|
|
|
- 'woocommerce_oauth_rejected': 'WooCommerce connection was cancelled. Please try again.',
|
|
|
- 'woocommerce_oauth_failed': 'Failed to connect to WooCommerce. Please try again.',
|
|
|
- 'woocommerce_connection_failed': 'Could not connect to your WooCommerce store. Please check your store URL and try again.',
|
|
|
- 'shopify_oauth_failed': 'Failed to connect to Shopify. Please try again.',
|
|
|
- 'shopify_hmac_invalid': 'Security verification failed. Please try again.',
|
|
|
- 'shopify_invalid_state': 'Invalid session. Please try connecting again.',
|
|
|
- 'shopify_state_expired': 'Connection session expired. Please try again.',
|
|
|
- 'shopify_token_exchange_failed': 'Failed to complete Shopify authorization. Please try again.',
|
|
|
- 'shopify_connection_failed': 'Could not connect to your Shopify store. Please check your domain and try again.',
|
|
|
- 'invalid_shop_domain': 'Invalid Shopify domain. Please check the domain and try again.',
|
|
|
- 'invalid_store_url': 'Invalid store URL. Please check the URL and try again.',
|
|
|
- 'failed_to_save': 'Failed to save store connection. Please try again.',
|
|
|
- 'internal_error': 'An internal error occurred. Please try again later.',
|
|
|
- };
|
|
|
-
|
|
|
toast({
|
|
|
- title: "Connection Failed",
|
|
|
- description: errorMessages[error] || "An unexpected error occurred. Please try again.",
|
|
|
+ title: t('integrations.oauth.connectionFailed'),
|
|
|
+ description: t(`integrations.oauth.errors.${error}`, { defaultValue: t('integrations.oauth.errors.default') }),
|
|
|
variant: "destructive",
|
|
|
});
|
|
|
// Clean up URL
|
|
|
@@ -211,22 +195,22 @@ export function IntegrationsContent() {
|
|
|
const platforms = [
|
|
|
{
|
|
|
id: "shopify",
|
|
|
- name: "Shopify",
|
|
|
- description: "Connect your Shopify store",
|
|
|
+ name: t('integrations.dialog.shopify'),
|
|
|
+ description: t('integrations.dialog.shopifyDescription'),
|
|
|
icon: Store,
|
|
|
color: "text-green-500"
|
|
|
},
|
|
|
{
|
|
|
id: "woocommerce",
|
|
|
- name: "WooCommerce",
|
|
|
- description: "Connect your WooCommerce store",
|
|
|
+ name: t('integrations.dialog.woocommerce'),
|
|
|
+ description: t('integrations.dialog.woocommerceDescription'),
|
|
|
icon: ShoppingBag,
|
|
|
color: "text-purple-500"
|
|
|
},
|
|
|
{
|
|
|
id: "shoprenter",
|
|
|
- name: "ShopRenter",
|
|
|
- description: "Connect your ShopRenter store",
|
|
|
+ name: t('integrations.dialog.shoprenter'),
|
|
|
+ description: t('integrations.dialog.shoprenterDescription'),
|
|
|
icon: Store,
|
|
|
color: "text-blue-500"
|
|
|
}
|
|
|
@@ -242,7 +226,7 @@ export function IntegrationsContent() {
|
|
|
};
|
|
|
|
|
|
const handleDisconnectStore = async (storeId: string, storeName: string) => {
|
|
|
- if (!confirm(`Are you sure you want to disconnect ${storeName}? This action cannot be undone.`)) {
|
|
|
+ if (!confirm(t('integrations.disconnectConfirm', { storeName }))) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
@@ -270,17 +254,17 @@ export function IntegrationsContent() {
|
|
|
}
|
|
|
|
|
|
toast({
|
|
|
- title: "Store Disconnected",
|
|
|
- description: `${storeName} has been disconnected successfully.`,
|
|
|
+ title: t('integrations.storeDisconnected'),
|
|
|
+ description: t('integrations.storeDisconnectedDescription', { storeName }),
|
|
|
});
|
|
|
|
|
|
// Refresh stores list
|
|
|
fetchStores();
|
|
|
} catch (error) {
|
|
|
console.error('Error disconnecting store:', error);
|
|
|
- const errorMessage = error instanceof Error ? error.message : 'Failed to disconnect the store. Please try again.';
|
|
|
+ const errorMessage = error instanceof Error ? error.message : t('integrations.disconnectionFailedDescription');
|
|
|
toast({
|
|
|
- title: "Disconnection Failed",
|
|
|
+ title: t('integrations.disconnectionFailed'),
|
|
|
description: errorMessage,
|
|
|
variant: "destructive",
|
|
|
});
|
|
|
@@ -308,8 +292,8 @@ export function IntegrationsContent() {
|
|
|
if (!response.ok) {
|
|
|
if (response.status === 409) {
|
|
|
toast({
|
|
|
- title: "Sync Already Running",
|
|
|
- description: "A sync is already in progress for this store.",
|
|
|
+ title: t('integrations.syncAlreadyRunning'),
|
|
|
+ description: t('integrations.syncAlreadyRunningDescription'),
|
|
|
variant: "default",
|
|
|
});
|
|
|
return;
|
|
|
@@ -321,8 +305,8 @@ export function IntegrationsContent() {
|
|
|
setSyncingStores(prev => new Set(prev).add(storeId));
|
|
|
|
|
|
toast({
|
|
|
- title: "Sync Started",
|
|
|
- description: `Data synchronization started for ${storeName}`,
|
|
|
+ title: t('integrations.syncStarted'),
|
|
|
+ description: t('integrations.syncStartedDescription', { storeName }),
|
|
|
});
|
|
|
|
|
|
// Refresh stores list immediately to show syncing status
|
|
|
@@ -330,8 +314,8 @@ export function IntegrationsContent() {
|
|
|
} catch (error) {
|
|
|
console.error('Error triggering sync:', error);
|
|
|
toast({
|
|
|
- title: "Sync Failed",
|
|
|
- description: "Failed to start data synchronization. Please try again.",
|
|
|
+ title: t('integrations.syncFailed'),
|
|
|
+ description: t('integrations.syncFailedDescription'),
|
|
|
variant: "destructive",
|
|
|
});
|
|
|
}
|
|
|
@@ -363,10 +347,10 @@ export function IntegrationsContent() {
|
|
|
}
|
|
|
|
|
|
toast({
|
|
|
- title: newEnabled ? "Shop Enabled" : "Shop Disabled",
|
|
|
+ title: newEnabled ? t('integrations.shopEnabled') : t('integrations.shopDisabled'),
|
|
|
description: newEnabled
|
|
|
- ? `${storeName} is now enabled. Background sync will resume.`
|
|
|
- : `${storeName} is now disabled. Background sync is paused (manual sync still available).`,
|
|
|
+ ? t('integrations.shopEnabledDescription', { storeName })
|
|
|
+ : t('integrations.shopDisabledDescription', { storeName }),
|
|
|
});
|
|
|
|
|
|
// Refresh stores list
|
|
|
@@ -374,8 +358,8 @@ export function IntegrationsContent() {
|
|
|
} catch (error) {
|
|
|
console.error('Error toggling store enabled status:', error);
|
|
|
toast({
|
|
|
- title: "Update Failed",
|
|
|
- description: "Failed to update shop status. Please try again.",
|
|
|
+ title: t('integrations.updateFailed'),
|
|
|
+ description: t('integrations.updateFailedDescription'),
|
|
|
variant: "destructive",
|
|
|
});
|
|
|
}
|
|
|
@@ -389,15 +373,15 @@ export function IntegrationsContent() {
|
|
|
return (
|
|
|
<Badge className="bg-blue-500 text-white animate-pulse">
|
|
|
<Loader2 className="w-3 h-3 mr-1 animate-spin" />
|
|
|
- Syncing
|
|
|
+ {t('integrations.syncing')}
|
|
|
</Badge>
|
|
|
);
|
|
|
case 'completed':
|
|
|
- return <Badge className="bg-green-500 text-white">Synced</Badge>;
|
|
|
+ return <Badge className="bg-green-500 text-white">{t('integrations.synced')}</Badge>;
|
|
|
case 'error':
|
|
|
- return <Badge className="bg-red-500 text-white">Error</Badge>;
|
|
|
+ return <Badge className="bg-red-500 text-white">{t('integrations.error')}</Badge>;
|
|
|
default:
|
|
|
- return <Badge className="bg-gray-500 text-white">Not Synced</Badge>;
|
|
|
+ return <Badge className="bg-gray-500 text-white">{t('integrations.notSynced')}</Badge>;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
@@ -407,13 +391,13 @@ export function IntegrationsContent() {
|
|
|
|
|
|
const items = [];
|
|
|
if (stats.products?.synced !== undefined) {
|
|
|
- items.push({ label: 'Products', count: stats.products.synced, errors: stats.products.errors || 0 });
|
|
|
+ items.push({ label: t('integrations.products'), count: stats.products.synced, errors: stats.products.errors || 0 });
|
|
|
}
|
|
|
if (stats.orders?.synced !== undefined) {
|
|
|
- items.push({ label: 'Orders', count: stats.orders.synced, errors: stats.orders.errors || 0 });
|
|
|
+ items.push({ label: t('integrations.orders'), count: stats.orders.synced, errors: stats.orders.errors || 0 });
|
|
|
}
|
|
|
if (stats.customers?.synced !== undefined) {
|
|
|
- items.push({ label: 'Customers', count: stats.customers.synced, errors: stats.customers.errors || 0 });
|
|
|
+ items.push({ label: t('integrations.customers'), count: stats.customers.synced, errors: stats.customers.errors || 0 });
|
|
|
}
|
|
|
|
|
|
if (items.length === 0) return null;
|
|
|
@@ -444,22 +428,22 @@ export function IntegrationsContent() {
|
|
|
<div className="flex flex-wrap gap-1">
|
|
|
{permissions.allow_product_access && (
|
|
|
<Badge variant="outline" className="text-xs border-blue-500 text-blue-400">
|
|
|
- Products
|
|
|
+ {t('integrations.products')}
|
|
|
</Badge>
|
|
|
)}
|
|
|
{permissions.allow_customer_access && (
|
|
|
<Badge variant="outline" className="text-xs border-green-500 text-green-400">
|
|
|
- Customers
|
|
|
+ {t('integrations.customers')}
|
|
|
</Badge>
|
|
|
)}
|
|
|
{permissions.allow_order_access && (
|
|
|
<Badge variant="outline" className="text-xs border-purple-500 text-purple-400">
|
|
|
- Orders
|
|
|
+ {t('integrations.orders')}
|
|
|
</Badge>
|
|
|
)}
|
|
|
{!permissions.allow_customer_access && !permissions.allow_order_access && (
|
|
|
<Badge variant="outline" className="text-xs border-orange-500 text-orange-400">
|
|
|
- Limited Access
|
|
|
+ {t('integrations.limitedAccess')}
|
|
|
</Badge>
|
|
|
)}
|
|
|
</div>
|
|
|
@@ -489,15 +473,15 @@ export function IntegrationsContent() {
|
|
|
<div className="flex-1 space-y-6 p-8 bg-slate-900">
|
|
|
<div className="flex items-center justify-between">
|
|
|
<div>
|
|
|
- <h2 className="text-3xl font-bold tracking-tight text-white">Webshops</h2>
|
|
|
- <p className="text-slate-400">Manage your connected stores and their AI configurations</p>
|
|
|
+ <h2 className="text-3xl font-bold tracking-tight text-white">{t('integrations.title')}</h2>
|
|
|
+ <p className="text-slate-400">{t('integrations.subtitle')}</p>
|
|
|
</div>
|
|
|
<Button
|
|
|
className="bg-cyan-500 hover:bg-cyan-600 text-white"
|
|
|
onClick={() => setShowConnectDialog(true)}
|
|
|
>
|
|
|
<Plus className="w-4 h-4 mr-2" />
|
|
|
- Connect Webshop
|
|
|
+ {t('integrations.connectWebshop')}
|
|
|
</Button>
|
|
|
</div>
|
|
|
|
|
|
@@ -507,9 +491,9 @@ export function IntegrationsContent() {
|
|
|
{!selectedPlatform ? (
|
|
|
<>
|
|
|
<DialogHeader>
|
|
|
- <DialogTitle className="text-white text-2xl">Connect Your E-commerce Platform</DialogTitle>
|
|
|
+ <DialogTitle className="text-white text-2xl">{t('integrations.dialog.title')}</DialogTitle>
|
|
|
<DialogDescription className="text-slate-400">
|
|
|
- Choose your e-commerce platform to get started with AI-powered customer calls
|
|
|
+ {t('integrations.dialog.description')}
|
|
|
</DialogDescription>
|
|
|
</DialogHeader>
|
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mt-6">
|
|
|
@@ -528,7 +512,7 @@ export function IntegrationsContent() {
|
|
|
<p className="text-slate-400 text-sm mt-1">{platform.description}</p>
|
|
|
</div>
|
|
|
<Button className="w-full bg-cyan-500 hover:bg-cyan-600 text-white">
|
|
|
- Connect
|
|
|
+ {t('integrations.dialog.connect')}
|
|
|
</Button>
|
|
|
</CardContent>
|
|
|
</Card>
|
|
|
@@ -545,13 +529,13 @@ export function IntegrationsContent() {
|
|
|
) : (
|
|
|
<div className="text-center py-8">
|
|
|
<p className="text-white">
|
|
|
- {platforms.find(p => p.id === selectedPlatform)?.name} integration coming soon!
|
|
|
+ {t('integrations.dialog.comingSoon', { platform: platforms.find(p => p.id === selectedPlatform)?.name })}
|
|
|
</p>
|
|
|
<Button
|
|
|
onClick={handleCloseDialog}
|
|
|
className="mt-4 bg-cyan-500 hover:bg-cyan-600 text-white"
|
|
|
>
|
|
|
- Close
|
|
|
+ {t('integrations.dialog.close')}
|
|
|
</Button>
|
|
|
</div>
|
|
|
)}
|
|
|
@@ -579,7 +563,7 @@ export function IntegrationsContent() {
|
|
|
<Store className="w-8 h-8 text-cyan-500" />
|
|
|
<div>
|
|
|
<p className="text-2xl font-bold text-white">{connectedShops.length}</p>
|
|
|
- <p className="text-slate-400">Connected Shops</p>
|
|
|
+ <p className="text-slate-400">{t('integrations.connectedShops')}</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
</CardContent>
|
|
|
@@ -591,7 +575,7 @@ export function IntegrationsContent() {
|
|
|
<PhoneCall className="w-8 h-8 text-green-500" />
|
|
|
<div>
|
|
|
<p className="text-2xl font-bold text-white">{connectedShops.filter(s => s.phone_number).length}</p>
|
|
|
- <p className="text-slate-400">With Phone Numbers</p>
|
|
|
+ <p className="text-slate-400">{t('integrations.withPhoneNumbers')}</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
</CardContent>
|
|
|
@@ -603,7 +587,7 @@ export function IntegrationsContent() {
|
|
|
<Store className="w-8 h-8 text-purple-500" />
|
|
|
<div>
|
|
|
<p className="text-2xl font-bold text-white">{connectedShops.filter(s => s.is_active).length}</p>
|
|
|
- <p className="text-slate-400">Active Stores</p>
|
|
|
+ <p className="text-slate-400">{t('integrations.activeStores')}</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
</CardContent>
|
|
|
@@ -615,7 +599,7 @@ export function IntegrationsContent() {
|
|
|
<Globe className="w-8 h-8 text-blue-500" />
|
|
|
<div>
|
|
|
<p className="text-2xl font-bold text-white">{new Set(connectedShops.map(s => s.platform_name)).size}</p>
|
|
|
- <p className="text-slate-400">Platforms</p>
|
|
|
+ <p className="text-slate-400">{t('integrations.platforms')}</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
</CardContent>
|
|
|
@@ -626,8 +610,8 @@ export function IntegrationsContent() {
|
|
|
<div>
|
|
|
<div className="flex items-center justify-between mb-4">
|
|
|
<div>
|
|
|
- <h3 className="text-xl font-semibold text-white">Connected Webshops</h3>
|
|
|
- <p className="text-slate-400 text-sm">Manage your connected stores</p>
|
|
|
+ <h3 className="text-xl font-semibold text-white">{t('integrations.connectedWebshops')}</h3>
|
|
|
+ <p className="text-slate-400 text-sm">{t('integrations.manageStores')}</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
@@ -648,16 +632,16 @@ export function IntegrationsContent() {
|
|
|
<CardContent className="p-12">
|
|
|
<div className="text-center">
|
|
|
<Store className="w-16 h-16 text-slate-600 mx-auto mb-4" />
|
|
|
- <h3 className="text-lg font-semibold text-white mb-2">No Stores Connected</h3>
|
|
|
+ <h3 className="text-lg font-semibold text-white mb-2">{t('integrations.noStoresConnected')}</h3>
|
|
|
<p className="text-slate-400 mb-6">
|
|
|
- Connect your first e-commerce store to get started with AI-powered customer calls
|
|
|
+ {t('integrations.noStoresDescription')}
|
|
|
</p>
|
|
|
<Button
|
|
|
className="bg-cyan-500 hover:bg-cyan-600 text-white"
|
|
|
onClick={() => setShowConnectDialog(true)}
|
|
|
>
|
|
|
<Plus className="w-4 h-4 mr-2" />
|
|
|
- Connect Your First Store
|
|
|
+ {t('integrations.connectFirstStore')}
|
|
|
</Button>
|
|
|
</div>
|
|
|
</CardContent>
|
|
|
@@ -676,12 +660,12 @@ export function IntegrationsContent() {
|
|
|
shop.platform_name === 'shoprenter' ? 'text-blue-500' :
|
|
|
'text-green-500'
|
|
|
}`} />
|
|
|
- <h4 className="text-white font-semibold truncate">{shop.store_name || 'Unnamed Store'}</h4>
|
|
|
+ <h4 className="text-white font-semibold truncate">{shop.store_name || t('integrations.unnamedStore')}</h4>
|
|
|
</div>
|
|
|
<p className="text-xs text-slate-500 truncate">{shop.store_url || '-'}</p>
|
|
|
</div>
|
|
|
<Badge className={`${shop.is_active ? "bg-green-500" : "bg-red-500"} text-white text-xs flex-shrink-0 ml-2`}>
|
|
|
- {shop.is_active ? "Active" : "Inactive"}
|
|
|
+ {shop.is_active ? t('integrations.active') : t('integrations.inactive')}
|
|
|
</Badge>
|
|
|
</div>
|
|
|
|
|
|
@@ -710,22 +694,22 @@ export function IntegrationsContent() {
|
|
|
<div className="bg-slate-700/50 rounded-lg p-3 mb-3">
|
|
|
<div className="flex items-center gap-2 mb-1">
|
|
|
<PhoneCall className="w-3 h-3 text-slate-400" />
|
|
|
- <span className="text-xs text-slate-400">Phone Number</span>
|
|
|
+ <span className="text-xs text-slate-400">{t('integrations.phoneNumber')}</span>
|
|
|
</div>
|
|
|
<div className={`text-sm ${shop.phone_number ? "text-white font-mono" : "text-slate-500 italic"}`}>
|
|
|
- {shop.phone_number || "Not assigned"}
|
|
|
+ {shop.phone_number || t('integrations.notAssigned')}
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
{/* Sync Status Section */}
|
|
|
<div className="bg-slate-700/50 rounded-lg p-3 mb-3">
|
|
|
<div className="flex items-center justify-between mb-2">
|
|
|
- <span className="text-xs text-slate-400">Sync Status</span>
|
|
|
+ <span className="text-xs text-slate-400">{t('integrations.syncStatus')}</span>
|
|
|
{getSyncStatusBadge(shop)}
|
|
|
</div>
|
|
|
{shop.sync_completed_at && shop.sync_status === 'completed' && (
|
|
|
<div className="text-xs text-slate-500">
|
|
|
- Last: {new Date(shop.sync_completed_at).toLocaleString()}
|
|
|
+ {t('integrations.lastSync')}: {new Date(shop.sync_completed_at).toLocaleString()}
|
|
|
</div>
|
|
|
)}
|
|
|
{shop.sync_error && (
|
|
|
@@ -739,11 +723,11 @@ export function IntegrationsContent() {
|
|
|
{/* Data Access & Background Sync */}
|
|
|
<div className="flex items-center justify-between mb-4 pb-3 border-b border-slate-700">
|
|
|
<div>
|
|
|
- <div className="text-xs text-slate-400 mb-1">Data Access</div>
|
|
|
+ <div className="text-xs text-slate-400 mb-1">{t('integrations.dataAccess')}</div>
|
|
|
{getDataAccessBadges(shop)}
|
|
|
</div>
|
|
|
<div className="text-right">
|
|
|
- <div className="text-xs text-slate-400 mb-1">Auto Sync</div>
|
|
|
+ <div className="text-xs text-slate-400 mb-1">{t('integrations.autoSync')}</div>
|
|
|
<Switch
|
|
|
checked={shop.store_sync_config?.[0]?.enabled ?? true}
|
|
|
onCheckedChange={() => handleToggleStoreEnabled(
|
|
|
@@ -772,7 +756,7 @@ export function IntegrationsContent() {
|
|
|
) : (
|
|
|
<Zap className="w-3 h-3 mr-1" />
|
|
|
)}
|
|
|
- Sync
|
|
|
+ {t('integrations.sync')}
|
|
|
</Button>
|
|
|
<Button
|
|
|
size="sm"
|
|
|
@@ -780,7 +764,7 @@ export function IntegrationsContent() {
|
|
|
onClick={() => window.location.href = `/ai-config?shop=${shop.id}`}
|
|
|
>
|
|
|
<Bot className="w-3 h-3 mr-1" />
|
|
|
- AI Config
|
|
|
+ {t('integrations.aiConfig')}
|
|
|
</Button>
|
|
|
<Button
|
|
|
size="sm"
|
|
|
@@ -789,7 +773,7 @@ export function IntegrationsContent() {
|
|
|
onClick={() => window.location.href = `/phone-numbers?shop=${shop.id}`}
|
|
|
>
|
|
|
<PhoneCall className="w-3 h-3 mr-1" />
|
|
|
- Phone
|
|
|
+ {t('integrations.phone')}
|
|
|
</Button>
|
|
|
<Button
|
|
|
size="sm"
|
|
|
@@ -798,7 +782,7 @@ export function IntegrationsContent() {
|
|
|
onClick={() => handleOpenPermissions(shop)}
|
|
|
>
|
|
|
<Shield className="w-3 h-3 mr-1" />
|
|
|
- Access
|
|
|
+ {t('integrations.access')}
|
|
|
</Button>
|
|
|
</div>
|
|
|
|
|
|
@@ -810,7 +794,7 @@ export function IntegrationsContent() {
|
|
|
onClick={() => handleDisconnectStore(shop.id, shop.store_name || 'this store')}
|
|
|
>
|
|
|
<Trash2 className="w-3 h-3 mr-1" />
|
|
|
- Disconnect Store
|
|
|
+ {t('integrations.disconnectStore')}
|
|
|
</Button>
|
|
|
</CardContent>
|
|
|
</Card>
|
|
|
@@ -823,38 +807,38 @@ export function IntegrationsContent() {
|
|
|
<CardHeader>
|
|
|
<div className="flex items-center gap-3">
|
|
|
<Zap className="w-6 h-6 text-cyan-500" />
|
|
|
- <CardTitle className="text-white">Quick Setup Wizard</CardTitle>
|
|
|
+ <CardTitle className="text-white">{t('integrations.quickSetup.title')}</CardTitle>
|
|
|
</div>
|
|
|
- <p className="text-slate-400">Set up AI and phone numbers for new webshops in minutes</p>
|
|
|
+ <p className="text-slate-400">{t('integrations.quickSetup.subtitle')}</p>
|
|
|
</CardHeader>
|
|
|
<CardContent className="space-y-4">
|
|
|
<div className="space-y-4">
|
|
|
<div className="flex gap-4">
|
|
|
<div className="flex-shrink-0 w-8 h-8 bg-cyan-500 text-white rounded-full flex items-center justify-center font-semibold">1</div>
|
|
|
<div>
|
|
|
- <h4 className="text-white font-medium">Connect your webshop</h4>
|
|
|
- <p className="text-slate-400">Link your Shopify, WooCommerce, or other e-commerce platform</p>
|
|
|
+ <h4 className="text-white font-medium">{t('integrations.quickSetup.step1.title')}</h4>
|
|
|
+ <p className="text-slate-400">{t('integrations.quickSetup.step1.description')}</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div className="flex gap-4">
|
|
|
<div className="flex-shrink-0 w-8 h-8 bg-cyan-500 text-white rounded-full flex items-center justify-center font-semibold">2</div>
|
|
|
<div>
|
|
|
- <h4 className="text-white font-medium">Get a phone number</h4>
|
|
|
- <p className="text-slate-400">We'll automatically assign a free local number or upgrade to premium</p>
|
|
|
+ <h4 className="text-white font-medium">{t('integrations.quickSetup.step2.title')}</h4>
|
|
|
+ <p className="text-slate-400">{t('integrations.quickSetup.step2.description')}</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div className="flex gap-4">
|
|
|
<div className="flex-shrink-0 w-8 h-8 bg-cyan-500 text-white rounded-full flex items-center justify-center font-semibold">3</div>
|
|
|
<div>
|
|
|
- <h4 className="text-white font-medium">Configure your AI assistant</h4>
|
|
|
- <p className="text-slate-400">Customize voice, language, and behavior for your region and brand</p>
|
|
|
+ <h4 className="text-white font-medium">{t('integrations.quickSetup.step3.title')}</h4>
|
|
|
+ <p className="text-slate-400">{t('integrations.quickSetup.step3.description')}</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div className="flex gap-4">
|
|
|
<div className="flex-shrink-0 w-8 h-8 bg-cyan-500 text-white rounded-full flex items-center justify-center font-semibold">4</div>
|
|
|
<div>
|
|
|
- <h4 className="text-white font-medium">Start receiving calls</h4>
|
|
|
- <p className="text-slate-400">Your AI will handle customer inquiries with store-specific knowledge</p>
|
|
|
+ <h4 className="text-white font-medium">{t('integrations.quickSetup.step4.title')}</h4>
|
|
|
+ <p className="text-slate-400">{t('integrations.quickSetup.step4.description')}</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -868,10 +852,10 @@ export function IntegrationsContent() {
|
|
|
<DialogHeader>
|
|
|
<DialogTitle className="text-white text-2xl flex items-center gap-2">
|
|
|
<Shield className="w-6 h-6 text-cyan-500" />
|
|
|
- Data Access Permissions
|
|
|
+ {t('integrations.dataAccessDialog.title')}
|
|
|
</DialogTitle>
|
|
|
<DialogDescription className="text-slate-400">
|
|
|
- {selectedStore && `Configure data access permissions for ${selectedStore.store_name || 'this store'}`}
|
|
|
+ {selectedStore && t('integrations.dataAccessDialog.description', { storeName: selectedStore.store_name || 'this store' })}
|
|
|
</DialogDescription>
|
|
|
</DialogHeader>
|
|
|
{selectedStore && (
|
|
|
@@ -892,7 +876,7 @@ export function IntegrationsContent() {
|
|
|
onClick={handleClosePermissions}
|
|
|
className="text-slate-400 border-slate-600 hover:bg-slate-700"
|
|
|
>
|
|
|
- Close
|
|
|
+ {t('integrations.dialog.close')}
|
|
|
</Button>
|
|
|
</div>
|
|
|
</DialogContent>
|