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
1174 changed files with 32196 additions and 82434 deletions

View File

@@ -9,23 +9,18 @@
"cojson-storage",
"cojson-storage-indexeddb",
"cojson-storage-sqlite",
"cojson-storage-rn-sqlite",
"cojson-transport-ws",
"jazz-browser",
"jazz-auth-clerk",
"jazz-auth-betterauth",
"jazz-betterauth-client-plugin",
"jazz-betterauth-server-plugin",
"jazz-react-auth-betterauth",
"jazz-browser-media-images",
"jazz-expo",
"jazz-inspector",
"jazz-inspector-element",
"jazz-nodejs",
"jazz-react",
"jazz-react-core",
"jazz-react-auth-clerk",
"jazz-react-native-core",
"jazz-react-native",
"jazz-react-native-auth-clerk",
"jazz-react-native-media-images",
"jazz-run",
"jazz-svelte",

View File

@@ -1,10 +0,0 @@
---
name: Docs request
about: Allow people to quickly report issues & improvements for the docs
title: 'Docs: '
labels: docs, requested
assignees: bensleveritt
---

View File

@@ -15,7 +15,4 @@ jobs:
with:
version: latest
- name: Run Biome
run: biome ci .
- name: Check Catalog Dependencies
run: node scripts/check-catalog-deps.js
run: biome ci .

View File

@@ -13,7 +13,7 @@ jobs:
continue-on-error: true
strategy:
matrix:
project: ["tests/e2e", "examples/chat", "examples/clerk", "examples/betterauth", "examples/file-share-svelte", "examples/form", "examples/music-player", "examples/organization", "examples/pets", "starters/react-passkey-auth"]
project: ["tests/e2e", "examples/chat", "examples/file-share-svelte", "examples/form", "examples/music-player", "examples/pets", "starters/react-passkey-auth"]
steps:
- uses: actions/checkout@v4

3
.gitignore vendored
View File

@@ -23,11 +23,8 @@ test-results
.husky
.vscode/*
.idea/*
.svelte-kit
.cursorrules
.windsurfrules
playwright-report

View File

@@ -13,7 +13,6 @@
"**/android/**",
"packages/jazz-svelte/**",
"examples/*svelte*/**",
"examples/jazz-paper-scissors/src/routeTree.gen.ts",
"homepage/homepage/**",
"**/package.json"
]

View File

@@ -1 +0,0 @@
BETTER_AUTH_SECRET="TEST_SECRET"

View File

@@ -1,47 +0,0 @@
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
sqlite.db
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
!.env
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

View File

@@ -1,198 +0,0 @@
# betterauth
## 0.1.17
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-betterauth-server-plugin@0.14.14
- jazz-inspector@0.14.14
- jazz-react@0.14.14
- jazz-react-auth-betterauth@0.14.14
- jazz-betterauth-client-plugin@0.14.14
## 0.1.16
### Patch Changes
- jazz-inspector@0.14.13
- jazz-react@0.14.13
- jazz-react-auth-betterauth@0.14.13
## 0.1.15
### Patch Changes
- jazz-inspector@0.14.12
- jazz-react@0.14.12
- jazz-react-auth-betterauth@0.14.12
## 0.1.14
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-react-auth-betterauth@0.14.10
- jazz-inspector@0.14.10
- jazz-react@0.14.10
- jazz-tools@0.14.10
- jazz-betterauth-server-plugin@0.14.10
- jazz-betterauth-client-plugin@0.14.10
## 0.1.13
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-betterauth-server-plugin@0.14.9
- jazz-inspector@0.14.9
- jazz-react@0.14.9
- jazz-react-auth-betterauth@0.14.9
- jazz-betterauth-client-plugin@0.14.9
## 0.1.12
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-betterauth-server-plugin@0.14.8
- jazz-inspector@0.14.8
- jazz-react@0.14.8
- jazz-react-auth-betterauth@0.14.8
- jazz-betterauth-client-plugin@0.14.8
## 0.1.11
### Patch Changes
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-betterauth-server-plugin@0.14.7
- jazz-inspector@0.14.7
- jazz-react@0.14.7
- jazz-react-auth-betterauth@0.14.7
- jazz-betterauth-client-plugin@0.14.7
## 0.1.10
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-betterauth-server-plugin@0.14.6
- jazz-inspector@0.14.6
- jazz-react@0.14.6
- jazz-react-auth-betterauth@0.14.6
- jazz-betterauth-client-plugin@0.14.6
## 0.1.9
### Patch Changes
- Updated dependencies [91cbb2f]
- Updated dependencies [20b3d88]
- jazz-tools@0.14.5
- jazz-betterauth-server-plugin@0.14.5
- jazz-inspector@0.14.5
- jazz-react@0.14.5
- jazz-react-auth-betterauth@0.14.5
- jazz-betterauth-client-plugin@0.14.5
## 0.1.8
### Patch Changes
- Updated dependencies [011af55]
- jazz-tools@0.14.4
- jazz-betterauth-server-plugin@0.14.4
- jazz-inspector@0.14.4
- jazz-react@0.14.4
- jazz-react-auth-betterauth@0.14.4
- jazz-betterauth-client-plugin@0.14.4
## 0.1.7
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-betterauth-server-plugin@0.14.2
- jazz-inspector@0.14.2
- jazz-react@0.14.2
- jazz-react-auth-betterauth@0.14.2
- jazz-betterauth-client-plugin@0.14.2
## 0.1.6
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-betterauth-server-plugin@0.14.1
- jazz-inspector@0.14.1
- jazz-react@0.14.1
- jazz-react-auth-betterauth@0.14.1
- jazz-betterauth-client-plugin@0.14.1
## 0.1.5
### Patch Changes
- Updated dependencies [5835ed1]
- jazz-tools@0.14.0
- jazz-betterauth-server-plugin@0.14.0
- jazz-inspector@0.14.0
- jazz-react@0.14.0
- jazz-react-auth-betterauth@0.14.0
- jazz-betterauth-client-plugin@0.14.0
## 0.1.4
### Patch Changes
- jazz-betterauth-server-plugin@0.13.32
- jazz-react@0.13.32
- jazz-react-auth-betterauth@0.13.32
- jazz-betterauth-client-plugin@0.13.32
## 0.1.3
### Patch Changes
- Updated dependencies [e5b170f]
- jazz-tools@0.13.31
- jazz-betterauth-server-plugin@0.13.31
- jazz-inspector@0.13.31
- jazz-react@0.13.31
- jazz-react-auth-betterauth@0.13.31
- jazz-betterauth-client-plugin@0.13.31
## 0.1.2
### Patch Changes
- jazz-betterauth-server-plugin@0.13.30
- jazz-inspector@0.13.30
- jazz-react@0.13.30
- jazz-react-auth-betterauth@0.13.30
- jazz-tools@0.13.30
- jazz-betterauth-client-plugin@0.13.30
## 0.1.1
### Patch Changes
- Updated dependencies [8e5ff13]
- jazz-inspector@0.13.29
- jazz-betterauth-server-plugin@0.0.1
- jazz-react@0.13.29
- jazz-react-auth-betterauth@0.0.1
- jazz-tools@0.13.29
- jazz-betterauth-client-plugin@0.0.1

View File

