compute and cache popover props in helper to avoid react_on_rails cache bugs
This commit is contained in:
@@ -8,6 +8,7 @@ module Domain::DescriptionsHelper
|
||||
include HelpersInterface
|
||||
include Domain::PostsHelper
|
||||
include Domain::DomainsHelper
|
||||
include Domain::UsersHelper
|
||||
requires_ancestor { Object }
|
||||
|
||||
abstract!
|
||||
@@ -204,4 +205,76 @@ module Domain::DescriptionsHelper
|
||||
"blue-link"
|
||||
end
|
||||
end
|
||||
|
||||
sig do
|
||||
params(user: Domain::User, visual_style: String, icon_size: String).returns(
|
||||
T::Hash[Symbol, T.untyped],
|
||||
)
|
||||
end
|
||||
def props_for_user_hover_preview(user, visual_style, icon_size)
|
||||
Rails
|
||||
.cache
|
||||
.fetch(
|
||||
[user, "popover_inline_link_domain_user", visual_style, icon_size],
|
||||
) do
|
||||
num_posts =
|
||||
user.has_created_posts? ? user.user_post_creations.count : nil
|
||||
registered_at = domain_user_registered_at_string_for_view(user)
|
||||
num_followed_by =
|
||||
user.has_followed_by_users? ? user.user_user_follows_to.count : nil
|
||||
num_followed =
|
||||
user.has_followed_users? ? user.user_user_follows_from.count : nil
|
||||
avatar_thumb_size = icon_size == "large" ? "64-avatar" : "32-avatar"
|
||||
|
||||
{
|
||||
visualStyle: visual_style,
|
||||
iconSize: icon_size,
|
||||
linkText: user.name_for_view,
|
||||
userId: user.to_param,
|
||||
userName: user.name_for_view,
|
||||
userPath: domain_user_path(user),
|
||||
userSmallAvatarPath:
|
||||
domain_user_avatar_img_src_path(
|
||||
user.avatar,
|
||||
thumb: avatar_thumb_size,
|
||||
),
|
||||
userAvatarPath: domain_user_avatar_img_src_path(user.avatar),
|
||||
userAvatarAlt: "View #{user.name_for_view}'s profile",
|
||||
userDomainIcon: domain_model_icon_path(user),
|
||||
userNumPosts: num_posts,
|
||||
userRegisteredAt: registered_at,
|
||||
userNumFollowedBy: num_followed_by,
|
||||
userNumFollowed: num_followed,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
sig do
|
||||
params(post: Domain::Post, link_text: String, visual_style: String).returns(
|
||||
T::Hash[Symbol, T.untyped],
|
||||
)
|
||||
end
|
||||
def props_for_post_hover_preview(post, link_text, visual_style)
|
||||
Rails
|
||||
.cache
|
||||
.fetch([post, "popover_inline_link_domain_post", visual_style]) do
|
||||
props = {
|
||||
visualStyle: visual_style,
|
||||
linkText: link_text,
|
||||
postId: post.to_param,
|
||||
postTitle: post.title,
|
||||
postPath: Rails.application.routes.url_helpers.domain_post_path(post),
|
||||
postThumbnailPath: thumbnail_for_post_path(post),
|
||||
postThumbnailAlt: "View on #{domain_name_for_model(post)}",
|
||||
postDomainIcon: domain_model_icon_path(post),
|
||||
}
|
||||
|
||||
if creator = post.primary_creator_for_view
|
||||
props[:creatorName] = creator.name_for_view
|
||||
props[:creatorAvatarPath] = user_avatar_path_for_view(creator)
|
||||
end
|
||||
|
||||
props
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -29,6 +29,21 @@ export const PostHoverPreview: React.FC<PostHoverPreviewProps> = ({
|
||||
creatorName,
|
||||
creatorAvatarPath,
|
||||
}) => {
|
||||
// Force eager loading of images
|
||||
React.useEffect(() => {
|
||||
// Preload post thumbnail
|
||||
if (postThumbnailPath) {
|
||||
const thumbnailImg = new Image();
|
||||
thumbnailImg.src = postThumbnailPath;
|
||||
}
|
||||
|
||||
// Preload creator avatar
|
||||
if (creatorAvatarPath) {
|
||||
const avatarImg = new Image();
|
||||
avatarImg.src = creatorAvatarPath;
|
||||
}
|
||||
}, [postThumbnailPath, creatorAvatarPath]);
|
||||
|
||||
// Add extra classes for PostHoverPreview's header/footer
|
||||
const postHeaderFooterClassName = `${getHeaderFooterClassName()} justify-between p-3`;
|
||||
|
||||
|
||||
@@ -35,6 +35,14 @@ export const UserHoverPreview: React.FC<UserHoverPreviewProps> = ({
|
||||
userNumFollowedBy,
|
||||
userNumFollowed,
|
||||
}) => {
|
||||
// Force eager loading of the avatar image
|
||||
React.useEffect(() => {
|
||||
if (userAvatarPath) {
|
||||
const img = new Image();
|
||||
img.src = userAvatarPath;
|
||||
}
|
||||
}, [userAvatarPath]);
|
||||
|
||||
const previewContent = (
|
||||
<>
|
||||
{/* Header: User Name and Domain Icon */}
|
||||
|
||||
@@ -2,27 +2,15 @@
|
||||
<%# sky-link (default, normal blue link) %>
|
||||
<%# description-section-link (smaller and has a border, for use in description section) %>
|
||||
<% visual_style = local_assigns[:visual_style] || "sky-link" %>
|
||||
<% cache [post, "popover_inline_link_domain_post", visual_style] do %>
|
||||
<% link_classes = link_classes_for_visual_style(visual_style) %>
|
||||
<%= react_component(
|
||||
<%=
|
||||
react_component(
|
||||
"PostHoverPreviewWrapper",
|
||||
{
|
||||
prerender: false,
|
||||
props: {
|
||||
visualStyle: visual_style,
|
||||
linkText: link_text,
|
||||
postId: post.to_param,
|
||||
postTitle: post.title,
|
||||
postPath: domain_post_path(post),
|
||||
postThumbnailPath: thumbnail_for_post_path(post),
|
||||
postThumbnailAlt: "View on #{domain_name_for_model(post)}",
|
||||
postDomainIcon: domain_model_icon_path(post),
|
||||
creatorName: post.primary_creator_for_view&.name_for_view,
|
||||
creatorAvatarPath: post.primary_creator_for_view ? user_avatar_path_for_view(post.primary_creator_for_view) : nil,
|
||||
},
|
||||
props: props_for_post_hover_preview(post, link_text, visual_style),
|
||||
html_options: {
|
||||
class: link_classes
|
||||
class: link_classes_for_visual_style(visual_style)
|
||||
}
|
||||
}
|
||||
) %>
|
||||
<% end %>
|
||||
)
|
||||
%>
|
||||
|
||||
@@ -6,36 +6,15 @@
|
||||
<%# large %>
|
||||
<% visual_style = local_assigns[:visual_style] || "sky-link" %>
|
||||
<% icon_size = local_assigns[:icon_size] || "small" %>
|
||||
<% cache [user, "popover_inline_link_domain_user", visual_style, icon_size] do %>
|
||||
<% link_classes = link_classes_for_visual_style(visual_style) %>
|
||||
<% num_posts = user.has_created_posts? ? user.user_post_creations.count : nil %>
|
||||
<% registered_at = domain_user_registered_at_string_for_view(user) %>
|
||||
<% num_followed_by = user.has_followed_by_users? ? user.user_user_follows_to.count : nil %>
|
||||
<% num_followed = user.has_followed_users? ? user.user_user_follows_from.count : nil %>
|
||||
<% avatar_thumb_size = icon_size == "large" ? "64-avatar" : "32-avatar" %>
|
||||
<%= react_component(
|
||||
<%=
|
||||
react_component(
|
||||
"UserHoverPreviewWrapper",
|
||||
{
|
||||
prerender: false,
|
||||
props: {
|
||||
visualStyle: visual_style,
|
||||
iconSize: icon_size,
|
||||
linkText: user.name_for_view,
|
||||
userId: user.to_param,
|
||||
userName: user.name,
|
||||
userPath: domain_user_path(user),
|
||||
userSmallAvatarPath: domain_user_avatar_img_src_path(user.avatar, thumb: avatar_thumb_size),
|
||||
userAvatarPath: domain_user_avatar_img_src_path(user.avatar),
|
||||
userAvatarAlt: "View #{user.name}'s profile",
|
||||
userDomainIcon: domain_model_icon_path(user),
|
||||
userNumPosts: num_posts,
|
||||
userRegisteredAt: registered_at,
|
||||
userNumFollowedBy: num_followed_by,
|
||||
userNumFollowed: num_followed,
|
||||
},
|
||||
props: props_for_user_hover_preview(user, visual_style, icon_size),
|
||||
html_options: {
|
||||
class: link_classes
|
||||
class: link_classes_for_visual_style(visual_style)
|
||||
}
|
||||
}
|
||||
) %>
|
||||
<% end %>
|
||||
)
|
||||
%>
|
||||
|
||||
Reference in New Issue
Block a user