feat: Add detailed logging for user profile components and image metadata extraction; enhance color handling utilities
This commit is contained in:
@@ -73,6 +73,7 @@ export function useUserBanner(): [
|
||||
|
||||
const profile = await mx.getProfileInfo(userId);
|
||||
const avatarUrl = profile.avatar_url;
|
||||
console.log('[useUserBanner.loadBanner] Loading banner from avatar:', avatarUrl);
|
||||
|
||||
if (!avatarUrl) {
|
||||
setBanner(undefined);
|
||||
@@ -90,6 +91,7 @@ export function useUserBanner(): [
|
||||
// Always use current session's token to avoid stale tokens during account switches
|
||||
const accessToken = getCurrentAccessToken();
|
||||
const metadata = await fetchAndExtractMetadata(httpUrl, useAuthentication ? accessToken : null);
|
||||
console.log('[useUserBanner.loadBanner] Extracted banner:', metadata.banner);
|
||||
setBanner(metadata.banner);
|
||||
} catch {
|
||||
setBanner(undefined);
|
||||
@@ -104,7 +106,8 @@ export function useUserBanner(): [
|
||||
if (!userId) return undefined;
|
||||
|
||||
const user = mx.getUser(userId);
|
||||
const onAvatarChange: UserEventHandlerMap[UserEvent.AvatarUrl] = () => {
|
||||
const onAvatarChange: UserEventHandlerMap[UserEvent.AvatarUrl] = (newAvatarUrl) => {
|
||||
console.log('[useUserBanner] Avatar changed event fired, new URL:', newAvatarUrl);
|
||||
loadBanner();
|
||||
};
|
||||
|
||||
@@ -143,12 +146,16 @@ export function useUserBanner(): [
|
||||
|
||||
// Get existing metadata to preserve
|
||||
const existingMetadata = extractMetadataFromImage(avatarData);
|
||||
console.log('[updateBanner] Existing metadata:', existingMetadata);
|
||||
|
||||
// Modify image metadata with new banner, preserving color
|
||||
const newMetadata: ImageMetadata = {
|
||||
color: existingMetadata.color,
|
||||
banner: newBanner,
|
||||
avatarBorderColor: existingMetadata.avatarBorderColor,
|
||||
gradient: existingMetadata.gradient,
|
||||
};
|
||||
console.log('[updateBanner] New metadata to embed:', newMetadata);
|
||||
|
||||
const newAvatarData = embedMetadataInImage(avatarData, newMetadata);
|
||||
|
||||
@@ -158,10 +165,13 @@ export function useUserBanner(): [
|
||||
|
||||
// Verify the banner was embedded correctly before uploading
|
||||
const verifyMetadata = extractMetadataFromImage(newAvatarData);
|
||||
console.log('[updateBanner] Verification - extracted metadata from new avatar:', verifyMetadata);
|
||||
|
||||
if (newBanner && verifyMetadata.banner !== newBanner) {
|
||||
console.error('[updateBanner] Banner verification FAILED!', 'Expected:', newBanner, 'Got:', verifyMetadata.banner);
|
||||
throw new Error('Banner verification failed');
|
||||
}
|
||||
console.log('[updateBanner] Banner verification passed');
|
||||
|
||||
// Upload modified avatar with correct MIME type
|
||||
const mimeType = getMimeType(format);
|
||||
@@ -172,21 +182,26 @@ export function useUserBanner(): [
|
||||
name: `avatar.${extension}`,
|
||||
type: mimeType,
|
||||
});
|
||||
console.log('[updateBanner] Avatar uploaded successfully, MXC:', uploadResponse.content_uri);
|
||||
|
||||
// Update profile with new avatar
|
||||
try {
|
||||
console.log('[updateBanner] Setting avatar URL to:', uploadResponse.content_uri);
|
||||
await Promise.race([
|
||||
mx.setAvatarUrl(uploadResponse.content_uri),
|
||||
new Promise((_, reject) => {
|
||||
setTimeout(() => reject(new Error('setAvatarUrl timeout')), 30000);
|
||||
})
|
||||
]);
|
||||
console.log('[updateBanner] setAvatarUrl completed');
|
||||
|
||||
// Manually sync user object to ensure event listeners are triggered
|
||||
const user = mx.getUser(userId);
|
||||
if (user && user.avatarUrl !== uploadResponse.content_uri) {
|
||||
console.log('[updateBanner] Manually syncing user avatar URL');
|
||||
user.setAvatarUrl(uploadResponse.content_uri);
|
||||
}
|
||||
console.log('[updateBanner] Banner update complete');
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to update avatar URL: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||
}
|
||||
@@ -217,11 +232,14 @@ export function useOtherUserBanner(userId: string, avatarMxc: string | undefined
|
||||
let blobUrl: string | undefined;
|
||||
|
||||
if (!avatarMxc) {
|
||||
console.log('[useOtherUserBanner] No avatarMxc provided for', userId);
|
||||
setBannerBlobUrl(undefined);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const loadBanner = async () => {
|
||||
console.log('[useOtherUserBanner] Loading banner for', userId, 'avatarMxc:', avatarMxc);
|
||||
|
||||
// Check cache first
|
||||
const cacheKey = `${userId}:${avatarMxc}`;
|
||||
const cached = userBannerCache.get(cacheKey);
|
||||
@@ -230,11 +248,15 @@ export function useOtherUserBanner(userId: string, avatarMxc: string | undefined
|
||||
|
||||
if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) {
|
||||
// Use cached banner MXC
|
||||
console.log('[useOtherUserBanner] Using cached bannerMxc:', cached.bannerMxc);
|
||||
bannerMxc = cached.bannerMxc;
|
||||
} else {
|
||||
// Fetch banner MXC from avatar metadata
|
||||
const httpUrl = mxcUrlToHttp(mx, avatarMxc, useAuthentication);
|
||||
console.log('[useOtherUserBanner] Fetching metadata from:', httpUrl);
|
||||
|
||||
if (!httpUrl) {
|
||||
console.log('[useOtherUserBanner] Failed to get HTTP URL');
|
||||
setBannerBlobUrl(undefined);
|
||||
return;
|
||||
}
|
||||
@@ -243,6 +265,8 @@ export function useOtherUserBanner(userId: string, avatarMxc: string | undefined
|
||||
const accessToken = getCurrentAccessToken();
|
||||
const metadata = await fetchAndExtractMetadata(httpUrl, useAuthentication ? accessToken : null);
|
||||
|
||||
console.log('[useOtherUserBanner] Extracted metadata:', metadata);
|
||||
|
||||
bannerMxc = metadata.banner;
|
||||
|
||||
// Cache the banner MXC (not the blob URL)
|
||||
@@ -250,17 +274,23 @@ export function useOtherUserBanner(userId: string, avatarMxc: string | undefined
|
||||
}
|
||||
|
||||
if (!bannerMxc) {
|
||||
console.log('[useOtherUserBanner] No banner MXC found');
|
||||
setBannerBlobUrl(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[useOtherUserBanner] Fetching banner image from MXC:', bannerMxc);
|
||||
|
||||
// Fetch the banner image data with authentication
|
||||
const bannerHttpUrl = mxcUrlToHttp(mx, bannerMxc, useAuthentication);
|
||||
if (!bannerHttpUrl) {
|
||||
console.log('[useOtherUserBanner] Failed to convert banner MXC to HTTP URL');
|
||||
setBannerBlobUrl(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[useOtherUserBanner] Banner HTTP URL:', bannerHttpUrl);
|
||||
|
||||
// Always use current session's token to avoid stale tokens during account switches
|
||||
const accessToken = getCurrentAccessToken();
|
||||
const headers: HeadersInit = {};
|
||||
|
||||
@@ -260,10 +260,19 @@ const CACHE_TTL_MS = 30 * 60 * 1000; // 30 minutes
|
||||
export function useOtherUserColor(userId: string, avatarMxc: string | undefined): string | undefined {
|
||||
const mx = useMatrixClient();
|
||||
const useAuthentication = useMediaAuthentication();
|
||||
const [color, setColor] = useState<string | undefined>();
|
||||
|
||||
// Check cache synchronously BEFORE initializing state to avoid flash
|
||||
const cacheKey = avatarMxc ? `${userId}:${avatarMxc}` : '';
|
||||
const cachedEntry = cacheKey ? userColorCache.get(cacheKey) : undefined;
|
||||
const cachedColor = cachedEntry && Date.now() - cachedEntry.timestamp < CACHE_TTL_MS
|
||||
? cachedEntry.color
|
||||
: undefined;
|
||||
|
||||
const [color, setColor] = useState<string | undefined>(cachedColor);
|
||||
|
||||
useEffect(() => {
|
||||
if (!avatarMxc) {
|
||||
console.log('[useOtherUserColor] No avatarMxc provided for', userId);
|
||||
setColor(undefined);
|
||||
return;
|
||||
}
|
||||
@@ -272,13 +281,16 @@ export function useOtherUserColor(userId: string, avatarMxc: string | undefined)
|
||||
const cacheKey = `${userId}:${avatarMxc}`;
|
||||
const cached = userColorCache.get(cacheKey);
|
||||
if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) {
|
||||
console.log('[useOtherUserColor] Using cached color for', userId, ':', cached.color);
|
||||
setColor(cached.color);
|
||||
return;
|
||||
}
|
||||
|
||||
const loadColor = async () => {
|
||||
const httpUrl = mxcUrlToHttp(mx, avatarMxc, useAuthentication);
|
||||
console.log('[useOtherUserColor] Loading color for', userId, 'from', httpUrl);
|
||||
if (!httpUrl) {
|
||||
console.log('[useOtherUserColor] Failed to get HTTP URL for', avatarMxc);
|
||||
setColor(undefined);
|
||||
return;
|
||||
}
|
||||
@@ -287,6 +299,8 @@ export function useOtherUserColor(userId: string, avatarMxc: string | undefined)
|
||||
const accessToken = getCurrentAccessToken();
|
||||
const extractedColor = await fetchAndExtractColor(httpUrl, useAuthentication ? accessToken : null);
|
||||
|
||||
console.log('[useOtherUserColor] Extracted color for', userId, ':', extractedColor);
|
||||
|
||||
// Cache the result
|
||||
userColorCache.set(cacheKey, { color: extractedColor, timestamp: Date.now() });
|
||||
|
||||
|
||||
@@ -212,22 +212,29 @@ export function useOtherUserProfileStyle(userId: string, avatarMxc: string | und
|
||||
|
||||
useEffect(() => {
|
||||
if (!avatarMxc) {
|
||||
console.log('[useOtherUserProfileStyle] No avatarMxc provided for', userId);
|
||||
setStyle({});
|
||||
return;
|
||||
}
|
||||
|
||||
const loadStyle = async () => {
|
||||
console.log('[useOtherUserProfileStyle] Loading style for', userId, 'avatarMxc:', avatarMxc);
|
||||
|
||||
// Check cache first
|
||||
const cacheKey = `${userId}:${avatarMxc}`;
|
||||
const cached = userStyleCache.get(cacheKey);
|
||||
|
||||
if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) {
|
||||
console.log('[useOtherUserProfileStyle] Using cached style:', cached.style);
|
||||
setStyle(cached.style);
|
||||
return;
|
||||
}
|
||||
|
||||
const httpUrl = mxcUrlToHttp(mx, avatarMxc, useAuthentication);
|
||||
console.log('[useOtherUserProfileStyle] Fetching metadata from:', httpUrl);
|
||||
|
||||
if (!httpUrl) {
|
||||
console.log('[useOtherUserProfileStyle] Failed to get HTTP URL');
|
||||
setStyle({});
|
||||
return;
|
||||
}
|
||||
@@ -236,11 +243,15 @@ export function useOtherUserProfileStyle(userId: string, avatarMxc: string | und
|
||||
const accessToken = getCurrentAccessToken();
|
||||
const metadata = await fetchAndExtractMetadata(httpUrl, useAuthentication ? accessToken : null);
|
||||
|
||||
console.log('[useOtherUserProfileStyle] Extracted metadata:', metadata);
|
||||
|
||||
const styleData: ProfileStyleData = {
|
||||
avatarBorderColor: metadata.avatarBorderColor,
|
||||
gradient: metadata.gradient,
|
||||
};
|
||||
|
||||
console.log('[useOtherUserProfileStyle] Final styleData:', styleData);
|
||||
|
||||
// Cache the result
|
||||
userStyleCache.set(cacheKey, { style: styleData, timestamp: Date.now() });
|
||||
setStyle(styleData);
|
||||
|
||||
Reference in New Issue
Block a user