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: add logic that lets users favorite a template #9713

Merged
merged 28 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e22cbbd
chore: update activity library custom tab empty state
nickoferrall Apr 23, 2024
6df1450
change var name to showResults instead of hideResults
nickoferrall Apr 23, 2024
d34002e
add favourite category
nickoferrall Apr 23, 2024
ad5ff86
add favorite icon
nickoferrall Apr 23, 2024
6cf0e57
can click on favorite icon
nickoferrall Apr 23, 2024
06152ae
only show favorite icon on activity grid
nickoferrall Apr 23, 2024
bdda429
show favourite icon in activity details
nickoferrall Apr 23, 2024
cd0f758
show tooltip on hover
nickoferrall Apr 23, 2024
b3334df
add favourite img
nickoferrall Apr 29, 2024
63d82ce
update favourite img
nickoferrall Apr 29, 2024
5f245f3
update favorite emoji color in al tabs
nickoferrall Apr 29, 2024
92d1d83
fix merge conflict
nickoferrall Apr 29, 2024
7e85cd1
implement addFavoriteTemplateIds migration
nickoferrall Apr 30, 2024
ac68c9a
update typeDef with favoriteTemplates
nickoferrall Apr 30, 2024
3aa7cb4
implement toggleFavoriteTemplate skeleton
nickoferrall Apr 30, 2024
86fe072
update favoriteTemplateids
nickoferrall May 2, 2024
630f8cf
favorite activities showing up
nickoferrall May 2, 2024
acbbdd8
update favs section after toggling
nickoferrall May 3, 2024
c6ebe25
implement favoriteTemplateIds dataloader
nickoferrall May 3, 2024
5ed46a9
bump font size of fav icon
nickoferrall May 3, 2024
4856285
update toggle success source type
nickoferrall May 3, 2024
7f1269b
use normalize in dataloader and adjust favorite icon position
nickoferrall May 7, 2024
70a055e
Merge branch 'master' into feat/9114/favorite-activities-ui
nickoferrall May 7, 2024
3e763da
fix merge conflict
nickoferrall May 7, 2024
d9cfbe0
update migration order
nickoferrall May 7, 2024
42a514e
remove vertical scroll from empty state
nickoferrall May 8, 2024
0b57e63
fix favorite icon height in safari
nickoferrall May 8, 2024
80310a9
fix merge conflicts
nickoferrall May 20, 2024
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
5 changes: 3 additions & 2 deletions codegen.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@
"ActionMeeting": "../../database/types/MeetingAction#default",
"ActionMeetingMember": "../../database/types/ActionMeetingMember#default as ActionMeetingMemberDB",
"AddApprovedOrganizationDomainsSuccess": "./types/AddApprovedOrganizationDomainsSuccess#AddApprovedOrganizationDomainsSuccessSource",
"AddPokerTemplateSuccess": "./types/AddPokerTemplateSuccess#AddPokerTemplateSuccessSource",
"AddReactjiToReactableSuccess": "./types/AddReactjiToReactableSuccess#AddReactjiToReactableSuccessSource",
"AddReflectTemplateSuccess": "./types/AddReflectTemplateSuccess#AddReflectTemplateSuccessSource",
"AddPokerTemplateSuccess": "./types/AddPokerTemplateSuccess#AddPokerTemplateSuccessSource",
"AddTranscriptionBotSuccess": "./types/AddTranscriptionBotSuccess#AddTranscriptionBotSuccessSource",
"AddedNotification": "./types/AddedNotification#AddedNotificationSource",
"AgendaItem": "../../database/types/AgendaItem#default as AgendaItemDB",
Expand Down Expand Up @@ -132,6 +132,7 @@
"TeamPromptResponse": "../../postgres/queries/getTeamPromptResponsesByIds#TeamPromptResponse",
"TemplateDimension": "../../database/types/TemplateDimension#default",
"TimelineEventTeamPromptComplete": "./types/TimelineEventTeamPromptComplete#TimelineEventTeamPromptCompleteSource",
"ToggleFavoriteTemplateSuccess": "./types/ToggleFavoriteTemplateSuccess#ToggleFavoriteTemplateSuccessSource",
"ToggleSummaryEmailSuccess": "./types/ToggleSummaryEmailSuccess#ToggleSummaryEmailSuccessSource",
"TopRetroTemplate": "./types/TopRetroTemplate#TopRetroTemplateSource",
"UpdateAutoJoinSuccess": "./types/UpdateAutoJoinSuccess#UpdateAutoJoinSuccessSource",
Expand All @@ -140,9 +141,9 @@
"UpdateFeatureFlagPayload": "./types/UpdateFeatureFlagPayload#UpdateFeatureFlagPayloadSource",
"UpdateGitLabDimensionFieldSuccess": "./types/UpdateGitLabDimensionFieldSuccess#UpdateGitLabDimensionFieldSuccessSource",
"UpdateMeetingPromptSuccess": "./types/UpdateMeetingPromptSuccess#UpdateMeetingPromptSuccessSource",
"UpdateMeetingTemplateSuccess": "./types/UpdateMeetingTemplateSuccess#UpdateMeetingTemplateSuccessSource",
"UpdateOrgPayload": "./types/UpdateOrgPayload#UpdateOrgPayloadSource",
"UpdateRecurrenceSettingsSuccess": "./types/UpdateRecurrenceSettingsSuccess#UpdateRecurrenceSettingsSuccessSource",
"UpdateMeetingTemplateSuccess": "./types/UpdateMeetingTemplateSuccess#UpdateMeetingTemplateSuccessSource",
"UpdateTaskPayload": "./types/UpdateTaskPayload#UpdateTaskPayloadSource",
"UpdateTemplateCategorySuccess": "./types/UpdateTemplateCategorySuccess#UpdateTemplateCategorySuccessSource",
"UpdateUserProfilePayload": "./types/UpdateUserProfilePayload#UpdateUserProfilePayloadSource",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {Favorite} from '@mui/icons-material'
import graphql from 'babel-plugin-relay/macro'
import clsx from 'clsx'
import React from 'react'
import {useFragment} from 'react-relay'
import {ActivityCardFavorite_user$key} from '../../__generated__/ActivityCardFavorite_user.graphql'
import useAtmosphere from '../../hooks/useAtmosphere'
import useMutationProps from '../../hooks/useMutationProps'
import ToggleFavoriteTemplateMutation from '../../mutations/ToggleFavoriteTemplateMutation'
import {Tooltip} from '../../ui/Tooltip/Tooltip'
import {TooltipContent} from '../../ui/Tooltip/TooltipContent'
import {TooltipTrigger} from '../../ui/Tooltip/TooltipTrigger'

