diff --git a/frontend/src/component/project/Project/ProjectStats/Feedback.tsx b/frontend/src/component/project/Project/ProjectStats/Feedback.tsx new file mode 100644 index 0000000000..4f29d3b204 --- /dev/null +++ b/frontend/src/component/project/Project/ProjectStats/Feedback.tsx @@ -0,0 +1,76 @@ +import { useState, VFC } from 'react'; +import { Box, Paper, Button, styled } from '@mui/material'; +import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; +import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; +import { createLocalStorage } from 'utils/createLocalStorage'; + +interface IFeedbackProps { + id: string; +} + +const StyledBox = styled(Box)(({ theme }) => ({ + display: 'flex', + gap: theme.spacing(1), + marginTop: theme.spacing(0.5), +})); + +export const Feedback: VFC = ({ id }) => { + const { uiConfig } = useUiConfig(); + const { value: selectedValue, setValue: setSelectedValue } = + createLocalStorage<{ value?: 'yes' | 'no' }>( + `ProjectOverviewFeedback:v1:${id}`, + {} + ); + const [selected, setSelected] = useState<'yes' | 'no' | undefined>( + selectedValue.value + ); + const { trackEvent } = usePlausibleTracker(); + + if (!uiConfig?.flags?.T) { + return null; + } + + const onTrackFeedback = (value: 'yes' | 'no') => { + setSelected(value); + setSelectedValue({ value }); + trackEvent('project_overview', { + props: { + eventType: id, + wasHelpful: value === 'yes', + }, + }); + }; + + return ( + theme.palette.neutral.light, + padding: theme => theme.spacing(1.5, 2), + marginTop: theme => theme.spacing(1.5), + }} + > + Was this information useful to you? + + + + + + ); +}; diff --git a/frontend/src/component/project/Project/ProjectStats/HelpPopper.tsx b/frontend/src/component/project/Project/ProjectStats/HelpPopper.tsx new file mode 100644 index 0000000000..da9b91e970 --- /dev/null +++ b/frontend/src/component/project/Project/ProjectStats/HelpPopper.tsx @@ -0,0 +1,75 @@ +import { FC, useState } from 'react'; +import { Close, HelpOutline } from '@mui/icons-material'; +import { + Box, + IconButton, + Popper, + Paper, + ClickAwayListener, + styled, +} from '@mui/material'; +import { Feedback } from './Feedback'; + +interface IHelpPopperProps { + id: string; +} + +const StyledPaper = styled(Paper)(({ theme }) => ({ + padding: theme.spacing(3, 3), + maxWidth: '350px', + borderRadius: `${theme.shape.borderRadiusMedium}px`, + border: `1px solid ${theme.palette.neutral.border}`, + fontSize: theme.typography.body2.fontSize, +})); + +export const HelpPopper: FC = ({ children, id }) => { + const [anchor, setAnchorEl] = useState(null); + + const onOpen = (event: React.FormEvent) => + setAnchorEl(event.currentTarget); + + const onClose = () => setAnchorEl(null); + + const open = Boolean(anchor); + + return ( + theme.spacing(0.5), + right: theme => theme.spacing(0.5), + }} + > + + theme.typography.body1.fontSize }} + /> + + + ({ zIndex: theme.zIndex.tooltip })} + > + + + + + theme.typography.body1.fontSize, + }} + /> + + {children} + + + + + + ); +}; diff --git a/frontend/src/component/project/Project/ProjectStats/ProjectStats.tsx b/frontend/src/component/project/Project/ProjectStats/ProjectStats.tsx index 08c79c941c..8b5296d7f5 100644 --- a/frontend/src/component/project/Project/ProjectStats/ProjectStats.tsx +++ b/frontend/src/component/project/Project/ProjectStats/ProjectStats.tsx @@ -1,5 +1,6 @@ import { Box, styled, Typography } from '@mui/material'; import { ProjectStatsSchema } from 'openapi/models'; +import { HelpPopper } from './HelpPopper'; import { StatusBox } from './StatusBox'; const StyledBox = styled(Box)(({ theme }) => ({ @@ -20,6 +21,7 @@ const StyledBox = styled(Box)(({ theme }) => ({ })); const StyledWidget = styled(Box)(({ theme }) => ({ + position: 'relative', padding: theme.spacing(3), backgroundColor: theme.palette.background.paper, flex: 1, @@ -73,7 +75,12 @@ export const ProjectStats = ({ stats }: IProjectStatsProps) => { projectActivityPastWindow - 20 } - /> + > + + Sum of all configuration and state modifications in the + project. + + { avgTimeToProdPastWindow )} percentage - /> + > + + How long did it take on average from a feature toggle + was created until it was enabled in an environment of + type production. + + { return 'warning.dark'; }; -export const StatusBox = ({ +export const StatusBox: FC = ({ title, boxText, change, percentage, -}: IStatusBoxProps) => ( + children, +}) => ( <> {title}} /> + {children} = () => [ * The state is also persisted to localStorage and restored on page load. * The localStorage state is not synced between tabs. * - * @deprecated `hooks/useLocalStorage` -- we don't need `react-hooks-global-state` + * @deprecated `utils/createLocalStorage` -- we don't need `react-hooks-global-state` */ export const createPersistentGlobalStateHook = ( key: string, diff --git a/frontend/src/hooks/usePlausibleTracker.ts b/frontend/src/hooks/usePlausibleTracker.ts index 3b9221d055..847e24621b 100644 --- a/frontend/src/hooks/usePlausibleTracker.ts +++ b/frontend/src/hooks/usePlausibleTracker.ts @@ -16,6 +16,7 @@ type CustomEvents = | 'maintenance' | 'message_banner' | 'hidden_environment' + | 'project_overview' | 'suggest_tags' | 'unknown_ui_error';