Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions frontend/cmmty/pages/documents/[id]/settings/ChangePassword.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React, { useState } from 'react';

const ChangePassword = () => {
const [oldPass, setOldPass] = useState('');
const [newPass, setNewPass] = useState('');

const handleChange = async () => {
try {
await fetch('/api/user/change-password', {
method: 'POST',
body: JSON.stringify({ oldPass, newPass }),
});
alert('Password changed successfully!');
} catch {
alert('Error changing password.');
}
};

return (
<div className="settings-section">
<h2>Change Password</h2>
<input
type="password"
placeholder="Old Password"
value={oldPass}
onChange={(e) => setOldPass(e.target.value)}
/>
<input
type="password"
placeholder="New Password"
value={newPass}
onChange={(e) => setNewPass(e.target.value)}
/>
<button onClick={handleChange}>Update Password</button>
</div>
);
};

export default ChangePassword;
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React, { useState } from 'react';

const NotificationToggles = () => {
const [prefs, setPrefs] = useState({
riskAlerts: true,
verificationEmails: true,
weeklyDigest: false,
});

const handleToggle = (key: keyof typeof prefs) => {
setPrefs({ ...prefs, [key]: !prefs[key] });
};

const handleSave = async () => {
try {
await fetch('/api/user/notifications', {
method: 'POST',
body: JSON.stringify(prefs),
});
alert('Notification preferences saved!');
} catch {
alert('Error saving preferences.');
}
};

return (
<div className="settings-section">
<h2>Notifications</h2>
{Object.keys(prefs).map((key) => (
<label key={key}>
<input
type="checkbox"
checked={prefs[key as keyof typeof prefs]}
onChange={() => handleToggle(key as keyof typeof prefs)}
/>
{key}
</label>
))}
<button onClick={handleSave}>Save Preferences</button>
</div>
);
};

export default NotificationToggles;
39 changes: 39 additions & 0 deletions frontend/cmmty/pages/documents/[id]/settings/SettingsForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React, { useState } from 'react';

const SettingsForm = () => {
const [fullName, setFullName] = useState('');
const [loading, setLoading] = useState(false);

const handleSave = async () => {
setLoading(true);
try {
// API call to save profile
await fetch('/api/user/update', {
method: 'POST',
body: JSON.stringify({ fullName }),
});
alert('Profile updated successfully!');
} catch (err) {
alert('Error updating profile.');
} finally {
setLoading(false);
}
};

return (
<div className="settings-section">
<h2>Personal Information</h2>
<input
type="text"
placeholder="Full Name"
value={fullName}
onChange={(e) => setFullName(e.target.value)}
/>
<button onClick={handleSave} disabled={loading}>
{loading ? 'Saving...' : 'Save'}
</button>
</div>
);
};

export default SettingsForm;
17 changes: 17 additions & 0 deletions frontend/cmmty/pages/documents/[id]/settings/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import SettingsForm from './SettingsForm';
import NotificationToggles from './NotificationToggles';
import ChangePassword from './ChangePassword';

const SettingsPage = () => {
return (
<div className="settings-container">
<h1>User Profile Settings</h1>
<SettingsForm />
<NotificationToggles />
<ChangePassword />
</div>
);
};

export default SettingsPage;
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
.forgot-container {
max-width: 400px;
margin: auto;
padding: 1rem;
text-align: center;
}

.forgot-form {
display: flex;
flex-direction: column;
}

.forgot-form input,
.forgot-form button {
margin: 0.5rem 0;
padding: 0.75rem;
width: 100%;
}

.success-msg {
color: green;
margin-top: 1rem;
}

.back-link {
display: block;
margin-top: 1rem;
color: #0070f3;
}

@media (max-width: 600px) {
.forgot-container {
padding: 0.5rem;
}
}
21 changes: 21 additions & 0 deletions frontend/cmmty/pages/documents/[id]/settings/styles/settings.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.settings-container {
max-width: 600px;
margin: auto;
padding: 1rem;
}

.settings-section {
margin-bottom: 2rem;
}

input, button {
display: block;
width: 100%;
margin: 0.5rem 0;
}

@media (max-width: 600px) {
.settings-container {
padding: 0.5rem;
}
}
41 changes: 41 additions & 0 deletions frontend/cmmty/pages/forgot-password/ForgotPasswordForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { useState } from 'react';

const ForgotPasswordForm = () => {
const [email, setEmail] = useState('');
const [submitted, setSubmitted] = useState(false);

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!email || !/\S+@\S+\.\S+/.test(email)) {
alert('Please enter a valid email.');
return;
}
try {
await fetch('/api/auth/forgot-password', {
method: 'POST',
body: JSON.stringify({ email }),
});
} catch (err) {
// swallow errors to avoid enumeration
} finally {
setSubmitted(true);
}
};

return (
<form onSubmit={handleSubmit} className="forgot-form">
<label>Email Address</label>
<input
type="email"
placeholder="Enter your email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
<button type="submit">Send Reset Link</button>
{submitted && <p className="success-msg">If an account exists, a reset link has been sent.</p>}
</form>
);
};

export default ForgotPasswordForm;
14 changes: 14 additions & 0 deletions frontend/cmmty/pages/forgot-password/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import ForgotPasswordForm from './ForgotPasswordForm';

const ForgotPasswordPage = () => {
return (
<div className="forgot-container">
<h1>Forgot Password</h1>
<ForgotPasswordForm />
<a href="/login" className="back-link">Back to Login</a>
</div>
);
};

export default ForgotPasswordPage;
Loading