diff --git a/assets/translations/en.json b/assets/translations/en.json
index 0dae4556c..25d3a8aef 100644
--- a/assets/translations/en.json
+++ b/assets/translations/en.json
@@ -131,7 +131,7 @@
"common_refresh_error": "The applets list was not refreshed. Please try again."
},
"activity_list_component": {
- "no_activities_yet": "No activities specified yet",
+ "no_activities": "No activities are available for you to complete right now",
"insufficient_data_error": "This applet was not refreshed. Please try to refresh again.",
"other_error": "Undefined error occurred"
},
diff --git a/assets/translations/fr.json b/assets/translations/fr.json
index 51a702162..2fcaf8828 100644
--- a/assets/translations/fr.json
+++ b/assets/translations/fr.json
@@ -131,7 +131,7 @@
"common_refresh_error": "La liste des applets n'a pas été actualisée. Veuillez réessayer."
},
"activity_list_component": {
- "no_activities_yet": "Aucune activité spécifiée pour le moment",
+ "no_activities": "Aucune activité n'est disponible pour le moment",
"insufficient_data_error": "Cette applet n'a pas été actualisée. Veuillez réessayer d'actualiser.",
"other_error": "Une erreur non définie s'est produite"
},
diff --git a/src/shared/ui/icons/ChecklistIcon.tsx b/src/shared/ui/icons/ChecklistIcon.tsx
new file mode 100644
index 000000000..f453cb2b4
--- /dev/null
+++ b/src/shared/ui/icons/ChecklistIcon.tsx
@@ -0,0 +1,10 @@
+import Svg, { Path, SvgProps } from 'react-native-svg';
+
+export const ChecklistIcon = (props: SvgProps) => (
+
+);
diff --git a/src/widgets/activity-group/ui/ActivityGroups.tsx b/src/widgets/activity-group/ui/ActivityGroups.tsx
index d04511d8e..425d52c10 100644
--- a/src/widgets/activity-group/ui/ActivityGroups.tsx
+++ b/src/widgets/activity-group/ui/ActivityGroups.tsx
@@ -1,6 +1,7 @@
-import { FC } from 'react';
+import { FC, useMemo } from 'react';
import { useIsFetching } from '@tanstack/react-query';
+import { useTranslation } from 'react-i18next';
import {
CheckAvailability,
@@ -9,10 +10,12 @@ import {
import { getAppletCompletedEntitiesKey } from '@app/shared/lib/utils/reactQueryHelpers';
import { ActivityIndicator } from '@app/shared/ui/ActivityIndicator';
import { Box, BoxProps, XStack, YStack } from '@app/shared/ui/base';
+import { ChecklistIcon } from '@app/shared/ui/icons/ChecklistIcon';
import { LoadListError } from '@app/shared/ui/LoadListError';
-import { NoListItemsYet } from '@app/shared/ui/NoListItemsYet';
import { ActivitySectionList } from './ActivitySectionList';
+import { EmptyState } from './EmptyState';
+import { ActivityGroupType } from '../lib/types/activityGroup';
import { useActivityGroups } from '../model/hooks/useActivityGroups';
import { useBaseInfo } from '../model/hooks/useBaseInfo';
@@ -23,6 +26,8 @@ type Props = {
} & BoxProps;
export const ActivityGroups: FC = props => {
+ const { t } = useTranslation();
+
const isLoadingCompletedEntities =
useIsFetching({
exact: true,
@@ -34,6 +39,26 @@ export const ActivityGroups: FC = props => {
const { responseTypes } = data || {};
const hasError = !isSuccess || !!baseInfoError;
+ const renderedGroups = useMemo(() => {
+ const hasActivities = groups.some(g => g.activities.length);
+
+ if (hasActivities) {
+ // Only show empty available group if there are no in-progress activities
+ const showAvailableGroup = !groups.some(
+ g => g.type === ActivityGroupType.InProgress && g.activities.length,
+ );
+
+ // Filter out empty groups, but show the available group based on above logic
+ return groups.filter(
+ g =>
+ g.activities.length ||
+ (g.type === ActivityGroupType.Available && showAvailableGroup),
+ );
+ } else {
+ return null;
+ }
+ }, [groups]);
+
if (isLoadingCompletedEntities || isLoading) {
return (
= props => {
);
}
- if (isSuccess && !groups?.length) {
- return (
-
-
-
- );
- }
-
return (
-
+ {renderedGroups ? (
+
+ ) : (
+ }
+ description={t('activity_list_component:no_activities')}
+ />
+ )}
);
diff --git a/src/widgets/activity-group/ui/ActivitySectionList.tsx b/src/widgets/activity-group/ui/ActivitySectionList.tsx
index b01d49c65..9a98e838c 100644
--- a/src/widgets/activity-group/ui/ActivitySectionList.tsx
+++ b/src/widgets/activity-group/ui/ActivitySectionList.tsx
@@ -28,8 +28,10 @@ import {
getSupportsMobile,
} from '@app/shared/lib/utils/responseTypes';
import { Box, YStack } from '@app/shared/ui/base';
+import { ChecklistIcon } from '@app/shared/ui/icons/ChecklistIcon';
import { Text } from '@app/shared/ui/Text';
+import { EmptyState } from './EmptyState';
import { ActivityListGroup } from '../lib/types/activityGroup';
import { useAvailabilityEvaluator } from '../model/hooks/useAvailabilityEvaluator';
@@ -54,16 +56,10 @@ export function ActivitySectionList({
const { isUploading } = useUploadObservable();
- const sections = useMemo(() => {
- return groups
- .filter(g => g.activities.length)
- .map(group => {
- return {
- data: group.activities,
- key: t(group.name),
- };
- });
- }, [t, groups]);
+ const sections = useMemo(
+ () => groups.map(group => ({ data: group.activities, key: t(group.name) })),
+ [t, groups],
+ );
const { startFlow, startActivity } = useStartEntity({
hasMediaReferences: getDefaultMediaLookupService().hasMediaReferences,
@@ -200,6 +196,16 @@ export function ActivitySectionList({
/>
);
}}
+ // SectionList doesn't provide a prop for section empty components, so we use
+ // renderSectionFooter to conditionally render any empty sections.
+ renderSectionFooter={({ section }) =>
+ section.data.length ? null : (
+ }
+ description={t('activity_list_component:no_activities')}
+ />
+ )
+ }
ItemSeparatorComponent={ItemSeparator}
stickySectionHeadersEnabled={false}
contentContainerStyle={styles.sectionList}
diff --git a/src/widgets/activity-group/ui/EmptyState.tsx b/src/widgets/activity-group/ui/EmptyState.tsx
new file mode 100644
index 000000000..080b1f3c6
--- /dev/null
+++ b/src/widgets/activity-group/ui/EmptyState.tsx
@@ -0,0 +1,26 @@
+import { ReactNode } from 'react';
+
+import { BoxProps, YStack } from '@app/shared/ui/base';
+import { Text } from '@app/shared/ui/Text';
+
+type Props = BoxProps & {
+ icon: ReactNode;
+ description: string;
+};
+
+export const EmptyState = ({ icon, description, ...rest }: Props) => {
+ return (
+
+ {icon}
+
+ {description}
+
+
+ );
+};