import React, { useEffect, useState } from "react"; import { Avatar, Button, Card, Layout, Row, Col, Typography, Space, Tag, Modal, Form, Input, Select, message, Upload, } from "antd"; import { UploadOutlined, UserOutlined, LockOutlined, StopOutlined, EditOutlined, KeyOutlined, } from "@ant-design/icons"; import { authenticationService } from "../_services"; import "./Profile.css"; import axios from "axios"; const { Title, Text } = Typography; const { Option } = Select; const Profile = () => { const [isModalOpen, setIsModalOpen] = useState(false); const [form] = Form.useForm(); const [loading, setLoading] = useState(false); const [resetLoading, setResetLoading] = useState(false); const [uploading, setUploading] = useState(false); const [imageUrl, setImageUrl] = useState(null); const [user, setUser] = useState({}); const [fetching, setFetching] = useState(true); /** 🧩 Prefill modal with user data */ const handleEdit = () => { form.setFieldsValue({ first_name: user.first_name || "", last_name: user.last_name || "", mobile_num: user.mobile_num || "", gender: user.gender || "", state: user.state || "", city: user.city || "", }); setIsModalOpen(true); }; /** 🧩 Fetch user details from API */ const fetchUserDetails = async () => { try { setFetching(true); const response = await axios.get( "https://api.practicekea.com/api-student/v1/Users/MyDetails", { headers: { Authorization: `Bearer ${authenticationService.currentUserValue.jwtToken}`, }, } ); if (response.status === 200 && response.data?.result) { const r = response.data.result; // Map backend fields → frontend fields const formattedUser = { first_name: r.firstName || "", last_name: r.lastName || "", gender: r.gender || "", state: r.state || "", city: r.city || "", email_id: authenticationService.currentUserValue.email_id || "", mobile_num: r.mobileNumber || "", role_name: authenticationService.currentUserValue.role_name || "", institute_name: authenticationService.currentUserValue.institute_name || "", profile_pic: r.profilePic || "", }; setUser(formattedUser); } else { message.warning("No user data found."); } } catch (error) { console.error("Error fetching user:", error); message.error("Failed to load profile data."); } finally { setFetching(false); } }; /** 🔄 Fetch on mount */ useEffect(() => { fetchUserDetails(); }, []); /** 📸 Upload profile picture to PracticeKea API (matches Android logic) */ const handleUpload = async ({ file }) => { const formData = new FormData(); // 🧩 Match Android's part names formData.append("file", file); // same as MultipartBody.Part.createFormData("file", ...) formData.append("someData", "Profile Image"); // same as .toRequestBody("text/plain") try { setUploading(true); const response = await axios.post( "https://api.practicekea.com/api/AWSS3File/uploadMyPic", formData, { headers: { Authorization: `Bearer ${authenticationService.currentUserValue.jwtToken}`, "Content-Type": "multipart/form-data", }, } ); // 🧠 Log structure to confirm what backend returns console.log("Upload response:", response.data); // ✅ Example: { data: { url: "https://api-bucket.practicekea.com/uploads/xyz.jpg" } } const uploadedUrl = response.data?.data?.url || response.data?.url; if (!uploadedUrl) throw new Error("No image URL returned from server"); // Update avatar immediately setImageUrl(uploadedUrl); message.success("Profile picture uploaded successfully!"); // ✅ Optionally update user's saved image in profile await axios.post( "https://api.practicekea.com/api-student/v1/Users/UpdateMyDetails", { profile_pic: uploadedUrl }, { headers: { Authorization: `Bearer ${authenticationService.currentUserValue.jwtToken}`, "Content-Type": "application/json", }, } ); // Update local user data authenticationService.updateCurrentUser({ ...user, profile_pic: uploadedUrl, }); } catch (error) { console.error("Upload error:", error); message.error("Failed to upload image. Please try again."); } finally { setUploading(false); } }; /** 💾 Save edited profile info to API */ const handleSave = async () => { try { const values = await form.validateFields(); setLoading(true); // ✅ Example backend API endpoint for updating user data const response = await axios.post( `https://api.practicekea.com/api-student/v1/Users/UpdateMyDetails`, // adjust endpoint as per your backend values, { headers: { Authorization: `Bearer ${authenticationService.currentUserValue.jwtToken}`, // if using JWT "Content-Type": "application/json", }, } ); if (response.status === 200) { message.success("Profile updated successfully!"); setIsModalOpen(false); } else { throw new Error("Unexpected response from server."); } } catch (error) { console.error(error); const errorMsg = error.response?.data?.message || "Failed to save profile changes."; message.error(errorMsg); } finally { setLoading(false); } }; /** 🔐 Reset password using Firebase Identity Toolkit */ const handleResetPassword = async () => { if (!user?.email_id) { message.warning("No email associated with this account."); return; } try { setResetLoading(true); const response = await fetch( `https://identitytoolkit.googleapis.com/v1/accounts:sendOobCode?key=${process.env.REACT_APP_FIREBASE_API_KEY}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ requestType: "PASSWORD_RESET", email: user.email_id, }), } ); const data = await response.json(); if (data.error) { throw new Error(data.error.message); } message.success( `Password reset email sent to ${user.email_id}. Please check your inbox.` ); } catch (error) { console.error(error); let msg = "Failed to send reset email."; if (error.message === "EMAIL_NOT_FOUND") msg = "User not found."; if (error.message === "INVALID_EMAIL") msg = "Invalid email address."; message.error(msg); } finally { setResetLoading(false); } }; return ( {/* --- Header --- */} } style={{ backgroundColor: "#1677ff" }} /> {user.first_name || user.last_name ? ( <> {user.first_name} {user.last_name} </> ) : ( <Text type="warning">No name entered</Text> )} {user.email_id}
{user.role_name || "No role assigned"} {user.institute_name && ( {user.institute_name} )}
{/* --- Account Info --- */} Account Information } style={{ borderRadius: 16, boxShadow: "0 2px 12px rgba(0,0,0,0.05)", }} > {[ { label: "Full Name", value: `${user.first_name || ""} ${user.last_name || ""}`.trim() || null }, { label: "Email ID", value: user.email_id }, { label: "Phone Number", value: user.mobile_num }, { label: "Gender", value: user.gender }, { label: "City", value: user.city }, { label: "State", value: user.state }, { label: "Affiliated Institute", value: user.institute_name }, { label: "Role", value: user.role_name }, ].map((item, index) => (
{item.label} {item.value ? ( item.value ) : ( No {item.label.toLowerCase()} entered )}
))}
{/* --- Action Buttons --- */}
{/* --- Edit Modal --- */} setIsModalOpen(false)} onOk={handleSave} okText="Save Changes" confirmLoading={loading} centered style={{ borderRadius: 16, // ✅ outer border radius overflow: "hidden", }} bodyStyle={{ borderRadius: 16, // ✅ inner rounding for modal body background: "#fff", padding: "24px", }} modalRender={(node) => (
{node}
)} >
); }; export default Profile;