type Props = {
className?: string
templateId: string
viewerRef: ActivityCardFavorite_user$key
}

const ActivityCardFavorite = (props: Props) => {
const {className, templateId, viewerRef} = props
const atmosphere = useAtmosphere()
const {onError, onCompleted} = useMutationProps()

const viewer = useFragment(
graphql`
fragment ActivityCardFavorite_user on User {
favoriteTemplates {
id
}
}
`,
viewerRef
)
const favoriteTemplateIds = viewer.favoriteTemplates.map((template) => template.id)
const isFavorite = favoriteTemplateIds.includes(templateId)
const tooltipCopy = isFavorite ? 'Remove from favorites' : 'Add to favorites'

const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault()
ToggleFavoriteTemplateMutation(atmosphere, {templateId}, {onError, onCompleted})
}

return (
<Tooltip>
<div
className={clsx(
className,
`z-10 flex h-10 w-10 items-center justify-center rounded-full bg-white`
)}
>
<TooltipTrigger asChild>
<button
onClick={handleClick}
className='flex h-full w-full cursor-pointer items-center justify-center bg-transparent'
>
<Favorite className={isFavorite ? 'text-rose-600' : 'text-slate-600'} />
</button>
</TooltipTrigger>
</div>
<TooltipContent side='bottom' align='center' sideOffset={20}>
{tooltipCopy}
</TooltipContent>
</Tooltip>
)
}

