Compare commits

...

40 Commits

Author SHA1 Message Date
Benjamin S. Leveritt
c76b15a924 Rename Expo in selector
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-27 15:00:35 +00:00
Benjamin S. Leveritt
6c68128cb3 Bump to 0.13.0
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-27 15:00:15 +00:00
Guido D'Orsi
32be2a8454 chore: update lockfile 2025-03-27 14:21:27 +01:00
Guido D'Orsi
68a5928d6d chore: migrate jazz-react-native-core o declaration files 2025-03-27 14:20:08 +01:00
Guido D'Orsi
ffa44d1b9e chore: more cleanup 2025-03-27 14:15:35 +01:00
Guido D'Orsi
1e243abd5a chore: update lockfile 2025-03-27 14:12:30 +01:00
Guido D'Orsi
774b9640ca feat: re-export the testing entry on jazz-expo and jazz-react-native 2025-03-27 14:11:59 +01:00
Guido D'Orsi
72e66c884a chore: clean up changes 2025-03-27 13:14:53 +01:00
Guido D'Orsi
12cd8dddb8 Merge remote-tracking branch 'origin/main' into feat/separate-expo-rn 2025-03-27 12:35:17 +01:00
Guido D'Orsi
51c9f09056 chore: clean up deps 2025-03-27 12:32:46 +01:00
pax-k
e2f05b3b8c fix: tests 2025-03-26 15:37:08 +02:00
Brad Anderson
336c2eda6d fix: removing mystery starters 2025-03-25 17:04:53 -04:00
Brad Anderson
0cf456a154 PR feedback 2025-03-25 10:56:51 -04:00
Brad Anderson
edcbabc9b6 PR feedback 2025-03-25 10:56:51 -04:00
Brad Anderson
1a7d862cb9 chore: rebase oops 2025-03-25 10:56:51 -04:00
Brad Anderson
56074d598d chore: rebase 2025-03-25 10:56:51 -04:00
Brad Anderson
b79adbc6d1 chore: docs update 2025-03-25 10:56:51 -04:00
Brad Anderson
98f8ab249f chore: first cut at docs changes 2025-03-25 10:56:51 -04:00
Brad Anderson
abb2357be2 fix: comment out suppressions 2025-03-25 10:56:51 -04:00
Brad Anderson
11603e14d7 fix: tests work 2025-03-25 10:56:51 -04:00
Brad Anderson
2ba1f1b5d7 wip: failing unit test work 2025-03-25 10:56:50 -04:00
Brad Anderson
af5bf96df1 fix: react/dom dependency warnings 2025-03-25 10:56:50 -04:00
Brad Anderson
9a11a19aa8 fix: more cleanup of packages 2025-03-25 10:56:50 -04:00
Brad Anderson
366a3e8e2f fix: lock file regen 2025-03-25 10:56:50 -04:00
Brad Anderson
f754896f13 fix: clean up styles 2025-03-25 10:56:50 -04:00
pax-k
3fb50d9aee works 2025-03-25 10:56:50 -04:00
pax-k
af4cd3df89 fix(rn): added ios and android dirs for barebone rn chat app 2025-03-25 10:56:50 -04:00
pax-k
c19989249d fix: workspace package versions for react, react-native 2025-03-25 10:56:50 -04:00
Brad Anderson
e8a3002577 try 0.78 on all RN apps 2025-03-25 10:56:49 -04:00
Brad Anderson
29083a9cf0 cosmetic 2025-03-25 10:56:49 -04:00
Brad Anderson
0c9e112be1 chat-rn builds and runs, but blank 2025-03-25 10:56:49 -04:00
Brad Anderson
b13f8889ec more naming changes 2025-03-25 10:56:49 -04:00
Brad Anderson
de2f998115 rename RN example apps 2025-03-25 10:56:49 -04:00
Brad Anderson
ea1468a609 add chat app & deps 2025-03-25 10:55:50 -04:00
Brad Anderson
77bc548c9b app starts, lint, format 2025-03-25 10:55:50 -04:00
Brad Anderson
88095b714e add chat-rn-cli app for frameworkless testing 2025-03-25 10:55:50 -04:00
Brad Anderson
987f037547 small changes 2025-03-25 10:55:50 -04:00
Brad Anderson
d86a2d1496 move jazz-expo-clerk-auth under jazz-expo, rename local e2e test 2025-03-25 10:55:48 -04:00
Brad Anderson
67c1654987 remove op-sqlite from chat-rn-clerk 2025-03-25 10:55:47 -04:00
Brad Anderson
58332c22fc feat: Separate Expo and React Native 2025-03-25 10:55:47 -04:00
234 changed files with 13878 additions and 3340 deletions

