ยินดีต้อนรับสู่ H2G แหล่งรวมงาน Hackathon ที่ใหญ่ที่สุด
diff --git a/frontend/src/personal.jsx b/frontend/src/personal.jsx
index b1e747a..d5249b4 100644
--- a/frontend/src/personal.jsx
+++ b/frontend/src/personal.jsx
@@ -11,7 +11,7 @@ const Personal = () => {
}).then(() => {
setUserlist([
...userlist,
- { personaltype: personaltype }
+ { personaltype: personaltype }
]);
});
}
diff --git a/frontend/src/profile.jsx b/frontend/src/profile.jsx
index d7e35d1..d4f2512 100644
--- a/frontend/src/profile.jsx
+++ b/frontend/src/profile.jsx
@@ -1,432 +1,419 @@
-import { useState } from 'react';
-import { FaUser, FaLock } from "react-icons/fa";
+import { useState, useEffect } from 'react';
+import { FaUser } from "react-icons/fa";
import { MdEmail } from "react-icons/md";
import Axios from 'axios';
-import { useEffect} from 'react';
+import PropTypes from 'prop-types';
+import Swal from 'sweetalert2'
-const Profile = () => {
- /*ข้อมูล User*/
- const [UserID] = useState('');
- const [UserName, setUserName] = useState('');
- const [Bio, setBio] = useState('');
- const [Email, setEmail] = useState('');
- const [Password, setPassword] = useState('');
- const [ProfileImage, setProfileImage] = useState('');
- const [WorkingStyle, setWorkingStyle] = useState(0);
- /*ไว้ Add ข้อมูล Skill*/
- const [company, setCompany] = useState('');
- const [description, setDescription] = useState('');
- const [endDate, setEnddate] = useState('');
- const [location, setLocation] = useState('');
- const [startDate, setStartdate] = useState(0);
- const [title, setTitle] = useState('');
-
- const [Skilllist, setSkilllist] = useState([]);
- const [isModalOpen, setIsModalOpen] = useState(false);
- const [isEditProfileModalOpen, setIsEditProfileModalOpen] = useState(false);
- const [userlist, setUserlist] = useState([]);
+// EditProfileModal component
+// EditProfileModal component
+const EditProfileModal = ({ isOpen, onClose, onSave, user }) => {
+ const [userName, setUserName] = useState(user?.UserName || '');
+ const [email, setEmail] = useState(user?.Email || '');
+ const [profileImage, setProfileImage] = useState(null);
+ const [workingStyle, setWorkingStyle] = useState(user?.WorkingStyle || '');
+ const [bio, setBio] = useState(user?.Bio || '');
+
+ const handleSubmit = async () => {
+ const formData = new FormData();
+ formData.append('userName', userName);
+ formData.append('email', email);
+ formData.append('profileImage', profileImage);
+ formData.append('workingStyle', workingStyle);
+ formData.append('bio', bio);
+
+ try {
+ const response = await Axios.put(`http://localhost:3000/user/${user.UserID}`, formData, {
+ headers: {
+ 'Content-Type': 'multipart/form-data',
+ },
+ });
+ onSave(response.data);
+
+
+ Swal.fire({
+ title: "Good job!",
+ text: "Register Sucessful!",
+ icon: "success"
+ });
+ setTimeout(() => {
+ Swal.close();
+ }, 3000);
+
+ await new Promise(resolve => setTimeout(resolve, 2000));
+
+
+ window.location.href = '/profile'
+
+
+ } catch (error) {
+ console.error('Error updating profile:', error);
+ }
+ };
+
+ if (!isOpen) return null;
+
+ return (
+
+ );
+};
+
+// PropTypes for validation
+EditProfileModal.propTypes = {
+ isOpen: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired,
+ onSave: PropTypes.func.isRequired,
+ user: PropTypes.shape({
+ UserID: PropTypes.string.isRequired,
+ UserName: PropTypes.string,
+ Email: PropTypes.string,
+ WorkingStyle: PropTypes.string,
+ Bio: PropTypes.string,
+ }),
+};
+
+
+
+// AddSkillModal component
+const AddSkillModal = ({ isOpen, onClose, onSave }) => {
+ const [skill, setSkill] = useState('');
+
+ const handleSubmit = () => {
+ onSave(skill);
+ };
+
+ if (!isOpen) return null;
+
+ return (
+
+
+
e.preventDefault()}>
+ Add Skill
+
+ setSkill(e.target.value)}
+ />
+
+
+
+ Save
+
+
+ Cancel
+
+
+
+
+
+ );
+};
+
+// PropTypes for validation
+AddSkillModal.propTypes = {
+ isOpen: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired,
+ onSave: PropTypes.func.isRequired,
+};
+
+// AddPersonalTypeModal component
+const AddPersonalTypeModal = ({ isOpen, onClose, onSave }) => {
+ const [personalType, setPersonalType] = useState('');
+
+ const handleSubmit = () => {
+ onSave(personalType);
+ };
+
+ if (!isOpen) return null;
+
+ return (
+
+
+
e.preventDefault()}>
+ Add Personal Type
+
+
+
+ Save
+
+
+ Cancel
+
+
+
+
+
+ );
+};
+// PropTypes for validation
+AddPersonalTypeModal.propTypes = {
+ isOpen: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired,
+ onSave: PropTypes.func.isRequired,
+};
- // const getSkill = () => {
- // Axios.get('http://localhost:3000/test').then((response) => {
- // setSkilllist(response.data);
- // });
- // };
+// Profile Component
+const Profile = () => {
+ const UserID = localStorage.getItem('UserID');
+ const [user, setUser] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+
+ const [isEditProfileModalOpen, setIsEditProfileModalOpen] = useState(false);
+ const [isAddSkillModalOpen, setIsAddSkillModalOpen] = useState(false);
+ const [isAddPersonalTypeModalOpen, setIsAddPersonalTypeModalOpen] = useState(false);
useEffect(() => {
const fetchUser = async () => {
- if (UserID) { // ตรวจสอบว่ามีค่า UserID ก่อนเรียก API
- try {
- const response = await Axios.get(`/api/getUserById?userId=${UserID}`);
- const { UserName, Bio, ProfileImage } = response.data;
- setUserName(UserName);
- setBio(Bio);
- setProfileImage(ProfileImage);
- } catch (error) {
- console.error('Error fetching user:', error);
- }
+ try {
+ if (!UserID) throw new Error("UserID is required");
+
+ const response = await Axios.get(`http://localhost:3000/user/id/${UserID}`);
+ if (!response.data) throw new Error("User not found");
+
+
+ setUser(response.data);
+ } catch (err) {
+ setError(err.message || "Error fetching user data");
+ } finally {
+ setLoading(false);
}
};
-
+
fetchUser();
}, [UserID]);
-
-
- const addSkill = () => {
- Axios.post('http://localhost:5173/profile', {
- company: company,
- description: description,
- endDate: endDate,
- location: location,
- startDate: startDate,
- title: title,
- }).then(() => {
- setSkilllist([
- ...Skilllist,
- {
- company: company,
- description: description,
- endDate: endDate,
- location: location,
- startDate: startDate,
- title: title,
- },
- ]);
- setIsModalOpen(false);
- });
+
+ const handleProfileUpdate = async (profileData) => {
+ try {
+ await Axios.put('http://localhost:3000/user/${UserID}', profileData);
+ setIsEditProfileModalOpen(false);
+ const response = await Axios.get(`http://localhost:3000/user/id/${UserID}`);
+ setUser(response.data);
+ } catch (error) {
+ console.error("Error updating profile:", error);
+ }
};
-
- // const getUsers = () => {
- // Axios.get('http://localhost:3000/test').then((response) => {
- // setUserlist(response.data);
- // });
- // };
-
-
- const addUsers = () => {
- Axios.post('http://localhost:5173/profile', {
- UserName: UserName,
- Bio: Bio,
- email: Email,
- password: Password,
- ProfileImage: ProfileImage,
- WorkingStyle: WorkingStyle,
- }).then(() => {
- setUserlist([
- ...userlist,
- {
- UserName: UserName,
- Bio: Bio,
- email: Email,
- password: Password,
- ProfileImage: ProfileImage,
- WorkingStyle: WorkingStyle,
- },
- ]);
- });
+ const handleSkillSave = async (skill) => {
+ try {
+ await Axios.post('http://localhost:3000/profile/add-skill', { skill, UserID });
+ setIsAddSkillModalOpen(false);
+ const response = await Axios.get(`http://localhost:3000/user/id/${UserID}`);
+ setUser(response.data);
+ } catch (error) {
+ console.error("Error adding skill:", error);
+ }
};
- return (
-
-
-
- {/* Profile Header Section */}
-
- {ProfileImage}
-
-
- {/* Profile Info */}
-
-
-
-
{UserName}
+
+ const handlePersonalTypeSave = async (personalType) => {
+ try {
+ await Axios.post('http://localhost:3000/profile/add-personal-type', { personalType, UserID });
+ setIsAddPersonalTypeModalOpen(false);
+ const response = await Axios.get(`http://localhost:3000/user/id/${UserID}`);
+ setUser(response.data);
+ } catch (error) {
+ console.error("Error adding personal type:", error);
+ }
+ };
+
+ if (loading) return
Loading...
;
+ if (error) return
Error: {error}
;
+
+ return (
+
+
+
-
- {[1, 2, 3, 4, 5].map((star) => (
-
-
-
- ))}
-
4.0
-
-
-
-
setIsEditProfileModalOpen(true)}
- className="px-4 py-2 bg-gray-200 rounded-lg text-sm">
- EDIT PROFILE
-
- {/* Popup สำหรับแก้ไขโปรไฟล์ */}
- {isEditProfileModalOpen && (
-
-
-
- Edit profile
-
-
-
-
- setPassword(event.target.value)}
- />
-
-
-
-
-
- Save
-
- setIsEditProfileModalOpen(false)}
- className="w-1/3 h-12 bg-red-500 text-white font-bold rounded-full shadow-md hover:bg-red-600 transition duration-300"
- >
- Cancel
-
-
-
-
-
-
- )}
-
-
-
setIsModalOpen(true)}
- className="px-4 py-2 bg-gray-200 rounded-lg text-sm">
- ADD SKILL
-
- {isModalOpen && (
-
-
-
Add skill
-
-
-
-
- Save
-
- setIsModalOpen(false)}
- className="w-1/3 h-12 bg-red-500 text-white font-bold rounded-full shadow-md hover:bg-red-600 transition duration-300"
- >
- Cancel
-
-
-
-
- )}
-
-
-
-
-
+
setIsEditProfileModalOpen(false)}
+ onSave={handleProfileUpdate}
+ user={user}
+ />
+ setIsAddSkillModalOpen(false)}
+ onSave={handleSkillSave}
+ />
+ setIsAddPersonalTypeModalOpen(false)}
+ onSave={handlePersonalTypeSave}
+ />
+
+
+
+
+ {user.ProfileImage ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+
+
+
{user.UserName || 'Anonymous User'}
+
แนะนำตัว
- {Bio}
+ {user.Bio || 'No bio available'}
-
-
-
- {/* Past Events Section */}
-
-
-
-
Past Event
-
-
+
+
+
setIsEditProfileModalOpen(true)}
+ className="px-6 py-2 bg-gray-200 rounded-lg text-sm font-medium transform transition-all duration-300 hover:bg-gray-300 hover:scale-105 hover:shadow-md"
>
-
-
-
-
-
-
-
-
-
Hackathon999
-
- เสร็จสิ้น
-
-
-
-
-
-
-
-
9/9/2023 - 2/10/2023
-
-
-
+ EDIT PROFILE
+
+
setIsAddSkillModalOpen(true)}
+ className="px-6 py-2 bg-gray-200 rounded-lg text-sm font-medium transform transition-all duration-300 hover:bg-gray-300 hover:scale-105 hover:shadow-md"
+ >
+ ADD SKILL
+
+
setIsAddPersonalTypeModalOpen(true)}
+ className="px-6 py-2 bg-gray-200 rounded-lg text-sm font-medium transform transition-all duration-300 hover:bg-gray-300 hover:scale-105 hover:shadow-md"
+ >
+ ADD PERSONAL TYPE
+
+
+
สไตล์การทำงาน
+
+ {user.WorkingStyle || 'No bio available'}
+
+
+
- );
- };
-
- export default Profile;
-
\ No newline at end of file
+
+
+
+
+
+
+ );
+};
+
+export default Profile;
diff --git a/src/controllers/userController.ts b/src/controllers/userController.ts
index 0dee6fe..8a6662c 100644
--- a/src/controllers/userController.ts
+++ b/src/controllers/userController.ts
@@ -7,7 +7,7 @@ export const userController = new Elysia({ prefix: "/user" })
.post(
"/create",
async ({ body, error }) => {
- const { userName, email, password, workingStyle, profileImage, bio } = body;
+ const { userName, email, password, workingStyle, ProfileImage, bio } = body;
const existingUser = await prisma.user.findUnique({
where: { Email: email },
@@ -30,7 +30,7 @@ export const userController = new Elysia({ prefix: "/user" })
Bio: bio,
Email: email,
Password: hashPassword,
- ProfileImage: profileImage,
+ ProfileImage: ProfileImage, // base64 string
WorkingStyle: workingStyle,
},
});
@@ -43,7 +43,7 @@ export const userController = new Elysia({ prefix: "/user" })
email: t.String(),
password: t.String(),
workingStyle: t.Optional(t.String()),
- profileImage: t.Optional(t.String()),
+ ProfileImage: t.Optional(t.String()),
bio: t.Optional(t.String()),
}),
})
@@ -82,6 +82,29 @@ export const userController = new Elysia({ prefix: "/user" })
}
)
+// Get user details by userID
+.get("/id/:UserID", async ({ params: { UserID }, error }) => {
+ const user = await prisma.user.findUnique({
+ where: { UserID: UserID },
+ select: {
+ UserID: true, // เพิ่ม UserID เพื่อใช้อ้างอิง
+ UserName: true,
+ Email: true,
+ WorkingStyle: true,
+ ProfileImage: true,
+ Bio: true,
+ },
+ });
+
+ if (!user) {
+ return error(404, "User not found");
+ }
+
+ return user;
+})
+
+
+
// Get user details by userID
.get(
@@ -114,49 +137,47 @@ export const userController = new Elysia({ prefix: "/user" })
)
// Update user profile
- .put(
- "/:userID",
- async ({ params: { userID }, body, error }) => {
- const { userName, email, password, workingStyle, profileImage, bio } = body;
+.put(
+ "/:userID",
+ async ({ params: { userID }, body, error }) => {
+ const { userName, email, workingStyle, profileImage, bio } = body;
- // Check if the user exists
- const user = await prisma.user.findUnique({
- where: { UserID: userID },
- });
+ // Check if the user exists
+ const user = await prisma.user.findUnique({
+ where: { UserID: userID },
+ });
- if (!user) {
- return error(404, "User not found");
- }
+ if (!user) {
+ return error(404, "User not found");
+ }
- // Update the user
- const updatedUser = await prisma.user.update({
- where: { UserID: userID },
- data: {
- UserName: userName,
- Email: email,
- Password: password,
- WorkingStyle: workingStyle,
- ProfileImage: profileImage,
- Bio: bio,
- },
- });
+ // Update the user
+ const updatedUser = await prisma.user.update({
+ where: { UserID: userID },
+ data: {
+ UserName: userName || user.UserName,
+ Email: email || user.Email,
+ WorkingStyle: workingStyle || user.WorkingStyle,
+ ProfileImage: profileImage || user.ProfileImage,
+ Bio: bio || user.Bio,
+ },
+ });
- return updatedUser; // Return the updated user
- },
- {
- params: t.Object({
- userID: t.String(),
- }),
- body: t.Object({
- userName: t.Optional(t.String()),
- email: t.Optional(t.String()),
- password: t.Optional(t.String()),
- workingStyle: t.Optional(t.String()),
- profileImage: t.Optional(t.String()),
- bio: t.Optional(t.String()),
+ return updatedUser; // Return the updated user
+ },
+ {
+ params: t.Object({
+ userID: t.String(),
+ }),
+ body: t.Object({
+ userName: t.Optional(t.String()),
+ email: t.Optional(t.String()),
+ workingStyle: t.Optional(t.String()),
+ profileImage: t.Optional(t.String()),
+ bio: t.Optional(t.String()),
}),
}
- )
+)
// Get all users
.get(