feat: wire photo upload/delete changes upward for instant page-wide refresh

This commit is contained in:
2026-05-09 14:00:13 +08:00
parent 11d944bef2
commit f808b8325a
4 changed files with 23 additions and 3 deletions
+5
View File
@@ -82,6 +82,10 @@ export default function ProfilePage() {
return null return null
} }
const handleImageChange = (url: string | null) => {
setProfile((prev) => (prev ? { ...prev, image: url } : null))
}
const tabs: { id: Tab; label: string; icon: typeof Bookmark }[] = [ const tabs: { id: Tab; label: string; icon: typeof Bookmark }[] = [
{ id: "overview", label: "Overview", icon: TrendingUp }, { id: "overview", label: "Overview", icon: TrendingUp },
{ id: "saved", label: "Saved Games", icon: Bookmark }, { id: "saved", label: "Saved Games", icon: Bookmark },
@@ -178,6 +182,7 @@ export default function ProfilePage() {
createdAt={profile.createdAt} createdAt={profile.createdAt}
image={profile.image} image={profile.image}
userId={profile.id} userId={profile.id}
onImageChange={handleImageChange}
/> />
)} )}
</motion.div> </motion.div>
+4 -1
View File
@@ -8,6 +8,7 @@ interface ProfilePhotoUploadProps {
currentImage: string | null currentImage: string | null
userName: string userName: string
userId: string userId: string
onImageChange?: (url: string | null) => void
} }
const ALLOWED_TYPES = ["image/jpeg", "image/png", "image/webp"] const ALLOWED_TYPES = ["image/jpeg", "image/png", "image/webp"]
@@ -22,7 +23,7 @@ function getInitials(name: string): string {
return name.charAt(0).toUpperCase() return name.charAt(0).toUpperCase()
} }
export function ProfilePhotoUpload({ currentImage, userName, userId }: ProfilePhotoUploadProps) { export function ProfilePhotoUpload({ currentImage, userName, userId, onImageChange }: ProfilePhotoUploadProps) {
const [previewUrl, setPreviewUrl] = useState<string | null>(currentImage) const [previewUrl, setPreviewUrl] = useState<string | null>(currentImage)
const [uploadState, setUploadState] = useState<"idle" | "uploading" | "success" | "error">("idle") const [uploadState, setUploadState] = useState<"idle" | "uploading" | "success" | "error">("idle")
const [errorMessage, setErrorMessage] = useState<string | null>(null) const [errorMessage, setErrorMessage] = useState<string | null>(null)
@@ -89,6 +90,7 @@ export function ProfilePhotoUpload({ currentImage, userName, userId }: ProfilePh
if (data.url) { if (data.url) {
setPreviewUrl(data.url) setPreviewUrl(data.url)
cleanupTempUrl() cleanupTempUrl()
onImageChange?.(data.url)
} }
setUploadState("success") setUploadState("success")
} catch (err) { } catch (err) {
@@ -139,6 +141,7 @@ export function ProfilePhotoUpload({ currentImage, userName, userId }: ProfilePh
setPreviewUrl(null) setPreviewUrl(null)
setUploadState("idle") setUploadState("idle")
setErrorMessage(null) setErrorMessage(null)
onImageChange?.(null)
} catch (err) { } catch (err) {
setErrorMessage(err instanceof Error ? err.message : "Delete failed") setErrorMessage(err instanceof Error ? err.message : "Delete failed")
setUploadState("error") setUploadState("error")
@@ -28,6 +28,7 @@ interface SettingsContainerProps {
createdAt: string createdAt: string
image?: string | null image?: string | null
userId: string userId: string
onImageChange?: (url: string | null) => void
} }
export function SettingsContainer({ export function SettingsContainer({
@@ -37,6 +38,7 @@ export function SettingsContainer({
createdAt, createdAt,
image, image,
userId, userId,
onImageChange,
}: SettingsContainerProps) { }: SettingsContainerProps) {
const [activeSubTab, setActiveSubTab] = useState<SettingsSubTab>("profile") const [activeSubTab, setActiveSubTab] = useState<SettingsSubTab>("profile")
const [authMethods, setAuthMethods] = useState<AuthMethods | null>(null) const [authMethods, setAuthMethods] = useState<AuthMethods | null>(null)
@@ -126,6 +128,7 @@ export function SettingsContainer({
createdAt={createdAt} createdAt={createdAt}
image={image} image={image}
userId={userId} userId={userId}
onImageChange={onImageChange}
/> />
)} )}
{activeSubTab === "security" && ( {activeSubTab === "security" && (
+11 -2
View File
@@ -14,9 +14,10 @@ interface SettingsProfileTabProps {
createdAt: string createdAt: string
image?: string | null image?: string | null
userId: string userId: string
onImageChange?: (url: string | null) => void
} }
export function SettingsProfileTab({ name, email, role, createdAt, image, userId }: SettingsProfileTabProps) { export function SettingsProfileTab({ name, email, role, createdAt, image, userId, onImageChange }: SettingsProfileTabProps) {
const [displayName, setDisplayName] = useState(name) const [displayName, setDisplayName] = useState(name)
const [isSaving, setIsSaving] = useState(false) const [isSaving, setIsSaving] = useState(false)
const [message, setMessage] = useState<{ type: "success" | "error"; text: string } | null>(null) const [message, setMessage] = useState<{ type: "success" | "error"; text: string } | null>(null)
@@ -54,7 +55,15 @@ export function SettingsProfileTab({ name, email, role, createdAt, image, userId
className="space-y-6" className="space-y-6"
> >
{/* Profile Photo */} {/* Profile Photo */}
<ProfilePhotoUpload currentImage={image ?? null} userName={name} userId={userId} /> <ProfilePhotoUpload
currentImage={image ?? null}
userName={name}
userId={userId}
onImageChange={async (url) => {
onImageChange?.(url)
await authClient.updateUser({ image: url ?? "" })
}}
/>
{/* Display Name */} {/* Display Name */}
<div className="rounded-xl border border-border bg-text/[0.03] p-5"> <div className="rounded-xl border border-border bg-text/[0.03] p-5">