Skip to content
Merged
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
10 changes: 5 additions & 5 deletions apps/mobile/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,23 @@
},
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.bokeeeey.codeitresources"
"bundleIdentifier": "com.bokeeeey.codeitresources",
"newArchEnabled": true
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"package": "com.bokeeeey.codeitresources"
"package": "com.bokeeeey.codeitresources",
"newArchEnabled": true
},
"web": {
"bundler": "metro",
"output": "static",
"favicon": "./assets/images/favicon.png"
},
"plugins": [
"expo-router"
],
"plugins": ["expo-router", "expo-font"],
"experiments": {
"typedRoutes": true
}
Expand Down
16 changes: 16 additions & 0 deletions apps/mobile/app/(route)/dashboard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import WebView, { WebViewMessageEvent } from "react-native-webview";

import { ROUTES } from "@/constants/routes";
import { useHandleNavigationActions } from "@/hooks/useHandleNavigationActions";
import { getBaseUrl } from "@/utils/getBaseUrl";

export default function DashboardScreen() {
const baseUrl = getBaseUrl();
const handleNavigationActions = useHandleNavigationActions();

const requestOnMessage = (e: WebViewMessageEvent) => {
handleNavigationActions(e);
};

return <WebView className="flex-1" source={{ uri: `${baseUrl}${ROUTES.DASHBOARD}` }} onMessage={requestOnMessage} />;
}
17 changes: 17 additions & 0 deletions apps/mobile/app/(route)/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { WebView, WebViewMessageEvent } from "react-native-webview";

import { useHandleNavigationActions } from "@/hooks/useHandleNavigationActions";
import { getBaseUrl } from "@/utils/getBaseUrl";

export default function HomeScreen() {
// TODO : login상태에 따른 분기 처리 설정

const baseUrl = getBaseUrl();
const handleNavigationActions = useHandleNavigationActions();

const requestOnMessage = (e: WebViewMessageEvent) => {
handleNavigationActions(e);
};

return <WebView className="flex-1" source={{ uri: `${baseUrl}` }} onMessage={requestOnMessage} />;
}
16 changes: 16 additions & 0 deletions apps/mobile/app/(route)/meetings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import WebView, { WebViewMessageEvent } from "react-native-webview";

import { ROUTES } from "@/constants/routes";
import { useHandleNavigationActions } from "@/hooks/useHandleNavigationActions";
import { getBaseUrl } from "@/utils/getBaseUrl";

export default function MeetingsScreen() {
const baseUrl = getBaseUrl();
const handleNavigationActions = useHandleNavigationActions();

const requestOnMessage = (e: WebViewMessageEvent) => {
handleNavigationActions(e);
};

return <WebView className="flex-1" source={{ uri: `${baseUrl}${ROUTES.MEETINGS}` }} onMessage={requestOnMessage} />;
}
Comment on lines +1 to +16
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

WebView 로직 재사용성 개선 필요

여러 라우트 파일에서 동일한 WebView 로직이 반복되고 있습니다. 이는 유지보수성을 저하시키고 코드 중복을 야기합니다.

공통 WebView 래퍼 컴포넌트를 생성하여 코드 중복을 제거하는 것을 추천드립니다:

// components/common/AppWebView.tsx
interface AppWebViewProps {
  route: string;
  onMessage?: (event: WebViewMessageEvent) => void;
}

export function AppWebView({ route, onMessage }: AppWebViewProps) {
  const baseUrl = getBaseUrl();
  const [isLoading, setIsLoading] = useState(true);

  return (
    <>
      <WebView
        className="flex-1"
        source={{ uri: `${baseUrl}${route}` }}
        onMessage={onMessage}
        onLoadStart={() => setIsLoading(true)}
        onLoadEnd={() => setIsLoading(false)}
        onError={(syntheticEvent) => {
          const { nativeEvent } = syntheticEvent;
          console.warn('WebView error: ', nativeEvent);
        }}
      />
      {isLoading && <LoadingSpinner />}
    </>
  );
}

이후 각 스크린에서 다음과 같이 사용할 수 있습니다:

export default function MeetingsScreen() {
  const handleNavigationActions = useHandleNavigationActions();
  return <AppWebView route={ROUTES.MEETINGS} onMessage={handleNavigationActions} />;
}

