1- import { Link , Stack } from "expo-router" ;
1+ import { Link , Stack , useRouter } from "expo-router" ;
22import { SymbolView } from "expo-symbols" ;
33import type { EnvironmentId , ProjectId } from "@t3tools/contracts" ;
44import { useMemo } from "react" ;
5- import { Pressable , ScrollView , View } from "react-native" ;
5+ import { ActivityIndicator , Pressable , ScrollView , View } from "react-native" ;
66import { useSafeAreaInsets } from "react-native-safe-area-context" ;
77import { useThemeColor } from "../../lib/useThemeColor" ;
88
99import { AppText as Text } from "../../components/AppText" ;
1010import { ProjectFavicon } from "../../components/ProjectFavicon" ;
1111import { groupProjectsByRepository } from "../../lib/repositoryGroups" ;
12- import { useRemoteCatalog } from "../../state/use-remote-catalog" ;
12+ import { type RemoteCatalogState , useRemoteCatalog } from "../../state/use-remote-catalog" ;
1313import { useRemoteEnvironmentState } from "../../state/use-remote-environment-registry" ;
1414
15+ function deriveProjectEmptyState ( catalogState : RemoteCatalogState ) : {
16+ readonly title : string ;
17+ readonly detail : string ;
18+ readonly loading : boolean ;
19+ } {
20+ if ( catalogState . isLoadingSavedConnections ) {
21+ return {
22+ title : "Loading environments" ,
23+ detail : "Checking saved environments on this device." ,
24+ loading : true ,
25+ } ;
26+ }
27+
28+ if ( ! catalogState . hasSavedConnections ) {
29+ return {
30+ title : "No environments connected" ,
31+ detail : "Add an environment before creating a task." ,
32+ loading : false ,
33+ } ;
34+ }
35+
36+ if ( catalogState . connectionState === "disconnected" && ! catalogState . hasLoadedShellSnapshot ) {
37+ return {
38+ title : "Environment unavailable" ,
39+ detail :
40+ catalogState . connectionError ??
41+ "The saved environment is offline. Check the URL or start the environment, then retry." ,
42+ loading : false ,
43+ } ;
44+ }
45+
46+ if (
47+ catalogState . hasConnectingEnvironment &&
48+ ! catalogState . hasLoadedShellSnapshot &&
49+ catalogState . connectionError === null
50+ ) {
51+ return {
52+ title : "Connecting to environment" ,
53+ detail : "Loading projects from the saved environment." ,
54+ loading : true ,
55+ } ;
56+ }
57+
58+ return {
59+ title : "No projects found" ,
60+ detail : "The connected environment did not report any projects." ,
61+ loading : false ,
62+ } ;
63+ }
64+
1565export default function NewTaskRoute ( ) {
16- const { projects, threads } = useRemoteCatalog ( ) ;
66+ const { projects, state : catalogState , threads } = useRemoteCatalog ( ) ;
1767 const { savedConnectionsById } = useRemoteEnvironmentState ( ) ;
68+ const router = useRouter ( ) ;
1869 const insets = useSafeAreaInsets ( ) ;
1970 const chevronColor = useThemeColor ( "--color-chevron" ) ;
71+ const accentColor = useThemeColor ( "--color-icon-muted" ) ;
2072 const borderSubtleColor = useThemeColor ( "--color-border-subtle" ) ;
2173 const repositoryGroups = useMemo (
2274 ( ) => groupProjectsByRepository ( { projects, threads } ) ,
@@ -45,6 +97,7 @@ export default function NewTaskRoute() {
4597 }
4698 return nextItems ;
4799 } , [ repositoryGroups ] ) ;
100+ const projectEmptyState = deriveProjectEmptyState ( catalogState ) ;
48101
49102 return (
50103 < View collapsable = { false } className = "flex-1 bg-sheet" >
@@ -65,17 +118,31 @@ export default function NewTaskRoute() {
65118 < ScrollView
66119 showsVerticalScrollIndicator = { false }
67120 style = { { flex : 1 } }
121+ contentInset = { { bottom : Math . max ( insets . bottom , 18 ) + 18 } }
68122 contentContainerStyle = { {
69123 paddingHorizontal : 20 ,
70124 paddingTop : 8 ,
71- paddingBottom : Math . max ( insets . bottom , 18 ) + 18 ,
72125 } }
73126 >
74127 { items . length === 0 ? (
75- < View collapsable = { false } className = "items-center rounded-[24px] bg-card px-6 py-8" >
76- < Text className = "text-[16px] font-medium text-foreground-muted" >
77- Loading projects...
128+ < View collapsable = { false } className = "items-center gap-3 rounded-[24px] bg-card px-6 py-8" >
129+ { projectEmptyState . loading ? < ActivityIndicator color = { accentColor } /> : null }
130+ < Text className = "text-center text-[17px] font-t3-bold text-foreground" >
131+ { projectEmptyState . title }
132+ </ Text >
133+ < Text className = "text-center text-[14px] leading-[20px] text-foreground-muted" >
134+ { projectEmptyState . detail }
78135 </ Text >
136+ { ! catalogState . hasReadyEnvironment ? (
137+ < Pressable
138+ className = "mt-1 rounded-full bg-primary px-4 py-2.5 active:opacity-70"
139+ onPress = { ( ) => router . push ( "/connections/new" ) }
140+ >
141+ < Text className = "text-[13px] font-t3-bold text-primary-foreground" >
142+ Add environment
143+ </ Text >
144+ </ Pressable >
145+ ) : null }
79146 </ View >
80147 ) : (
81148 < View collapsable = { false } className = "overflow-hidden rounded-[24px] bg-card" >
0 commit comments