remove avator edit
This commit is contained in:
parent
315ee14087
commit
16ed3560a3
@ -80,10 +80,8 @@
|
||||
"passwordMinLength": "Password must be at least 6 characters",
|
||||
"passwordUpdatedSuccessfully": "Password updated successfully",
|
||||
"failedToUpdatePassword": "Failed to update password",
|
||||
"uploading": "Uploading...",
|
||||
"clickCameraToUpload": "Click the camera icon to upload a new picture",
|
||||
"avatarUpdatedSuccessfully": "Avatar updated successfully",
|
||||
"failedToUploadAvatar": "Failed to upload avatar",
|
||||
"googleAvatar": "Avatar from Google account",
|
||||
"defaultAvatar": "Default avatar",
|
||||
"noUsernameSet": "No username set",
|
||||
"enterUsername": "Enter username",
|
||||
"enterEmail": "Enter email",
|
||||
|
@ -80,10 +80,8 @@
|
||||
"passwordMinLength": "密码至少需要6个字符",
|
||||
"passwordUpdatedSuccessfully": "密码更新成功",
|
||||
"failedToUpdatePassword": "密码更新失败",
|
||||
"uploading": "上传中...",
|
||||
"clickCameraToUpload": "点击相机图标上传新头像",
|
||||
"avatarUpdatedSuccessfully": "头像更新成功",
|
||||
"failedToUploadAvatar": "头像上传失败",
|
||||
"googleAvatar": "来自Google账号的头像",
|
||||
"defaultAvatar": "默认头像",
|
||||
"noUsernameSet": "未设置用户名",
|
||||
"enterUsername": "输入用户名",
|
||||
"enterEmail": "输入邮箱",
|
||||
|
@ -13,7 +13,7 @@ import { Avatar } from '@/components/ui/avatar'
|
||||
import { LoadingSpinner, LoadingOverlay } from '@/components/ui/loading-spinner'
|
||||
import { FullScreenLoading } from '@/components/ui/full-screen-loading'
|
||||
import { AvatarSkeleton, FormFieldSkeleton, TextAreaSkeleton } from '@/components/ui/skeleton'
|
||||
import { Camera, Save, Eye, EyeOff, Globe, CreditCard, Crown, Star } from 'lucide-react'
|
||||
import { Save, Eye, EyeOff, Globe, CreditCard, Crown, Star } from 'lucide-react'
|
||||
|
||||
interface UserProfile {
|
||||
id: string
|
||||
@ -83,7 +83,6 @@ export default function ProfilePage() {
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [profileLoading, setProfileLoading] = useState(true)
|
||||
const [fieldLoading, setFieldLoading] = useState<{ [key: string]: boolean }>({})
|
||||
const [avatarUploading, setAvatarUploading] = useState(false)
|
||||
const [creditInfo, setCreditInfo] = useState<CreditInfo | null>(null)
|
||||
|
||||
const supabase = createClient()
|
||||
@ -219,53 +218,6 @@ export default function ProfilePage() {
|
||||
}
|
||||
}
|
||||
|
||||
const uploadAvatar = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = event.target.files?.[0]
|
||||
if (!file || !user) return
|
||||
|
||||
setAvatarUploading(true)
|
||||
setIsLoading(true)
|
||||
setSaveStatus({ type: null, message: '' })
|
||||
|
||||
try {
|
||||
// Create a unique filename for future use with actual file storage
|
||||
// const fileExt = file.name.split('.').pop()
|
||||
// const fileName = `${user.id}-${Date.now()}.${fileExt}`
|
||||
|
||||
// For now, we'll use a placeholder upload since we need to configure storage
|
||||
// In a real implementation, you would upload to Supabase Storage or Cloudflare R2
|
||||
const reader = new FileReader()
|
||||
reader.onload = async (e) => {
|
||||
const dataUrl = e.target?.result as string
|
||||
|
||||
// Update avatar using our API
|
||||
const response = await fetch('/api/users/profile', {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
userId: user.id,
|
||||
avatar: dataUrl
|
||||
})
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json()
|
||||
throw new Error(errorData.error || 'Failed to update avatar')
|
||||
}
|
||||
|
||||
await loadProfile()
|
||||
setSaveStatus({ type: 'success', message: t('avatarUpdatedSuccessfully') })
|
||||
setIsLoading(false)
|
||||
setAvatarUploading(false)
|
||||
}
|
||||
reader.readAsDataURL(file)
|
||||
|
||||
} catch (error: unknown) {
|
||||
setSaveStatus({ type: 'error', message: (error instanceof Error ? error.message : 'Unknown error') || t('failedToUploadAvatar') })
|
||||
setIsLoading(false)
|
||||
setAvatarUploading(false)
|
||||
}
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return <FullScreenLoading isVisible={true} message={t('loadingStudio')} />
|
||||
@ -311,38 +263,20 @@ export default function ProfilePage() {
|
||||
{profileLoading ? (
|
||||
<AvatarSkeleton />
|
||||
) : (
|
||||
<LoadingOverlay isLoading={avatarUploading}>
|
||||
<div className="bg-card p-6 rounded-lg border border-border">
|
||||
<h2 className="text-xl font-semibold text-foreground mb-4">{t('profilePicture')}</h2>
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="relative">
|
||||
<Avatar
|
||||
src={profile?.avatar}
|
||||
alt="Profile Avatar"
|
||||
size={96}
|
||||
className="w-24 h-24"
|
||||
/>
|
||||
<label className={`absolute -bottom-2 -right-2 bg-primary text-primary-foreground p-2 rounded-full cursor-pointer hover:bg-primary/90 ${avatarUploading ? 'pointer-events-none opacity-50' : ''}`}>
|
||||
{avatarUploading ? (
|
||||
<LoadingSpinner size="sm" className="text-primary-foreground" />
|
||||
) : (
|
||||
<Camera className="w-4 h-4" />
|
||||
)}
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
className="hidden"
|
||||
onChange={uploadAvatar}
|
||||
disabled={isLoading || avatarUploading}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<Avatar
|
||||
src={user?.user_metadata?.avatar_url || profile?.avatar}
|
||||
alt="Profile Avatar"
|
||||
size={96}
|
||||
className="w-24 h-24"
|
||||
/>
|
||||
<p className="text-sm text-muted-foreground mt-2 text-center">
|
||||
{avatarUploading ? t('uploading') : t('clickCameraToUpload')}
|
||||
{user?.user_metadata?.avatar_url ? t('googleAvatar') : t('defaultAvatar')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</LoadingOverlay>
|
||||
)}
|
||||
|
||||
{/* Subscription Status */}
|
||||
@ -428,7 +362,7 @@ export default function ProfilePage() {
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setIsEditing(prev => ({ ...prev, username: true }))}
|
||||
disabled={isLoading || avatarUploading}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{tCommon('edit')}
|
||||
</Button>
|
||||
@ -489,7 +423,7 @@ export default function ProfilePage() {
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setIsEditing(prev => ({ ...prev, email: true }))}
|
||||
disabled={isLoading || avatarUploading}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{tCommon('edit')}
|
||||
</Button>
|
||||
@ -551,7 +485,7 @@ export default function ProfilePage() {
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setIsEditing(prev => ({ ...prev, bio: true }))}
|
||||
disabled={isLoading || avatarUploading}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{tCommon('edit')}
|
||||
</Button>
|
||||
@ -627,7 +561,7 @@ export default function ProfilePage() {
|
||||
updateProfile('language', newLanguage)
|
||||
}}
|
||||
className="w-full px-3 py-2 border border-border rounded-md bg-input text-foreground focus:outline-none focus:ring-2 focus:ring-ring"
|
||||
disabled={isLoading || fieldLoading.language || avatarUploading}
|
||||
disabled={isLoading || fieldLoading.language}
|
||||
>
|
||||
<option value="en">{t('english')}</option>
|
||||
<option value="zh">{t('chinese')}</option>
|
||||
@ -649,7 +583,7 @@ export default function ProfilePage() {
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setIsEditing(prev => ({ ...prev, password: true }))}
|
||||
disabled={isLoading || avatarUploading}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{t('changePassword')}
|
||||
</Button>
|
||||
@ -760,7 +694,7 @@ export default function ProfilePage() {
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setIsEditing(prev => ({ ...prev, versionLimit: true }))}
|
||||
disabled={isLoading || avatarUploading}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{tCommon('edit')}
|
||||
</Button>
|
||||
|
Loading…
Reference in New Issue
Block a user