import { t, i18n } from '../../i18n.js'
import { auth } from '../../services/auth.js'
import { favoritesService } from '../../services/favorites.js'
import { getCurrencySymbol, SUPPORTED_CURRENCIES } from '../../services/currency.js'
class PageSettings extends HTMLElement {
constructor() {
super()
this.isLoggedIn = false
this.user = null
this.uidVisible = false
}
async connectedCallback() {
this.isLoggedIn = auth.isLoggedIn()
if (!this.isLoggedIn) {
window.location.hash = '#/'
return
}
this.user = await auth.getUser()
this.render()
this.setupEventListeners()
this._unsubs = []
this._unsubs.push(i18n.subscribe(() => {
this.render()
this.setupEventListeners()
}))
this._unsubs.push(auth.subscribe(() => {
this.isLoggedIn = auth.isLoggedIn()
if (!this.isLoggedIn) {
window.location.hash = '#/'
}
}))
}
disconnectedCallback() {
this._unsubs.forEach(fn => fn())
this._unsubs = []
}
setupEventListeners() {
// Theme toggle
this.querySelectorAll('input[name="theme"]').forEach(input => {
input.addEventListener('change', (e) => {
this.setTheme(e.target.value)
})
})
// Language select
this.querySelector('#lang-select')?.addEventListener('change', async (e) => {
i18n.setLocale(e.target.value)
// Save to user profile if logged in
if (this.isLoggedIn) {
await auth.updatePreferences({ preferred_locale: e.target.value })
}
})
// Currency select
this.querySelector('#currency-select')?.addEventListener('change', async (e) => {
await this.setCurrency(e.target.value)
this.showToast(t('settings.currencyChanged'))
})
// Clear favorites
this.querySelector('#clear-favorites')?.addEventListener('click', async () => {
if (confirm(t('settings.confirmClearFavorites'))) {
const ids = favoritesService.getAll()
for (const id of ids) {
await favoritesService.toggle(id)
}
this.showToast(t('settings.favoritesCleared'))
}
})
// Clear search history
this.querySelector('#clear-search')?.addEventListener('click', () => {
if (confirm(t('settings.confirmClearSearch'))) {
localStorage.removeItem('searchFilters')
this.showToast(t('settings.searchCleared'))
}
})
// Delete all local data
this.querySelector('#clear-all-data')?.addEventListener('click', async () => {
if (confirm(t('settings.confirmDeleteAll'))) {
await auth.clearAllData()
window.location.hash = '#/'
window.location.reload()
}
})
// Toggle UUID visibility
this.querySelector('#toggle-uid-btn')?.addEventListener('click', () => {
this.uidVisible = !this.uidVisible
const display = this.querySelector('#user-id-display')
const eyeIcon = this.querySelector('#toggle-uid-btn .icon-eye')
const eyeOffIcon = this.querySelector('#toggle-uid-btn .icon-eye-off')
if (display) {
display.textContent = this.uidVisible
? auth.getStoredUuid()
: '••••••••-••••-••••-••••-••••••••••••'
}
if (eyeIcon) eyeIcon.style.display = this.uidVisible ? 'none' : 'block'
if (eyeOffIcon) eyeOffIcon.style.display = this.uidVisible ? 'block' : 'none'
})
// Copy UUID
this.querySelector('#copy-uid-btn')?.addEventListener('click', async () => {
const uuid = auth.getStoredUuid()
if (uuid) {
await navigator.clipboard.writeText(uuid)
this.showToast(t('auth.copy') + ' ✓')
}
})
// Logout
this.querySelector('#logout-btn')?.addEventListener('click', () => {
auth.logout()
this.showToast(t('settings.loggedOut'))
})
// Login
this.querySelector('#login-btn')?.addEventListener('click', () => {
document.querySelector('auth-modal')?.show()
})
}
setTheme(theme) {
if (theme === 'system') {
localStorage.removeItem('theme')
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
document.documentElement.dataset.theme = prefersDark ? 'dark' : 'light'
} else {
localStorage.setItem('theme', theme)
document.documentElement.dataset.theme = theme
}
}
getCurrentTheme() {
return localStorage.getItem('theme') || 'system'
}
getCurrentCurrency() {
return localStorage.getItem('kashilo_currency') || 'USD'
}
async setCurrency(currency) {
localStorage.setItem('kashilo_currency', currency)
window.dispatchEvent(new CustomEvent('currency-changed', { detail: { currency } }))
// Save to user profile if logged in
if (auth.isLoggedIn()) {
await auth.updatePreferences({ preferred_currency: currency })
}
}
showToast(message) {
const existing = document.querySelector('.settings-toast')
existing?.remove()
const toast = document.createElement('div')
toast.className = 'settings-toast'
toast.textContent = message
document.body.appendChild(toast)
requestAnimationFrame(() => toast.classList.add('visible'))
setTimeout(() => {
toast.classList.remove('visible')
setTimeout(() => toast.remove(), 300)
}, 2000)
}
render() {
const currentTheme = this.getCurrentTheme()
const currentLang = i18n.getLocale()
const user = this.user
this.innerHTML = /* html */`
${t('settings.appearance')}
${t('settings.account')}
${this.isLoggedIn ? /* html */`
${t('settings.userIdHint')}
${'•'.repeat(8)}-••••-••••-••••-${'•'.repeat(12)}
` : /* html */`
${t('settings.notLoggedIn')}
`}
${t('settings.data')}
${t('settings.favoritesHint')}
${t('settings.searchHistoryHint')}
${t('settings.deleteAllDataHint')}
${t('settings.about')}
kashilo.com v1.0.0
`
}
}
customElements.define('page-settings', PageSettings)
const style = document.createElement('style')
style.textContent = /* css */`
page-settings .settings-page {
padding: var(--space-lg) 0;
max-width: 600px;
}
page-settings .page-header {
margin-bottom: var(--space-xl);
}
page-settings .page-header h1 {
margin: 0;
}
page-settings .settings-sections {
display: flex;
flex-direction: column;
gap: var(--space-xl);
}
page-settings .settings-section {
background: var(--color-bg-secondary);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
padding: var(--space-lg);
}
page-settings .settings-section h2 {
font-size: var(--font-size-lg);
margin: 0 0 var(--space-lg);
padding-bottom: var(--space-sm);
border-bottom: 1px solid var(--color-border);
}
page-settings .setting-item {
display: flex;
justify-content: space-between;
align-items: center;
gap: var(--space-md);
padding: var(--space-sm) 0;
}
page-settings .setting-item-column {
flex-direction: column;
align-items: stretch;
}
page-settings .setting-item + .setting-item {
border-top: 1px solid var(--color-border);
margin-top: var(--space-sm);
padding-top: var(--space-md);
}
page-settings .setting-item > label {
font-weight: var(--font-weight-medium);
}
page-settings .setting-hint {
font-size: var(--font-size-sm);
color: var(--color-text-muted);
margin: var(--space-xs) 0 0;
}
page-settings .theme-options {
display: flex;
gap: var(--space-sm);
}
page-settings .theme-option {
display: flex;
align-items: center;
gap: var(--space-xs);
padding: var(--space-xs) var(--space-sm);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
cursor: pointer;
font-size: var(--font-size-sm);
transition: all var(--transition-fast);
}
page-settings .theme-option:has(input:checked) {
border-color: var(--color-primary);
background: var(--color-primary-light);
}
page-settings .theme-option input {
display: none;
}
page-settings select {
padding: var(--space-xs) var(--space-sm);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-bg);
color: var(--color-text);
font-size: var(--font-size-sm);
}
page-settings .user-id-row {
display: flex;
align-items: center;
gap: var(--space-xs);
flex-wrap: wrap;
}
page-settings .user-id-actions {
display: flex;
gap: var(--space-xs);
}
@media (max-width: 768px) {
page-settings .user-id-row {
flex-direction: column;
align-items: stretch;
}
page-settings .user-id-actions {
justify-content: flex-end;
}
}
page-settings .user-id {
flex: 1;
min-width: 0;
padding: var(--space-xs) var(--space-sm);
background: var(--color-bg-tertiary);
border-radius: var(--radius-sm);
font-size: var(--font-size-sm);
word-break: break-all;
letter-spacing: 0.05em;
}
page-settings .btn-icon-sm {
width: 32px;
height: 32px;
padding: 0;
flex-shrink: 0;
}
page-settings .btn-ghost {
background: transparent;
border: none;
color: var(--color-text-muted);
cursor: pointer;
border-radius: var(--radius-sm);
display: flex;
align-items: center;
justify-content: center;
transition: color var(--transition-fast), background var(--transition-fast);
}
page-settings .btn-ghost:hover {
color: var(--color-text);
background: var(--color-bg-secondary);
}
page-settings .btn-danger {
color: var(--color-error, #dc2626);
border-color: var(--color-error, #dc2626);
}
page-settings .btn-danger:hover {
background: var(--color-error, #dc2626);
color: white;
}
page-settings .about-links {
display: flex;
flex-wrap: wrap;
gap: var(--space-md);
margin-bottom: var(--space-md);
}
page-settings .about-links a {
color: var(--color-text-secondary);
text-decoration: none;
}
page-settings .about-links a:hover {
color: var(--color-primary);
}
page-settings .version {
font-size: var(--font-size-sm);
color: var(--color-text-muted);
margin: 0;
}
@media (max-width: 768px) {
page-settings .setting-item {
flex-direction: column;
align-items: flex-start;
}
page-settings .theme-options {
flex-wrap: wrap;
}
}
/* Toast */
.settings-toast {
position: fixed;
bottom: var(--space-lg);
left: 50%;
transform: translateX(-50%) translateY(100px);
padding: var(--space-sm) var(--space-lg);
background: var(--color-bg-secondary);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
box-shadow: var(--shadow-lg);
opacity: 0;
transition: all 0.3s ease;
z-index: 1000;
}
.settings-toast.visible {
transform: translateX(-50%) translateY(0);
opacity: 1;
}
`
document.head.appendChild(style)