View File

@@ -7,8 +7,7 @@ on:
- ".github/actions/android-emulator/**"
- ".github/actions/source-code/**"
- ".github/workflows/e2e-rn-test.yml"
- "examples/chat-rn/**"
- "examples/chat-rn-clerk/**"
- "examples/chat-rn-expo/**"
- "packages/**"
jobs:
@@ -36,8 +35,8 @@ jobs:
- name: Pnpm Build
run: pnpm turbo build --filter="./packages/*"
- name: chat-rn App Pre Build
working-directory: ./examples/chat-rn
- name: chat-rn-expo App Pre Build
working-directory: ./examples/chat-rn-expo
run: |
pnpm build
pnpm expo prebuild --clean
@@ -61,7 +60,7 @@ jobs:
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -no-metrics
disable-animations: true
working-directory: ./examples/chat-rn/
working-directory: ./examples/chat-rn-expo/
script: ./test/e2e/run.sh
- name: Copy Maestro Output

7
.gitignore vendored
View File

@@ -22,6 +22,9 @@ test-results
.husky
.vscode/settings.json
.vscode/*
.svelte-kit
.svelte-kit
.cursorrules
.windsurfrules

View File

@@ -1 +0,0 @@
export const apiKey = "chat-rn-clerk-example-jazz@garden.co";

View File

@@ -1,4 +1,4 @@
# chat-rn-clerk
# chat-rn-expo-clerk
## 1.0.88

View File

@@ -11,7 +11,7 @@ pnpm i
pnpm run build
```
### 2. Inside the `examples/chat-rn-clerk` Directory
### 2. Inside the `examples/chat-rn-expo-clerk` Directory
Next, navigate to the specific example project and run the following commands:

View File

@@ -1,8 +1,8 @@
{
"expo": {
"name": "jazz-chat-rn-clerk",
"scheme": "jazz-chat-rn-clerk",
"slug": "jazz-chat-rn-clerk",
"name": "jazz-chat-rn-expo-clerk",
"scheme": "jazz-chat-rn-expo-clerk",
"slug": "jazz-chat-rn-expo-clerk",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
@@ -24,20 +24,10 @@
"package": "com.jazz.chatrnclerk"
},
"plugins": [
[
"expo-build-properties",
{
"ios": {
"newArchEnabled": true
},
"android": {
"newArchEnabled": true
}
}
],
"expo-secure-store",
"expo-font",
"expo-router",
"expo-sqlite",
[
"expo-image-picker",
{

View File

@@ -1,5 +1,5 @@
import { Redirect, Stack } from "expo-router";
import { useIsAuthenticated } from "jazz-react-native";
import { useIsAuthenticated } from "jazz-expo";
import React from "react";
export default function HomeLayout() {

View File

@@ -1,5 +1,5 @@
import { Redirect, Stack } from "expo-router";
import { useIsAuthenticated } from "jazz-react-native";
import { useIsAuthenticated } from "jazz-expo";
export default function UnAuthenticatedLayout() {
const isAuthenticated = useIsAuthenticated();

View File

@@ -28,7 +28,7 @@ const SignInWithOAuth = () => {
const { createdSessionId, signIn, signUp, setActive } =
await startOAuthFlow({
redirectUrl: Linking.createURL("/", {
scheme: "jazz-chat-rn-clerk",
scheme: "jazz-chat-rn-expo-clerk",
}),
});

View File

@@ -4,8 +4,8 @@ import clsx from "clsx";
import * as Clipboard from "expo-clipboard";
import * as ImagePicker from "expo-image-picker";
import { useLocalSearchParams } from "expo-router";
import { useAccount, useCoState } from "jazz-react-native";
import { ProgressiveImg } from "jazz-react-native";
import { useAccount, useCoState } from "jazz-expo";
import { ProgressiveImg } from "jazz-expo";
import { createImage } from "jazz-react-native-media-images";
import { Group, ID } from "jazz-tools";
import { useEffect, useLayoutEffect, useState } from "react";

View File

@@ -11,7 +11,7 @@ import React, {
} from "react-native";
import { useUser } from "@clerk/clerk-expo";
import { useAccount } from "jazz-react-native";
import { useAccount } from "jazz-expo";
import { Chat } from "../../src/schema";
export default function ChatScreen() {

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 313 KiB

After

Width:  |  Height:  |  Size: 313 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -1,5 +1,5 @@
{
"name": "chat-rn-clerk",
"name": "chat-rn-expo-clerk",
"main": "index.js",
"version": "1.0.88",
"scripts": {
@@ -9,7 +9,8 @@
"format-and-lint:fix": "biome check . --write",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web"
"web": "expo start --web",
"run:ios": "pnpm expo prebuild && npx pod-install && pnpm expo run:ios"
},
"jest": {
"preset": "jest-expo"
@@ -18,55 +19,54 @@
"@azure/core-asynciterator-polyfill": "^1.0.2",
"@bacons/text-decoder": "0.0.0",
"@bam.tech/react-native-image-resizer": "^3.0.11",
"@craftzdog/react-native-buffer": "6.0.5",
"@clerk/clerk-expo": "^2.2.21",
"@craftzdog/react-native-buffer": "6.0.5",
"@expo/vector-icons": "^14.0.2",
"@op-engineering/op-sqlite": "^11.2.12",
"@react-native-community/netinfo": "^11.4.1",
"@react-navigation/native": "^7.0.13",
"@react-navigation/native-stack": "^7.1.14",
"@react-native-community/netinfo": "11.4.1",
"@react-navigation/native": "7.0.15",
"@react-navigation/native-stack": "7.2.1",
"clsx": "^2.0.0",
"expo": "^52.0.0",
"expo-build-properties": "~0.13.1",
"expo-clipboard": "~7.0.0",
"expo-constants": "~17.0.3",
"expo": "^52.0.39",
"expo-build-properties": "~0.13.2",
"expo-clipboard": "~7.0.1",
"expo-constants": "~17.0.8",
"expo-crypto": "~14.0.1",
"expo-dev-client": "~5.0.5",
"expo-dev-client": "~5.0.14",
"expo-file-system": "^18.0.4",
"expo-font": "~13.0.1",
"expo-image-picker": "~16.0.4",
"expo-linking": "~7.0.3",
"expo-linking": "~7.0.5",
"expo-router": "~4.0.11",
"expo-secure-store": "~14.0.0",
"expo-secure-store": "~14.0.1",
"expo-splash-screen": "~0.29.16",
"expo-status-bar": "~2.0.0",
"expo-system-ui": "~4.0.5",
"expo-web-browser": "~14.0.1",
"jazz-react-native": "workspace:*",
"jazz-react-native-auth-clerk": "workspace:*",
"expo-sqlite": "15.1.2",
"expo-status-bar": "~2.0.1",
"expo-system-ui": "~4.0.8",
"expo-web-browser": "~14.0.2",
"jazz-expo": "workspace:*",
"jazz-react-native-media-images": "workspace:*",
"jazz-tools": "workspace:*",
"nativewind": "^4.1.21",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-native": "~0.76.3",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-native": "0.76.7",
"react-native-gesture-handler": "~2.20.2",
"react-native-get-random-values": "^1.11.0",
"react-native-reanimated": "~3.16.3",
"react-native-safe-area-context": "4.12.0",
"react-native-screens": "4.1.0",
"react-native-screens": "4.4.0",
"react-native-url-polyfill": "^2.0.0",
"react-native-web": "~0.19.13",
"readable-stream": "4.7.0"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@types/jest": "^29.5.3",
"@types/react": "^18.3.12",
"@types/react-test-renderer": "^18.0.7",
"jest": "^29.2.1",
"jest-expo": "~52.0.2",
"react-test-renderer": "18.2.0",
"@babel/core": "^7.25.2",
"@types/jest": "^29.5.13",
"@types/react": "~18.3.12",
"@types/react-test-renderer": "^19.0.0",
"jest": "^29.6.3",
"jest-expo": "51.0.2",
"react-test-renderer": "18.3.1",
"tailwindcss": "^3.4.17",
"typescript": "~5.6.2"
},

View File

@@ -0,0 +1 @@
export const apiKey = "chat-rn-expo-clerk-example-jazz@garden.co";

View File

@@ -1,5 +1,6 @@
import { useClerk } from "@clerk/clerk-expo";
import { JazzProviderWithClerk } from "jazz-react-native-auth-clerk";
// FIXME: why isn't the export working? IDE is fine, Metro doesn't like the non 'dist' import
import { JazzProviderWithClerk } from "jazz-expo/dist/auth/clerk";
import React, { PropsWithChildren } from "react";
import { apiKey } from "./apiKey";
@@ -9,7 +10,6 @@ export function JazzAndAuth({ children }: PropsWithChildren) {
return (
<JazzProviderWithClerk
clerk={clerk}
storage="sqlite"
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}

View File

@@ -1,4 +1,4 @@
# chat-rn
# chat-rn-expo
## 1.0.84

View File

@@ -0,0 +1,24 @@
# 🎷 Jazz + Expo + `react-navigation` + Demo Auth
## 🚀 How to Run
### 1. Inside the Workspace Root
First, install dependencies and build the project:
```bash
pnpm i
pnpm run build
```
### 2. Inside the `examples/chat-rn-expo` Directory
Next, navigate to the specific example project and run the following commands:
```bash
pnpm expo prebuild
pnpx pod-install
pnpm expo run:ios
```
This will set up and launch the app on iOS. For Android, you can replace the last command with `pnpm expo run:android`.

View File

@@ -0,0 +1,34 @@
{
"expo": {
"name": "jazz-chat-rn-expo",
"scheme": "jazz-chat-rn-expo",
"slug": "jazz-chat-rn-expo",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.jazz.chatrn"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"package": "com.jazz.chatrn"
},
"plugins": ["expo-secure-store", "expo-sqlite", "expo-build-properties"],
"extra": {
"eas": {
"projectId": "e0e61872-1906-4c84-b9d8-9be77355cad0"
}
},
"owner": "paxx"
}
}

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -0,0 +1,9 @@
module.exports = function (api) {
api.cache(true);
return {
presets: [
["babel-preset-expo", { jsxImportSource: "nativewind" }],
"nativewind/babel",
],
};
};

View File

@@ -0,0 +1,35 @@
// Learn more https://docs.expo.dev/guides/monorepos
const { getDefaultConfig } = require("expo/metro-config");
const { withNativeWind } = require("nativewind/metro");
const { FileStore } = require("metro-cache");
const path = require("path");
// eslint-disable-next-line no-undef
const projectRoot = __dirname;
const workspaceRoot = path.resolve(projectRoot, "../..");
const config = getDefaultConfig(projectRoot, { isCSSEnabled: true });
// Since we are using pnpm, we have to setup the monorepo manually for Metro
// #1 - Watch all files in the monorepo
config.watchFolders = [workspaceRoot];
// #2 - Try resolving with project modules first, then workspace modules
config.resolver.nodeModulesPaths = [
path.resolve(projectRoot, "node_modules"),
path.resolve(workspaceRoot, "node_modules"),
];
config.resolver.sourceExts = ["mjs", "js", "json", "ts", "tsx"];
config.resolver.requireCycleIgnorePatterns = [
/(^|\/|\\)node_modules($|\/|\\)/,
/(^|\/|\\)packages($|\/|\\)/,
];
// Use turborepo to restore the cache when possible
config.cacheStores = [
new FileStore({
root: path.join(projectRoot, "node_modules", ".cache", "metro"),
}),
];
// module.exports = config;
module.exports = withNativeWind(config, { input: "./global.css" });

View File

@@ -0,0 +1,52 @@
{
"name": "chat-rn-expo",
"version": "1.0.79",
"main": "index.js",
"scripts": {
"build": "expo export -p ios",
"start": "expo start",
"format-and-lint": "biome check .",
"format-and-lint:fix": "biome check . --write",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web"
},
"dependencies": {
"@azure/core-asynciterator-polyfill": "^1.0.2",
"@bacons/text-decoder": "0.0.0",
"@craftzdog/react-native-buffer": "6.0.5",
"@react-native-community/netinfo": "11.4.1",
"@react-navigation/native": "7.0.15",
"@react-navigation/native-stack": "7.2.1",
"clsx": "^2.0.0",
"expo": "^52.0.39",
"expo-build-properties": "~0.13.2",
"expo-clipboard": "~7.0.1",
"expo-constants": "~17.0.8",
"expo-dev-client": "~5.0.14",
"expo-linking": "~7.0.5",
"expo-secure-store": "~14.0.1",
"expo-sqlite": "15.1.2",
"expo-status-bar": "~2.0.1",
"expo-system-ui": "~4.0.8",
"expo-web-browser": "~14.0.2",
"jazz-expo": "workspace:*",
"jazz-tools": "workspace:*",
"nativewind": "^4.1.21",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-native": "0.76.7",
"react-native-get-random-values": "^1.11.0",
"react-native-safe-area-context": "4.12.0",
"react-native-screens": "4.4.0",
"react-native-url-polyfill": "^2.0.0",
"readable-stream": "4.7.0"
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@types/react": "~18.3.12",
"tailwindcss": "^3.4.17",
"typescript": "~5.6.2"
},
"private": true
}

View File

@@ -0,0 +1,72 @@
import "../global.css";
import {
NavigationContainer,
useNavigationContainerRef,
} from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import * as Linking from "expo-linking";
import React, { StrictMode, useEffect, useState } from "react";
import HandleInviteScreen from "./invite";
import { JazzProvider } from "jazz-expo";
import { apiKey } from "./apiKey";
import ChatScreen from "./chat";
const Stack = createNativeStackNavigator();
const prefix = Linking.createURL("/");
const linking = {
prefixes: [prefix],
config: {
screens: {
HandleInviteScreen: {
path: "router/invite/:valueHint?/:valueID/:inviteSecret",
},
},
},
};
function App() {
const [initialRoute, setInitialRoute] = useState<
"ChatScreen" | "HandleInviteScreen"
>("ChatScreen");
const navigationRef = useNavigationContainerRef();
useEffect(() => {
Linking.getInitialURL().then((url) => {
if (url) {
if (url && url.includes("invite")) {
setInitialRoute("HandleInviteScreen");
}
}
});
}, []);
return (
<StrictMode>
<JazzProvider
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
>
<NavigationContainer linking={linking} ref={navigationRef}>
<Stack.Navigator initialRouteName={initialRoute}>
<Stack.Screen
options={{ title: "Jazz Chat" }}
name="ChatScreen"
// @ts-ignore
component={ChatScreen}
/>
<Stack.Screen
name="HandleInviteScreen"
component={HandleInviteScreen}
/>
</Stack.Navigator>
</NavigationContainer>
</JazzProvider>
</StrictMode>
);
}
export default App;

View File

@@ -0,0 +1 @@
export const apiKey = "chat-rn-expo-example-jazz@garden.co";

View File

@@ -0,0 +1,209 @@
import clsx from "clsx";
import * as Clipboard from "expo-clipboard";
import { Group, ID, Profile } from "jazz-tools";
import { useEffect, useState } from "react";
import React, {
Button,
FlatList,
KeyboardAvoidingView,
SafeAreaView,
Text,
TextInput,
TouchableOpacity,
View,
Alert,
} from "react-native";
import { useAccount, useCoState } from "jazz-expo";
import { Chat, Message } from "./schema";
export default function ChatScreen({ navigation }: { navigation: any }) {
const { me, logOut } = useAccount();
const [chatId, setChatId] = useState<ID<Chat>>();
const loadedChat = useCoState(Chat, chatId, [{}]);
const [message, setMessage] = useState("");
const profile = useCoState(Profile, me._refs.profile?.id, {});
function handleLogOut() {
setChatId(undefined);
logOut();
}
useEffect(() => {
navigation.setOptions({
headerRight: () => <Button onPress={handleLogOut} title="Logout" />,
headerLeft: () =>
loadedChat ? (
<Button
onPress={() => {
if (loadedChat?.id) {
Clipboard.setStringAsync(
`https://chat.jazz.tools/#/chat/${loadedChat.id}`,
);
Alert.alert("Copied to clipboard", `Chat ID: ${loadedChat.id}`);
}
}}
title="Share"
/>
) : null,
});
}, [navigation, loadedChat]);
const createChat = () => {
const group = Group.create({ owner: me });
group.addMember("everyone", "writer");
const chat = Chat.create([], { owner: group });
setChatId(chat.id);
};
const joinChat = () => {
Alert.prompt(
"Join Chat",
"Enter the Chat ID (example: co_zBGEHYvRfGuT2YSBraY3njGjnde)",
[
{
text: "Cancel",
style: "cancel",
},
{
text: "Join",
onPress: (chatId) => {
if (chatId) {
setChatId(chatId as ID<Chat>);
} else {
Alert.alert("Error", "Chat ID cannot be empty.");
}
},
},
],
"plain-text",
);
};
const sendMessage = () => {
if (!loadedChat) return;
if (message.trim()) {
loadedChat.push(
Message.create({ text: message }, { owner: loadedChat?._owner }),
);
setMessage("");
}
};
const renderMessageItem = ({ item }: { item: Message }) => {
const isMe = item._edits?.text?.by?.isMe;
return (
<View
className={clsx(
`rounded-lg p-1 px-1.5 max-w-[80%] `,
isMe ? `bg-gray-200 self-end text-right` : `bg-gray-300 self-start `,
)}
>
{!isMe ? (
<Text
className={clsx(
`text-xs text-gray-500`,
isMe ? "text-right" : "text-left",
)}
>
{item?._edits?.text?.by?.profile?.name}
</Text>
) : null}
<View
className={clsx(
"flex relative items-end justify-between",
isMe ? "flex-row" : "flex-row",
)}
>
<Text className={clsx(`text-black text-md max-w-[85%]`)}>
{item.text}
</Text>
<Text
className={clsx(
"text-[10px] text-gray-500 text-right ml-2",
!isMe ? "mt-2" : "mt-1",
)}
>
{item?._edits?.text?.madeAt?.getHours()}:
{item?._edits?.text?.madeAt?.getMinutes()}
</Text>
</View>
</View>
);
};
return (
<View className="flex flex-col h-full">
{!loadedChat ? (
<View className="flex flex-col h-full items-center justify-center">
<Text className="text-m font-bold mb-6">Username</Text>
<TextInput
className="rounded h-12 p-2 mb-12 w-40 border border-gray-200 block"
value={profile?.name ?? ""}
onChangeText={(value) => {
if (profile) {
profile.name = value;
}
}}
textAlignVertical="center"
onSubmitEditing={sendMessage}
testID="username-input"
/>
<TouchableOpacity
onPress={createChat}
className="bg-blue-500 p-4 rounded-md"
>
<Text className="text-white font-semibold">Start new chat</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={joinChat}
className="bg-green-500 p-4 rounded-md mt-4"
>
<Text className="text-white font-semibold">Join chat</Text>
</TouchableOpacity>
</View>
) : (
<>
<FlatList
contentContainerStyle={{
flexGrow: 1,
flex: 1,
gap: 6,
padding: 8,
}}
className="flex"
data={loadedChat}
keyExtractor={(item) => item.id}
renderItem={renderMessageItem}
/>
<KeyboardAvoidingView
keyboardVerticalOffset={110}
behavior="padding"
className="p-3 bg-white border-t border-gray-300"
>
<SafeAreaView className="flex flex-row items-center gap-2">
<TextInput
className="rounded-full h-8 py-0 px-2 border border-gray-200 block flex-1"
value={message}
onChangeText={setMessage}
placeholder="Type a message..."
textAlignVertical="center"
onSubmitEditing={sendMessage}
testID="message-input"
/>
<TouchableOpacity
onPress={sendMessage}
className="bg-gray-300 text-white rounded-full h-8 w-8 items-center justify-center"
testID="send-button"
>
<Text></Text>
</TouchableOpacity>
</SafeAreaView>
</KeyboardAvoidingView>
</>
)}
</View>
);
}

View File

@@ -0,0 +1,18 @@
import { useAcceptInvite } from "jazz-expo";
import React, { Text } from "react-native";
import { Chat } from "./schema";
export default function HandleInviteScreen({
navigation,
}: {
navigation: any;
}) {
useAcceptInvite({
invitedObjectSchema: Chat,
onAccept: async (chatId) => {
navigation.navigate("ChatScreen", { chatId });
},
});
return <Text>Accepting invite...</Text>;
}

View File

@@ -0,0 +1,7 @@
import { CoList, CoMap, co } from "jazz-tools";
export class Message extends CoMap {
text = co.string;
}
export class Chat extends CoList.Of(co.ref(Message)) {}

View File

@@ -0,0 +1,2 @@
BUNDLE_PATH: "vendor/bundle"
BUNDLE_FORCE_RUBY_PLATFORM: 1

View File

@@ -0,0 +1,5 @@
module.exports = {
root: true,
extends: ["@react-native", "plugin:prettier/recommended"],
plugins: ["prettier"],
};

View File

@@ -1,38 +1,75 @@
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
# OSX
#
.DS_Store
# dependencies
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
**/.xcode.env.local
# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml
*.hprof
.cxx/
*.keystore
!debug.keystore
.kotlin/
# node.js
#
node_modules/
npm-debug.log
yarn-error.log
# Expo
.expo/
dist/
web-build/
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/
# Native
*.orig.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision
**/fastlane/report.xml
**/fastlane/Preview.html
**/fastlane/screenshots
**/fastlane/test_output
# Metro
# Bundle artifact
*.jsbundle
# Ruby / CocoaPods
**/Pods/
/vendor/bundle/
# Temporary files created by Metro to check the health of the file watcher
.metro-health-check*
# debug
npm-debug.*
yarn-debug.*
yarn-error.*
# testing
/coverage
# macOS
.DS_Store
*.pem
# local env files
.env*.local
# typescript
*.tsbuildinfo
ios
android
# Yarn
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

