Compare commits

..

2 Commits

Author SHA1 Message Date
Trisha Lim
95f51ea783 Update gitignore 2025-01-24 14:51:57 +08:00
Trisha Lim
82b0268c4d Fix example readme instructions 2025-01-24 14:49:54 +08:00
875 changed files with 17315 additions and 60717 deletions

View File

@@ -1,6 +0,0 @@
---
"jazz-tools": minor
"cojson": minor
---
Check CoValue access permissions when loading

View File

@@ -9,15 +9,12 @@
"cojson-storage",
"cojson-storage-indexeddb",
"cojson-storage-sqlite",
"cojson-storage-rn-sqlite",
"cojson-transport-ws",
"jazz-browser",
"jazz-auth-clerk",
"jazz-browser-auth-clerk",
"jazz-browser-media-images",
"jazz-inspector",
"jazz-nodejs",
"jazz-react",
"jazz-react-core",
"jazz-react-auth-clerk",
"jazz-react-native",
"jazz-react-native-auth-clerk",

View File

@@ -1,5 +0,0 @@
---
"jazz-tools": minor
---
Implement new API for deep loading

View File

@@ -1,5 +0,0 @@
---
"jazz-tools": minor
---
The .load function now returns `null` on error

View File

@@ -1,5 +0,0 @@
---
"cojson": minor
---
Return the EVERYONE role if the account is not direct a member of the group

View File

@@ -1,5 +0,0 @@
---
"jazz-vue": patch
---
Fix types compilation for useAccount

View File

@@ -1,39 +0,0 @@
name: Setup Android Emulator
inputs:
api-level:
description: 'API level to use for the emulator'
required: true
default: '29'
runs:
using: "composite"
steps:
- name: Enable KVM
shell: bash
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Gradle cache
uses: gradle/actions/setup-gradle@v4
- name: AVD cache
uses: useblacksmith/cache@v5
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-${{ inputs.api-level }}
- name: Create AVD and Generate Snapshot for Caching
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ inputs.api-level }}
force-avd-creation: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -no-metrics
disable-animations: false
script: echo "Generated AVD snapshot for caching."

View File

@@ -1,36 +0,0 @@
name: Get and Build Source Code
runs:
using: "composite"
steps:
- name: Enable latestcorepack
shell: bash
run: |
echo "Before: corepack version => $(corepack --version || echo 'not installed')"
npm install -g corepack@latest
echo "After : corepack version => $(corepack --version)"
corepack enable
pnpm --version
- name: Install Node.js
uses: useblacksmith/setup-node@v5
with:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: useblacksmith/cache@v5
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
shell: bash
run: pnpm install --frozen-lockfile

View File

@@ -6,7 +6,7 @@ on:
jobs:
build-examples:
runs-on: blacksmith-4vcpu-ubuntu-2204
runs-on: ubuntu-latest
strategy:
matrix:
example: [
@@ -19,16 +19,40 @@ jobs:
"pets",
"reactions",
"todo",
"onboarding",
]
steps:
- name: Checkout
uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
- name: Setup Source Code
uses: ./.github/actions/source-code/
- name: Enable corepack
run: corepack enable
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Pnpm Build
run: |

View File

@@ -2,25 +2,51 @@ name: Build Starters
on:
push:
branches: ["main"]
branches: [ "main" ]
jobs:
build-starters:
runs-on: blacksmith-4vcpu-ubuntu-2204
runs-on: ubuntu-latest
strategy:
matrix:
starter: ["react-passkey-auth"]
starter: [
"react-demo-auth-tailwind",
]
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: actions/checkout@v3
with:
submodules: true
- name: Setup Source Code
uses: ./.github/actions/source-code/
- name: Enable corepack
run: corepack enable
- name: Pnpm Build
run: |
pnpm install
pnpm turbo build;
working-directory: ./starters/${{ matrix.starter }}
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Pnpm Build
run: |
pnpm install
pnpm turbo build;
working-directory: ./starters/${{ matrix.starter }}

View File

@@ -6,7 +6,7 @@ on:
jobs:
quality:
runs-on: blacksmith-4vcpu-ubuntu-2204
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

View File

@@ -1,85 +0,0 @@
name: End-to-End Tests for React Native
on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- ".github/actions/android-emulator/**"
- ".github/actions/source-code/**"
- ".github/workflows/e2e-rn-test.yml"
- "examples/chat-rn/**"
- "examples/chat-rn-clerk/**"
- "packages/**"
jobs:
e2e-tests:
runs-on: blacksmith-4vcpu-ubuntu-2204
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Source Code
uses: ./.github/actions/source-code/
- name: Create Output Directory
run: |
mkdir -p ~/output
- name: Setup JDK
uses: actions/setup-java@v4
with:
distribution: corretto
java-version: 22
cache: gradle
- name: Pnpm Build
run: pnpm turbo build --filter="./packages/*"
- name: chat-rn App Pre Build
working-directory: ./examples/chat-rn
run: |
pnpm build
pnpm expo prebuild --clean
- name: Install Maestro
run: |
curl -fsSL "https://get.maestro.mobile.dev" | bash
- name: Setup Android Emulator
id: android-emulator
uses: ./.github/actions/android-emulator/
with:
api-level: 29
- name: Test App
uses: reactivecircus/android-emulator-runner@v2
id: e2e_test
continue-on-error: true
with:
api-level: 29
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -no-metrics
disable-animations: true
working-directory: ./examples/chat-rn/
script: ./test/e2e/run.sh
- name: Copy Maestro Output
if: steps.e2e_test.outcome != 'success'
run: |
cp -r ~/.maestro/tests/* ~/output
- name: Upload Output Files
if: steps.e2e_test.outcome != 'success'
uses: actions/upload-artifact@v4
with:
name: e2e-test-output
path: ~/output/*
retention-days: 5
- name: Exit with Test Result
if: always()
run: |
if [ "${{ steps.e2e_test.outcome }}" != "success" ]; then
exit 1
fi

View File

@@ -8,16 +8,38 @@ on:
jobs:
test:
runs-on: blacksmith-4vcpu-ubuntu-2204
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
- name: Setup Source Code
uses: ./.github/actions/source-code/
- name: Enable corepack
run: corepack enable
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build jazz-run
run: pnpm exec turbo build && chmod +x dist/index.js;
@@ -26,3 +48,4 @@ jobs:
- name: Run create account
run: ./dist/index.js account create --name "Jazz Run CI test"
working-directory: ./packages/jazz-run

View File

@@ -9,19 +9,41 @@ on:
jobs:
test:
timeout-minutes: 60
runs-on: blacksmith-4vcpu-ubuntu-2204
runs-on: ubuntu-latest
continue-on-error: true
strategy:
matrix:
project: ["tests/e2e", "examples/chat", "examples/file-share-svelte", "examples/form", "examples/music-player", "examples/pets", "starters/react-passkey-auth"]
project: ["tests/e2e", "examples/chat", "examples/file-share-svelte", "examples/form", "examples/music-player", "examples/pets", "examples/onboarding", "starters/react-demo-auth-tailwind"]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: true
- name: Setup Source Code
uses: ./.github/actions/source-code/
- name: Enable corepack
run: corepack enable
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Pnpm Build
run: pnpm turbo build

View File

@@ -1,102 +0,0 @@
name: Pre-Publish tagged Pull Requests
on:
pull_request:
types: [opened, synchronize, reopened, labeled]
jobs:
pre-release:
if: contains(github.event.pull_request.labels.*.name, 'pre-release')
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Source Code
uses: ./.github/actions/source-code/
- name: Pnpm Build
run: pnpm turbo build --filter="./packages/*"
- name: Pre publish
run: pnpm exec pkg-pr-new publish --json output.json --comment=off "./packages/*"
- name: Post or update comment
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const output = JSON.parse(fs.readFileSync('output.json', 'utf8'));
const packages = output.packages
.map((p) => `- ${p.name}: ${p.url}`)
.join('\n');
const sha =
context.event_name === 'pull_request'
? context.payload.pull_request.head.sha
: context.payload.after;
const resolutions = Object.fromEntries(
output.packages.map((p) => [p.name, p.url])
);
const commitUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/commit/${sha}`;
const body = `## Jazz pre-release
### Packages:
\`\`\`json
${JSON.stringify(resolutions, null, 4)}
\`\`\`
[View Commit](${commitUrl})`;
async function logPublishInfo() {
console.log('\n' + '='.repeat(50));
console.log('Publish Information');
console.log('='.repeat(50));
console.log('\nPublished Packages:');
console.log(output.packages);
console.log('\nTemplates:');
console.log(templates);
console.log(`\nCommit URL: ${commitUrl}`);
console.log('\n' + '='.repeat(50));
}
if (context.eventName === 'pull_request') {
if (context.issue.number) {
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body,
});
}
} else if (context.eventName === 'push') {
const pullRequests = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
head: `${context.repo.owner}:${context.ref.replace(
'refs/heads/',
''
)}`,
});
if (pullRequests.data.length > 0) {
await github.rest.issues.createComment({
issue_number: pullRequests.data[0].number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body,
});
} else {
console.log(
'No open pull request found for this push. Logging publish information to console:'
);
await logPublishInfo();
}
}

View File

@@ -17,16 +17,35 @@ concurrency: ${{ github.workflow }}-${{ github.ref }}
jobs:
release:
name: Release
runs-on: blacksmith-4vcpu-ubuntu-2204
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Setup Source Code
uses: ./.github/actions/source-code/
- name: Enable corepack
run: corepack enable
- name: Build packages
run: pnpm exec turbo run build --filter='./packages/*'
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Create Release Pull Request or Publish to npm
id: changesets

View File

@@ -9,20 +9,39 @@ on:
jobs:
unit-tests:
runs-on: blacksmith-4vcpu-ubuntu-2204
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Source Code
uses: ./.github/actions/source-code/
- name: Enable corepack
run: corepack enable
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Pnpm Build
run: pnpm turbo build --filter="./packages/*"
- name: Install Playwright Browsers
run: pnpm exec playwright install
- name: Unit Tests
run: pnpm test:ci

6
.gitignore vendored
View File

@@ -7,15 +7,11 @@ docsTmp
coverage
.direnv
# Typescript
**/*.tsbuildinfo
# Next.js
**/.next
# Vite output
**/dist
__screenshots__
# Playwright
test-results
@@ -23,5 +19,3 @@ test-results
.husky
.vscode/settings.json
.svelte-kit

View File

@@ -36,7 +36,7 @@ We welcome all ideas! If you have suggestions, feel free to open an issue marked
### 5. Local Setup
You'll need Node.js 22.x installed (we're working on support for 23.x), and pnpm 9.x installed. If you're using nix, run `nix develop` to get a shell with the correct versions of everything installed.
You'll need Node.js 20.x or 22.x installed (we're working on support for 23.x), and pnpm 9.x installed. If you're using nix, run `nix develop` to get a shell with the correct versions of everything installed.
1. **Clone the repository**:
```bash
@@ -48,25 +48,7 @@ You'll need Node.js 22.x installed (we're working on support for 23.x), and pnpm
pnpm install
```
3. **Install homepage dependencies**:
```bash
cd homepage && pnpm install
```
4. **Go back to the project root**:
```bash
cd ..
```
4. **Build the packages**:
```bash
pnpm build
```
5. **Run tests** to verify everything is working:
3. **Run tests** to verify everything is working:
```bash
pnpm test
```

View File

@@ -1,4 +1,4 @@
Copyright 2025, Garden Computing, Inc.
Copyright 2024, Garden Computing, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -16,4 +16,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.

View File

