Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 56 additions & 23 deletions formulus/src/components/common/FormListTable.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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<string, number>;
Expand All @@ -24,24 +34,36 @@ type FormTableRowProps = {
divider: string;
primary: string;
newLabel: string;
isNarrow: boolean;
};

const FormTableRow = memo<FormTableRowProps>(
({ 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 (
<View style={[styles.row, { borderColor: divider }]}>
<Text style={[styles.cellForm, { color: cellColor }]} numberOfLines={1}>
{form.name || form.id}
</Text>
<Text
style={[styles.cellCount, { color: cellColor }]}
numberOfLines={1}>
{count == null ? '—' : String(count)}
</Text>
{!isNarrow && (
<Text
style={[styles.cellCount, { color: cellColor }]}
numberOfLines={1}>
{count == null ? '—' : String(count)}
</Text>
)}
<Pressable
onPress={onPress}
style={styles.cellNew}
style={[styles.cellNew, isNarrow && styles.cellNewNarrow]}
accessibilityRole="button"
accessibilityLabel={newLabel}
hitSlop={8}>
Expand All @@ -59,6 +81,8 @@ const FormListTable: React.FC<FormListTableProps> = ({
}) => {
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;
Expand All @@ -74,19 +98,21 @@ const FormListTable: React.FC<FormListTableProps> = ({
<Text style={[styles.cellForm, styles.header, { color: headerColor }]}>
{t('forms.colFormType')}
</Text>
<Text style={[styles.cellCount, styles.header, { color: headerColor }]}>
{t('forms.colObservationCount')}
</Text>
<Text
style={[
styles.cellNew,
styles.header,
styles.newHeader,
{ color: headerColor },
]}
numberOfLines={2}>
{t('forms.colNewObservation')}
</Text>
{!isNarrow && (
<Text
style={[styles.cellCount, styles.header, { color: headerColor }]}>
{t('forms.colObservationCount')}
</Text>
)}
<View style={[styles.cellNew, isNarrow && styles.cellNewNarrow]}>
{!isNarrow && (
<Text
style={[styles.header, styles.newHeader, { color: headerColor }]}
numberOfLines={2}>
{t('forms.colNewObservation')}
</Text>
)}
</View>
</View>
{forms.map(form => (
<FormTableRow
Expand All @@ -102,6 +128,7 @@ const FormListTable: React.FC<FormListTableProps> = ({
divider={divider}
primary={primary}
newLabel={newLabel}
isNarrow={isNarrow}
/>
))}
</ScrollView>
Expand Down Expand Up @@ -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',
},
Expand Down
63 changes: 45 additions & 18 deletions formulus/src/components/common/ObservationListTable.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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<string, string>;
Expand All @@ -31,6 +40,7 @@ type ObservationTableRowProps = {
syncedColor: string;
syncedLabel: string;
pendingLabel: string;
isNarrow: boolean;
};

const ObservationTableRow = memo<ObservationTableRowProps>(
Expand All @@ -44,6 +54,7 @@ const ObservationTableRow = memo<ObservationTableRowProps>(
syncedColor,
syncedLabel,
pendingLabel,
isNarrow,
}) => {
const synced = isObservationFullySynced(row);
const onPress = useCallback(() => onPressRow(row), [onPressRow, row]);
Expand All @@ -66,16 +77,20 @@ const ObservationTableRow = memo<ObservationTableRowProps>(
numberOfLines={1}>
{synced ? syncedLabel : pendingLabel}
</Text>
<Text
style={[styles.cellAuthor, { color: cellColor }]}
numberOfLines={1}>
{row.author || '—'}
</Text>
<Text
style={[styles.cellId, styles.mono, { color: cellColor }]}
numberOfLines={1}>
{formatObservationIdShort(row.observationId)}
</Text>
{!isNarrow && (
<>
<Text
style={[styles.cellAuthor, { color: cellColor }]}
numberOfLines={1}>
{row.author || '—'}
</Text>
<Text
style={[styles.cellId, styles.mono, { color: cellColor }]}
numberOfLines={1}>
{formatObservationIdShort(row.observationId)}
</Text>
</>
)}
</Pressable>
);
},
Expand All @@ -88,6 +103,8 @@ const ObservationListTable: React.FC<ObservationListTableProps> = ({
}) => {
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;
Expand All @@ -111,13 +128,22 @@ const ObservationListTable: React.FC<ObservationListTableProps> = ({
<Text style={[styles.cellSync, styles.header, { color: headerColor }]}>
{t('observations.colSync')}
</Text>
<Text
style={[styles.cellAuthor, styles.header, { color: headerColor }]}>
{t('observations.colAuthor')}
</Text>
<Text style={[styles.cellId, styles.header, { color: headerColor }]}>
{t('observations.colId')}
</Text>
{!isNarrow && (
<>
<Text
style={[
styles.cellAuthor,
styles.header,
{ color: headerColor },
]}>
{t('observations.colAuthor')}
</Text>
<Text
style={[styles.cellId, styles.header, { color: headerColor }]}>
{t('observations.colId')}
</Text>
</>
)}
</View>
{rows.map(row => (
<ObservationTableRow
Expand All @@ -131,6 +157,7 @@ const ObservationListTable: React.FC<ObservationListTableProps> = ({
syncedColor={syncedColor}
syncedLabel={syncedLabel}
pendingLabel={pendingLabel}
isNarrow={isNarrow}
/>
))}
</ScrollView>
Expand Down
Loading