16 changes: 16 additions & 0 deletions apps/mobile/app/(route)/seats.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import WebView, { WebViewMessageEvent } from "react-native-webview";

import { ROUTES } from "@/constants/routes";
import { useHandleNavigationActions } from "@/hooks/useHandleNavigationActions";
import { getBaseUrl } from "@/utils/getBaseUrl";

export default function SeatsScreen() {
const baseUrl = getBaseUrl();
const handleNavigationActions = useHandleNavigationActions();

const requestOnMessage = (e: WebViewMessageEvent) => {
handleNavigationActions(e);
};

return <WebView className="flex-1" source={{ uri: `${baseUrl}${ROUTES.SEATS}` }} onMessage={requestOnMessage} />;
}
Comment on lines +1 to +16
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

WebView 로직을 재사용 가능한 커스텀 훅으로 분리해주세요.

HomeScreenSeatsScreen에서 중복되는 WebView 로직을 다음과 같이 분리하면 좋을 것 같습니다:

새로운 커스텀 훅을 생성해주세요 (useWebViewScreen.ts):

interface UseWebViewScreenProps {
  path?: string;
}

export const useWebViewScreen = ({ path = '' }: UseWebViewScreenProps) => {
  const baseUrl = getBaseUrl();
  const handleNavigationActions = useHandleNavigationActions();

  const requestOnMessage = (e: WebViewMessageEvent) => {
    handleNavigationActions(e);
  };

  return {
    uri: `${baseUrl}${path}`,
    onMessage: requestOnMessage,
  };
};

그리고 각 스크린에서 다음과 같이 사용:

export default function SeatsScreen() {
  const webViewProps = useWebViewScreen({ path: ROUTES.SEATS });

  return (
    <ErrorBoundary fallback={<ErrorScreen />}>
      <WebView
        className="flex-1"
        source={{ uri: webViewProps.uri }}
        onMessage={webViewProps.onMessage}
        onError={handleError}
        renderLoading={() => <LoadingSpinner />}
        startInLoadingState
      />
    </ErrorBoundary>
  );
}

15 changes: 15 additions & 0 deletions apps/mobile/app/(route)/settings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import WebView, { WebViewMessageEvent } from "react-native-webview";

import { ROUTES } from "@/constants/routes";
import { useHandleNavigationActions } from "@/hooks/useHandleNavigationActions";
import { getBaseUrl } from "@/utils/getBaseUrl";

export default function SettingsScreen() {
const baseUrl = getBaseUrl();
const handleNavigationActions = useHandleNavigationActions();

const requestOnMessage = (e: WebViewMessageEvent) => {
handleNavigationActions(e);
};
return <WebView className="flex-1" source={{ uri: `${baseUrl}${ROUTES.SETTINGS}` }} onMessage={requestOnMessage} />;
}
Comment on lines +7 to +15
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

WebView 구현에 대한 개선 제안

WebView 컴포넌트에 다음과 같은 필수적인 기능들이 누락되어 있습니다:

  1. 로딩 상태 처리
  2. 에러 처리
  3. 네트워크 연결 상태 확인

