diff --git a/packages/client/components/MeetingOptions.tsx b/packages/client/components/MeetingOptions.tsx
new file mode 100644
index 00000000000..d0fd3d97a7c
--- /dev/null
+++ b/packages/client/components/MeetingOptions.tsx
@@ -0,0 +1,62 @@
+import React, {useState} from 'react'
+import IconLabel from './IconLabel'
+import {Menu} from '../ui/Menu/Menu'
+import {MenuItem} from '../ui/Menu/MenuItem'
+import SwapHorizIcon from '@mui/icons-material/SwapHoriz'
+import {OptionsButton} from './TeamPrompt/TeamPromptOptions'
+import {Tooltip} from '../ui/Tooltip/Tooltip'
+import {TooltipTrigger} from '../ui/Tooltip/TooltipTrigger'
+import {TooltipContent} from '../ui/Tooltip/TooltipContent'
+
+type Props = {
+ setShowDrawer: (showDrawer: boolean) => void
+ showDrawer: boolean
+ hasReflections: boolean
+}
+
+const MeetingOptions = (props: Props) => {
+ const {setShowDrawer, showDrawer, hasReflections} = props
+ const [isOpen, setIsOpen] = useState(false)
+
+ const handleClick = () => {
+ if (hasReflections) return
+ setShowDrawer(!showDrawer)
+ }
+
+ const handleMouseEnter = () => {
+ if (hasReflections) {
+ setIsOpen(true)
+ }
+ }
+
+ const handleMouseLeave = () => {
+ setIsOpen(false)
+ }
+
+ return (
+
+ )
+}
+
+export default MeetingOptions
diff --git a/packages/client/components/MeetingTopBar.tsx b/packages/client/components/MeetingTopBar.tsx
index a9d37c7e096..287a53012b4 100644
--- a/packages/client/components/MeetingTopBar.tsx
+++ b/packages/client/components/MeetingTopBar.tsx
@@ -1,6 +1,6 @@
import styled from '@emotion/styled'
import {Comment} from '@mui/icons-material'
-import React, {ReactElement, ReactNode} from 'react'
+import React, {ReactElement, ReactNode, useState} from 'react'
import {PALETTE} from '~/styles/paletteV3'
import {meetingAvatarMediaQueries} from '../styles/meeting'
import hasToken from '../utils/hasToken'
@@ -9,6 +9,7 @@ import makeMinWidthMediaQuery from '../utils/makeMinWidthMediaQuery'
import DemoCreateAccountButton from './DemoCreateAccountButton'
import PlainButton from './PlainButton/PlainButton'
import SidebarToggle from './SidebarToggle'
+import RetroDrawerRoot from './RetroDrawerRoot'
const localHeaderBreakpoint = makeMinWidthMediaQuery(600)
@@ -148,6 +149,7 @@ interface Props {
isRightDrawerOpen?: boolean
toggleSidebar: () => void
toggleDrawer?: () => void
+ meetingId?: string
}
const MeetingTopBar = (props: Props) => {
@@ -158,10 +160,14 @@ const MeetingTopBar = (props: Props) => {
isMeetingSidebarCollapsed,
isRightDrawerOpen,
toggleDrawer,
- toggleSidebar
+ toggleSidebar,
+ meetingId
} = props
const showButton = isDemoRoute() && !hasToken()
const showDiscussionButton = toggleDrawer && !isRightDrawerOpen
+ const [showDrawer, setShowDrawer] = useState(false)
+ const isOptionsVisible = !!meetingId && !isDemoRoute()
+
return (
@@ -177,6 +183,13 @@ const MeetingTopBar = (props: Props) => {
)}
{avatarGroup}
+ {isOptionsVisible && (
+
+ )}
{showDiscussionButton && toggleDrawer && (
diff --git a/packages/client/components/RetroDrawer.tsx b/packages/client/components/RetroDrawer.tsx
new file mode 100644
index 00000000000..8d6404ada0e
--- /dev/null
+++ b/packages/client/components/RetroDrawer.tsx
@@ -0,0 +1,108 @@
+import {Close} from '@mui/icons-material'
+import graphql from 'babel-plugin-relay/macro'
+import React, {useEffect} from 'react'
+import {PreloadedQuery, usePreloadedQuery} from 'react-relay'
+import {Breakpoint, DiscussionThreadEnum} from '../types/constEnums'
+import ResponsiveDashSidebar from './ResponsiveDashSidebar'
+import MeetingOptions from './MeetingOptions'
+import RetroDrawerTemplateCard from './RetroDrawerTemplateCard'
+import {Drawer} from './TeamPrompt/TeamPromptDrawer'
+import {RetroDrawerQuery} from '../__generated__/RetroDrawerQuery.graphql'
+import useBreakpoint from '../hooks/useBreakpoint'
+
+interface Props {
+ setShowDrawer: (showDrawer: boolean) => void
+ showDrawer: boolean
+ queryRef: PreloadedQuery
+}
+
+const RetroDrawer = (props: Props) => {
+ const {queryRef, showDrawer, setShowDrawer} = props
+ const {viewer} = usePreloadedQuery(
+ graphql`
+ query RetroDrawerQuery($first: Int!, $type: MeetingTypeEnum!, $meetingId: ID!) {
+ viewer {
+ meeting(meetingId: $meetingId) {
+ ... on RetrospectiveMeeting {
+ reflectionGroups {
+ id
+ }
+ localPhase {
+ ... on ReflectPhase {
+ phaseType
+ }
+ }
+ }
+ }
+ availableTemplates(first: $first, type: $type)
+ @connection(key: "RetroDrawer_availableTemplates") {
+ edges {
+ node {
+ ...RetroDrawerTemplateCard_template
+ id
+ }
+ }
+ }
+ }
+ }
+ `,
+ queryRef
+ )
+
+ const templates = viewer.availableTemplates.edges
+ const meeting = viewer.meeting
+ const hasReflections = !!(meeting?.reflectionGroups && meeting.reflectionGroups.length > 0)
+ const phaseType = meeting?.localPhase?.phaseType
+ const isMobile = !useBreakpoint(Breakpoint.FUZZY_TABLET)
+ const isDesktop = useBreakpoint(Breakpoint.SIDEBAR_LEFT)
+
+ const toggleDrawer = () => {
+ setShowDrawer(!showDrawer)
+ }
+
+ useEffect(() => {
+ if (hasReflections && showDrawer) {
+ setShowDrawer(false)
+ }
+ }, [hasReflections])
+
+ if (!phaseType || phaseType !== 'reflect') return null
+ return (
+ <>
+
+
+
+
+
+ {templates.map((template) => (
+
+ ))}
+
+
+
+ >
+ )
+}
+export default RetroDrawer
diff --git a/packages/client/components/RetroDrawerRoot.tsx b/packages/client/components/RetroDrawerRoot.tsx
new file mode 100644
index 00000000000..58bf63544ff
--- /dev/null
+++ b/packages/client/components/RetroDrawerRoot.tsx
@@ -0,0 +1,28 @@
+import React, {Suspense} from 'react'
+import useQueryLoaderNow from '../hooks/useQueryLoaderNow'
+import retroDrawerQuery, {RetroDrawerQuery} from '../__generated__/RetroDrawerQuery.graphql'
+import RetroDrawer from './RetroDrawer'
+
+type Props = {
+ showDrawer: boolean
+ setShowDrawer: (showDrawer: boolean) => void
+ meetingId: string
+}
+
+const RetroDrawerRoot = (props: Props) => {
+ const {showDrawer, setShowDrawer, meetingId} = props
+ const queryRef = useQueryLoaderNow(retroDrawerQuery, {
+ first: 200,
+ type: 'retrospective',
+ meetingId
+ })
+ return (
+
+ {queryRef && (
+
+ )}
+
+ )
+}
+
+export default RetroDrawerRoot
diff --git a/packages/client/components/RetroDrawerTemplateCard.tsx b/packages/client/components/RetroDrawerTemplateCard.tsx
new file mode 100644
index 00000000000..c126f6d0d6c
--- /dev/null
+++ b/packages/client/components/RetroDrawerTemplateCard.tsx
@@ -0,0 +1,55 @@
+import {ActivityBadge} from './ActivityLibrary/ActivityBadge'
+import {ActivityLibraryCardDescription} from './ActivityLibrary/ActivityLibraryCardDescription'
+import graphql from 'babel-plugin-relay/macro'
+import React from 'react'
+import {useFragment} from 'react-relay'
+import {ActivityLibraryCard} from './ActivityLibrary/ActivityLibraryCard'
+import {ActivityCardImage} from './ActivityLibrary/ActivityCard'
+import {RetroDrawerTemplateCard_template$key} from '~/__generated__/RetroDrawerTemplateCard_template.graphql'
+import {CategoryID, CATEGORY_THEMES} from '././ActivityLibrary/Categories'
+
+interface Props {
+ templateRef: RetroDrawerTemplateCard_template$key
+}
+
+const RetroDrawerTemplateCard = (props: Props) => {
+ const {templateRef} = props
+ const template = useFragment(
+ graphql`
+ fragment RetroDrawerTemplateCard_template on MeetingTemplate {
+ ...ActivityLibraryCardDescription_template
+ name
+ category
+ illustrationUrl
+ isFree
+ }
+ `,
+ templateRef
+ )
+
+ return (
+
+
Premium
+ ) : null
+ }
+ >
+
+
+
+
+ )
+}
+export default RetroDrawerTemplateCard
diff --git a/packages/client/components/RetroReflectPhase/RetroReflectPhase.tsx b/packages/client/components/RetroReflectPhase/RetroReflectPhase.tsx
index 74a5f422cb3..493ae73247c 100644
--- a/packages/client/components/RetroReflectPhase/RetroReflectPhase.tsx
+++ b/packages/client/components/RetroReflectPhase/RetroReflectPhase.tsx
@@ -30,6 +30,7 @@ const RetroReflectPhase = (props: Props) => {
...StageTimerDisplay_meeting
...StageTimerControl_meeting
...PhaseItemColumn_meeting
+ id
endedAt
localPhase {
...RetroReflectPhase_phase @relay(mask: false)
@@ -59,6 +60,7 @@ const RetroReflectPhase = (props: Props) => {
(
+export const Drawer = styled('div')<{isDesktop: boolean; isMobile: boolean; isOpen: boolean}>(
({isDesktop, isMobile, isOpen}) => ({
boxShadow: isDesktop ? desktopSidebarShadow : undefined,
backgroundColor: '#FFFFFF',
diff --git a/packages/client/components/TeamPrompt/TeamPromptOptions.tsx b/packages/client/components/TeamPrompt/TeamPromptOptions.tsx
index f34a7530830..bef32e09be0 100644
--- a/packages/client/components/TeamPrompt/TeamPromptOptions.tsx
+++ b/packages/client/components/TeamPrompt/TeamPromptOptions.tsx
@@ -14,7 +14,7 @@ import TeamPromptOptionsMenu from './TeamPromptOptionsMenu'
const COPIED_TOOLTIP_DURATION_MS = 2000
-const OptionsButton = styled(BaseButton)({
+export const OptionsButton = styled(BaseButton)({
color: PALETTE.SKY_500,
display: 'flex',
flexDirection: 'column',
diff --git a/packages/client/ui/Menu/Menu.tsx b/packages/client/ui/Menu/Menu.tsx
new file mode 100644
index 00000000000..47afbbbf35b
--- /dev/null
+++ b/packages/client/ui/Menu/Menu.tsx
@@ -0,0 +1,32 @@
+import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
+import React from 'react'
+import {twMerge} from 'tailwind-merge'
+
+interface MenuProps {
+ trigger: React.ReactNode
+ className?: string
+ children: React.ReactNode
+}
+
+export const Menu = React.forwardRef(
+ ({trigger, className, children}, ref) => {
+ return (
+
+ {trigger}
+
+
+ {children}
+
+
+
+ )
+ }
+)
diff --git a/packages/client/ui/Menu/MenuItem.tsx b/packages/client/ui/Menu/MenuItem.tsx
new file mode 100644
index 00000000000..fe117676eb0
--- /dev/null
+++ b/packages/client/ui/Menu/MenuItem.tsx
@@ -0,0 +1,28 @@
+import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
+import React from 'react'
+import {twMerge} from 'tailwind-merge'
+
+interface MenuItemProps {
+ onClick: (event: Event) => void
+ isDisabled?: boolean
+ className?: string
+ children: React.ReactNode
+}
+
+export const MenuItem = React.forwardRef(
+ ({onClick, isDisabled, className, children}, ref) => {
+ return (
+
+ {children}
+
+ )
+ }
+)
diff --git a/packages/client/ui/Tooltip/TooltipContent.tsx b/packages/client/ui/Tooltip/TooltipContent.tsx
index 03f77bea4ef..c119f4a2b70 100644
--- a/packages/client/ui/Tooltip/TooltipContent.tsx
+++ b/packages/client/ui/Tooltip/TooltipContent.tsx
@@ -1,7 +1,7 @@
import {Content, Portal} from '@radix-ui/react-tooltip'
import * as React from 'react'
import {twMerge} from 'tailwind-merge'
-import {forwardRadix} from '../fordwardRadix'
+import {forwardRadix} from '../forwardRadix'
export const TooltipContent = forwardRadix(
({className, children, ...props}, ref) => (
diff --git a/packages/client/ui/Tooltip/TooltipTrigger.tsx b/packages/client/ui/Tooltip/TooltipTrigger.tsx
index b364812034c..2a0b7b0ca36 100644
--- a/packages/client/ui/Tooltip/TooltipTrigger.tsx
+++ b/packages/client/ui/Tooltip/TooltipTrigger.tsx
@@ -1,6 +1,6 @@
import {Trigger} from '@radix-ui/react-tooltip'
import * as React from 'react'
-import {forwardRadix} from '../fordwardRadix'
+import {forwardRadix} from '../forwardRadix'
export const TooltipTrigger = forwardRadix(
({className, children, ...props}, ref) => (
diff --git a/packages/client/ui/fordwardRadix.tsx b/packages/client/ui/forwardRadix.tsx
similarity index 100%
rename from packages/client/ui/fordwardRadix.tsx
rename to packages/client/ui/forwardRadix.tsx
diff --git a/packages/server/graphql/public/typeDefs/User.graphql b/packages/server/graphql/public/typeDefs/User.graphql
index 232c2027391..ce643e797e5 100644
--- a/packages/server/graphql/public/typeDefs/User.graphql
+++ b/packages/server/graphql/public/typeDefs/User.graphql
@@ -433,6 +433,10 @@ type User {
The cursor, which is the templateId
"""
after: ID
+ """
+ An optional argument to filter by template type
+ """
+ type: MeetingTypeEnum
): MeetingTemplateConnection!
"""
diff --git a/packages/server/graphql/public/types/User.ts b/packages/server/graphql/public/types/User.ts
index cd396dd8963..f46afe30511 100644
--- a/packages/server/graphql/public/types/User.ts
+++ b/packages/server/graphql/public/types/User.ts
@@ -114,7 +114,7 @@ const User: UserResolvers = {
const invoice = await manager.retrieveInvoice(invoiceId)
return generateInvoice(invoice, stripeLineItems, orgId, invoiceId, dataLoader)
},
- availableTemplates: async ({id: userId}, {first, after}, {authToken, dataLoader}) => {
+ availableTemplates: async ({id: userId}, {first, after, type}, {authToken, dataLoader}) => {
const viewerId = getUserId(authToken)
const user = await dataLoader.get('users').loadNonNull(userId)
const teamIds =
@@ -175,6 +175,7 @@ const User: UserResolvers = {
...activity,
sortOrder: getScore(activity, teamIds)
}))
+ .filter((activity) => !type || activity.type === type)
.sort((a, b) => (a.sortOrder > b.sortOrder ? -1 : 1))
return connectionFromTemplateArray(allActivities, first, after)