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
9 changes: 7 additions & 2 deletions examples/mobile-client/fishjam-chat/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@

## Prerequisites

Create a `.env` file in the `examples/mobile-client/fishjam-chat` directory (optional), or copy the `.env.example` file. The following environment variables are required:
Copy `.env.example` to `.env` in the `examples/mobile-client/fishjam-chat` directory and fill in the required value:

- `EXPO_PUBLIC_VIDEOROOM_STAGING_SANDBOX_URL` - Sandbox URL for VideoRoom staging environment
- `EXPO_PUBLIC_FISHJAM_ID` - Fishjam ID for production environment

You can find the value for this variable by creating an account on [fishjam.io](https://fishjam.io) and copying it from the sandbox dashboard.

There also exists this additional environment variable, which is used for internal testing purposes:
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

There is a trailing space at the end of the sentence "There also exists this additional environment variable, which is used for internal testing purposes: " (after the colon). This should be removed.

Suggested change
There also exists this additional environment variable, which is used for internal testing purposes:
There also exists this additional environment variable, which is used for internal testing purposes:

Copilot uses AI. Check for mistakes.

- `EXPO_PUBLIC_VIDEOROOM_STAGING_SANDBOX_URL` - Sandbox URL for VideoRoom staging environment

## Example Overview

The app has 2 tabs showing different ways to connect to Fishjam video calls:
Expand Down
65 changes: 10 additions & 55 deletions examples/mobile-client/fishjam-chat/app/(tabs)/room.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import React, { useState, useCallback } from "react";
import { router } from "expo-router";
import { useState } from "react";
import {
Dimensions,
Image,
KeyboardAvoidingView,
Keyboard,
KeyboardAvoidingView,
StyleSheet,
Text,
View,
View
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { router, useFocusEffect } from "expo-router";
import AsyncStorage from "@react-native-async-storage/async-storage";
Copy link
Collaborator

Choose a reason for hiding this comment

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

suggestion: I think we don't use this library anymore and it could be removed.

import { Button, TextInput, DismissKeyboard } from "../../components";
import { Button, DismissKeyboard, TextInput } from "../../components";
import { changeFishjamId } from "../../utils/fishjamIdStore";

const FishjamLogo = require("../../assets/images/fishjam-logo.png");
Expand All @@ -23,31 +22,12 @@ const VIDEOROOM_PROD_SANDBOX_URL =

type VideoRoomEnv = "staging" | "prod";

type VideoRoomData = {
videoRoomEnv: VideoRoomEnv;
roomName: string;
userName: string;
};

async function saveStorageData(videoRoomData: VideoRoomData) {
await AsyncStorage.setItem("videoRoomData", JSON.stringify(videoRoomData));
}

async function readStorageData(): Promise<VideoRoomData> {
const storageData = await AsyncStorage.getItem("videoRoomData");
if (storageData) {
const videoRoomData = JSON.parse(storageData) as VideoRoomData;
return videoRoomData;
}
return { videoRoomEnv: "staging", roomName: "", userName: "" };
}

export default function RoomScreen() {
const [connectionError, setConnectionError] = useState<string | null>(null);
const [roomName, setRoomName] = useState("");
const [userName, setUserName] = useState("");
const [videoRoomEnv, setVideoRoomEnv] = useState<VideoRoomEnv>("staging");

const [videoRoomEnv, setVideoRoomEnv] = useState<VideoRoomEnv>("prod");
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

There is a trailing whitespace on this line (line 32 in the new file, line 53 in the diff). While not a functional issue, this is inconsistent with the surrounding code style.

Copilot uses AI. Check for mistakes.
const handleEnvChange = (env: VideoRoomEnv) => {
setVideoRoomEnv(env);
if (env === "staging") {
Expand All @@ -57,43 +37,18 @@ export default function RoomScreen() {
}
};

useFocusEffect(
useCallback(() => {
const loadData = async () => {
const {
videoRoomEnv: storedVideoRoomEnv,
roomName: storedRoomName,
userName: storedUserName,
} = await readStorageData();

setRoomName(storedRoomName);
setUserName(storedUserName);
setVideoRoomEnv(storedVideoRoomEnv);

if (storedVideoRoomEnv === "staging") {
changeFishjamId(VIDEOROOM_STAGING_SANDBOX_URL);
} else {
changeFishjamId(VIDEOROOM_PROD_SANDBOX_URL);
}
};
loadData();
}, [])
);

const validateInputs = () => {
if (!roomName) {
throw new Error("Room name is required");
}
};

const onTapConnectButton = async () => {
const displayName = userName || "Mobile User";
try {
validateInputs();
setConnectionError(null);

const displayName = userName || "Mobile User";
await saveStorageData({ videoRoomEnv, roomName, userName: displayName });

Keyboard.dismiss();
router.push({
pathname: "/room/preview",
Expand All @@ -118,7 +73,7 @@ export default function RoomScreen() {
source={FishjamLogo}
resizeMode="contain"
/>
<View
{VIDEOROOM_STAGING_SANDBOX_URL && (<View
style={{
flexDirection: 'row',
justifyContent: 'space-around',
Expand All @@ -134,7 +89,7 @@ export default function RoomScreen() {
type={videoRoomEnv === 'prod' ? 'primary' : 'secondary'}
onPress={() => handleEnvChange('prod')}
/>
</View>
</View>)}
Comment on lines 76 to +92
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

The env switcher (staging/prod buttons) is conditionally shown only when VIDEOROOM_STAGING_SANDBOX_URL is set, but it does not also check whether VIDEOROOM_PROD_SANDBOX_URL is set. When only staging is available, pressing the "Production" button calls changeFishjamId(""), which sets the Fishjam ID to an empty string and would cause connection errors. The condition should also verify that VIDEOROOM_PROD_SANDBOX_URL is non-empty before showing both buttons, or at minimum the "Production" button should be disabled/hidden when VIDEOROOM_PROD_SANDBOX_URL is absent.

Copilot uses AI. Check for mistakes.
<TextInput
onChangeText={setRoomName}
placeholder="Room Name"
Expand Down
10 changes: 8 additions & 2 deletions examples/mobile-client/fishjam-chat/app/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Stack } from "expo-router";
import { FishjamProvider } from "@fishjam-cloud/react-native-client";
import { useState, useEffect } from "react";
import { Stack } from "expo-router";
import { useEffect, useState } from "react";

import { setFishjamIdChangeCallback } from "../utils/fishjamIdStore";

Expand All @@ -13,6 +13,12 @@ export default function RootLayout() {
setFishjamIdChangeCallback(setFishjamId);
}, []);

useEffect(() => {
if (!fishjamId) {
console.error("Fishjam ID is not set. Please set the EXPO_PUBLIC_FISHJAM_ID environment variable.");
}
}, [fishjamId]);
Comment on lines +17 to +20
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

The error message says "Please set the EXPO_PUBLIC_FISHJAM_ID environment variable" but fishjamId can also be legitimately changed to an empty string by changeFishjamId("") (e.g., via the "Production" button when no prod URL is configured). In such cases this error message is misleading. Additionally, this effect fires on every change to fishjamId, so if fishjamId goes empty after already being set, users would see a confusing console error. Consider restricting this log to mount only (using a ref to track initial mount), or making the message more general.

Suggested change
if (!fishjamId) {
console.error("Fishjam ID is not set. Please set the EXPO_PUBLIC_FISHJAM_ID environment variable.");
}
}, [fishjamId]);
if (!DEFAULT_FISHJAM_ID) {
console.error(
"Fishjam ID is not configured. Set the EXPO_PUBLIC_FISHJAM_ID environment variable or select a preset that provides a Fishjam ID.",
);
}
}, []);

Copilot uses AI. Check for mistakes.

return (
<FishjamProvider fishjamId={fishjamId}>
<Stack screenOptions={{ headerShown: false }}>
Expand Down
1 change: 0 additions & 1 deletion examples/mobile-client/fishjam-chat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
"dependencies": {
"@expo/vector-icons": "^15.0.3",
"@fishjam-cloud/react-native-client": "workspace:*",
"@react-native-async-storage/async-storage": "^2.2.0",
"@react-navigation/bottom-tabs": "^7.4.0",
"@react-navigation/elements": "^2.6.3",
"@react-navigation/native": "^7.1.8",
Expand Down
28 changes: 0 additions & 28 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5715,17 +5715,6 @@ __metadata:
languageName: node
linkType: hard

"@react-native-async-storage/async-storage@npm:^2.2.0":
version: 2.2.0
resolution: "@react-native-async-storage/async-storage@npm:2.2.0"
dependencies:
merge-options: "npm:^3.0.4"
peerDependencies:
react-native: ^0.0.0-0 || >=0.65 <1.0
checksum: 10c0/84900eba46a40225c4ac9bf5eb58885200dc1e789d873ecda46a2a213870cc7110536ed1fd7a74b873071f3603c093958fbd84c635d6f6d4f94bfbb616ffa0ef
languageName: node
linkType: hard

"@react-native/assets-registry@npm:0.81.5":
version: 0.81.5
resolution: "@react-native/assets-registry@npm:0.81.5"
Expand Down Expand Up @@ -12038,7 +12027,6 @@ __metadata:
dependencies:
"@expo/vector-icons": "npm:^15.0.3"
"@fishjam-cloud/react-native-client": "workspace:*"
"@react-native-async-storage/async-storage": "npm:^2.2.0"
"@react-navigation/bottom-tabs": "npm:^7.4.0"
"@react-navigation/elements": "npm:^2.6.3"
"@react-navigation/native": "npm:^7.1.8"
Expand Down Expand Up @@ -13175,13 +13163,6 @@ __metadata:
languageName: node
linkType: hard

"is-plain-obj@npm:^2.1.0":
version: 2.1.0
resolution: "is-plain-obj@npm:2.1.0"
checksum: 10c0/e5c9814cdaa627a9ad0a0964ded0e0491bfd9ace405c49a5d63c88b30a162f1512c069d5b80997893c4d0181eadc3fed02b4ab4b81059aba5620bfcdfdeb9c53
languageName: node
linkType: hard

"is-potential-custom-element-name@npm:^1.0.1":
version: 1.0.1
resolution: "is-potential-custom-element-name@npm:1.0.1"
Expand Down Expand Up @@ -14615,15 +14596,6 @@ __metadata:
languageName: node
linkType: hard

"merge-options@npm:^3.0.4":
version: 3.0.4
resolution: "merge-options@npm:3.0.4"
dependencies:
is-plain-obj: "npm:^2.1.0"
checksum: 10c0/02b5891ceef09b0b497b5a0154c37a71784e68ed71b14748f6fd4258ffd3fe4ecd5cb0fd6f7cae3954fd11e7686c5cb64486daffa63c2793bbe8b614b61c7055
languageName: node
linkType: hard

"merge-stream@npm:^2.0.0":
version: 2.0.0
resolution: "merge-stream@npm:2.0.0"
Expand Down
Loading