View File

@@ -0,0 +1,2 @@
ios
android

View File

@@ -0,0 +1,7 @@
module.exports = {
arrowParens: "avoid",
bracketSameLine: true,
bracketSpacing: true,
singleQuote: false,
trailingComma: "all",
};

View File

@@ -0,0 +1 @@
{}

11
examples/chat-rn/Gemfile Normal file
View File

@@ -0,0 +1,11 @@
source 'https://rubygems.org'
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
ruby ">= 2.6.10"
# Exclude problematic versions of cocoapods and activesupport that causes build failures.
gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1'
gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0'
gem 'xcodeproj', '< 1.26.0'
gem 'concurrent-ruby', '< 1.3.4'
gem "bigdecimal", "~> 3.1"

View File

@@ -0,0 +1,111 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.7)
base64
nkf
rexml
activesupport (6.1.7.10)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
algoliasearch (1.27.5)
httpclient (~> 2.8, >= 2.8.3)
json (>= 1.5.1)
atomos (0.1.3)
base64 (0.2.0)
bigdecimal (3.1.9)
claide (1.1.0)
cocoapods (1.15.2)
addressable (~> 2.8)
claide (>= 1.0.2, < 2.0)
cocoapods-core (= 1.15.2)
cocoapods-deintegrate (>= 1.0.3, < 2.0)
cocoapods-downloader (>= 2.1, < 3.0)
cocoapods-plugins (>= 1.0.0, < 2.0)
cocoapods-search (>= 1.0.0, < 2.0)
cocoapods-trunk (>= 1.6.0, < 2.0)
cocoapods-try (>= 1.1.0, < 2.0)
colored2 (~> 3.1)
escape (~> 0.0.4)
fourflusher (>= 2.3.0, < 3.0)
gh_inspector (~> 1.0)
molinillo (~> 0.8.0)
nap (~> 1.0)
ruby-macho (>= 2.3.0, < 3.0)
xcodeproj (>= 1.23.0, < 2.0)
cocoapods-core (1.15.2)
activesupport (>= 5.0, < 8)
addressable (~> 2.8)
algoliasearch (~> 1.0)
concurrent-ruby (~> 1.1)
fuzzy_match (~> 2.0.4)
nap (~> 1.0)
netrc (~> 0.11)
public_suffix (~> 4.0)
typhoeus (~> 1.0)
cocoapods-deintegrate (1.0.5)
cocoapods-downloader (2.1)
cocoapods-plugins (1.0.0)
nap
cocoapods-search (1.0.1)
cocoapods-trunk (1.6.0)
nap (>= 0.8, < 2.0)
netrc (~> 0.11)
cocoapods-try (1.2.0)
colored2 (3.1.2)
concurrent-ruby (1.3.3)
escape (0.0.4)
ethon (0.16.0)
ffi (>= 1.15.0)
ffi (1.17.1)
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gh_inspector (1.1.3)
httpclient (2.9.0)
mutex_m
i18n (1.14.7)
concurrent-ruby (~> 1.0)
json (2.7.6)
minitest (5.25.4)
molinillo (0.8.0)
mutex_m (0.3.0)
nanaimo (0.3.0)
nap (1.1.0)
netrc (0.11.0)
nkf (0.2.0)
public_suffix (4.0.7)
rexml (3.4.1)
ruby-macho (2.5.1)
typhoeus (1.4.1)
ethon (>= 0.9.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
xcodeproj (1.25.1)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.3.0)
rexml (>= 3.3.6, < 4.0)
zeitwerk (2.6.18)
PLATFORMS
ruby
DEPENDENCIES
activesupport (>= 6.1.7.5, != 7.1.0)
bigdecimal (~> 3.1)
cocoapods (>= 1.13, != 1.15.1, != 1.15.0)
concurrent-ruby (< 1.3.4)
xcodeproj (< 1.26.0)
RUBY VERSION
ruby 2.6.10p210
BUNDLED WITH
2.3.25

