File size: 2,814 Bytes
921d377
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/**
 * UserAvatar — displays a user's avatar image or a generated initials fallback.
 *
 * Usage:
 *   <UserAvatar displayName="Alice" avatarUrl="/files/avatar_xxx.png" size={40} />
 *   <UserAvatar displayName="Bob" size={32} />  // shows initials "B"
 *
 * ADDITIVE ONLY — new component, does not modify existing code.
 */
import React, { useState } from 'react';
import { resolveBackendUrl } from '../lib/backendUrl';
/** Deterministic color from a string (name-based, visually distinct). */
function nameToColor(name) {
    const colors = [
        '#3b82f6', '#8b5cf6', '#ec4899', '#06b6d4', '#f59e0b',
        '#10b981', '#ef4444', '#6366f1', '#14b8a6', '#f97316',
    ];
    let hash = 0;
    for (let i = 0; i < name.length; i++) {
        hash = name.charCodeAt(i) + ((hash << 5) - hash);
    }
    return colors[Math.abs(hash) % colors.length];
}
function getInitials(name) {
    const parts = (name || '').trim().split(/\s+/);
    if (parts.length >= 2) {
        return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
    }
    return (name || '?')[0].toUpperCase();
}
export default function UserAvatar({ displayName, avatarUrl, size = 40, onClick, style, }) {
    const [imgError, setImgError] = useState(false);
    const hasImage = avatarUrl && !imgError;
    const baseStyle = {
        width: size,
        height: size,
        borderRadius: '50%',
        overflow: 'hidden',
        flexShrink: 0,
        cursor: onClick ? 'pointer' : 'default',
        ...style,
    };
    if (hasImage) {
        // Resolve relative URLs against the backend, append auth token for /files/ paths
        const backendUrl = resolveBackendUrl();
        let fullUrl = avatarUrl.startsWith('http') ? avatarUrl : `${backendUrl}${avatarUrl}`;
        if (fullUrl.includes('/files/')) {
            const tok = localStorage.getItem('homepilot_auth_token') || '';
            if (tok) {
                const sep = fullUrl.includes('?') ? '&' : '?';
                fullUrl = `${fullUrl}${sep}token=${encodeURIComponent(tok)}`;
            }
        }
        return (<div style={baseStyle} onClick={onClick}>
        <img src={fullUrl} alt={displayName} onError={() => setImgError(true)} style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}/>
      </div>);
    }
    // Initials fallback
    const bg = nameToColor(displayName);
    return (<div style={{
            ...baseStyle,
            background: bg,
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            color: '#fff',
            fontWeight: 700,
            fontSize: Math.round(size * 0.4),
            fontFamily: 'system-ui, sans-serif',
            userSelect: 'none',
        }} onClick={onClick}>
      {getInitials(displayName)}
    </div>);
}