Skip to content

Commit

Permalink
Added change password functionality
Browse files Browse the repository at this point in the history
Added change password function
  • Loading branch information
brian0309 committed Sep 22, 2024
1 parent 7254844 commit 093b5c8
Show file tree
Hide file tree
Showing 9 changed files with 373 additions and 76 deletions.
24 changes: 24 additions & 0 deletions backend/controllers/auth.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,27 @@ export const checkAuth = async (req, res) => {
res.status(400).json({ success: false, message: error.message });
}
};

export const changePassword = async (req, res) => {
const { currentPassword, newPassword } = req.body;
try {
const user = await User.findById(req.userId);
if (!user) {
return res.status(400).json({ success: false, message: "User not found" });
}

const isPasswordValid = await bcryptjs.compare(currentPassword, user.password);
if (!isPasswordValid) {
return res.status(400).json({ success: false, message: "Current password is incorrect" });
}

const hashedPassword = await bcryptjs.hash(newPassword, 10);
user.password = hashedPassword;
await user.save();

res.status(200).json({ success: true, message: "Password changed successfully" });
} catch (error) {
console.log("Error in changePassword ", error);
res.status(400).json({ success: false, message: error.message });
}
};
2 changes: 1 addition & 1 deletion backend/mailtrap/mailtrap.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ export const mailtrapClient = new MailtrapClient({

export const sender = {
email: "[email protected]",
name: "Burak",
name: "MT5 Webhook",
};
2 changes: 2 additions & 0 deletions backend/routes/auth.route.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
forgotPassword,
resetPassword,
checkAuth,
changePassword // Add this line
} from "../controllers/auth.controller.js";
import { verifyToken } from "../middleware/verifyToken.js";

Expand All @@ -22,5 +23,6 @@ router.post("/verify-email", verifyEmail);
router.post("/forgot-password", forgotPassword);

router.post("/reset-password/:token", resetPassword);
router.post("/change-password", verifyToken, changePassword); // Add this line

export default router;
58 changes: 35 additions & 23 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import EmailVerificationPage from "./pages/EmailVerificationPage";
import DashboardPage from "./pages/DashboardPage";
import ForgotPasswordPage from "./pages/ForgotPasswordPage";
import ResetPasswordPage from "./pages/ResetPasswordPage";
import ChangePasswordPage from "./pages/ChangePasswordPage"; // Import the new page

import LoadingSpinner from "./components/LoadingSpinner";

Expand Down Expand Up @@ -101,6 +102,14 @@ function App() {
</RedirectAuthenticatedUser>
}
/>
<Route
path='/change-password'
element={
<ProtectedRoute>
<ChangePasswordPage />
</ProtectedRoute>
}
/>
{/* catch all routes */}
<Route path='*' element={<Navigate to='/' replace />} />
</Routes>
Expand Down
83 changes: 83 additions & 0 deletions frontend/src/pages/ChangePasswordPage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { useState } from "react";
import { motion } from "framer-motion";
import { useAuthStore } from "../store/authStore";
import Input from "../components/Input";
import { Lock } from "lucide-react";
import toast from "react-hot-toast";

const ChangePasswordPage = () => {
const [currentPassword, setCurrentPassword] = useState("");
const [newPassword, setNewPassword] = useState("");
const [confirmNewPassword, setConfirmNewPassword] = useState("");
const { changePassword, error, isLoading } = useAuthStore();

const handleSubmit = async (e) => {
e.preventDefault();

if (newPassword !== confirmNewPassword) {
alert("New passwords do not match");
return;
}
try {
await changePassword(currentPassword, newPassword);
toast.success("Password changed successfully");
} catch (error) {
console.error(error);
toast.error(error.message || "Error changing password");
}
};

return (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className='max-w-md w-full bg-gray-800 bg-opacity-50 backdrop-filter backdrop-blur-xl rounded-2xl shadow-xl overflow-hidden'
>
<div className='p-8'>
<h2 className='text-3xl font-bold mb-6 text-center bg-gradient-to-r from-green-400 to-emerald-500 text-transparent bg-clip-text'>
Change Password
</h2>
{error && <p className='text-red-500 text-sm mb-4'>{error}</p>}

<form onSubmit={handleSubmit}>
<Input
icon={Lock}
type='password'
placeholder='Current Password'
value={currentPassword}
onChange={(e) => setCurrentPassword(e.target.value)}
required
/>
<Input
icon={Lock}
type='password'
placeholder='New Password'
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
required
/>
<Input
icon={Lock}
type='password'
placeholder='Confirm New Password'
value={confirmNewPassword}
onChange={(e) => setConfirmNewPassword(e.target.value)}
required
/>
<motion.button
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
className='w-full py-3 px-4 bg-gradient-to-r from-green-500 to-emerald-600 text-white font-bold rounded-lg shadow-lg hover:from-green-600 hover:to-emerald-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 focus:ring-offset-gray-900 transition duration-200'
type='submit'
disabled={isLoading}
>
{isLoading ? "Changing..." : "Change Password"}
</motion.button>
</form>
</div>
</motion.div>
);
};

export default ChangePasswordPage;
13 changes: 13 additions & 0 deletions frontend/src/store/authStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,17 @@ export const useAuthStore = create((set) => ({
throw error;
}
},
changePassword: async (currentPassword, newPassword) => {
set({ isLoading: true, error: null });
try {
const response = await axios.post(`${API_URL}/change-password`, { currentPassword, newPassword });
set({ message: response.data.message, isLoading: false });
} catch (error) {
set({
isLoading: false,
error: error.response.data.message || "Error changing password",
});
throw error;
}
},
}));
Loading

0 comments on commit 093b5c8

Please sign in to comment.