import React, { useState, useEffect, useCallback } from 'react'; import { StyleSheet, View, Text, TouchableOpacity, ScrollView, ActivityIndicator, Switch, StatusBar, Alert } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { supabase } from '../../lib/supabase'; import { COLORS, SHADOWS } from '../../styles/theme'; import { Cpu, Database, ShieldCheck, Save, RotateCcw, Clock, Bell, Inbox } from 'lucide-react-native'; import { useNotification } from '../../components/NotificationProvider'; import * as Haptics from 'expo-haptics'; const StepperControl = ({ label, value, onValueChange, min = 0.1, max = 1.0, step = 0.05, suffix = '%' }) => { const handleDecrement = () => { if (value > min) { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); onValueChange(Math.max(min, parseFloat((value - step).toFixed(2)))); } }; const handleIncrement = () => { if (value < max) { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); onValueChange(Math.min(max, parseFloat((value + step).toFixed(2)))); } }; const displayValue = suffix === '%' ? `${(value * 100).toFixed(0)}%` : value.toFixed(0); return ( {label} - {displayValue} = max && styles.disabledBtn]} onPress={handleIncrement} disabled={value >= max} > + ); }; const AdminSettingsScreen = () => { const { success, error: toastError } = useNotification(); const [profile, setProfile] = useState(null); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); // Settings states const [confidenceThreshold, setConfidenceThreshold] = useState(0.80); const [duplicateSensitivity, setDuplicateSensitivity] = useState(0.85); const [enableAutoResolve, setEnableAutoResolve] = useState(false); const [autoCloseEnabled, setAutoCloseEnabled] = useState(true); const [autoCloseDays, setAutoCloseDays] = useState(7); const [emailNotifications, setEmailNotifications] = useState(true); const [adminAlerts, setAdminAlerts] = useState(true); const [digestFrequency, setDigestFrequency] = useState('daily'); // 'daily' | 'weekly' const fetchSettings = useCallback(async () => { try { const { data: { user } } = await supabase.auth.getUser(); if (!user) return; const { data: profileData } = await supabase .from('profiles') .select('*') .eq('id', user.id) .single(); if (profileData) { setProfile(profileData); const companyId = profileData.company_id; if (companyId) { // Fetch settings from system_settings const { data: settings, error } = await supabase .from('system_settings') .select('*') .eq('company_id', companyId) .single(); if (!error && settings) { setConfidenceThreshold(settings.ai_confidence_threshold ?? 0.80); setDuplicateSensitivity(settings.duplicate_sensitivity ?? 0.85); setEnableAutoResolve(settings.enable_auto_resolve ?? false); setAutoCloseEnabled(settings.auto_close_enabled ?? true); setAutoCloseDays(settings.auto_close_days ?? 7); setEmailNotifications(settings.email_notifications ?? true); setAdminAlerts(settings.admin_alerts ?? true); setDigestFrequency(settings.digest_frequency ?? 'daily'); } } } } catch (e) { console.error('Fetch settings error:', e); } finally { setLoading(false); } }, []); useEffect(() => { fetchSettings(); }, [fetchSettings]); const handleSaveSettings = async () => { const companyId = profile?.company_id; if (!companyId) { toastError("Link Error", "Your profile is not associated with any company."); return; } Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success); setSaving(true); try { // Upsert into system_settings mapping to precise columns const { error } = await supabase .from('system_settings') .upsert({ company_id: companyId, ai_confidence_threshold: confidenceThreshold, duplicate_sensitivity: duplicateSensitivity, enable_auto_resolve: enableAutoResolve, auto_close_enabled: autoCloseEnabled, auto_close_days: autoCloseDays, email_notifications: emailNotifications, admin_alerts: adminAlerts, digest_frequency: digestFrequency, updated_at: new Date().toISOString() }); if (error) { console.error('Save settings error details:', error); toastError("Save Failed", "Could not synchronize settings to database."); } else { success("Settings Saved", "AI thresholds and SLA guidelines synchronized successfully!"); } } catch (e) { console.error(e); toastError("Error", "An unexpected error occurred during save."); } finally { setSaving(false); } }; const handleReset = () => { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); setConfidenceThreshold(0.80); setDuplicateSensitivity(0.85); setEnableAutoResolve(false); setAutoCloseEnabled(true); setAutoCloseDays(7); setEmailNotifications(true); setAdminAlerts(true); setDigestFrequency('daily'); }; if (loading) { return ( ); } return ( {/* Header */} System Settings {/* Section 1: AI Engine Benchmarks */} AI Neural Benchmarks Configure standard confidence limits to bypass manual ticketing queues. Tickets with category classification confidence above this threshold will bypass manual triage. AI Auto-Resolution Allow the system to automatically close tickets when a verified solution RAG score exceeds 95%. { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); setEnableAutoResolve(val); }} trackColor={{ false: '#e5e7eb', true: COLORS.primaryLight }} thumbColor={enableAutoResolve ? COLORS.primary : '#9ca3af'} /> {/* Section 2: Duplication Parameters */} Duplicate Mitigation Adjust semantic limits to identify duplicate support inquiries automatically. A higher percentage demands exact word matching, while a lower percentage flags conceptual duplicates. {/* Section 3: Auto-Close Tickets */} Auto-Close Settings Configure standard procedures for resolving ticket inactivity. Auto-Close Inactive Automatically archive resolved tickets after a period of user inactivity. { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); setAutoCloseEnabled(val); }} trackColor={{ false: '#e5e7eb', true: COLORS.primaryLight }} thumbColor={autoCloseEnabled ? COLORS.primary : '#9ca3af'} /> {autoCloseEnabled && ( <> )} {/* Section 4: Notifications and Digests */} Notifications & Digests Configure administrator alert guidelines and scheduled digest updates. Email Notifications Receive summary digests and incident reports via work email. { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); setEmailNotifications(val); }} trackColor={{ false: '#e5e7eb', true: COLORS.primaryLight }} thumbColor={emailNotifications ? COLORS.primary : '#9ca3af'} /> Critical Admin Alerts Enable push notifications for critical Priority 1 events. { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); setAdminAlerts(val); }} trackColor={{ false: '#e5e7eb', true: COLORS.primaryLight }} thumbColor={adminAlerts ? COLORS.primary : '#9ca3af'} /> {emailNotifications && ( <> Digest Frequency { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); setDigestFrequency('daily'); }} > Daily { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); setDigestFrequency('weekly'); }} > Weekly )} {/* Section 5: SLA Guidelines Summary */} SLA Policies & Breach Targets Configure escalation times based on priority categories. Critical Priority SLA Breach target: 2 Hours High Priority SLA Breach target: 8 Hours Medium Priority SLA Breach target: 24 Hours Low Priority SLA Breach target: 72 Hours {/* Action buttons */} Reset Defaults {saving ? ( ) : ( <> Save Settings )} ); }; const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: COLORS.background }, loadingWrap: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: COLORS.background }, header: { paddingHorizontal: 24, paddingTop: 16, paddingBottom: 16 }, title: { fontSize: 28, fontWeight: '900', color: COLORS.text, letterSpacing: -0.8 }, scrollContent: { paddingBottom: 120 }, // Section card sectionCard: { backgroundColor: '#fff', borderRadius: 24, marginHorizontal: 20, padding: 20, marginBottom: 16, borderWidth: 1, borderColor: 'rgba(0,0,0,0.03)', ...SHADOWS.soft, }, sectionHeader: { flexDirection: 'row', alignItems: 'center', gap: 10, marginBottom: 8 }, sectionTitle: { fontSize: 16, fontWeight: '900', color: COLORS.text }, sectionDesc: { fontSize: 12.5, color: COLORS.textMuted, fontWeight: '600', lineHeight: 18, marginBottom: 16 }, // Controls list controlsList: { gap: 12 }, settingControlRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }, controlLabel: { fontSize: 14, fontWeight: '800', color: COLORS.text }, // Steppers stepperContainer: { flexDirection: 'row', alignItems: 'center', backgroundColor: '#f3f4f6', borderRadius: 12, padding: 4, height: 40 }, stepperBtn: { width: 32, height: 32, borderRadius: 8, backgroundColor: '#fff', justifyContent: 'center', alignItems: 'center', ...SHADOWS.soft }, disabledBtn: { opacity: 0.4 }, stepperBtnText: { fontSize: 16, fontWeight: '800', color: COLORS.text }, stepperValueContainer: { minWidth: 60, alignItems: 'center', justifyContent: 'center' }, stepperValueText: { fontSize: 13, fontWeight: '800', color: COLORS.text }, frequencyPicker: { flexDirection: 'row', backgroundColor: '#f3f4f6', padding: 3, borderRadius: 10 }, freqBtn: { paddingHorizontal: 12, paddingVertical: 6, borderRadius: 8 }, activeFreqBtn: { backgroundColor: '#fff', ...SHADOWS.soft }, freqBtnText: { fontSize: 11, fontWeight: '700', color: COLORS.textMuted }, activeFreqBtnText: { color: COLORS.text, fontWeight: '900' }, helpText: { fontSize: 11.5, color: COLORS.textMuted, fontWeight: '500', lineHeight: 16, marginTop: 4 }, separator: { height: 1, backgroundColor: 'rgba(0,0,0,0.05)', marginVertical: 8 }, policyRow: { flexDirection: 'row', alignItems: 'center', gap: 10, marginVertical: 6, paddingHorizontal: 4 }, policyDot: { width: 8, height: 8, borderRadius: 4 }, policyText: { fontSize: 13, color: COLORS.textLight, fontWeight: '500' }, boldText: { fontWeight: '800', color: COLORS.text }, // Buttons btnRow: { flexDirection: 'row', gap: 12, marginHorizontal: 20, marginTop: 8 }, resetBtn: { flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 8, backgroundColor: '#fff', height: 52, borderRadius: 18, borderWidth: 1.5, borderColor: 'rgba(0,0,0,0.08)', ...SHADOWS.soft }, resetBtnText: { fontSize: 14, fontWeight: '800', color: COLORS.textLight }, saveBtn: { flex: 1.5, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 8, backgroundColor: COLORS.primary, height: 52, borderRadius: 18, ...SHADOWS.medium, shadowColor: COLORS.primary }, saveBtnText: { fontSize: 14, fontWeight: '800', color: '#fff' } }); export default AdminSettingsScreen;