1- import { ApolloProvider , gql , useQuery } from "@apollo/client" ;
1+ import { gql } from "@apollo/client" ;
2+ import { ApolloProvider , useQuery } from "@apollo/client/react" ;
23import { Picker } from "@react-native-picker/picker" ;
3- import { useState } from "react" ;
4+ import { useState , useEffect } from "react" ;
45import { ActivityIndicator , StyleSheet , Text , View } from "react-native" ;
5-
66import { apolloClient } from "./apollo" ;
77
8- // Imperial I-class Star Destroyer
9- const defaultStarshipId = "c3RhcnNoaXBzOjM= " ;
8+ // Imperial I-class Star Destroyer (numeric ID string, not Relay)
9+ const defaultStarshipId = "3 " ;
1010
11- const LIST_STARSHIPTS = gql `
11+ // List all starships (your wrapper returns results array)
12+ const LIST_STARSHIPS = gql `
1213 query listStarships {
1314 allStarships {
14- starships {
15- id
16- name
15+ edges {
16+ node {
17+ id
18+ name
19+ }
1720 }
1821 }
1922 }
2023` ;
2124
25+ // Fetch single starship by numeric id (snake_case + films = [String])
2226const GET_STARSHIP = gql `
2327 query getStarship($id: ID!) {
24- starship (id: $id) {
28+ starshipById (id: $id) {
2529 id
2630 name
2731 model
28- starshipClass
29- manufacturers
30- length
32+ starship_class
3133 crew
32- costInCredits
34+ length
35+ cost_in_credits
3336 consumables
34- filmConnection {
35- films {
36- id
37- title
38- }
37+ manufacturers
38+ film_names {
39+ title
40+ episode_id
41+ release_date
3942 }
4043 }
4144 }
4245` ;
4346
47+
4448function RootComponent ( ) {
4549 const [ starshipId , setStarshipId ] = useState ( defaultStarshipId ) ;
4650 const { data, error, loading } = useQuery ( GET_STARSHIP , {
@@ -51,6 +55,8 @@ function RootComponent() {
5155 console . log ( "Error fetching starship" , error ) ;
5256 }
5357
58+ const starship = data ?. starshipById ;
59+
5460 return (
5561 < View style = { styles . container } >
5662 < View style = { styles . section } >
@@ -59,24 +65,33 @@ function RootComponent() {
5965 onStarshipChange = { setStarshipId }
6066 />
6167 </ View >
62- { loading ? (
63- < ActivityIndicator color = "#333" />
64- ) : (
65- < StarshipDetails starship = { data . starship } />
66- ) }
68+ < View style = { styles . detailsContainer } >
69+ { loading ? (
70+ < ActivityIndicator color = "#333" />
71+ ) : starship ? (
72+ < StarshipDetails starship = { starship } />
73+ ) : (
74+ < Text style = { { color : "red" } } > No starship found</ Text >
75+ ) }
76+ </ View >
6777 </ View >
6878 ) ;
6979}
7080
7181function StarshipPicker ( props ) {
72- const { data, error, loading } = useQuery ( LIST_STARSHIPTS ) ;
82+ const { data, error, loading } = useQuery ( LIST_STARSHIPS ) ;
7383
7484 if ( error ) {
7585 console . log ( "Error listing starships" , error ) ;
86+ return < Text style = { { color : "red" } } > Failed to load starships</ Text > ;
7687 }
77- if ( loading ) return null ;
7888
79- const { starships } = data . allStarships ;
89+ if ( loading ) {
90+ return null ;
91+ }
92+
93+ // Flatten edges → nodes
94+ const starships = data . allStarships . edges . map ( edge => edge . node ) ;
8095
8196 return (
8297 < Picker
@@ -94,7 +109,11 @@ function StarshipPicker(props) {
94109 ) ;
95110}
96111
112+
97113function StarshipDetails ( { starship } ) {
114+ const [ films , setFilms ] = useState ( [ ] ) ;
115+ const [ loadingFilms , setLoadingFilms ] = useState ( false ) ;
116+
98117 return (
99118 < >
100119 < View style = { styles . section } >
@@ -104,29 +123,48 @@ function StarshipDetails({ starship }) {
104123
105124 < View style = { styles . section } >
106125 < Text style = { styles . label } > Operational abilities</ Text >
107- < Text > - { starship . crew } crew members</ Text >
108- < Text > - { starship . consumables } without restocking</ Text >
126+ < Text > - { starship . crew ?? "N/A" } crew members</ Text >
127+ < Text > - { starship . consumables ?? "N/A" } without restocking</ Text >
109128 </ View >
110129
111- < View >
130+ < View style = { styles . section } >
112131 < Text style = { styles . label } > Ship attributes</ Text >
113- < Text > - { starship . length } m long</ Text >
114- < Text > - { starship . costInCredits } credits</ Text >
132+ < Text > - { starship . length ?? "N/A" } m long</ Text >
133+ < Text > - { starship . cost_in_credits ?? "N/A" } credits</ Text >
115134 </ View >
116135
117- < View style = { styles . section } >
118- < Text style = { styles . label } > Manufacturers</ Text >
119- { starship . manufacturers . map ( ( manufacturer ) => (
120- < Text key = { manufacturer } > - { manufacturer } </ Text >
121- ) ) }
122- </ View >
136+ { starship . manufacturers ?. length > 0 && (
137+ < View style = { styles . section } >
138+ < Text style = { styles . label } > Manufacturers</ Text >
139+ { starship . manufacturers . map ( ( m , idx ) => (
140+ < Text key = { idx } > - { m } </ Text >
141+ ) ) }
142+ </ View >
143+ ) }
123144
124- < View style = { styles . section } >
125- < Text style = { styles . label } > Appeared in</ Text >
126- { starship . filmConnection . films . map ( ( film ) => (
127- < Text key = { film . id } > - { film . title } </ Text >
128- ) ) }
129- </ View >
145+ { starship . film_names ?. length > 0 && (
146+ < View style = { styles . section } >
147+ < Text style = { styles . label } > Appeared in</ Text >
148+ { starship . film_names . map ( ( film , idx ) => (
149+ < Text key = { idx } >
150+ - { film . title } (Episode { film . episode_id } , { film . release_date } )
151+ </ Text >
152+ ) ) }
153+ </ View >
154+ ) }
155+
156+ { loadingFilms ? (
157+ < ActivityIndicator color = "#333" />
158+ ) : films . length > 0 ? (
159+ < View style = { styles . section } >
160+ < Text style = { styles . label } > Appeared in</ Text >
161+ { films . map ( ( film , idx ) => (
162+ < Text key = { idx } >
163+ - { film . title } (Episode { film . episode_id } )
164+ </ Text >
165+ ) ) }
166+ </ View >
167+ ) : null }
130168 </ >
131169 ) ;
132170}
@@ -136,11 +174,18 @@ const styles = StyleSheet.create({
136174 flex : 1 ,
137175 justifyContent : "center" ,
138176 alignItems : "center" ,
177+ } ,
178+ detailsContainer : {
179+ flexGrow : 1 ,
180+ justifyContent : "flex-start" , // keeps it pinned to the top
181+ minHeight : 200 , // avoids collapse
182+ paddingTop : 20 ,
139183 } ,
140184 container : {
141185 flex : 1 ,
142186 justifyContent : "center" ,
143187 paddingHorizontal : 50 ,
188+ paddingTop : 100 ,
144189 } ,
145190 label : {
146191 marginBottom : 2 ,
0 commit comments