mirror of
https://github.com/TurTaskProject/TurTaskWeb.git
synced 2025-12-19 22:14:07 +01:00
Add Profile update page
This commit is contained in:
parent
0ce32b9613
commit
47d4d97ce7
@ -31,6 +31,19 @@ class UpdateProfileSerializer(serializers.ModelSerializer):
|
|||||||
"""
|
"""
|
||||||
Serializer for updating user profile.
|
Serializer for updating user profile.
|
||||||
"""
|
"""
|
||||||
|
profile_pic = serializers.ImageField(required=False)
|
||||||
|
first_name = serializers.CharField(max_length=255, required=False)
|
||||||
|
about = serializers.CharField(required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CustomUser
|
model = CustomUser
|
||||||
fields = ('profile_pic', 'first_name', 'about')
|
fields = ('profile_pic', 'first_name', 'about')
|
||||||
|
|
||||||
|
def update(self, instance, validated_data):
|
||||||
|
"""
|
||||||
|
Update an existing user's profile.
|
||||||
|
"""
|
||||||
|
for attr, value in validated_data.items():
|
||||||
|
setattr(instance, attr, value)
|
||||||
|
instance.save()
|
||||||
|
return instance
|
||||||
@ -8,7 +8,7 @@ from rest_framework.views import APIView
|
|||||||
from rest_framework.parsers import MultiPartParser
|
from rest_framework.parsers import MultiPartParser
|
||||||
|
|
||||||
from users.serializers import CustomUserSerializer, UpdateProfileSerializer
|
from users.serializers import CustomUserSerializer, UpdateProfileSerializer
|
||||||
|
from users.models import CustomUser
|
||||||
|
|
||||||
class CustomUserCreate(APIView):
|
class CustomUserCreate(APIView):
|
||||||
"""
|
"""
|
||||||
@ -49,8 +49,12 @@ class CustomUserProfileUpdate(APIView):
|
|||||||
return Response(data)
|
return Response(data)
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
serializer = UpdateProfileSerializer(data=request.data)
|
if not CustomUser.objects.filter(email=request.user.email).exists():
|
||||||
|
return Response ({
|
||||||
|
'error': 'User does not exist'
|
||||||
|
}, status=status.HTTP_404_NOT_FOUND)
|
||||||
|
serializer = UpdateProfileSerializer(request.user, data=request.data)
|
||||||
if serializer.is_valid():
|
if serializer.is_valid():
|
||||||
serializer.save()
|
serializer.save()
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
return Response(serializer.errors, status=400)
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
@ -2,11 +2,11 @@ import './App.css';
|
|||||||
import { BrowserRouter, Route, Routes, Link } from 'react-router-dom';
|
import { BrowserRouter, Route, Routes, Link } from 'react-router-dom';
|
||||||
|
|
||||||
import TestAuth from './components/testAuth';
|
import TestAuth from './components/testAuth';
|
||||||
import IconSideNav from './components/IconSideNav';
|
|
||||||
import LoginPage from './components/authentication/LoginPage';
|
import LoginPage from './components/authentication/LoginPage';
|
||||||
import SignUpPage from './components/authentication/SignUpPage';
|
import SignUpPage from './components/authentication/SignUpPage';
|
||||||
import NavBar from './components/Nav/Navbar';
|
import NavBar from './components/Nav/Navbar';
|
||||||
import Home from './components/Home';
|
import Home from './components/Home';
|
||||||
|
import ProfileUpdate from './components/ProfileUpdatePage'
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
return (
|
return (
|
||||||
@ -18,11 +18,9 @@ const App = () => {
|
|||||||
<Route path="/login" element={<LoginPage/>}/>
|
<Route path="/login" element={<LoginPage/>}/>
|
||||||
<Route path="/signup" element={<SignUpPage/>}/>
|
<Route path="/signup" element={<SignUpPage/>}/>
|
||||||
<Route path="/testAuth" element={<TestAuth/>}/>
|
<Route path="/testAuth" element={<TestAuth/>}/>
|
||||||
|
<Route path="/update_profile" element={<ProfileUpdate/>}/>
|
||||||
</Routes>
|
</Routes>
|
||||||
</div>
|
</div>
|
||||||
{/* <div>
|
|
||||||
<IconSideNav />
|
|
||||||
</div> */}
|
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
21
frontend/src/api/UserProfileApi.jsx
Normal file
21
frontend/src/api/UserProfileApi.jsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const ApiUpdateUserProfile = async (formData) => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post('http://127.0.1:8000/api/user/update/', formData, {
|
||||||
|
headers: {
|
||||||
|
'Authorization': "Bearer " + localStorage.getItem('access_token'),
|
||||||
|
'Content-Type': 'multipart/form-data',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(response.data);
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error updating user profile:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export { ApiUpdateUserProfile };
|
||||||
107
frontend/src/components/ProfileUpdatePage.jsx
Normal file
107
frontend/src/components/ProfileUpdatePage.jsx
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import React, { useState, useRef } from 'react';
|
||||||
|
import { ApiUpdateUserProfile } from '../api/UserProfileApi';
|
||||||
|
|
||||||
|
function ProfileUpdate() {
|
||||||
|
const [file, setFile] = useState(null);
|
||||||
|
const [username, setUsername] = useState('');
|
||||||
|
const [fullName, setFullName] = useState('');
|
||||||
|
const [about, setAbout] = useState('');
|
||||||
|
const defaultImage = 'https://i1.sndcdn.com/artworks-cTz48e4f1lxn5Ozp-L3hopw-t500x500.jpg';
|
||||||
|
const fileInputRef = useRef(null);
|
||||||
|
|
||||||
|
const handleImageUpload = () => {
|
||||||
|
if (fileInputRef.current) {
|
||||||
|
fileInputRef.current.click();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFileChange = (e) => {
|
||||||
|
const selectedFile = e.target.files[0];
|
||||||
|
if (selectedFile) {
|
||||||
|
setFile(selectedFile);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('profile_pic', file);
|
||||||
|
formData.append('first_name', username);
|
||||||
|
formData.append('about', about);
|
||||||
|
|
||||||
|
ApiUpdateUserProfile(formData);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center mt-12 space-y-4">
|
||||||
|
{/* Profile Image */}
|
||||||
|
<div className="w-32 h-32 relative">
|
||||||
|
<label htmlFor="profileImage" className="absolute inset-0">
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
id="profileImage"
|
||||||
|
accept="image/*"
|
||||||
|
className="hidden"
|
||||||
|
onChange={handleFileChange}
|
||||||
|
ref={fileInputRef}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<div
|
||||||
|
className="avatar w-32 h-32 cursor-pointer hover:blur"
|
||||||
|
onClick={handleImageUpload}
|
||||||
|
>
|
||||||
|
{file ? (
|
||||||
|
<img src={URL.createObjectURL(file)} alt="Profile" className="rounded-full" />
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<img src={defaultImage} alt="Default" className="rounded-full" />
|
||||||
|
<i className="fas fa-camera text-white text-2xl absolute bottom-0 right-0 mr-2 mb-2"></i>
|
||||||
|
<i className="fas fa-arrow-up text-white text-2xl absolute top-0 right-0 mr-2 mt-2"></i>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Username Field */}
|
||||||
|
<div className="w-96">
|
||||||
|
<label className="block mb-2 text-gray-600">Username</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Enter your username"
|
||||||
|
className="input w-full"
|
||||||
|
value={username}
|
||||||
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Full Name Field */}
|
||||||
|
<div className="w-96">
|
||||||
|
<label className="block mb-2 text-gray-600">Full Name</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Enter your full name"
|
||||||
|
className="input w-full"
|
||||||
|
value={fullName}
|
||||||
|
onChange={(e) => setFullName(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* About Field */}
|
||||||
|
<div className="w-96">
|
||||||
|
<label className="block mb-2 text-gray-600">About Me</label>
|
||||||
|
<textarea
|
||||||
|
placeholder="Tell us about yourself"
|
||||||
|
className="textarea w-full h-32"
|
||||||
|
value={about}
|
||||||
|
onChange={(e) => setAbout(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Save Button */}
|
||||||
|
<button className="btn btn-primary w-96" onClick={handleSave}>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ProfileUpdate;
|
||||||
Loading…
Reference in New Issue
Block a user