Skip to content

Conversation

myrta2302
Copy link
Contributor

@myrta2302 myrta2302 commented Jul 23, 2025

📄 Description

This PR updates the <post-avatar> component to better handle cases where no Gravatar image is found, with the following:

  1. The name initials are displayed by default before any image fetch.
  2. The getImageByProp() function now first checks for a cached failed image url to avoid unnecessary fetch.
  3. Introduces the storageKey as a combination of userid and email props to track changes and refresh the avatar accordingly.

📝 Checklist

  • ✅ My code follows the style guidelines of this project
  • 🛠️ I have performed a self-review of my own code
  • ⚠️ My changes generate no new warnings or errors
  • ✔️ New and existing unit tests pass locally with my changes

Copy link

changeset-bot bot commented Jul 23, 2025

🦋 Changeset detected

Latest commit: 03d002e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 12 packages
Name Type
@swisspost/design-system-components Patch
@swisspost/design-system-components-angular-workspace Patch
@swisspost/design-system-components-react Patch
@swisspost/design-system-documentation Patch
@swisspost/design-system-components-angular Patch
@swisspost/design-system-nextjs-integration Patch
@swisspost/design-system-styles Patch
@swisspost/design-system-tokens Patch
@swisspost/design-system-icons Patch
@swisspost/design-system-styles-primeng Patch
@swisspost/internet-header Patch
@swisspost/design-system-styles-primeng-workspace Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@swisspost-bot
Copy link
Contributor

swisspost-bot commented Jul 23, 2025

Related Previews

@myrta2302 myrta2302 marked this pull request as ready for review July 23, 2025 13:40
@myrta2302 myrta2302 requested a review from a team as a code owner July 23, 2025 13:40
@myrta2302 myrta2302 requested a review from alizedebray July 23, 2025 13:40
@myrta2302 myrta2302 requested a review from alizedebray July 25, 2025 13:42
Copy link
Contributor

@oliverschuerch oliverschuerch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The gravatar is not working anymore
image

Copy link
Contributor

@oliverschuerch oliverschuerch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it's working now, I'm fine with it generally.

However, I have two concerns:

  1. It's not only fixing a bug, but adding features, therefore, please update the changeset file or split the pr into a bugfix and a feature (if possible).
  2. Let @alizedebray review it as well, because I expect, she could be not fully ok with the change, since it is not exactly what she demanded for.

Comment on lines +3 to +18
const GRAVATAR_DEFAULT = '404';
const GRAVATAR_RATING = 'g';
const GRAVATAR_SIZE = 80;

function getGravatarUrl(email: string): string {
const hash = cryptify(email.trim().toLowerCase());
return `https://www.gravatar.com/avatar/${hash}?s=${GRAVATAR_SIZE}&d=${GRAVATAR_DEFAULT}&r=${GRAVATAR_RATING}`;
}

async function cryptify(key: string) {
return await crypto.subtle.digest('SHA-256', new TextEncoder().encode(key)).then(buffer => {
return Array.from(new Uint8Array(buffer))
.map(bytes => bytes.toString(16).padStart(2, '0'))
.join('');
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice, if we could share these constants and logic somehow between the component and the e2e test.
For example store and export them in a dedicated file aside the post-avatar.tsx, so you can use the same source on both sides.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about that topic? Is something not clear?
I can't see any change, nor any message, why we should not do this.

@alizedebray alizedebray removed their request for review August 19, 2025 14:57
@myrta2302
Copy link
Contributor Author

myrta2302 commented Aug 26, 2025

Functionality Changes

  • Add AvatarStorage interface
  • Introduce @State() storageKey
  • Add a double watcher on two props (userId, email); when either changes:
    a) Reset the image
    b) Initialize storage to an empty object
    c) Set avatar type to default (initials)
    d) Call this.getAvatar() to fetch the image
  • On onSlotChange, update avatar type and perform related actions
  • Load avatar initials on componentWillLoad
  • Fetch avatar image on componentWillRender
  • Store fetch results (URL or error) in sessionStorage under the storage key
  • Session storage entries are never removed or reused to cache the already fetched keys (pairs of userId/email)