View File

@@ -1,14 +1,13 @@
# 🎷 Jazz + Expo + `react-navigation` + Demo Auth
# 🎷 Jazz + React Native + Demo Auth
## 🚀 How to Run
### 1. Inside the Workspace Root
First, install dependencies and build the project:
First, install dependencies for the project:
```bash
pnpm i
pnpm run build
```
### 2. Inside the `examples/chat-rn` Directory
@@ -16,9 +15,18 @@ pnpm run build
Next, navigate to the specific example project and run the following commands:
```bash
pnpm expo prebuild
npx pod-install
pnpm expo run:ios
pnpm pods
pnpm ios
```
This will set up and launch the app on iOS. For Android, you can replace the last command with `pnpm expo run:android`.
This will set up and launch the app on iOS. For Android, you can skip `pnpm pods` and replace the last command with `pnpm android`.
## Creation
This was created using the following command:
```bash
bunx @react-native-community/cli init chat-rn --version 0.78 --install-pods true --skip-git-init true --package-name com.jazz.chatrn --directory chat-rn
```
Then delete `bun.lock`, change package name in `package.json`, and begin build instructions above.

View File

@@ -0,0 +1,119 @@
apply plugin: "com.android.application"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"
/**
* This is the configuration block to customize your React Native Android app.
* By default you don't need to apply any configuration, just uncomment the lines you need.
*/
react {
/* Folders */
// The root of your project, i.e. where "package.json" lives. Default is '../..'
// root = file("../../")
// The folder where the react-native NPM package is. Default is ../../node_modules/react-native
// reactNativeDir = file("../../node_modules/react-native")
// The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
// codegenDir = file("../../node_modules/@react-native/codegen")
// The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js
// cliFile = file("../../node_modules/react-native/cli.js")
/* Variants */
// The list of variants to that are debuggable. For those we're going to
// skip the bundling of the JS bundle and the assets. By default is just 'debug'.
// If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
// debuggableVariants = ["liteDebug", "prodDebug"]
/* Bundling */
// A list containing the node command and its flags. Default is just 'node'.
// nodeExecutableAndArgs = ["node"]
//
// The command to run when bundling. By default is 'bundle'
// bundleCommand = "ram-bundle"
//
// The path to the CLI configuration file. Default is empty.
// bundleConfig = file(../rn-cli.config.js)
//
// The name of the generated asset file containing your JS bundle
// bundleAssetName = "MyApplication.android.bundle"
//
// The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
// entryFile = file("../js/MyApplication.android.js")
//
// A list of extra flags to pass to the 'bundle' commands.
// See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
// extraPackagerArgs = []
/* Hermes Commands */
// The hermes compiler command to run. By default it is 'hermesc'
// hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
//
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
// hermesFlags = ["-O", "-output-source-map"]
/* Autolinking */
autolinkLibrariesWithApp()
}
/**
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
*/
def enableProguardInReleaseBuilds = false
/**
* The preferred build flavor of JavaScriptCore (JSC)
*
* For example, to use the international variant, you can use:
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
*
* The international variant includes ICU i18n library and necessary data
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
* give correct results when using with locales other than en-US. Note that
* this variant is about 6MiB larger per architecture than default.
*/
def jscFlavor = 'org.webkit:android-jsc:+'
android {
ndkVersion rootProject.ext.ndkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
compileSdk rootProject.ext.compileSdkVersion
namespace "com.chatrn"
defaultConfig {
applicationId "com.chatrn"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
}
signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
}
buildTypes {
debug {
signingConfig signingConfigs.debug
}
release {
// Caution! In production, you need to generate your own keystore file.
// see https://reactnative.dev/docs/signed-apk-android.
signingConfig signingConfigs.debug
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
}
dependencies {
// The version of react-native is set by the React Native Gradle Plugin
implementation("com.facebook.react:react-android")
if (hermesEnabled.toBoolean()) {
implementation("com.facebook.react:hermes-android")
} else {
implementation jscFlavor
}
}

Binary file not shown.

View File

@@ -0,0 +1,10 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:usesCleartextTraffic="true"
tools:targetApi="28"
tools:ignore="GoogleAppIndexingWarning"/>
</manifest>

View File

@@ -0,0 +1,26 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme"
android:supportsRtl="true">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,22 @@
package com.chatrn
import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
import com.facebook.react.defaults.DefaultReactActivityDelegate
class MainActivity : ReactActivity() {
/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
override fun getMainComponentName(): String = "ChatRN"
/**
* Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
* which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
*/
override fun createReactActivityDelegate(): ReactActivityDelegate =
DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
}

View File

@@ -0,0 +1,44 @@
package com.chatrn
import android.app.Application
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.soloader.OpenSourceMergedSoMapping
import com.facebook.soloader.SoLoader
class MainApplication : Application(), ReactApplication {
override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> =
PackageList(this).packages.apply {
// Packages that cannot be autolinked yet can be added manually here, for example:
// add(MyReactNativePackage())
}
override fun getJSMainModuleName(): String = "index"
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
}
override val reactHost: ReactHost
get() = getDefaultReactHost(applicationContext, reactNativeHost)
override fun onCreate() {
super.onCreate()
SoLoader.init(this, OpenSourceMergedSoMapping)
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
load()
}
}
}

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="@dimen/abc_edit_text_inset_horizontal_material"
android:insetRight="@dimen/abc_edit_text_inset_horizontal_material"
android:insetTop="@dimen/abc_edit_text_inset_top_material"
android:insetBottom="@dimen/abc_edit_text_inset_bottom_material"
>
<selector>
<!--
This file is a copy of abc_edit_text_material (https://bit.ly/3k8fX7I).
The item below with state_pressed="false" and state_focused="false" causes a NullPointerException.
NullPointerException:tempt to invoke virtual method 'android.graphics.drawable.Drawable android.graphics.drawable.Drawable$ConstantState.newDrawable(android.content.res.Resources)'
<item android:state_pressed="false" android:state_focused="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
For more info, see https://bit.ly/3CdLStv (react-native/pull/29452) and https://bit.ly/3nxOMoR.
-->
<item android:state_enabled="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
<item android:drawable="@drawable/abc_textfield_activated_mtrl_alpha"/>
</selector>
</inset>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">ChatRN</string>
</resources>

Some files were not shown because too many files have changed in this diff Show More