Skip to content
Merged

Dev #36

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
43 changes: 34 additions & 9 deletions client/src/pages/user/Profile.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import BottomBar from '../../components/constants/Bottombar';
import Navbar from '../../components/constants/Navbar';
import { useNavigate } from 'react-router-dom';
import { useGetPostsByUserQuery } from '../../redux/posts/postApi';
import { useUpdatePasswordMutation, useUpdateFullNameMutation, useLogoutMutation } from '../../redux/apiSlice';
import { useUpdatePasswordMutation, useUpdateFullNameMutation, useUpdateUPIMutation, useLogoutMutation } from '../../redux/apiSlice';
import { useGetMyApplicationQuery } from '../../redux/opportunities/opportunity-api';
import { setCurrentUser } from '../../redux/user/userSlice';
import InfiniteScroll from 'react-infinite-scroll-component';
Expand All @@ -16,9 +16,11 @@ const Profile = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
const [password, setPassword] = useState('');
const [upi, setUpi] = useState('');
const [activeTab, setActiveTab] = useState('posts');
const [updatePassword, { isLoading: isUpdating, error: updateError }] = useUpdatePasswordMutation();
const [updateFullName, { isLoading: isUpdatingName }] = useUpdateFullNameMutation();
const [updateUPI, { isLoading: isUpdatingUPI }] = useUpdateUPIMutation();

// Name editing state
const [isEditingName, setIsEditingName] = useState(false);
Expand Down Expand Up @@ -54,6 +56,20 @@ const Profile = () => {
}
};

const handleUpdateUPI = async (e) => {
e.preventDefault();
if (!upi) {
alert('Please enter your UPI ID');
return;
}
try {
await updateUPI({ upi }).unwrap();
alert('UPI updated successfully');
} catch (error) {
alert('Failed to update UPI:', error);
}
};