@myrta2302 myrta2302 modified the milestone: v10.0.0 Release Sep 1, 2025
Copy link

sonarqubecloud bot commented Sep 2, 2025

Comment on lines +125 to +132
if (!imageResponse?.ok) {
return false;
}
if (imageResponse.ok) {
this.imageUrl = imageResponse.url;
this.imageAlt = `${this.firstname} ${this.lastname} avatar`;
this.avatarType = AvatarType.Image;
return true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be an if/else statement.
if imageResponse.ok use it, else return false;

Or keep the return imageResponse.ok; as it was.

this.slottedImage = this.host.querySelector('img');
this.getAvatar();
connectedCallback() {
this.getAvatarInitials();
Copy link
Contributor

@oliverschuerch oliverschuerch Sep 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment in the code to explain, why this is necessary.

}

componentDidLoad() {
componentWillLoad() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there was a reason, why we had to validate only on componentDidLoad.
Have a look into the other components to find out, if this change should be reverted.

}
});
this.getAvatarImage();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}
}

Comment on lines +118 to +119
let imageResponse: Response;
try {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let imageResponse: Response;
try {
let imageResponse: Response;
try {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add some empty lines between var definition and if statements which do not belong together, in getAvatarImage function, to improve readability.

Comment on lines 76 to 86
@Watch('userid')
validateUserid() {
checkEmptyOrType(this, 'userid', 'string');
this.getAvatarImage();
}

@Watch('email')
validateEmail() {
if (this.email) checkEmptyOrPattern(this, 'email', emailPattern);
this.getAvatarImage();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving this as is, and calling the validateUserId and validateEmail function on componentWillLoad causes the getAvatarImage function to be called three times on startup.

  1. In the connectedCallback (which is the only one that should be called initially)
  2. In validateUserId triggered by componentWillLoad
  3. In validateEmail triggered by componentWillLoad

Please make it possible to call the validation functions without triggering the getAvatarImage.

For example:

// like so, `updateUserId()` is only called when 'userid' gets an update
@Watch('userid')
updateUserid() {
  this.validateUserid();
  this.getAvatarImage();
}

// while the `validateUserid()` function can be called initially and when the `userid` chages
private validateUserid() {
  checkEmtpyOrType(this, 'userid', 'string');
}

connectedCallback() {
  // this should be the only inital call to `getAvatarImage()`
  this.getAvatarImage();
}

componentDidLoad() {
  // initially only call the validation
  this.validateUserid();
}

cy.get('@avatar').find('img').should('not.exist');
cy.get('@avatar').find('.initials').should('exist');
});

it('should not show image bur fallback to initials, when slotted image is invalid', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
it('should not show image bur fallback to initials, when slotted image is invalid', () => {
it('should not show image but fallback to initials, when slotted image is invalid', () => {

'append',
'<img src="/assets/images/invalid-image.svg" alt="Invalid image" />',
);
cy.get('@avatar').find('.initials').should('exist');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should also check if the slotted image is not visible

Comment on lines +3 to +18
const GRAVATAR_DEFAULT = '404';
const GRAVATAR_RATING = 'g';
const GRAVATAR_SIZE = 80;

function getGravatarUrl(email: string): string {
const hash = cryptify(email.trim().toLowerCase());
return `https://www.gravatar.com/avatar/${hash}?s=${GRAVATAR_SIZE}&d=${GRAVATAR_DEFAULT}&r=${GRAVATAR_RATING}`;
}

async function cryptify(key: string) {
return await crypto.subtle.digest('SHA-256', new TextEncoder().encode(key)).then(buffer => {
return Array.from(new Uint8Array(buffer))
.map(bytes => bytes.toString(16).padStart(2, '0'))
.join('');
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about that topic? Is something not clear?
I can't see any change, nor any message, why we should not do this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[bug]: post-avatar is continuously logging errors if no gravatar is found
4 participants