@@ -17,4 +17,4 @@ For community and support, please join our [Discord](https://discord.gg/utDMjHYg
- Community & support: [Discord](https://discord.gg/utDMjHYg42)
- Updates: [X](https://x.com/jazz_tools) & [Email](https://garden.co/news)
Copyright 2025 — Garden Computing, Inc.
Copyright 2024 — Garden Computing, Inc.

View File

@@ -12,9 +12,7 @@
"**/ios/**",
"**/android/**",
"packages/jazz-svelte/**",
"examples/*svelte*/**",
"homepage/homepage/**",
"**/package.json"
"examples/*svelte*/**"
]
},
"formatter": {
@@ -54,24 +52,21 @@
}
},
{
"include": ["packages/cojson-storage*/**", "cojson-transport-ws/**"],
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
}
},
{
"include": ["packages/**/src/tests/**"],
"include": ["packages/**/src/tests/**", "packages/**/src/test/**"],
"linter": {
"rules": {
"correctness": {
"useImportExtensions": "off"
},
"style": {
"noNonNullAssertion": "off"
},
}
}
}
},
{
"include": ["packages/cojson-storage-indexeddb/**"],
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"suspicious": {
"noExplicitAny": "info"
}

View File

@@ -1,308 +1,5 @@
# chat-rn-clerk
## 1.0.87
### Patch Changes
- 1bfa9bb: Removed when="singedUp" from examples apps' Jazz providers. This is a really niche use-case option and can lead to broken-feeling experiences when anonymous users try to load something.
- Updated dependencies [e7c85b7]
- jazz-react-native@0.11.6
- jazz-tools@0.11.6
- jazz-react-native-auth-clerk@0.11.6
- jazz-react-native-media-images@0.11.6
## 1.0.86
### Patch Changes
- jazz-react-native@0.11.5
- jazz-react-native-auth-clerk@0.11.5
- jazz-tools@0.11.5
- jazz-react-native-media-images@0.11.5
## 1.0.85
### Patch Changes
- Updated dependencies [57a3dbe]
- Updated dependencies [a717754]
- Updated dependencies [a91f343]
- jazz-tools@0.11.4
- jazz-react-native@0.11.4
- jazz-react-native-auth-clerk@0.11.4
- jazz-react-native-media-images@0.11.4
## 1.0.84
### Patch Changes
- jazz-react-native@0.11.3
- jazz-react-native-auth-clerk@0.11.3
- jazz-tools@0.11.3
- jazz-react-native-media-images@0.11.3
## 1.0.83
### Patch Changes
- Updated dependencies [6892dc6]
- jazz-tools@0.11.2
- jazz-react-native@0.11.2
- jazz-react-native-auth-clerk@0.11.2
- jazz-react-native-media-images@0.11.2
## 1.0.82
### Patch Changes
- jazz-react-native@0.11.1
- jazz-react-native-auth-clerk@0.11.1
## 1.0.81
### 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-media-images@0.11.0
- jazz-react-native-auth-clerk@0.11.0
- jazz-react-native@0.11.0
## 1.0.80
### Patch Changes
- Updated dependencies [2f99de0]
- jazz-tools@0.10.15
- jazz-react-native@0.10.15
- jazz-react-native-auth-clerk@0.10.15
- jazz-react-native-media-images@0.10.15
## 1.0.79
### Patch Changes
- Updated dependencies [75211e3]
- jazz-tools@0.10.14
- jazz-react-native@0.10.14
- jazz-react-native-auth-clerk@0.10.14
- jazz-react-native-media-images@0.10.14
## 1.0.78
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react-native@0.10.13
- jazz-react-native-auth-clerk@0.10.13
- jazz-react-native-media-images@0.10.13
## 1.0.77
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react-native@0.10.12
- jazz-react-native-auth-clerk@0.10.12
- jazz-react-native-media-images@0.10.12
## 1.0.76
### Patch Changes
- Updated dependencies [5a54e4a]
- jazz-react-native@0.10.11
- jazz-react-native-auth-clerk@0.10.11
## 1.0.75
### Patch Changes
- Updated dependencies [3405d8f]
- jazz-react-native@0.10.10
- jazz-react-native-auth-clerk@0.10.10
## 1.0.74
### Patch Changes
- jazz-react-native-auth-clerk@0.10.9
## 1.0.73
### Patch Changes
- Updated dependencies [2fb6428]
- jazz-tools@0.10.8
- jazz-react-native@0.10.8
- jazz-react-native-auth-clerk@0.10.8
- jazz-react-native-media-images@0.10.8
## 1.0.72
### Patch Changes
- Updated dependencies [1136d9b]
- Updated dependencies [0eed228]
- jazz-react-native@0.10.7
- jazz-tools@0.10.7
- jazz-react-native-auth-clerk@0.10.7
- jazz-react-native-media-images@0.10.7
## 1.0.71
### Patch Changes
- Updated dependencies [ada802b]
- jazz-tools@0.10.6
- jazz-react-native@0.10.6
- jazz-react-native-auth-clerk@0.10.6
- jazz-react-native-media-images@0.10.6
## 1.0.70
### Patch Changes
- Updated dependencies [59ff77e]
- jazz-tools@0.10.5
- jazz-react-native@0.10.5
- jazz-react-native-auth-clerk@0.10.5
- jazz-react-native-media-images@0.10.5
## 1.0.69
### Patch Changes
- jazz-react-native@0.10.4
- jazz-react-native-auth-clerk@0.10.4
- jazz-tools@0.10.4
- jazz-react-native-media-images@0.10.4
## 1.0.68
### Patch Changes
- Updated dependencies [d8582fc]
- jazz-tools@0.10.3
- jazz-react-native@0.10.3
- jazz-react-native-auth-clerk@0.10.3
- jazz-react-native-media-images@0.10.3
## 1.0.67
### Patch Changes
- jazz-react-native@0.10.2
- jazz-react-native-auth-clerk@0.10.2
- jazz-tools@0.10.2
- jazz-react-native-media-images@0.10.2
## 1.0.66
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-react-native@0.10.1
- jazz-react-native-auth-clerk@0.10.1
- jazz-react-native-media-images@0.10.1
## 1.0.65
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-react-native-auth-clerk@0.10.0
- jazz-react-native@0.10.0
- jazz-tools@0.10.0
- jazz-react-native-media-images@0.10.0
## 1.0.64
### Patch Changes
- jazz-react-native@0.9.23
- jazz-react-native-auth-clerk@0.9.23
- jazz-tools@0.9.23
- jazz-react-native-media-images@0.9.23
## 1.0.63
### Patch Changes
- jazz-react-native@0.9.22
- jazz-react-native-auth-clerk@0.9.22
## 1.0.62
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-react-native@0.9.21
- jazz-react-native-auth-clerk@0.9.21
- jazz-react-native-media-images@0.9.21
## 1.0.61
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-react-native@0.9.20
- jazz-react-native-auth-clerk@0.9.20
- jazz-react-native-media-images@0.9.20
## 1.0.60
### Patch Changes
- jazz-react-native@0.9.19
- jazz-react-native-auth-clerk@0.9.19
- jazz-tools@0.9.19
- jazz-react-native-media-images@0.9.19
## 1.0.59
### Patch Changes
- jazz-react-native@0.9.18
- jazz-react-native-auth-clerk@0.9.18
- jazz-tools@0.9.18
- jazz-react-native-media-images@0.9.18
## 1.0.58
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-react-native@0.9.17
- jazz-react-native-auth-clerk@0.9.17
- jazz-react-native-media-images@0.9.17
## 1.0.57
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-react-native-auth-clerk@0.9.16
- jazz-tools@0.9.16
- jazz-react-native@0.9.16
- jazz-react-native-media-images@0.9.16
## 1.0.56
### Patch Changes

View File

@@ -1,9 +1,9 @@
import { Redirect, Stack } from "expo-router";
import { useIsAuthenticated } from "jazz-react-native";
import React from "react";
import { useAuth } from "../../src/auth-context";
export default function HomeLayout() {
const isAuthenticated = useIsAuthenticated();
const { isAuthenticated } = useAuth();
if (isAuthenticated) {
return <Redirect href={"/chat"} />;

View File

@@ -1,8 +1,8 @@
import { Redirect, Stack } from "expo-router";
import { useIsAuthenticated } from "jazz-react-native";
import { useAuth } from "../../src/auth-context";
export default function UnAuthenticatedLayout() {
const isAuthenticated = useIsAuthenticated();
const { isAuthenticated } = useAuth();
if (isAuthenticated) {
return <Redirect href={"/chat"} />;

View File

@@ -1,6 +1,5 @@
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 } from "expo-router";
import * as SplashScreen from "expo-splash-screen";
@@ -34,11 +33,7 @@ export default function RootLayout() {
}
return (
<ClerkProvider
tokenCache={tokenCache}
publishableKey={publishableKey}
__experimental_resourceCache={secureStore}
>
<ClerkProvider tokenCache={tokenCache} publishableKey={publishableKey}>
<ClerkLoaded>
<JazzAndAuth>
<Slot />

View File

@@ -28,7 +28,7 @@ export default function Conversation() {
const { me } = useAccount();
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);
@@ -71,7 +71,7 @@ export default function Conversation() {
const loadChat = async (chatId: ID<Chat>) => {
try {
const chat = await Chat.load(chatId, me);
const chat = await Chat.load(chatId, me, []);
setChat(chat);
} catch (error) {
console.log("Error loading chat", error);

View File

@@ -20,15 +20,10 @@ export default function ChatScreen() {
const navigation = useNavigation();
const { user } = useUser();
function handleLogOut() {
logOut();
router.navigate("/");
}
useLayoutEffect(() => {
navigation.setOptions({
headerTitle: "Chat",
headerRight: () => <Button onPress={handleLogOut} title="Logout" />,
headerRight: () => <Button onPress={logOut} title="Logout" />,
});
}, [navigation]);

View File

@@ -19,6 +19,7 @@ config.resolver.nodeModulesPaths = [
path.resolve(workspaceRoot, "node_modules"),
];
config.resolver.sourceExts = ["mjs", "js", "json", "ts", "tsx"];
config.resolver.unstable_enablePackageExports = true;
config.resolver.requireCycleIgnorePatterns = [
/(^|\/|\\)node_modules($|\/|\\)/,
/(^|\/|\\)packages($|\/|\\)/,

View File

@@ -1,7 +1,7 @@
{
"name": "chat-rn-clerk",
"main": "index.js",
"version": "1.0.87",
"version": "1.0.56",
"scripts": {
"build": "expo export -p ios",
"start": "expo start",
@@ -9,22 +9,23 @@
"format-and-lint:fix": "biome check . --write",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web"
"web": "expo start --web",
"test": "jest --watchAll"
},
"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",
"@craftzdog/react-native-buffer": "6.0.5",
"@clerk/clerk-expo": "^2.2.21",
"@expo/vector-icons": "^14.0.2",
"@op-engineering/op-sqlite": "^11.2.12",
"@react-native-community/netinfo": "^11.4.1",
"@react-navigation/native": "^7.0.13",
"@react-navigation/native-stack": "^7.1.14",
"base-64": "^1.0.0",
"buffer": "^6.0.3",
"clsx": "^2.0.0",
"expo": "^52.0.0",
"expo-build-properties": "~0.13.1",
@@ -50,14 +51,18 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-native": "~0.76.3",
"react-native-fetch-api": "^3.0.0",
"react-native-gesture-handler": "~2.20.2",
"react-native-get-random-values": "^1.11.0",
"react-native-polyfill-globals": "^3.1.0",
"react-native-quick-base64": "^2.1.2",
"react-native-reanimated": "~3.16.3",
"react-native-safe-area-context": "4.12.0",
"react-native-screens": "4.1.0",
"react-native-url-polyfill": "^2.0.0",
"react-native-web": "~0.19.13",
"readable-stream": "4.7.0"
"text-encoding": "^0.7.0",
"web-streams-polyfill": "^3.2.1"
},
"devDependencies": {
"@babel/core": "^7.20.0",
@@ -67,7 +72,7 @@
"jest": "^29.2.1",
"jest-expo": "~52.0.2",
"react-test-renderer": "18.2.0",
"tailwindcss": "^3.4.17",
"tailwindcss": "^3.4.15",
"typescript": "~5.6.2"
},
"private": true

View File

@@ -1,17 +1,8 @@
/* eslint-disable import/order */
// @ts-expect-error - @types/react-native doesn't cover this file
import { polyfillGlobal } from "react-native/Libraries/Utilities/PolyfillFunctions";
import { Buffer } from "@craftzdog/react-native-buffer";
polyfillGlobal("Buffer", () => Buffer);
// @ts-expect-error - @types/readable-stream doesn't have ReadableStream type
import { ReadableStream } from "readable-stream";
polyfillGlobal("ReadableStream", () => ReadableStream);
import "react-native-polyfill-globals/auto";
import "@azure/core-asynciterator-polyfill";
import { Buffer } from "buffer";
import { polyfillGlobal } from "react-native/Libraries/Utilities/PolyfillFunctions";
import { ReadableStream } from "web-streams-polyfill/ponyfill/es6";
import "@bacons/text-decoder/install";
import "react-native-get-random-values";
polyfillGlobal("Buffer", () => Buffer);
polyfillGlobal("ReadableStream", () => ReadableStream);

View File

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

View File

@@ -1,20 +1,49 @@
import { useClerk } from "@clerk/clerk-expo";
import { JazzProviderWithClerk } from "jazz-react-native-auth-clerk";
import React, { PropsWithChildren } from "react";
import { apiKey } from "./apiKey";
import { useClerk, useUser } from "@clerk/clerk-expo";
import { JazzProvider, setupKvStore } from "jazz-react-native";
import { useJazzClerkAuth } from "jazz-react-native-auth-clerk";
import React, { createContext, PropsWithChildren, useContext } from "react";
import { Text, View } from "react-native";
const AuthContext = createContext<{
isAuthenticated: boolean;
isLoading: boolean;
}>({
isAuthenticated: false,
isLoading: true,
});
export function useAuth() {
return useContext(AuthContext);
}
const kvStore = setupKvStore();
export function JazzAndAuth({ children }: PropsWithChildren) {
const { isSignedIn, isLoaded: isClerkLoaded } = useUser();
const clerk = useClerk();
const [auth, state] = useJazzClerkAuth(clerk, kvStore);
const isAuthenticated = Boolean(isSignedIn && isClerkLoaded && auth);
return (
<JazzProviderWithClerk
clerk={clerk}
storage="sqlite"
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
<AuthContext.Provider
value={{ isAuthenticated, isLoading: !isClerkLoaded || !auth }}
>
{children}
</JazzProviderWithClerk>
{state?.errors?.length > 0 &&
state.errors.map((error) => (
<View key={error}>
<Text style={{ color: "red" }}>{error}</Text>
</View>
))}
{auth && clerk.user ? (
<JazzProvider
auth={auth}
storage="sqlite"
peer="wss://cloud.jazz.tools/?key=chat-rn-clerk-example-jazz@garden.co"
>
{children}
</JazzProvider>
) : (
children
)}
</AuthContext.Provider>
);
}

View File

@@ -1,245 +1,5 @@
# chat-rn
## 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

View File

@@ -19,6 +19,7 @@ config.resolver.nodeModulesPaths = [
path.resolve(workspaceRoot, "node_modules"),
];
config.resolver.sourceExts = ["mjs", "js", "json", "ts", "tsx"];
config.resolver.unstable_enablePackageExports = true;
config.resolver.requireCycleIgnorePatterns = [
/(^|\/|\\)node_modules($|\/|\\)/,
/(^|\/|\\)packages($|\/|\\)/,

View File

@@ -1,6 +1,6 @@
{
"name": "chat-rn",
"version": "1.0.83",
"version": "1.0.53",
"main": "index.js",
"scripts": {
"build": "expo export -p ios",
@@ -13,17 +13,17 @@
},
"dependencies": {
"@azure/core-asynciterator-polyfill": "^1.0.2",
"@bacons/text-decoder": "0.0.0",
"@craftzdog/react-native-buffer": "6.0.5",
"@op-engineering/op-sqlite": "^11.2.12",
"@react-native-community/netinfo": "^11.4.1",
"@react-navigation/native": "^7.0.13",
"@react-navigation/native-stack": "^7.1.14",
"base-64": "^1.0.0",
"clsx": "^2.0.0",
"expo": "^52.0.0",
"expo-build-properties": "~0.13.1",
"expo-clipboard": "~7.0.0",
"expo-constants": "~17.0.3",
"expo-crypto": "~14.0.1",
"expo-dev-client": "~5.0.5",
"expo-linking": "~7.0.3",
"expo-secure-store": "~14.0.0",
@@ -34,16 +34,19 @@
"nativewind": "^4.1.21",
"react": "^18.3.1",
"react-native": "~0.76.3",
"react-native-fetch-api": "^3.0.0",
"react-native-get-random-values": "^1.11.0",
"react-native-polyfill-globals": "^3.1.0",
"react-native-safe-area-context": "4.12.0",
"react-native-screens": "4.1.0",
"react-native-url-polyfill": "^2.0.0",
"readable-stream": "4.7.0"
"text-encoding": "^0.7.0",
"web-streams-polyfill": "^3.2.1"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@types/react": "^18.3.12",
"tailwindcss": "^3.4.17",
"tailwindcss": "^3.4.15",
"typescript": "~5.6.2"
},
"private": true

View File

@@ -1,17 +1,6 @@
/* eslint-disable import/order */
// @ts-expect-error - @types/react-native doesn't cover this file
import { polyfillGlobal } from "react-native/Libraries/Utilities/PolyfillFunctions";
import { Buffer } from "@craftzdog/react-native-buffer";
polyfillGlobal("Buffer", () => Buffer);
// @ts-expect-error - @types/readable-stream doesn't have ReadableStream type
import { ReadableStream } from "readable-stream";
polyfillGlobal("ReadableStream", () => ReadableStream);
import "react-native-polyfill-globals/auto";
import "@azure/core-asynciterator-polyfill";
import { polyfillGlobal } from "react-native/Libraries/Utilities/PolyfillFunctions";
import { ReadableStream } from "web-streams-polyfill/ponyfill/es6";
import "@bacons/text-decoder/install";
import "react-native-get-random-values";
polyfillGlobal("ReadableStream", () => ReadableStream);

View File

@@ -9,8 +9,7 @@ import * as Linking from "expo-linking";
import React, { StrictMode, useEffect, useState } from "react";
import HandleInviteScreen from "./invite";
import { JazzProvider } from "jazz-react-native";
import { apiKey } from "./apiKey";
import { DemoAuthBasicUI, JazzProvider, useDemoAuth } from "jazz-react-native";
import ChatScreen from "./chat";
const Stack = createNativeStackNavigator();
@@ -29,6 +28,7 @@ const linking = {
};
function App() {
const [auth, state] = useDemoAuth();
const [initialRoute, setInitialRoute] = useState<
"ChatScreen" | "HandleInviteScreen"
>("ChatScreen");
@@ -43,13 +43,16 @@ function App() {
});
}, []);
if (!auth) {
return null;
}
return (
<StrictMode>
<JazzProvider
auth={auth}
storage="sqlite"
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
peer="wss://cloud.jazz.tools/?key=chat-rn-example-jazz@garden.co"
>
<NavigationContainer linking={linking} ref={navigationRef}>
<Stack.Navigator initialRouteName={initialRoute}>
@@ -66,6 +69,9 @@ function App() {
</Stack.Navigator>
</NavigationContainer>
</JazzProvider>
{state.state !== "signedIn" ? (
<DemoAuthBasicUI appName="Jazz Chat" state={state} />
) : null}
</StrictMode>
);
}

View File

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

View File

@@ -1,6 +1,6 @@
import clsx from "clsx";
import * as Clipboard from "expo-clipboard";
import { Group, ID, Profile } from "jazz-tools";
import { Group, ID } from "jazz-tools";
import { useEffect, useState } from "react";
import React, {
Button,
@@ -20,18 +20,12 @@ import { Chat, Message } from "./schema";
export default function ChatScreen({ navigation }: { navigation: any }) {
const { me, logOut } = useAccount();
const [chatId, setChatId] = useState<ID<Chat>>();
const loadedChat = useCoState(Chat, chatId, { resolve: { $each: true } });
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" />,
headerRight: () => <Button onPress={logOut} title="Logout" />,
headerLeft: () =>
loadedChat ? (
<Button
@@ -137,19 +131,6 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
<View className="flex flex-col h-full">
{!loadedChat ? (
<View className="flex flex-col h-full items-center justify-center">
<Text className="text-m font-bold mb-6">Username</Text>
<TextInput
className="rounded h-12 p-2 mb-12 w-40 border border-gray-200 block"
value={profile?.name ?? ""}
onChangeText={(value) => {
if (profile) {
profile.name = value;
}
}}
textAlignVertical="center"
onSubmitEditing={sendMessage}
testID="username-input"
/>
<TouchableOpacity
onPress={createChat}
className="bg-blue-500 p-4 rounded-md"
@@ -191,12 +172,10 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
placeholder="Type a message..."
textAlignVertical="center"
onSubmitEditing={sendMessage}
testID="message-input"
/>
<TouchableOpacity
onPress={sendMessage}
className="bg-gray-300 text-white rounded-full h-8 w-8 items-center justify-center"
testID="send-button"
>
<Text></Text>
</TouchableOpacity>

View File

@@ -1,16 +0,0 @@
# this sub-flow exists to work around an ios issue where the text field is not
# fully erased. The tap into the input field hits the middle, and clears all
# text to the left. If there's more to the right, it slides left, and thus we
# repeat this step. https://maestro.mobile.dev/api-reference/commands/erasetext
appId: com.jazz.chatrn
---
- copyTextFrom:
id: ${id}
- repeat:
times: 4
commands:
- tapOn:
id: ${id}
- eraseText
- copyTextFrom:
id: ${id}

View File

@@ -1,50 +0,0 @@
appId: com.jazz.chatrn
---
- launchApp
# # handle Expo screens (for local dev)
# - assertVisible: "Continue"
# - tapOn: "Continue"
# - assertVisible: "Reload"
# - tapOn: "Reload"
# login
- assertVisible: "Anonymous user"
- runFlow:
label: "Erase existing username"
file: erase_text.yml
env:
id: "username-input"
- inputText: "boorad"
- assertVisible: "boorad"
# start new chat
- tapOn: "Start new chat"
- assertVisible: "Share"
- assertVisible: "Jazz Chat"
- assertVisible: "Logout"
# send a message
- tapOn:
id: "message-input"
- inputText: "bro, low key, it do be like that tho"
- tapOn:
id: "send-button"
- assertVisible: "bro, low key, it do be like that tho"
# get invite code
- tapOn: "Share"
- assertVisible: "Copied to clipboard"
- tapOn: "OK"
# this assert doesn't work. maestro.copiedText only populates from `copyTextFrom`
# - assertTrue: ${maestro.copiedText.startsWith("co_z")}
# logout
- tapOn: "Logout"
- assertVisible: "Anonymous user"
# 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

@@ -1,20 +0,0 @@
#!/bin/bash
# This script is necessary, because unlike ios, the android emulator action
# accepts a script, runs it as your tests, then terminates.
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 ..
# run the e2e tests
export PATH="$PATH":"$HOME/.maestro/bin"
export MAESTRO_DRIVER_STARTUP_TIMEOUT=300000 # setting to 5 mins 👀
export MAESTRO_CLI_NO_ANALYTICS=1
export MAESTRO_CLI_ANALYSIS_NOTIFICATION_DISABLED=true
maestro test test/e2e/flow.yml

View File

@@ -1,263 +1,5 @@
# chat-vue
## 0.0.68
### Patch Changes
- Updated dependencies [e7c85b7]
- jazz-tools@0.11.6
- jazz-vue@0.11.6
- jazz-browser@0.11.6
## 0.0.67
### Patch Changes
- jazz-browser@0.11.5
- jazz-tools@0.11.5
- jazz-vue@0.11.5
## 0.0.66
### Patch Changes
- Updated dependencies [57a3dbe]
- Updated dependencies [a717754]
- Updated dependencies [a91f343]
- jazz-tools@0.11.4
- jazz-browser@0.11.4
- jazz-vue@0.11.4
## 0.0.65
### Patch Changes
- jazz-browser@0.11.3
- jazz-tools@0.11.3
- jazz-vue@0.11.3
## 0.0.64
### Patch Changes
- Updated dependencies [6892dc6]
- jazz-tools@0.11.2
- jazz-browser@0.11.2
- jazz-vue@0.11.2
## 0.0.63
### Patch Changes
- Updated dependencies [6a96d8b]
- Updated dependencies [a35249a]
- Updated dependencies [b9d194a]
- Updated dependencies [a4713df]
- Updated dependencies [34cbdc3]
- Updated dependencies [18428ea]
- Updated dependencies [f039e8f]
- Updated dependencies [e22de9f]
- jazz-tools@0.11.0
- jazz-browser@0.11.0
- jazz-vue@0.11.0
## 0.0.62
### Patch Changes
- Updated dependencies [2f99de0]
- jazz-tools@0.10.15
- jazz-browser@0.10.15
- jazz-vue@0.10.15
## 0.0.61
### Patch Changes
- Updated dependencies [75211e3]
- jazz-tools@0.10.14
- jazz-browser@0.10.14
- jazz-vue@0.10.14
## 0.0.60
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-browser@0.10.13
- jazz-vue@0.10.13
## 0.0.59
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-vue@0.10.12
- jazz-browser@0.10.12
## 0.0.58
### Patch Changes
- Updated dependencies [834203f]
- jazz-browser@0.10.9
- jazz-vue@0.10.9
## 0.0.57
### Patch Changes
- Updated dependencies [1e87fc7]
- Updated dependencies [2fb6428]
- jazz-browser@0.10.8
- jazz-tools@0.10.8
- jazz-vue@0.10.8
## 0.0.56
### Patch Changes
- Updated dependencies [1136d9b]
- Updated dependencies [bf76d79]
- Updated dependencies [0eed228]
- jazz-browser@0.10.7
- jazz-tools@0.10.7
- jazz-vue@0.10.7
## 0.0.55
### Patch Changes
- Updated dependencies [ada802b]
- jazz-tools@0.10.6
- jazz-browser@0.10.6
- jazz-vue@0.10.6
## 0.0.54
### Patch Changes
- Updated dependencies [59ff77e]
- jazz-tools@0.10.5
- jazz-browser@0.10.5
- jazz-vue@0.10.5
## 0.0.53
### Patch Changes
- jazz-browser@0.10.4
- jazz-tools@0.10.4
- jazz-vue@0.10.4
## 0.0.52
### Patch Changes
- Updated dependencies [d8582fc]
- jazz-tools@0.10.3
- jazz-browser@0.10.3
- jazz-vue@0.10.3
## 0.0.51
### Patch Changes
- jazz-browser@0.10.2
- jazz-tools@0.10.2
- jazz-vue@0.10.2
## 0.0.50
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-browser@0.10.1
- jazz-vue@0.10.1
## 0.0.49
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-browser@0.10.0
- jazz-tools@0.10.0
- jazz-vue@0.10.0
## 0.0.48
### Patch Changes
- jazz-browser@0.9.23
- jazz-tools@0.9.23
- jazz-vue@0.9.23
## 0.0.47
### Patch Changes
- jazz-browser@0.9.22
- jazz-vue@0.9.22
## 0.0.46
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-browser@0.9.21
- jazz-vue@0.9.21
## 0.0.45
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-browser@0.9.20
- jazz-vue@0.9.20
## 0.0.44
### Patch Changes
- jazz-browser@0.9.19
- jazz-tools@0.9.19
- jazz-vue@0.9.19
## 0.0.43
### Patch Changes
- jazz-browser@0.9.18
- jazz-tools@0.9.18
- jazz-vue@0.9.18
## 0.0.42
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-browser@0.9.17
- jazz-vue@0.9.17
## 0.0.41
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-tools@0.9.16
- jazz-browser@0.9.16
- jazz-vue@0.9.16
## 0.0.40
### Patch Changes

View File

@@ -11,12 +11,16 @@ You can either
Create a new Jazz project, and use this example as a template.
```bash
npx create-jazz-app@latest chat-vue-app --example chat-vue
npm create jazz-app@latest --example chat-vue --project-name chat-vue
```
or
```bash
npx create-jazz-app@latest --example chat-vue --project-name chat-vue
```
Go to the new project directory.
```bash
cd chat-vue-app
cd chat-vue
```
Run the dev server.

View File

@@ -1,6 +1,6 @@
{
"name": "chat-vue",
"version": "0.0.68",
"version": "0.0.40",
"private": true,
"type": "module",
"scripts": {
@@ -30,9 +30,9 @@
"eslint-plugin-vue": "^9.28.0",
"npm-run-all2": "^6.2.3",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"tailwindcss": "^3.4.15",
"typescript": "~5.6.2",
"vite": "^6.0.11",
"vite": "^5.4.10",
"vite-plugin-vue-devtools": "^7.4.6",
"vue-tsc": "^2.1.6"
}

View File

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

View File

@@ -1,31 +1,32 @@
import { DemoAuthBasicUI, JazzProvider } from "jazz-vue";
import { DemoAuthBasicUI, JazzProvider, useDemoAuth } from "jazz-vue";
import { createApp, defineComponent, h } from "vue";
import App from "./App.vue";
import "./index.css";
import { apiKey } from "@/apiKey";
import router from "./router";
const RootComponent = defineComponent({
name: "RootComponent",
setup() {
return () =>
const { authMethod, state } = useDemoAuth();
return () => [
h(
JazzProvider,
{
sync: {
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
},
auth: authMethod.value,
peer: "wss://cloud.jazz.tools/?key=chat-example-jazz@garden.co",
},
h(
DemoAuthBasicUI,
{
appName: "Jazz Vue Chat",
},
{
default: () => h(App),
},
),
);
{
default: () => h(App),
},
),
state.state !== "signedIn" &&
h(DemoAuthBasicUI, {
appName: "Jazz Chat",
state,
}),
];
},
});

View File

@@ -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(() => {

View File

@@ -1,272 +1,5 @@
# jazz-example-chat
## 0.0.165
### Patch Changes
- Updated dependencies [e7c85b7]
- Updated dependencies [09f0a98]
- Updated dependencies [11da4d1]
- Updated dependencies [8ed144e]
- jazz-react@0.11.6
- jazz-tools@0.11.6
- jazz-inspector@0.11.6
- jazz-browser-media-images@0.11.6
## 0.0.164
### Patch Changes
- jazz-react@0.11.5
- jazz-tools@0.11.5
- jazz-browser-media-images@0.11.5
## 0.0.163
### Patch Changes
- 2074e45: In the chat app example, show a "Message not readable" placeholder, if messages from a chat list are not readable by the user.
- Updated dependencies [57a3dbe]
- Updated dependencies [a717754]
- Updated dependencies [a91f343]
- jazz-tools@0.11.4
- jazz-browser-media-images@0.11.4
- jazz-react@0.11.4
## 0.0.162
### Patch Changes
- jazz-react@0.11.3
- jazz-tools@0.11.3
- jazz-browser-media-images@0.11.3
## 0.0.161
### Patch Changes
- Updated dependencies [6892dc6]
- jazz-tools@0.11.2
- jazz-react@0.11.2
- jazz-browser-media-images@0.11.2
## 0.0.160
### Patch Changes
- jazz-react@0.11.1
## 0.0.159
### 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-browser-media-images@0.11.0
- jazz-react@0.11.0
## 0.0.158
### Patch Changes
- Updated dependencies [2f99de0]
- jazz-tools@0.10.15
- jazz-browser-media-images@0.10.15
- jazz-react@0.10.15
## 0.0.157
### Patch Changes
- Updated dependencies [75211e3]
- jazz-tools@0.10.14
- jazz-react@0.10.14
- jazz-browser-media-images@0.10.14
## 0.0.156
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-browser-media-images@0.10.13
- jazz-react@0.10.13
## 0.0.155
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
- jazz-browser-media-images@0.10.12
## 0.0.154
### Patch Changes
- jazz-browser-media-images@0.10.9
- jazz-react@0.10.9
## 0.0.153
### Patch Changes
- Updated dependencies [2fb6428]
- jazz-tools@0.10.8
- jazz-react@0.10.8
- jazz-browser-media-images@0.10.8
## 0.0.152
### Patch Changes
- Updated dependencies [1136d9b]
- Updated dependencies [0eed228]
- jazz-react@0.10.7
- jazz-tools@0.10.7
- jazz-browser-media-images@0.10.7
## 0.0.151
### Patch Changes
- Updated dependencies [1d71ca1]
- Updated dependencies [ada802b]
- hash-slash@0.2.2
- jazz-react@0.10.6
- jazz-tools@0.10.6
- jazz-browser-media-images@0.10.6
## 0.0.150
### Patch Changes
- Updated dependencies [59ff77e]
- jazz-tools@0.10.5
- jazz-browser-media-images@0.10.5
- jazz-react@0.10.5
## 0.0.149
### Patch Changes
- jazz-react@0.10.4
- jazz-tools@0.10.4
- jazz-browser-media-images@0.10.4
## 0.0.148
### Patch Changes
- Updated dependencies [d8582fc]
- jazz-tools@0.10.3
- jazz-browser-media-images@0.10.3
- jazz-react@0.10.3
## 0.0.147
### Patch Changes
- jazz-react@0.10.2
- jazz-tools@0.10.2
- jazz-browser-media-images@0.10.2
## 0.0.146
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-browser-media-images@0.10.1
- jazz-react@0.10.1
## 0.0.145
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-react@0.10.0
- jazz-tools@0.10.0
- jazz-browser-media-images@0.10.0
## 0.0.144
### Patch Changes
- jazz-react@0.9.23
- jazz-tools@0.9.23
- jazz-browser-media-images@0.9.23
## 0.0.143
### Patch Changes
- jazz-browser-media-images@0.9.22
- jazz-react@0.9.22
## 0.0.142
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-browser-media-images@0.9.21
- jazz-react@0.9.21
## 0.0.141
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-browser-media-images@0.9.20
- jazz-react@0.9.20
## 0.0.140
### Patch Changes
- jazz-react@0.9.19
- jazz-tools@0.9.19
- jazz-browser-media-images@0.9.19
## 0.0.139
### Patch Changes
- jazz-react@0.9.18
- jazz-tools@0.9.18
- jazz-browser-media-images@0.9.18
## 0.0.138
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-browser-media-images@0.9.17
- jazz-react@0.9.17
## 0.0.137
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-tools@0.9.16
- jazz-browser-media-images@0.9.16
- jazz-react@0.9.16
## 0.0.136
### Patch Changes

View File

@@ -13,12 +13,16 @@ You can either
Create a new Jazz project, and use this example as a template.
```bash
npx create-jazz-app@latest chat-app --example chat
npm create jazz-app@latest --example chat --project-name chat
```
or
```bash
npx create-jazz-app@latest --example chat --project-name chat
```
Go to the new project directory.
```bash
cd chat-app
cd chat
```
Run the dev server.

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat",
"private": true,
"version": "0.0.165",
"version": "0.0.136",
"type": "module",
"scripts": {
"dev": "vite",
@@ -9,14 +9,13 @@
"format-and-lint": "biome check .",
"format-and-lint:fix": "biome check . --write",
"preview": "vite preview",
"test:e2e": "playwright test",
"test:e2e:ui": "playwright test --ui"
"test": "playwright test",
"test:ui": "playwright test --ui"
},
"dependencies": {
"clsx": "^2.0.0",
"hash-slash": "workspace:*",
"jazz-browser-media-images": "workspace:*",
"jazz-inspector": "workspace:*",
"jazz-react": "workspace:*",
"jazz-tools": "workspace:*",
"lucide-react": "^0.274.0",
@@ -24,15 +23,15 @@
"react-dom": "^18.3.1"
},
"devDependencies": {
"@playwright/test": "^1.50.1",
"@playwright/test": "^1.46.1",
"@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",
"tailwindcss": "^3.4.15",
"typescript": "~5.6.2",
"vite": "^6.0.11"
"vite": "^5.4.10"
}
}

View File

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

View File

@@ -1,12 +1,11 @@
import { apiKey } from "@/apiKey.ts";
import { getRandomUsername, inIframe, onChatLoad } from "@/util.ts";
import { inIframe, onChatLoad } from "@/util.ts";
import { useIframeHashRouter } from "hash-slash";
import { JazzInspector } from "jazz-inspector";
import { JazzProvider, useAccount } from "jazz-react";
import { useAccount } from "jazz-react";
import { Group, ID } from "jazz-tools";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { ChatScreen } from "./chatScreen.tsx";
import { JazzAndAuth } from "./jazz.tsx";
import { Chat } from "./schema.ts";
import { ThemeProvider } from "./themeProvider.tsx";
import { AppContainer, TopBar } from "./ui.tsx";
@@ -29,16 +28,7 @@ export function App() {
return (
<AppContainer>
<TopBar>
<input
type="text"
value={me?.profile?.name ?? ""}
className="bg-transparent"
onChange={(e) => {
if (!me?.profile) return;
me.profile.name = e.target.value;
}}
placeholder="Set username"
/>
<p>{me?.profile?.name}</p>
{!inIframe && <button onClick={logOut}>Log out</button>}
</TopBar>
{router.route({
@@ -49,21 +39,12 @@ export function App() {
);
}
const url = new URL(window.location.href);
const defaultProfileName = url.searchParams.get("user") ?? getRandomUsername();
createRoot(document.getElementById("root")!).render(
<ThemeProvider>
<StrictMode>
<JazzProvider
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
defaultProfileName={defaultProfileName}
>
<JazzAndAuth>
<App />
<JazzInspector />
</JazzProvider>
</JazzAndAuth>
</StrictMode>
</ThemeProvider>,
);

View File

@@ -1,6 +1,6 @@
import { createImage } from "jazz-browser-media-images";
import { useAccount, useCoState } from "jazz-react";
import { Account, ID } from "jazz-tools";
import { useCoState } from "jazz-react";
import { ID } from "jazz-tools";
import { useState } from "react";
import { Chat, Message } from "./schema.ts";
import {
@@ -17,8 +17,7 @@ import {
} from "./ui.tsx";
export function ChatScreen(props: { chatID: ID<Chat> }) {
const chat = useCoState(Chat, props.chatID, { resolve: { $each: true } });
const account = useAccount();
const chat = useCoState(Chat, props.chatID, [{}]);
const [showNLastMessages, setShowNLastMessages] = useState(30);
if (!chat)
@@ -48,7 +47,7 @@ export function ChatScreen(props: { chatID: ID<Chat> }) {
chat
.slice(-showNLastMessages)
.reverse() // this plus flex-col-reverse on ChatBody gives us scroll-to-bottom behavior
.map((msg) => <ChatBubble me={account.me} msg={msg} key={msg.id} />)
.map((msg) => <ChatBubble msg={msg} key={msg.id} />)
) : (
<EmptyChatMessage />
)}
@@ -75,20 +74,7 @@ export function ChatScreen(props: { chatID: ID<Chat> }) {
);
}
function ChatBubble(props: { me: Account; msg: Message }) {
if (!props.me.canRead(props.msg)) {
return (
<BubbleContainer fromMe={false}>
<BubbleBody fromMe={false}>
<BubbleText
text="Message not readable"
className="text-gray-500 italic"
/>
</BubbleBody>
</BubbleContainer>
);
}
function ChatBubble(props: { msg: Message }) {
const lastEdit = props.msg._edits.text;
const fromMe = lastEdit.by?.isMe;
const { text, image } = props.msg;

View File

@@ -0,0 +1,19 @@
import { DemoAuthBasicUI, JazzProvider, useDemoAuth } from "jazz-react";
export function JazzAndAuth({ children }: { children: React.ReactNode }) {
const [auth, state] = useDemoAuth();
return (
<>
<JazzProvider
auth={auth}
peer="wss://cloud.jazz.tools/?key=chat-example-jazz@garden.co"
>
{children}
</JazzProvider>
{state.state !== "signedIn" && (
<DemoAuthBasicUI appName="Jazz Chat" state={state} />
)}
</>
);
}

View File

@@ -6,7 +6,7 @@ import { useId, useRef } from "react";
export function AppContainer(props: { children: React.ReactNode }) {
return (
<div className="flex flex-col justify-between w-screen h-screen bg-stone-50 dark:bg-stone-925 dark:text-white">
<div className="flex flex-col justify-between w-screen h-screen bg-stone-50 dark:bg-black dark:text-white">
{props.children}
</div>
);
@@ -14,7 +14,7 @@ export function AppContainer(props: { children: React.ReactNode }) {
export function TopBar(props: { children: React.ReactNode }) {
return (
<div className="p-3 bg-white w-full flex justify-between gap-2 border-b dark:bg-transparent dark:border-stone-900">
<div className="p-3 bg-white w-full flex justify-between gap-2 border-b dark:bg-transparent dark:border-stone-800">
{props.children}
</div>
);
@@ -33,7 +33,7 @@ export function ChatBody(props: { children: React.ReactNode }) {
export function EmptyChatMessage() {
return (
<div className="h-full text-base text-stone-500 flex items-center justify-center px-3 md:text-2xl">
<div className="h-full text-base text-stone-500 flex items-center justify-center px-3 text-lg md:text-2xl">
Start a conversation below.
</div>
);
@@ -61,7 +61,7 @@ export function BubbleBody(props: {
"line-clamp-10 text-ellipsis whitespace-pre-wrap",
"rounded-2xl overflow-hidden max-w-[calc(100%-5rem)] shadow-sm p-1",
props.fromMe
? "bg-white dark:bg-stone-900 dark:text-white"
? "bg-white dark:bg-stone-700 dark:text-white"
: "bg-blue text-white",
)}
>
@@ -70,12 +70,8 @@ export function BubbleBody(props: {
);
}
export function BubbleText(props: { text: string; className?: string }) {
return (
<p className={clsx("px-2 leading-relaxed", props.className)}>
{props.text}
</p>
);
export function BubbleText(props: { text: string }) {
return <p className="px-2 leading-relaxed">{props.text}</p>;
}
export function BubbleImage(props: { image: ImageDefinition }) {
@@ -101,7 +97,7 @@ export function BubbleInfo(props: { by: string | undefined; madeAt: Date }) {
export function InputBar(props: { children: React.ReactNode }) {
return (
<div className="p-3 bg-white border-t shadow-2xl mt-auto flex gap-1 dark:bg-transparent dark:border-stone-900">
<div className="p-3 bg-white border-t shadow-2xl mt-auto flex gap-1 dark:bg-transparent dark:border-stone-800">
{props.children}
</div>
);
@@ -151,7 +147,7 @@ export function TextInput(props: { onSubmit: (text: string) => void }) {
</label>
<input
id={inputId}
className="rounded-full py-1 px-3 border block w-full placeholder:text-stone-500 dark:bg-stone-925 dark:text-white dark:border-stone-900"
className="rounded-full py-1 px-3 border block w-full placeholder:text-stone-500 dark:bg-black dark:text-white dark:border-stone-700"
placeholder="Type a message and press Enter"
maxLength={2048}
onKeyDown={({ key, currentTarget: input }) => {

View File

@@ -15,20 +15,3 @@ export function onChatLoad(chat: Chat) {
}
export const inIframe = window.self !== window.top;
const animals = [
"elephant",
"penguin",
"giraffe",
"octopus",
"kangaroo",
"dolphin",
"cheetah",
"koala",
"platypus",
"pangolin",
];
export function getRandomUsername() {
return `Anonymous ${animals[Math.floor(Math.random() * animals.length)]}`;
}

View File

@@ -1,35 +1,48 @@
import { test } from "@playwright/test";
import { ChatPage } from "./pages/ChatPage";
import { LoginPage } from "./pages/LoginPage";
test("chat between two users", async ({ page: marioPage, browser }) => {
const context = await browser.newContext();
const luigiPage = await context.newPage();
test("chat between two users", async ({ page }) => {
const loginPage = new LoginPage(page);
await marioPage.goto("/");
const mario = "S. Mario";
const luigi = "Luigi";
const marioChat = new ChatPage(marioPage);
const luigiChat = new ChatPage(luigiPage);
await loginPage.goto();
await loginPage.fillUsername(mario);
await loginPage.signup();
await marioChat.setUsername("Mario");
const chatPage = new ChatPage(page);
const message1ByMario = "Hello Luigi, are you ready to save the princess?";
await marioChat.sendMessage(message1ByMario);
await marioChat.expectMessageRow(message1ByMario);
await chatPage.sendMessage(message1ByMario);
await chatPage.expectMessageRow(message1ByMario);
const roomURL = marioPage.url();
await luigiPage.goto(roomURL);
const roomURL = page.url();
await luigiChat.setUsername("Luigi");
await chatPage.logout();
await luigiChat.expectMessageRow(message1ByMario);
await loginPage.expectLoaded();
await loginPage.fillUsername(luigi);
await loginPage.signup();
await page.goto(roomURL);
await chatPage.expectMessageRow(message1ByMario);
const message2ByLuigi =
"No, I'm not ready yet. I'm still trying to find the key to the castle.";
await luigiChat.sendMessage(message2ByLuigi);
await luigiChat.expectMessageRow(message2ByLuigi);
await chatPage.sendMessage(message2ByLuigi);
await chatPage.expectMessageRow(message2ByLuigi);
await marioChat.expectMessageRow(message1ByMario);
await luigiChat.expectMessageRow(message2ByLuigi);
await chatPage.logout();
await loginPage.loginAs(mario);
await page.goto(roomURL);
await chatPage.expectMessageRow(message1ByMario);
await chatPage.expectMessageRow(message2ByLuigi);
});

View File

@@ -4,7 +4,7 @@ export class ChatPage {
readonly page: Page;
readonly messageInput: Locator;
readonly logoutButton: Locator;
readonly usernameInput: Locator;
constructor(page: Page) {
this.page = page;
this.messageInput = page.getByRole("textbox", {
@@ -13,11 +13,6 @@ export class ChatPage {
this.logoutButton = page.getByRole("button", {
name: "Log out",
});
this.usernameInput = page.getByPlaceholder("Set username");
}
async setUsername(username: string) {
await this.usernameInput.fill(username);
}
async sendMessage(message: string) {

View File

@@ -0,0 +1,40 @@
import { Locator, Page, expect } from "@playwright/test";
export class LoginPage {
readonly page: Page;
readonly usernameInput: Locator;
readonly signupButton: Locator;
constructor(page: Page) {
this.page = page;
this.usernameInput = page.getByRole("textbox");
this.signupButton = page.getByRole("button", {
name: "Sign up",
});
}
async goto() {
this.page.goto("/");
}
async fillUsername(value: string) {
await this.usernameInput.clear();
await this.usernameInput.fill(value);
}
async loginAs(value: string) {
await this.page
.getByRole("button", {
name: value,
})
.click();
}
async signup() {
await this.signupButton.click();
}
async expectLoaded() {
await expect(this.signupButton).toBeVisible();
}
}

View File

@@ -1,268 +1,5 @@
# minimal-auth-clerk
## 0.0.64
### Patch Changes
- 1bfa9bb: Removed when="singedUp" from examples apps' Jazz providers. This is a really niche use-case option and can lead to broken-feeling experiences when anonymous users try to load something.
- Updated dependencies [e7c85b7]
- jazz-react@0.11.6
- jazz-tools@0.11.6
- jazz-react-auth-clerk@0.11.6
## 0.0.63
### Patch Changes
- jazz-react@0.11.5
- jazz-react-auth-clerk@0.11.5
- jazz-tools@0.11.5
## 0.0.62
### Patch Changes
- Updated dependencies [57a3dbe]
- Updated dependencies [a717754]
- Updated dependencies [a91f343]
- jazz-tools@0.11.4
- jazz-react@0.11.4
- jazz-react-auth-clerk@0.11.4
## 0.0.61
### Patch Changes
- jazz-react@0.11.3
- jazz-react-auth-clerk@0.11.3
- jazz-tools@0.11.3
## 0.0.60
### Patch Changes
- Updated dependencies [6892dc6]
- jazz-tools@0.11.2
- jazz-react@0.11.2
- jazz-react-auth-clerk@0.11.2
## 0.0.59
### Patch Changes
- jazz-react@0.11.1
- jazz-react-auth-clerk@0.11.1
## 0.0.58
### 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-auth-clerk@0.11.0
- jazz-react@0.11.0
## 0.0.57
### Patch Changes
- Updated dependencies [2f99de0]
- jazz-tools@0.10.15
- jazz-react@0.10.15
- jazz-react-auth-clerk@0.10.15
## 0.0.56
### Patch Changes
- Updated dependencies [75211e3]
- jazz-tools@0.10.14
- jazz-react@0.10.14
- jazz-react-auth-clerk@0.10.14
## 0.0.55
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react@0.10.13
- jazz-react-auth-clerk@0.10.13
## 0.0.54
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
- jazz-react-auth-clerk@0.10.12
## 0.0.53
### Patch Changes
- jazz-react@0.10.9
- jazz-react-auth-clerk@0.10.9
## 0.0.52
### Patch Changes
- Updated dependencies [2fb6428]
- jazz-tools@0.10.8
- jazz-react@0.10.8
- jazz-react-auth-clerk@0.10.8
## 0.0.51
### Patch Changes
- Updated dependencies [1136d9b]
- Updated dependencies [0eed228]
- jazz-react-auth-clerk@0.10.7
- jazz-react@0.10.7
- jazz-tools@0.10.7
## 0.0.50
### Patch Changes
- Updated dependencies [1d71ca1]
- Updated dependencies [ada802b]
- jazz-react-auth-clerk@0.10.6
- jazz-react@0.10.6
- jazz-tools@0.10.6
## 0.0.49
### Patch Changes
- Updated dependencies [59ff77e]
- jazz-tools@0.10.5
- jazz-react@0.10.5
- jazz-react-auth-clerk@0.10.5
## 0.0.48
### Patch Changes
- jazz-react@0.10.4
- jazz-react-auth-clerk@0.10.4
- jazz-tools@0.10.4
## 0.0.47
### Patch Changes
- Updated dependencies [d8582fc]
- jazz-tools@0.10.3
- jazz-react@0.10.3
- jazz-react-auth-clerk@0.10.3
## 0.0.46
### Patch Changes
- jazz-react@0.10.2
- jazz-react-auth-clerk@0.10.2
- jazz-tools@0.10.2
## 0.0.45
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-react@0.10.1
- jazz-react-auth-clerk@0.10.1
## 0.0.44
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-react-auth-clerk@0.10.0
- jazz-react@0.10.0
- jazz-tools@0.10.0
## 0.0.43
### Patch Changes
- jazz-react@0.9.23
- jazz-react-auth-clerk@0.9.23
- jazz-tools@0.9.23
## 0.0.42
### Patch Changes
- jazz-react@0.9.22
- jazz-react-auth-clerk@0.9.22
## 0.0.41
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-react@0.9.21
- jazz-react-auth-clerk@0.9.21
## 0.0.40
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-react@0.9.20
- jazz-react-auth-clerk@0.9.20
## 0.0.39
### Patch Changes
- jazz-react@0.9.19
- jazz-react-auth-clerk@0.9.19
- jazz-tools@0.9.19
## 0.0.38
### Patch Changes
- jazz-react@0.9.18
- jazz-react-auth-clerk@0.9.18
- jazz-tools@0.9.18
## 0.0.37
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-react@0.9.17
- jazz-react-auth-clerk@0.9.17
## 0.0.36
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-react-auth-clerk@0.9.16
- jazz-tools@0.9.16
- jazz-react@0.9.16
## 0.0.35
### Patch Changes

View File

@@ -15,12 +15,16 @@ You can either
Create a new Jazz project, and use this example as a template.
```bash
npx create-jazz-app@latest clerk-app --example clerk
npm create jazz-app@latest --example clerk --project-name clerk
```
or
```bash
npx create-jazz-app@latest --example clerk --project-name clerk
```
Go to the new project directory.
```bash
cd clerk-app
cd clerk
```
Run the dev server.

View File

@@ -1,7 +1,7 @@
{
"name": "clerk",
"private": true,
"version": "0.0.64",
"version": "0.0.35",
"type": "module",
"scripts": {
"dev": "vite",
@@ -13,7 +13,7 @@
"dependencies": {
"@clerk/clerk-react": "^5.4.1",
"jazz-react": "workspace:*",
"jazz-react-auth-clerk": "workspace:0.11.6",
"jazz-react-auth-clerk": "workspace:0.9.15",
"jazz-tools": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1"
@@ -25,6 +25,6 @@
"@vitejs/plugin-react": "^4.3.3",
"globals": "^15.11.0",
"typescript": "~5.6.2",
"vite": "^6.0.11"
"vite": "^5.4.10"
}
}

View File

@@ -1,25 +1,13 @@
import { SignInButton } from "@clerk/clerk-react";
import { useAccount, useIsAuthenticated } from "jazz-react";
import { useAccount } from "jazz-react";
function App() {
const { me, logOut } = useAccount();
const isAuthenticated = useIsAuthenticated();
if (isAuthenticated) {
return (
<div className="container">
<h1>You're logged in</h1>
<p>Welcome back, {me?.profile?.name}</p>
<button onClick={() => logOut()}>Logout</button>
</div>
);
}
return (
<div className="container">
<h1>You're not logged in</h1>
<SignInButton />
<h1>You're logged in</h1>
<p>Welcome back, {me?.profile?.name}</p>
<button onClick={() => logOut()}>Logout</button>
</div>
);
}

View File

@@ -1 +0,0 @@
export const apiKey = "minimal-auth-clerk-example@garden.co";

View File

@@ -62,7 +62,7 @@ button {
}
.container {
max-width: 400px;
max-width: 200px;
margin: 0 auto;
padding: 0 1rem;
display: flex;

View File

@@ -1,10 +1,10 @@
import { ClerkProvider, useClerk } from "@clerk/clerk-react";
import { ClerkProvider, SignInButton, useClerk } from "@clerk/clerk-react";
import { useJazzClerkAuth } from "jazz-react-auth-clerk";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./index.css";
import { JazzProviderWithClerk } from "jazz-react-auth-clerk";
import { apiKey } from "./apiKey";
import { JazzProvider } from "jazz-react";
// Import your publishable key
const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY;
@@ -13,27 +13,35 @@ if (!PUBLISHABLE_KEY) {
throw new Error("Add your Clerk publishable key to the .env.local file");
}
function JazzProvider({ children }: { children: React.ReactNode }) {
function JazzAndAuth({ children }: { children: React.ReactNode }) {
const clerk = useClerk();
const [auth, state] = useJazzClerkAuth(clerk);
return (
<JazzProviderWithClerk
clerk={clerk}
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
>
{children}
</JazzProviderWithClerk>
<main className="container">
{state?.errors?.map((error) => (
<div key={error}>{error}</div>
))}
{clerk.user && auth ? (
<JazzProvider
auth={auth}
peer="wss://cloud.jazz.tools/?key=minimal-auth-clerk-example@garden.co"
>
{children}
</JazzProvider>
) : (
<SignInButton />
)}
</main>
);
}
createRoot(document.getElementById("root")!).render(
<StrictMode>
<ClerkProvider publishableKey={PUBLISHABLE_KEY} afterSignOutUrl="/">
<JazzProvider>
<JazzAndAuth>
<App />
</JazzProvider>
</JazzAndAuth>
</ClerkProvider>
</StrictMode>,
);

View File

@@ -1,232 +1,5 @@
# file-share-svelte
## 0.0.48
### Patch Changes
- 1bfa9bb: Removed when="singedUp" from examples apps' Jazz providers. This is a really niche use-case option and can lead to broken-feeling experiences when anonymous users try to load something.
- Updated dependencies [e7c85b7]
- jazz-tools@0.11.6
- jazz-svelte@0.11.6
## 0.0.47
### Patch Changes
- jazz-svelte@0.11.5
- jazz-tools@0.11.5
## 0.0.46
### Patch Changes
- Updated dependencies [57a3dbe]
- Updated dependencies [a717754]
- Updated dependencies [a91f343]
- jazz-tools@0.11.4
- jazz-svelte@0.11.4
## 0.0.45
### Patch Changes
- jazz-svelte@0.11.3
- jazz-tools@0.11.3
## 0.0.44
### Patch Changes
- Updated dependencies [6892dc6]
- jazz-tools@0.11.2
- jazz-svelte@0.11.2
## 0.0.43
### 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-svelte@0.11.0
## 0.0.42
### Patch Changes
- Updated dependencies [2f99de0]
- jazz-tools@0.10.15
- jazz-svelte@0.10.15
## 0.0.41
### Patch Changes
- Updated dependencies [75211e3]
- jazz-tools@0.10.14
- jazz-svelte@0.10.14
## 0.0.40
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-svelte@0.10.13
## 0.0.39
### Patch Changes
- Updated dependencies [4612e05]
- jazz-svelte@0.10.12
- jazz-tools@0.10.12
## 0.0.38
### Patch Changes
- jazz-svelte@0.10.9
## 0.0.37
### Patch Changes
- Updated dependencies [2fb6428]
- jazz-tools@0.10.8
- jazz-svelte@0.10.8
## 0.0.36
### Patch Changes
- Updated dependencies [1136d9b]
- Updated dependencies [0eed228]
- jazz-svelte@0.10.7
- jazz-tools@0.10.7
## 0.0.35
### Patch Changes
- Updated dependencies [ada802b]
- jazz-tools@0.10.6
- jazz-svelte@0.10.6
## 0.0.34
### Patch Changes
- Updated dependencies [59ff77e]
- jazz-tools@0.10.5
- jazz-svelte@0.10.5
## 0.0.33
### Patch Changes
- jazz-svelte@0.10.4
- jazz-tools@0.10.4
## 0.0.32
### Patch Changes
- Updated dependencies [d8582fc]
- jazz-tools@0.10.3
- jazz-svelte@0.10.3
## 0.0.31
### Patch Changes
- jazz-svelte@0.10.2
- jazz-tools@0.10.2
## 0.0.30
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-svelte@0.10.1
## 0.0.29
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-tools@0.10.0
- jazz-svelte@0.10.0
## 0.0.28
### Patch Changes
- jazz-svelte@0.9.23
- jazz-tools@0.9.23
## 0.0.27
### Patch Changes
- jazz-svelte@0.9.22
## 0.0.26
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-svelte@0.9.21
## 0.0.25
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-svelte@0.9.20
## 0.0.24
### Patch Changes
- jazz-svelte@0.9.19
- jazz-tools@0.9.19
## 0.0.23
### Patch Changes
- jazz-svelte@0.9.18
- jazz-tools@0.9.18
## 0.0.22
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-svelte@0.9.17
## 0.0.21
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-tools@0.9.16
- jazz-svelte@0.9.16
## 0.0.20
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "file-share-svelte",
"version": "0.0.48",
"version": "0.0.20",
"private": true,
"type": "module",
"scripts": {
@@ -13,13 +13,13 @@
"lint": "prettier --check . && eslint .",
"format-and-lint": "pnpm run format && pnpm run lint",
"format-and-lint:fix": "pnpm run format --write && pnpm run lint --fix",
"test:e2e": "playwright test",
"test:e2e:ui": "playwright test --ui"
"test": "playwright test",
"test:ui": "playwright test --ui"
},
"devDependencies": {
"@sveltejs/adapter-vercel": "^5.5.0",
"@sveltejs/kit": "^2.16.0",
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^4.0.1",
"@types/is-ci": "^3.0.4",
"autoprefixer": "^10.4.20",
"eslint": "^9.7.0",
@@ -32,10 +32,10 @@
"prettier-plugin-tailwindcss": "^0.6.5",
"svelte": "^5.0.0",
"svelte-check": "^4.0.0",
"tailwindcss": "^3.4.17",
"tailwindcss": "^3.4.15",
"typescript": "~5.6.2",
"typescript-eslint": "^8.0.0",
"vite": "^6.0.11"
"vite": "^5.4.10"
},
"dependencies": {
"@tailwindcss/typography": "^0.5.15",

View File

@@ -1 +0,0 @@
export const apiKey = "file-share-svelte@garden.co"

View File

@@ -17,6 +17,6 @@ export function formatFileSize(bytes: number): string {
* @param createdAt The creation date
* @returns A unique file ID string
*/
export function generateTempFileId(fileName: string | undefined, createdAt: Date | undefined): string {
return `file-${fileName ?? 'unknown'}-${createdAt?.getTime() ?? 0}`;
export function generateTempFileId(fileName: string, createdAt: Date): string {
return `file-${fileName}-${createdAt.getTime()}`;
}

View File

@@ -12,9 +12,11 @@
import { Toaster } from 'svelte-sonner';
import '../app.css';
import { FileShareAccount } from '$lib/schema';
import {apiKey} from '../apiKey';
let { children } = $props();
const auth = usePasskeyAuth({
appName: 'File Share'
});
</script>
<svelte:head>
@@ -23,15 +25,21 @@
<Toaster richColors />
<JazzProvider
AccountSchema={FileShareAccount}
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
>
<PasskeyAuthBasicUI appName="File Share">
{#if auth.state.state === 'ready'}
<div class="fixed inset-0 flex items-center justify-center bg-gray-50/80">
<div class="rounded-lg bg-white p-8 shadow-lg">
<PasskeyAuthBasicUI state={auth.state} />
</div>
</div>
{/if}
{#if auth.current}
<JazzProvider
AccountSchema={FileShareAccount}
auth={auth.current}
peer="wss://cloud.jazz.tools/?key=file-share-svelte@garden.co"
>
<div class="min-h-screen bg-gray-100">
{@render children()}
</div>
</PasskeyAuthBasicUI>
</JazzProvider>
</JazzProvider>
{/if}

View File

@@ -28,7 +28,7 @@
const input = event.target as HTMLInputElement;
const files = input.files;
if (!files || !files.length || !me.root?.sharedFiles || !me.root.publicGroup) return;
if (!files || !files.length || !me?.root?.sharedFiles || !me.root.publicGroup) return;
const file = files[0];
const fileName = file.name;
@@ -129,14 +129,12 @@
{#if sharedFiles.current}
{#if !(sharedFiles.current.length === 0 && uploadingFiles.size === 0)}
{#each [...sharedFiles.current, ...uploadingFiles.values()] as file (generateTempFileId(file?.name, file?.createdAt))}
{#if file}
<FileItem
{file}
loading={uploadingFiles.has(generateTempFileId(file?.name, file?.createdAt))}
onShare={shareFile}
onDelete={deleteFile}
/>
{/if}
<FileItem
{file}
loading={uploadingFiles.has(generateTempFileId(file?.name, file?.createdAt))}
onShare={shareFile}
onDelete={deleteFile}
/>
{/each}
{:else}
<p class="text-center text-gray-500">No files yet</p>

View File

@@ -1,292 +0,0 @@
# jazz-tailwind-demo-auth-starter
## 0.0.4
### Patch Changes
- Updated dependencies [e7c85b7]
- jazz-react@0.11.6
- jazz-tools@0.11.6
## 0.0.3
### Patch Changes
- jazz-react@0.11.5
- jazz-tools@0.11.5
## 0.0.2
### Patch Changes
- Updated dependencies [57a3dbe]
- Updated dependencies [a717754]
- Updated dependencies [a91f343]
- jazz-tools@0.11.4
- jazz-react@0.11.4
## 0.0.52
### Patch Changes
- Updated dependencies [2f99de0]
- jazz-tools@0.10.15
- jazz-react@0.10.15
## 0.0.51
### Patch Changes
- Updated dependencies [75211e3]
- jazz-tools@0.10.14
- jazz-react@0.10.14
## 0.0.50
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react@0.10.13
## 0.0.49
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
## 0.0.48
### Patch Changes
- jazz-react@0.10.9
## 0.0.47
### Patch Changes
- Updated dependencies [2fb6428]
- jazz-tools@0.10.8
- jazz-react@0.10.8
## 0.0.46
### Patch Changes
- Updated dependencies [1136d9b]
- Updated dependencies [0eed228]
- jazz-react@0.10.7
- jazz-tools@0.10.7
## 0.0.45
### Patch Changes
- Updated dependencies [1d71ca1]
- Updated dependencies [ada802b]
- jazz-react@0.10.6
- jazz-tools@0.10.6
## 0.0.44
### Patch Changes
- Updated dependencies [59ff77e]
- jazz-tools@0.10.5
- jazz-react@0.10.5
## 0.0.43
### Patch Changes
- jazz-react@0.10.4
- jazz-tools@0.10.4
## 0.0.42
### Patch Changes
- Updated dependencies [d8582fc]
- jazz-tools@0.10.3
- jazz-react@0.10.3
## 0.0.41
### Patch Changes
- jazz-react@0.10.2
- jazz-tools@0.10.2
## 0.0.40
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-react@0.10.1
## 0.0.39
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-react@0.10.0
- jazz-tools@0.10.0
## 0.0.38
### Patch Changes
- jazz-react@0.9.23
- jazz-tools@0.9.23
## 0.0.37
### Patch Changes
- jazz-react@0.9.22
## 0.0.36
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-react@0.9.21
## 0.0.35
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-react@0.9.20
## 0.0.34
### Patch Changes
- jazz-react@0.9.19
- jazz-tools@0.9.19
## 0.0.33
### Patch Changes
- jazz-react@0.9.18
- jazz-tools@0.9.18
## 0.0.32
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-react@0.9.17
## 0.0.31
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-tools@0.9.16
- jazz-react@0.9.16
## 0.0.30
### Patch Changes
- Updated dependencies [7491711]
- jazz-tools@0.9.15
- jazz-react@0.9.15
## 0.0.29
### Patch Changes
- Updated dependencies [3df93cc]
- jazz-tools@0.9.14
- jazz-react@0.9.14
## 0.0.28
### Patch Changes
- jazz-react@0.9.13
- jazz-tools@0.9.13
## 0.0.27
### Patch Changes
- jazz-react@0.9.12
- jazz-tools@0.9.12
## 0.0.26
### Patch Changes
- jazz-react@0.9.11
- jazz-tools@0.9.11
## 0.0.25
### Patch Changes
- Updated dependencies [5e83864]
- jazz-react@0.9.10
- jazz-tools@0.9.10
## 0.0.24
### Patch Changes
- Updated dependencies [8eb9247]
- jazz-tools@0.9.9
- jazz-react@0.9.9
## 0.0.23
### Patch Changes
- Updated dependencies [d1d773b]
- jazz-tools@0.9.8
- jazz-react@0.9.8
## 0.0.22
### Patch Changes
- jazz-react@0.9.4
## 0.0.21
### Patch Changes
- Updated dependencies [1b71969]
- jazz-react@0.9.1
- jazz-tools@0.9.1
## 0.0.20
### Patch Changes
- Updated dependencies [956a4d1]
- Updated dependencies [8eda792]
- jazz-react@0.9.0
- jazz-tools@0.9.0
## 0.0.19
### Patch Changes
- Updated dependencies [dc62b95]
- Updated dependencies [1de26f8]
- jazz-tools@0.8.51
- jazz-react@0.8.51

View File

@@ -1,37 +0,0 @@
import { FileWidget } from "./FileWidget.js";
import { Logo } from "./Logo.tsx";
function App() {
return (
<>
<main className="container mt-16 flex flex-col gap-8">
<Logo />
<FileWidget />
<p className="text-center">
Edit the form above,{" "}
<button
type="button"
onClick={() => window.location.reload()}
className="font-semibold underline"
>
refresh
</button>{" "}
this page, and see your changes persist.
</p>
<p className="text-center my-16">
Go to{" "}
<a
className="font-semibold underline"
href="https://jazz.tools/docs/react/guide"
>
jazz.tools/docs/react/guide
</a>{" "}
for a full tutorial.
</p>
</main>
</>
);
}
export default App;

View File

@@ -1,269 +0,0 @@
"use client";
import { useAccount } from "jazz-react";
import { FileStream } from "jazz-tools";
import { useRef, useState } from "react";
export function FileWidget() {
const inputRef = useRef<HTMLInputElement>(null);
const dragAndDropElementRef = useRef<HTMLDivElement>(null);
const [isUploading, setIsUploading] = useState(false);
const [progress, setProgress] = useState(0);
const [error, setError] = useState<string | null>(null);
const { me } = useAccount();
async function handleUpload(event: React.FormEvent) {
event.preventDefault();
setError(null);
if (!me?.profile) {
setError("User profile not found");
return;
}
setProgress(0);
const file = inputRef.current?.files?.[0];
if (!file) {
setError("Please select a file");
return;
}
try {
setIsUploading(true);
me.profile.file = await FileStream.createFromBlob(file, {
onProgress: (p) => setProgress(Math.round(p * 100)),
});
} catch (error) {
setError(
error instanceof Error ? error.message : "Failed to upload file",
);
console.error("Error uploading file:", error);
} finally {
setIsUploading(false);
}
}
function handleDelete() {
if (!me?.profile) return;
delete me.profile?.file;
}
async function handleDownload() {
if (!me?.profile) return;
const file = me.profile.file;
if (!file) return;
try {
const blob = file.toBlob();
const url = URL.createObjectURL(blob || new Blob());
const a = document.createElement("a");
a.href = url;
a.download = file.id || "download";
a.click();
URL.revokeObjectURL(url);
} catch (error) {
console.error("Error downloading file:", error);
}
}
function formatFileSize(bytes?: number): string {
if (!bytes) return "0 Bytes";
const k = 1024;
const sizes = ["Bytes", "KB", "MB", "GB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
}
const onDragEnter = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
e.stopPropagation();
dragAndDropElementRef?.current?.classList.replace(
"border-stone-400",
"border-blue-700",
);
};
const onDragOver = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
e.stopPropagation();
dragAndDropElementRef?.current?.classList.replace(
"border-stone-400",
"border-blue-700",
);
};
const onDragLeave = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
e.stopPropagation();
dragAndDropElementRef?.current?.classList.replace(
"border-blue-700",
"border-stone-400",
);
};
const onDrop = async (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
e.stopPropagation();
dragAndDropElementRef?.current?.classList.replace(
"border-blue-700",
"border-stone-400",
);
if (!me?.profile) {
setError("User profile not found");
return;
}
const droppedFiles = e.dataTransfer.files;
if (!droppedFiles || droppedFiles.length === 0) {
return;
}
const file = droppedFiles[0];
setProgress(0);
try {
setIsUploading(true);
me.profile.file = await FileStream.createFromBlob(file, {
onProgress: (p) => setProgress(Math.round(p * 100)),
});
} catch (error) {
setError(
error instanceof Error ? error.message : "Failed to upload file",
);
console.error("Error uploading file:", error);
} finally {
setIsUploading(false);
}
};
if (me?.profile?.file == null) {
return (
<div className="flex flex-col gap-4">
<div
className="flex flex-col border-2 border-dashed border-stone-400 h-48 items-center justify-center bg-stone-100 m-5 rounded-md"
ref={dragAndDropElementRef}
onDragEnter={onDragEnter}
onDragOver={onDragOver}
onDragLeave={onDragLeave}
onDrop={onDrop}
>
<p>Drag & drop your file here</p>
</div>
<form onSubmit={handleUpload} className="flex gap-2">
<input
className="bg-stone-100 py-1.5 px-2 text-sm rounded-md w-4/5"
ref={inputRef}
type="file"
accept="file"
onChange={() => setError(null)}
disabled={isUploading}
/>
<button
type="submit"
className="bg-stone-100 py-1.5 px-3 text-sm rounded-md disabled:opacity-50"
disabled={isUploading}
>
{isUploading ? `Uploading...` : "Upload file"}
</button>
</form>
{error && (
<div className="text-red-800 text-sm pl-4" role="alert">
{error}
</div>
)}
{isUploading && (
<div className="flex gap-2 items-center">
<div className="py-1.5 px-3 text-sm">Progress: {progress}%</div>
<div className="h-2 bg-stone-200 rounded-full flex-1">
<div
className="h-full bg-blue-500 rounded-full transition-all duration-300"
style={{ width: `${progress}%` }}
/>
</div>
</div>
)}
</div>
);
}
const fileData = me?.profile?.file?.getChunks();
const mimeType = fileData?.mimeType || "unknown";
return (
<div className="gap-2">
<div className="p-4">
<div className="space-y-2">
<div className="flex justify-between">
<span className="font-bold">File name</span>
<span>{fileData?.fileName}</span>
</div>
<div className="flex justify-between">
<span className="font-bold">Type</span>
<span>{mimeType}</span>
</div>
<div className="flex justify-between">
<span className="font-bold">Size</span>
<span>{formatFileSize(fileData?.totalSizeBytes)}</span>
</div>
</div>
</div>
<div className="flex gap-2 justify-end">
<button
className="bg-stone-100 py-1.5 px-3 text-sm rounded-md"
onClick={handleDelete}
>
Delete file
</button>
<button
className="bg-stone-100 py-1.5 px-3 text-sm rounded-md"
onClick={handleDownload}
>
Download file
</button>
</div>
<div className="w-full justify-center pt-8">
{fileData?.mimeType?.startsWith("image/") && (
<div className="flex justify-center">
<img
src={URL.createObjectURL(
me?.profile?.file?.toBlob() || new Blob(),
)}
alt="File preview"
className="max-w-xs mb-4"
/>
</div>
)}
{fileData?.mimeType?.startsWith("audio/") && (
<div className="flex justify-center">
<audio
src={URL.createObjectURL(
me?.profile?.file?.toBlob() || new Blob(),
)}
controls
className="w-full mb-4"
/>
</div>
)}
{fileData?.mimeType?.startsWith("video/") && (
<div className="flex justify-center">
<video
src={URL.createObjectURL(
me?.profile?.file?.toBlob() || new Blob(),
)}
controls
className="w-full mb-4"
/>
</div>
)}
</div>
</div>
);
}

View File

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

View File

@@ -1,29 +0,0 @@
import { JazzProvider } from "jazz-react";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import { apiKey } from "./apiKey.ts";
import "./index.css";
import { JazzAccount } from "./schema.ts";
// We use this to identify the app in the passkey auth
export const APPLICATION_NAME = "Jazz File Stream Example";
declare module "jazz-react" {
export interface Register {
Account: JazzAccount;
}
}
createRoot(document.getElementById("root")!).render(
<StrictMode>
<JazzProvider
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
AccountSchema={JazzAccount}
>
<App />
</JazzProvider>
</StrictMode>,
);

View File

@@ -1,14 +0,0 @@
import { Account, FileStream, Profile, co } from "jazz-tools";
export class JazzProfile extends Profile {
file = co.ref(FileStream, { optional: true });
}
export class JazzAccount extends Account {
profile = co.ref(JazzProfile);
/** The account migration is run on account creation and on every log-in.
* You can use it to set up the account root and any other initial CoValues you need.
*/
migrate(this: JazzAccount) {}
}

View File

@@ -1,9 +0,0 @@
import { expect, test } from "@playwright/test";
test("home page loads", async ({ page }) => {
await page.goto("/");
await expect(page.getByText("Welcome!")).toBeVisible();
await page.getByLabel("Name").fill("Bob");
await expect(page.getByText("Welcome, Bob!")).toBeVisible();
});

View File

@@ -1,272 +1,5 @@
# form
## 0.1.6
### Patch Changes
- Updated dependencies [e7c85b7]
- Updated dependencies [8ed144e]
- jazz-react@0.11.6
- jazz-tools@0.11.6
- jazz-browser-media-images@0.11.6
## 0.1.5
### Patch Changes
- jazz-react@0.11.5
- jazz-tools@0.11.5
- jazz-browser-media-images@0.11.5
## 0.1.4
### Patch Changes
- Updated dependencies [57a3dbe]
- Updated dependencies [a717754]
- Updated dependencies [a91f343]
- jazz-tools@0.11.4
- jazz-browser-media-images@0.11.4
- jazz-react@0.11.4
## 0.1.3
### Patch Changes
- jazz-react@0.11.3
- jazz-tools@0.11.3
- jazz-browser-media-images@0.11.3
## 0.1.2
### Patch Changes
- Updated dependencies [6892dc6]
- jazz-tools@0.11.2
- jazz-react@0.11.2
- jazz-browser-media-images@0.11.2
## 0.1.1
### Patch Changes
- jazz-react@0.11.1
## 0.1.0
### Minor Changes
- 18428ea: PasskeyAuth: Sets `profile.name` only if a non-empty username is passed to `signUp`
### 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-browser-media-images@0.11.0
- jazz-react@0.11.0
## 0.0.53
### Patch Changes
- Updated dependencies [2f99de0]
- jazz-tools@0.10.15
- jazz-browser-media-images@0.10.15
- jazz-react@0.10.15
## 0.0.52
### Patch Changes
- Updated dependencies [75211e3]
- jazz-tools@0.10.14
- jazz-react@0.10.14
- jazz-browser-media-images@0.10.14
## 0.0.51
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-browser-media-images@0.10.13
- jazz-react@0.10.13
## 0.0.50
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
- jazz-browser-media-images@0.10.12
## 0.0.49
### Patch Changes
- jazz-browser-media-images@0.10.9
- jazz-react@0.10.9
## 0.0.48
### Patch Changes
- Updated dependencies [2fb6428]
- jazz-tools@0.10.8
- jazz-react@0.10.8
- jazz-browser-media-images@0.10.8
## 0.0.47
### Patch Changes
- Updated dependencies [1136d9b]
- Updated dependencies [0eed228]
- jazz-react@0.10.7
- jazz-tools@0.10.7
- jazz-browser-media-images@0.10.7
## 0.0.46
### Patch Changes
- Updated dependencies [1d71ca1]
- Updated dependencies [ada802b]
- hash-slash@0.2.2
- jazz-react@0.10.6
- jazz-tools@0.10.6
- jazz-browser-media-images@0.10.6
## 0.0.45
### Patch Changes
- Updated dependencies [59ff77e]
- jazz-tools@0.10.5
- jazz-browser-media-images@0.10.5
- jazz-react@0.10.5
## 0.0.44
### Patch Changes
- jazz-react@0.10.4
- jazz-tools@0.10.4
- jazz-browser-media-images@0.10.4
## 0.0.43
### Patch Changes
- Updated dependencies [d8582fc]
- jazz-tools@0.10.3
- jazz-browser-media-images@0.10.3
- jazz-react@0.10.3
## 0.0.42
### Patch Changes
- jazz-react@0.10.2
- jazz-tools@0.10.2
- jazz-browser-media-images@0.10.2
## 0.0.41
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-browser-media-images@0.10.1
- jazz-react@0.10.1
## 0.0.40
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-react@0.10.0
- jazz-tools@0.10.0
- jazz-browser-media-images@0.10.0
## 0.0.39
### Patch Changes
- jazz-react@0.9.23
- jazz-tools@0.9.23
- jazz-browser-media-images@0.9.23
## 0.0.38
### Patch Changes
- jazz-browser-media-images@0.9.22
- jazz-react@0.9.22
## 0.0.37
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-browser-media-images@0.9.21
- jazz-react@0.9.21
## 0.0.36
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-browser-media-images@0.9.20
- jazz-react@0.9.20
## 0.0.35
### Patch Changes
- jazz-react@0.9.19
- jazz-tools@0.9.19
- jazz-browser-media-images@0.9.19
## 0.0.34
### Patch Changes
- jazz-react@0.9.18
- jazz-tools@0.9.18
- jazz-browser-media-images@0.9.18
## 0.0.33
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-browser-media-images@0.9.17
- jazz-react@0.9.17
## 0.0.32
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-tools@0.9.16
- jazz-browser-media-images@0.9.16
- jazz-react@0.9.16
## 0.0.31
### Patch Changes

View File

@@ -28,12 +28,16 @@ You can either
Create a new Jazz project, and use this example as a template.
```bash
npx create-jazz-app@latest form-app --example form
npm create jazz-app@latest --example form --project-name form
```
or
```bash
npx create-jazz-app@latest --example form --project-name form
```
Go to the new project directory.
```bash
cd form-app
cd form
```
Run the dev server.

View File

@@ -1,7 +1,7 @@
{
"name": "form",
"private": true,
"version": "0.1.6",
"version": "0.0.31",
"type": "module",
"scripts": {
"dev": "vite",
@@ -20,7 +20,7 @@
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@playwright/test": "^1.50.1",
"@playwright/test": "^1.46.1",
"@tailwindcss/forms": "^0.5.9",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
@@ -29,8 +29,8 @@
"globals": "^15.11.0",
"is-ci": "^3.0.1",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"tailwindcss": "^3.4.15",
"typescript": "~5.6.2",
"vite": "^6.0.11"
"vite": "^5.4.10"
}
}

View File

@@ -1,4 +1,5 @@
import { useIframeHashRouter } from "hash-slash";
import { useAccount } from "jazz-react";
import { ID } from "jazz-tools";
import { CreateOrder } from "./CreateOrder.tsx";
import { EditOrder } from "./EditOrder.tsx";
@@ -6,10 +7,25 @@ import { Orders } from "./Orders.tsx";
import { BubbleTeaOrder } from "./schema.ts";
function App() {
const { me, logOut } = useAccount();
const router = useIframeHashRouter();
return (
<>
<header>
<nav className="container py-2 border-b flex items-center justify-between">
<span>
You're logged in as <strong>{me?.profile?.name}</strong>
</span>
<button
className="bg-stone-100 py-1.5 px-3 text-sm rounded-md dark:bg-stone-900 dark:text-white"
onClick={() => logOut()}
>
Log out
</button>
</nav>
</header>
<main className="container py-8 space-y-8">
{router.route({
"/": () => <Orders />,

View File

@@ -12,9 +12,7 @@ import {
} from "./schema.ts";
export function CreateOrder() {
const { me } = useAccount({
resolve: { root: { draft: true, orders: true } },
});
const { me } = useAccount({ root: { draft: {}, orders: [] } });
const router = useIframeHashRouter();
const [errors, setErrors] = useState<string[]>([]);
@@ -62,7 +60,7 @@ function CreateOrderForm({
onSave: (draft: DraftBubbleTeaOrder) => void;
}) {
const draft = useCoState(DraftBubbleTeaOrder, id, {
resolve: { addOns: true },
addOns: [],
});
if (!draft) return;

View File

@@ -2,7 +2,7 @@ import { useAccount } from "jazz-react";
export function DraftIndicator() {
const { me } = useAccount({
resolve: { root: { draft: true } },
root: { draft: {} },
});
if (me?.root.draft?.hasChanges) {

View File

@@ -6,7 +6,7 @@ import { OrderThumbnail } from "./OrderThumbnail.tsx";
import { BubbleTeaOrder } from "./schema.ts";
export function EditOrder(props: { id: ID<BubbleTeaOrder> }) {
const order = useCoState(BubbleTeaOrder, props.id);
const order = useCoState(BubbleTeaOrder, props.id, []);
if (!order) return;

View File

@@ -4,7 +4,7 @@ import { OrderThumbnail } from "./OrderThumbnail.tsx";
export function Orders() {
const { me } = useAccount({
resolve: { root: { orders: true } },
root: { orders: [] },
});
return (

View File

@@ -1 +0,0 @@
export const apiKey = "form-example@garden.co";

View File

@@ -1,11 +1,30 @@
import { JazzProvider } from "jazz-react";
import { DemoAuthBasicUI, JazzProvider, useDemoAuth } from "jazz-react";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./index.css";
import { apiKey } from "./apiKey";
import { JazzAccount } from "./schema.ts";
function JazzAndAuth({ children }: { children: React.ReactNode }) {
const [auth, authState] = useDemoAuth();
return (
<>
<JazzProvider
auth={auth}
peer="wss://cloud.jazz.tools/?key=form-example@garden.co"
AccountSchema={JazzAccount}
>
{children}
</JazzProvider>
{authState.state !== "signedIn" && (
<DemoAuthBasicUI appName="Form" state={authState} />
)}
</>
);
}
declare module "jazz-react" {
interface Register {
Account: JazzAccount;
@@ -14,13 +33,8 @@ declare module "jazz-react" {
createRoot(document.getElementById("root")!).render(
<StrictMode>
<JazzProvider
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
AccountSchema={JazzAccount}
>
<JazzAndAuth>
<App />
</JazzProvider>
</JazzAndAuth>
</StrictMode>,
);

View File

@@ -1,7 +1,13 @@
import { expect, test } from "@playwright/test";
import { LoginPage } from "./pages/LoginPage";
test("create and edit an order", async ({ page }) => {
await page.goto("/");
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.fillUsername("Alice");
await loginPage.signup();
// start an order
await page.getByRole("link", { name: "Add new order" }).click();
await page.getByLabel("Base tea").selectOption("Oolong");

View File

@@ -0,0 +1,40 @@
import { Locator, Page, expect } from "@playwright/test";
export class LoginPage {
readonly page: Page;
readonly usernameInput: Locator;
readonly signupButton: Locator;
constructor(page: Page) {
this.page = page;
this.usernameInput = page.getByRole("textbox");
this.signupButton = page.getByRole("button", {
name: "Sign up",
});
}
async goto() {
this.page.goto("/");
}
async fillUsername(value: string) {
await this.usernameInput.clear();
await this.usernameInput.fill(value);
}
async loginAs(value: string) {
await this.page
.getByRole("button", {
name: value,
})
.click();
}
async signup() {
await this.signupButton.click();
}
async expectLoaded() {
await expect(this.signupButton).toBeVisible();
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"root":["./src/app.tsx","./src/createorder.tsx","./src/draftindicator.tsx","./src/editorder.tsx","./src/errors.tsx","./src/linktohome.tsx","./src/orderform.tsx","./src/orderthumbnail.tsx","./src/orders.tsx","./src/main.tsx","./src/schema.ts","./src/vite-env.d.ts"],"version":"5.6.3"}

View File

@@ -1,267 +1,5 @@
# image-upload
## 0.0.62
### Patch Changes
- Updated dependencies [e7c85b7]
- Updated dependencies [8ed144e]
- jazz-react@0.11.6
- jazz-tools@0.11.6
- jazz-browser-media-images@0.11.6
## 0.0.61
### Patch Changes
- jazz-react@0.11.5
- jazz-tools@0.11.5
- jazz-browser-media-images@0.11.5
## 0.0.60
### Patch Changes
- Updated dependencies [57a3dbe]
- Updated dependencies [a717754]
- Updated dependencies [a91f343]
- jazz-tools@0.11.4
- jazz-browser-media-images@0.11.4
- jazz-react@0.11.4
## 0.0.59
### Patch Changes
- jazz-react@0.11.3
- jazz-tools@0.11.3
- jazz-browser-media-images@0.11.3
## 0.0.58
### Patch Changes
- Updated dependencies [6892dc6]
- jazz-tools@0.11.2
- jazz-react@0.11.2
- jazz-browser-media-images@0.11.2
## 0.0.57
### Patch Changes
- jazz-react@0.11.1
## 0.0.56
### 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-browser-media-images@0.11.0
- jazz-react@0.11.0
## 0.0.55
### Patch Changes
- Updated dependencies [2f99de0]
- jazz-tools@0.10.15
- jazz-browser-media-images@0.10.15
- jazz-react@0.10.15
## 0.0.54
### Patch Changes
- Updated dependencies [75211e3]
- jazz-tools@0.10.14
- jazz-react@0.10.14
- jazz-browser-media-images@0.10.14
## 0.0.53
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-browser-media-images@0.10.13
- jazz-react@0.10.13
## 0.0.52
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
- jazz-browser-media-images@0.10.12
## 0.0.51
### Patch Changes
- jazz-browser-media-images@0.10.9
- jazz-react@0.10.9
## 0.0.50
### Patch Changes
- Updated dependencies [2fb6428]
- jazz-tools@0.10.8
- jazz-react@0.10.8
- jazz-browser-media-images@0.10.8
## 0.0.49
### Patch Changes
- Updated dependencies [1136d9b]
- Updated dependencies [0eed228]
- jazz-react@0.10.7
- jazz-tools@0.10.7
- jazz-browser-media-images@0.10.7
## 0.0.48
### Patch Changes
- Updated dependencies [1d71ca1]
- Updated dependencies [ada802b]
- jazz-react@0.10.6
- jazz-tools@0.10.6
- jazz-browser-media-images@0.10.6
## 0.0.47
### Patch Changes
- Updated dependencies [59ff77e]
- jazz-tools@0.10.5
- jazz-browser-media-images@0.10.5
- jazz-react@0.10.5
## 0.0.46
### Patch Changes
- jazz-react@0.10.4
- jazz-tools@0.10.4
- jazz-browser-media-images@0.10.4
## 0.0.45
### Patch Changes
- Updated dependencies [d8582fc]
- jazz-tools@0.10.3
- jazz-browser-media-images@0.10.3
- jazz-react@0.10.3
## 0.0.44
### Patch Changes
- jazz-react@0.10.2
- jazz-tools@0.10.2
- jazz-browser-media-images@0.10.2
## 0.0.43
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-browser-media-images@0.10.1
- jazz-react@0.10.1
## 0.0.42
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-react@0.10.0
- jazz-tools@0.10.0
- jazz-browser-media-images@0.10.0
## 0.0.41
### Patch Changes
- jazz-react@0.9.23
- jazz-tools@0.9.23
- jazz-browser-media-images@0.9.23
## 0.0.40
### Patch Changes
- jazz-browser-media-images@0.9.22
- jazz-react@0.9.22
## 0.0.39
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-browser-media-images@0.9.21
- jazz-react@0.9.21
## 0.0.38
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-browser-media-images@0.9.20
- jazz-react@0.9.20
## 0.0.37
### Patch Changes
- jazz-react@0.9.19
- jazz-tools@0.9.19
- jazz-browser-media-images@0.9.19
## 0.0.36
### Patch Changes
- jazz-react@0.9.18
- jazz-tools@0.9.18
- jazz-browser-media-images@0.9.18
## 0.0.35
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-browser-media-images@0.9.17
- jazz-react@0.9.17
## 0.0.34
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-tools@0.9.16
- jazz-browser-media-images@0.9.16
- jazz-react@0.9.16
## 0.0.33
### Patch Changes

View File

@@ -15,12 +15,16 @@ You can either
Create a new Jazz project, and use this example as a template.
```bash
npx create-jazz-app@latest image-upload-app --example image-upload
npm create jazz-app@latest --example image-upload --project-name image-upload
```
or
```bash
npx create-jazz-app@latest --example image-upload --project-name image-upload
```
Go to the new project directory.
```bash
cd image-upload-app
cd image-upload
```
Run the dev server.

View File

@@ -1,7 +1,7 @@
{
"name": "image-upload",
"private": true,
"version": "0.0.62",
"version": "0.0.33",
"type": "module",
"scripts": {
"dev": "vite",
@@ -24,9 +24,6 @@
"@vitejs/plugin-react": "^4.3.3",
"globals": "^15.11.0",
"typescript": "~5.6.2",
"vite": "^6.0.11",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17"
"vite": "^5.4.10"
}
}

View File

@@ -1,9 +1,20 @@
import { useAccount } from "jazz-react";
import ImageUpload from "./ImageUpload.tsx";
function App() {
const { me, logOut } = useAccount();
return (
<>
<main className="container py-16">
<header>
<nav className="container">
<span>
You're logged in as <strong>{me?.profile?.name}</strong>
</span>
<button onClick={() => logOut()}>Log out</button>
</nav>
</header>
<main className="container">
<ImageUpload />
</main>
</>

View File

@@ -1,97 +1,55 @@
import { createImage } from "jazz-browser-media-images";
import { ProgressiveImg, useAccount } from "jazz-react";
import { ChangeEvent, useEffect, useRef, useState } from "react";
import { ImageDefinition } from "jazz-tools";
import { ChangeEvent, useRef } from "react";
function Image({ image }: { image: ImageDefinition }) {
return (
<ProgressiveImg image={image}>
{({ src }) => <img src={src} />}
</ProgressiveImg>
);
}
export default function ImageUpload() {
const { me } = useAccount();
const [imagePreviewUrl, setImagePreviewUrl] = useState<string | null>(null);
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
if (imagePreviewUrl) {
e.preventDefault();
return "Upload in progress. Are you sure you want to leave?";
}
};
window.addEventListener("beforeunload", handleBeforeUnload);
return () => {
window.removeEventListener("beforeunload", handleBeforeUnload);
if (imagePreviewUrl) {
URL.revokeObjectURL(imagePreviewUrl);
}
};
}, [imagePreviewUrl]);
const onImageChange = async (event: ChangeEvent<HTMLInputElement>) => {
if (!me?.profile) return;
const file = event.currentTarget.files?.[0];
if (file) {
const objectUrl = URL.createObjectURL(file);
setImagePreviewUrl(objectUrl);
try {
me.profile.image = await createImage(file, {
owner: me.profile._owner,
});
} catch (error) {
console.error("Error uploading image:", error);
} finally {
URL.revokeObjectURL(objectUrl);
setImagePreviewUrl(null);
}
me.profile.image = await createImage(file, {
owner: me.profile._owner,
});
}
};
const deleteImage = () => {
if (!me?.profile) return;
me.profile.image = null;
};
if (me?.profile?.image) {
return (
<>
<ProgressiveImg image={me.profile.image}>
{({ src }) => <img alt="" src={src} className="w-full h-auto" />}
</ProgressiveImg>
<button type="button" onClick={deleteImage} className="mt-5">
Delete image
</button>
</>
);
}
if (imagePreviewUrl) {
return (
<div className="relative">
<p className="z-10 absolute font-semibold text-gray-900 inset-0 flex items-center justify-center">
Uploading image...
</p>
<img
src={imagePreviewUrl}
alt="Preview"
className="opacity-50 w-full h-auto"
/>
</div>
);
}
return (
<div className="flex flex-col gap-3">
<label htmlFor="image">Image</label>
<input
id="image"
name="image"
ref={inputRef}
type="file"
accept="image/png, image/jpeg, image/gif, image/bmp"
onChange={onImageChange}
/>
</div>
<>
<div>{me?.profile?.image && <Image image={me.profile.image} />}</div>
<div>
{me?.profile?.image ? (
<button type="button" onClick={deleteImage}>
Delete image
</button>
) : (
<div>
<label>Upload image</label>
<input ref={inputRef} type="file" onChange={onImageChange} />
</div>
)}
</div>
</>
);
}

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