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
48 changes: 48 additions & 0 deletions SPACECRAFT_PROGRESS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Spacecraft - Progression

Suivi des étapes pour refaire Spacecraft avec la nouvelle méthode.

---

## 1. Foundation

- [x] 01 - Introduction
- [x] 02 - Project setup
- [x] 03 - Scroll on mobile
- [x] 04 - Render a list of data
- [x] 05 - Named and default import / exports

## 2. Data

- [x] 01 - How to debug with React Native
- [x] 02 - Fetching data with `react-query`
- [x] 03 - Add an `Offline` component

## 3. Ecosystem

- [x] 01 - React Native Extensions in Visual Studio Code
- [x] 02 - Integrating React Native with Linters
- [x] 03 - TypeScript with the React Native Ecosystem
- [x] 04 - Design System in React Native with Storybook
- [x] 05 - Unit Testing with React Native
- [x] 06 - End-to-End Testing with Maestro

## 4. Expo Router

- [x] 01 - File-based Routing
- [x] 02 - Passing data with Dynamic Routes
- [x] 03 - Protected Routes & Auth Flow
- [x] 04 - Tab Navigation
- [x] 05 - Auth Persistence & Splash Screen

## 5. Release

- [ ] 01 - Release with EAS
- [ ] 02 - Configuration and Environment variables
- [ ] 03 - Strategies for beta testing on real device

---

## Notes

_Ajouter des notes au fur et à mesure de la progression._
44 changes: 44 additions & 0 deletions hackathon/spacecraft-expo-router/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files

# dependencies
node_modules/

# Expo
.expo/
dist/
web-build/
expo-env.d.ts

# Native
.kotlin/
*.orig.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision

# Metro
.metro-health-check*

# debug
npm-debug.*
yarn-debug.*
yarn-error.*

# macOS
.DS_Store
*.pem

# local env files
.env*.local

# typescript
*.tsbuildinfo

# generated native folders
/ios
/android

*storybook.log
storybook-static
8 changes: 8 additions & 0 deletions hackathon/spacecraft-expo-router/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"$schema": "http://json.schemastore.org/prettierrc",
"semi": true,
"singleAttributePerLine": true,
"trailingComma": "all",
"tabWidth": 2,
"singleQuote": false
}
11 changes: 11 additions & 0 deletions hackathon/spacecraft-expo-router/.rnstorybook/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import AsyncStorage from "@react-native-async-storage/async-storage";
import { view } from "./storybook.requires";

const StorybookUIRoot = view.getStorybookUI({
storage: {
getItem: AsyncStorage.getItem,
setItem: AsyncStorage.setItem,
},
});

export default StorybookUIRoot;
14 changes: 14 additions & 0 deletions hackathon/spacecraft-expo-router/.rnstorybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { StorybookConfig } from "@storybook/react-native";

const main: StorybookConfig = {
stories: ["../src/components/**/*.stories.?(ts|tsx|js|jsx)"],
addons: [
"@storybook/addon-ondevice-notes",
"@storybook/addon-ondevice-controls",
"@storybook/addon-ondevice-backgrounds",
"@storybook/addon-ondevice-actions",
],
framework: "@storybook/react-native",
};

export default main;
26 changes: 26 additions & 0 deletions hackathon/spacecraft-expo-router/.rnstorybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { withBackgrounds } from "@storybook/addon-ondevice-backgrounds";
import type { Preview } from "@storybook/react-native";

const preview: Preview = {
decorators: [withBackgrounds],

parameters: {
backgrounds: {
default: "plain",
values: [
{ name: "plain", value: "white" },
{ name: "warm", value: "hotpink" },
{ name: "cool", value: "deepskyblue" },
],
},
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
},
};

export default preview;
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/* do not change this file, it is auto generated by storybook. */
import { start, updateView, View } from "@storybook/react-native";

