Fixed banner upload bug

This commit is contained in:
Christopher
2026-01-22 12:05:51 -08:00
parent ee3d75d6b5
commit 812a986d0f
9 changed files with 490 additions and 40 deletions
+6 -3
View File
@@ -4,6 +4,7 @@ import { useState, useEffect } from 'react';
import Link from 'next/link';
import { ArrowLeftIcon } from '@/components/Icons';
import { useAuth } from '@/lib/contexts/AuthContext';
import { TriangleAlert, ShieldAlert } from 'lucide-react';
interface ExportStats {
posts: number;
@@ -286,8 +287,8 @@ export default function MigrationPage() {
border: '1px solid rgba(239, 68, 68, 0.3)',
borderRadius: '8px',
}}>
<div style={{ fontWeight: 600, color: 'var(--error)', marginBottom: '8px' }}>
Security Warning
<div style={{ fontWeight: 600, color: 'var(--error)', marginBottom: '8px', display: 'flex', alignItems: 'center', gap: '8px' }}>
<ShieldAlert size={18} /> Security Warning
</div>
<p style={{ fontSize: '13px', color: 'var(--foreground-secondary)', margin: 0 }}>
The export file contains your encrypted private key. Keep this file secure
@@ -368,7 +369,9 @@ export default function MigrationPage() {
style={{ marginTop: '4px' }}
/>
<span style={{ fontSize: '14px', color: 'var(--foreground-secondary)', lineHeight: 1.6 }}>
<strong style={{ color: 'var(--warning)' }}> Content Compliance:</strong> All of your post history
<strong style={{ color: 'var(--warning)', display: 'inline-flex', alignItems: 'center', gap: '4px' }}>
<TriangleAlert size={14} /> Content Compliance:
</strong> All of your post history
and content will be migrated to this node. It is your responsibility to ensure your content
complies with this node's rules. If you migrate content that violates this node's rules,
you may be subject to any moderation action the node operator sees fit.
+23 -17
View File
@@ -2,6 +2,7 @@
import Link from 'next/link';
import { ArrowLeftIcon } from '@/components/Icons';
import { Rocket, Shield, Bell } from 'lucide-react';
export default function SettingsPage() {
return (
@@ -31,34 +32,39 @@ export default function SettingsPage() {
color: 'var(--foreground)',
transition: 'border-color 0.15s ease',
}}>
<div style={{ fontWeight: 600, marginBottom: '4px' }}>
🚀 Account Migration
<div style={{ fontWeight: 600, marginBottom: '8px', display: 'flex', alignItems: 'center', gap: '8px' }}>
<Rocket size={18} />
Account Migration
</div>
<div style={{ color: 'var(--foreground-secondary)', fontSize: '14px' }}>
Export your account or import from another Synapsis node
</div>
</Link>
<Link href="/settings/security" className="card" style={{
display: 'block',
padding: '20px',
textDecoration: 'none',
color: 'var(--foreground)',
transition: 'border-color 0.15s ease',
}}>
<div style={{ fontWeight: 600, marginBottom: '8px', display: 'flex', alignItems: 'center', gap: '8px' }}>
<Shield size={18} />
Security
</div>
<div style={{ color: 'var(--foreground-secondary)', fontSize: '14px' }}>
Change password, manage sessions
</div>
</Link>
<div className="card" style={{
display: 'block',
padding: '20px',
opacity: 0.5,
}}>
<div style={{ fontWeight: 600, marginBottom: '4px' }}>
🔐 Security
</div>
<div style={{ color: 'var(--foreground-secondary)', fontSize: '14px' }}>
Change password, manage sessions (coming soon)
</div>
</div>
<div className="card" style={{
display: 'block',
padding: '20px',
opacity: 0.5,
}}>
<div style={{ fontWeight: 600, marginBottom: '4px' }}>
🔔 Notifications
<div style={{ fontWeight: 600, marginBottom: '8px', display: 'flex', alignItems: 'center', gap: '8px' }}>
<Bell size={18} />
Notifications
</div>
<div style={{ color: 'var(--foreground-secondary)', fontSize: '14px' }}>
Notification preferences (coming soon)
+213
View File
@@ -0,0 +1,213 @@
'use client';
import { useState } from 'react';
import Link from 'next/link';
import { ArrowLeftIcon } from '@/components/Icons';
import { Shield, Lock, Check, AlertCircle } from 'lucide-react';
export default function SecuritySettingsPage() {
const [currentPassword, setCurrentPassword] = useState('');
const [newPassword, setNewPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const [error, setError] = useState<string | null>(null);
const [success, setSuccess] = useState<string | null>(null);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError(null);
setSuccess(null);
// Validation
if (newPassword.length < 8) {
setError('New password must be at least 8 characters long');
return;
}
if (newPassword !== confirmPassword) {
setError('New passwords do not match');
return;
}
if (currentPassword === newPassword) {
setError('New password cannot be the same as the current password');
return;
}
setIsSubmitting(true);
try {
const res = await fetch('/api/account/password', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ currentPassword, newPassword }),
});
const data = await res.json();
if (!res.ok) {
throw new Error(data.error || 'Failed to change password');
}
setSuccess('Password updated successfully');
setCurrentPassword('');
setNewPassword('');
setConfirmPassword('');
} catch (error) {
setError(error instanceof Error ? error.message : 'An error occurred');
} finally {
setIsSubmitting(false);
}
};
return (
<div style={{ maxWidth: '600px', margin: '0 auto', padding: '24px 16px 64px' }}>
<header style={{
display: 'flex',
alignItems: 'center',
gap: '16px',
marginBottom: '32px',
}}>
<Link href="/settings" style={{ color: 'var(--foreground)' }}>
<ArrowLeftIcon />
</Link>
<div>
<h1 style={{ fontSize: '24px', fontWeight: 700 }}>Security</h1>
<p style={{ color: 'var(--foreground-tertiary)', fontSize: '14px' }}>
Manage your password and security settings
</p>
</div>
</header>
<div className="card" style={{ padding: '24px' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: '12px', marginBottom: '24px' }}>
<div style={{
width: '40px',
height: '40px',
borderRadius: '50%',
background: 'var(--background-tertiary)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}>
<Lock size={20} />
</div>
<div>
<h2 style={{ fontSize: '18px', fontWeight: 600 }}>Change Password</h2>
<p style={{ color: 'var(--foreground-secondary)', fontSize: '14px' }}>
Update your password to keep your account secure
</p>
</div>
</div>
<form onSubmit={handleSubmit}>
<div style={{ marginBottom: '20px' }}>
<label style={{ fontSize: '13px', color: 'var(--foreground-tertiary)', display: 'block', marginBottom: '6px' }}>
Current Password
</label>
<input
type="password"
className="input"
value={currentPassword}
onChange={(e) => setCurrentPassword(e.target.value)}
placeholder="Enter current password"
required
/>
</div>
<div style={{ marginBottom: '20px' }}>
<label style={{ fontSize: '13px', color: 'var(--foreground-tertiary)', display: 'block', marginBottom: '6px' }}>
New Password
</label>
<input
type="password"
className="input"
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
placeholder="Enter new password (min. 8 characters)"
required
/>
</div>
<div style={{ marginBottom: '24px' }}>
<label style={{ fontSize: '13px', color: 'var(--foreground-tertiary)', display: 'block', marginBottom: '6px' }}>
Confirm New Password
</label>
<input
type="password"
className="input"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
placeholder="Confirm new password"
required
/>
</div>
{error && (
<div style={{
padding: '12px',
background: 'rgba(239, 68, 68, 0.1)',
border: '1px solid rgba(239, 68, 68, 0.2)',
borderRadius: '8px',
color: 'var(--error)',
fontSize: '14px',
marginBottom: '20px',
display: 'flex',
alignItems: 'center',
gap: '8px',
}}>
<AlertCircle size={16} />
{error}
</div>
)}
{success && (
<div style={{
padding: '12px',
background: 'rgba(34, 197, 94, 0.1)',
border: '1px solid rgba(34, 197, 94, 0.2)',
borderRadius: '8px',
color: 'var(--success)',
fontSize: '14px',
marginBottom: '20px',
display: 'flex',
alignItems: 'center',
gap: '8px',
}}>
<Check size={16} />
{success}
</div>
)}
<div style={{
marginTop: '20px',
padding: '12px',
background: 'var(--background-tertiary)',
borderRadius: '8px',
marginBottom: '20px',
fontSize: '13px',
color: 'var(--foreground-secondary)'
}}>
<strong>Note:</strong> Changing your password will re-encrypt your identity keys.
Your DID and followers remain unchanged.
</div>
<button
type="submit"
className="btn btn-primary"
disabled={isSubmitting || !currentPassword || !newPassword || !confirmPassword}
style={{ width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '8px' }}
>
{isSubmitting ? (
'Updating...'
) : (
<>
<Shield size={16} /> Update Password
</>
)}
</button>
</form>
</div>
</div>
);
}