Skip to content

Commit

Permalink
Issue 254/big brother report (#261)
Browse files Browse the repository at this point in the history
* Add state differences for report page

* Additional states for managing ai report

* theme updates for hey sport message

* Better weekly report validation

* updating themes to make light mode better
  • Loading branch information
rphovley authored Nov 5, 2024
1 parent fcbfe57 commit e73b25a
Show file tree
Hide file tree
Showing 20 changed files with 692 additions and 133 deletions.
4 changes: 4 additions & 0 deletions packages/app/src/api/platformServer/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ export const gamemakerKeys = {
gameSettings: (id: string) => ['gameSettings', id] as const,
aiWeeklyReports: ['aiWeeklyReports'] as const,
}

export const weeklyReportKeys = {
aiWeeklyReports: (date: string) => ['aiWeeklyReports', date] as const,
}
43 changes: 43 additions & 0 deletions packages/app/src/api/platformServer/weeklyReport.platformApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { platformApiRequest } from '../request'

import { PLATFORM_API_URL, useBetterQuery } from '..'
import { weeklyReportKeys } from './keys'
import { useMutation, useQueryClient } from '@tanstack/react-query'

export const useGetAiWeeklyReport = (startOfWeek: string, email?: string) => {
const queryFn = () =>
platformApiRequest({
url: `${PLATFORM_API_URL}/ai-weekly-report?email=${email}&startOfWeek=${startOfWeek}`,
method: 'GET',
})
return useBetterQuery<string, Error>({
queryKey: weeklyReportKeys.aiWeeklyReports(startOfWeek),
queryFn,
enabled: !!email,
})
}

export const useGenerateAiWeeklyReport = () => {
const queryClient = useQueryClient()
let startOfWeek: string
const mutationFn = (body: {
email: string
startOfWeek: string
weeklyReport: CodeClimbers.WeeklyScores
}) => {
startOfWeek = body.startOfWeek
return platformApiRequest({
url: `${PLATFORM_API_URL}/ai-weekly-report`,
method: 'POST',
body,
})
}
return useMutation({
mutationFn,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: weeklyReportKeys.aiWeeklyReports(startOfWeek),
})
},
})
}
Binary file added packages/app/src/assets/agi_2048.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 6 additions & 1 deletion packages/app/src/components/ContributorsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import { SimpleInfoCard, SimpleInfoCardProps } from './common/SimpleInfoCard'
import Grid2 from '@mui/material/Unstable_Grid2'
import { getContributors } from '../services/contributors.service'
import { PlainHeader } from './common/PlainHeader'
import { useTheme } from '@mui/material/styles'

