diff --git a/babel.config.js b/babel.config.js index 677016d..b80b49e 100644 --- a/babel.config.js +++ b/babel.config.js @@ -2,13 +2,29 @@ module.exports = function (api) { api.cache(true); const plugins = []; - plugins.push([ - '@tamagui/babel-plugin', - { - components: ['tamagui'], - config: './tamagui.config.ts', - }, - ]); + plugins.push( + [ + '@tamagui/babel-plugin', + { + components: ['tamagui'], + config: './tamagui.config.ts', + }, + ], + [ + 'module-resolver', + { + alias: { + '@api': './src/api/*', + '@components': './src/components/*', + '@modules': './src/modules/*', + '@screens': './src/screens/*', + '@utils': './src/utils/*', + '@types': './src/types/*', + }, + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, + ] + ); return { presets: ['babel-preset-expo'], diff --git a/src/app/(auth)/(tabs)/notification.tsx b/src/app/(auth)/(tabs)/notification.tsx index 1b7894b..62ee0a1 100644 --- a/src/app/(auth)/(tabs)/notification.tsx +++ b/src/app/(auth)/(tabs)/notification.tsx @@ -3,7 +3,7 @@ import { Text } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { Button } from 'tamagui'; -import useAuth from '../../../hooks/useAuth'; +import useAuth from '../../../modules/auth/useAuth'; import { router } from 'expo-router'; import AsyncStorage from '@react-native-async-storage/async-storage'; diff --git a/src/app/(auth)/_layout.tsx b/src/app/(auth)/_layout.tsx index 08f0165..5fff521 100644 --- a/src/app/(auth)/_layout.tsx +++ b/src/app/(auth)/_layout.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { ActivityIndicator } from 'react-native'; import { YStack } from 'tamagui'; -import useAuth from '../../hooks/useAuth'; +import useAuth from '../../modules/auth/useAuth'; export default function AppLayout() { const { isLoading, session } = useAuth(); diff --git a/src/app/(auth)/stream/[streamId]/_layout.tsx b/src/app/(auth)/stream/[streamId]/_layout.tsx index 34385a1..f458c67 100644 --- a/src/app/(auth)/stream/[streamId]/_layout.tsx +++ b/src/app/(auth)/stream/[streamId]/_layout.tsx @@ -1,7 +1,7 @@ import { Slot } from 'expo-router'; import React from 'react'; -import WebSocketProvider from '../../../../components/providers/WebSocketProvider'; +import WebSocketProvider from '../../../../modules/ws/WebSocketProvider'; const StreamLayout = () => { return ( diff --git a/src/app/(auth)/stream/[streamId]/index.tsx b/src/app/(auth)/stream/[streamId]/index.tsx index a0b77a2..f393383 100644 --- a/src/app/(auth)/stream/[streamId]/index.tsx +++ b/src/app/(auth)/stream/[streamId]/index.tsx @@ -1,20 +1,19 @@ +import useSocket from '@modules/ws/useSocket'; import { useLocalSearchParams } from 'expo-router'; import { Device } from 'mediasoup-client'; +import { RtpCapabilities } from 'mediasoup-client/lib/types'; import React, { useContext, useEffect, useState } from 'react'; -import { Platform, SafeAreaView, StatusBar, View } from 'react-native'; +import { View } from 'react-native'; import { mediaDevices, RTCView, MediaStream } from 'react-native-webrtc'; import { YStack, Button } from 'tamagui'; -import { WebSocketContext } from '../../../../context/WebSocketContext'; - const Stream = () => { const { streamId } = useLocalSearchParams(); const [flag, setFlag] = useState(false); - const { socket } = useContext(WebSocketContext); // Todo add useSocket hook for this + const { socket } = useSocket(); // Todo add useSocket hook for this - const [device, setDevice] = useState(null); const [stream, setStream] = useState(null); useEffect(() => { @@ -22,10 +21,10 @@ const Stream = () => { }, []); useEffect(() => { - if (socket) { + if (socket && !flag) { console.log('call create_stream'); - socket.emit('create_stream', { streamId }, (data) => { + socket.emit('create_stream', { streamId }, (data: any) => { console.log(data); socket.emit('connect_as_streamer'); setFlag(true); @@ -44,17 +43,22 @@ const Stream = () => { recvTransportOptions, sendTransportOptions, }) => { + console.log( + streamId, + peerId, + routerRtpCapabilities, + recvTransportOptions, + sendTransportOptions + ); // Todo use response - await loadDevice(routerRtpCapabilities); + // await loadDevice(routerRtpCapabilities); } ); } }, [socket]); - const loadDevice = async (routerRtpCapabilities) => { - const newDevice = getDevice(); - await newDevice.load({ routerRtpCapabilities }); - setDevice(newDevice); + const loadDevice = async (device: Device, routerRtpCapabilities: RtpCapabilities) => { + await device.load({ routerRtpCapabilities }); }; const startMedia = async () => { diff --git a/src/app/(auth)/stream/index.tsx b/src/app/(auth)/stream/index.tsx index 2cc1571..0e52a73 100644 --- a/src/app/(auth)/stream/index.tsx +++ b/src/app/(auth)/stream/index.tsx @@ -5,7 +5,7 @@ import { SafeAreaView } from 'react-native-safe-area-context'; import { Button, H3, XStack, YStack } from 'tamagui'; import GenreBadge from '../../../components/GenreBadge'; -import useAuth from '../../../hooks/useAuth'; +import useAuth from '../../../modules/auth/useAuth'; const StreamPage = () => { const { user } = useAuth(); @@ -86,21 +86,21 @@ const StreamPage = () => { const addSelectedGenre = (idx: number) => { if ( selectedGenre.filter((g) => g.selected === true).length >= 3 || - selectedGenre[idx].selected + selectedGenre[idx]?.selected ) { return; } const updatedGenres = [...selectedGenre]; - updatedGenres[idx].selected = true; + updatedGenres[idx]!.selected = true; setSelectedGenre(updatedGenres); }; const removeSelectedGenre = (idx: number) => { - if (!selectedGenre[idx].selected) return; + if (!selectedGenre[idx]?.selected) return; const updatedGenres = [...selectedGenre]; - updatedGenres[idx].selected = false; + updatedGenres[idx]!.selected = false; setSelectedGenre(updatedGenres); }; @@ -158,7 +158,7 @@ const StreamPage = () => { color={g.color} selected={g.selected} onPress={() => { - if (selectedGenre[idx].selected) { + if (selectedGenre[idx]?.selected) { removeSelectedGenre(idx); } else { addSelectedGenre(idx); diff --git a/src/app/_layout.tsx b/src/app/_layout.tsx index 7330e5f..09a7196 100644 --- a/src/app/_layout.tsx +++ b/src/app/_layout.tsx @@ -12,7 +12,7 @@ import { TamaguiProvider } from 'tamagui'; import config from '../../tamagui.config'; import { APIProvider } from '../api/APIProvider'; -import AuthProvider from '../components/providers/AuthProvider'; +import AuthProvider from '../modules/auth/AuthProvider'; export const unstable_settings = { // Ensure that reloading on `/modal` keeps a back button present. diff --git a/src/app/login.tsx b/src/app/login.tsx index 7fe9474..909305d 100644 --- a/src/app/login.tsx +++ b/src/app/login.tsx @@ -1,12 +1,11 @@ +import useAuth from '@modules/auth/useAuth'; import React from 'react'; import { SafeAreaView } from 'react-native-safe-area-context'; import Svg, { Path } from 'react-native-svg'; -import { YStack, Button, Text } from 'tamagui'; - -import useAuth from '../hooks/useAuth'; +import { YStack, Text, Button } from 'tamagui'; const LoginPage = () => { - const { isLoading, session, signIn } = useAuth(); + const { signIn } = useAuth(); return ( { - const authContext = useContext(AuthContext); - if (!authContext) { - throw new Error("useAuth must be used within an AuthProvider"); - } - return authContext; -}; - -export default useAuth; diff --git a/src/context/AuthContext.ts b/src/modules/auth/AuthContext.ts similarity index 67% rename from src/context/AuthContext.ts rename to src/modules/auth/AuthContext.ts index 309b183..bf28267 100644 --- a/src/context/AuthContext.ts +++ b/src/modules/auth/AuthContext.ts @@ -1,5 +1,5 @@ import { createContext } from 'react'; -import { AuthContextData } from '../types/auth'; +import { AuthContextData } from '../../types/auth'; export const AuthContext = createContext({} as AuthContextData); diff --git a/src/components/providers/AuthProvider.tsx b/src/modules/auth/AuthProvider.tsx similarity index 98% rename from src/components/providers/AuthProvider.tsx rename to src/modules/auth/AuthProvider.tsx index 35e5bd1..b9d4091 100644 --- a/src/components/providers/AuthProvider.tsx +++ b/src/modules/auth/AuthProvider.tsx @@ -8,13 +8,12 @@ import { useAutoDiscovery, revokeAsync, refreshAsync, - TokenResponseConfig, } from 'expo-auth-session'; import { router } from 'expo-router'; import { jwtDecode } from 'jwt-decode'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { AuthContext } from '../../context/AuthContext'; +import { AuthContext } from './AuthContext'; import { AuthContextData, KeycloakConfiguration } from '../../types/auth'; // This is needed for ios diff --git a/src/modules/auth/useAuth.ts b/src/modules/auth/useAuth.ts new file mode 100644 index 0000000..d6e4bdf --- /dev/null +++ b/src/modules/auth/useAuth.ts @@ -0,0 +1,13 @@ +import { useContext } from 'react'; + +import { AuthContext } from './AuthContext'; + +const useAuth = () => { + const authContext = useContext(AuthContext); + if (!authContext) { + throw new Error('useAuth must be used within an AuthProvider'); + } + return authContext; +}; + +export default useAuth; diff --git a/src/modules/stream/.gitkeep b/src/modules/stream/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/stores/useStreamStore.ts b/src/modules/webrtc/stores/useStreamStore.ts similarity index 94% rename from src/stores/useStreamStore.ts rename to src/modules/webrtc/stores/useStreamStore.ts index 4ba92c1..ec0c059 100644 --- a/src/stores/useStreamStore.ts +++ b/src/modules/webrtc/stores/useStreamStore.ts @@ -1,6 +1,6 @@ import { Device } from 'mediasoup-client'; import { detectDevice, Transport } from 'mediasoup-client/lib/types'; -import create from 'zustand'; +import { create } from 'zustand'; import { combine } from 'zustand/middleware'; export const getDevice = async () => { @@ -16,7 +16,7 @@ export const getDevice = async () => { } }; -export const useVoiceStore = create( +export const useStreamStore = create( combine( { streamId: '', diff --git a/src/context/WebSocketContext.ts b/src/modules/ws/WebSocketContext.ts similarity index 100% rename from src/context/WebSocketContext.ts rename to src/modules/ws/WebSocketContext.ts diff --git a/src/components/providers/WebSocketProvider.tsx b/src/modules/ws/WebSocketProvider.tsx similarity index 90% rename from src/components/providers/WebSocketProvider.tsx rename to src/modules/ws/WebSocketProvider.tsx index 8cf8066..2c8f377 100644 --- a/src/components/providers/WebSocketProvider.tsx +++ b/src/modules/ws/WebSocketProvider.tsx @@ -2,8 +2,8 @@ import AsyncStorage from '@react-native-async-storage/async-storage'; import React, { useEffect, useMemo, useState } from 'react'; import { Socket, io } from 'socket.io-client'; -import { WebSocketContext } from '../../context/WebSocketContext'; -import useAuth from '../../hooks/useAuth'; +import { WebSocketContext } from './WebSocketContext'; +import useAuth from '../auth/useAuth'; const WebSocketProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const [socket, setSocket] = useState(null as any); diff --git a/src/modules/ws/useSocket.ts b/src/modules/ws/useSocket.ts new file mode 100644 index 0000000..7baf902 --- /dev/null +++ b/src/modules/ws/useSocket.ts @@ -0,0 +1,13 @@ +import { useContext } from 'react'; + +import { WebSocketContext } from './WebSocketContext'; + +const useSocket = () => { + const socketContext = useContext(WebSocketContext); + if (!socketContext) { + throw new Error('useSocket must be used within an WebSocketProvider'); + } + return socketContext; +}; + +export default useSocket; diff --git a/src/utils/formatNumber.ts b/src/utils/formatNumber.ts index b49c6b5..4b1ac21 100644 --- a/src/utils/formatNumber.ts +++ b/src/utils/formatNumber.ts @@ -6,10 +6,10 @@ * @returns {string} The formatted number as a string. */ export const formatNumber = (number: number): string => { - if (isNaN(number) || number === null) return "0"; + if (isNaN(number) || number === null) return '0'; let absNumber: number = Math.abs(number); - const abbrev: string[] = ["", "k", "M", "B", "T"]; + const abbrev: string[] = ['', 'k', 'M', 'B', 'T']; let index = 0; while (absNumber >= 1000 && index < abbrev.length - 1) { @@ -17,6 +17,6 @@ export const formatNumber = (number: number): string => { index++; } - const formattedNumber: string = absNumber.toFixed(1).replace(/\.0$/, ""); - return (number < 0 ? "-" : "") + formattedNumber + abbrev[index]; + const formattedNumber: string = absNumber.toFixed(1).replace(/\.0$/, ''); + return (number < 0 ? '-' : '') + formattedNumber + abbrev[index]; }; diff --git a/tsconfig.app.json b/tsconfig.app.json index 94bf6cd..25a8279 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -14,7 +14,7 @@ "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts", - + "./src/**/*", "jest.config.ts", "metro.config.js", "tamagui.config.ts", diff --git a/tsconfig.json b/tsconfig.json index 407991e..0c23025 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,9 +20,12 @@ "skipDefaultLibCheck": true, "baseUrl": ".", "paths": { - "~/*": [ - "./src/*" - ] + "@api/*": ["./src/api/*"], + "@components/*": ["./src/components/*"], + "@modules/*": ["./src/modules/*"], + "@screens/*": ["./src/screens/*"], + "@utils/*": ["./src/utils/*"], + "@types/*": ["./src/types/*"], }, "strict": true, "strictNullChecks": true, @@ -43,7 +46,8 @@ "files": [], "include": [ ".expo/types/**/*.ts", - "expo-env.d.ts" + "expo-env.d.ts", + "./src/**/*" ], "exclude": [ "node_modules", diff --git a/tsconfig.spec.json b/tsconfig.spec.json index 383e9ac..eea6c50 100644 --- a/tsconfig.spec.json +++ b/tsconfig.spec.json @@ -15,7 +15,8 @@ "src/**/*.spec.js", "src/**/*.test.jsx", "src/**/*.spec.jsx", - "src/**/*.d.ts" + "src/**/*.d.ts", + "./src/**/*" ] } \ No newline at end of file