|
|
@@ -11,6 +11,7 @@ import { Mic, MessageSquare, Brain, Zap, Store, ChevronDown, Loader2 } from "luc
|
|
|
import { useState, useEffect } from "react";
|
|
|
import { API_URL } from "@/lib/config";
|
|
|
import { useToast } from "@/hooks/use-toast";
|
|
|
+import { useTranslation } from "react-i18next";
|
|
|
|
|
|
interface StoreData {
|
|
|
id: string;
|
|
|
@@ -35,6 +36,7 @@ interface AIConfig {
|
|
|
}
|
|
|
|
|
|
export function AIConfigContent() {
|
|
|
+ const { t } = useTranslation();
|
|
|
const { toast } = useToast();
|
|
|
const [stores, setStores] = useState<StoreData[]>([]);
|
|
|
const [selectedStore, setSelectedStore] = useState<StoreData | null>(null);
|
|
|
@@ -97,8 +99,8 @@ export function AIConfigContent() {
|
|
|
} catch (error) {
|
|
|
console.error('Error fetching stores:', error);
|
|
|
toast({
|
|
|
- title: "Error",
|
|
|
- description: "Failed to load stores. Please try again.",
|
|
|
+ title: t('common.error'),
|
|
|
+ description: t('webshops.error'),
|
|
|
variant: "destructive"
|
|
|
});
|
|
|
} finally {
|
|
|
@@ -161,14 +163,14 @@ export function AIConfigContent() {
|
|
|
}
|
|
|
|
|
|
toast({
|
|
|
- title: "Success",
|
|
|
- description: "AI configuration saved successfully.",
|
|
|
+ title: t('common.success'),
|
|
|
+ description: t('aiConfig.saveConfiguration'),
|
|
|
});
|
|
|
} catch (error) {
|
|
|
console.error('Error saving config:', error);
|
|
|
toast({
|
|
|
- title: "Error",
|
|
|
- description: "Failed to save configuration. Please try again.",
|
|
|
+ title: t('common.error'),
|
|
|
+ description: t('common.tryAgain'),
|
|
|
variant: "destructive"
|
|
|
});
|
|
|
} finally {
|
|
|
@@ -190,15 +192,15 @@ export function AIConfigContent() {
|
|
|
<div className="flex items-center justify-center min-h-[60vh]">
|
|
|
<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('aiConfig.noStoresConnected.title')}</h3>
|
|
|
<p className="text-slate-400 mb-6">
|
|
|
- Please connect a store first before configuring AI settings.
|
|
|
+ {t('aiConfig.noStoresConnected.description')}
|
|
|
</p>
|
|
|
<Button
|
|
|
className="bg-cyan-500 hover:bg-cyan-600 text-white"
|
|
|
onClick={() => window.location.href = '/webshops'}
|
|
|
>
|
|
|
- Go to Webshops
|
|
|
+ {t('aiConfig.noStoresConnected.goToWebshops')}
|
|
|
</Button>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -218,8 +220,8 @@ export function AIConfigContent() {
|
|
|
<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">AI Configuration</h2>
|
|
|
- <p className="text-slate-400">Configure AI behavior and responses per webshop</p>
|
|
|
+ <h2 className="text-3xl font-bold tracking-tight text-white">{t('aiConfig.title')}</h2>
|
|
|
+ <p className="text-slate-400">{t('aiConfig.subtitle')}</p>
|
|
|
</div>
|
|
|
<div className="flex gap-3">
|
|
|
<Button
|
|
|
@@ -230,10 +232,10 @@ export function AIConfigContent() {
|
|
|
{saving ? (
|
|
|
<>
|
|
|
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
|
|
|
- Saving...
|
|
|
+ {t('aiConfig.saving')}
|
|
|
</>
|
|
|
) : (
|
|
|
- "Save Configuration"
|
|
|
+ t('aiConfig.saveConfiguration')
|
|
|
)}
|
|
|
</Button>
|
|
|
</div>
|
|
|
@@ -244,9 +246,9 @@ export function AIConfigContent() {
|
|
|
<CardHeader>
|
|
|
<div className="flex items-center gap-3">
|
|
|
<Store className="w-6 h-6 text-cyan-500" />
|
|
|
- <CardTitle className="text-white">Select Webshop</CardTitle>
|
|
|
+ <CardTitle className="text-white">{t('aiConfig.selectWebshop.title')}</CardTitle>
|
|
|
</div>
|
|
|
- <p className="text-slate-400">Choose which webshop to configure</p>
|
|
|
+ <p className="text-slate-400">{t('aiConfig.selectWebshop.subtitle')}</p>
|
|
|
</CardHeader>
|
|
|
<CardContent>
|
|
|
<Select value={selectedStore.id} onValueChange={handleStoreChange}>
|
|
|
@@ -281,7 +283,7 @@ export function AIConfigContent() {
|
|
|
)}
|
|
|
</div>
|
|
|
<Badge className={`${selectedStore.is_active ? "bg-green-500" : "bg-red-500"} text-white`}>
|
|
|
- {selectedStore.is_active ? "Active" : "Inactive"}
|
|
|
+ {selectedStore.is_active ? t('webshops.active') : t('webshops.inactive')}
|
|
|
</Badge>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -293,49 +295,49 @@ export function AIConfigContent() {
|
|
|
<CardHeader>
|
|
|
<div className="flex items-center gap-3">
|
|
|
<Mic className="w-6 h-6 text-cyan-500" />
|
|
|
- <CardTitle className="text-white">Voice & Speech Settings</CardTitle>
|
|
|
+ <CardTitle className="text-white">{t('aiConfig.voiceSettings.title')}</CardTitle>
|
|
|
</div>
|
|
|
- <p className="text-slate-400">Configure voice characteristics for {selectedStore.store_name || 'your store'}</p>
|
|
|
+ <p className="text-slate-400">{t('aiConfig.voiceSettings.subtitle')} {selectedStore.store_name || 'your store'}</p>
|
|
|
</CardHeader>
|
|
|
<CardContent className="space-y-6">
|
|
|
<div className="grid gap-6 md:grid-cols-2">
|
|
|
<div className="space-y-2">
|
|
|
- <Label className="text-slate-300">Voice Type</Label>
|
|
|
+ <Label className="text-slate-300">{t('aiConfig.voiceSettings.voiceType')}</Label>
|
|
|
<Select value={aiConfig.voice_type} onValueChange={(value) => setAiConfig({ ...aiConfig, voice_type: value })}>
|
|
|
<SelectTrigger className="bg-slate-700 border-slate-600 text-white">
|
|
|
<SelectValue />
|
|
|
</SelectTrigger>
|
|
|
<SelectContent className="bg-slate-700 border-slate-600">
|
|
|
- <SelectItem value="sarah">Sarah (Professional)</SelectItem>
|
|
|
- <SelectItem value="james">James (Friendly)</SelectItem>
|
|
|
- <SelectItem value="emma">Emma (Warm)</SelectItem>
|
|
|
+ <SelectItem value="sarah">{t('aiConfig.voiceSettings.voices.sarah')}</SelectItem>
|
|
|
+ <SelectItem value="james">{t('aiConfig.voiceSettings.voices.james')}</SelectItem>
|
|
|
+ <SelectItem value="emma">{t('aiConfig.voiceSettings.voices.emma')}</SelectItem>
|
|
|
</SelectContent>
|
|
|
</Select>
|
|
|
</div>
|
|
|
<div className="space-y-2">
|
|
|
- <Label className="text-slate-300">Speaking Speed</Label>
|
|
|
+ <Label className="text-slate-300">{t('aiConfig.voiceSettings.speakingSpeed')}</Label>
|
|
|
<Select value={aiConfig.speaking_speed} onValueChange={(value) => setAiConfig({ ...aiConfig, speaking_speed: value })}>
|
|
|
<SelectTrigger className="bg-slate-700 border-slate-600 text-white">
|
|
|
<SelectValue />
|
|
|
</SelectTrigger>
|
|
|
<SelectContent className="bg-slate-700 border-slate-600">
|
|
|
- <SelectItem value="slow">Slow</SelectItem>
|
|
|
- <SelectItem value="normal">Normal</SelectItem>
|
|
|
- <SelectItem value="fast">Fast</SelectItem>
|
|
|
+ <SelectItem value="slow">{t('aiConfig.voiceSettings.speeds.slow')}</SelectItem>
|
|
|
+ <SelectItem value="normal">{t('aiConfig.voiceSettings.speeds.normal')}</SelectItem>
|
|
|
+ <SelectItem value="fast">{t('aiConfig.voiceSettings.speeds.fast')}</SelectItem>
|
|
|
</SelectContent>
|
|
|
</Select>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div className="space-y-2">
|
|
|
- <Label className="text-slate-300">Accent & Language</Label>
|
|
|
+ <Label className="text-slate-300">{t('aiConfig.voiceSettings.accentLanguage')}</Label>
|
|
|
<Select value={aiConfig.accent_language} onValueChange={(value) => setAiConfig({ ...aiConfig, accent_language: value })}>
|
|
|
<SelectTrigger className="bg-slate-700 border-slate-600 text-white">
|
|
|
<SelectValue />
|
|
|
</SelectTrigger>
|
|
|
<SelectContent className="bg-slate-700 border-slate-600">
|
|
|
- <SelectItem value="us-english">US English</SelectItem>
|
|
|
- <SelectItem value="uk-english">UK English</SelectItem>
|
|
|
- <SelectItem value="australian">Australian</SelectItem>
|
|
|
+ <SelectItem value="us-english">{t('aiConfig.voiceSettings.accents.usEnglish')}</SelectItem>
|
|
|
+ <SelectItem value="uk-english">{t('aiConfig.voiceSettings.accents.ukEnglish')}</SelectItem>
|
|
|
+ <SelectItem value="australian">{t('aiConfig.voiceSettings.accents.australian')}</SelectItem>
|
|
|
</SelectContent>
|
|
|
</Select>
|
|
|
</div>
|
|
|
@@ -346,13 +348,13 @@ export function AIConfigContent() {
|
|
|
<CardHeader>
|
|
|
<div className="flex items-center gap-3">
|
|
|
<MessageSquare className="w-6 h-6 text-cyan-500" />
|
|
|
- <CardTitle className="text-white">Conversation Behavior</CardTitle>
|
|
|
+ <CardTitle className="text-white">{t('aiConfig.conversationBehavior.title')}</CardTitle>
|
|
|
</div>
|
|
|
- <p className="text-slate-400">Define how the AI interacts with {selectedStore.store_name || 'your store'} customers</p>
|
|
|
+ <p className="text-slate-400">{t('aiConfig.conversationBehavior.subtitle')} {selectedStore.store_name || 'your store'} customers</p>
|
|
|
</CardHeader>
|
|
|
<CardContent className="space-y-6">
|
|
|
<div className="space-y-2">
|
|
|
- <Label className="text-slate-300">Greeting Message</Label>
|
|
|
+ <Label className="text-slate-300">{t('aiConfig.conversationBehavior.greetingMessage')}</Label>
|
|
|
<Textarea
|
|
|
className="bg-slate-700 border-slate-600 text-white min-h-[100px]"
|
|
|
value={aiConfig.greeting_message}
|
|
|
@@ -363,8 +365,8 @@ export function AIConfigContent() {
|
|
|
<div className="grid gap-6 md:grid-cols-2">
|
|
|
<div className="flex items-center justify-between">
|
|
|
<div className="space-y-1">
|
|
|
- <Label className="text-slate-300">Business Hours Mode</Label>
|
|
|
- <p className="text-sm text-slate-400">Adjust behavior based on store hours</p>
|
|
|
+ <Label className="text-slate-300">{t('aiConfig.conversationBehavior.businessHoursMode')}</Label>
|
|
|
+ <p className="text-sm text-slate-400">{t('aiConfig.conversationBehavior.businessHoursModeDesc')}</p>
|
|
|
</div>
|
|
|
<Switch
|
|
|
checked={aiConfig.business_hours_mode}
|
|
|
@@ -374,8 +376,8 @@ export function AIConfigContent() {
|
|
|
</div>
|
|
|
<div className="flex items-center justify-between">
|
|
|
<div className="space-y-1">
|
|
|
- <Label className="text-slate-300">Local Currency Support</Label>
|
|
|
- <p className="text-sm text-slate-400">Auto-detect customer location</p>
|
|
|
+ <Label className="text-slate-300">{t('aiConfig.conversationBehavior.localCurrencySupport')}</Label>
|
|
|
+ <p className="text-sm text-slate-400">{t('aiConfig.conversationBehavior.localCurrencySupportDesc')}</p>
|
|
|
</div>
|
|
|
<Switch
|
|
|
checked={aiConfig.local_currency_support}
|
|
|
@@ -386,15 +388,15 @@ export function AIConfigContent() {
|
|
|
</div>
|
|
|
|
|
|
<div className="space-y-2">
|
|
|
- <Label className="text-slate-300">Escalation Policy</Label>
|
|
|
+ <Label className="text-slate-300">{t('aiConfig.conversationBehavior.escalationPolicy')}</Label>
|
|
|
<Select value={aiConfig.escalation_policy} onValueChange={(value) => setAiConfig({ ...aiConfig, escalation_policy: value })}>
|
|
|
<SelectTrigger className="bg-slate-700 border-slate-600 text-white">
|
|
|
<SelectValue />
|
|
|
</SelectTrigger>
|
|
|
<SelectContent className="bg-slate-700 border-slate-600">
|
|
|
- <SelectItem value="low">Quick Escalation - Transfer to human quickly</SelectItem>
|
|
|
- <SelectItem value="medium">Balanced - Try to resolve then escalate</SelectItem>
|
|
|
- <SelectItem value="high">AI First - Extensive AI resolution attempts</SelectItem>
|
|
|
+ <SelectItem value="low">{t('aiConfig.conversationBehavior.escalationPolicies.low')}</SelectItem>
|
|
|
+ <SelectItem value="medium">{t('aiConfig.conversationBehavior.escalationPolicies.medium')}</SelectItem>
|
|
|
+ <SelectItem value="high">{t('aiConfig.conversationBehavior.escalationPolicies.high')}</SelectItem>
|
|
|
</SelectContent>
|
|
|
</Select>
|
|
|
</div>
|
|
|
@@ -405,47 +407,47 @@ export function AIConfigContent() {
|
|
|
<CardHeader>
|
|
|
<div className="flex items-center gap-3">
|
|
|
<Brain className="w-6 h-6 text-cyan-500" />
|
|
|
- <CardTitle className="text-white">Knowledge Base</CardTitle>
|
|
|
+ <CardTitle className="text-white">{t('aiConfig.knowledgeBase.title')}</CardTitle>
|
|
|
</div>
|
|
|
- <p className="text-slate-400">Training data specific to {selectedStore.store_name || 'your store'}</p>
|
|
|
+ <p className="text-slate-400">{t('aiConfig.knowledgeBase.subtitle')} {selectedStore.store_name || 'your store'}</p>
|
|
|
</CardHeader>
|
|
|
<CardContent className="space-y-6">
|
|
|
<div className="grid gap-4 md:grid-cols-3">
|
|
|
<div className="p-4 bg-slate-700/50 rounded-lg">
|
|
|
<div className="flex items-center justify-between mb-2">
|
|
|
- <h4 className="text-white font-medium">Product Catalog</h4>
|
|
|
+ <h4 className="text-white font-medium">{t('aiConfig.knowledgeBase.productCatalog')}</h4>
|
|
|
<Badge className={`${selectedStore.sync_status === 'completed' ? 'bg-green-500' : 'bg-slate-500'} text-white`}>
|
|
|
- {selectedStore.sync_status === 'completed' ? 'Synced' : 'Not Synced'}
|
|
|
+ {selectedStore.sync_status === 'completed' ? t('aiConfig.knowledgeBase.synced') : t('aiConfig.knowledgeBase.notSynced')}
|
|
|
</Badge>
|
|
|
</div>
|
|
|
<p className="text-slate-400 text-sm">
|
|
|
- {selectedStore.alt_data?.last_sync_stats?.products?.synced || 0} products
|
|
|
+ {selectedStore.alt_data?.last_sync_stats?.products?.synced || 0} {t('aiConfig.knowledgeBase.products')}
|
|
|
</p>
|
|
|
- <p className="text-slate-500 text-xs capitalize">Auto-sync from {selectedStore.platform_name}</p>
|
|
|
+ <p className="text-slate-500 text-xs capitalize">{t('aiConfig.knowledgeBase.autoSync')} {selectedStore.platform_name}</p>
|
|
|
</div>
|
|
|
<div className="p-4 bg-slate-700/50 rounded-lg">
|
|
|
<div className="flex items-center justify-between mb-2">
|
|
|
- <h4 className="text-white font-medium">Orders</h4>
|
|
|
+ <h4 className="text-white font-medium">{t('aiConfig.knowledgeBase.orders')}</h4>
|
|
|
<Badge className={`${selectedStore.sync_status === 'completed' ? 'bg-green-500' : 'bg-slate-500'} text-white`}>
|
|
|
- {selectedStore.sync_status === 'completed' ? 'Synced' : 'Not Synced'}
|
|
|
+ {selectedStore.sync_status === 'completed' ? t('aiConfig.knowledgeBase.synced') : t('aiConfig.knowledgeBase.notSynced')}
|
|
|
</Badge>
|
|
|
</div>
|
|
|
<p className="text-slate-400 text-sm">
|
|
|
- {selectedStore.alt_data?.last_sync_stats?.orders?.synced || 0} orders
|
|
|
+ {selectedStore.alt_data?.last_sync_stats?.orders?.synced || 0} {t('aiConfig.knowledgeBase.ordersCount')}
|
|
|
</p>
|
|
|
- <p className="text-slate-500 text-xs">Order history</p>
|
|
|
+ <p className="text-slate-500 text-xs">{t('aiConfig.knowledgeBase.orderHistory')}</p>
|
|
|
</div>
|
|
|
<div className="p-4 bg-slate-700/50 rounded-lg">
|
|
|
<div className="flex items-center justify-between mb-2">
|
|
|
- <h4 className="text-white font-medium">Customers</h4>
|
|
|
+ <h4 className="text-white font-medium">{t('aiConfig.knowledgeBase.customers')}</h4>
|
|
|
<Badge className={`${selectedStore.sync_status === 'completed' ? 'bg-green-500' : 'bg-slate-500'} text-white`}>
|
|
|
- {selectedStore.sync_status === 'completed' ? 'Synced' : 'Not Synced'}
|
|
|
+ {selectedStore.sync_status === 'completed' ? t('aiConfig.knowledgeBase.synced') : t('aiConfig.knowledgeBase.notSynced')}
|
|
|
</Badge>
|
|
|
</div>
|
|
|
<p className="text-slate-400 text-sm">
|
|
|
- {selectedStore.alt_data?.last_sync_stats?.customers?.synced || 0} customers
|
|
|
+ {selectedStore.alt_data?.last_sync_stats?.customers?.synced || 0} {t('aiConfig.knowledgeBase.customersCount')}
|
|
|
</p>
|
|
|
- <p className="text-slate-500 text-xs">Customer database</p>
|
|
|
+ <p className="text-slate-500 text-xs">{t('aiConfig.knowledgeBase.customerDatabase')}</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
@@ -454,7 +456,7 @@ export function AIConfigContent() {
|
|
|
className="bg-cyan-500 hover:bg-cyan-600 text-white"
|
|
|
onClick={() => window.location.href = `/manage-store-data?shop=${selectedStore.id}`}
|
|
|
>
|
|
|
- Manage Store Data
|
|
|
+ {t('aiConfig.knowledgeBase.manageStoreData')}
|
|
|
</Button>
|
|
|
</div>
|
|
|
</CardContent>
|