export const ContributorsPage = () => {
const theme = useTheme()
const contributors = getContributors()
const contributorCardData: SimpleInfoCardProps[] = contributors.map(
(contributor) => ({
Expand All @@ -25,7 +27,10 @@ export const ContributorsPage = () => {
<Grid2 container spacing={2}>
{contributorCardData.map((contributor) => (
<Grid2 key={contributor.title} xs={12} sm={6} md={4} lg={3}>
<SimpleInfoCard {...contributor} />
<SimpleInfoCard
{...contributor}
backgroundColor={theme.palette.background.paper}
/>
</Grid2>
))}
</Grid2>
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/components/Home/DateHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const DateHeader = ({
title,
}: Props) => {
const today = dayjs().startOf(period === 'week' ? 'isoWeek' : period)

const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null)
const open = Boolean(anchorEl)
const navigate = useNavigate()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,10 @@ export const ExtensionsWidget = () => {
</Stack>
<Stack spacing={2}>
{extensionCardData.map((extension) => (
<SimpleInfoCard key={extension.title} {...extension} />
<SimpleInfoCard
key={`${extension.title}-${extension.callout}`}
{...extension}
/>
))}
</Stack>
</Stack>
Expand Down
88 changes: 75 additions & 13 deletions packages/app/src/components/Home/Time/Time.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,100 @@ import Grid2 from '@mui/material/Unstable_Grid2/Grid2'
import { Dayjs } from 'dayjs'

import { BossImage } from '../../common/Icons/BossImage'
import { useState } from 'react'
import { useEffect, useRef, useState } from 'react'
import { WeeklyReportDialog } from '../../common/WeeklyReportDialog'
import { NotificationIcon } from '../../common/Icons/NotificationIcon'
import { DeepWork } from '../DeepWork'
import { CategoryChart } from './CategoryChart'
import { useGetCurrentUser } from '../../../api/browser/user.api'
import { useBrowserStorage } from '../../../hooks/useBrowserStorage'

type Props = { selectedDate: Dayjs }
export const Time = ({ selectedDate }: Props) => {
const [isWeeklyReportModalOpen, setIsWeeklyReportModalOpen] = useState(false)
const iconRef = useRef<HTMLImageElement>(null)
const { data: user } = useGetCurrentUser()
const [dismissedInfo, setDismissedInfo] = useBrowserStorage({
key: 'weekly-report-dismissed',
value: {
dismissed: false,
dismissedAt: null as number | null,
},
})
const [iconPosition, setIconPosition] = useState<DOMRect | null>(null)
const updateIconPosition = () => {
if (!iconRef.current) return
const newPosition = iconRef.current.getBoundingClientRect()
setIconPosition(newPosition)
}
useEffect(() => {
updateIconPosition()
// Add resize event listener
window.addEventListener('resize', updateIconPosition)

// Cleanup
return () => {
window.removeEventListener('resize', updateIconPosition)
}
}, [iconRef])
const WeeklyReportSettings = () => {
const showNotificationIcon = user?.weeklyReportType === '' && !user?.email
const showNotification =
(user?.weeklyReportType === '' && !user?.email) ||
!dismissedInfo?.dismissed
return (
<Box
sx={{ position: 'relative', padding: 0.5, cursor: 'pointer' }}
ref={iconRef}
sx={{
padding: 0.5,
cursor: 'pointer',
}}
onClick={() => {
setIsWeeklyReportModalOpen(true)
setDismissedInfo({ dismissed: true, dismissedAt: Date.now() })
}}
>
<BossImage />
{showNotificationIcon && (
<NotificationIcon
height={16}
width={16}
sx={{
position: 'absolute',
top: 0,
right: 0,
}}
/>
{showNotification && (
<>
<NotificationIcon
height={16}
width={16}
sx={{
position: 'absolute',
top: iconPosition?.top,
left: (iconPosition?.left || 0) + 25,
}}
/>
<Box
sx={{
position: 'absolute',
top: (iconPosition?.top || 0) - 40,
left: (iconPosition?.left || 0) - 45,
borderRadius: 1,
padding: 0.5,
background: (theme) => theme.palette.background.inverted,
'&::after': {
content: '""',
position: 'absolute',
bottom: -6,
right: 10,
width: 0,
height: 0,
borderLeft: '6px solid transparent',
borderRight: '6px solid transparent',
borderTop: (theme) =>
`6px solid ${theme.palette.background.inverted}`,
},
}}
>
<Typography
variant="monospace"
sx={{ color: (theme) => theme.palette.text.inverted }}
>
Hey sport!
</Typography>
</Box>
</>
)}
</Box>
)
Expand Down
30 changes: 22 additions & 8 deletions packages/app/src/components/PerformanceReviewFax.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, Divider, Stack } from '@mui/material'
import { Box, Divider, Stack, Typography } from '@mui/material'
import { BossImage } from './common/Icons/BossImage'

interface Props {
Expand All @@ -7,24 +7,38 @@ interface Props {

export const PerformanceReviewFax = ({ performanceReview }: Props) => {
return (
<Box sx={{ backgroundColor: '#FAF7F7', m: 2, color: '#000', p: 8 }}>
<Box
sx={{
backgroundColor: (theme) => theme.palette.common.white,
color: (theme) => theme.palette.common.black,
p: 6,
}}
>
<Stack>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
<BossImage variant="happy" width={96} height={96} />
<BossImage variant="happy" width={64} height={64} />
<Stack>
<pre style={{ margin: 0, marginBottom: '24px' }}>
<Typography
variant="monospace"
style={{ margin: 0, marginBottom: '12px' }}
>
From: Timothy Brother
</pre>
<pre style={{ margin: 0 }}>Subject: Comments on Your Week</pre>
</Typography>
<Typography variant="monospace" style={{ margin: 0 }}>
Subject: Comments on Your Week
</Typography>
</Stack>
</Box>
<Divider
sx={{ my: 4, backgroundColor: '#000', borderBottomWidth: 2 }}
/>
</Stack>
<pre style={{ whiteSpace: 'pre-wrap', margin: 0 }}>
<Typography
variant="monospace"
style={{ whiteSpace: 'pre-wrap', margin: 0 }}
>
{performanceReview}
</pre>
</Typography>
</Box>
)
}
136 changes: 136 additions & 0 deletions packages/app/src/components/WeeklyReports/AiReportHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { Box, Stack, Typography } from '@mui/material'
import { BossImage } from '../common/Icons/BossImage'
import { CodeClimbersIconButton } from '../common/CodeClimbersIconButton'
import CloseIcon from '@mui/icons-material/Close'
import { WeeklyReportDialog } from '../common/WeeklyReportDialog'
import { useGetCurrentUser } from '../../api/browser/user.api'
import { useEffect, useState } from 'react'
import { CodeClimbersButton } from '../common/CodeClimbersButton'

const getLoadingTexts = (): string => {
return 'Contacting your manager... Choosing excuses... Engaging passive-aggressive behavior... Attempting to sabotage your career... Synergizing with your peers... Scheduling a meeting... Reviewing vieled threats... '
}

const useLoadingText = (loading?: boolean) => {
const [loadingTextIndex, setLoadingTextIndex] = useState(0)

const [loadingText, setLoadingText] = useState('')

useEffect(() => {
if (!loading) {
return
}
const interval = setInterval(() => {
const index =
loadingTextIndex > getLoadingTexts().length ? 0 : loadingTextIndex
setLoadingText((prevText) => prevText + getLoadingTexts()[index])
setLoadingTextIndex((prevIndex) => {
const newIndex = prevIndex + 1
return newIndex >= getLoadingTexts().length ? 0 : newIndex
})
}, 100)
return () => clearInterval(interval)
}, [loadingTextIndex, loadingText, loading])
return {
loadingText,
}
}

export const AiReportHeader = (props: {
showCloseButton?: boolean
aiButton: {
text: string
onClick?: () => void
disabled?: boolean
loading?: boolean
}
openWeeklyReportModal?: boolean
}) => {
const { data: user } = useGetCurrentUser()
const [isWeeklyReportModalOpen, setIsWeeklyReportModalOpen] = useState(false)
const { loadingText } = useLoadingText(props.aiButton.loading)

return (
<Box
sx={{
display: 'flex',
backgroundColor: (theme) => theme.palette.common.white,
color: (theme) => theme.palette.common.black,
justifyContent: 'center',
p: 4,
}}
>
<Box>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2, mb: 4 }}>
<BossImage variant="neutral" width={64} height={64} />
<Stack>
<Typography
variant="monospace"
style={{ margin: 0, marginBottom: '12px' }}
>
From: Timothy Brother
</Typography>
<Typography variant="monospace" style={{ margin: 0 }}>
Subject: Comments on Your Week
</Typography>
</Stack>
</Box>
{props.aiButton.loading ? (
<Typography
variant="monospace"
style={{
width: '265px',
height: '36.5px',
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
textWrap: 'nowrap',
overflow: 'hidden',
}}
>
{loadingText}
</Typography>
) : (
<CodeClimbersButton
eventName="generate_ai_weekly_report"
variant="contained"
fullWidth
disabled={props.aiButton.disabled}
sx={{
'&.Mui-disabled': {
backgroundColor: '#E0E0E0', // or any other color you prefer
color: '#00000080',
},
}}
onClick={() => {
if (props.openWeeklyReportModal) {
setIsWeeklyReportModalOpen(true)
}
props.aiButton.onClick?.()
}}
>
{props.aiButton.text}
</CodeClimbersButton>
)}
</Box>
{props.showCloseButton && (
<Box>
<CodeClimbersIconButton
eventName="close_big_brother_report"
color="inherit"
sx={{ p: 0, pl: 2 }}
>
<CloseIcon />
</CodeClimbersIconButton>
</Box>
)}
{user && isWeeklyReportModalOpen && (
<WeeklyReportDialog
user={user}
open={isWeeklyReportModalOpen}
onClose={() => setIsWeeklyReportModalOpen(false)}
/>
)}
</Box>
)
}
Loading

0 comments on commit e73b25a

Please sign in to comment.