Add report bug functionality and settings sections refactor

This commit is contained in:
Mo Tarbin
2026-08-11 17:42:23 -04:00
parent c474041c7c
commit fb4d4efe66
7 changed files with 155 additions and 137 deletions

View File

@@ -1,22 +1,4 @@
import {
AccountCircle,
Api,
BugReport,
ChevronRight,
Circle,
Code,
FamilyRestroom,
Feedback,
Language,
Notifications,
Palette,
Person,
Security,
Settings,
Star,
Storage,
ViewSidebar,
} from '@mui/icons-material'
import { BugReport, ChevronRight, Feedback, Star } from '@mui/icons-material'
import {
Avatar,
Box,
@@ -37,6 +19,7 @@ import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router-dom'
import { SETTINGS_SECTIONS } from '../../constants/settingsSections'
import { useUserProfile } from '../../queries/UserQueries'
import { isPlusAccount } from '../../utils/Helpers'
import { isParentUser } from '../../utils/UserHelpers'
@@ -51,85 +34,13 @@ const SettingsOverview = () => {
const [bugReportOpen, setBugReportOpen] = useState(false)
const settingsCards = [
{
id: 'profile',
title: t('overview.sections.profile.title'),
description: t('overview.sections.profile.description'),
icon: <Person />,
},
{
id: 'circle',
title: t('overview.sections.circle.title'),
description: t('overview.sections.circle.description'),
icon: <Circle />,
},
{
id: 'account',
title: t('overview.sections.account.title'),
description: t('overview.sections.account.description'),
icon: <AccountCircle />,
},
{
id: 'subaccounts',
title: t('overview.sections.subaccounts.title'),
description: t('overview.sections.subaccounts.description'),
icon: <FamilyRestroom />,
},
{
id: 'notifications',
title: t('overview.sections.notifications.title'),
description: t('overview.sections.notifications.description'),
icon: <Notifications />,
},
{
id: 'mfa',
title: t('overview.sections.mfa.title'),
description: t('overview.sections.mfa.description'),
icon: <Security />,
},
{
id: 'apitokens',
title: t('overview.sections.apitokens.title'),
description: t('overview.sections.apitokens.description'),
icon: <Api />,
},
{
id: 'storage',
title: t('overview.sections.storage.title'),
description: t('overview.sections.storage.description'),
icon: <Storage />,
},
{
id: 'sidepanel',
title: t('overview.sections.sidepanel.title'),
description: t('overview.sections.sidepanel.description'),
icon: <ViewSidebar />,
},
{
id: 'theme',
title: t('overview.sections.theme.title'),
description: t('overview.sections.theme.description'),
icon: <Palette />,
},
{
id: 'localization',
title: t('overview.sections.localization.title'),
description: t('overview.sections.localization.description'),
icon: <Language />,
isBeta: true,
},
{
id: 'advanced',
title: t('overview.sections.advanced.title'),
description: t('overview.sections.advanced.description'),
icon: <Settings />,
},
{
id: 'developer',
title: t('overview.sections.developer.title'),
description: t('overview.sections.developer.description'),
icon: <Code />,
},
...SETTINGS_SECTIONS.map(({ icon: Icon, id, isBeta }) => ({
id,
title: t(`overview.sections.${id}.title`),
description: t(`overview.sections.${id}.description`),
icon: <Icon />,
isBeta,
})),
{
id: 'feedback',
title: t('overview.sections.feedback.title'),
@@ -154,23 +65,19 @@ const SettingsOverview = () => {
navigate(`/settings/${setting.id}`)
}
const parentOnlyIds = SETTINGS_SECTIONS.filter(
section => section.parentOnly,
).map(section => section.id)
// Filter settings based on user type
const getAvailableSettings = () => {
const parentOnlySettings = [
'children',
'mfa',
'apitokens',
'circle',
'account',
]
if (isParentUser(userProfile)) {
// Parent users can access all settings
return settingsCards
} else {
// Child users can only access basic settings
return settingsCards.filter(
setting => !parentOnlySettings.includes(setting.id),
setting => !parentOnlyIds.includes(setting.id),
)
}
}

View File

@@ -1,5 +1,14 @@
import { Add } from '@mui/icons-material'
import { Box, Button, Typography } from '@mui/joy'
import { Add, KeyboardArrowDown } from '@mui/icons-material'
import {
Box,
Button,
Dropdown,
ListItemDecorator,
Menu,
MenuButton,
MenuItem,
Typography,
} from '@mui/joy'
import { useMediaQuery } from '@mui/material'
import { useQueryClient } from '@tanstack/react-query'
import * as chrono from 'chrono-node'
@@ -9,6 +18,7 @@ import { flushSync } from 'react-dom'
import KeyboardShortcutHint from '../../components/common/KeyboardShortcutHint'
import ModalActions from '../../components/common/ModalActions'
import { Z_INDEX } from '../../constants/zIndex'
import { useDocumentScanner } from '../../hooks/useDocumentScanner'
import { useFileUpload } from '../../hooks/useFileUpload'
import { useResponsiveModal } from '../../hooks/useResponsiveModal'
@@ -20,6 +30,7 @@ import LABEL_COLORS, { TASK_COLOR } from '../../utils/Colors'
import { CreateLabel } from '../../utils/Fetcher'
import { imageSourceToFile } from '../../utils/FileConvert'
import { isPlusAccount } from '../../utils/Helpers'
import { getIconComponent } from '../../utils/ProjectIcons'
import { generateUUID } from '../../utils/UUID'
import { useLabels } from '../Labels/LabelQueries'
import { useProjects } from '../Projects/ProjectQueries'
@@ -122,6 +133,13 @@ const getInitialProject = () => {
return 'default'
}
const DEFAULT_PROJECT = {
id: 'default',
name: 'Default Project',
color: '#9CA3AF',
icon: 'FolderOpen',
}
const PRIORITY_COLORS = {
0: TASK_COLOR.NO_PRIORITY,
1: TASK_COLOR.PRIORITY_1,
@@ -175,7 +193,7 @@ const TaskInput = ({ initialMode, isModalOpen, onChoreUpdate, onClose }) => {
const { data: userLabels, isLoading: userLabelsLoading } = useLabels()
const { data: circleMembers, isLoading: isCircleMembersLoading } =
useCircleMembers()
const { isLoading: isProjectsLoading } = useProjects()
const { data: projects, isLoading: isProjectsLoading } = useProjects()
const createChoreMutation = useCreateChore()
const queryClient = useQueryClient()
@@ -293,6 +311,17 @@ const TaskInput = ({ initialMode, isModalOpen, onChoreUpdate, onClose }) => {
const [useCustomTime, setUseCustomTime] = useState(false)
const [showKeyboardShortcuts, setShowKeyboardShortcuts] = useState(false)
const [projectId, setProjectId] = useState(getInitialProject)
const selectedProject = useMemo(
() =>
(projectId !== 'default' &&
projects?.find(project => project.id === projectId)) ||
DEFAULT_PROJECT,
[projects, projectId],
)
const SelectedProjectIcon = useMemo(
() => getIconComponent(selectedProject.icon),
[selectedProject],
)
const [attachments, setAttachments] = useState([])
const [draftId, setDraftId] = useState(() => generateUUID())
@@ -1117,6 +1146,50 @@ const TaskInput = ({ initialMode, isModalOpen, onChoreUpdate, onClose }) => {
title='Create new task'
footer={
<ModalActions>
{!showScan && !showVoice && projects?.length >= 1 && (
<Dropdown>
<MenuButton
variant='plain'
color='neutral'
size='sm'
startDecorator={
<SelectedProjectIcon
sx={{ fontSize: 18, color: selectedProject.color }}
/>
}
endDecorator={<KeyboardArrowDown sx={{ fontSize: 16 }} />}
sx={{
mr: 'auto',
color: 'text.secondary',
fontWeight: 'normal',
}}
>
{selectedProject.name}
</MenuButton>
<Menu
placement='top-start'
sx={{ minWidth: 200, zIndex: Z_INDEX.MODAL_POPOVER }}
>
{[DEFAULT_PROJECT, ...projects].map(project => {
const ProjectIcon = getIconComponent(project.icon)
return (
<MenuItem
key={project.id}
selected={projectId === project.id}
onClick={() => setProjectId(project.id)}
>
<ListItemDecorator>
<ProjectIcon
sx={{ fontSize: 18, color: project.color }}
/>
</ListItemDecorator>
{project.name}
</MenuItem>
)
})}
</Menu>
</Dropdown>
)}
<Button
variant='outlined'
color='neutral'

View File

@@ -2,6 +2,7 @@ import { Capacitor } from '@capacitor/core'
import {
Archive,
ArrowBack,
BugReport,
FilterAlt,
FolderOpen,
History,
@@ -35,6 +36,7 @@ import { useLocalization } from '../../contexts/LocalizationContext'
import { useResource } from '../../queries/ResourceQueries'
import { useGlobalSearch } from '../../search/GlobalSearchContext'
import { apiClient } from '../../utils/ApiClient'
import ErrorReportModal from '../Modals/ErrorReportModal'
import NavBarLink from './NavBarLink'
import SyncStatusIndicator from './SyncStatusIndicator'
@@ -47,6 +49,7 @@ const NavBar = () => {
const navigate = useNavigate()
const [drawerOpen, setDrawerOpen] = useState(false)
const [bugReportOpen, setBugReportOpen] = useState(false)
const links = [
{
@@ -293,6 +296,17 @@ const NavBar = () => {
</ListItemDecorator>
<ListItemContent>Upgrade to Plus</ListItemContent>
</ListItemButton> */}
<ListItemButton
onClick={() => setBugReportOpen(true)}
sx={{
py: 1.2,
}}
>
<ListItemDecorator>
<BugReport />
</ListItemDecorator>
<ListItemContent>{t('navigation.reportBug')}</ListItemContent>
</ListItemButton>
<ListItemButton
onClick={() => {
apiClient.handleLogout()
@@ -326,6 +340,10 @@ const NavBar = () => {
</List>
</div>
</Drawer>
<ErrorReportModal
open={bugReportOpen}
onClose={() => setBugReportOpen(false)}
/>
</nav>
)
}