Add Authentik sign-in, fix tab scroll insets, and polish multi-account auth.

Mobile app detects SSO per server, supports OAuth sign-in, and preserves saved
sessions when adding accounts. Tab screens get proper chrome layout and tab-bar
clearance with scrollable page headers.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-18 02:27:31 -04:00
parent 3daf123399
commit 0b2d65a4e9
21 changed files with 449 additions and 200 deletions
+5 -12
View File
@@ -1,9 +1,10 @@
import { useEffect, useMemo, useState, type ReactNode } from "react";
import { Alert, Platform, Pressable, RefreshControl, ScrollView, StyleSheet, Text, View } from "react-native";
import { Alert, Pressable, RefreshControl, StyleSheet, Text, View } from "react-native";
import { router } from "expo-router";
import { GlassSurface } from "@/components/GlassSurface";
import { LoadingScreen } from "@/components/LoadingScreen";
import { TabScrollView } from "@/components/TabScrollView";
import { Button } from "@/components/ui/Button";
import { Card } from "@/components/ui/Card";
import { DateTimeField } from "@/components/ui/DateTimeField";
@@ -11,8 +12,6 @@ import { Input } from "@/components/ui/Input";
import { SelectField } from "@/components/ui/SelectField";
import { fonts, spacing } from "@/constants/theme";
import { useAppTheme } from "@/contexts/ThemeContext";
import { useTabBarScrollPadding } from "@/lib/tab-bar-insets";
import { tabLayout } from "@/lib/tab-layout";
import { formatDateTime } from "@/lib/format";
import { parseNonNegativeNumber } from "@/lib/form-validation";
import type { ThemeColors } from "@/lib/theme-palette";
@@ -70,7 +69,6 @@ export function TimeClockPanel({
}, []);
const todayQuery = api.timeEntries.getAll.useQuery({ from: todayStart });
const scrollPadding = useTabBarScrollPadding();
const clockIn = api.timeEntries.clockIn.useMutation({
onSuccess: async () => {
@@ -252,11 +250,9 @@ export function TimeClockPanel({
.join(" · ");
return (
<ScrollView
<TabScrollView
style={styles.scroll}
contentContainerStyle={[tabLayout.scrollContent, { paddingBottom: scrollPadding }]}
contentInsetAdjustmentBehavior={Platform.OS === "ios" ? "never" : undefined}
scrollIndicatorInsets={{ bottom: scrollPadding }}
header={header}
refreshControl={
<RefreshControl
refreshing={runningQuery.isRefetching}
@@ -270,8 +266,6 @@ export function TimeClockPanel({
/>
}
>
{header}
<View style={tabLayout.scrollBody}>
{running || !compact ? (
<GlassSurface style={running ? styles.runningCard : undefined}>
<View style={styles.hero}>
@@ -442,8 +436,7 @@ export function TimeClockPanel({
})}
</Card>
) : null}
</View>
</ScrollView>
</TabScrollView>
);
}