Skip to content

Commit

Permalink
feat(discussions): add avatars (#3587)
Browse files Browse the repository at this point in the history
  • Loading branch information
benfurber authored Jun 3, 2024
2 parents 8d1796b + c97ad47 commit e296c10
Show file tree
Hide file tree
Showing 22 changed files with 345 additions and 155 deletions.
44 changes: 35 additions & 9 deletions functions/src/userUpdates/hasKeyDetailsChanged.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { hasKeyDetailsChanged } from './hasKeyDetailsChanged'
import {
hasCoverImagesChanged,
hasKeyDetailsChanged,
} from './hasKeyDetailsChanged'

import type { IUserDB } from '../../../src/models'

Expand All @@ -10,6 +13,11 @@ describe('hasKeyDetailsChanged', () => {
} as IUserDB
const user = {
displayName: 'new name',
coverImages: [
{
downloadUrl: 'http//etc.',
},
],
location: { countryCode: 'USA' },
badges: { verified: true },
} as IUserDB
Expand All @@ -18,23 +26,41 @@ describe('hasKeyDetailsChanged', () => {
})

it('returns false when details are the same', () => {
const prevUser = {
const user = {
displayName: 'same name',
location: { countryCode: 'USA' },
coverImages: [
{
downloadUrl: 'http://etc.',
},
],
badges: {
verified: true,
supporter: false,
},
} as IUserDB

expect(hasKeyDetailsChanged(user, user)).toEqual(false)
})
})

describe('hasKeyDetailsChanged', () => {
it('returns false when coverImage array is missing from both', () => {
const user = {} as IUserDB
expect(hasCoverImagesChanged(user, user)).toEqual(false)
})

it('returns false when coverImage array is empty for both', () => {
const user = {
displayName: 'same name',
location: { countryCode: 'USA' },
badges: {
verified: true,
supporter: false,
},
coverImages: [],
} as IUserDB
expect(hasCoverImagesChanged(user, user)).toEqual(false)
})

expect(hasKeyDetailsChanged(prevUser, user)).toEqual(false)
it('returns false when coverImage first item is the same for both', () => {
const user = {
coverImages: [{ downloadUrl: 'same' }],
} as IUserDB
expect(hasCoverImagesChanged(user, user)).toEqual(false)
})
})
15 changes: 15 additions & 0 deletions functions/src/userUpdates/hasKeyDetailsChanged.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
import { valuesAreDeepEqual } from '../Utils'

import type { IUserDB } from '../models'

export const hasKeyDetailsChanged = (prevUser: IUserDB, user: IUserDB) => {
const detailsChanged = [
prevUser.displayName !== user.displayName,
prevUser.location?.countryCode !== user.location?.countryCode,
hasCoverImagesChanged(prevUser, user),
prevUser.badges?.verified !== user.badges?.verified,
prevUser.badges?.supporter !== user.badges?.supporter,
]
return !!detailsChanged.find((detail) => detail === true)
}

export const hasCoverImagesChanged = (prevUser: IUserDB, user: IUserDB) => {
if (!prevUser.coverImages && !user.coverImages) return false

if (prevUser.coverImages && user.coverImages) {
if (!prevUser.coverImages[0] && !user.coverImages[0]) return false

return !valuesAreDeepEqual(prevUser.coverImages, user.coverImages)
}

return false
}
14 changes: 14 additions & 0 deletions functions/src/userUpdates/updateDiscussionComments.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import type { IUserDB } from '../models'
const prevUser = {
_id: 'hjg235z',
location: { countryCode: 'UK' },
coverImages: [
{
downloadUrl: 'https://avatars.githubusercontent.com/u/16688508',
},
],
badges: {
verified: true,
},
Expand All @@ -15,6 +20,7 @@ const userComment = {
_creatorId: prevUser._id,
creatorName: prevUser.displayName,
creatorCountry: prevUser.location.countryCode,
creatorImage: prevUser.coverImages[0].downloadUrl,
isUserVerified: prevUser.badges.verified,
comment: 'Great Post',
}
Expand Down Expand Up @@ -61,16 +67,24 @@ describe('updateDiscussionComments', () => {
const user = {
...prevUser,
location: { countryCode: 'New' },
coverImages: [
{
downloadUrl: 'https://avatars.githubusercontent.com/u/13672737?v=4',
},
],
badges: {
verified: false,
supporter: true,
},
} as IUserDB

getMock.mockResolvedValue(snapshot(discussion))

await updateDiscussionComments(prevUser, user)

const expectedUpdatedComment = expect.objectContaining({
creatorCountry: user.location.countryCode,
creatorImage: user.coverImages[0].downloadUrl,
isUserVerified: user.badges.verified,
isUserSupporter: user.badges.supporter,
})
Expand Down
56 changes: 34 additions & 22 deletions functions/src/userUpdates/updateDiscussionComments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,46 @@ export const updateDiscussionComments = async (
) => {
if (!hasKeyDetailsChanged(prevUser, user)) return

let updatedCommentCount = 0

const { _id, badges, location } = user
const userDetails = {
creatorCountry: location?.countryCode || '',
isUserVerified: !!badges?.verified,
isUserSupporter: !!badges?.supporter,
}

const snapshot = await db
.collection(DB_ENDPOINTS.discussions)
.where('contributorIds', 'array-contains', _id)
.where('contributorIds', 'array-contains', user._id)
.get()

for (const doc of snapshot.docs) {
const discussion = doc.data() as IDiscussion
if (!snapshot.empty) {
const { _id, badges, coverImages, location } = user
const creatorImage = getCreatorImage(coverImages)

const userDetails = {
creatorCountry: location?.countryCode || '',
...(creatorImage ? { creatorImage } : {}),
isUserVerified: !!badges?.verified,
isUserSupporter: !!badges?.supporter,
}

let updatedCommentCount = 0

const comments = discussion.comments.map((comment) => {
if (comment._creatorId !== _id) return comment
for (const doc of snapshot.docs) {
const discussion = doc.data() as IDiscussion

updatedCommentCount++
return {
...comment,
...userDetails,
}
})
const comments = discussion.comments.map((comment) => {
if (comment._creatorId !== _id) return comment

updatedCommentCount++
return {
...comment,
...userDetails,
}
})

await doc.ref.update({ comments })
}
return console.log(`Updated ${updatedCommentCount} discussion comments`)
}
}

await doc.ref.update({ comments })
const getCreatorImage = (coverImages) => {
if (coverImages && coverImages[0] && coverImages[0].downloadUrl) {
return coverImages[0].downloadUrl
}
console.log(`Updated ${updatedCommentCount} discussion comments`)
return undefined
}
24 changes: 13 additions & 11 deletions packages/components/src/CommentItem/CommentItem.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { faker } from '@faker-js/faker'

import { fakeComment } from '../utils'
import { CommentItem } from './CommentItem'

Expand All @@ -9,40 +11,40 @@ export default {
} as Meta<typeof CommentItem>

export const Default: StoryFn<typeof CommentItem> = () => {
const comment = fakeComment({ creatorImage: faker.image.avatar() })

return <CommentItem isReply={false} comment={comment} showAvatar />
}

export const WithoutAvatar: StoryFn<typeof CommentItem> = () => {
const comment = fakeComment()

return <CommentItem isReply={false} comment={comment} />
return <CommentItem isReply={false} comment={comment} showAvatar={false} />
}

export const Editable: StoryFn<typeof CommentItem> = () => {
const comment = fakeComment({ isEditable: true })

return <CommentItem isReply={false} comment={comment} />
return <CommentItem isReply={false} comment={comment} showAvatar />
}

export const Edited: StoryFn<typeof CommentItem> = () => {
const comment = fakeComment({ _edited: new Date().toISOString() })

return <CommentItem isReply={false} comment={comment} />
return <CommentItem isReply={false} comment={comment} showAvatar />
}

export const LongText: StoryFn<typeof CommentItem> = () => {
const text = `Ut dignissim, odio a cursus pretium, erat ex dictum quam, a eleifend augue mauris vel metus. Suspendisse pellentesque, elit efficitur rutrum maximus, arcu enim congue ipsum, vel aliquam ipsum urna quis tellus. Mauris at imperdiet nisi. Integer at neque ex. Nullam vel ipsum sodales, porttitor nulla vitae, tincidunt est. Pellentesque vitae lectus arcu. Integer dapibus rutrum facilisis. Nullam tincidunt quam at arcu interdum, vitae egestas libero vehicula. Morbi metus tortor, dapibus id finibus ac, egestas quis leo. Phasellus scelerisque suscipit mauris sed rhoncus. In quis ultricies ipsum. Integer vitae iaculis risus, sit amet elementum augue. Pellentesque vitae sagittis erat, eget consectetur lorem.\n\nUt pharetra molestie quam id dictum. In molestie, arcu sit amet faucibus pulvinar, eros erat egestas leo, at molestie nunc velit a arcu. Aliquam erat volutpat. Vivamus vehicula mi sit amet nibh auctor efficitur. Duis fermentum sem et nibh facilisis, ut tincidunt sem commodo. Nullam ornare ex a elementum accumsan. Etiam a neque ut lacus suscipit blandit. Maecenas id tortor velit.\n\nInterdum et malesuada fames ac ante ipsum primis in faucibus. Nam ut commodo tellus. Maecenas at leo metus. Vivamus ullamcorper ex purus, volutpat auctor nunc lobortis a. Integer sit amet ornare nisi, sed ultrices enim. Pellentesque ut aliquam urna, eu fringilla ante. Nullam dui nibh, feugiat id vestibulum nec, efficitur a lorem. In vitae pellentesque tellus. Pellentesque sed odio iaculis, imperdiet turpis at, aliquam ex. Praesent iaculis bibendum nibh, vel egestas turpis ultrices ac. Praesent tincidunt libero sed gravida ornare. Aliquam vehicula risus ut molestie suscipit. Nunc erat odio, venenatis nec posuere in, placerat eget massa. Sed in ultrices ex, vel egestas quam. Integer lectus magna, ornare at nisl sed, convallis euismod enim. Cras pretium commodo arcu non bibendum.\n\nNullam dictum lectus felis. Duis vitae lacus vitae nisl aliquet faucibus. Integer neque lacus, dignissim sed mi et, dignissim luctus metus. Cras sollicitudin vestibulum leo, ac ultrices sapien bibendum ac. Phasellus lobortis aliquam libero eu volutpat. Donec vitae rutrum tellus. Fusce vel ante ipsum. Suspendisse mollis tempus porta. Sed a orci tempor, rhoncus tortor eu, sodales justo.`
const comment = fakeComment({ text })

return <CommentItem isReply={true} comment={comment} />
}

export const ShortText: StoryFn<typeof CommentItem> = () => {
const comment = fakeComment({ text: `Ut dignissim, odio a cursus pretium.` })

return <CommentItem isReply={false} comment={comment} />
return <CommentItem isReply={true} comment={comment} showAvatar />
}

export const ShortTextWithLink: StoryFn<typeof CommentItem> = () => {
const comment = fakeComment({
text: `Ut dignissim, odio a cursus pretium. https://example.com`,
})

return <CommentItem isReply={true} comment={comment} />
return <CommentItem isReply={true} comment={comment} showAvatar />
}
20 changes: 20 additions & 0 deletions packages/components/src/CommentItem/CommentItem.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { render } from '../tests/utils'
import { Default, WithoutAvatar } from './CommentItem.stories'

import type { IProps } from './CommentItem'

describe('CommentList', () => {
it('shows the avatar when set', () => {
const { getByTestId } = render(<Default {...(Default.args as IProps)} />)

expect(getByTestId('commentAvatar')).toBeInTheDocument()
})

it('hides the avatar when set', () => {
const { getByTestId } = render(
<WithoutAvatar {...(WithoutAvatar.args as IProps)} />,
)

expect(() => getByTestId('commentAvatar')).toThrow()
})
})
Loading

0 comments on commit e296c10

Please sign in to comment.