diff --git a/formulus/src/components/common/FormListTable.tsx b/formulus/src/components/common/FormListTable.tsx index 99d76bb21..d0cff067e 100644 --- a/formulus/src/components/common/FormListTable.tsx +++ b/formulus/src/components/common/FormListTable.tsx @@ -1,5 +1,12 @@ import React, { memo, useCallback } from 'react'; -import { View, Text, Pressable, StyleSheet, ScrollView } from 'react-native'; +import { + View, + Text, + Pressable, + StyleSheet, + ScrollView, + useWindowDimensions, +} from 'react-native'; import Icon from '@react-native-vector-icons/material-design-icons'; import { useTranslation } from 'react-i18next'; import { useAppTheme } from '../../contexts/AppThemeContext'; @@ -10,6 +17,9 @@ import { } from '../../theme/odeDesign'; import type { FormSpec } from '../../services/FormService'; +// Below 600px, hide secondary columns to keep tables usable on small screens. +const NARROW_WIDTH = 600; + type FormListTableProps = { forms: FormSpec[]; observationCounts: Record; @@ -24,24 +34,36 @@ type FormTableRowProps = { divider: string; primary: string; newLabel: string; + isNarrow: boolean; }; const FormTableRow = memo( - ({ form, count, onCreate, cellColor, divider, primary, newLabel }) => { + ({ + form, + count, + onCreate, + cellColor, + divider, + primary, + newLabel, + isNarrow, + }) => { const onPress = useCallback(() => onCreate(form.id), [onCreate, form.id]); return ( {form.name || form.id} - - {count == null ? '—' : String(count)} - + {!isNarrow && ( + + {count == null ? '—' : String(count)} + + )} @@ -59,6 +81,8 @@ const FormListTable: React.FC = ({ }) => { const { t } = useTranslation(); const { themeColors } = useAppTheme(); + const { width } = useWindowDimensions(); + const isNarrow = width < NARROW_WIDTH; const headerColor = themeColors.onSurface as string; const cellColor = themeColors.onSurface as string; const divider = themeColors.divider as string; @@ -74,19 +98,21 @@ const FormListTable: React.FC = ({ {t('forms.colFormType')} - - {t('forms.colObservationCount')} - - - {t('forms.colNewObservation')} - + {!isNarrow && ( + + {t('forms.colObservationCount')} + + )} + + {!isNarrow && ( + + {t('forms.colNewObservation')} + + )} + {forms.map(form => ( = ({ divider={divider} primary={primary} newLabel={newLabel} + isNarrow={isNarrow} /> ))} @@ -137,16 +164,22 @@ const styles = StyleSheet.create({ paddingRight: odeSpacing.xs, }, cellCount: { - width: 216, + flex: 0.8, + minWidth: 0, fontSize: odeTypography.bodySm, paddingRight: odeSpacing.sm, textAlign: 'right', }, cellNew: { - width: 160, + flex: 0.8, + minWidth: 0, alignItems: 'flex-end', justifyContent: 'center', }, + cellNewNarrow: { + flex: 0, + width: 40, + }, newHeader: { textAlign: 'right', }, diff --git a/formulus/src/components/common/ObservationListTable.tsx b/formulus/src/components/common/ObservationListTable.tsx index 37de90804..2a8309107 100644 --- a/formulus/src/components/common/ObservationListTable.tsx +++ b/formulus/src/components/common/ObservationListTable.tsx @@ -1,5 +1,12 @@ import React, { memo, useCallback } from 'react'; -import { View, Text, Pressable, StyleSheet, ScrollView } from 'react-native'; +import { + View, + Text, + Pressable, + StyleSheet, + ScrollView, + useWindowDimensions, +} from 'react-native'; import { useTranslation } from 'react-i18next'; import { useAppTheme } from '../../contexts/AppThemeContext'; import colors from '../../theme/colors'; @@ -15,6 +22,8 @@ import { import { isObservationFullySynced } from '../../utils/observationSyncStatus'; import { formatDateTimeShort } from '../../utils/dateUtils'; +const NARROW_WIDTH = 600; + type ObservationListTableProps = { rows: ObservationListRow[]; formNames: Record; @@ -31,6 +40,7 @@ type ObservationTableRowProps = { syncedColor: string; syncedLabel: string; pendingLabel: string; + isNarrow: boolean; }; const ObservationTableRow = memo( @@ -44,6 +54,7 @@ const ObservationTableRow = memo( syncedColor, syncedLabel, pendingLabel, + isNarrow, }) => { const synced = isObservationFullySynced(row); const onPress = useCallback(() => onPressRow(row), [onPressRow, row]); @@ -66,16 +77,20 @@ const ObservationTableRow = memo( numberOfLines={1}> {synced ? syncedLabel : pendingLabel} - - {row.author || '—'} - - - {formatObservationIdShort(row.observationId)} - + {!isNarrow && ( + <> + + {row.author || '—'} + + + {formatObservationIdShort(row.observationId)} + + + )} ); }, @@ -88,6 +103,8 @@ const ObservationListTable: React.FC = ({ }) => { const { t } = useTranslation(); const { themeColors } = useAppTheme(); + const { width } = useWindowDimensions(); + const isNarrow = width < NARROW_WIDTH; const headerColor = themeColors.onSurface as string; const cellColor = themeColors.onSurface as string; const divider = themeColors.divider as string; @@ -111,13 +128,22 @@ const ObservationListTable: React.FC = ({ {t('observations.colSync')} - - {t('observations.colAuthor')} - - - {t('observations.colId')} - + {!isNarrow && ( + <> + + {t('observations.colAuthor')} + + + {t('observations.colId')} + + + )} {rows.map(row => ( = ({ syncedColor={syncedColor} syncedLabel={syncedLabel} pendingLabel={pendingLabel} + isNarrow={isNarrow} /> ))}