mirror of
https://github.com/TurTaskProject/TurTaskWeb.git
synced 2025-12-18 21:44: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.
|
||||
"""
|
||||
profile_pic = serializers.ImageField(required=False)
|
||||
first_name = serializers.CharField(max_length=255, required=False)
|
||||
about = serializers.CharField(required=False)
|
||||
|
||||
class Meta:
|
||||
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 users.serializers import CustomUserSerializer, UpdateProfileSerializer
|
||||
|
||||
from users.models import CustomUser
|
||||
|
||||
class CustomUserCreate(APIView):
|
||||
"""
|
||||
@ -49,8 +49,12 @@ class CustomUserProfileUpdate(APIView):
|
||||
return Response(data)
|
||||
|
||||
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():
|
||||
serializer.save()
|
||||
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 TestAuth from './components/testAuth';
|
||||
import IconSideNav from './components/IconSideNav';
|
||||
import LoginPage from './components/authentication/LoginPage';
|
||||
import SignUpPage from './components/authentication/SignUpPage';
|
||||
import NavBar from './components/Nav/Navbar';
|
||||
import Home from './components/Home';
|
||||
import ProfileUpdate from './components/ProfileUpdatePage'
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
@ -18,11 +18,9 @@ const App = () => {
|
||||
<Route path="/login" element={<LoginPage/>}/>
|
||||
<Route path="/signup" element={<SignUpPage/>}/>
|
||||
<Route path="/testAuth" element={<TestAuth/>}/>
|
||||
<Route path="/update_profile" element={<ProfileUpdate/>}/>
|
||||
</Routes>
|
||||
</div>
|
||||
{/* <div>
|
||||
<IconSideNav />
|
||||
</div> */}
|
||||
</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