Fix: pass the right user id when impersonating a user to chorefilter
implement experimental offline mode; add toggle in StorageSettings and update chore filters
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { networkManager } from '../hooks/NetworkManager'
|
import { networkManager } from '../hooks/NetworkManager'
|
||||||
|
import { FEATURES, isFeatureEnabled } from '../utils/FeatureToggle'
|
||||||
import {
|
import {
|
||||||
CreateChore,
|
CreateChore,
|
||||||
GetChoreByID,
|
GetChoreByID,
|
||||||
@@ -17,6 +18,11 @@ export const useChores = includeArchive => {
|
|||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const onlineChores = await GetChoresNew(includeArchive)
|
const onlineChores = await GetChoresNew(includeArchive)
|
||||||
|
|
||||||
|
// Only handle offline tasks if experimental offline mode is enabled
|
||||||
|
if (!isFeatureEnabled(FEATURES.OFFLINE_MODE)) {
|
||||||
|
return onlineChores
|
||||||
|
}
|
||||||
|
|
||||||
const offlineTasks = (await localStore.getFromCache('offlineTasks')) || []
|
const offlineTasks = (await localStore.getFromCache('offlineTasks')) || []
|
||||||
// go throught each and if there is two chores with same id in offline and online, prefer the offline one:
|
// go throught each and if there is two chores with same id in offline and online, prefer the offline one:
|
||||||
var finalChores = []
|
var finalChores = []
|
||||||
@@ -58,7 +64,7 @@ export const useCreateChore = () => {
|
|||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: CreateChore,
|
mutationFn: CreateChore,
|
||||||
onMutate: async newTask => {
|
onMutate: async newTask => {
|
||||||
if (!networkManager.isOnline) {
|
if (!networkManager.isOnline && isFeatureEnabled(FEATURES.OFFLINE_MODE)) {
|
||||||
const tempId = crypto.randomUUID() // Generate temp ID
|
const tempId = crypto.randomUUID() // Generate temp ID
|
||||||
const offlineTasks =
|
const offlineTasks =
|
||||||
(await localStore.getFromCache('offlineTasks')) || []
|
(await localStore.getFromCache('offlineTasks')) || []
|
||||||
@@ -95,7 +101,7 @@ export const useUpdateChore = () => {
|
|||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async updatedChore => {
|
mutationFn: async updatedChore => {
|
||||||
if (!networkManager.isOnline) {
|
if (!networkManager.isOnline && isFeatureEnabled(FEATURES.OFFLINE_MODE)) {
|
||||||
updatedChore['updatedAt'] = new Date().toISOString()
|
updatedChore['updatedAt'] = new Date().toISOString()
|
||||||
if (!updatedChore['nextDueDate']) {
|
if (!updatedChore['nextDueDate']) {
|
||||||
updatedChore['nextDueDate'] = updatedChore['dueDate']
|
updatedChore['nextDueDate'] = updatedChore['dueDate']
|
||||||
@@ -150,7 +156,7 @@ export const useUpdateChore = () => {
|
|||||||
queryClient.invalidateQueries(['chores'])
|
queryClient.invalidateQueries(['chores'])
|
||||||
},
|
},
|
||||||
onMutate: async updatedChore => {
|
onMutate: async updatedChore => {
|
||||||
if (!networkManager.isOnline) {
|
if (!networkManager.isOnline && isFeatureEnabled(FEATURES.OFFLINE_MODE)) {
|
||||||
// Handle offline case here if needed
|
// Handle offline case here if needed
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -192,6 +198,11 @@ export const useChoreDetails = choreId => {
|
|||||||
console.error('Error fetching chore detail:', error)
|
console.error('Error fetching chore detail:', error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only check offline tasks if experimental offline mode is enabled
|
||||||
|
if (!isFeatureEnabled(FEATURES.OFFLINE_MODE)) {
|
||||||
|
return onlineChore
|
||||||
|
}
|
||||||
|
|
||||||
const offlineTasks = (await localStore.getFromCache('offlineTasks')) || []
|
const offlineTasks = (await localStore.getFromCache('offlineTasks')) || []
|
||||||
const offline = offlineTasks.find(task => {
|
const offline = offlineTasks.find(task => {
|
||||||
// Match by tempId or id if it was created offline
|
// Match by tempId or id if it was created offline
|
||||||
@@ -224,6 +235,11 @@ export const useChore = choreId => {
|
|||||||
console.error('Error fetching chore detail:', error)
|
console.error('Error fetching chore detail:', error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only check offline tasks if experimental offline mode is enabled
|
||||||
|
if (!isFeatureEnabled(FEATURES.OFFLINE_MODE)) {
|
||||||
|
return onlineChore
|
||||||
|
}
|
||||||
|
|
||||||
const offlineTasks = (await localStore.getFromCache('offlineTasks')) || []
|
const offlineTasks = (await localStore.getFromCache('offlineTasks')) || []
|
||||||
const offline = offlineTasks.find(task => {
|
const offline = offlineTasks.find(task => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -327,21 +327,21 @@ export const notInCompletionWindow = chore => {
|
|||||||
moment().add(chore.completionWindow, 'hours') < moment(chore.nextDueDate)
|
moment().add(chore.completionWindow, 'hours') < moment(chore.nextDueDate)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
export const ChoreFilters = userProfile => ({
|
export const ChoreFilters = userId => ({
|
||||||
anyone: () => true,
|
anyone: () => true,
|
||||||
assigned_to_me: chore => {
|
assigned_to_me: chore => {
|
||||||
return chore.assignedTo && chore.assignedTo === userProfile?.id
|
return chore.assignedTo && chore.assignedTo === userId
|
||||||
},
|
},
|
||||||
assigned_to_others: chore => {
|
assigned_to_others: chore => {
|
||||||
return chore.assignedTo && chore.assignedTo !== userProfile?.id
|
return chore.assignedTo && chore.assignedTo !== userId
|
||||||
},
|
},
|
||||||
assigned_to_me_tasks: chore => {
|
assigned_to_me_tasks: chore => {
|
||||||
return (
|
return (
|
||||||
chore.assignees &&
|
chore.assignees &&
|
||||||
chore.assignees.some(assignee => assignee.userId === userProfile?.id)
|
chore.assignees.some(assignee => assignee.userId === userId)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
created_by_me: chore => {
|
created_by_me: chore => {
|
||||||
return chore.createdBy && chore.createdBy === userProfile?.id
|
return chore.createdBy && chore.createdBy === userId
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -146,7 +146,9 @@ const MyChores = () => {
|
|||||||
const sections = ChoresGrouper(
|
const sections = ChoresGrouper(
|
||||||
selectedChoreSection,
|
selectedChoreSection,
|
||||||
sortedChores,
|
sortedChores,
|
||||||
ChoreFilters(userProfile)[selectedChoreFilter],
|
ChoreFilters(impersonatedUser?.userId || userProfile?.id)[
|
||||||
|
selectedChoreFilter
|
||||||
|
],
|
||||||
)
|
)
|
||||||
setChoreSections(sections)
|
setChoreSections(sections)
|
||||||
if (localStorage.getItem('openChoreSections') === null) {
|
if (localStorage.getItem('openChoreSections') === null) {
|
||||||
@@ -537,7 +539,11 @@ const MyChores = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return choresToFilter.filter(ChoreFilters(userProfile)[selectedChoreFilter])
|
return choresToFilter.filter(
|
||||||
|
ChoreFilters(impersonatedUser?.userId || userProfile?.id)[
|
||||||
|
selectedChoreFilter
|
||||||
|
],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to get chores for a specific date
|
// Helper function to get chores for a specific date
|
||||||
@@ -567,7 +573,9 @@ const MyChores = () => {
|
|||||||
ChoresGrouper(
|
ChoresGrouper(
|
||||||
selectedChoreSection,
|
selectedChoreSection,
|
||||||
newChores,
|
newChores,
|
||||||
ChoreFilters(userProfile)[selectedChoreFilter],
|
ChoreFilters(impersonatedUser?.userId || userProfile?.id)[
|
||||||
|
selectedChoreFilter
|
||||||
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
setSearchFilter('All')
|
setSearchFilter('All')
|
||||||
@@ -641,7 +649,9 @@ const MyChores = () => {
|
|||||||
ChoresGrouper(
|
ChoresGrouper(
|
||||||
selectedChoreSection,
|
selectedChoreSection,
|
||||||
newChores,
|
newChores,
|
||||||
ChoreFilters(userProfile)[selectedChoreFilter],
|
ChoreFilters(impersonatedUser?.userId || userProfile?.id)[
|
||||||
|
selectedChoreFilter
|
||||||
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -715,7 +725,9 @@ const MyChores = () => {
|
|||||||
ChoresGrouper(
|
ChoresGrouper(
|
||||||
selectedChoreSection,
|
selectedChoreSection,
|
||||||
newChores,
|
newChores,
|
||||||
ChoreFilters(userProfile)[selectedChoreFilter],
|
ChoreFilters(impersonatedUser?.userId || userProfile?.id)[
|
||||||
|
selectedChoreFilter
|
||||||
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -982,7 +994,9 @@ const MyChores = () => {
|
|||||||
ChoresGrouper(
|
ChoresGrouper(
|
||||||
selectedChoreSection,
|
selectedChoreSection,
|
||||||
newChores,
|
newChores,
|
||||||
ChoreFilters(userProfile)[selectedChoreFilter],
|
ChoreFilters(impersonatedUser?.userId || userProfile?.id)[
|
||||||
|
selectedChoreFilter
|
||||||
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1155,7 +1169,9 @@ const MyChores = () => {
|
|||||||
const section = ChoresGrouper(
|
const section = ChoresGrouper(
|
||||||
selectedChoreSection,
|
selectedChoreSection,
|
||||||
chores,
|
chores,
|
||||||
ChoreFilters(impersonatedUser | userProfile)[filter],
|
ChoreFilters(impersonatedUser?.userId || userProfile?.id)[
|
||||||
|
filter
|
||||||
|
],
|
||||||
)
|
)
|
||||||
setChoreSections(section)
|
setChoreSections(section)
|
||||||
setOpenChoreSectionsWithCache(
|
setOpenChoreSectionsWithCache(
|
||||||
@@ -1170,7 +1186,9 @@ const MyChores = () => {
|
|||||||
const section = ChoresGrouper(
|
const section = ChoresGrouper(
|
||||||
selected.value,
|
selected.value,
|
||||||
chores,
|
chores,
|
||||||
ChoreFilters(userProfile)[selectedChoreFilter],
|
ChoreFilters(impersonatedUser?.userId || userProfile?.id)[
|
||||||
|
selectedChoreFilter
|
||||||
|
],
|
||||||
)
|
)
|
||||||
setChoreSections(section)
|
setChoreSections(section)
|
||||||
setSelectedChoreSectionWithCache(selected.value)
|
setSelectedChoreSectionWithCache(selected.value)
|
||||||
|
|||||||
@@ -1,8 +1,20 @@
|
|||||||
import { Capacitor } from '@capacitor/core'
|
import { Capacitor } from '@capacitor/core'
|
||||||
import { Button, Card, Chip, LinearProgress, Typography } from '@mui/joy'
|
import {
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Chip,
|
||||||
|
LinearProgress,
|
||||||
|
Switch,
|
||||||
|
Typography,
|
||||||
|
} from '@mui/joy'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { useUserProfile } from '../../queries/UserQueries'
|
import { useUserProfile } from '../../queries/UserQueries'
|
||||||
|
import {
|
||||||
|
FEATURES,
|
||||||
|
isFeatureEnabled,
|
||||||
|
setFeatureEnabled,
|
||||||
|
} from '../../utils/FeatureToggle'
|
||||||
import { GetStorageUsage } from '../../utils/Fetcher'
|
import { GetStorageUsage } from '../../utils/Fetcher'
|
||||||
import { isPlusAccount } from '../../utils/Helpers'
|
import { isPlusAccount } from '../../utils/Helpers'
|
||||||
import ConfirmationModal from '../Modals/Inputs/ConfirmationModal'
|
import ConfirmationModal from '../Modals/Inputs/ConfirmationModal'
|
||||||
@@ -14,6 +26,9 @@ const StorageSettings = () => {
|
|||||||
const [usage, setUsage] = useState({ used: 0, total: 0 })
|
const [usage, setUsage] = useState({ used: 0, total: 0 })
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
const [confirmModalConfig, setConfirmModalConfig] = useState({})
|
const [confirmModalConfig, setConfirmModalConfig] = useState({})
|
||||||
|
const [offlineModeEnabled, setOfflineModeEnabledState] = useState(
|
||||||
|
isFeatureEnabled(FEATURES.OFFLINE_MODE),
|
||||||
|
)
|
||||||
|
|
||||||
const showConfirmation = (
|
const showConfirmation = (
|
||||||
message,
|
message,
|
||||||
@@ -39,6 +54,11 @@ const StorageSettings = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleOfflineModeToggle = enabled => {
|
||||||
|
setOfflineModeEnabledState(enabled)
|
||||||
|
setFeatureEnabled(FEATURES.OFFLINE_MODE, enabled)
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isPlusAccount(userProfile)) {
|
if (isPlusAccount(userProfile)) {
|
||||||
GetStorageUsage().then(resp => {
|
GetStorageUsage().then(resp => {
|
||||||
@@ -106,6 +126,40 @@ const StorageSettings = () => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
<Card className='p-4' sx={{ maxWidth: 500, mb: 2 }}>
|
||||||
|
<Typography level='title-md' sx={{ mb: 1 }}>
|
||||||
|
Experimental Features
|
||||||
|
<Chip variant='soft' color='warning' sx={{ ml: 1 }}>
|
||||||
|
Coming Soon
|
||||||
|
</Chip>
|
||||||
|
</Typography>
|
||||||
|
<div className='mb-2 flex items-center justify-between'>
|
||||||
|
<div className='flex-1'>
|
||||||
|
<Typography level='body-md' sx={{ mb: 0.5 }}>
|
||||||
|
Enable Offline Mode
|
||||||
|
</Typography>
|
||||||
|
<Typography level='body-sm' color='neutral'>
|
||||||
|
Allows the app to work offline by caching data locally. This is
|
||||||
|
experimental and may cause some slowness. If you experience
|
||||||
|
performance issues, we recommend turning this off.
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<Switch
|
||||||
|
checked={offlineModeEnabled}
|
||||||
|
disabled={true}
|
||||||
|
onChange={event => handleOfflineModeToggle(event.target.checked)}
|
||||||
|
sx={{ ml: 2 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{offlineModeEnabled && (
|
||||||
|
<Typography level='body-xs' color='warning' sx={{ mt: 1 }}>
|
||||||
|
⚠️ Offline mode is enabled. If you experience slowness, disable
|
||||||
|
this setting.
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
|
||||||
<Card className='p-4' sx={{ maxWidth: 500, mb: 2 }}>
|
<Card className='p-4' sx={{ maxWidth: 500, mb: 2 }}>
|
||||||
<Typography level='title-md' sx={{ mb: 1 }}>
|
<Typography level='title-md' sx={{ mb: 1 }}>
|
||||||
{Capacitor.isNativePlatform() ? 'App' : 'Browser'} Local Storage &
|
{Capacitor.isNativePlatform() ? 'App' : 'Browser'} Local Storage &
|
||||||
|
|||||||
Reference in New Issue
Block a user