다음과 같이 개선하는 것을 추천드립니다:

 export default function SettingsScreen() {
   const baseUrl = getBaseUrl();
   const handleNavigationActions = useHandleNavigationActions();
+  const [isLoading, setIsLoading] = useState(true);
 
   const requestOnMessage = (e: WebViewMessageEvent) => {
     handleNavigationActions(e);
   };
 
-  return <WebView className="flex-1" source={{ uri: `${baseUrl}${ROUTES.SETTINGS}` }} onMessage={requestOnMessage} />;
+  return (
+    <>
+      <WebView
+        className="flex-1"
+        source={{ uri: `${baseUrl}${ROUTES.SETTINGS}` }}
+        onMessage={requestOnMessage}
+        onLoadStart={() => setIsLoading(true)}
+        onLoadEnd={() => setIsLoading(false)}
+        onError={(syntheticEvent) => {
+          const { nativeEvent } = syntheticEvent;
+          console.warn('WebView error: ', nativeEvent);
+        }}
+      />
+      {isLoading && <LoadingSpinner />}
+    </>
+  );

Committable suggestion skipped: line range outside the PR's diff.

45 changes: 0 additions & 45 deletions apps/mobile/app/(tabs)/_layout.tsx

This file was deleted.

99 changes: 0 additions & 99 deletions apps/mobile/app/(tabs)/explore.tsx

This file was deleted.

62 changes: 0 additions & 62 deletions apps/mobile/app/(tabs)/index.tsx

This file was deleted.

14 changes: 0 additions & 14 deletions apps/mobile/app/(tabs)/test.tsx

This file was deleted.

24 changes: 13 additions & 11 deletions apps/mobile/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,38 @@ import { useFonts } from "expo-font";
import { Stack } from "expo-router";
import * as SplashScreen from "expo-splash-screen";
import { useEffect } from "react";
import "react-native-reanimated";

import { DIR_NAME, ROUTES } from "@/constants/routes";
import { useColorScheme } from "@/hooks/useColorScheme";

import "react-native-reanimated";
import "@repo/ui/styles/globals.css";

// Prevent the splash screen from auto-hiding before asset loading is complete.
// TODO : splash 적용할건지?
SplashScreen.preventAutoHideAsync();

export default function RootLayout() {
const colorScheme = useColorScheme();

const [loaded] = useFonts({
SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
});

useEffect(() => {
if (loaded) {
SplashScreen.hideAsync();
}
if (loaded) SplashScreen.hideAsync();
}, [loaded]);

if (!loaded) {
return null;
}
if (!loaded) return null;

return (
<ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
<Stack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen name="+not-found" />
<Stack screenOptions={{ headerShown: false, animation: "default" }}>
<Stack.Screen name={`${DIR_NAME}${ROUTES.HOME}`} />
<Stack.Screen name={`${DIR_NAME}${ROUTES.DASHBOARD}`} />
<Stack.Screen name={`${DIR_NAME}${ROUTES.MEETINGS}`} />
<Stack.Screen name={`${DIR_NAME}${ROUTES.SEATS}`} />
<Stack.Screen name={`${DIR_NAME}${ROUTES.SETTINGS}`} />
<Stack.Screen name={ROUTES.NOT_FOUND} />
Comment on lines +31 to +37
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

라우트 상수의 타입 안전성 강화 필요

DIR_NAMEROUTES 상수를 사용한 스크린 구성에서 타입 안전성을 개선해야 합니다.

다음과 같이 개선하는 것을 제안합니다:

+type RouteNames = keyof typeof ROUTES;
+
 <Stack screenOptions={{ headerShown: false, animation: "default" }}>
-  <Stack.Screen name={`${DIR_NAME}${ROUTES.HOME}`} />
-  <Stack.Screen name={`${DIR_NAME}${ROUTES.DASHBOARD}`} />
-  <Stack.Screen name={`${DIR_NAME}${ROUTES.MEETINGS}`} />
-  <Stack.Screen name={`${DIR_NAME}${ROUTES.SEATS}`} />
-  <Stack.Screen name={`${DIR_NAME}${ROUTES.SETTINGS}`} />
-  <Stack.Screen name={ROUTES.NOT_FOUND} />
+  {(Object.keys(ROUTES) as RouteNames[]).map((route) => (
+    <Stack.Screen
+      key={route}
+      name={route === 'NOT_FOUND' ? ROUTES[route] : `${DIR_NAME}${ROUTES[route]}`}
+    />
+  ))}
 </Stack>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Stack screenOptions={{ headerShown: false, animation: "default" }}>
<Stack.Screen name={`${DIR_NAME}${ROUTES.HOME}`} />
<Stack.Screen name={`${DIR_NAME}${ROUTES.DASHBOARD}`} />
<Stack.Screen name={`${DIR_NAME}${ROUTES.MEETINGS}`} />
<Stack.Screen name={`${DIR_NAME}${ROUTES.SEATS}`} />
<Stack.Screen name={`${DIR_NAME}${ROUTES.SETTINGS}`} />
<Stack.Screen name={ROUTES.NOT_FOUND} />
type RouteNames = keyof typeof ROUTES;
<Stack screenOptions={{ headerShown: false, animation: "default" }}>
{(Object.keys(ROUTES) as RouteNames[]).map((route) => (
<Stack.Screen
key={route}
name={route === 'NOT_FOUND' ? ROUTES[route] : `${DIR_NAME}${ROUTES[route]}`}
/>
))}
</Stack>

</Stack>
</ThemeProvider>
);
Expand Down
Loading
Loading