201 lines
6.5 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client'
import { useState } from 'react'
import { SettingsNav, SettingsSection, SettingToggle, SettingInput } from '@/components/settings'
import { Button } from '@/components/ui/button'
import { Download, Upload, Trash2, Loader2, Check } from 'lucide-react'
import { toast } from 'sonner'
export default function DataSettingsPage() {
const [isExporting, setIsExporting] = useState(false)
const [isImporting, setIsImporting] = useState(false)
const [isDeleting, setIsDeleting] = useState(false)
const [exportUrl, setExportUrl] = useState('')
const handleExport = async () => {
setIsExporting(true)
try {
const response = await fetch('/api/notes/export')
if (response.ok) {
const blob = await response.blob()
const url = window.URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `keep-notes-export-${new Date().toISOString().split('T')[0]}.json`
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
window.URL.revokeObjectURL(url)
toast.success('Notes exported successfully')
}
} catch (error) {
console.error('Export error:', error)
toast.error('Failed to export notes')
} finally {
setIsExporting(false)
}
}
const handleImport = async (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0]
if (!file) return
setIsImporting(true)
try {
const formData = new FormData()
formData.append('file', file)
const response = await fetch('/api/notes/import', {
method: 'POST',
body: formData
})
if (response.ok) {
const result = await response.json()
toast.success(`Imported ${result.count} notes`)
// Refresh the page to show imported notes
window.location.reload()
} else {
throw new Error('Import failed')
}
} catch (error) {
console.error('Import error:', error)
toast.error('Failed to import notes')
} finally {
setIsImporting(false)
// Reset input
event.target.value = ''
}
}
const handleDeleteAll = async () => {
if (!confirm('Are you sure you want to delete all notes? This action cannot be undone.')) {
return
}
setIsDeleting(true)
try {
const response = await fetch('/api/notes/delete-all', { method: 'POST' })
if (response.ok) {
toast.success('All notes deleted')
window.location.reload()
}
} catch (error) {
console.error('Delete error:', error)
toast.error('Failed to delete notes')
} finally {
setIsDeleting(false)
}
}
return (
<div className="container mx-auto py-10 px-4 max-w-6xl">
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
{/* Sidebar Navigation */}
<aside className="lg:col-span-1">
<SettingsNav />
</aside>
{/* Main Content */}
<main className="lg:col-span-3 space-y-6">
<div>
<h1 className="text-3xl font-bold mb-2">Data Management</h1>
<p className="text-gray-600 dark:text-gray-400">
Export, import, or manage your data
</p>
</div>
<SettingsSection
title="Export Data"
icon={<span className="text-2xl">💾</span>}
description="Download your notes as a JSON file"
>
<div className="flex items-center justify-between py-4">
<div>
<p className="font-medium">Export All Notes</p>
<p className="text-sm text-gray-600 dark:text-gray-400">
Download all your notes in JSON format
</p>
</div>
<Button
onClick={handleExport}
disabled={isExporting}
>
{isExporting ? (
<Loader2 className="h-4 w-4 animate-spin mr-2" />
) : (
<Download className="h-4 w-4 mr-2" />
)}
{isExporting ? 'Exporting...' : 'Export'}
</Button>
</div>
</SettingsSection>
<SettingsSection
title="Import Data"
icon={<span className="text-2xl">📥</span>}
description="Import notes from a JSON file"
>
<div className="flex items-center justify-between py-4">
<div>
<p className="font-medium">Import Notes</p>
<p className="text-sm text-gray-600 dark:text-gray-400">
Upload a JSON file to import notes
</p>
</div>
<div>
<input
type="file"
accept=".json"
onChange={handleImport}
disabled={isImporting}
className="hidden"
id="import-file"
/>
<Button
onClick={() => document.getElementById('import-file')?.click()}
disabled={isImporting}
>
{isImporting ? (
<Loader2 className="h-4 w-4 animate-spin mr-2" />
) : (
<Upload className="h-4 w-4 mr-2" />
)}
{isImporting ? 'Importing...' : 'Import'}
</Button>
</div>
</div>
</SettingsSection>
<SettingsSection
title="Danger Zone"
icon={<span className="text-2xl"></span>}
description="Permanently delete your data"
>
<div className="flex items-center justify-between py-4 border-t border-red-200 dark:border-red-900">
<div>
<p className="font-medium text-red-600 dark:text-red-400">Delete All Notes</p>
<p className="text-sm text-gray-600 dark:text-gray-400">
This action cannot be undone
</p>
</div>
<Button
variant="destructive"
onClick={handleDeleteAll}
disabled={isDeleting}
>
{isDeleting ? (
<Loader2 className="h-4 w-4 animate-spin mr-2" />
) : (
<Trash2 className="h-4 w-4 mr-2" />
)}
{isDeleting ? 'Deleting...' : 'Delete All'}
</Button>
</div>
</SettingsSection>
</main>
</div>
</div>
)
}