Spaces:
Sleeping
Sleeping
| import React, { useState, useEffect } from 'react'; | |
| import { motion } from 'framer-motion'; | |
| import { toast } from 'react-toastify'; | |
| import { classNames } from '~/utils/classNames'; | |
| import { Switch } from '~/components/ui/Switch'; | |
| import type { UserProfile } from '~/components/@settings/core/types'; | |
| export default function SettingsTab() { | |
| const [currentTimezone, setCurrentTimezone] = useState(''); | |
| const [settings, setSettings] = useState<UserProfile>(() => { | |
| const saved = localStorage.getItem('bolt_user_profile'); | |
| return saved | |
| ? JSON.parse(saved) | |
| : { | |
| notifications: true, | |
| language: 'en', | |
| timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, | |
| }; | |
| }); | |
| useEffect(() => { | |
| setCurrentTimezone(Intl.DateTimeFormat().resolvedOptions().timeZone); | |
| }, []); | |
| // Save settings automatically when they change | |
| useEffect(() => { | |
| try { | |
| // Get existing profile data | |
| const existingProfile = JSON.parse(localStorage.getItem('bolt_user_profile') || '{}'); | |
| // Merge with new settings | |
| const updatedProfile = { | |
| ...existingProfile, | |
| notifications: settings.notifications, | |
| language: settings.language, | |
| timezone: settings.timezone, | |
| }; | |
| localStorage.setItem('bolt_user_profile', JSON.stringify(updatedProfile)); | |
| toast.success('Settings updated'); | |
| } catch (error) { | |
| console.error('Error saving settings:', error); | |
| toast.error('Failed to update settings'); | |
| } | |
| }, [settings]); | |
| return ( | |
| <div className="space-y-4"> | |
| {/* Language & Notifications */} | |
| <motion.div | |
| className="bg-white dark:bg-[#0A0A0A] rounded-lg shadow-sm dark:shadow-none p-4 space-y-4" | |
| initial={{ opacity: 0, y: 20 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| transition={{ delay: 0.1 }} | |
| > | |
| <div className="flex items-center gap-2 mb-4"> | |
| <div className="i-ph:palette-fill w-4 h-4 text-purple-500" /> | |
| <span className="text-sm font-medium text-bolt-elements-textPrimary">Preferences</span> | |
| </div> | |
| <div> | |
| <div className="flex items-center gap-2 mb-2"> | |
| <div className="i-ph:translate-fill w-4 h-4 text-bolt-elements-textSecondary" /> | |
| <label className="block text-sm text-bolt-elements-textSecondary">Language</label> | |
| </div> | |
| <select | |
| value={settings.language} | |
| onChange={(e) => setSettings((prev) => ({ ...prev, language: e.target.value }))} | |
| className={classNames( | |
| 'w-full px-3 py-2 rounded-lg text-sm', | |
| 'bg-[#FAFAFA] dark:bg-[#0A0A0A]', | |
| 'border border-[#E5E5E5] dark:border-[#1A1A1A]', | |
| 'text-bolt-elements-textPrimary', | |
| 'focus:outline-none focus:ring-2 focus:ring-purple-500/30', | |
| 'transition-all duration-200', | |
| )} | |
| > | |
| <option value="en">English</option> | |
| <option value="es">Español</option> | |
| <option value="fr">Français</option> | |
| <option value="de">Deutsch</option> | |
| <option value="it">Italiano</option> | |
| <option value="pt">Português</option> | |
| <option value="ru">Русский</option> | |
| <option value="zh">中文</option> | |
| <option value="ja">日本語</option> | |
| <option value="ko">한국어</option> | |
| </select> | |
| </div> | |
| <div> | |
| <div className="flex items-center gap-2 mb-2"> | |
| <div className="i-ph:bell-fill w-4 h-4 text-bolt-elements-textSecondary" /> | |
| <label className="block text-sm text-bolt-elements-textSecondary">Notifications</label> | |
| </div> | |
| <div className="flex items-center justify-between"> | |
| <span className="text-sm text-bolt-elements-textSecondary"> | |
| {settings.notifications ? 'Notifications are enabled' : 'Notifications are disabled'} | |
| </span> | |
| <Switch | |
| checked={settings.notifications} | |
| onCheckedChange={(checked) => { | |
| // Update local state | |
| setSettings((prev) => ({ ...prev, notifications: checked })); | |
| // Update localStorage immediately | |
| const existingProfile = JSON.parse(localStorage.getItem('bolt_user_profile') || '{}'); | |
| const updatedProfile = { | |
| ...existingProfile, | |
| notifications: checked, | |
| }; | |
| localStorage.setItem('bolt_user_profile', JSON.stringify(updatedProfile)); | |
| // Dispatch storage event for other components | |
| window.dispatchEvent( | |
| new StorageEvent('storage', { | |
| key: 'bolt_user_profile', | |
| newValue: JSON.stringify(updatedProfile), | |
| }), | |
| ); | |
| toast.success(`Notifications ${checked ? 'enabled' : 'disabled'}`); | |
| }} | |
| /> | |
| </div> | |
| </div> | |
| </motion.div> | |
| {/* Timezone */} | |
| <motion.div | |
| className="bg-white dark:bg-[#0A0A0A] rounded-lg shadow-sm dark:shadow-none p-4" | |
| initial={{ opacity: 0, y: 20 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| transition={{ delay: 0.2 }} | |
| > | |
| <div className="flex items-center gap-2 mb-4"> | |
| <div className="i-ph:clock-fill w-4 h-4 text-purple-500" /> | |
| <span className="text-sm font-medium text-bolt-elements-textPrimary">Time Settings</span> | |
| </div> | |
| <div> | |
| <div className="flex items-center gap-2 mb-2"> | |
| <div className="i-ph:globe-fill w-4 h-4 text-bolt-elements-textSecondary" /> | |
| <label className="block text-sm text-bolt-elements-textSecondary">Timezone</label> | |
| </div> | |
| <select | |
| value={settings.timezone} | |
| onChange={(e) => setSettings((prev) => ({ ...prev, timezone: e.target.value }))} | |
| className={classNames( | |
| 'w-full px-3 py-2 rounded-lg text-sm', | |
| 'bg-[#FAFAFA] dark:bg-[#0A0A0A]', | |
| 'border border-[#E5E5E5] dark:border-[#1A1A1A]', | |
| 'text-bolt-elements-textPrimary', | |
| 'focus:outline-none focus:ring-2 focus:ring-purple-500/30', | |
| 'transition-all duration-200', | |
| )} | |
| > | |
| <option value={currentTimezone}>{currentTimezone}</option> | |
| </select> | |
| </div> | |
| </motion.div> | |
| </div> | |
| ); | |
| } | |