work on navigation component workflow.
This commit is contained in:
parent
6673663883
commit
eb7599bfe8
38
__mocks__/api.ts
Normal file
38
__mocks__/api.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// __mocks__/api.ts
|
||||||
|
|
||||||
|
import { language_matrix, language_matrix_entry } from "@/app/i18n/api";
|
||||||
|
|
||||||
|
// Import the actual API module to extend its functionality
|
||||||
|
const origApi = jest.requireActual('@/app/i18n/api.ts');
|
||||||
|
|
||||||
|
class LanguageServer {
|
||||||
|
constructor(...args: any[]) { }
|
||||||
|
fetchLanguages(): language_matrix {
|
||||||
|
return {
|
||||||
|
"en" : { code: "en", name: "English", targets: ['fr', 'es'] },
|
||||||
|
"fr" : { code: "fr", name: "French", targets: ["en", "es"] },
|
||||||
|
"es": { code: "es", name: "Spanish", targets: ['fr', 'en'] },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Translator {
|
||||||
|
constructor(...args : any []) {}
|
||||||
|
translate(message : string, target : string) {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CachedTranslator extends Translator{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
...origApi,
|
||||||
|
LanguageServer,
|
||||||
|
Translator,
|
||||||
|
CachedTranslator,
|
||||||
|
// Mock the specific functions you want to override
|
||||||
|
fetchData: jest.fn(() => Promise.resolve({ data: 'mocked data' })),
|
||||||
|
// Add more mock implementations as needed
|
||||||
|
};
|
@ -83,6 +83,12 @@ export class Translator {
|
|||||||
console.log(data)
|
console.log(data)
|
||||||
return data.translatedText
|
return data.translatedText
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async getDefault(defaultTarget: string | undefined = undefined) {
|
||||||
|
const settings = await Settings.getDefault();
|
||||||
|
const source = await settings.getHostLanguage();
|
||||||
|
return new Translator(source, defaultTarget, await LanguageServer.getDefault())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CachedTranslator extends Translator {
|
export class CachedTranslator extends Translator {
|
||||||
|
@ -4,6 +4,7 @@ import { Image, Text, View, StyleSheet, Button, Pressable } from "react-native";
|
|||||||
import { LanguageServer, Translator, language_matrix_entry } from "./i18n/api";
|
import { LanguageServer, Translator, language_matrix_entry } from "./i18n/api";
|
||||||
import { Conversation } from "./lib/conversation";
|
import { Conversation } from "./lib/conversation";
|
||||||
import { LanguageSelection } from "@/components/LanguageSelection";
|
import { LanguageSelection } from "@/components/LanguageSelection";
|
||||||
|
import { Link } from 'expo-router';
|
||||||
|
|
||||||
function LogoTitle() {
|
function LogoTitle() {
|
||||||
return (
|
return (
|
||||||
|
@ -67,6 +67,7 @@ const ConversationThread = ({ route } : {route?: Route<"Conversation", {conversa
|
|||||||
|
|
||||||
return cachedTranslator ? (
|
return cachedTranslator ? (
|
||||||
<View style={{ flex: 1, flexDirection: "column" }}>
|
<View style={{ flex: 1, flexDirection: "column" }}>
|
||||||
|
<Text>Conversation Thread</Text>
|
||||||
<ScrollView
|
<ScrollView
|
||||||
style={{
|
style={{
|
||||||
borderColor: "black",
|
borderColor: "black",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { CachedTranslator, Translator, language_matrix, language_matrix_entry } from "@/app/i18n/api";
|
import { CachedTranslator, LanguageServer, Translator, language_matrix, language_matrix_entry } from "@/app/i18n/api";
|
||||||
import { LIBRETRANSLATE_BASE_URL } from "@/constants/api";
|
import { LIBRETRANSLATE_BASE_URL } from "@/constants/api";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import ISpeakButton from "./ui/ISpeakButton";
|
import ISpeakButton from "./ui/ISpeakButton";
|
||||||
@ -7,17 +7,19 @@ import { ScrollView, StyleSheet, Text, View } from "react-native";
|
|||||||
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
|
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
|
||||||
import { Conversation, Speaker } from "@/app/lib/conversation";
|
import { Conversation, Speaker } from "@/app/lib/conversation";
|
||||||
import { NavigationProp, ParamListBase } from "@react-navigation/native";
|
import { NavigationProp, ParamListBase } from "@react-navigation/native";
|
||||||
|
import { Link } from "expo-router";
|
||||||
|
|
||||||
|
|
||||||
export function LanguageSelection(props: {
|
export function LanguageSelection(props: {
|
||||||
navigation?: NavigationProp<ParamListBase>
|
navigation?: NavigationProp<ParamListBase>
|
||||||
translator?: Translator
|
translator?: Translator
|
||||||
onLangSelected? : (lang : language_matrix_entry) => any
|
onLangSelected?: (lang: language_matrix_entry) => any
|
||||||
}) {
|
}) {
|
||||||
const [languages, setLanguages] = useState<language_matrix | undefined>();
|
const [languages, setLanguages] = useState<language_matrix | undefined>();
|
||||||
const [languagesLoaded, setLanguagesLoaded] = useState<boolean>(false);
|
const [languagesLoaded, setLanguagesLoaded] = useState<boolean>(false);
|
||||||
|
|
||||||
const translator = props.translator || new CachedTranslator("en")
|
const languageServer = new LanguageServer(LIBRETRANSLATE_BASE_URL);
|
||||||
|
const translator = props.translator || new CachedTranslator("en", undefined, languageServer);
|
||||||
|
|
||||||
function onLangSelected(language: language_matrix_entry) {
|
function onLangSelected(language: language_matrix_entry) {
|
||||||
props.onLangSelected && props.onLangSelected(language)
|
props.onLangSelected && props.onLangSelected(language)
|
||||||
@ -28,7 +30,7 @@ export function LanguageSelection(props: {
|
|||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
// Replace with your actual async data fetching logic
|
// Replace with your actual async data fetching logic
|
||||||
const languages = await translator.fetchLanguages();
|
const languages = await languageServer.fetchLanguages();
|
||||||
setLanguages(languages);
|
setLanguages(languages);
|
||||||
setLanguagesLoaded(true);
|
setLanguagesLoaded(true);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -41,6 +43,10 @@ export function LanguageSelection(props: {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<View>
|
||||||
|
<Link href={"/settings"}>
|
||||||
|
<Text>Settings</Text>
|
||||||
|
</Link>
|
||||||
<ScrollView >
|
<ScrollView >
|
||||||
<SafeAreaProvider >
|
<SafeAreaProvider >
|
||||||
<SafeAreaView>
|
<SafeAreaView>
|
||||||
@ -55,6 +61,7 @@ export function LanguageSelection(props: {
|
|||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
</SafeAreaProvider>
|
</SafeAreaProvider>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,16 +2,38 @@ import * as React from 'react';
|
|||||||
import { NavigationContainer } from '@react-navigation/native';
|
import { NavigationContainer } from '@react-navigation/native';
|
||||||
import SettingsComponent from '@/components/Settings';
|
import SettingsComponent from '@/components/Settings';
|
||||||
import { LanguageSelection } from '@/components/LanguageSelection';
|
import { LanguageSelection } from '@/components/LanguageSelection';
|
||||||
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
import { createNativeStackNavigator, NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||||
|
import {
|
||||||
|
useNavigation,
|
||||||
|
} from '@react-navigation/native'
|
||||||
import ConversationThread from '@/components/ConversationThread';
|
import ConversationThread from '@/components/ConversationThread';
|
||||||
|
import { language_matrix_entry, Translator } from '@/app/i18n/api';
|
||||||
|
import { useRouter } from 'expo-router';
|
||||||
|
import { Conversation } from '@/app/lib/conversation';
|
||||||
|
import { Settings } from '@/app/lib/settings';
|
||||||
|
import { RootStackParamList } from '@/navigation.types';
|
||||||
|
|
||||||
const Stack = createNativeStackNavigator();
|
const Stack = createNativeStackNavigator();
|
||||||
|
|
||||||
export default function TTNavStack() {
|
export default function TTNavStack() {
|
||||||
|
|
||||||
|
|
||||||
|
async function onLangSelected(lang: language_matrix_entry) {
|
||||||
|
const nav = useNavigation<NativeStackNavigationProp<RootStackParamList, 'ConversationThread'>>();
|
||||||
|
const settings = await Settings.getDefault();
|
||||||
|
const hostLanguage = await settings.getHostLanguage();
|
||||||
|
const conversation = new Conversation(
|
||||||
|
(await Translator.getDefault(lang.code)),
|
||||||
|
{ id: "host", language: hostLanguage },
|
||||||
|
{ "id": "guest", language: lang.code, }
|
||||||
|
)
|
||||||
|
nav.navigate("Conversation", { conversation, })
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavigationContainer>
|
<NavigationContainer>
|
||||||
<Stack.Navigator initialRouteName='LanguageSelection'>
|
<Stack.Navigator initialRouteName='LanguageSelection'>
|
||||||
<Stack.Screen name="LanguageSelection" component={LanguageSelection} />
|
<Stack.Screen name="LanguageSelection" component={({ ...props }) => <LanguageSelection {...props} onLangSelected={onLangSelected} />} />
|
||||||
<Stack.Screen name="ConversationThread" component={ConversationThread} />
|
<Stack.Screen name="ConversationThread" component={ConversationThread} />
|
||||||
<Stack.Screen name="Settings" component={SettingsComponent} />
|
<Stack.Screen name="Settings" component={SettingsComponent} />
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
|
@ -1,17 +1,11 @@
|
|||||||
import {dirname, resolve} from 'path'
|
import {dirname, resolve} from 'path'
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { fireEvent, render, screen } from '@testing-library/react-native';
|
import { act, fireEvent, render, screen } from '@testing-library/react-native';
|
||||||
import { NavigationContainer } from '@react-navigation/native';
|
|
||||||
import { createStackNavigator } from '@react-navigation/stack';
|
import { createStackNavigator } from '@react-navigation/stack';
|
||||||
import TTNavStack from '../TTNavStack';
|
|
||||||
|
|
||||||
// Mock the expo-file-system/next module
|
jest.mock("@/app/i18n/api", () => require("../../__mocks__/api.ts"));
|
||||||
jest.mock('expo-file-system/next', () => ({
|
|
||||||
File: jest.fn(),
|
import TTNavStack from '../TTNavStack';
|
||||||
Paths: {
|
|
||||||
join: jest.fn(),
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const Stack = createStackNavigator();
|
const Stack = createStackNavigator();
|
||||||
|
|
||||||
@ -23,15 +17,19 @@ describe('Navigation', () => {
|
|||||||
|
|
||||||
it('Navigates to ConversationThread on language selection', async () => {
|
it('Navigates to ConversationThread on language selection', async () => {
|
||||||
render(<TTNavStack />);
|
render(<TTNavStack />);
|
||||||
const languageSelectionText = await screen.findByText("Language Selection");
|
const languageSelectionText = await screen.findByText(/I Speak French\./i);
|
||||||
|
act(() => {
|
||||||
fireEvent.press(languageSelectionText);
|
fireEvent.press(languageSelectionText);
|
||||||
|
})
|
||||||
expect(await screen.findByText("Conversation Thread")).toBeOnTheScreen();
|
expect(await screen.findByText("Conversation Thread")).toBeOnTheScreen();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Navigates to Settings on settings selection', async () => {
|
it('Navigates to Settings on settings selection', async () => {
|
||||||
render(<TTNavStack />);
|
render(<TTNavStack />);
|
||||||
const settingsButton = await screen.findByText("Settings");
|
const settingsButton = await screen.findByText("Settings");
|
||||||
fireEvent.press(settingsButton);
|
act(() => {
|
||||||
|
fireEvent.press(settingsButton)
|
||||||
|
})
|
||||||
expect(await screen.findByText("Settings")).toBeOnTheScreen();
|
expect(await screen.findByText("Settings")).toBeOnTheScreen();
|
||||||
});
|
});
|
||||||
});
|
});
|
11
navigation.types.ts
Normal file
11
navigation.types.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// navigation.types.ts
|
||||||
|
|
||||||
|
import { ParamListBase } from '@react-navigation/native';
|
||||||
|
import { Conversation } from '@/app/lib/conversation';
|
||||||
|
|
||||||
|
export type RootStackParamList = {
|
||||||
|
LanguageSelection: undefined;
|
||||||
|
ConversationThread: undefined;
|
||||||
|
Settings: undefined;
|
||||||
|
Conversation: { conversation: Conversation };
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user