Skip to content

Commit 5df0229

Browse files
authored
Merge pull request NCUAppTeam#165 from AnaAngle/main
Feat: 上傳profile, 修改profile, 載入profile
2 parents eb858b9 + d99803d commit 5df0229

File tree

2 files changed

+52
-18
lines changed

2 files changed

+52
-18
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
export class GlobalFunction {
3+
static formatDate(date: Date): string {
4+
const year = date.getFullYear();
5+
const month = String(date.getMonth() + 1).padStart(2, '0');
6+
const day = String(date.getDate()).padStart(2, '0');
7+
8+
return `${year}-${month}-${day}`;
9+
}
10+
}

src/routes/home/profile.tsx

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { createFileRoute, redirect } from '@tanstack/react-router';
22
import { useState } from 'react';
33
import defaultAvatar from '../../assets/logo.png';
44
import defaultBackground from '../../assets/squirrel.jpg';
5+
import { GlobalFunction } from '../../backend/global/globalFunction';
56
import UserController from '../../backend/user/Controllers/UserController';
67
import { AuthGuard } from '../../utils/auth';
78

@@ -18,20 +19,22 @@ export const Route = createFileRoute('/home/profile')({
1819
component: ProfilePage,
1920
})
2021

22+
2123
function ProfilePage() {
24+
const profile = Route.useLoaderData().user
2225
const [isEditing, setIsEditing] = useState(false);
2326
const [formData, setFormData] = useState({
24-
avatar: defaultAvatar,
27+
avatar: profile.avatar || defaultAvatar,
2528
profileBackground: defaultBackground,
26-
name: '李小明',
27-
username: 'xiaoming',
28-
bio: '喜歡松鼠、熱愛開發的資訊系學生。',
29-
department: '資訊工程學系',
30-
email: 'xiaoming@example.com',
31-
grade: '大三',
32-
identity: '學生',
33-
joinedAt: '2022-09-01',
34-
phone: '0912345678',
29+
name: profile.name,
30+
username: profile.username,
31+
bio: profile.bio,
32+
department: profile.department,
33+
email: profile.email,
34+
grade: profile.grade,
35+
identity: profile.identity,
36+
joinedAt: GlobalFunction.formatDate(profile.joinedAt),
37+
phone: profile.phone,
3538
});
3639

3740
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
@@ -47,6 +50,22 @@ function ProfilePage() {
4750
if (file) reader.readAsDataURL(file);
4851
};
4952

53+
const handleSave = async () => {
54+
const userController = new UserController();
55+
profile.avatar = formData.avatar;
56+
profile.profileBackground = formData.profileBackground;
57+
profile.name = formData.name;
58+
profile.username = formData.username;
59+
profile.bio = formData.bio;
60+
profile.department = formData.department;
61+
profile.email = formData.email;
62+
profile.grade = Number(formData.grade);
63+
profile.identity = Number(formData.identity);
64+
profile.phone = formData.phone;
65+
66+
await userController.updateUser(profile.id, profile);
67+
setIsEditing(false);
68+
}
5069
return (
5170
<div className="w-full max-w-4xl mx-auto bg-red-100 shadow-xl/30 rounded-2xl p-4 sm:p-6 lg:p-8">
5271
{/* Profile Background */}
@@ -86,11 +105,11 @@ function ProfilePage() {
86105
</svg>
87106
</div>
88107
)}
89-
<div className="absolute -bottom-12 left-6">
108+
<div className="absolute -bottom-12 right-6">
90109
<img
91110
src={formData.avatar}
92111
alt="Avatar"
93-
className="w-24 h-24 rounded-full border-4 border-white object-cover cursor-pointer"
112+
className="w-24 h-24 rounded-full border-4 border-red-100 object-cover cursor-pointer bg-red-100"
94113
onClick={() => document.getElementById('avatarInput')?.click()}
95114
/>
96115
{isEditing && (
@@ -108,7 +127,7 @@ function ProfilePage() {
108127
{/* Info Section */}
109128
<div className="pt-16 px-6 pb-6">
110129
<div className="flex justify-between items-center">
111-
<h2 className="text-2xl font-bold">
130+
<h2 className="text-2xl font-bold text-black">
112131
{isEditing ? (
113132
<input
114133
type="text"
@@ -122,20 +141,25 @@ function ProfilePage() {
122141
)}
123142
</h2>
124143
<button
125-
onClick={() => setIsEditing(!isEditing)}
144+
onClick={() => {
145+
setIsEditing(!isEditing)
146+
if (isEditing) {
147+
handleSave()
148+
}
149+
}}
126150
className="text-blue-600 hover:underline"
127151
>
128152
{isEditing ? '完成' : '編輯個人檔案'}
129153
</button>
130154
</div>
131155
<p className="text-gray-500">@{formData.username}</p>
132156

133-
<div className="mt-4 space-y-2">
157+
<div className="mt-4 space-y-2 bg-red-50 shadow-md rounded-lg p-4">
134158
<Field label="自我介紹" name="bio" value={formData.bio} isEditing={isEditing} handleChange={handleChange} multiline />
135159
<Field label="系所" name="department" value={formData.department} isEditing={isEditing} handleChange={handleChange} />
136-
<Field label="年級" name="grade" value={formData.grade} isEditing={isEditing} handleChange={handleChange} />
137-
<Field label="身分" name="identity" value={formData.identity} isEditing={isEditing} handleChange={handleChange} />
138-
<Field label="電子信箱" name="email" value={formData.email} isEditing={isEditing} handleChange={handleChange} />
160+
<Field label="年級" name="grade" value={String(formData.grade)} isEditing={isEditing} handleChange={handleChange} />
161+
<Field label="身分" name="identity" value={String(formData.identity)} isEditing={isEditing} handleChange={handleChange} />
162+
<Field label="電子信箱" name="email" value={String(formData.email)} isEditing={isEditing} handleChange={handleChange} />
139163
<Field label="電話" name="phone" value={formData.phone} isEditing={isEditing} handleChange={handleChange} />
140164
<div className="text-gray-600 text-sm">
141165
加入時間:{formData.joinedAt}

0 commit comments

Comments
 (0)