refactoring: TypeScript migration, security fixes,

This commit is contained in:
Maurice
2026-03-27 18:40:18 +01:00
parent 510475a46f
commit 8396a75223
150 changed files with 8116 additions and 8467 deletions
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'
import { useEffect, useState } from 'react'
import { adminApi } from '../../api/client'
import { useTranslation } from '../../i18n'
import { useSettingsStore } from '../../store/settingsStore'
@@ -9,7 +9,20 @@ const ICON_MAP = {
ListChecks, Wallet, FileText, CalendarDays, Puzzle, Globe, Briefcase,
}
function AddonIcon({ name, size = 20 }) {
interface Addon {
id: string
name: string
description: string
icon: string
enabled: boolean
}
interface AddonIconProps {
name: string
size?: number
}
function AddonIcon({ name, size = 20 }: AddonIconProps) {
const Icon = ICON_MAP[name] || Puzzle
return <Icon size={size} />
}
@@ -31,7 +44,7 @@ export default function AddonManager() {
try {
const data = await adminApi.addons()
setAddons(data.addons)
} catch (err) {
} catch (err: unknown) {
toast.error(t('admin.addons.toast.error'))
} finally {
setLoading(false)
@@ -46,7 +59,7 @@ export default function AddonManager() {
await adminApi.updateAddon(addon.id, { enabled: newEnabled })
window.dispatchEvent(new Event('addons-changed'))
toast.success(t('admin.addons.toast.updated'))
} catch (err) {
} catch (err: unknown) {
// Rollback
setAddons(prev => prev.map(a => a.id === addon.id ? { ...a, enabled: !newEnabled } : a))
toast.error(t('admin.addons.toast.error'))
@@ -117,7 +130,13 @@ export default function AddonManager() {
)
}
function AddonRow({ addon, onToggle, t }) {
interface AddonRowProps {
addon: Addon
onToggle: (addonId: string) => void
t: (key: string) => string
}
function AddonRow({ addon, onToggle, t }: AddonRowProps) {
const isComingSoon = false
return (
<div className="flex items-center gap-4 px-6 py-4 border-b transition-colors hover:opacity-95" style={{ borderColor: 'var(--border-secondary)', opacity: isComingSoon ? 0.5 : 1, pointerEvents: isComingSoon ? 'none' : 'auto' }}>
@@ -1,8 +1,9 @@
import React, { useState, useEffect, useRef } from 'react'
import { useState, useEffect, useRef } from 'react'
import { backupApi } from '../../api/client'
import { useToast } from '../shared/Toast'
import { Download, Trash2, Plus, RefreshCw, RotateCcw, Upload, Clock, Check, HardDrive, AlertTriangle } from 'lucide-react'
import { useTranslation } from '../../i18n'
import { getApiErrorMessage } from '../../types'
const INTERVAL_OPTIONS = [
{ value: 'hourly', labelKey: 'backup.interval.hourly' },
@@ -73,7 +74,7 @@ export default function BackupPanel() {
}
const handleUploadRestore = (e) => {
const file = e.target.files?.[0]
const file = (e.target as HTMLInputElement).files?.[0]
if (!file) return
e.target.value = ''
setRestoreConfirm({ type: 'upload', filename: file.name, file })
@@ -90,8 +91,8 @@ export default function BackupPanel() {
await backupApi.restore(filename)
toast.success(t('backup.toast.restored'))
setTimeout(() => window.location.reload(), 1500)
} catch (err) {
toast.error(err.response?.data?.error || t('backup.toast.restoreError'))
} catch (err: unknown) {
toast.error(getApiErrorMessage(err, t('backup.toast.restoreError')))
setRestoringFile(null)
}
} else {
@@ -100,8 +101,8 @@ export default function BackupPanel() {
await backupApi.uploadRestore(file)
toast.success(t('backup.toast.restored'))
setTimeout(() => window.location.reload(), 1500)
} catch (err) {
toast.error(err.response?.data?.error || t('backup.toast.uploadError'))
} catch (err: unknown) {
toast.error(getApiErrorMessage(err, t('backup.toast.uploadError')))
setIsUploading(false)
}
}
@@ -1,9 +1,10 @@
import React, { useState, useEffect, useRef } from 'react'
import { useState, useEffect, useRef } from 'react'
import { categoriesApi } from '../../api/client'
import { useToast } from '../shared/Toast'
import { Plus, Edit2, Trash2, Pipette } from 'lucide-react'
import { CATEGORY_ICON_MAP, ICON_LABELS, getCategoryIcon } from '../shared/categoryIcons'
import { useTranslation } from '../../i18n'
import { getApiErrorMessage } from '../../types'
const PRESET_COLORS = [
'#6366f1', '#8b5cf6', '#ec4899', '#ef4444', '#f97316',
@@ -31,7 +32,7 @@ export default function CategoryManager() {
try {
const data = await categoriesApi.list()
setCategories(data.categories || [])
} catch (err) {
} catch (err: unknown) {
toast.error(t('categories.toast.loadError'))
} finally {
setIsLoading(false)
@@ -71,8 +72,8 @@ export default function CategoryManager() {
toast.success(t('categories.toast.created'))
}
setForm({ name: '', color: '#6366f1', icon: 'MapPin' })
} catch (err) {
toast.error(err.response?.data?.error || t('categories.toast.saveError'))
} catch (err: unknown) {
toast.error(getApiErrorMessage(err, t('categories.toast.saveError')))
} finally {
setIsSaving(false)
}
@@ -84,8 +85,8 @@ export default function CategoryManager() {
await categoriesApi.delete(id)
setCategories(prev => prev.filter(c => c.id !== id))
toast.success(t('categories.toast.deleted'))
} catch (err) {
toast.error(err.response?.data?.error || t('categories.toast.deleteError'))
} catch (err: unknown) {
toast.error(getApiErrorMessage(err, t('categories.toast.deleteError')))
}
}
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react'
import { useState, useEffect } from 'react'
import { Tag, Calendar, ExternalLink, ChevronDown, ChevronUp, Loader2 } from 'lucide-react'
import { useTranslation } from '../../i18n'
@@ -22,8 +22,8 @@ export default function GitHubPanel() {
const data = await res.json()
setReleases(prev => append ? [...prev, ...data] : data)
setHasMore(data.length === PER_PAGE)
} catch (err) {
setError(err.message)
} catch (err: unknown) {
setError(err instanceof Error ? err.message : 'Unknown error')
}
}