const handleLogout = async (e) => {
e.preventDefault();
try {
Expand Down Expand Up @@ -154,15 +170,24 @@ const Profile = () => {

<input className="w-full p-2 mb-2 border rounded-xl bg-[#eeeeee] focus:outline-none" type="text" placeholder="Username" value={currentUser.username} readOnly />
<input className="w-full p-2 mb-2 border rounded-xl bg-[#eeeeee] focus:outline-none" type="email" placeholder="Email" value={currentUser.email} readOnly />

{/* ── Password Section ── */}
<input className="w-full p-2 mb-2 border rounded-xl bg-[#eeeeee] focus:outline-none" type="password" placeholder="New Password" value={password} onChange={(e) => setPassword(e.target.value)} />
<p className='text-xs text-start'>NOTE: Passwords are hashed and then stored. You can change it here.</p>
<div className='flex gap-6'>
<button className="mt-4 p-3 bg-[#ffffff] border-2 border-[#D9D9D9] font-bold text-[#6a7cff] rounded-xl" onClick={handleUpdate} disabled={isUpdating}>
{isUpdating ? 'Updating...' : 'Change Password'}
</button>
<button className="mt-4 p-3 bg-[#ffffff] border-2 border-[#D9D9D9] text-[#6a7cff] font-bold rounded-xl" onClick={handleLogout}>Logout</button>
</div>
{updateError && <div className="text-red-500">Error: {updateError.data?.message || 'Failed to update password.'}</div>}
<p className='text-xs text-start w-full'>NOTE: Passwords are hashed and then stored. You can change it here.</p>
<button className="mt-4 mb-6 w-full p-3 bg-[#ffffff] border-2 border-[#D9D9D9] font-bold text-[#6a7cff] rounded-xl" onClick={handleUpdate} disabled={isUpdating}>
{isUpdating ? 'Updating...' : 'Change Password'}
</button>
{updateError && <div className="text-red-500 mb-4">Error: {updateError.data?.message || 'Failed to update password.'}</div>}

{/* ── UPI Section ── */}
<input className="w-full p-2 mb-2 border rounded-xl bg-[#eeeeee] focus:outline-none" type="text" placeholder="UPI ID (e.g. username@bank)" value={upi} onChange={(e) => setUpi(e.target.value)} />
<p className='text-xs text-start w-full'>Used for receiving payments for completed opportunities.</p>
<button className="mt-4 mb-6 w-full p-3 bg-[#ffffff] border-2 border-[#D9D9D9] font-bold text-[#6a7cff] rounded-xl" onClick={handleUpdateUPI} disabled={isUpdatingUPI}>
{isUpdatingUPI ? 'Updating...' : 'Update UPI'}
</button>

{/* ── Logout ── */}
<button className="w-full p-3 bg-[#ffffff] border-2 border-red-200 text-red-400 font-bold rounded-xl" onClick={handleLogout}>Logout</button>

{/* ── Tabs ─────────────────────────────────────────────────────────── */}
<div className="flex w-full mt-6 border-b border-[#D9D9D9]">
Expand Down
25 changes: 19 additions & 6 deletions client/src/redux/apiSlice.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,26 @@ export const authApi = createApi({
}),
// UpdatePassword
updatePassword: builder.mutation({
query: (newPassword) => ({
query: ({password}) => ({
url: `/auth/updatepassword`,
method: 'POST',
body: { newPassword }, // Correctly wrapping in an object
body: { newPassword: password }, // Correctly wrapping in an object
}),
}),
// UpdateFullName
updateFullName: builder.mutation({
query: (fullname) => ({
url: `/auth/updatefullname`,
method: 'POST',
body: { fullname },
body: { fullname }, // Correctly wrapping in an object
}),
}),
// UpdateUPI
updateUPI: builder.mutation({
query: ({ upi }) => ({
url: `/auth/updateupi`,
method: 'POST',
body: { upi },
}),
}),
logout: builder.mutation({
Expand All @@ -47,8 +55,13 @@ export const authApi = createApi({
}),
}),
}),
// Define the middleware to handle the response and set cookies

});

export const { useSignUpMutation, useSignInMutation, useUpdatePasswordMutation,useUpdateFullNameMutation, useLogoutMutation } = authApi;
export const {
useSignUpMutation,
useSignInMutation,
useUpdatePasswordMutation,
useUpdateFullNameMutation,
useUpdateUPIMutation,
useLogoutMutation,
} = authApi;
9 changes: 7 additions & 2 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import js from "@eslint/js";
import importPlugin from "eslint-plugin-import";

export default [
{
ignores: ["client/**","api/**"]
},
js.configs.recommended,
{
files: ["**/*.js", "**/*.mjs"],
Expand All @@ -26,11 +29,12 @@ export default [
"globals",
"@eslint/js",
"eslint-plugin-import"

]
},
rules: {
"no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
"import/no-unresolved": "error",
"import/no-unresolved": ["error" , {ignore: ["uuid"]}],
"import/named": "error",
"import/default": "error",
"import/namespace": "error",
Expand All @@ -42,5 +46,6 @@ export default [
rules: {
"import/no-unresolved": "off",
},
},
}

];
6 changes: 3 additions & 3 deletions src/modules/auth/auth.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const logout = asyncHandler(async (req, res) => {
* POST /api/auth/updatepassword
*/
export const updatePassword = asyncHandler(async (req, res) => {
const result = await authService.updatePassword(req.body.newPassword);
const result = await authService.updatePassword(req.body.newPassword, req.user.id);
res.status(200).json(ApiResponses.success(result, 'Password updated successfully'));
});

Expand All @@ -56,7 +56,7 @@ export const updatePassword = asyncHandler(async (req, res) => {
* POST /api/auth/updatefullname
*/
export const updateFullName = asyncHandler(async (req, res) => {
const result = await authService.updateFullName(req.body.fullname);
const result = await authService.updateFullName(req.body.fullname , req.user.id);
res.status(200).json(ApiResponses.success(result, 'Full Name updated successfully'));
});

Expand All @@ -65,7 +65,7 @@ export const updateFullName = asyncHandler(async (req, res) => {
* POST /api/auth/updateupi
*/
export const updateUPI = asyncHandler(async (req, res) => {
const result = await authService.updateUPI(req.body.upi);
const result = await authService.updateUPI(req.body.upi , req.user.id);
res.status(200).json(ApiResponses.success(result, 'UPI updated successfully'));
});

Expand Down
8 changes: 4 additions & 4 deletions src/modules/auth/auth.routes.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import express from 'express';
import { validate, isAuthenticated, ipLimiter } from '../../shared/middleware/index.js';
import { validate, isAuthenticated, ipLimiter, verifyToken } from '../../shared/middleware/index.js';
import {
handleSignUp,
handleSignIn,
Expand Down Expand Up @@ -33,13 +33,13 @@ router.post('/signup', ipLimiter, validate(signUpSchema), handleSignUp);
router.post('/signin', ipLimiter, validate(signInSchema), handleSignIn);

// Update password - with validation
router.post('/updatepassword', validate(updatePasswordSchema), updatePassword);
router.post('/updatepassword',verifyToken, validate(updatePasswordSchema), updatePassword);

// Update full name - with validation
router.post('/updatefullname', validate(updateFullNameSchema), updateFullName);
router.post('/updatefullname',verifyToken, validate(updateFullNameSchema), updateFullName);

// Update UPI - with validation
router.post('/updateupi', validate(updateUPISchema), updateUPI);
router.post('/updateupi',verifyToken, validate(updateUPISchema), updateUPI);

// Logout - requires authentication
router.post('/logout', isAuthenticated, logout);
Expand Down
18 changes: 9 additions & 9 deletions src/modules/auth/auth.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
config.JWT_SECRET
);

const { password: _, ...userWithoutPassword } = savedUser._doc;

Check warning on line 56 in src/modules/auth/auth.service.js

View workflow job for this annotation

GitHub Actions / test-backend

'_' is assigned a value but never used

return { user: userWithoutPassword, token };
},
Expand Down Expand Up @@ -85,7 +85,7 @@
{ expiresIn: '30d' }
);

const { password: _, ...userWithoutPassword } = user._doc;

Check warning on line 88 in src/modules/auth/auth.service.js

View workflow job for this annotation

GitHub Actions / test-backend

'_' is assigned a value but never used

return { user: userWithoutPassword, token };
},
Expand All @@ -95,9 +95,9 @@
* @param {string} newPassword - New password
* @returns {Promise<Object>} Success message
*/
async updatePassword(newPassword) {
// Find first user (this seems like a development function)
const user = await User.findOne({});
async updatePassword(newPassword, userId) {
// Find user by ID
const user = await User.findById(userId);
if (!user) {
throw ApiErrors.notFound('User not found');
}
Expand All @@ -115,9 +115,9 @@
* @param {string} fullname - New full name
* @returns {Promise<Object>} Success message
*/
async updateFullName(fullname) {
// Find first user (this seems like a development function)
const user = await User.findOne({});
async updateFullName(fullname, userId) {
// Find user by ID
const user = await User.findById(userId);
if (!user) {
throw ApiErrors.notFound('User not found');
}
Expand All @@ -133,9 +133,9 @@
* @param {string} upi - New UPI
* @returns {Promise<Object>} Success message
*/
async updateUPI(upi) {
// Find first user (this seems like a development function)
const user = await User.findOne({});
async updateUPI(upi, userId) {
// Find user by ID
const user = await User.findById(userId);
if (!user) {
throw ApiErrors.notFound('User not found');
}
Expand Down Expand Up @@ -164,7 +164,7 @@
}

// Remove password from response
const { password: _, ...userWithoutPassword } = updatedUser._doc;

Check warning on line 167 in src/modules/auth/auth.service.js

View workflow job for this annotation

GitHub Actions / test-backend

'_' is assigned a value but never used

return userWithoutPassword;
},
Expand All @@ -178,7 +178,7 @@
try {
const decoded = jwt.verify(token, config.JWT_SECRET);
return decoded;
} catch (error) {

Check warning on line 181 in src/modules/auth/auth.service.js

View workflow job for this annotation

GitHub Actions / test-backend

'error' is defined but never used
throw ApiErrors.unauthorized('Invalid token');
}
},
Expand Down
2 changes: 1 addition & 1 deletion src/modules/payments/payment.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const paymentService = {

let paymentLevel = '1'; // by default level is 1 for 1st payment

if (Boolean(plainObject.paymentStatus.firstPayment.status)) {
if ((plainObject.paymentStatus.firstPayment.status)) {
paymentLevel = '2'; // if 1st payment true, then it is for second payment
}

Expand Down
Loading