export default ActivityCardFavorite
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {setActiveTemplate} from '../../../utils/relay/setActiveTemplate'
import useTemplateDescription from '../../../utils/useTemplateDescription'
import DetailAction from '../../DetailAction'
import FlatButton from '../../FlatButton'
import ActivityCardFavorite from '../ActivityCardFavorite'
import {QUICK_START_CATEGORY_ID} from '../Categories'
import TeamPickerModal from '../TeamPickerModal'
import ActivityDetailsBadges from './ActivityDetailsBadges'
Expand Down Expand Up @@ -132,6 +133,7 @@ export const TemplateDetails = (props: Props) => {
const viewer = useFragment(
graphql`
fragment TemplateDetails_user on User {
...ActivityCardFavorite_user
preferredTeamId
teams {
...TeamPickerModal_teams
Expand Down Expand Up @@ -258,15 +260,22 @@ export const TemplateDetails = (props: Props) => {
{!isOwner && __typename !== 'FixedActivity' && (
<div className='flex items-center justify-between'>
<div className='py-2 text-sm font-semibold text-slate-600'>{description}</div>
<div className='rounded-full border border-solid border-slate-400 text-slate-600'>
<FlatButton
style={{padding: '8px 12px', border: '0'}}
className='flex gap-1 px-12'
onClick={toggleTeamPickerPortal}
>
<ContentCopy className='text-slate-600' />
<div className='font-semibold text-slate-700'>Clone & Edit</div>
</FlatButton>
<div className='flex items-center gap-2'>
<ActivityCardFavorite
templateId={activityId}
viewerRef={viewer}
className='rounded-full border border-solid border-slate-400 hover:bg-slate-200'
/>
<div className='rounded-full border border-solid border-slate-400'>
<FlatButton
style={{padding: '8px 12px', border: '0'}}
className='flex cursor-pointer gap-1 px-12'
onClick={toggleTeamPickerPortal}
>
<ContentCopy className='text-slate-600' />
<div className='font-semibold text-slate-700'>Clone & Edit</div>
</FlatButton>
</div>
</div>
</div>
)}
Expand Down
23 changes: 22 additions & 1 deletion packages/client/components/ActivityLibrary/ActivityGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
import graphql from 'babel-plugin-relay/macro'
import React from 'react'
import {useFragment} from 'react-relay'
import {Link} from 'react-router-dom'
import {ActivityGrid_user$key} from '../../__generated__/ActivityGrid_user.graphql'
import {ActivityBadge} from './ActivityBadge'
import {ActivityCard, ActivityCardImage} from './ActivityCard'
import ActivityCardFavorite from './ActivityCardFavorite'
import {Template} from './ActivityLibrary'
import {ActivityLibraryCardDescription} from './ActivityLibraryCardDescription'
import {CATEGORY_THEMES, CategoryID} from './Categories'

interface ActivityGridProps {
templates: Template[]
selectedCategory: string
viewerRef?: ActivityGrid_user$key
}

const ActivityGrid = ({templates, selectedCategory}: ActivityGridProps) => {
const ActivityGrid = (props: ActivityGridProps) => {
const {templates, selectedCategory, viewerRef} = props
const viewer = useFragment(
graphql`
fragment ActivityGrid_user on User {
...ActivityCardFavorite_user
}
`,
viewerRef ?? null
)
return (
<>
{templates.map((template) => {
Expand Down Expand Up @@ -42,6 +56,13 @@ const ActivityGrid = ({templates, selectedCategory}: ActivityGridProps) => {
src={template.illustrationUrl}
category={template.category as CategoryID}
/>
{viewer && (
<ActivityCardFavorite
templateId={template.id}
className='absolute bottom-2 right-2'
viewerRef={viewer}
/>
)}
<ActivityLibraryCardDescription
className='hidden group-hover/card:flex'
templateRef={template}
Expand Down
19 changes: 18 additions & 1 deletion packages/client/components/ActivityLibrary/ActivityLibrary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ graphql`
const query = graphql`
query ActivityLibraryQuery {
viewer {
...ActivityGrid_user
favoriteTemplates {
...ActivityLibrary_template @relay(mask: false)
}
availableTemplates(first: 2000) @connection(key: "ActivityLibrary_availableTemplates") {
edges {
node {
Expand Down Expand Up @@ -240,6 +244,9 @@ export const ActivityLibrary = (props: Props) => {
// If there's a search query, just use the search filter results
return filteredTemplates
}
if (categoryId === 'favorite') {
return viewer.favoriteTemplates
}

return filteredTemplates.filter((template) =>
categoryId === QUICK_START_CATEGORY_ID
Expand Down Expand Up @@ -326,7 +333,7 @@ export const ActivityLibrary = (props: Props) => {
<ScrollArea.Root className='w-full'>
<ScrollArea.Viewport className='w-full'>
<div className='flex gap-2 px-4 pt-6 md:flex-wrap md:pb-4 lg:mx-[15%]'>
{(availableCategoryIds as Array<CategoryID | typeof QUICK_START_CATEGORY_ID>).map(
{(availableCategoryIds as Array<AllCategoryID | typeof QUICK_START_CATEGORY_ID>).map(
(category) => (
<Link
className={clsx(
Expand All @@ -341,6 +348,14 @@ export const ActivityLibrary = (props: Props) => {
to={`/activity-library/category/${category}`}
onClick={() => resetQuery()}
key={category}
style={{
color:
category === 'favorite'
? category === categoryId && searchQuery.length === 0
? 'white'
: 'red'
: undefined
}}
>
{CATEGORY_ID_TO_NAME[category]}
</Link>
Expand Down Expand Up @@ -380,6 +395,7 @@ export const ActivityLibrary = (props: Props) => {
<ActivityGrid
templates={subCategoryTemplates}
selectedCategory={categoryId}
viewerRef={viewer}
/>
</div>
</Fragment>
Expand All @@ -392,6 +408,7 @@ export const ActivityLibrary = (props: Props) => {
<ActivityGrid
templates={templatesToRender as Template[]}
selectedCategory={categoryId}
viewerRef={viewer}
/>
</div>
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import FavoriteIcon from '@mui/icons-material/Favorite'
import React from 'react'
import favoriteImg from '../../../../static/images/illustrations/favorite-empty-state.png'
import halloweenRetrospectiveTemplate from '../../../../static/images/illustrations/halloweenRetrospectiveTemplate.png'
import {AllCategoryID, QUICK_START_CATEGORY_ID} from './Categories'
import CreateActivityCard from './CreateActivityCard'
Expand All @@ -12,6 +14,32 @@ const ActivityLibraryEmptyState = (props: Props) => {
const {categoryId, searchQuery} = props
const showResultsNotFound = categoryId !== 'custom' || searchQuery !== ''

if (categoryId === 'favorite') {
return (
<div className='relative mx-auto flex p-2 text-slate-700'>
<div className='md:p-18 p-4 xl:p-24'>
<img className='w-82' src={favoriteImg} alt='Favorite placeholder' />
<div className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transform'>
<div className='flex flex-col items-center'>
<FavoriteIcon
className='icon-color-red icon-border-gold rounded-full p-3 text-5xl md:text-6xl lg:p-5 lg:text-8xl'
style={{
color: 'red',
border: '2px solid gold',
borderRadius: '50%'
}}
/>

<span className='mt-2 text-center md:text-lg'>
Activities you mark as favorite will show up here
</span>
</div>
</div>
</div>
</div>
)
}

return (
<div className='mx-auto flex p-2 text-slate-700'>
<div className='ml-10'>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import FavoriteIcon from '@mui/icons-material/Favorite'
import React from 'react'
import {MeetingTypeEnum} from '../../__generated__/MeetingSelectorQuery.graphql'
import {CardTheme} from './ActivityCard'

Expand All @@ -13,10 +15,12 @@ export const MAIN_CATEGORIES = [

export const QUICK_START_CATEGORY_ID = 'recommended'
export const CUSTOM_CATEGORY_ID = 'custom'
export const FAVORITE_CATEGORY_ID = 'favorite'

export const ALL_CATEGORIES = [
QUICK_START_CATEGORY_ID,
...MAIN_CATEGORIES,
FAVORITE_CATEGORY_ID,
CUSTOM_CATEGORY_ID
] as const

Expand Down Expand Up @@ -46,11 +50,25 @@ export const CATEGORY_THEMES: Record<AllCategoryID, CardTheme> = {
primary: 'bg-fuscia-400',
secondary: 'bg-slate-200',
text: 'text-slate-500'
},
[FAVORITE_CATEGORY_ID]: {
primary: 'bg-grape-700',
secondary: 'bg-slate-200',
text: 'text-slate-500'
}
}

export const CATEGORY_ID_TO_NAME: Record<AllCategoryID, string> = {
export const CATEGORY_ID_TO_NAME: Record<AllCategoryID, string | JSX.Element> = {
[QUICK_START_CATEGORY_ID]: 'Quick Start',
[FAVORITE_CATEGORY_ID]: (
<FavoriteIcon
style={{
color: 'inherit',
display: 'flex',
fontSize: '20px'
}}
/>
),
[CUSTOM_CATEGORY_ID]: 'Custom',
retrospective: 'Retrospective',
estimation: 'Estimation',
Expand Down
41 changes: 41 additions & 0 deletions packages/client/mutations/ToggleFavoriteTemplateMutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import graphql from 'babel-plugin-relay/macro'
import {commitMutation} from 'react-relay'
import {ToggleFavoriteTemplateMutation as TToggleFavoriteTemplateMutation} from '../__generated__/ToggleFavoriteTemplateMutation.graphql'
import {StandardMutation} from '../types/relayMutations'

graphql`
fragment ToggleFavoriteTemplateMutation_viewer on ToggleFavoriteTemplateSuccess {
user {
id
...ActivityCardFavorite_user
}
}
`

const mutation = graphql`
mutation ToggleFavoriteTemplateMutation($templateId: ID!) {
toggleFavoriteTemplate(templateId: $templateId) {
... on ErrorPayload {
error {
message
}
}
...ToggleFavoriteTemplateMutation_viewer @relay(mask: false)
}
}
`

const ToggleFavoriteTemplateMutation: StandardMutation<TToggleFavoriteTemplateMutation> = (
atmosphere,
variables,
{onError, onCompleted}
) => {
return commitMutation<TToggleFavoriteTemplateMutation>(atmosphere, {
mutation,
variables,
onCompleted,
onError
})
}

export default ToggleFavoriteTemplateMutation
Loading
Loading