import "@storybook/addon-ondevice-notes/register";
import "@storybook/addon-ondevice-controls/register";
import "@storybook/addon-ondevice-backgrounds/register";
import "@storybook/addon-ondevice-actions/register";

const normalizedStories = [
{
titlePrefix: "",
directory: "./src/components",
files: "**/*.stories.?(ts|tsx|js|jsx)",
importPathMatcher:
/^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(?:ts|tsx|js|jsx)?)$/,
// @ts-ignore
req: require.context(
"../src/components",
true,
/^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(?:ts|tsx|js|jsx)?)$/,
),
},
];

declare global {
var view: View;
var STORIES: typeof normalizedStories;
}

const annotations = [
require("./preview"),
require("@storybook/react-native/preview"),
];

global.STORIES = normalizedStories;

// @ts-ignore
module?.hot?.accept?.();

if (!global.view) {
global.view = start({
annotations,
storyEntries: normalizedStories,
});
} else {
updateView(global.view, annotations, normalizedStories);
}

export const view: View = global.view;
32 changes: 32 additions & 0 deletions hackathon/spacecraft-expo-router/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { Provider as PaperProvider } from "react-native-paper";

import { NetworkProvider } from "./src/context/Network";
import { LoginScreen } from "./src/screens/LoginScreen";
import { TermsScreen } from "./src/screens/TermsScreen";
import { StarshipFeedScreen } from "./src/screens/StarshipFeedScreen";

const queryClient = new QueryClient();

function App() {
return (
<QueryClientProvider client={queryClient}>
<PaperProvider>
<NetworkProvider>
{/* <LoginScreen /> */}
{/* <TermsScreen /> */}
<StarshipFeedScreen />
</NetworkProvider>
</PaperProvider>
</QueryClientProvider>
);
}

let AppEntryPoint = App;

if (process.env.EXPO_PUBLIC_STORYBOOK_ENABLED === "true") {
AppEntryPoint = require("./.rnstorybook").default;
}

