Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: verified icon in usernames #1205

Merged
merged 7 commits into from
Feb 17, 2022
Merged
Show file tree
Hide file tree
Changes from 6 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
19 changes: 11 additions & 8 deletions src/components/Comment/Comment.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import React, { useState } from 'react'
import { FaTrash, FaRegEdit } from 'react-icons/fa'
import { Field, Form } from 'react-final-form'
import { FaRegEdit, FaTrash } from 'react-icons/fa'
import { Flex } from 'rebass'
import { useCommonStores } from 'src'
import { IComment } from 'src/models'
import { CommentHeader } from './CommentHeader'
import { Text } from 'src/components/Text'
import { Modal } from '../Modal/Modal'
import { TextAreaField } from '../Form/Fields'
import { Field, Form } from 'react-final-form'
import { Button } from 'src/components/Button'
import { Text } from 'src/components/Text'
import { IComment } from 'src/models'
import { AuthWrapper } from '../Auth/AuthWrapper'
import { TextAreaField } from '../Form/Fields'
import { Modal } from '../Modal/Modal'
import { CommentHeader } from './CommentHeader'

export interface IProps extends IComment {}
export interface IProps extends IComment {
verified: boolean
}

export const Comment: React.FC<IProps> = ({
_creatorId,
Expand All @@ -20,6 +22,7 @@ export const Comment: React.FC<IProps> = ({
...props
}) => {
const { stores } = useCommonStores()

const [showEditModal, setShowEditModal] = useState(false)

return (
Expand Down
11 changes: 9 additions & 2 deletions src/components/Comment/CommentHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { Box, Flex, Text } from 'rebass'
import { Box, Flex, Text, Image } from 'rebass'
import { FlagIconHowTos } from 'src/components/Icons/FlagIcon/FlagIcon'
import { IComment } from 'src/models'
import { Link } from 'src/components/Links'
import VerifiedBadgeIcon from 'src/assets/icons/icon-verified-badge.svg'

interface IProps extends Omit<IComment, 'text' | '_id' | '_creatorId'> {}
interface IProps extends Omit<IComment, 'text' | '_id' | '_creatorId'> {
verified: boolean
}

export const CommentHeader = ({
creatorName,
creatorCountry,
_created,
_edited,
verified,
}: IProps) => {
return (
<Flex justifyContent="space-between" alignItems="baseline">
Expand All @@ -25,6 +29,9 @@ export const CommentHeader = ({
>
{creatorName}
</Link>
{verified && (
<Image src={VerifiedBadgeIcon} ml={1} height="12px" width="12px" />
)}
</span>
</Box>
<Flex alignItems="center">
Expand Down
14 changes: 11 additions & 3 deletions src/components/EventCard/EventCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ import FlagIconEvents from 'src/components/Icons/FlagIcon/FlagIcon'
import { IEvent } from '../../models/events.models'
import { getMonth, getDay, capitalizeFirstLetter } from 'src/utils/helpers'
import { LinkTargetBlank } from '../Links/LinkTargetBlank/LinkTargetBlank'
import { Image } from 'rebass'
import VerifiedBadgeIcon from 'src/assets/icons/icon-verified-badge.svg'

interface IProps {
event: IEvent
verified?: boolean
needsModeration: boolean
moderateEvent: (event: IEvent, accepted: boolean) => void
}
Expand Down Expand Up @@ -79,9 +82,14 @@ export const EventCard = (props: IProps) => (
{capitalizeFirstLetter(props.event.title)}
</Text>
</Flex>
<Text auxiliary width={1}>
By {props.event._createdBy}
</Text>
<Flex>
<Text auxiliary width={1}>
By {props.event._createdBy}
</Text>
{props.verified && (
<Image src={VerifiedBadgeIcon} height="16px" width="16px" />
)}
</Flex>
</Flex>
<Flex
flexWrap={'nowrap'}
Expand Down
8 changes: 7 additions & 1 deletion src/components/Research/ResearchListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ import { ModerationStatusText } from 'src/components/ModerationStatusText'
import Text from 'src/components/Text'
import { IResearch } from 'src/models/research.models'
import theme from 'src/themes/styled.theme'
import { Image } from 'rebass/styled-components'
import VerifiedBadgeIcon from 'src/assets/icons/icon-verified-badge.svg'

interface IProps {
item: IResearch.ItemDB
verified: boolean
}

const ResearchListItem: React.FC<IProps> = ({ item }) => (
const ResearchListItem: React.FC<IProps> = ({ item, verified }) => (
<Flex
card
mediumRadius
Expand Down Expand Up @@ -44,6 +47,9 @@ const ResearchListItem: React.FC<IProps> = ({ item }) => (
>
{item._createdBy}
</Text>
{verified && (
<Image src={VerifiedBadgeIcon} ml={1} height="12px" width="12px" />
)}
</Flex>
<Flex
alignItems="center"
Expand Down
2 changes: 1 addition & 1 deletion src/mocks/user.mock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { MOCK_DB_META } from './db.mock'

export const MOCK_USER: IUser = {
verified: true,
badges: { verified: true },
badges: { verified: 1 },
userName: 'chris-m-clarke',
displayName: 'chris-m-clarke',
moderation: 'accepted',
Expand Down
8 changes: 4 additions & 4 deletions src/mocks/user_pp.mock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export const MOCK_USER_WORKSPACE: IUserPP = {
}
export const MOCK_USER_COLLECTION: IUserPP = {
verified: true,
badges: { verified: true },
badges: { verified: 1 },
userName: 'collection-username',
about: 'We are collecting plastic in city center',
...MOCK_DB_META(),
Expand Down Expand Up @@ -142,7 +142,7 @@ export const MOCK_USER_COLLECTION: IUserPP = {
}
export const MOCK_USER_MEMBER: IUserPP = {
verified: true,
badges: { verified: false },
badges: { verified: 0 },
userName: 'member-username',
about: "I'm just a member of this community that share knowledge",
...MOCK_DB_META(),
Expand Down Expand Up @@ -196,7 +196,7 @@ export const MOCK_USER_MEMBER: IUserPP = {
}
export const MOCK_USER_COMMUNITY: IUserPP = {
verified: true,
badges: { verified: true },
badges: { verified: 1 },
userName: 'community-username',
about: 'We are building a local community to fight plastic waste',
...MOCK_DB_META(),
Expand Down Expand Up @@ -252,7 +252,7 @@ export const MOCK_USER_COMMUNITY: IUserPP = {
}
export const MOCK_USER_MACHINE: IUserPP = {
verified: true,
badges: { verified: true },
badges: { verified: 1 },
userName: 'community-username',
about: 'We are building machine to recycle plastic',
...MOCK_DB_META(),
Expand Down
6 changes: 5 additions & 1 deletion src/models/user.models.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ export interface IUser {
}

interface IUserBadges {
verified: boolean
/** We use number instead of boolean to enable Dexie to index the data
* (it is not compatible with boolean)
* 0 -> false, 1 -> true
* */
verified: number
}

interface IExternalLink {
Expand Down
6 changes: 6 additions & 0 deletions src/pages/Events/Content/EventsList/EventsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ export class EventsList extends React.Component<any> {
// eslint-disable-next-line
constructor(props: any) {
super(props)

// fetch verified users to show badges on events
this.props.userStore?.fetchAllVerifiedUsers()
}

get injected() {
Expand Down Expand Up @@ -111,6 +114,9 @@ export class EventsList extends React.Component<any> {
{filteredEvents.map((event: IEventDB) => (
<EventCard
key={event._id}
verified={this.props.userStore?.verifiedUsers?.some(
user => user.userName === event._createdBy,
)}
event={event}
needsModeration={this.store.needsModeration(event)}
moderateEvent={this.moderateEvent}
Expand Down
16 changes: 14 additions & 2 deletions src/pages/Howto/Content/Howto/HowToComments/HowToComments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import { Comment } from 'src/components/Comment/Comment'
import { CommentTextArea } from 'src/components/Comment/CommentTextArea'
import { IComment } from 'src/models'
import styled from 'styled-components'
import { IUser } from 'src/models/user.models'

const MAX_COMMENTS = 5

interface IProps {
comments?: IComment[]
verifiedUsers?: IUser[]
}

const BoxStyled = styled(Box)`
Expand All @@ -25,7 +27,7 @@ const ButtonStyled = styled(Button)`
`

// TODO: Expect the comments as a prop from the HowTo
export const HowToComments = ({ comments }: IProps) => {
export const HowToComments = ({ comments, verifiedUsers }: IProps) => {
const [comment, setComment] = useState('')
const [loading, setLoading] = useState(false)
const { stores } = useCommonStores()
Expand Down Expand Up @@ -61,7 +63,17 @@ export const HowToComments = ({ comments }: IProps) => {
{comments &&
comments
.slice(0, shownComments)
.map(comment => <Comment key={comment._id} {...comment} />)}
.map(comment => (
<Comment
key={comment._id}
verified={
!!verifiedUsers?.some(
user => user.userName === comment.creatorName,
)
}
{...comment}
/>
))}
{comments && comments.length > shownComments && (
<Button
width="max-content"
Expand Down
11 changes: 10 additions & 1 deletion src/pages/Howto/Content/Howto/Howto.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ export class Howto extends React.Component<
this.state = {
isLoading: true,
}

// Verified users will be used to display badges on comments & howto author
this.injected.userStore.fetchAllVerifiedUsers()
}
// workaround used later so that userStore can be called in render method when not existing on
get injected() {
Expand Down Expand Up @@ -126,6 +129,9 @@ export class Howto extends React.Component<
<>
<HowtoDescription
howto={activeHowto}
verified={this.injected.userStore.verifiedUsers.some(
user => user.userName === this.store.activeHowto?._createdBy,
)}
Copy link
Collaborator

Choose a reason for hiding this comment

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

question: Can we move the verified state to the HowTo document rather than perform this look up?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't recall any specific reason why I did this, it's been a while but maybe I just didn't think it through enough. If we move this logic to the store and have the verified state in every HowTo doc, it would certainly be a lot more efficient and only perform the search once 😅

votedUsefulCount={this.store.howtoStats?.votedUsefulCount}
loggedInUser={loggedInUser}
needsModeration={this.store.needsModeration(activeHowto)}
Expand All @@ -139,7 +145,10 @@ export class Howto extends React.Component<
<Step step={step} key={index} stepindex={index} />
))}
</Box>
<HowToComments comments={activeHowto.comments} />
<HowToComments
comments={activeHowto.comments}
verifiedUsers={this.injected.userStore.verifiedUsers}
/>
<MoreBox py={20} mt={20}>
<Text bold txtcenter fontSize={[4, 4, 5]}>
You're done.
Expand Down
35 changes: 21 additions & 14 deletions src/pages/Howto/Content/Howto/HowtoDescription/HowtoDescription.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,35 @@
import { PureComponent } from 'react'
import TagDisplay from 'src/components/Tags/TagDisplay/TagDisplay'
import { format } from 'date-fns'
import { IHowtoDB } from 'src/models/howto.models'
import Heading from 'src/components/Heading'
import Text from 'src/components/Text'
import ModerationStatusText from 'src/components/ModerationStatusText'
import { Link } from 'src/components/Links'
import { PureComponent } from 'react'
import { Box, Flex, Image } from 'rebass'
import { FileInfo } from 'src/components/FileInfo/FileInfo'
import ArrowIcon from 'src/assets/icons/icon-arrow-select.svg'
import DifficultyLevel from 'src/assets/icons/icon-difficulty-level.svg'
import StepsIcon from 'src/assets/icons/icon-steps.svg'
import TimeNeeded from 'src/assets/icons/icon-time-needed.svg'
import DifficultyLevel from 'src/assets/icons/icon-difficulty-level.svg'
import VerifiedBadgeIcon from 'src/assets/icons/icon-verified-badge.svg'
import { Button } from 'src/components/Button'
import { FileInfo } from 'src/components/FileInfo/FileInfo'
import Heading from 'src/components/Heading'
import { FlagIconHowTos } from 'src/components/Icons/FlagIcon/FlagIcon'
import { Link } from 'src/components/Links'
import ModerationStatusText from 'src/components/ModerationStatusText'
import TagDisplay from 'src/components/Tags/TagDisplay/TagDisplay'
import Text from 'src/components/Text'
import { IHowtoDB } from 'src/models/howto.models'
import { IUser } from 'src/models/user.models'
import theme from 'src/themes/styled.theme'
import {
isAllowToEditContent,
emStringToPx,
capitalizeFirstLetter,
emStringToPx,
isAllowToEditContent,
} from 'src/utils/helpers'
import theme from 'src/themes/styled.theme'
import ArrowIcon from 'src/assets/icons/icon-arrow-select.svg'
import { FlagIconHowTos } from 'src/components/Icons/FlagIcon/FlagIcon'
import { HowtoUsefulStats } from './HowtoUsefulStats'

interface IProps {
howto: IHowtoDB
loggedInUser: IUser | undefined
needsModeration: boolean
votedUsefulCount?: number
verified?: boolean
userVotedUseful: boolean
moderateHowto: (accepted: boolean) => void
onUsefulClick: () => void
Expand Down Expand Up @@ -144,6 +146,11 @@ export default class HowtoDescription extends PureComponent<IProps> {
>
{howto._createdBy}
</Link>{' '}
{this.props.verified && (
<>
<Image src={VerifiedBadgeIcon} height="12px" width="12px" />{' '}
</>
)}
| Published on {this.dateCreatedByText(howto)}
</Text>
</Flex>
Expand Down
8 changes: 7 additions & 1 deletion src/pages/Howto/Content/HowtoList/HowToCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ import TagDisplay from 'src/components/Tags/TagDisplay/TagDisplay'
import { IHowtoDB } from 'src/models/howto.models'
import Heading from 'src/components/Heading'
import { capitalizeFirstLetter } from 'src/utils/helpers'
import VerifiedBadgeIcon from 'src/assets/icons/icon-verified-badge.svg'
import { Image } from 'rebass'

interface IProps {
howto: IHowtoDB
verified: boolean
}
export const HowToCard = (props: IProps) => (
<Flex
Expand Down Expand Up @@ -56,9 +59,12 @@ export const HowToCard = (props: IProps) => (
{props.howto.creatorCountry && (
<FlagIconHowTos code={props.howto.creatorCountry} />
)}
<Text auxiliary my={2} ml={1}>
<Text auxiliary my={2} ml={1} display="flex">
By {props.howto._createdBy}
</Text>
{props.verified && (
<Image src={VerifiedBadgeIcon} ml={1} height="12px" width="12px" />
)}
</Flex>
<Flex mt={4}>
{props.howto.tags &&
Expand Down
Loading