@@ -1,54 +0,0 @@
# Better Auth Integration Example
This example demonstrates how to integrate [Better Auth](https://www.better-auth.com/) with Jazz.
## Getting started
To run this example, you may either:
* Clone the Jazz monorepo and run this example from within.
* Create a new Jazz project using this example as a template, and run that new project.
### Setting environment variables
- `NEXT_PUBLIC_AUTH_BASE_URL`: A URL to a Better Auth server. If undefined, the example will self-host a Better Auth server.
- `BETTER_AUTH_SECRET`: The encryption secret used by the self-hosted Better Auth server (required only if `NEXT_PUBLIC_AUTH_BASE_URL` is undefined)
- `GITHUB_CLIENT_ID`: The client ID for the GitHub OAuth provider used by the self-hosted Better Auth server (required only if `NEXT_PUBLIC_AUTH_BASE_URL` is undefined)
- `GITHUB_CLIENT_SECRET`: The client secret for the GitHub OAuth provider used by the self-hosted Better Auth server (required only if `NEXT_PUBLIC_AUTH_BASE_URL` is undefined)
### Using this example as a template
1. Create a new Jazz project, and use this example as a template.
```sh
npx create-jazz-app@latest betterauth-app --example betterauth
```
2. Navigate to the new project and start the development server.
```sh
cd betterauth-app
pnpm install
pnpm dev
```
### Using the monorepo
This requires `pnpm` to be installed, see [https://pnpm.io/installation](https://pnpm.io/installation).
Clone the jazz repository.
```bash
git clone https://github.com/garden-co/jazz.git
```
Install and build dependencies.
```bash
pnpm i && npx turbo build
```
Go to the example directory.
```bash
cd jazz/examples/betterauth/
```
Start the dev server.
```bash
pnpm dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

View File

@@ -1,21 +0,0 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/styles/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}

View File

@@ -1,7 +0,0 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
};
export default nextConfig;

View File

@@ -1,51 +0,0 @@
{
"name": "betterauth",
"version": "0.1.17",
"private": true,
"type": "module",
"scripts": {
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "next lint",
"format-and-lint": "biome check .",
"format-and-lint:fix": "biome check . --write",
"test:e2e": "playwright test",
"test:e2e:ui": "playwright test --ui",
"email": "email dev --dir src/components/emails"
},
"dependencies": {
"@icons-pack/react-simple-icons": "^12.8.0",
"@radix-ui/react-label": "^2.1.6",
"@radix-ui/react-slot": "^1.2.2",
"better-auth": "^1.2.4",
"better-sqlite3": "^11.9.1",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"jazz-betterauth-client-plugin": "workspace:*",
"jazz-betterauth-server-plugin": "workspace:*",
"jazz-inspector": "workspace:*",
"jazz-react": "workspace:*",
"jazz-react-auth-betterauth": "workspace:*",
"jazz-tools": "workspace:*",
"lucide-react": "^0.510.0",
"next": "15.3.2",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"sonner": "^2.0.3",
"tailwind-merge": "^3.3.0",
"tw-animate-css": "^1.2.5"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@playwright/test": "^1.50.1",
"@tailwindcss/postcss": "^4",
"@types/better-sqlite3": "^7.6.12",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"react-email": "^4.0.11",
"tailwindcss": "^4",
"typescript": "^5"
}
}

View File

@@ -1,53 +0,0 @@
import { defineConfig, devices } from "@playwright/test";
import isCI from "is-ci";
/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// import dotenv from 'dotenv';
// dotenv.config({ path: path.resolve(__dirname, '.env') });
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: "./tests",
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: isCI,
/* Retry on CI only */
retries: isCI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: isCI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: "html",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: "http://localhost:3000/",
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
permissions: ["clipboard-read", "clipboard-write"],
},
/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
],
/* Run your local dev server before starting the tests */
webServer: [
{
command: "pnpm dev",
url: "http://localhost:3000/",
reuseExistingServer: !isCI,
},
],
});

View File

@@ -1,5 +0,0 @@
const config = {
plugins: ["@tailwindcss/postcss"],
};
export default config;

View File

@@ -1,15 +0,0 @@
<svg
viewBox="0 0 386 146"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path id="text"
d="M176.725 33.865H188.275V22.7H176.725V33.865ZM164.9 129.4H172.875C182.72 129.4 188.275 123.9 188.275 114.22V43.6H176.725V109.545C176.725 115.65 173.975 118.51 167.925 118.51H164.9V129.4ZM245.298 53.28C241.613 45.47 233.363 41.95 222.748 41.95C208.998 41.95 200.748 48.44 197.888 58.615L208.613 61.915C210.648 55.315 216.368 52.565 222.638 52.565C231.933 52.565 235.673 56.415 236.058 64.61C226.433 65.93 216.643 67.195 209.768 69.23C200.583 72.145 195.743 77.865 195.743 86.83C195.743 96.51 202.673 104.65 215.818 104.65C225.443 104.65 232.318 101.35 237.213 94.365V103H247.388V66.425C247.388 61.475 247.168 57.185 245.298 53.28ZM217.853 95.245C210.483 95.245 207.128 91.34 207.128 86.72C207.128 82.045 210.593 79.515 215.323 77.92C220.328 76.435 226.983 75.5 235.948 74.18C235.893 76.93 235.673 80.725 234.738 83.475C233.418 89.25 227.643 95.245 217.853 95.245ZM251.22 103H301.545V92.715H269.535L303.195 45.47V43.6H254.3V53.885H284.935L251.22 101.185V103ZM304.815 103H355.14V92.715H323.13L356.79 45.47V43.6H307.895V53.885H338.53L304.815 101.185V103Z"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M136.179 44.8277C136.179 44.8277 136.179 44.8277 136.179 44.8276V21.168C117.931 28.5527 97.9854 32.6192 77.0897 32.6192C65.1466 32.6192 53.5138 31.2908 42.331 28.7737V51.4076C42.331 51.4076 42.331 51.4076 42.331 51.4076V81.1508C41.2955 80.4385 40.1568 79.8458 38.9405 79.3915C36.1732 78.358 33.128 78.0876 30.1902 78.6145C27.2524 79.1414 24.5539 80.4419 22.4358 82.3516C20.3178 84.2613 18.8754 86.6944 18.291 89.3433C17.7066 91.9921 18.0066 94.7377 19.1528 97.2329C20.2991 99.728 22.2403 101.861 24.7308 103.361C27.2214 104.862 30.1495 105.662 33.1448 105.662H33.1455C33.6061 105.662 33.8365 105.662 34.0314 105.659C44.5583 105.449 53.042 96.9656 53.2513 86.4386C53.2534 86.3306 53.2544 86.2116 53.2548 86.0486H53.2552V85.7149L53.2552 85.5521V82.0762L53.2552 53.1993C61.0533 54.2324 69.0092 54.7656 77.0897 54.7656C77.6696 54.7656 78.2489 54.7629 78.8276 54.7574V110.696C77.792 109.983 76.6533 109.391 75.437 108.936C72.6697 107.903 69.6246 107.632 66.6867 108.159C63.7489 108.686 61.0504 109.987 58.9323 111.896C56.8143 113.806 55.3719 116.239 54.7875 118.888C54.2032 121.537 54.5031 124.283 55.6494 126.778C56.7956 129.273 58.7368 131.405 61.2273 132.906C63.7179 134.406 66.646 135.207 69.6414 135.207C70.1024 135.207 70.3329 135.207 70.5279 135.203C81.0548 134.994 89.5385 126.51 89.7478 115.983C89.7517 115.788 89.7517 115.558 89.7517 115.097V111.621L89.7517 54.3266C101.962 53.4768 113.837 51.4075 125.255 48.2397V80.9017C124.219 80.1894 123.081 79.5966 121.864 79.1424C119.097 78.1089 116.052 77.8384 113.114 78.3653C110.176 78.8922 107.478 80.1927 105.36 82.1025C103.242 84.0122 101.799 86.4453 101.215 89.0941C100.631 91.743 100.931 94.4886 102.077 96.9837C103.223 99.4789 105.164 101.612 107.655 103.112C110.145 104.612 113.073 105.413 116.069 105.413C116.53 105.413 116.76 105.413 116.955 105.409C127.482 105.2 135.966 96.7164 136.175 86.1895C136.179 85.9945 136.179 85.764 136.179 85.3029V81.8271L136.179 44.8277Z"
fill="#146AFF"
/>
</svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -1,12 +0,0 @@
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 125 125"
fill="none"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M118.179 29.6597V6C99.931 13.3847 79.9854 17.4512 59.0897 17.4512C47.1466 17.4512 35.5138 16.1228 24.331 13.6057V36.2396V65.9828C23.2955 65.2705 22.1568 64.6778 20.9405 64.2235C18.1732 63.19 15.128 62.9196 12.1902 63.4465C9.25242 63.9734 6.55392 65.2739 4.43582 67.1836C2.31782 69.0933 0.875416 71.5264 0.291016 74.1753C-0.293384 76.8241 0.00661504 79.5697 1.15281 82.0649C2.29911 84.56 4.24032 86.693 6.73082 88.193C9.22142 89.694 12.1495 90.494 15.1448 90.494C15.6054 90.494 15.8365 90.494 16.0314 90.491C26.5583 90.281 35.042 81.7976 35.2513 71.2706C35.2534 71.1626 35.2544 71.0436 35.2548 70.8806L35.2552 70.5469V70.3841V66.9082V38.0313C43.0533 39.0644 51.0092 39.5976 59.0897 39.5976C59.6696 39.5976 60.2489 39.5949 60.8276 39.5894V95.528C59.792 94.815 58.6533 94.223 57.437 93.768C54.6697 92.735 51.6246 92.464 48.6867 92.991C45.7489 93.518 43.0504 94.819 40.9323 96.728C38.8143 98.638 37.3719 101.071 36.7875 103.72C36.2032 106.369 36.5031 109.115 37.6494 111.61C38.7956 114.105 40.7368 116.237 43.2273 117.738C45.7179 119.238 48.646 120.039 51.6414 120.039C52.1024 120.039 52.3329 120.039 52.5279 120.035C63.0548 119.826 71.5385 111.342 71.7478 100.815C71.7517 100.62 71.7517 100.39 71.7517 99.929V96.453V39.1586C83.962 38.3088 95.837 36.2395 107.255 33.0717V65.7337C106.219 65.0214 105.081 64.4286 103.864 63.9744C101.097 62.9409 98.052 62.6704 95.114 63.1973C92.176 63.7242 89.478 65.0247 87.36 66.9345C85.242 68.8442 83.799 71.2773 83.215 73.9261C82.631 76.575 82.931 79.3206 84.077 81.8157C85.223 84.3109 87.164 86.444 89.655 87.944C92.145 89.444 95.073 90.245 98.069 90.245C98.53 90.245 98.76 90.245 98.955 90.241C109.482 90.032 117.966 81.5484 118.175 71.0215C118.179 70.8265 118.179 70.596 118.179 70.1349V66.6591V29.6597Z"
fill="#146AFF"
/>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1,22 +0,0 @@
import { Navbar } from "@/components/navbar";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Jazz Example: Better Auth",
description: "Jazz example application demonstrating Better Auth integration",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<>
<Navbar />
<div className="container mx-auto pt-16 min-h-screen flex flex-col items-center justify-center">
{children}
</div>
</>
);
}

View File

@@ -1,113 +0,0 @@
"use client";
import { Button } from "@/components/ui/button";
import { useAccount } from "jazz-react";
import { Account } from "jazz-tools";
import {
AppWindowMacIcon,
FileTextIcon,
GlobeIcon,
WrenchIcon,
} from "lucide-react";
import Image from "next/image";
export default function Home() {
const { me } = useAccount(Account, { resolve: { profile: {} } });
if (!me) {
return null;
}
return (
<div className="grow flex flex-col items-center justify-center">
<main className="flex flex-col gap-8 row-start-2 grow justify-center">
<Image
src="/jazz-logo.svg"
alt="Jazz logo"
width={180}
height={38}
priority
/>
<p className="text-sm/6 text-center sm:text-left">
Signed in as{" "}
<span className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-mono font-semibold">
{me.profile.name}
</span>{" "}
with id{" "}
<span className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-mono font-semibold">
{me.id}
</span>
</p>
<div className="flex gap-4 items-center flex-row">
<Button asChild size="lg">
<a
href="https://jazz.tools/docs"
target="_blank"
rel="noopener noreferrer"
>
<Image src="/jazz.svg" alt="" width={20} height={20} />
Start building
</a>
</Button>
<Button asChild variant="secondary" size="lg">
<a
href="https://jazz.tools/docs"
target="_blank"
rel="noopener noreferrer"
>
<FileTextIcon className="size-4" />
Read the docs
</a>
</Button>
</div>
</main>
<footer className="flex gap-4 py-8">
<Button asChild variant="ghost">
<a
href="https://jazz.tools/api-reference"
target="_blank"
rel="noopener noreferrer"
>
<FileTextIcon className="size-4" />
API reference
</a>
</Button>
<Button asChild variant="ghost">
<a
href="https://jazz.tools/examples"
target="_blank"
rel="noopener noreferrer"
>
<AppWindowMacIcon className="size-4" />
Examples
</a>
</Button>
<Button asChild variant="ghost">
<a
href="https://jazz.tools/status"
target="_blank"
rel="noopener noreferrer"
>
<GlobeIcon className="size-4" />
Status
</a>
</Button>
<Button asChild variant="ghost">
<a
href="https://jazz.tools/showcase"
target="_blank"
rel="noopener noreferrer"
>
<WrenchIcon className="size-4" />
Built with Jazz
</a>
</Button>
</footer>
</div>
);
}

View File

@@ -1,14 +0,0 @@
import { UserSettings } from "@/components/user-settings";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Settings | Jazz Example: Better Auth",
};
export default function SettingsPage() {
return (
<div className="max-w-screen-md w-full mx-auto px-4">
<UserSettings />
</div>
);
}

View File

@@ -1,10 +0,0 @@
import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";
export const { GET, POST } = (() => {
if (!process.env.NEXT_PUBLIC_AUTH_BASE_URL) {
return toNextJsHandler(auth.handler);
} else {
return { GET: undefined, POST: undefined };
}
})();

View File

@@ -1,10 +0,0 @@
import { ForgotPasswordForm } from "@/components/forgot-password-form";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Forgot password | Jazz Example: Better Auth",
};
export default function ForgotPasswordPage() {
return <ForgotPasswordForm />;
}

View File

@@ -1,23 +0,0 @@
import Image from "next/image";
import Link from "next/link";
interface Props {
children: React.ReactNode;
}
export default function AuthLayout({ children }: Props) {
return (
<div className="bg-muted flex min-h-svh flex-col items-center justify-center gap-6 p-6 md:p-10">
<div className="flex w-full max-w-sm flex-col gap-6">
<Link
href="/"
className="flex items-center gap-2 self-center font-medium"
>
<Image src="/jazz.svg" alt="Jazz Logo" width={24} height={24} />
Jazz BetterAuth Demo
</Link>
{children}
</div>
</div>
);
}

View File

@@ -1,10 +0,0 @@
import { ResetPasswordForm } from "@/components/reset-password-form";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Reset password | Jazz Example: Better Auth",
};
export default function ResetPasswordPage() {
return <ResetPasswordForm />;
}

View File

@@ -1,11 +0,0 @@
import { SigninForm } from "@/components/signin-form";
import type { Metadata } from "next";
import { ssoProviders } from "../sso-providers";
export const metadata: Metadata = {
title: "Sign in | Jazz Example: Better Auth",
};
export default function LoginPage() {
return <SigninForm providers={ssoProviders} />;
}

View File

@@ -1,11 +0,0 @@
import { SignupForm } from "@/components/signup-form";
import type { Metadata } from "next";
import { ssoProviders } from "../sso-providers";
export const metadata: Metadata = {
title: "Sign up | Jazz Example: Better Auth",
};
export default function LoginPage() {
return <SignupForm providers={ssoProviders} />;
}

View File

@@ -1,4 +0,0 @@
import type { SSOProviderType } from "jazz-react-auth-betterauth";
// Fill in the providers you want to use
export const ssoProviders: SSOProviderType[] = ["github"];

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -1,123 +0,0 @@
@import "tailwindcss";
@import "tw-animate-css";
@custom-variant dark (&:is(.dark *));
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--radius: 0.625rem;
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.145 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.145 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.985 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.396 0.141 25.723);
--destructive-foreground: oklch(0.637 0.237 25.331);
--border: oklch(0.269 0 0);
--input: oklch(0.269 0 0);
--ring: oklch(0.439 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(0.269 0 0);
--sidebar-ring: oklch(0.439 0 0);
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
}

View File

@@ -1,26 +0,0 @@
import { JazzAndAuth } from "@/components/JazzAndAuth";
import { Toaster } from "@/components/ui/sonner";
import type { Metadata } from "next";
import "./globals.css";
export const metadata: Metadata = {
title: "Jazz Example: Better Auth",
description: "Jazz example application demonstrating Better Auth integration",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className="antialiased">
<JazzAndAuth>
{children}
<Toaster richColors />
</JazzAndAuth>
</body>
</html>
);
}

View File

@@ -1,33 +0,0 @@
"use client";
import { JazzProvider } from "jazz-react";
import { AuthProvider } from "jazz-react-auth-betterauth";
import { type ReactNode, lazy } from "react";
const JazzDevTools =
process.env.NODE_ENV === "production"
? () => null
: lazy(() =>
import("jazz-inspector").then((res) => ({
default: res.JazzInspector,
})),
);
export function JazzAndAuth({ children }: { children: ReactNode }) {
return (
<JazzProvider
sync={{
peer: "wss://cloud.jazz.tools/?key=betterauth-example@garden.co",
}}
>
<AuthProvider
options={{
baseURL: process.env.NEXT_PUBLIC_AUTH_BASE_URL,
}}
>
{children}
</AuthProvider>
<JazzDevTools />
</JazzProvider>
);
}

View File

@@ -1,137 +0,0 @@
import { Button } from "@/components/ui/button";
import {
SiApple,
SiDiscord,
SiDropbox,
SiFacebook,
SiGithub,
SiGitlab,
SiGoogle,
SiKick,
SiReddit,
SiRoblox,
SiSpotify,
SiTiktok,
SiTwitch,
SiVk,
SiX,
SiZoom,
} from "@icons-pack/react-simple-icons";
import { type SSOProviderType, useAuth } from "jazz-react-auth-betterauth";
import { useRouter } from "next/navigation";
import type { ReactNode } from "react";
import { toast } from "sonner";
interface SocialProvider {
name: string;
icon?: ReactNode;
}
const socialProviderMap: Record<SSOProviderType, SocialProvider> = {
github: {
name: "GitHub",
icon: <SiGithub />,
},
google: {
name: "Google",
icon: <SiGoogle />,
},
apple: {
name: "Apple",
icon: <SiApple />,
},
discord: {
name: "Discord",
icon: <SiDiscord />,
},
facebook: {
name: "Facebook",
icon: <SiFacebook />,
},
microsoft: {
name: "Microsoft",
},
twitter: {
name: "X",
icon: <SiX />,
},
dropbox: {
name: "Dropbox",
icon: <SiDropbox />,
},
linkedin: {
name: "LinkedIn",
},
gitlab: {
name: "GitLab",
icon: <SiGitlab />,
},
kick: {
name: "Kick",
icon: <SiKick />,
},
tiktok: {
name: "TikTok",
icon: <SiTiktok />,
},
twitch: {
name: "Twitch",
icon: <SiTwitch />,
},
vk: {
name: "VK",
icon: <SiVk />,
},
zoom: {
name: "Zoom",
icon: <SiZoom />,
},
roblox: {
name: "Roblox",
icon: <SiRoblox />,
},
reddit: {
name: "Reddit",
icon: <SiReddit />,
},
spotify: {
name: "Spotify",
icon: <SiSpotify />,
},
};
interface Props {
provider: SSOProviderType;
}
export function SSOButton({ provider }: Props) {
const auth = useAuth();
const router = useRouter();
return (
<Button
type="button"
variant="outline"
onClick={() => {
auth.authClient.signIn.social(
{
provider,
},
{
onSuccess: () => {
router.push("/");
},
onError: (error) => {
toast.error("Error", {
description: error.error.message,
});
},
},
);
}}
>
{socialProviderMap[provider].icon}
Continue with {socialProviderMap[provider].name}
</Button>
);
}

View File

@@ -1,85 +0,0 @@
"use client";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { useAuth } from "jazz-react-auth-betterauth";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { toast } from "sonner";
export function ForgotPasswordForm() {
const router = useRouter();
const [email, setEmail] = useState("");
const auth = useAuth();
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
auth.authClient.forgetPassword(
{ email, redirectTo: `${window.location.origin}/auth/reset-password` },
{
onSuccess: () => {
toast.success("Email sent");
},
onError: (error) => {
toast.error("Error", {
description: error.error.message,
});
},
},
);
};
return (
<div className="flex flex-col gap-6">
<Card>
<CardHeader className="text-center">
<CardTitle className="text-xl">Recover password</CardTitle>
<CardDescription>
Enter your email to receive a link to reset your password
</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit}>
<div className="grid gap-6">
<div className="grid gap-6">
<div className="grid gap-3">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
placeholder="you@example.com"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<Button type="submit" className="w-full">
Recover password
</Button>
</div>
<div className="text-center text-sm">
Back to{" "}
<Link
href="/auth/sign-in"
className="underline underline-offset-4"
>
Sign in
</Link>
</div>
</div>
</form>
</CardContent>
</Card>
</div>
);
}

View File

@@ -1,55 +0,0 @@
"use client";
import { Button } from "@/components/ui/button";
import { useAccount, useIsAuthenticated } from "jazz-react";
import { useAuth } from "jazz-react-auth-betterauth";
import { Account } from "jazz-tools";
import Image from "next/image";
import Link from "next/link";
import { useCallback } from "react";
export function Navbar() {
const { authClient } = useAuth();
const { logOut } = useAccount(Account, { resolve: { profile: {} } });
const isAuthenticated = useIsAuthenticated();
const signOut = useCallback(() => {
authClient.signOut().catch(console.error).finally(logOut);
}, [logOut, authClient]);
return (
<header className="absolute p-4 top-0 left-0 w-full z-10 flex justify-between">
<nav className="flex gap-4">
<Link href="/">
<Image
src="/jazz-logo.svg"
alt="Jazz logo"
width={96}
height={96}
priority
/>
</Link>
{isAuthenticated && (
<Button asChild variant="link">
<Link href="/settings">Settings</Link>
</Button>
)}
</nav>
<nav className="flex gap-4">
{isAuthenticated ? (
<Button onClick={signOut}>Sign out</Button>
) : (
<>
<Button asChild variant="secondary">
<Link href="/auth/sign-in">Sign in</Link>
</Button>
<Button asChild>
<Link href="/auth/sign-up">Sign up</Link>
</Button>
</>
)}
</nav>
</header>
);
}

View File

@@ -1,108 +0,0 @@
"use client";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { useAuth } from "jazz-react-auth-betterauth";
import Link from "next/link";
import { useRouter, useSearchParams } from "next/navigation";
import { useState } from "react";
import { toast } from "sonner";
export function ResetPasswordForm() {
const router = useRouter();
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const auth = useAuth();
const searchParams = useSearchParams();
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const token = searchParams.get("token");
if (password !== confirmPassword) {
toast.error("Passwords do not match");
return;
}
if (!token) {
toast.error("Invalid token");
return;
}
auth.authClient.resetPassword(
{ newPassword: password, token },
{
onSuccess: () => {
toast.success("Password successfully updated");
router.push("/auth/sign-in");
},
onError: (error) => {
toast.error("Error", {
description: error.error.message,
});
},
},
);
};
return (
<div className="flex flex-col gap-6">
<Card>
<CardHeader className="text-center">
<CardTitle className="text-xl">Reset password</CardTitle>
<CardDescription>Enter your new password</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit}>
<div className="grid gap-6">
<div className="grid gap-6">
<div className="grid gap-3">
<Label htmlFor="password">New password</Label>
<Input
id="password"
type="password"
required
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<div className="grid gap-3">
<Label htmlFor="confirmPassword">Confirm password</Label>
<Input
id="confirmPassword"
type="password"
required
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
/>
</div>
<Button type="submit" className="w-full">
Set password
</Button>
</div>
<div className="text-center text-sm">
Back to{" "}
<Link
href="/auth/sign-in"
className="underline underline-offset-4"
>
Sign in
</Link>
</div>
</div>
</form>
</CardContent>
</Card>
</div>
);
}

View File

@@ -1,124 +0,0 @@
"use client";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { type SSOProviderType, useAuth } from "jazz-react-auth-betterauth";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { toast } from "sonner";
import { SSOButton } from "./SSOButton";
interface Props {
providers: SSOProviderType[];
}
export function SigninForm({ providers }: Props) {
const router = useRouter();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const auth = useAuth();
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
await auth.authClient.signIn.email(
{ email, password },
{
onSuccess: async () => {
await auth.logIn();
router.push("/");
},
onError: (error) => {
toast.error("Error", {
description: error.error.message,
});
},
},
);
};
return (
<div className="flex flex-col gap-6">
<Card>
<CardHeader className="text-center">
<CardTitle className="text-xl">Welcome back</CardTitle>
<CardDescription>
Sign in with one of the following providers
</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit}>
<div className="grid gap-6">
{providers.length > 0 && (
<>
<div className="flex flex-col gap-4">
{providers?.map((provider) => (
<SSOButton key={provider} provider={provider} />
))}
</div>
<div className="after:border-border relative text-center text-sm after:absolute after:inset-0 after:top-1/2 after:z-0 after:flex after:items-center after:border-t">
<span className="bg-card text-muted-foreground relative z-10 px-2">
Or continue with
</span>
</div>
</>
)}
<div className="grid gap-6">
<div className="grid gap-3">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
placeholder="you@example.com"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div className="grid gap-3">
<div className="flex items-center justify-between">
<Label htmlFor="password">Password</Label>
<Link
href="/auth/forgot-password"
className="ml-auto inline-block text-sm underline-offset-4 hover:underline"
>
Forgot your password?
</Link>
</div>
<Input
id="password"
type="password"
required
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<Button type="submit" className="w-full">
Sign in
</Button>
</div>
<div className="text-center text-sm">
Don&apos;t have an account?{" "}
<Link
href="/auth/sign-up"
className="underline underline-offset-4"
>
Sign up
</Link>
</div>
</div>
</form>
</CardContent>
</Card>
</div>
);
}

View File

@@ -1,151 +0,0 @@
"use client";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { type SSOProviderType, useAuth } from "jazz-react-auth-betterauth";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { toast } from "sonner";
import { SSOButton } from "./SSOButton";
interface Props {
providers: SSOProviderType[];
}
export function SignupForm({ providers }: Props) {
const router = useRouter();
const auth = useAuth();
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (password !== confirmPassword) {
toast.error("Error", {
description: "Passwords do not match",
});
return;
}
await auth.authClient.signUp.email(
{
email,
password,
name,
},
{
onSuccess: async () => {
await auth.signIn();
router.push("/");
},
onError: (error) => {
toast.error("Sign up error", {
description: error.error.message,
});
},
},
);
};
return (
<div className="flex flex-col gap-6">
<Card>
<CardHeader className="text-center">
<CardTitle className="text-xl">Welcome</CardTitle>
<CardDescription>
Sign up with one of the following providers
</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit}>
<div className="grid gap-6">
{providers.length > 0 && (
<>
<div className="flex flex-col gap-4">
{providers?.map((provider) => (
<SSOButton key={provider} provider={provider} />
))}
</div>
<div className="after:border-border relative text-center text-sm after:absolute after:inset-0 after:top-1/2 after:z-0 after:flex after:items-center after:border-t">
<span className="bg-card text-muted-foreground relative z-10 px-2">
Or continue with
</span>
</div>
</>
)}
<div className="grid gap-6">
<div className="grid gap-3">
<Label htmlFor="name">Name</Label>
<Input
id="name"
type="text"
placeholder="John Doe"
required
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
<div className="grid gap-3">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
placeholder="you@example.com"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div className="grid gap-3">
<Label htmlFor="password">Password</Label>
<Input
id="password"
type="password"
placeholder="********"
required
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<div className="grid gap-3">
<Label htmlFor="confirmPassword">Confirm password</Label>
<Input
id="confirmPassword"
type="password"
required
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
/>
</div>
<Button type="submit" className="w-full">
Sign up
</Button>
</div>
<div className="text-center text-sm">
Already have an account?{" "}
<Link
href="/auth/sign-in"
className="underline underline-offset-4"
>
Sign in
</Link>
</div>
</div>
</form>
</CardContent>
</Card>
</div>
);
}

View File

@@ -1,59 +0,0 @@
import { Slot } from "@radix-ui/react-slot";
import { type VariantProps, cva } from "class-variance-authority";
import * as React from "react";
import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
destructive:
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
outline:
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
secondary:
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
ghost:
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2 has-[>svg]:px-3",
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
icon: "size-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
);
function Button({
className,
variant,
size,
asChild = false,
...props
}: React.ComponentProps<"button"> &
VariantProps<typeof buttonVariants> & {
asChild?: boolean;
}) {
const Comp = asChild ? Slot : "button";
return (
<Comp
data-slot="button"
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
);
}
export { Button, buttonVariants };

View File

@@ -1,92 +0,0 @@
import * as React from "react";
import { cn } from "@/lib/utils";
function Card({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card"
className={cn(
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
className,
)}
{...props}
/>
);
}
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-header"
className={cn(
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
className,
)}
{...props}
/>
);
}
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-title"
className={cn("leading-none font-semibold", className)}
{...props}
/>
);
}
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-description"
className={cn("text-muted-foreground text-sm", className)}
{...props}
/>
);
}
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-action"
className={cn(
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
className,
)}
{...props}
/>
);
}
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-content"
className={cn("px-6", className)}
{...props}
/>
);
}
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-footer"
className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
{...props}
/>
);
}
export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardAction,
CardDescription,
CardContent,
};

View File

@@ -1,21 +0,0 @@
import * as React from "react";
import { cn } from "@/lib/utils";
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
return (
<input
type={type}
data-slot="input"
className={cn(
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
className,
)}
{...props}
/>
);
}
export { Input };

View File

@@ -1,22 +0,0 @@
import * as LabelPrimitive from "@radix-ui/react-label";
import * as React from "react";
import { cn } from "@/lib/utils";
function Label({
className,
...props
}: React.ComponentProps<typeof LabelPrimitive.Root>) {
return (
<LabelPrimitive.Root
data-slot="label"
className={cn(
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
className,
)}
{...props}
/>
);
}
export { Label };

View File

@@ -1,22 +0,0 @@
"use client";
import { Toaster as Sonner, type ToasterProps } from "sonner";
const Toaster = ({ ...props }: ToasterProps) => {
return (
<Sonner
theme="light"
className="toaster group"
style={
{
"--normal-bg": "var(--popover)",
"--normal-text": "var(--popover-foreground)",
"--normal-border": "var(--border)",
} as React.CSSProperties
}
{...props}
/>
);
};
export { Toaster };

View File

@@ -1,60 +0,0 @@
"use client";
import { Button } from "@/components/ui/button";
import { useAccount, useIsAuthenticated } from "jazz-react";
import { useAuth } from "jazz-react-auth-betterauth";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { toast } from "sonner";
export function UserSettings() {
const router = useRouter();
const { authClient } = useAuth();
const { logOut } = useAccount();
const isAuthenticated = useIsAuthenticated();
if (!isAuthenticated) {
return (
<div className="flex flex-col gap-8">
<h1 className="text-center text-2xl">Forbidden</h1>
<p className="text-center text-sm text-muted-foreground">
Please{" "}
<Link href="/auth/sign-in" className="underline text-primary">
sign in
</Link>{" "}
to access this page.
</p>
</div>
);
}
return (
<>
<div className="flex flex-col gap-8">
<h1 className="text-4xl font-semibold">Settings</h1>
<Button
variant="destructive"
className="relative"
type="button"
onClick={async (e) => {
e.preventDefault();
authClient.deleteUser(undefined, {
onSuccess: () => {
logOut();
router.push("/");
},
onError: (error) => {
toast.error("Error", {
description: error.error.message,
});
},
});
}}
>
Delete account
</Button>
</div>
</>
);
}

View File

@@ -1,50 +0,0 @@
import { betterAuth } from "better-auth";
import { getMigrations } from "better-auth/db";
import Database from "better-sqlite3";
import { jazzPlugin } from "jazz-betterauth-server-plugin";
import { socialProviders } from "./socialProviders";
export const auth = await (async () => {
// Configure Better Auth server
const auth = betterAuth({
appName: "Jazz Example: Better Auth",
database: new Database("sqlite.db"),
emailAndPassword: {
enabled: true,
async sendResetPassword({ url }) {
// Here we can send an email to the user with the reset password link
console.log("****** RESET PASSWORD ******");
console.log("navigate to", url, "to reset your password");
console.log("******");
},
},
emailVerification: {
async sendVerificationEmail(data) {
console.error("Not implemented");
},
},
socialProviders,
user: {
deleteUser: {
enabled: true,
},
},
plugins: [jazzPlugin()],
databaseHooks: {
user: {
create: {
async after(user) {
// Here we can send a welcome email to the user
console.error("Not implemented");
},
},
},
},
});
// Run database migrations
const migrations = await getMigrations(auth.options);
await migrations.runMigrations();
return auth;
})();

View File

@@ -1,186 +0,0 @@
const apple =
process.env.APPLE_CLIENT_ID &&
process.env.APPLE_CLIENT_SECRET &&
process.env.APPLE_APP_BUNDLE_IDENTIFIER
? {
apple: {
clientId: process.env.APPLE_CLIENT_ID as string,
clientSecret: process.env.APPLE_CLIENT_SECRET as string,
// For native iOS
appBundleIdentifier: process.env
.APPLE_APP_BUNDLE_IDENTIFIER as string,
},
}
: undefined;
const discord =
process.env.DISCORD_CLIENT_ID && process.env.DISCORD_CLIENT_SECRET
? {
discord: {
clientId: process.env.DISCORD_CLIENT_ID as string,
clientSecret: process.env.DISCORD_CLIENT_SECRET as string,
},
}
: undefined;
const facebook =
process.env.FACEBOOK_CLIENT_ID && process.env.FACEBOOK_CLIENT_SECRET
? {
facebook: {
clientId: process.env.FACEBOOK_CLIENT_ID as string,
clientSecret: process.env.FACEBOOK_CLIENT_SECRET as string,
},
}
: undefined;
const github =
process.env.GITHUB_CLIENT_ID && process.env.GITHUB_CLIENT_SECRET
? {
github: {
clientId: process.env.GITHUB_CLIENT_ID as string,
clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
},
}
: undefined;
const google =
process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET
? {
google: {
clientId: process.env.GOOGLE_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
},
}
: undefined;
const kick =
process.env.KICK_CLIENT_ID && process.env.KICK_CLIENT_SECRET
? {
kick: {
clientId: process.env.KICK_CLIENT_ID as string,
clientSecret: process.env.KICK_CLIENT_SECRET as string,
},
}
: undefined;
const microsoft =
process.env.MICROSOFT_CLIENT_ID && process.env.MICROSOFT_CLIENT_SECRET
? {
microsoft: {
clientId: process.env.MICROSOFT_CLIENT_ID as string,
clientSecret: process.env.MICROSOFT_CLIENT_SECRET as string,
tenantId: "common",
requireSelectAccount: true,
},
}
: undefined;
const tiktok =
process.env.TIKTOK_CLIENT_ID &&
process.env.TIKTOK_CLIENT_SECRET &&
process.env.TIKTOK_CLIENT_KEY
? {
tiktok: {
clientId: process.env.TIKTOK_CLIENT_ID,
clientSecret: process.env.TIKTOK_CLIENT_SECRET,
clientKey: process.env.TIKTOK_CLIENT_KEY,
},
}
: undefined;
const twitch =
process.env.TWITCH_CLIENT_ID && process.env.TWITCH_CLIENT_SECRET
? {
twitch: {
clientId: process.env.TWITCH_CLIENT_ID as string,
clientSecret: process.env.TWITCH_CLIENT_SECRET as string,
},
}
: undefined;
const twitter =
process.env.TWITTER_CLIENT_ID && process.env.TWITTER_CLIENT_SECRET
? {
twitter: {
clientId: process.env.TWITTER_CLIENT_ID,
clientSecret: process.env.TWITTER_CLIENT_SECRET,
},
}
: undefined;
const dropbox =
process.env.DROPBOX_CLIENT_ID && process.env.DROPBOX_CLIENT_SECRET
? {
dropbox: {
clientId: process.env.DROPBOX_CLIENT_ID as string,
clientSecret: process.env.DROPBOX_CLIENT_SECRET as string,
},
}
: undefined;
const linkedin =
process.env.LINKEDIN_CLIENT_ID && process.env.LINKEDIN_CLIENT_SECRET
? {
linkedin: {
clientId: process.env.LINKEDIN_CLIENT_ID as string,
clientSecret: process.env.LINKEDIN_CLIENT_SECRET as string,
},
}
: undefined;
const gitlab =
process.env.GITLAB_CLIENT_ID &&
process.env.GITLAB_CLIENT_SECRET &&
process.env.GITLAB_ISSUER
? {
gitlab: {
clientId: process.env.GITLAB_CLIENT_ID as string,
clientSecret: process.env.GITLAB_CLIENT_SECRET as string,
issuer: process.env.GITLAB_ISSUER as string,
},
}
: undefined;
const reddit =
process.env.REDDIT_CLIENT_ID && process.env.REDDIT_CLIENT_SECRET
? {
reddit: {
clientId: process.env.REDDIT_CLIENT_ID as string,
clientSecret: process.env.REDDIT_CLIENT_SECRET as string,
},
}
: undefined;
const roblox =
process.env.ROBLOX_CLIENT_ID && process.env.ROBLOX_CLIENT_SECRET
? {
roblox: {
clientId: process.env.ROBLOX_CLIENT_ID,
clientSecret: process.env.ROBLOX_CLIENT_SECRET,
},
}
: undefined;
const spotify =
process.env.SPOTIFY_CLIENT_ID && process.env.SPOTIFY_CLIENT_SECRET
? {
spotify: {
clientId: process.env.SPOTIFY_CLIENT_ID as string,
clientSecret: process.env.SPOTIFY_CLIENT_SECRET as string,
},
}
: undefined;
const vk =
process.env.VK_CLIENT_ID && process.env.VK_CLIENT_SECRET
? {
vk: {
clientId: process.env.VK_CLIENT_ID as string,
clientSecret: process.env.VK_CLIENT_SECRET as string,
},
}
: undefined;
export const socialProviders = {
...(apple && { ...apple }),
...(discord && { ...discord }),
...(facebook && { ...facebook }),
...(github && { ...github }),
...(google && { ...google }),
...(kick && { ...kick }),
...(microsoft && { ...microsoft }),
...(tiktok && { ...tiktok }),
...(twitch && { ...twitch }),
...(twitter && { ...twitter }),
...(dropbox && { ...dropbox }),
...(linkedin && { ...linkedin }),
...(gitlab && { ...gitlab }),
...(reddit && { ...reddit }),
...(roblox && { ...roblox }),
...(spotify && { ...spotify }),
...(vk && { ...vk }),
};

View File

@@ -1,6 +0,0 @@
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

View File

@@ -1,28 +0,0 @@
import { randomBytes } from "node:crypto";
import { test } from "@playwright/test";
import { HomePage } from "./pages/HomePage";
test("should sign up, sign in, and logout", async ({ page }) => {
const username = randomBytes(4).toString("hex");
const email = `${username}@example.com`;
const password = randomBytes(8).toString("hex");
// Sign up
await page.goto("/");
const homePage = new HomePage(page);
await homePage.expectLoggedOut();
await homePage.signUpLink.click();
await homePage.signUpEmail(username, email, password);
await homePage.expectLoggedIn(username);
// Log out & sign in
await homePage.logout();
await homePage.expectLoggedOut();
await homePage.signInLink.click();
await homePage.signInEmail(email, password);
await homePage.expectLoggedIn(username);
// Logout
await homePage.logout();
await homePage.expectLoggedOut();
});

View File

@@ -1,76 +0,0 @@
import { type Page, expect } from "@playwright/test";
export class HomePage {
constructor(public page: Page) {}
usernameInput = this.page.getByRole("textbox", {
name: "Name",
exact: true,
});
emailInput = this.page.getByRole("textbox", {
name: "Email",
exact: true,
});
passwordInput = this.page.getByRole("textbox", {
name: "Password",
exact: true,
});
confirmPasswordInput = this.page.getByRole("textbox", {
name: "Confirm password",
exact: true,
});
signUpButton = this.page.getByRole("button", {
name: "Sign up",
exact: true,
});
signInButton = this.page.getByRole("button", {
name: "Sign in",
exact: true,
});
signUpLink = this.page.getByRole("link", {
name: "Sign up",
exact: true,
});
signInLink = this.page.getByRole("link", {
name: "Sign in",
exact: true,
});
logoutButton = this.page.getByRole("button", {
name: "Sign out",
exact: true,
});
async signUpEmail(name: string, email: string, password: string) {
await this.usernameInput.fill(name);
await this.emailInput.fill(email);
await this.passwordInput.fill(password);
await this.confirmPasswordInput.fill(password);
await this.signUpButton.click();
}
async signInEmail(email: string, password: string) {
await this.emailInput.fill(email);
await this.passwordInput.fill(password);
await this.signInButton.click();
}
async logout() {
await this.logoutButton.click();
}
async expectLoggedIn(name?: string) {
await expect(this.logoutButton).toBeVisible();
await expect(this.signInLink).not.toBeVisible();
await expect(this.signUpLink).not.toBeVisible();
if (name) {
await expect(this.page.getByText(`Signed in as ${name}`)).toBeVisible();
}
}
async expectLoggedOut() {
await expect(this.logoutButton).not.toBeVisible();
await expect(this.signInLink).toBeVisible();
await expect(this.signUpLink).toBeVisible();
await expect(this.page.getByText(`Anonymous user`)).toBeVisible();
}
}

View File

@@ -1,27 +0,0 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

View File

@@ -1,427 +1,5 @@
# chat-rn-expo-clerk
## 1.0.137
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-expo@0.14.14
- jazz-react-native-media-images@0.14.14
## 1.0.136
### Patch Changes
- jazz-expo@0.14.13
## 1.0.135
### Patch Changes
- jazz-expo@0.14.12
## 1.0.134
### Patch Changes
- Updated dependencies [98d697f]
- jazz-expo@0.14.11
## 1.0.133
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-react-native-media-images@0.14.10
- jazz-tools@0.14.10
- jazz-expo@0.14.10
## 1.0.132
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-expo@0.14.9
- jazz-react-native-media-images@0.14.9
## 1.0.131
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-expo@0.14.8
- jazz-react-native-media-images@0.14.8
## 1.0.130
### Patch Changes
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-expo@0.14.7
- jazz-react-native-media-images@0.14.7
## 1.0.129
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-expo@0.14.6
- jazz-react-native-media-images@0.14.6
## 1.0.128
### Patch Changes
- Updated dependencies [91cbb2f]
- Updated dependencies [20b3d88]
- jazz-tools@0.14.5
- jazz-expo@0.14.5
- jazz-react-native-media-images@0.14.5
## 1.0.127
### Patch Changes
- Updated dependencies [011af55]
- jazz-tools@0.14.4
- jazz-expo@0.14.4
- jazz-react-native-media-images@0.14.4
## 1.0.126
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-expo@0.14.2
- jazz-react-native-media-images@0.14.2
## 1.0.125
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-expo@0.14.1
- jazz-react-native-media-images@0.14.1
## 1.0.124
### Patch Changes
- Updated dependencies [5835ed1]
- jazz-tools@0.14.0
- jazz-expo@0.14.0
- jazz-react-native-media-images@0.14.0
## 1.0.123
### Patch Changes
- jazz-expo@0.13.32
## 1.0.122
### Patch Changes
- Updated dependencies [e5b170f]
- jazz-tools@0.13.31
- jazz-expo@0.13.31
- jazz-react-native-media-images@0.13.31
## 1.0.121
### Patch Changes
- jazz-expo@0.13.30
- jazz-tools@0.13.30
- jazz-react-native-media-images@0.13.30
## 1.0.120
### Patch Changes
- jazz-expo@0.13.29
- jazz-tools@0.13.29
- jazz-react-native-media-images@0.13.29
## 1.0.119
### Patch Changes
- jazz-expo@0.13.28
- jazz-tools@0.13.28
- jazz-react-native-media-images@0.13.28
## 1.0.118
### Patch Changes
- jazz-expo@0.13.27
- jazz-tools@0.13.27
- jazz-react-native-media-images@0.13.27
## 1.0.117
### Patch Changes
- Updated dependencies [ff846d9]
- jazz-tools@0.13.26
- jazz-expo@0.13.26
- jazz-react-native-media-images@0.13.26
## 1.0.116
### Patch Changes
- jazz-expo@0.13.25
- jazz-tools@0.13.25
- jazz-react-native-media-images@0.13.25
## 1.0.115
### Patch Changes
- Updated dependencies [02a240c]
- jazz-tools@0.13.23
- jazz-expo@0.13.23
- jazz-react-native-media-images@0.13.23
## 1.0.114
### Patch Changes
- jazz-expo@0.13.22
## 1.0.113
### Patch Changes
- jazz-expo@0.13.21
- jazz-tools@0.13.21
- jazz-react-native-media-images@0.13.21
## 1.0.112
### Patch Changes
- Updated dependencies [439f0fe]
- jazz-tools@0.13.20
- jazz-expo@0.13.20
- jazz-react-native-media-images@0.13.20
## 1.0.111
### Patch Changes
- Updated dependencies [80530a4]
- jazz-tools@0.13.19
- jazz-expo@0.13.19
- jazz-react-native-media-images@0.13.19
## 1.0.110
### Patch Changes
- Updated dependencies [761759c]
- jazz-tools@0.13.18
- jazz-expo@0.13.18
- jazz-react-native-media-images@0.13.18
## 1.0.109
### Patch Changes
- jazz-expo@0.13.17
- jazz-tools@0.13.17
- jazz-react-native-media-images@0.13.17
## 1.0.108
### Patch Changes
- jazz-expo@0.13.16
- jazz-tools@0.13.16
- jazz-react-native-media-images@0.13.16
## 1.0.107
### Patch Changes
- jazz-expo@0.13.15
- jazz-tools@0.13.15
- jazz-react-native-media-images@0.13.15
## 1.0.106
### Patch Changes
- Updated dependencies [bd94012]
- jazz-expo@0.13.14
- jazz-tools@0.13.14
- jazz-react-native-media-images@0.13.14
## 1.0.105
### Patch Changes
- jazz-expo@0.13.13
- jazz-tools@0.13.13
- jazz-react-native-media-images@0.13.13
## 1.0.104
### Patch Changes
- Updated dependencies [4547525]
- jazz-tools@0.13.12
- jazz-expo@0.13.12
- jazz-react-native-media-images@0.13.12
## 1.0.103
### Patch Changes
- Updated dependencies [17273a6]
- jazz-tools@0.13.11
- jazz-expo@0.13.11
- jazz-react-native-media-images@0.13.11
## 1.0.102
### Patch Changes
- jazz-expo@0.13.10
- jazz-tools@0.13.10
- jazz-react-native-media-images@0.13.10
## 1.0.101
### Patch Changes
- Updated dependencies [a6cf01f]
- jazz-tools@0.13.9
- jazz-expo@0.13.9
- jazz-react-native-media-images@0.13.9
## 1.0.100
### Patch Changes
- jazz-expo@0.13.8
## 1.0.99
### Patch Changes
- Updated dependencies [bc3d7bb]
- jazz-tools@0.13.7
- jazz-expo@0.13.7
- jazz-react-native-media-images@0.13.7
## 1.0.98
### Patch Changes
- Updated dependencies [fe6f561]
- jazz-tools@0.13.5
- jazz-expo@0.13.5
- jazz-react-native-media-images@0.13.5
## 1.0.97
### Patch Changes
- Updated dependencies [3129982]
- Updated dependencies [3129982]
- jazz-expo@0.13.4
- jazz-tools@0.13.4
- jazz-react-native-media-images@0.13.4
## 1.0.96
### Patch Changes
- Updated dependencies [12f8bfa]
- Updated dependencies [bd57177]
- jazz-tools@0.13.3
- jazz-expo@0.13.3
- jazz-react-native-media-images@0.13.3
## 1.0.95
### Patch Changes
- jazz-expo@0.13.2
- jazz-tools@0.13.2
- jazz-react-native-media-images@0.13.2
## 1.0.94
### Patch Changes
- Updated dependencies [63a7aa0]
- jazz-expo@0.13.1
## 1.0.93
### Patch Changes
- Updated dependencies [bce3bcc]
- Updated dependencies [afd1374]
- jazz-expo@0.13.0
- jazz-tools@0.13.0
- jazz-react-native-media-images@0.13.0
## 1.0.92
### Patch Changes
- jazz-react-native@0.12.2
- jazz-react-native-auth-clerk@0.12.2
- jazz-tools@0.12.2
- jazz-react-native-media-images@0.12.2
## 1.0.91
### Patch Changes
- jazz-react-native@0.12.1
- jazz-react-native-auth-clerk@0.12.1
- jazz-tools@0.12.1
- jazz-react-native-media-images@0.12.1
## 1.0.90
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react-native@0.12.0
- jazz-react-native-auth-clerk@0.12.0
- jazz-react-native-media-images@0.12.0
## 1.0.89
### Patch Changes
- jazz-react-native@0.11.8
- jazz-react-native-auth-clerk@0.11.8
- jazz-tools@0.11.8
- jazz-react-native-media-images@0.11.8
## 1.0.88
### Patch Changes

View File

@@ -17,7 +17,7 @@ Next, navigate to the specific example project and run the following commands:
```bash
pnpm expo prebuild
pnpx pod-install
npx pod-install
pnpm expo run:ios
```

View File

@@ -23,7 +23,6 @@
},
"package": "com.jazz.chatrnclerk"
},
"newArchEnabled": true,
"plugins": [
"expo-secure-store",
"expo-font",

View File

@@ -2,40 +2,29 @@ import "../global.css";
import { ClerkLoaded, ClerkProvider } from "@clerk/clerk-expo";
import { secureStore } from "@clerk/clerk-expo/secure-store";
import { useFonts } from "expo-font";
import { Slot, useRouter, useSegments } from "expo-router";
import { Slot } from "expo-router";
import * as SplashScreen from "expo-splash-screen";
import { useIsAuthenticated, useJazzContext } from "jazz-expo";
import React, { useEffect } from "react";
import { tokenCache } from "../cache";
import { JazzAndAuth } from "../src/auth-context";
SplashScreen.preventAutoHideAsync();
function InitialLayout() {
const isAuthenticated = useIsAuthenticated();
const segments = useSegments();
const router = useRouter();
useEffect(() => {
const inAuthGroup = segments[0] === "(auth)";
if (isAuthenticated && inAuthGroup) {
router.replace("/chat");
} else if (!isAuthenticated && !inAuthGroup) {
router.replace("/");
}
SplashScreen.hideAsync();
}, [isAuthenticated, segments, router]);
return <Slot />;
}
export default function RootLayout() {
const [fontsLoaded] = useFonts({
const [loaded] = useFonts({
SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
});
useEffect(() => {
if (loaded) {
SplashScreen.hideAsync();
}
}, [loaded]);
if (!loaded) {
return null;
}
const publishableKey = process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY;
if (!publishableKey) {
@@ -44,17 +33,6 @@ export default function RootLayout() {
);
}
useEffect(() => {
if (fontsLoaded) {
} else {
SplashScreen.preventAutoHideAsync();
}
}, [fontsLoaded]);
if (!fontsLoaded) {
return null;
}
return (
<ClerkProvider
tokenCache={tokenCache}
@@ -63,7 +41,7 @@ export default function RootLayout() {
>
<ClerkLoaded>
<JazzAndAuth>
<InitialLayout />
<Slot />
</JazzAndAuth>
</ClerkLoaded>
</ClerkProvider>

View File

@@ -7,7 +7,7 @@ import { useLocalSearchParams } from "expo-router";
import { useAccount, useCoState } from "jazz-expo";
import { ProgressiveImg } from "jazz-expo";
import { createImage } from "jazz-react-native-media-images";
import { CoPlainText, Group, Loaded } from "jazz-tools";
import { Group, ID } from "jazz-tools";
import { useEffect, useLayoutEffect, useState } from "react";
import React, {
SafeAreaView,
@@ -26,9 +26,9 @@ import React, {
export default function Conversation() {
const { chatId } = useLocalSearchParams();
const { me } = useAccount();
const [chat, setChat] = useState<Loaded<typeof Chat>>();
const [chat, setChat] = useState<Chat>();
const [message, setMessage] = useState("");
const loadedChat = useCoState(Chat, chat?.id, { resolve: { $each: true } });
const loadedChat = useCoState(Chat, chat?.id, [{}]);
const navigation = useNavigation();
const [isUploading, setIsUploading] = useState(false);
@@ -37,7 +37,7 @@ export default function Conversation() {
if (chatId === "new") {
createChat();
} else {
loadChat(chatId as string);
loadChat(chatId as ID<Chat>);
}
}, [chat]);
@@ -69,10 +69,10 @@ export default function Conversation() {
setChat(chat);
};
const loadChat = async (chatId: string) => {
const loadChat = async (chatId: ID<Chat>) => {
try {
const chat = await Chat.load(chatId);
if (chat) setChat(chat);
const chat = await Chat.load(chatId, me, []);
setChat(chat);
} catch (error) {
console.log("Error loading chat", error);
Alert.alert("Error", `Error loading chat: ${error}`);
@@ -82,12 +82,7 @@ export default function Conversation() {
const sendMessage = () => {
if (!chat) return;
if (message.trim()) {
chat.push(
Message.create(
{ text: CoPlainText.create(message, chat._owner) },
chat._owner,
),
);
chat.push(Message.create({ text: message }, { owner: chat._owner }));
setMessage("");
}
};
@@ -109,12 +104,7 @@ export default function Conversation() {
maxSize: 2048,
});
chat.push(
Message.create(
{ text: CoPlainText.create("", chat._owner), image },
chat._owner,
),
);
chat.push(Message.create({ text: "", image }, { owner: chat._owner }));
}
} catch (error) {
Alert.alert("Error", "Failed to upload image");
@@ -123,8 +113,8 @@ export default function Conversation() {
}
};
const renderMessageItem = ({ item }: { item: Loaded<typeof Message> }) => {
const isMe = item._edits.text?.by?.isMe;
const renderMessageItem = ({ item }: { item: Message }) => {
const isMe = item._edits.text.by?.isMe;
return (
<View
className={clsx(
@@ -139,7 +129,7 @@ export default function Conversation() {
isMe ? "text-right" : "text-left",
)}
>
{item._edits.text?.by?.profile?.name}
{item._edits.text.by?.profile?.name}
</Text>
) : null}
<View
@@ -175,8 +165,8 @@ export default function Conversation() {
!isMe ? "mt-2 text-gray-500" : "mt-1 text-gray-200",
)}
>
{item._edits.text?.madeAt?.getHours().toString().padStart(2, "0")}:
{item._edits.text?.madeAt?.getMinutes().toString().padStart(2, "0")}
{item._edits.text.madeAt.getHours()}:
{item._edits.text.madeAt.getMinutes()}
</Text>
</View>
</View>

View File

@@ -32,7 +32,7 @@ export default function ChatScreen() {
});
}, [navigation]);
const loadChat = async (chatId: string | "new") => {
const loadChat = async (chatId: ID<Chat> | "new") => {
router.navigate(`/chat/${chatId}`);
};
@@ -49,7 +49,7 @@ export default function ChatScreen() {
text: "Join",
onPress: (chatId) => {
if (chatId) {
loadChat(chatId);
loadChat(chatId as ID<Chat>);
} else {
Alert.alert("Error", "Chat ID cannot be empty.");
}

View File

@@ -1,67 +1,74 @@
{
"name": "chat-rn-expo-clerk",
"main": "index.js",
"version": "1.0.137",
"version": "1.0.88",
"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 prebuild && pnpx pod-install && expo run:ios",
"ios": "expo run:ios",
"web": "expo start --web",
"run:ios": "pnpm expo prebuild && npx pod-install && pnpm expo run:ios"
},
"jest": {
"preset": "jest-expo"
},
"dependencies": {
"@azure/core-asynciterator-polyfill": "^1.0.2",
"@bacons/text-decoder": "0.0.0",
"@bam.tech/react-native-image-resizer": "^3.0.11",
"@clerk/clerk-expo": "^2.2.21",
"@craftzdog/react-native-buffer": "6.0.5",
"@expo/vector-icons": "^14.1.0",
"@expo/vector-icons": "^14.0.2",
"@react-native-community/netinfo": "11.4.1",
"@react-navigation/native": "7.0.19",
"@react-navigation/native": "7.0.15",
"@react-navigation/native-stack": "7.2.1",
"clsx": "^2.0.0",
"expo": "^53.0.8",
"expo-build-properties": "~0.14.6",
"expo-clipboard": "~7.1.4",
"expo-constants": "~17.1.6",
"expo-crypto": "~14.1.4",
"expo-dev-client": "~5.1.8",
"expo-file-system": "^18.1.9",
"expo-font": "~13.3.1",
"expo-image-picker": "~16.1.4",
"expo-linking": "~7.1.4",
"expo-router": "~5.0.6",
"expo-secure-store": "~14.2.3",
"expo-splash-screen": "~0.30.8",
"expo-sqlite": "15.2.9",
"expo-status-bar": "~2.2.3",
"expo-web-browser": "~14.1.6",
"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.14",
"expo-file-system": "^18.0.4",
"expo-font": "~13.0.1",
"expo-image-picker": "~16.0.4",
"expo-linking": "~7.0.5",
"expo-router": "~4.0.11",
"expo-secure-store": "~14.0.1",
"expo-splash-screen": "~0.29.16",
"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": "19.0.0",
"react-dom": "19.0.0",
"react-native": "0.79.2",
"react-native-gesture-handler": "~2.24.0",
"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.17.5",
"react-native-safe-area-context": "5.4.0",
"react-native-screens": "4.10.0",
"react-native-reanimated": "~3.16.3",
"react-native-safe-area-context": "4.12.0",
"react-native-screens": "4.4.0",
"react-native-url-polyfill": "^2.0.0",
"react-native-web": "~0.20.0",
"react-native-web": "~0.19.13",
"readable-stream": "4.7.0"
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@types/react": "~19.0.14",
"@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.8.3"
"typescript": "~5.6.2"
},
"private": true
}

View File

@@ -1,5 +1,6 @@
import { useClerk } from "@clerk/clerk-expo";
import { JazzProviderWithClerk } from "jazz-expo/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";

View File

@@ -1,8 +1,8 @@
import { CoList, co, coField, z } from "jazz-tools";
import { CoList, CoMap, ImageDefinition, co } from "jazz-tools";
export const Message = co.map({
text: co.plainText(),
image: z.optional(co.image()),
});
export class Message extends CoMap {
text = co.string;
image = co.optional.ref(ImageDefinition);
}
export const Chat = co.list(Message);
export class Chat extends CoList.Of(co.ref(Message)) {}

View File

@@ -7,10 +7,8 @@ node_modules/
.expo/
dist/
web-build/
expo-env.d.ts
# Native
.kotlin/
*.orig.*
*.jks
*.p8
@@ -35,5 +33,6 @@ yarn-error.*
# typescript
*.tsbuildinfo
android/
ios/
ios
android

View File

@@ -1,38 +1,654 @@
# chat-rn-expo
## 1.0.84
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react-native@0.11.7
## 1.0.83
### Patch Changes
- Updated dependencies [e7c85b7]
- jazz-react-native@0.11.6
- jazz-tools@0.11.6
## 1.0.82
### Patch Changes
- jazz-react-native@0.11.5
- jazz-tools@0.11.5
## 1.0.81
### Patch Changes
- Updated dependencies [57a3dbe]
- Updated dependencies [a717754]
- Updated dependencies [a91f343]
- jazz-tools@0.11.4
- jazz-react-native@0.11.4
## 1.0.80
### Patch Changes
- jazz-react-native@0.11.3
- jazz-tools@0.11.3
## 1.0.79
### Patch Changes
- Updated dependencies [6892dc6]
- jazz-tools@0.11.2
- jazz-react-native@0.11.2
## 1.0.78
### Patch Changes
- jazz-react-native@0.11.1
## 1.0.77
### Patch Changes
- Updated dependencies [6a96d8b]
- Updated dependencies [a35249a]
- Updated dependencies [b9d194a]
- Updated dependencies [a4713df]
- Updated dependencies [34cbdc3]
- Updated dependencies [f039e8f]
- Updated dependencies [e22de9f]
- jazz-tools@0.11.0
- jazz-react-native@0.11.0
## 1.0.76
### Patch Changes
- Updated dependencies [2f99de0]
- jazz-tools@0.10.15
- jazz-react-native@0.10.15
## 1.0.75
### Patch Changes
- Updated dependencies [75211e3]
- jazz-tools@0.10.14
- jazz-react-native@0.10.14
## 1.0.74
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react-native@0.10.13
## 1.0.73
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react-native@0.10.12
## 1.0.72
### Patch Changes
- Updated dependencies [5a54e4a]
- jazz-react-native@0.10.11
## 1.0.71
### Patch Changes
- Updated dependencies [3405d8f]
- jazz-react-native@0.10.10
## 1.0.70
### Patch Changes
- Updated dependencies [2fb6428]
- jazz-tools@0.10.8
- jazz-react-native@0.10.8
## 1.0.69
### Patch Changes
- Updated dependencies [1136d9b]
- Updated dependencies [0eed228]
- jazz-react-native@0.10.7
- jazz-tools@0.10.7
## 1.0.68
### Patch Changes
- Updated dependencies [ada802b]
- jazz-tools@0.10.6
- jazz-react-native@0.10.6
## 1.0.67
### Patch Changes
- Updated dependencies [59ff77e]
- jazz-tools@0.10.5
- jazz-react-native@0.10.5
## 1.0.66
### Patch Changes
- jazz-react-native@0.10.4
- jazz-tools@0.10.4
## 1.0.65
### Patch Changes
- Updated dependencies [d8582fc]
- jazz-tools@0.10.3
- jazz-react-native@0.10.3
## 1.0.64
### Patch Changes
- jazz-react-native@0.10.2
- jazz-tools@0.10.2
## 1.0.63
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-react-native@0.10.1
## 1.0.62
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-react-native@0.10.0
- jazz-tools@0.10.0
## 1.0.61
### Patch Changes
- jazz-react-native@0.9.23
- jazz-tools@0.9.23
## 1.0.60
### Patch Changes
- jazz-react-native@0.9.22
## 1.0.59
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-react-native@0.9.21
## 1.0.58
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-react-native@0.9.20
## 1.0.57
### Patch Changes
- jazz-react-native@0.9.19
- jazz-tools@0.9.19
## 1.0.56
### Patch Changes
- jazz-react-native@0.9.18
- jazz-tools@0.9.18
## 1.0.55
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-react-native@0.9.17
## 1.0.54
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-tools@0.9.16
- jazz-react-native@0.9.16
## 1.0.53
### Patch Changes
- Updated dependencies [7491711]
- jazz-tools@0.9.15
- jazz-react-native@0.9.15
## 1.0.52
### Patch Changes
- Updated dependencies [3df93cc]
- jazz-tools@0.9.14
- jazz-react-native@0.9.14
## 1.0.51
### Patch Changes
- jazz-react-native@0.9.13
- jazz-tools@0.9.13
## 1.0.50
### Patch Changes
- jazz-react-native@0.9.12
- jazz-tools@0.9.12
## 1.0.49
### Patch Changes
- jazz-react-native@0.9.11
- jazz-tools@0.9.11
## 1.0.48
### Patch Changes
- Updated dependencies [f76274c]
- Updated dependencies [5e83864]
- jazz-react-native@0.9.10
- jazz-tools@0.9.10
## 1.0.47
### Patch Changes
- Updated dependencies [8eb9247]
- jazz-tools@0.9.9
- jazz-react-native@0.9.9
## 1.0.46
### Patch Changes
- Updated dependencies [d1d773b]
- jazz-tools@0.9.8
- jazz-react-native@0.9.8
## 1.0.45
### Patch Changes
- Updated dependencies [8a390d2]
- jazz-react-native@0.9.6
## 1.0.44
### Patch Changes
- Updated dependencies [c871912]
- jazz-react-native@0.9.5
## 1.0.43
### Patch Changes
- jazz-react-native@0.9.4
## 1.0.42
### Patch Changes
- Updated dependencies [7cd691f]
- jazz-react-native@0.9.3
## 1.0.41
### Patch Changes
- Updated dependencies [80fd3e9]
- jazz-react-native@0.9.2
## 1.0.40
### Patch Changes
- Updated dependencies [1b71969]
- jazz-tools@0.9.1
- jazz-react-native@0.9.1
## 1.0.39
### Patch Changes
- Updated dependencies [1da4d55]
- Updated dependencies [8eda792]
- Updated dependencies [1e5e3a1]
- jazz-react-native@0.9.0
- jazz-tools@0.9.0
## 1.0.38
### Patch Changes
- Updated dependencies [dc62b95]
- Updated dependencies [1de26f8]
- jazz-tools@0.8.51
- jazz-react-native@0.8.51
## 1.0.37
### Patch Changes
- jazz-react-native@0.8.50
- jazz-tools@0.8.50
## 1.0.36
### Patch Changes
- jazz-react-native@0.8.49
- jazz-tools@0.8.49
## 1.0.35
### Patch Changes
- Updated dependencies [635e824]
- Updated dependencies [0a85982]
- jazz-tools@0.8.48
- jazz-react-native@0.8.48
## 1.0.34
### Patch Changes
- Updated dependencies [33ef9c4]
- jazz-react-native@0.8.47
## 1.0.33
### Patch Changes
- Updated dependencies [ab4ffbd]
- jazz-react-native@0.8.46
## 1.0.32
### Patch Changes
- Updated dependencies [7701307]
- Updated dependencies [fa41f8e]
- Updated dependencies [88d7d9a]
- Updated dependencies [60e35ea]
- jazz-react-native@0.8.45
- jazz-tools@0.8.45
## 1.0.31
### Patch Changes
- jazz-react-native@0.8.44
- jazz-tools@0.8.44
## 1.0.30
### Patch Changes
- jazz-react-native@0.8.41
- jazz-tools@0.8.41
## 1.0.29
### Patch Changes
- Updated dependencies [0c6b0f3]
- Updated dependencies [249eecb]
- jazz-react-native@0.8.39
- jazz-tools@0.8.39
## 1.0.28
### Patch Changes
- jazz-react-native@0.8.38
- jazz-tools@0.8.38
## 1.0.27
### Patch Changes
- jazz-react-native@0.8.37
- jazz-tools@0.8.37
## 1.0.26
### Patch Changes
- Updated dependencies [c84764a]
- Updated dependencies [441fe27]
- jazz-react-native@0.8.36
- jazz-tools@0.8.36
## 1.0.25
### Patch Changes
- Updated dependencies [8b87117]
- jazz-tools@0.8.35
- jazz-react-native@0.8.35
## 1.0.24
### Patch Changes
- jazz-react-native@0.8.34
- jazz-tools@0.8.34
## 1.0.23
### Patch Changes
- Updated dependencies [df42b2b]
- jazz-tools@0.8.32
- jazz-react-native@0.8.32
## 1.0.22
### Patch Changes
- jazz-react-native@0.8.31
- jazz-tools@0.8.31
## 1.0.21
### Patch Changes
- jazz-react-native@0.8.30
- jazz-tools@0.8.30
## 1.0.20
### Patch Changes
- jazz-react-native@0.8.29
- jazz-tools@0.8.29
## 1.0.19
### Patch Changes
- jazz-react-native@0.8.28
- jazz-tools@0.8.28
## 1.0.18
### Patch Changes
- jazz-react-native@0.8.27
- jazz-tools@0.8.27
## 1.0.17
### Patch Changes
- Updated dependencies [d348c2d]
- Updated dependencies [6902b5b]
- Updated dependencies [1a0cd3d]
- jazz-tools@0.8.23
- jazz-react-native@0.8.23
## 1.0.16
### Patch Changes
- Updated dependencies [149ca97]
- jazz-tools@0.8.21
- jazz-react-native@0.8.21
## 1.0.15
### Patch Changes
- Updated dependencies [3ef3ff3]
- jazz-react-native@0.8.20
## 1.0.14
### Patch Changes
- jazz-react-native@0.8.19
- jazz-tools@0.8.19
## 1.0.13
### Patch Changes
- jazz-react-native@0.8.18
- jazz-tools@0.8.18
## 1.0.12
### Patch Changes
- jazz-react-native@0.8.17
- jazz-tools@0.8.17
## 1.0.11
### Patch Changes
- jazz-react-native@0.8.16
- jazz-tools@0.8.16
## 1.0.10
### Patch Changes
- Updated dependencies [cce679b]
- jazz-tools@0.8.15
- jazz-react-native@0.8.15
## 1.0.9
### Patch Changes
- Updated dependencies [36273b3]
- jazz-tools@0.8.14
- jazz-react-native@0.8.14
## 1.0.8
### Patch Changes
- Updated dependencies [fd011d7]
- jazz-tools@0.8.13
- jazz-react-native@0.8.13
## 1.0.7
### Patch Changes
- jazz-react-native@0.8.12
- jazz-tools@0.8.12
## 1.0.6
### Patch Changes
- jazz-react-native@0.8.11
- jazz-tools@0.8.11
## 1.0.5
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-expo@0.14.14
- b7639cf: feat(react-native): replaced react-native-mmkv with expo-secure-store and initialize it by default as kvStore in createJazzRNApp() (BREAKING)
- Updated dependencies [b7639cf]
- jazz-react-native@0.8.8
## 1.0.4
### Patch Changes
- jazz-expo@0.14.13
- Updated dependencies [32b05b6]
- jazz-react-native@0.8.7
## 1.0.3
### Patch Changes
- jazz-expo@0.14.12
- jazz-react-native@0.8.6
## 1.0.2
### Patch Changes
- Updated dependencies [98d697f]
- jazz-expo@0.14.11
- Updated dependencies [c3f4e6b]
- Updated dependencies [d9152ed]
- jazz-react-native@0.8.5
- jazz-tools@0.8.5
## 1.0.1
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-tools@0.14.10
- jazz-expo@0.14.10
- Updated dependencies
- jazz-react-native@0.8.3
- jazz-tools@0.8.3

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

@@ -1,32 +1,34 @@
{
"expo": {
"name": "chat-rn-expo",
"slug": "chat-rn-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",
"newArchEnabled": true,
"splash": {
"image": "./assets/splash-icon.png",
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.anonymous.chatrnexpo"
"bundleIdentifier": "com.jazz.chatrn"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"edgeToEdgeEnabled": true,
"package": "com.anonymous.chatrnexpo"
"package": "com.jazz.chatrn"
},
"web": {
"favicon": "./assets/favicon.png"
"plugins": ["expo-secure-store", "expo-sqlite", "expo-build-properties"],
"extra": {
"eas": {
"projectId": "e0e61872-1906-4c84-b9d8-9be77355cad0"
}
},
"plugins": ["expo-secure-store", "expo-sqlite"]
"owner": "paxx"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

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,27 @@
{
"cli": {
"version": ">= 12.5.1",
"appVersionSource": "remote"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"ios-simulator": {
"extends": "development",
"ios": {
"simulator": true
}
},
"preview": {
"distribution": "internal"
},
"production": {
"autoIncrement": true
}
},
"submit": {
"production": {}
}
}

View File

@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@@ -0,0 +1,4 @@
import "./polyfills";
import { registerRootComponent } from "expo";
import App from "./src/App";
registerRootComponent(App);

View File

@@ -1,9 +0,0 @@
import { registerRootComponent } from "expo";
import "./polyfills";
import App from "./src/App";
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in Expo Go or in a native build,
// the environment is set up appropriately
registerRootComponent(App);

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 @@
/// <reference types="nativewind/types" />

View File

@@ -1,35 +1,52 @@
{
"name": "chat-rn-expo",
"version": "1.0.5",
"main": "index.ts",
"version": "1.0.79",
"main": "index.js",
"scripts": {
"build": "expo prebuild",
"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",
"@bacons/text-decoder": "0.0.0",
"@craftzdog/react-native-buffer": "6.0.5",
"@react-native-community/netinfo": "11.4.1",
"expo": "~53.0.9",
"expo-clipboard": "^7.1.4",
"expo-secure-store": "~14.2.3",
"expo-sqlite": "~15.2.10",
"expo-status-bar": "~2.2.3",
"@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:*",
"react": "19.0.0",
"react-native": "0.79.2",
"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",
"readable-stream": "^4.7.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": "~19.0.10",
"typescript": "~5.8.3"
"@types/react": "~18.3.12",
"tailwindcss": "^3.4.17",
"typescript": "~5.6.2"
},
"private": true
}

View File

@@ -1,9 +1,48 @@
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 React, { StrictMode } from "react";
import { apiKey } from "./apiKey";
import ChatScreen from "./chat";
export default function App() {
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
@@ -11,8 +50,23 @@ export default function App() {
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
>
<ChatScreen />
<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

@@ -1,6 +1,7 @@
import clsx from "clsx";
import * as Clipboard from "expo-clipboard";
import { Account, Group } from "jazz-tools";
import { useState } from "react";
import { Group, ID, Profile } from "jazz-tools";
import { useEffect, useState } from "react";
import React, {
Button,
FlatList,
@@ -11,41 +12,72 @@ import React, {
TouchableOpacity,
View,
Alert,
StyleSheet,
} from "react-native";
import { useAccount, useCoState } from "jazz-expo";
import { Chat, Message } from "./schema";
export default function ChatScreen() {
const { me, logOut } = useAccount(Account, { resolve: { profile: true } });
const [chatId, setChatId] = useState<string>();
const [chatIdInput, setChatIdInput] = useState<string>();
const loadedChat = useCoState(Chat, chatId, { resolve: { $each: true } });
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();
const group = Group.create({ owner: me });
group.addMember("everyone", "writer");
const chat = Chat.create([], group);
const chat = Chat.create([], { owner: group });
setChatId(chat.id);
};
const joinChat = () => {
if (chatIdInput) {
if (chatIdInput.startsWith("https://chat.jazz.tools/#/chat/")) {
setChatId(chatIdInput.split("/").pop());
} else {
setChatId(chatIdInput);
}
} else {
Alert.alert("Error", "Chat ID cannot be empty.");
}
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 = () => {
@@ -62,30 +94,39 @@ export default function ChatScreen() {
const isMe = item._edits?.text?.by?.isMe;
return (
<View
style={[
styles.messageContainer,
isMe ? styles.myMessage : styles.otherMessage,
]}
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
style={[
styles.messageSender,
{ textAlign: isMe ? "right" : "left" },
]}
className={clsx(
`text-xs text-gray-500`,
isMe ? "text-right" : "text-left",
)}
>
{item?._edits?.text?.by?.profile?.name}
</Text>
) : null}
<View style={styles.messageContent}>
<Text style={styles.messageText}>{item.text}</Text>
<Text style={[styles.messageTime, { marginTop: !isMe ? 8 : 4 }]}>
{item?._edits?.text?.madeAt?.getHours().toString().padStart(2, "0")}
:
{item?._edits?.text?.madeAt
?.getMinutes()
.toString()
.padStart(2, "0")}
<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>
@@ -93,73 +134,45 @@ export default function ChatScreen() {
};
return (
<View style={styles.container}>
<View className="flex flex-col h-full">
{!loadedChat ? (
<View style={styles.welcomeContainer}>
<Text style={styles.usernameTitle}>Username</Text>
<View className="flex flex-col h-full items-center justify-center">
<Text className="text-m font-bold mb-6">Username</Text>
<TextInput
style={styles.usernameInput}
value={me?.profile.name ?? ""}
className="rounded h-12 p-2 mb-12 w-40 border border-gray-200 block"
value={profile?.name ?? ""}
onChangeText={(value) => {
if (me?.profile) {
me.profile.name = value;
if (profile) {
profile.name = value;
}
}}
textAlignVertical="center"
onSubmitEditing={sendMessage}
testID="username-input"
/>
<TouchableOpacity onPress={createChat} style={styles.newChatButton}>
<Text style={styles.newChatButtonText}>Start new chat</Text>
<TouchableOpacity
onPress={createChat}
className="bg-blue-500 p-4 rounded-md"
>
<Text className="text-white font-semibold">Start new chat</Text>
</TouchableOpacity>
<Text style={styles.joinChatTitle}>Join existing chat</Text>
<TextInput
style={styles.chatIdInput}
placeholder="Chat ID"
value={chatIdInput ?? ""}
onChangeText={(value) => {
setChatIdInput(value);
}}
textAlignVertical="center"
onSubmitEditing={() => {
if (chatIdInput) {
setChatId(chatIdInput);
}
}}
testID="chat-id-input"
/>
<TouchableOpacity onPress={joinChat} style={styles.joinChatButton}>
<Text style={styles.newChatButtonText}>Join chat</Text>
<TouchableOpacity
onPress={joinChat}
className="bg-green-500 p-4 rounded-md mt-4"
>
<Text className="text-white font-semibold">Join chat</Text>
</TouchableOpacity>
</View>
) : (
<>
<View style={styles.chatHeader}>
<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"
/>
<Text style={{ fontWeight: "bold", fontSize: 18 }}>Jazz chat</Text>
<Button onPress={handleLogOut} title="Logout" />
</View>
<FlatList
contentContainerStyle={{
flexGrow: 1,
flex: 1,
gap: 6,
padding: 8,
justifyContent: "flex-end",
}}
style={styles.messageList}
className="flex"
data={loadedChat}
keyExtractor={(item) => item.id}
renderItem={renderMessageItem}
@@ -168,11 +181,11 @@ export default function ChatScreen() {
<KeyboardAvoidingView
keyboardVerticalOffset={110}
behavior="padding"
style={styles.inputContainer}
className="p-3 bg-white border-t border-gray-300"
>
<SafeAreaView style={styles.inputRow}>
<SafeAreaView className="flex flex-row items-center gap-2">
<TextInput
style={styles.messageInput}
className="rounded-full h-8 py-0 px-2 border border-gray-200 block flex-1"
value={message}
onChangeText={setMessage}
placeholder="Type a message..."
@@ -182,7 +195,7 @@ export default function ChatScreen() {
/>
<TouchableOpacity
onPress={sendMessage}
style={styles.sendButton}
className="bg-gray-300 text-white rounded-full h-8 w-8 items-center justify-center"
testID="send-button"
>
<Text></Text>
@@ -194,133 +207,3 @@ export default function ChatScreen() {
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "column",
height: "100%",
},
chatHeader: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
padding: 8,
paddingTop: 48,
backgroundColor: "#f0f0f0",
},
welcomeContainer: {
flex: 1,
flexDirection: "column",
height: "100%",
alignItems: "center",
justifyContent: "center",
},
usernameTitle: {
fontSize: 16,
fontWeight: "bold",
marginBottom: 24,
},
usernameInput: {
borderRadius: 4,
height: 48,
padding: 8,
marginBottom: 48,
width: 160,
borderWidth: 1,
borderColor: "#e5e5e5",
},
newChatButton: {
backgroundColor: "#3b82f6",
padding: 16,
borderRadius: 6,
},
newChatButtonText: {
color: "white",
fontWeight: "600",
},
joinChatTitle: {
fontSize: 16,
fontWeight: "bold",
marginTop: 24,
},
chatIdInput: {
borderRadius: 4,
height: 48,
padding: 8,
margin: 8,
marginTop: 16,
width: 320,
borderWidth: 1,
borderColor: "#e5e5e5",
},
joinChatButton: {
backgroundColor: "#22c55e",
padding: 16,
borderRadius: 6,
},
messageList: {
display: "flex",
},
messageContainer: {
borderRadius: 8,
padding: 4,
paddingHorizontal: 6,
maxWidth: "80%",
},
myMessage: {
backgroundColor: "#e5e5e5",
alignSelf: "flex-end",
},
otherMessage: {
backgroundColor: "#d4d4d4",
alignSelf: "flex-start",
},
messageSender: {
fontSize: 12,
color: "#6b7280",
},
messageContent: {
flexDirection: "row",
alignItems: "flex-end",
justifyContent: "space-between",
},
messageText: {
color: "black",
fontSize: 16,
maxWidth: "85%",
},
messageTime: {
fontSize: 10,
color: "#6b7280",
marginLeft: 8,
},
inputContainer: {
padding: 12,
backgroundColor: "white",
borderTopWidth: 1,
borderTopColor: "#d4d4d4",
},
inputRow: {
flexDirection: "row",
alignItems: "center",
gap: 8,
},
messageInput: {
borderRadius: 9999,
height: 32,
paddingVertical: 0,
paddingHorizontal: 8,
borderWidth: 1,
borderColor: "#e5e5e5",
flex: 1,
},
sendButton: {
backgroundColor: "#d4d4d4",
borderRadius: 9999,
height: 32,
width: 32,
alignItems: "center",
justifyContent: "center",
},
});

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

@@ -1,9 +1,7 @@
import { co, z } from "jazz-tools";
import { CoList, CoMap, co } from "jazz-tools";
export const Message = co.map({
text: z.string(),
});
export type Message = co.loaded<typeof Message>;
export class Message extends CoMap {
text = co.string;
}
export const Chat = co.list(Message);
export type Chat = co.loaded<typeof Chat>;
export class Chat extends CoList.Of(co.ref(Message)) {}

View File

@@ -0,0 +1,14 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
// NOTE: Update this to include the paths to all of your component files.
content: [
"./app/**/*.{js,jsx,ts,tsx}",
"./components/**/*.{js,jsx,ts,tsx}",
"./src/**/*.{js,jsx,ts,tsx}",
],
presets: [require("nativewind/preset")],
theme: {
extend: {},
},
plugins: [],
};

View File

@@ -8,7 +8,8 @@ appId: com.jazz.chatrn
# - assertVisible: "Reload"
# - tapOn: "Reload"
- assertVisible: "Username"
# login
- assertVisible: "Anonymous user"
- runFlow:
label: "Erase existing username"
file: erase_text.yml
@@ -40,13 +41,10 @@ appId: com.jazz.chatrn
# logout
- tapOn: "Logout"
- assertVisible: "Username"
- assertVisible: "Anonymous user"
# join chat
# - tapOn:
# id: "chat-id-input"
# - inputText: "co_zFs6KFyhxPw4xtw83tcEMzeHUNv" # Use a static id because maestro doesn't have access to the system clipboard
# This doesn't work on CI, maybe because Android has a different alert dialog
# - tapOn: "Join chat"
# - inputText: "co_zFs6KFyhxPw4xtw83tcEMzeHUNv" # Use a static id because maestro doesn't have access to the system clipboard
# - pressKey: "enter"
# - assertVisible: "boorad"
# - assertVisible: "bro, low key, it do be like that tho"

View File

@@ -3,14 +3,14 @@
# This script is necessary, because unlike ios, the android emulator action
# accepts a script, runs it as your tests, then terminates.
# set -e
set -e
# # build and install the app
# echo "Building and installing Android app."
# echo "If it fails, its output will be in artifact: android-install.log..."
# cd ./android/
# ./gradlew installRelease >> ~/output/android-install.log 2>&1
# cd ..
# build and install the app
echo "Building and installing Android app."
echo "If it fails, its output will be in artifact: android-install.log..."
cd ./android/
./gradlew installRelease >> ~/output/android-install.log 2>&1
cd ..
# run the e2e tests
export PATH="$PATH":"$HOME/.maestro/bin"

View File

@@ -1,6 +1,8 @@
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"strict": true
}
"strict": true,
"moduleResolution": "bundler"
},
"exclude": ["src/tests"]
}

View File

@@ -1,428 +0,0 @@
# chat-rn
## 1.0.132
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react-native@0.14.14
## 1.0.131
### Patch Changes
- jazz-react-native@0.14.13
## 1.0.130
### Patch Changes
- jazz-react-native@0.14.12
## 1.0.129
### Patch Changes
- Updated dependencies [98d697f]
- jazz-react-native@0.14.11
## 1.0.128
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-react-native@0.14.10
- jazz-tools@0.14.10
## 1.0.127
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-react-native@0.14.9
## 1.0.126
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-react-native@0.14.8
## 1.0.125
### Patch Changes
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-react-native@0.14.7
## 1.0.124
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-react-native@0.14.6
## 1.0.123
### Patch Changes
- Updated dependencies [91cbb2f]
- Updated dependencies [20b3d88]
- jazz-tools@0.14.5
- jazz-react-native@0.14.5
## 1.0.122
### Patch Changes
- Updated dependencies [011af55]
- jazz-tools@0.14.4
- jazz-react-native@0.14.4
## 1.0.121
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-react-native@0.14.2
## 1.0.120
### Patch Changes
- Updated dependencies [c8b33ad]
- Updated dependencies [cdfc105]
- cojson@0.14.1
- jazz-tools@0.14.1
- cojson-transport-ws@0.14.1
- jazz-react-native@0.14.1
## 1.0.119
### Patch Changes
- Updated dependencies [5835ed1]
- Updated dependencies [5835ed1]
- cojson@0.14.0
- jazz-tools@0.14.0
- cojson-transport-ws@0.14.0
- jazz-react-native@0.14.0
## 1.0.118
### Patch Changes
- jazz-react-native@0.13.32
## 1.0.117
### Patch Changes
- Updated dependencies [e5b170f]
- Updated dependencies [d63716a]
- Updated dependencies [d5edad7]
- jazz-tools@0.13.31
- cojson@0.13.31
- jazz-react-native@0.13.31
- cojson-transport-ws@0.13.31
## 1.0.116
### Patch Changes
- Updated dependencies [07dd2c5]
- cojson@0.13.30
- cojson-transport-ws@0.13.30
- jazz-react-native@0.13.30
- jazz-tools@0.13.30
## 1.0.115
### Patch Changes
- Updated dependencies [eef1a5d]
- Updated dependencies [191ae38]
- Updated dependencies [daee7b9]
- cojson@0.13.29
- jazz-react-native@0.13.29
- cojson-transport-ws@0.13.29
- jazz-tools@0.13.29
## 1.0.114
### Patch Changes
- Updated dependencies [e7ccb2c]
- Updated dependencies [422dbc4]
- cojson@0.13.28
- cojson-transport-ws@0.13.28
- jazz-react-native@0.13.28
- jazz-tools@0.13.28
## 1.0.113
### Patch Changes
- Updated dependencies [6357052]
- cojson@0.13.27
- cojson-transport-ws@0.13.27
- jazz-react-native@0.13.27
- jazz-tools@0.13.27
## 1.0.112
### Patch Changes
- Updated dependencies [ff846d9]
- jazz-tools@0.13.26
- jazz-react-native@0.13.26
## 1.0.111
### Patch Changes
- Updated dependencies [a846e07]
- cojson@0.13.25
- cojson-transport-ws@0.13.25
- jazz-react-native@0.13.25
- jazz-tools@0.13.25
## 1.0.110
### Patch Changes
- Updated dependencies [6b781cf]
- Updated dependencies [02a240c]
- cojson@0.13.23
- jazz-tools@0.13.23
- cojson-transport-ws@0.13.23
- jazz-react-native@0.13.23
## 1.0.109
### Patch Changes
- jazz-react-native@0.13.22
## 1.0.108
### Patch Changes
- Updated dependencies [e14e61f]
- cojson@0.13.21
- cojson-transport-ws@0.13.21
- jazz-react-native@0.13.21
- jazz-tools@0.13.21
## 1.0.107
### Patch Changes
- Updated dependencies [adfc9a6]
- Updated dependencies [1389207]
- Updated dependencies [d6e143e]
- Updated dependencies [439f0fe]
- Updated dependencies [3e6229d]
- cojson@0.13.20
- jazz-tools@0.13.20
- jazz-react-native@0.13.20
- cojson-transport-ws@0.13.20
## 1.0.106
### Patch Changes
- Updated dependencies [80530a4]
- jazz-tools@0.13.19
- jazz-react-native@0.13.19
## 1.0.105
### Patch Changes
- Updated dependencies [9089252]
- Updated dependencies [b470f63]
- Updated dependencies [761759c]
- Updated dependencies [66373ba]
- Updated dependencies [f24cad1]
- cojson@0.13.18
- jazz-tools@0.13.18
- cojson-transport-ws@0.13.18
- jazz-react-native@0.13.18
## 1.0.104
### Patch Changes
- Updated dependencies [9fb98e2]
- Updated dependencies [0b89fad]
- cojson@0.13.17
- cojson-transport-ws@0.13.17
- jazz-react-native@0.13.17
- jazz-tools@0.13.17
## 1.0.103
### Patch Changes
- Updated dependencies [c6fb8dc]
- cojson@0.13.16
- cojson-transport-ws@0.13.16
- jazz-react-native@0.13.16
- jazz-tools@0.13.16
## 1.0.102
### Patch Changes
- Updated dependencies [c712ef2]
- cojson@0.13.15
- cojson-transport-ws@0.13.15
- jazz-react-native@0.13.15
- jazz-tools@0.13.15
## 1.0.101
### Patch Changes
- Updated dependencies [5c2c7d4]
- cojson@0.13.14
- cojson-transport-ws@0.13.14
- jazz-react-native@0.13.14
- jazz-tools@0.13.14
## 1.0.100
### Patch Changes
- Updated dependencies [ec9cb40]
- cojson@0.13.13
- cojson-transport-ws@0.13.13
- jazz-react-native@0.13.13
- jazz-tools@0.13.13
## 1.0.99
### Patch Changes
- Updated dependencies [4547525]
- Updated dependencies [65719f2]
- jazz-tools@0.13.12
- cojson@0.13.12
- jazz-react-native@0.13.12
- cojson-transport-ws@0.13.12
## 1.0.98
### Patch Changes
- Updated dependencies [17273a6]
- Updated dependencies [3396ed4]
- Updated dependencies [17273a6]
- Updated dependencies [267ea4c]
- cojson@0.13.11
- jazz-tools@0.13.11
- cojson-transport-ws@0.13.11
- jazz-react-native@0.13.11
## 1.0.97
### Patch Changes
- Updated dependencies [f837cfe]
- cojson@0.13.10
- cojson-transport-ws@0.13.10
- jazz-react-native@0.13.10
- jazz-tools@0.13.10
## 1.0.96
### Patch Changes
- Updated dependencies [a6cf01f]
- jazz-tools@0.13.9
- jazz-react-native@0.13.9
## 1.0.95
### Patch Changes
- Updated dependencies [bc3d7bb]
- Updated dependencies [4e9aae1]
- Updated dependencies [21c935c]
- Updated dependencies [aa1c80e]
- Updated dependencies [13074be]
- jazz-tools@0.13.7
- cojson@0.13.7
- jazz-react-native@0.13.7
- cojson-transport-ws@0.13.7
## 1.0.94
### Patch Changes
- Updated dependencies [e090b39]
- Updated dependencies [fe6f561]
- cojson@0.13.5
- jazz-tools@0.13.5
- cojson-transport-ws@0.13.5
- jazz-react-native@0.13.5
## 1.0.93
### Patch Changes
- Updated dependencies [3129982]
- jazz-tools@0.13.4
- jazz-react-native@0.13.4
## 1.0.92
### Patch Changes
- Updated dependencies [12f8bfa]
- Updated dependencies [b19cab7]
- Updated dependencies [bd57177]
- jazz-tools@0.13.3
- cojson-transport-ws@0.13.3
- jazz-react-native@0.13.3
## 1.0.91
### Patch Changes
- Updated dependencies [c551839]
- cojson@0.13.2
- cojson-transport-ws@0.13.2
- jazz-react-native@0.13.2
- jazz-tools@0.13.2
## 1.0.90
### Patch Changes
- Updated dependencies [63a7aa0]
- jazz-react-native@0.13.1
## 1.0.89
### Patch Changes
- Updated dependencies [a013538]
- Updated dependencies [bce3bcc]
- Updated dependencies [afd1374]
- Updated dependencies [bce3bcc]
- cojson@0.13.0
- jazz-react-native@0.13.0
- jazz-tools@0.13.0
- cojson-transport-ws@0.13.0

View File

@@ -26,7 +26,7 @@ This will set up and launch the app on iOS. For Android, you can skip `pnpm pods
This was created using the following command:
```bash
pnpx @react-native-community/cli init chat-rn --version 0.76.7 --install-pods true --skip-git-init true --package-name com.chatrn --directory chat-rn
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 change package name in `package.json`, and begin build instructions above.
Then delete `bun.lock`, change package name in `package.json`, and begin build instructions above.

View File

@@ -1920,72 +1920,72 @@ SPEC CHECKSUMS:
fmt: 10c6e61f4be25dc963c36bd73fc7b1705fe975be
glog: 08b301085f15bcbb6ff8632a8ebaf239aae04e6a
hermes-engine: eb4a80f6bf578536c58a44198ec93a30f6e69218
op-sqlite: 7ecaedd41684cc6c9f6fa267db0da48cbb11dc90
op-sqlite: 17f173ae72a5e9617bf9000c9e0474cc518fdc5c
RCT-Folly: bf5c0376ffe4dd2cf438dcf86db385df9fdce648
RCTDeprecation: 7691283dd69fed46f6653d376de6fa83aaad774c
RCTRequired: eac044a04629288f272ee6706e31f81f3a2b4bfe
RCTTypeSafety: cfe499e127eda6dd46e5080e12d80d0bfe667228
React: 1f3737a983fdd26fb3d388ddbca41a26950fe929
React-callinvoker: 5c15ac628eab5468fe0b4dc453495f4742761f00
React-Core: e467bf49f10da6fe92d915d2311cd0fd9bfbe052
React-CoreModules: 0299b3c0782edd3b37c8445ba07bf18ceb73812d
React-cxxreact: 54e253030b3b82b05575f19a1fb0e25c049f30ba
React-Core: 4b90a977a5b2777fd8f4a8db7325a83431ecd2d8
React-CoreModules: 385bbacfa34ac9208aa24f239a5184fa7ab1cd28
React-cxxreact: 3e09bcdf1f86b931b5e96bf5429d7c274a0ec168
React-debug: 2086b55a5e55fb0abae58c42b8f280ebd708c956
React-defaultsnativemodule: f80f41ea8c1216917fd224b553291360e0e6a175
React-domnativemodule: b14aaaf4afbaa7e1dbc86ad78cbcc71eb59f1faf
React-Fabric: 409ce8a065374d737bdbc0fce506dcdda8f51e88
React-FabricComponents: bd5faafffd07e56cf217d5417e80ec29348c19d9
React-FabricImage: 04d01f3ecfed6121733613a5c794f684e81cb3fb
React-defaultsnativemodule: 491e2541856e3580dae7f29d80754673a2134e48
React-domnativemodule: 4aaed5d5eef3da7d7d49b1f2ae8f422a4d7794b7
React-Fabric: 5b8373d1bd34bf269b13529a0ebee0643165ccf8
React-FabricComponents: 3f8528c3ed060464a120e161ffaef9307a88817b
React-FabricImage: 8efa4e206b1e5cf2e8e1e48fd345619c5c0484f4
React-featureflags: 4503c901bf16b267b689e8a1aed24e951e0b091b
React-featureflagsnativemodule: 79c980bfc96bcdcc9bd793d49fe75bbfb0e417ad
React-graphics: c2febdc940fb3ebdaef082d940b70254ef49c7a1
React-hermes: 91baa15c07e76b0768d6e10f4dac1c080a47eef4
React-idlecallbacksnativemodule: 5daef402290b91e54a884101b032186c03fa1827
React-ImageManager: b258354a48a92168edc41fdc0c14a4310cc4d576
React-jserrorhandler: 45d858315f6474dad3912aadb3f6595004dc5f4f
React-jsi: 87fa67556d7a82125bc77930bf973717fb726d14
React-jsiexecutor: 3a92052dd96cff1cd693fa3ef8d9738b1d05372a
React-jsinspector: 05aff7dd91b0685d351cdeb8c151c9f9ec97accd
React-jsitracing: 419fa21e8543f5a938b11b5a0bfc257b00dac7a5
React-logger: 5cad0c76d056809523289e589309012215a393b5
React-Mapbuffer: a381120aea722d2244d4e4b663a10d4c3b2d4e51
React-microtasksnativemodule: d9b946675010659cddd1c7611c074216579c8ad3
react-native-get-random-values: d16467cf726c618e9c7a8c3c39c31faa2244bbba
react-native-mmkv: b4af3744580f08e1ffc7761103b408d313b2f772
react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187
react-native-safe-area-context: 0f16e24dc808e9f0ced17f2bdcec692b2376fb68
React-featureflagsnativemodule: 415168f5d23413fd0cc55ad98c41a3f3f135b2a7
React-graphics: c619a6e974baf9a7dbae8442944c7b7408391d46
React-hermes: 24bfc254f1ba83182d4936641898fe963af343fb
React-idlecallbacksnativemodule: 2c2e4c3f561a98c84a7a68c0d1f868b64ca5f839
React-ImageManager: ba9c89729be310413c610444a658fac505253d2c
React-jserrorhandler: bf16ea495377b22223bf93f3ef6d0711b9852613
React-jsi: ede7e8c96f997f8772871c82688cea53c1ffb148
React-jsiexecutor: fc9b287189ce800a92d5ab4e7291508eacaab451
React-jsinspector: fa5e8b22102b599c2bb2aeafebbf957a1ab836da
React-jsitracing: f38c15aeb910bafcf3ba2e24af8c92e6af4ce1d4
React-logger: f9d104eace4ce03d7d5ab96802069d9905082225
React-Mapbuffer: 23ffe602d0f5ca53b861ef8534cb8c63c4479671
React-microtasksnativemodule: 73fdf0c53b6d50d55de2d5bd9abfb8c006b043a4
react-native-get-random-values: 21325b2244dfa6b58878f51f9aa42821e7ba3d06
react-native-mmkv: 21d0f6ed2d9532f2370cef81eca4ccbef7350441
react-native-netinfo: f0a9899081c185db1de5bb2fdc1c88c202a059ac
react-native-safe-area-context: 458f6b948437afcb59198016b26bbd02ff9c3b47
React-nativeconfig: 67fa7a63ea288cb5b1d0dd2deaf240405fec164f
React-NativeModulesApple: 34b7a4d7441a4ee78d18109ff107c1ccf7c074a9
React-perflogger: d1149037ac466ad2141d4ae541ca16cb73b2343b
React-performancetimeline: 6b46b0a17727a3ec22ec4777d156d6b6efc4f8eb
React-NativeModulesApple: cbf1a34443e1f67b56344547f4b0af69e1c685ba
React-perflogger: f02ee21d98773121d77993b3c1a8be445840fae3
React-performancetimeline: 7021d68884291b649b4c39ecb71e0fd3a2e53a59
React-RCTActionSheet: ad84d5a0bd1ad1782f0b78b280c6f329ad79a53a
React-RCTAnimation: 64ed42bb43b33b0d861126f83048429606390903
React-RCTAppDelegate: de8150cd7e748bd7a98ffc05c88f21c668407ab4
React-RCTBlob: e74dfdbbfcd46d9d1eec3b3a0f045e655e3f7861
React-RCTFabric: bc0327e719fb12f969ac0e17485ba274b9c2c335
React-RCTImage: 1b6d8ad60f74a3cec4ee52e0ca55f1773afd03f4
React-RCTLinking: 88b2384d876346fbb16839a60c1d20830b2e95fe
React-RCTNetwork: 88aa473814e796d3a7bc6a0b51e7ae5749bdc243
React-RCTSettings: 0d73a1846aef87ef07c2026c186ea0d80602a130
React-RCTText: bfdb776f849156f895909ee999b4b5f2f9cf9a0b
React-RCTVibration: 81c8bbcc841ce5a7ae6e1bd2ec949b30e58d1fcf
React-RCTAnimation: 388460f7c124c76e337c6646738a83d6ea147095
React-RCTAppDelegate: 4661e2a44f7ce1033bf6f373f7d5368b11f5a2be
React-RCTBlob: 07cccbb74e22ce66745358799f6ab02a5bed2993
React-RCTFabric: 77ebcd07a3c1f3d4c2d2f67f69033a65d16a36a8
React-RCTImage: 8fbdae841ea1217c44f4c413bba2403134b83cd1
React-RCTLinking: c59bf8286ba2cc327b01bb524fb9c16446dc18bc
React-RCTNetwork: 2c137a0aaaed2cf4bb53aff82a2bb8c34f2fbeac
React-RCTSettings: 9fcd32c5b38af6421a3dd20cdd9ebf09df0a9a6d
React-RCTText: 5308618477fec454282809065bd121c2bd3dd5e1
React-RCTVibration: 7b2a186756b5c8e586e3e7948eed4432a93299c0
React-rendererconsistency: 65d4692825fda4d9516924b68c29d0f28da3158c
React-rendererdebug: ab3696594d3506acc22ecea4dd68ac258c529c2d
React-rendererdebug: 0b97f49d44c91862e1576961faf6bde836ed4eb3
React-rncore: 6aca111c05a48c58189a005cb10a7b52780738dc
React-RuntimeApple: 5245e8cf30e417fe3e798ed991b938679656ab8f
React-RuntimeCore: c79d23b31aded614f4afeaac53f4da37c792c362
React-RuntimeApple: aa20633298595444bf2dfbc5246889b4f475b871
React-RuntimeCore: 8ac56cc6d82a1090f1d15d48b487c9a5a1d7d915
React-runtimeexecutor: 732038d7c356ba74132f1d16253a410621d3c2c1
React-RuntimeHermes: b3b1d7fc42d74141a71ae23fedbc4e07e5a7fbd2
React-runtimescheduler: 6e804311c6c9512ffe7f4b68d012767b225c48a1
React-RuntimeHermes: a695d944686adc97f85a1b34c31840a0a39e356c
React-runtimescheduler: 00666e100e35a13f28fb2fdab22817cf62bbd6a3
React-timing: c2915214b94a62bdf77d2965c31f76bc25b362a5
React-utils: 0342746d2cf989cf5e0d1b84c98cfa152edbdf3f
ReactCodegen: ca395237650513af628c32aa1eb8fd586c771b13
ReactCommon: 81e0744ee33adfd6d586141b927024f488bc49ea
RNCClipboard: bdad452a8a44c90098dab5468152a6f72cb689be
RNScreens: 351f431ef2a042a1887d4d90e1c1024b8ae9d123
React-utils: 9f9a6a31d703b136eb1614d914c10a3c96b1e6dd
ReactCodegen: 5d7e2d2948a6629a51a59ebc99f620e2afb13ee5
ReactCommon: 04292c6f596181ebf755e7929d96d2148542b0e8
RNCClipboard: c1dd9a853d56764a04ba278f61cd2cb58a138396
RNScreens: d022507f2b6d76c73335e9e35aedcf7bb2f791b0
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
Yoga: 90d80701b27946c4b23461c00a7207f300a6ff71
PODFILE CHECKSUM: 3c941cec20e8dff1c7d38ce78a515b4cca0ee574
COCOAPODS: 1.16.2
COCOAPODS: 1.15.2

View File

@@ -1,13 +1,14 @@
{
"name": "chat-rn",
"version": "1.0.132",
"main": "index.js",
"private": true,
"version": "1.0.84",
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"lint": "eslint .",
"start": "react-native start",
"pods": "pod-install"
"test": "jest",
"pods": "bundle install && RCT_NEW_ARCH_ENABLED=1 bundle exec pod install --project-directory=ios"
},
"dependencies": {
"@azure/core-asynciterator-polyfill": "^1.0.2",
@@ -16,15 +17,16 @@
"@op-engineering/op-sqlite": "^11.4.8",
"@react-native-clipboard/clipboard": "1.16.1",
"@react-native-community/netinfo": "11.4.1",
"@react-navigation/native": "7.0.19",
"@react-navigation/native": "7.0.15",
"@react-navigation/native-stack": "7.2.1",
"clsx": "^2.0.0",
"cojson": "workspace:*",
"cojson-transport-ws": "workspace:*",
"jazz-expo": "workspace:*",
"jazz-react-native": "workspace:*",
"jazz-tools": "workspace:*",
"react": "19.0.0",
"react-native": "0.79.2",
"react": "18.3.1",
"react-native": "0.76.7",
"react-native-get-random-values": "^1.11.0",
"react-native-mmkv": "^3.2.0",
"react-native-polyfill-globals": "^3.1.0",
@@ -46,13 +48,15 @@
"@react-native/typescript-config": "0.76.7",
"@rnx-kit/metro-config": "^2.0.1",
"@rnx-kit/metro-resolver-symlinks": "^0.2.1",
"@types/jest": "^29.5.13",
"@types/react": "^18.3.12",
"@types/react-test-renderer": "^18.0.0",
"babel-jest": "^29.6.3",
"eslint": "^8.19.0",
"pod-install": "^0.3.5",
"jest": "^29.6.3",
"prettier": "2.8.8",
"react-test-renderer": "18.3.1",
"typescript": "5.6.2"
"typescript": "5.0.4"
},
"engines": {
"node": ">=18"

View File

@@ -1,6 +1,6 @@
import Clipboard from "@react-native-clipboard/clipboard";
import { useAccount, useCoState } from "jazz-react-native";
import { CoPlainText, Group, ID, Loaded, Profile } from "jazz-tools";
import { Group, ID, Profile } from "jazz-tools";
import { useEffect, useState } from "react";
import {
Alert,
@@ -18,8 +18,8 @@ import { Chat, Message } from "./schema";
export function ChatScreen({ navigation }: { navigation: any }) {
const { me, logOut } = useAccount();
const [chatId, setChatId] = useState<string>();
const loadedChat = useCoState(Chat, chatId, { resolve: { $each: true } });
const [chatId, setChatId] = useState<ID<Chat>>();
const loadedChat = useCoState(Chat, chatId, [{}]);
const [message, setMessage] = useState("");
const profile = useCoState(Profile, me._refs.profile?.id, {});
@@ -68,7 +68,7 @@ export function ChatScreen({ navigation }: { navigation: any }) {
text: "Join",
onPress: (chatId) => {
if (chatId) {
setChatId(chatId);
setChatId(chatId as ID<Chat>);
} else {
Alert.alert("Error", "Chat ID cannot be empty.");
}
@@ -83,18 +83,13 @@ export function ChatScreen({ navigation }: { navigation: any }) {
if (!loadedChat) return;
if (message.trim()) {
loadedChat.push(
Message.create(
{ text: CoPlainText.create(message, loadedChat?._owner) },
loadedChat?._owner,
),
Message.create({ text: message }, { owner: loadedChat?._owner }),
);
setMessage("");
}
};
const renderMessageItem = ({
item,
}: { item: Loaded<typeof Message, { text: true }> }) => {
const renderMessageItem = ({ item }: { item: Message }) => {
const isMe = item._edits?.text?.by?.isMe;
return (
<View
@@ -121,12 +116,8 @@ export function ChatScreen({ navigation }: { navigation: any }) {
!isMe ? styles.timestampOther : styles.timestampMy,
]}
>
{item?._edits?.text?.madeAt?.getHours().toString().padStart(2, "0")}
:
{item?._edits?.text?.madeAt
?.getMinutes()
.toString()
.padStart(2, "0")}
{item?._edits?.text?.madeAt?.getHours()}:
{item?._edits?.text?.madeAt?.getMinutes()}
</Text>
</View>
</View>

View File

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

View File

@@ -1,386 +1,5 @@
# chat-vue
## 0.0.112
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-browser@0.14.14
- jazz-vue@0.14.14
## 0.0.111
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-tools@0.14.10
- jazz-browser@0.14.10
- jazz-vue@0.14.10
## 0.0.110
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-browser@0.14.9
- jazz-vue@0.14.9
## 0.0.109
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-browser@0.14.8
- jazz-vue@0.14.8
## 0.0.108
### Patch Changes
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-browser@0.14.7
- jazz-vue@0.14.7
## 0.0.107
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-browser@0.14.6
- jazz-vue@0.14.6
## 0.0.106
### Patch Changes
- Updated dependencies [91cbb2f]
- Updated dependencies [20b3d88]
- jazz-tools@0.14.5
- jazz-browser@0.14.5
- jazz-vue@0.14.5
## 0.0.105
### Patch Changes
- Updated dependencies [011af55]
- jazz-tools@0.14.4
- jazz-browser@0.14.4
- jazz-vue@0.14.4
## 0.0.104
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-browser@0.14.2
- jazz-vue@0.14.2
## 0.0.103
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-browser@0.14.1
- jazz-vue@0.14.1
## 0.0.102
### Patch Changes
- Updated dependencies [5835ed1]
- jazz-tools@0.14.0
- jazz-browser@0.14.0
- jazz-vue@0.14.0
## 0.0.101
### Patch Changes
- jazz-browser@0.13.32
- jazz-vue@0.13.32
## 0.0.100
### Patch Changes
- Updated dependencies [e5b170f]
- jazz-tools@0.13.31
- jazz-browser@0.13.31
- jazz-vue@0.13.31
## 0.0.99
### Patch Changes
- jazz-browser@0.13.30
- jazz-tools@0.13.30
- jazz-vue@0.13.30
## 0.0.98
### Patch Changes
- jazz-browser@0.13.29
- jazz-tools@0.13.29
- jazz-vue@0.13.29
## 0.0.97
### Patch Changes
- jazz-browser@0.13.28
- jazz-tools@0.13.28
- jazz-vue@0.13.28
## 0.0.96
### Patch Changes
- jazz-browser@0.13.27
- jazz-tools@0.13.27
- jazz-vue@0.13.27
## 0.0.95
### Patch Changes
- Updated dependencies [ff846d9]
- jazz-tools@0.13.26
- jazz-browser@0.13.26
- jazz-vue@0.13.26
## 0.0.94
### Patch Changes
- jazz-browser@0.13.25
- jazz-tools@0.13.25
- jazz-vue@0.13.25
## 0.0.93
### Patch Changes
- Updated dependencies [02a240c]
- jazz-tools@0.13.23
- jazz-browser@0.13.23
- jazz-vue@0.13.23
## 0.0.92
### Patch Changes
- jazz-browser@0.13.21
- jazz-tools@0.13.21
- jazz-vue@0.13.21
## 0.0.91
### Patch Changes
- Updated dependencies [439f0fe]
- jazz-tools@0.13.20
- jazz-browser@0.13.20
- jazz-vue@0.13.20
## 0.0.90
### Patch Changes
- Updated dependencies [80530a4]
- jazz-tools@0.13.19
- jazz-browser@0.13.19
- jazz-vue@0.13.19
## 0.0.89
### Patch Changes
- Updated dependencies [761759c]
- jazz-tools@0.13.18
- jazz-browser@0.13.18
- jazz-vue@0.13.18
## 0.0.88
### Patch Changes
- jazz-browser@0.13.17
- jazz-tools@0.13.17
- jazz-vue@0.13.17
## 0.0.87
### Patch Changes
- jazz-browser@0.13.16
- jazz-tools@0.13.16
- jazz-vue@0.13.16
## 0.0.86
### Patch Changes
- jazz-browser@0.13.15
- jazz-tools@0.13.15
- jazz-vue@0.13.15
## 0.0.85
### Patch Changes
- jazz-browser@0.13.14
- jazz-tools@0.13.14
- jazz-vue@0.13.14
## 0.0.84
### Patch Changes
- jazz-browser@0.13.13
- jazz-tools@0.13.13
- jazz-vue@0.13.13
## 0.0.83
### Patch Changes
- Updated dependencies [4547525]
- Updated dependencies [29e05c4]
- jazz-tools@0.13.12
- jazz-browser@0.13.12
- jazz-vue@0.13.12
## 0.0.82
### Patch Changes
- Updated dependencies [17273a6]
- jazz-tools@0.13.11
- jazz-browser@0.13.11
- jazz-vue@0.13.11
## 0.0.81
### Patch Changes
- jazz-browser@0.13.10
- jazz-tools@0.13.10
- jazz-vue@0.13.10
## 0.0.80
### Patch Changes
- Updated dependencies [a6cf01f]
- jazz-tools@0.13.9
- jazz-browser@0.13.9
- jazz-vue@0.13.9
## 0.0.79
### Patch Changes
- Updated dependencies [bc3d7bb]
- jazz-tools@0.13.7
- jazz-browser@0.13.7
- jazz-vue@0.13.7
## 0.0.78
### Patch Changes
- Updated dependencies [fe6f561]
- jazz-tools@0.13.5
- jazz-browser@0.13.5
- jazz-vue@0.13.5
## 0.0.77
### Patch Changes
- Updated dependencies [3129982]
- jazz-browser@0.13.4
- jazz-tools@0.13.4
- jazz-vue@0.13.4
## 0.0.76
### Patch Changes
- Updated dependencies [12f8bfa]
- Updated dependencies [bd57177]
- jazz-tools@0.13.3
- jazz-browser@0.13.3
- jazz-vue@0.13.3
## 0.0.75
### Patch Changes
- jazz-browser@0.13.2
- jazz-tools@0.13.2
- jazz-vue@0.13.2
## 0.0.74
### Patch Changes
- Updated dependencies [afd1374]
- jazz-tools@0.13.0
- jazz-browser@0.13.0
- jazz-vue@0.13.0
## 0.0.73
### Patch Changes
- Updated dependencies [cc684eb]
- jazz-browser@0.12.2
- jazz-vue@0.12.2
- jazz-tools@0.12.2
## 0.0.72
### Patch Changes
- jazz-browser@0.12.1
- jazz-tools@0.12.1
- jazz-vue@0.12.1
## 0.0.71
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- Updated dependencies [4c01459]
- jazz-tools@0.12.0
- jazz-vue@0.12.0
- jazz-browser@0.12.0
## 0.0.70
### Patch Changes
- jazz-browser@0.11.8
- jazz-tools@0.11.8
- jazz-vue@0.11.8
## 0.0.69
### Patch Changes

View File

@@ -2,9 +2,9 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="./public/favicon.ico" type="image/png">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Jazz Chat Vue Example</title>
<title>Vite App</title>
</head>
<body>
<div id="app"></div>

View File

@@ -1,11 +1,11 @@
{
"name": "chat-vue",
"version": "0.0.112",
"version": "0.0.69",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build-type-check": "run-p type-check \"build {@}\" --",
"build-type-check": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build": "vite build",
"type-check": "vue-tsc --build --force",
@@ -31,8 +31,8 @@
"npm-run-all2": "^6.2.3",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "5.6.2",
"vite": "6.0.11",
"typescript": "~5.6.2",
"vite": "^6.0.11",
"vite-plugin-vue-devtools": "^7.4.6",
"vue-tsc": "^2.1.6"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1,9 +1,9 @@
<template>
<BubbleContainer :fromMe="lastEdit.by?.isMe">
<BubbleBody>{{ msg.text }}</BubbleBody>
<BubbleInfo :by="lastEdit.by?.profile?.name" :madeAt="lastEdit.madeAt" />
</BubbleContainer>
</template>
<BubbleContainer :fromMe="lastEdit.by?.isMe">
<BubbleBody>{{ msg.text }}</BubbleBody>
<BubbleInfo :by="lastEdit.by?.profile?.name" :madeAt="lastEdit.madeAt" />
</BubbleContainer>
</template>
<script lang="ts">
import { computed, defineComponent } from "vue";

View File

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

View File

@@ -25,7 +25,7 @@
</template>
<script lang="ts">
import { CoPlainText, type ID } from "jazz-tools";
import type { ID } from "jazz-tools";
import { useCoState } from "jazz-vue";
import { type PropType, computed, defineComponent, ref } from "vue";
import ChatBody from "../components/ChatBody.vue";
@@ -49,7 +49,7 @@ export default defineComponent({
},
},
setup(props) {
const chat = useCoState(Chat, props.chatId, { resolve: { $each: true } });
const chat = useCoState(Chat, props.chatId, [{}]);
const showNLastMessages = ref(30);
const displayedMessages = computed(() => {
@@ -61,12 +61,7 @@ export default defineComponent({
}
function handleSubmit(text: string) {
chat?.value?.push(
Message.create(
{ text: CoPlainText.create(text, chat.value._owner) },
chat.value._owner,
),
);
chat?.value?.push(Message.create({ text }, { owner: chat.value._owner }));
}
return {

View File

@@ -1,417 +1,5 @@
# jazz-example-chat
## 0.0.212
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-inspector@0.14.14
- jazz-react@0.14.14
## 0.0.211
### Patch Changes
- jazz-inspector@0.14.13
- jazz-react@0.14.13
## 0.0.210
### Patch Changes
- jazz-inspector@0.14.12
- jazz-react@0.14.12
## 0.0.209
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-inspector@0.14.10
- hash-slash@0.2.3
- jazz-react@0.14.10
- jazz-tools@0.14.10
## 0.0.208
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-inspector@0.14.9
- jazz-react@0.14.9
## 0.0.207
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-inspector@0.14.8
- jazz-react@0.14.8
## 0.0.206
### Patch Changes
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-inspector@0.14.7
- jazz-react@0.14.7
## 0.0.205
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-inspector@0.14.6
- jazz-react@0.14.6
## 0.0.204
### Patch Changes
- Updated dependencies [91cbb2f]
- Updated dependencies [20b3d88]
- jazz-tools@0.14.5
- jazz-inspector@0.14.5
- jazz-react@0.14.5
## 0.0.203
### Patch Changes
- Updated dependencies [011af55]
- jazz-tools@0.14.4
- jazz-inspector@0.14.4
- jazz-react@0.14.4
## 0.0.202
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-inspector@0.14.2
- jazz-react@0.14.2
## 0.0.201
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-inspector@0.14.1
- jazz-react@0.14.1
## 0.0.200
### Patch Changes
- Updated dependencies [5835ed1]
- jazz-tools@0.14.0
- jazz-inspector@0.14.0
- jazz-react@0.14.0
## 0.0.199
### Patch Changes
- jazz-react@0.13.32
## 0.0.198
### Patch Changes
- Updated dependencies [e5b170f]
- jazz-tools@0.13.31
- jazz-inspector@0.13.31
- jazz-react@0.13.31
## 0.0.197
### Patch Changes
- jazz-inspector@0.13.30
- jazz-react@0.13.30
- jazz-tools@0.13.30
## 0.0.196
### Patch Changes
- Updated dependencies [8e5ff13]
- jazz-inspector@0.13.29
- jazz-react@0.13.29
- jazz-tools@0.13.29
## 0.0.195
### Patch Changes
- jazz-inspector@0.13.28
- jazz-react@0.13.28
- jazz-tools@0.13.28
## 0.0.194
### Patch Changes
- jazz-inspector@0.13.27
- jazz-react@0.13.27
- jazz-tools@0.13.27
## 0.0.193
### Patch Changes
- Updated dependencies [ff846d9]
- jazz-tools@0.13.26
- jazz-inspector@0.13.26
- jazz-react@0.13.26
## 0.0.192
### Patch Changes
- jazz-inspector@0.13.25
- jazz-react@0.13.25
- jazz-tools@0.13.25
## 0.0.191
### Patch Changes
- Updated dependencies [02a240c]
- jazz-tools@0.13.23
- jazz-inspector@0.13.23
- jazz-react@0.13.23
## 0.0.190
### Patch Changes
- Updated dependencies [7de210f]
- jazz-inspector@0.13.21
- jazz-react@0.13.21
- jazz-tools@0.13.21
## 0.0.189
### Patch Changes
- Updated dependencies [439f0fe]
- jazz-tools@0.13.20
- jazz-inspector@0.13.20
- jazz-react@0.13.20
## 0.0.188
### Patch Changes
- Updated dependencies [80530a4]
- jazz-tools@0.13.19
- jazz-inspector@0.13.19
- jazz-react@0.13.19
## 0.0.187
### Patch Changes
- Updated dependencies [761759c]
- jazz-tools@0.13.18
- jazz-inspector@0.13.18
- jazz-react@0.13.18
## 0.0.186
### Patch Changes
- jazz-inspector@0.13.17
- jazz-react@0.13.17
- jazz-tools@0.13.17
## 0.0.185
### Patch Changes
- jazz-inspector@0.13.16
- jazz-react@0.13.16
- jazz-tools@0.13.16
## 0.0.184
### Patch Changes
- jazz-inspector@0.13.15
- jazz-react@0.13.15
- jazz-tools@0.13.15
## 0.0.183
### Patch Changes
- jazz-inspector@0.13.14
- jazz-react@0.13.14
- jazz-tools@0.13.14
## 0.0.182
### Patch Changes
- jazz-inspector@0.13.13
- jazz-react@0.13.13
- jazz-tools@0.13.13
## 0.0.181
### Patch Changes
- Updated dependencies [4547525]
- jazz-tools@0.13.12
- jazz-inspector@0.13.12
- jazz-react@0.13.12
## 0.0.180
### Patch Changes
- Updated dependencies [17273a6]
- jazz-tools@0.13.11
- jazz-inspector@0.13.11
- jazz-react@0.13.11
## 0.0.179
### Patch Changes
- jazz-inspector@0.13.10
- jazz-react@0.13.10
- jazz-tools@0.13.10
## 0.0.178
### Patch Changes
- Updated dependencies [a6cf01f]
- jazz-tools@0.13.9
- jazz-inspector@0.13.9
- jazz-react@0.13.9
## 0.0.177
### Patch Changes
- Updated dependencies [22b5c4f]
- Updated dependencies [31ea2ef]
- Updated dependencies [4530c4a]
- Updated dependencies [bc3d7bb]
- jazz-inspector@0.13.7
- jazz-tools@0.13.7
- jazz-react@0.13.7
## 0.0.176
### Patch Changes
- Updated dependencies [c320615]
- jazz-inspector@0.13.6
## 0.0.175
### Patch Changes
- Updated dependencies [08ae9b2]
- Updated dependencies [fe6f561]
- jazz-inspector@0.13.5
- jazz-tools@0.13.5
- jazz-react@0.13.5
## 0.0.174
### Patch Changes
- Updated dependencies [3129982]
- jazz-react@0.13.4
- jazz-tools@0.13.4
- jazz-inspector@0.13.4
## 0.0.173
### Patch Changes
- Updated dependencies [12f8bfa]
- Updated dependencies [bd57177]
- Updated dependencies [017f6c8]
- jazz-tools@0.13.3
- jazz-inspector@0.13.3
- jazz-react@0.13.3
## 0.0.172
### Patch Changes
- Updated dependencies [ae4be2b]
- jazz-inspector@0.13.2
- jazz-react@0.13.2
- jazz-tools@0.13.2
## 0.0.171
### Patch Changes
- Updated dependencies [2796689]
- Updated dependencies [afd1374]
- Updated dependencies [2224ed4]
- jazz-inspector@0.13.0
- jazz-tools@0.13.0
- jazz-react@0.13.0
## 0.0.170
### Patch Changes
- Updated dependencies [8a71835]
- jazz-inspector@0.12.2
- jazz-react@0.12.2
- jazz-tools@0.12.2
## 0.0.169
### Patch Changes
- jazz-inspector@0.12.1
- jazz-react@0.12.1
- jazz-tools@0.12.1
## 0.0.168
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- Updated dependencies [9a56bb3]
- jazz-tools@0.12.0
- jazz-inspector@0.12.0
- jazz-react@0.12.0
## 0.0.167
### Patch Changes
- Updated dependencies [71b9390]
- jazz-inspector@0.11.8
- jazz-react@0.11.8
- jazz-tools@0.11.8
## 0.0.166
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat",
"private": true,
"version": "0.0.212",
"version": "0.0.166",
"type": "module",
"scripts": {
"dev": "vite",
@@ -19,20 +19,19 @@
"jazz-react": "workspace:*",
"jazz-tools": "workspace:*",
"lucide-react": "^0.274.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"zod": "4.0.0-beta.20250505T012514"
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@playwright/test": "^1.50.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react-swc": "^3.3.2",
"autoprefixer": "^10.4.20",
"is-ci": "^3.0.1",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "5.6.2",
"vite": "6.0.11"
"typescript": "~5.6.2",
"vite": "^6.0.11"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@@ -3,7 +3,7 @@ import { getRandomUsername, inIframe, onChatLoad } from "@/util.ts";
import { useIframeHashRouter } from "hash-slash";
import { JazzInspector } from "jazz-inspector";
import { JazzProvider, useAccount } from "jazz-react";
import { Group } from "jazz-tools";
import { Group, ID } from "jazz-tools";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { ChatScreen } from "./chatScreen.tsx";
@@ -43,7 +43,7 @@ export function App() {
</TopBar>
{router.route({
"/": () => createChat() as never,
"/chat/:id": (id) => <ChatScreen chatID={id} />,
"/chat/:id": (id) => <ChatScreen chatID={id as ID<Chat>} />,
})}
</AppContainer>
);

View File

@@ -1,5 +1,5 @@
import { createImage, useAccount, useCoState } from "jazz-react";
import { Account, co } from "jazz-tools";
import { Account, ID } from "jazz-tools";
import { useState } from "react";
import { Chat, Message } from "./schema.ts";
import {
@@ -15,11 +15,9 @@ import {
TextInput,
} from "./ui.tsx";
export function ChatScreen(props: { chatID: string }) {
const chat = useCoState(Chat, props.chatID, {
resolve: { $each: { text: true } },
});
export function ChatScreen(props: { chatID: ID<Chat> }) {
const account = useAccount();
const chat = useCoState(Chat, props.chatID, [{}]);
const [showNLastMessages, setShowNLastMessages] = useState(30);
if (!chat)
@@ -38,15 +36,7 @@ export function ChatScreen(props: { chatID: string }) {
}
createImage(file, { owner: chat._owner }).then((image) => {
chat.push(
Message.create(
{
text: co.plainText().create(file.name, chat._owner),
image: image,
},
chat._owner,
),
);
chat.push(Message.create({ text: file.name, image: image }, chat._owner));
});
};
@@ -76,12 +66,7 @@ export function ChatScreen(props: { chatID: string }) {
<TextInput
onSubmit={(text) => {
chat.push(
Message.create(
{ text: co.plainText().create(text, chat._owner) },
chat._owner,
),
);
chat.push(Message.create({ text }, { owner: chat._owner }));
}}
/>
</InputBar>
@@ -89,11 +74,8 @@ export function ChatScreen(props: { chatID: string }) {
);
}
function ChatBubble(props: {
me: Account;
msg: co.loaded<typeof Message, { text: true }>;
}) {
if (!props.me.canRead(props.msg) || !props.msg.text?.toString()) {
function ChatBubble(props: { me: Account; msg: Message }) {
if (!props.me.canRead(props.msg)) {
return (
<BubbleContainer fromMe={false}>
<BubbleBody fromMe={false}>
@@ -107,7 +89,7 @@ function ChatBubble(props: {
}
const lastEdit = props.msg._edits.text;
const fromMe = lastEdit?.by?.isMe;
const fromMe = lastEdit.by?.isMe;
const { text, image } = props.msg;
return (
@@ -116,9 +98,7 @@ function ChatBubble(props: {
{image && <BubbleImage image={image} />}
<BubbleText text={text} />
</BubbleBody>
{lastEdit && (
<BubbleInfo by={lastEdit.by?.profile?.name} madeAt={lastEdit.madeAt} />
)}
<BubbleInfo by={lastEdit.by?.profile?.name} madeAt={lastEdit.madeAt} />
</BubbleContainer>
);
}

View File

@@ -1,10 +1,8 @@
import { co, z } from "jazz-tools";
import { CoList, CoMap, ImageDefinition, co } from "jazz-tools";
export const Message = co.map({
text: co.plainText(),
image: z.optional(co.image()),
});
export type Message = co.loaded<typeof Message>;
export class Message extends CoMap {
text = co.string;
image = co.optional.ref(ImageDefinition);
}
export const Chat = co.list(Message);
export type Chat = co.loaded<typeof Chat>;
export class Chat extends CoList.Of(co.ref(Message)) {}

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