export default AppEntryPoint;
1 change: 1 addition & 0 deletions hackathon/spacecraft-expo-router/api/data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"count":37,"next":"https://swapi.py4e.com/api/starships/?page=2","previous":null,"results":[{"name":"CR90 corvette","model":"CR90 corvette","manufacturer":"Corellian Engineering Corporation","cost_in_credits":"3500000","length":"150","max_atmosphering_speed":"950","crew":"30-165","passengers":"600","cargo_capacity":"3000000","consumables":"1 year","hyperdrive_rating":"2.0","MGLT":"60","starship_class":"corvette","pilots":[],"films":["https://swapi.py4e.com/api/films/1/","https://swapi.py4e.com/api/films/3/","https://swapi.py4e.com/api/films/6/"],"created":"2014-12-10T14:20:33.369000Z","edited":"2014-12-20T21:23:49.867000Z","url":"https://swapi.py4e.com/api/starships/2/"},{"name":"Star Destroyer","model":"Imperial I-class Star Destroyer","manufacturer":"Kuat Drive Yards","cost_in_credits":"150000000","length":"1,600","max_atmosphering_speed":"975","crew":"47,060","passengers":"n/a","cargo_capacity":"36000000","consumables":"2 years","hyperdrive_rating":"2.0","MGLT":"60","starship_class":"Star Destroyer","pilots":[],"films":["https://swapi.py4e.com/api/films/1/","https://swapi.py4e.com/api/films/2/","https://swapi.py4e.com/api/films/3/"],"created":"2014-12-10T15:08:19.848000Z","edited":"2014-12-20T21:23:49.870000Z","url":"https://swapi.py4e.com/api/starships/3/"},{"name":"Sentinel-class landing craft","model":"Sentinel-class landing craft","manufacturer":"Sienar Fleet Systems, Cyngus Spaceworks","cost_in_credits":"240000","length":"38","max_atmosphering_speed":"1000","crew":"5","passengers":"75","cargo_capacity":"180000","consumables":"1 month","hyperdrive_rating":"1.0","MGLT":"70","starship_class":"landing craft","pilots":[],"films":["https://swapi.py4e.com/api/films/1/"],"created":"2014-12-10T15:48:00.586000Z","edited":"2014-12-20T21:23:49.873000Z","url":"https://swapi.py4e.com/api/starships/5/"},{"name":"Death Star","model":"DS-1 Orbital Battle Station","manufacturer":"Imperial Department of Military Research, Sienar Fleet Systems","cost_in_credits":"1000000000000","length":"120000","max_atmosphering_speed":"n/a","crew":"342,953","passengers":"843,342","cargo_capacity":"1000000000000","consumables":"3 years","hyperdrive_rating":"4.0","MGLT":"10","starship_class":"Deep Space Mobile Battlestation","pilots":[],"films":["https://swapi.py4e.com/api/films/1/"],"created":"2014-12-10T16:36:50.509000Z","edited":"2014-12-20T21:26:24.783000Z","url":"https://swapi.py4e.com/api/starships/9/"},{"name":"Millennium Falcon","model":"YT-1300 light freighter","manufacturer":"Corellian Engineering Corporation","cost_in_credits":"100000","length":"34.37","max_atmosphering_speed":"1050","crew":"4","passengers":"6","cargo_capacity":"100000","consumables":"2 months","hyperdrive_rating":"0.5","MGLT":"75","starship_class":"Light freighter","pilots":["https://swapi.py4e.com/api/people/13/","https://swapi.py4e.com/api/people/14/","https://swapi.py4e.com/api/people/25/","https://swapi.py4e.com/api/people/31/"],"films":["https://swapi.py4e.com/api/films/1/","https://swapi.py4e.com/api/films/2/","https://swapi.py4e.com/api/films/3/","https://swapi.py4e.com/api/films/7/"],"created":"2014-12-10T16:59:45.094000Z","edited":"2014-12-20T21:23:49.880000Z","url":"https://swapi.py4e.com/api/starships/10/"},{"name":"Y-wing","model":"BTL Y-wing","manufacturer":"Koensayr Manufacturing","cost_in_credits":"134999","length":"14","max_atmosphering_speed":"1000km","crew":"2","passengers":"0","cargo_capacity":"110","consumables":"1 week","hyperdrive_rating":"1.0","MGLT":"80","starship_class":"assault starfighter","pilots":[],"films":["https://swapi.py4e.com/api/films/1/","https://swapi.py4e.com/api/films/2/","https://swapi.py4e.com/api/films/3/"],"created":"2014-12-12T11:00:39.817000Z","edited":"2014-12-20T21:23:49.883000Z","url":"https://swapi.py4e.com/api/starships/11/"},{"name":"X-wing","model":"T-65 X-wing","manufacturer":"Incom Corporation","cost_in_credits":"149999","length":"12.5","max_atmosphering_speed":"1050","crew":"1","passengers":"0","cargo_capacity":"110","consumables":"1 week","hyperdrive_rating":"1.0","MGLT":"100","starship_class":"Starfighter","pilots":["https://swapi.py4e.com/api/people/1/","https://swapi.py4e.com/api/people/9/","https://swapi.py4e.com/api/people/18/","https://swapi.py4e.com/api/people/19/"],"films":["https://swapi.py4e.com/api/films/1/","https://swapi.py4e.com/api/films/2/","https://swapi.py4e.com/api/films/3/"],"created":"2014-12-12T11:19:05.340000Z","edited":"2014-12-20T21:23:49.886000Z","url":"https://swapi.py4e.com/api/starships/12/"},{"name":"TIE Advanced x1","model":"Twin Ion Engine Advanced x1","manufacturer":"Sienar Fleet Systems","cost_in_credits":"unknown","length":"9.2","max_atmosphering_speed":"1200","crew":"1","passengers":"0","cargo_capacity":"150","consumables":"5 days","hyperdrive_rating":"1.0","MGLT":"105","starship_class":"Starfighter","pilots":["https://swapi.py4e.com/api/people/4/"],"films":["https://swapi.py4e.com/api/films/1/"],"created":"2014-12-12T11:21:32.991000Z","edited":"2014-12-20T21:23:49.889000Z","url":"https://swapi.py4e.com/api/starships/13/"},{"name":"Executor","model":"Executor-class star dreadnought","manufacturer":"Kuat Drive Yards, Fondor Shipyards","cost_in_credits":"1143350000","length":"19000","max_atmosphering_speed":"n/a","crew":"279,144","passengers":"38000","cargo_capacity":"250000000","consumables":"6 years","hyperdrive_rating":"2.0","MGLT":"40","starship_class":"Star dreadnought","pilots":[],"films":["https://swapi.py4e.com/api/films/2/","https://swapi.py4e.com/api/films/3/"],"created":"2014-12-15T12:31:42.547000Z","edited":"2014-12-20T21:23:49.893000Z","url":"https://swapi.py4e.com/api/starships/15/"},{"name":"Rebel transport","model":"GR-75 medium transport","manufacturer":"Gallofree Yards, Inc.","cost_in_credits":"unknown","length":"90","max_atmosphering_speed":"650","crew":"6","passengers":"90","cargo_capacity":"19000000","consumables":"6 months","hyperdrive_rating":"4.0","MGLT":"20","starship_class":"Medium transport","pilots":[],"films":["https://swapi.py4e.com/api/films/2/","https://swapi.py4e.com/api/films/3/"],"created":"2014-12-15T12:34:52.264000Z","edited":"2014-12-20T21:23:49.895000Z","url":"https://swapi.py4e.com/api/starships/17/"}]}
38 changes: 38 additions & 0 deletions hackathon/spacecraft-expo-router/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"expo": {
"name": "spacecraft-expo-router",
"slug": "spacecraft-expo-router",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"newArchEnabled": true,
"splash": {
"image": "./assets/splash-icon.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"ios": {
"supportsTablet": true
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"edgeToEdgeEnabled": true,
"predictiveBackGestureEnabled": false
},
"web": {
"favicon": "./assets/favicon.png"
},
"scheme": "spacecraft",
"experiments": {
"typedRoutes": true
},
"plugins": [
"expo-router",
"@react-native-community/datetimepicker"
]
}
}
69 changes: 69 additions & 0 deletions hackathon/spacecraft-expo-router/app/(app)/(tabs)/_layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { useTheme } from "react-native-paper";
import { Ionicons } from "@expo/vector-icons";
import { Tabs } from "expo-router";

export default function TabLayout() {
const theme = useTheme();

return (
<Tabs
screenOptions={{
headerShown: false,
tabBarActiveTintColor: theme.colors.primary,
}}
>
<Tabs.Screen
name="starships"
options={{
title: "Starships",
tabBarIcon: ({ color }) => (
<Ionicons
name="rocket"
size={24}
color={color}
/>
),
}}
/>
<Tabs.Screen
name="pilots"
options={{
title: "Pilots",
tabBarIcon: ({ color }) => (
<Ionicons
name="people"
size={24}
color={color}
/>
),
}}
/>
<Tabs.Screen
name="planets"
options={{
title: "Planets",
tabBarIcon: ({ color }) => (
<Ionicons
name="planet"
size={24}
color={color}
/>
),
}}
/>
<Tabs.Screen
name="plus"
options={{
title: "Plus",
tabBarIcon: ({ color }) => (
<Ionicons
name="add-circle"
size={24}
color={color}
/>
),
}}
/>
</Tabs>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Stack } from "expo-router";

export default function PilotsLayout() {
return (
<Stack>
<Stack.Screen
name="index"
options={{ headerShown: false }}
/>
</Stack>
);
}
Loading