-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
#705 @taxi/app
init
#704
#705 @taxi/app
init
#704
Changes from all commits
ab623cd
a230234
0c45634
44b0157
d2eb95f
17b39bb
d548130
b315981
adedbd9
3d2129d
2ff481a
036ac16
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node-linker=hoisted |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files | ||
|
||
# dependencies | ||
node_modules/ | ||
|
||
# Expo | ||
.expo/ | ||
dist/ | ||
web-build/ | ||
|
||
# Native | ||
*.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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import type { ConfigContext, ExpoConfig } from "@expo/config"; | ||
import ip from "internal-ip"; | ||
|
||
const isDev = process.env.NODE_ENV === "development"; | ||
|
||
export default ({ config }: ConfigContext): Partial<ExpoConfig> => ({ | ||
...config, | ||
name: "Taxi for KAIST", | ||
slug: "Taxi-for-KAIST", | ||
version: "1.0.0", | ||
orientation: "portrait", | ||
icon: "./assets/icon.png", | ||
userInterfaceStyle: "light", | ||
splash: { | ||
image: "./assets/splash.png", | ||
resizeMode: "contain", | ||
backgroundColor: "#ffffff", | ||
}, | ||
assetBundlePatterns: ["**/*"], | ||
ios: { | ||
supportsTablet: true, | ||
}, | ||
android: { | ||
adaptiveIcon: { | ||
foregroundImage: "./assets/adaptive-icon.png", | ||
backgroundColor: "#ffffff", | ||
}, | ||
}, | ||
web: { | ||
favicon: "./assets/favicon.png", | ||
}, | ||
experiments: { | ||
tsconfigPaths: true, | ||
}, | ||
extra: { | ||
SERVER_URL: isDev | ||
? `http://${ip.v4.sync()}:3000` | ||
: "https://taxi.sparcs.org", | ||
Comment on lines
+36
to
+38
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 개발 환경에서는 로컬 네트워크의 택시 웹이 뜨도록 하였습니다. |
||
}, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module.exports = function(api) { | ||
api.cache(true); | ||
return { | ||
presets: ['babel-preset-expo'], | ||
}; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// Learn more https://docs.expo.dev/guides/monorepos | ||
const { getDefaultConfig } = require('expo/metro-config'); | ||
const { FileStore } = require('metro-cache'); | ||
const path = require('path'); | ||
|
||
const projectRoot = __dirname; | ||
const workspaceRoot = path.resolve(projectRoot, '../..'); | ||
|
||
const config = getDefaultConfig(projectRoot); | ||
|
||
// #1 - Watch all files in the monorepo | ||
config.watchFolders = [workspaceRoot]; | ||
// #3 - Force resolving nested modules to the folders below | ||
config.resolver.disableHierarchicalLookup = true; | ||
// #2 - Try resolving with project modules first, then workspace modules | ||
config.resolver.nodeModulesPaths = [ | ||
path.resolve(projectRoot, 'node_modules'), | ||
path.resolve(workspaceRoot, 'node_modules'), | ||
]; | ||
|
||
// Use turborepo to restore the cache when possible | ||
config.cacheStores = [ | ||
new FileStore({ root: path.join(projectRoot, 'node_modules', '.cache', 'metro') }), | ||
]; | ||
|
||
module.exports = config; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/// <reference types="@types/node" /> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"name": "@taxi/app", | ||
"version": "1.0.0", | ||
"main": "src/main.js", | ||
"scripts": { | ||
"start": "expo start", | ||
"android": "expo start --android", | ||
"ios": "expo start --ios", | ||
"web": "expo start --web" | ||
}, | ||
"dependencies": { | ||
"@react-navigation/bottom-tabs": "^6.5.11", | ||
"@react-navigation/native": "^6.1.9", | ||
"@react-navigation/stack": "^6.3.20", | ||
"expo": "~49.0.15", | ||
"expo-status-bar": "~1.6.0", | ||
"react": "18.2.0", | ||
"react-native": "0.72.6", | ||
"react-native-webview": "^13.6.4", | ||
"shallow-equal": "^3.1.0", | ||
"url-pattern": "^1.0.3", | ||
"uuid": "3.4.0" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "^7.20.0", | ||
"@types/node": "^20.11.5", | ||
"@types/react": "~18.2.14", | ||
"internal-ip": "^6.2.0", | ||
"typescript": "^5.1.3" | ||
}, | ||
"private": true | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { RootStack } from "@/screens"; | ||
import { NavigationContainer } from "@react-navigation/native"; | ||
import { StatusBar } from "expo-status-bar"; | ||
import { View } from "react-native"; | ||
|
||
export function App() { | ||
return ( | ||
<View style={{ flex: 1 }}> | ||
<NavigationContainer> | ||
<RootStack /> | ||
</NavigationContainer> | ||
<StatusBar style="auto" /> | ||
</View> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { env } from "@/env"; | ||
import { mapWebRoutes } from "@/navigation/web"; | ||
import { isSameScreen } from "@/utils/navigation"; | ||
import { useIsFocused, useNavigation } from "@react-navigation/native"; | ||
import React, { useCallback, useMemo, useRef } from "react"; | ||
import { Platform } from "react-native"; | ||
import { WebView, type WebViewNavigation } from "react-native-webview"; | ||
|
||
type TaxiWebViewProps = { | ||
path: string; | ||
}; | ||
|
||
export const TaxiWebView: React.FC<TaxiWebViewProps> = ({ path }) => { | ||
const uri = useMemo( | ||
() => (path.startsWith("/") ? env.SERVER_URL + path : path), | ||
[path] | ||
); | ||
const ref = useRef<WebView>(null); | ||
const currentScreen = useMemo(() => mapWebRoutes(uri), [uri]); | ||
const isFocused = useIsFocused(); | ||
const navigation = useNavigation(); | ||
|
||
const onNavigationStateChange = useCallback( | ||
(event: WebViewNavigation) => { | ||
const screen = mapWebRoutes(event.url); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. uri가 바뀔 때 그 uri가 매칭되는 스크린을 받아옵니다. |
||
if (!isFocused || isSameScreen(currentScreen, screen)) return; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 매칭된 스크린이 현재 스크린과 동일한 경우, 새로운 route navigation을 진행하지 않습니다. |
||
|
||
navigation.navigate(...screen); | ||
ref.current?.stopLoading(); | ||
ref.current?.goBack(); | ||
Comment on lines
+28
to
+30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 다른 스크린으로 이동하는 경우, 현재 |
||
}, | ||
[isFocused, currentScreen, navigation] | ||
); | ||
Comment on lines
+23
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
나중에 앱과 웹의 코드베이스가 공유되는 경우에는 다른 접근을 취하는게 좋을 것 같습니다. |
||
|
||
return ( | ||
<WebView | ||
cacheEnabled | ||
ref={ref} | ||
userAgent={`taxi-app-webview/${Platform.OS}`} | ||
source={{ uri }} | ||
onNavigationStateChange={onNavigationStateChange} | ||
/> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import Constants from "expo-constants"; | ||
|
||
export const env = { | ||
SERVER_URL: "https://taxi.sparcs.org", | ||
...Constants.expoConfig?.extra, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { registerRootComponent } from "expo"; | ||
import { App }from "./App"; | ||
|
||
registerRootComponent(App); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/** | ||
* Native tab navigation is disabled temporarily. (handled inside webview) | ||
* Uncomment the commented code to enable native tab navigation. | ||
*/ | ||
// import type { BottomTabScreenProps } from "@react-navigation/bottom-tabs"; | ||
// import type { | ||
// CompositeScreenProps, | ||
// NavigatorScreenParams, | ||
// } from "@react-navigation/native"; | ||
import type { StackScreenProps } from "@react-navigation/stack"; | ||
|
||
// export type HomeTabParamList = { | ||
// Home: undefined; | ||
// Search: undefined; | ||
// AddRoom: undefined; | ||
// MyRoom: undefined; | ||
// MyPage: undefined; | ||
// }; | ||
|
||
export type RootStackParamList = { | ||
// HomeTab: NavigatorScreenParams<HomeTabParamList>; | ||
Home: undefined; | ||
Event: { eventName: string }; | ||
Chatting: { roomId: string }; | ||
Web: { uri: string }; | ||
}; | ||
|
||
export type RootStackScreenProps<T extends keyof RootStackParamList> = | ||
StackScreenProps<RootStackParamList, T>; | ||
|
||
// export type HomeTabScreenProps<T extends keyof HomeTabParamList> = | ||
// CompositeScreenProps< | ||
// BottomTabScreenProps<HomeTabParamList, T>, | ||
// RootStackScreenProps<keyof RootStackParamList> | ||
// >; | ||
|
||
declare global { | ||
namespace ReactNavigation { | ||
interface RootParamList extends RootStackParamList {} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { route, routes, screen } from "@/utils/navigation"; | ||
|
||
export const mapWebRoutes = routes([ | ||
route("/", () => screen("Home")), | ||
route("/home(/:roomId)", () => screen("Home")), | ||
route("/event/:eventName", ({ eventName }) => screen("Event", { eventName })), | ||
route("/search", () => screen("Home")), | ||
route("/addroom", () => screen("Home")), | ||
route("/myroom", () => screen("Home")), | ||
route("/myroom/:roomId", ({ roomId }) => screen("Chatting", { roomId })), | ||
route("/mypage", () => screen("Home")), | ||
route("/chatting/:roomId", ({ roomId }) => screen("Chatting", { roomId })), | ||
]); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { RootStackScreenProps } from "@/navigation/types"; | ||
import React from "react"; | ||
import { KeyboardAvoidingView, Platform } from "react-native"; | ||
|
||
import { TaxiWebView } from "@/components/TaxiWebView"; | ||
|
||
export const Chatting: React.FC<RootStackScreenProps<"Chatting">> = ({ | ||
route: { params }, | ||
}) => ( | ||
<KeyboardAvoidingView | ||
behavior={Platform.select({ ios: "padding", android: "height" })} | ||
style={{ flex: 1 }} | ||
// @TODO: Remove keyboard avoiding in web | ||
> | ||
<TaxiWebView path={`/chatting/${params.roomId}`} /> | ||
</KeyboardAvoidingView> | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { RootStackScreenProps } from "@/navigation/types"; | ||
import React from "react"; | ||
|
||
import { TaxiWebView } from "@/components/TaxiWebView"; | ||
|
||
export const Event: React.FC<RootStackScreenProps<"Event">> = ({ | ||
route: { params }, | ||
}) => <TaxiWebView path={`/event/${params.eventName}`} />; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { RootStackScreenProps } from "@/navigation/types"; | ||
import React from "react"; | ||
|
||
import { TaxiWebView } from "@/components/TaxiWebView"; | ||
|
||
export const Home: React.FC<RootStackScreenProps<"Home">> = () => ( | ||
<TaxiWebView path="/home" /> | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { HomeTabScreenProps } from "@/navigation/types"; | ||
import React from "react"; | ||
|
||
import { TaxiWebView } from "@/components/TaxiWebView"; | ||
|
||
export const AddRoom: React.FC<HomeTabScreenProps<"AddRoom">> = () => ( | ||
<TaxiWebView path="/addroom" /> | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { HomeTabScreenProps } from "@/navigation/types"; | ||
import React from "react"; | ||
|
||
import { TaxiWebView } from "@/components/TaxiWebView"; | ||
|
||
export const Home: React.FC<HomeTabScreenProps<"Home">> = () => ( | ||
<TaxiWebView path="/home" /> | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { HomeTabScreenProps } from "@/navigation/types"; | ||
import React from "react"; | ||
|
||
import { TaxiWebView } from "@/components/TaxiWebView"; | ||
|
||
export const MyPage: React.FC<HomeTabScreenProps<"MyPage">> = () => ( | ||
<TaxiWebView path="/mypage" /> | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { HomeTabScreenProps } from "@/navigation/types"; | ||
import React from "react"; | ||
|
||
import { TaxiWebView } from "@/components/TaxiWebView"; | ||
|
||
export const MyRoom: React.FC<HomeTabScreenProps<"MyRoom">> = () => ( | ||
<TaxiWebView path="/myroom" /> | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { HomeTabScreenProps } from "@/navigation/types"; | ||
import React from "react"; | ||
|
||
import { TaxiWebView } from "@/components/TaxiWebView"; | ||
|
||
export const Search: React.FC<HomeTabScreenProps<"Search">> = () => ( | ||
<TaxiWebView path="/search" /> | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import type { HomeTabParamList } from "@/navigation/types"; | ||
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"; | ||
import React from "react"; | ||
|
||
import { AddRoom } from "./AddRoom"; | ||
import { Home } from "./Home"; | ||
import { MyPage } from "./MyPage"; | ||
import { MyRoom } from "./MyRoom"; | ||
import { Search } from "./Search"; | ||
|
||
const Tab = createBottomTabNavigator<HomeTabParamList>(); | ||
|
||
export const HomeTab: React.FC = () => ( | ||
<Tab.Navigator screenOptions={{ headerShown: false }}> | ||
<Tab.Screen name="Home" options={{ title: "홈" }} component={Home} /> | ||
<Tab.Screen name="Search" options={{ title: "검색" }} component={Search} /> | ||
<Tab.Screen | ||
name="AddRoom" | ||
options={{ title: "개설" }} | ||
component={AddRoom} | ||
/> | ||
<Tab.Screen name="MyRoom" options={{ title: "내 방" }} component={MyRoom} /> | ||
<Tab.Screen name="MyPage" options={{ title: "마이" }} component={MyPage} /> | ||
</Tab.Navigator> | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pnpm start:app
을 할 경우 web과 app이 동시에 시작됩니다.