Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 31 additions & 9 deletions src/components/image.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import md5 from 'md5';

import { parseSize, calculateBorderRadius, getNullableText } from '../utils';
import Wrapper from './wrapper';

export default
class AvatarImage extends React.PureComponent {

export default class AvatarImage extends React.PureComponent {
static propTypes = {
alt: PropTypes.oneOfType([
PropTypes.string,
Expand All @@ -19,7 +18,7 @@ class AvatarImage extends React.PureComponent {
name: PropTypes.string,
value: PropTypes.string,
avatar: PropTypes.object,

email: PropTypes.string, // Add email prop for Gravatar
className: PropTypes.string,
unstyled: PropTypes.bool,
round: PropTypes.oneOfType([
Expand All @@ -31,14 +30,35 @@ class AvatarImage extends React.PureComponent {
PropTypes.number,
PropTypes.string
]),
}
fallback: PropTypes.string, // Optional fallback prop for Gravatar fallback
onError: PropTypes.func // Allow passing an external onError prop
};

static defaultProps = {
className: '',
round: false,
size: 100,
unstyled: false
}
unstyled: false,
fallback: 'blank', // Default to 'blank' if no fallback is provided
onError: null // No default external onError
};

handleImageError = (e) => {
const { email, fallback, onError } = this.props;

// Only run fallback logic if fallback is explicitly provided
if (fallback) {
const emailHash = email ? md5(email.trim().toLowerCase()) : ''; // Hash the email for Gravatar

// Set the fallback URL with the hashed email and fallback option
e.target.src = `https://www.gravatar.com/avatar/${emailHash}?d=${encodeURIComponent(fallback)}`;
}

// If there's an external onError handler, call it as well
if (onError) {
onError(e);
}
};

render() {
const {
Expand All @@ -49,7 +69,8 @@ class AvatarImage extends React.PureComponent {
title,
name,
value,
avatar
avatar,
email, // Email used for Gravatar hash
} = this.props;

const size = parseSize(this.props.size);
Expand All @@ -70,7 +91,8 @@ class AvatarImage extends React.PureComponent {
src={avatar.src}
alt={getNullableText(alt, name || value)}
title={getNullableText(title, name || value)}
onError={avatar.onRenderFailed} />
onError={this.handleImageError} // Call the error handler to use fallback and external onError
/>
</Wrapper>
);
}
Expand Down
22 changes: 20 additions & 2 deletions src/sources/Gravatar.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,25 @@ import md5 from 'md5';

import { getImageSize } from '../utils';

// Define valid Gravatar fallback options
const validGravatarFallbacks = [
'404', // Do not load any image, return a 404
'mp', // Mystery Person
'identicon', // Geometric pattern based on email hash
'monsterid', // A generated monster image
'wavatar', // A generated face
'retro', // 8-bit retro avatar
'robohash', // Robot based on hash
'blank' // Transparent, blank image
];

export default
class GravatarSource {

static propTypes = {
email: PropTypes.string,
md5Email: PropTypes.string
md5Email: PropTypes.string,
fallback: PropTypes.string
}

props = null;
Expand All @@ -29,7 +41,13 @@ class GravatarSource {
const email = props.md5Email || md5(props.email);
const size = getImageSize(props.size);

let url = `https://secure.gravatar.com/avatar/${email}?d=404`;
// Check if the provided fallback is a valid Gravatar option or a URL
let fallback = validGravatarFallbacks.includes(props.fallback)
? props.fallback
: encodeURIComponent(props.fallback || 'blank'); // Use fallback, or default to 'blank'

// Construct the Gravatar URL with the valid fallback
let url = `https://secure.gravatar.com/avatar/${email}?d=${fallback}`;

if (size)
url += `&s=${size}`;
Expand Down