Compare commits
1 Commits
fix/option
...
styling/ki
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c939db1af0 |
@@ -1,6 +0,0 @@
|
||||
---
|
||||
"jazz-tools": minor
|
||||
"cojson": minor
|
||||
---
|
||||
|
||||
Check CoValue access permissions when loading
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"jazz-tools": minor
|
||||
---
|
||||
|
||||
Implement new API for deep loading
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"cojson": minor
|
||||
---
|
||||
|
||||
Return the EVERYONE role if the account is not direct a member of the group
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
"jazz-react-core": patch
|
||||
"jazz-svelte": patch
|
||||
"jazz-tools": patch
|
||||
"jazz-vue": patch
|
||||
---
|
||||
|
||||
Fix type inference on `useCoState`
|
||||
1
.github/workflows/build-examples.yaml
vendored
1
.github/workflows/build-examples.yaml
vendored
@@ -19,6 +19,7 @@ jobs:
|
||||
"pets",
|
||||
"reactions",
|
||||
"todo",
|
||||
"onboarding",
|
||||
]
|
||||
|
||||
steps:
|
||||
|
||||
2
.github/workflows/playwright.yml
vendored
2
.github/workflows/playwright.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
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-passkey-auth"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -7,15 +7,11 @@ docsTmp
|
||||
coverage
|
||||
.direnv
|
||||
|
||||
# Typescript
|
||||
**/*.tsbuildinfo
|
||||
|
||||
# Next.js
|
||||
**/.next
|
||||
|
||||
# Vite output
|
||||
**/dist
|
||||
__screenshots__
|
||||
|
||||
# Playwright
|
||||
test-results
|
||||
|
||||
@@ -1,68 +1,5 @@
|
||||
# chat-rn-clerk
|
||||
|
||||
## 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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "chat-rn-clerk",
|
||||
"main": "index.js",
|
||||
"version": "1.0.76",
|
||||
"version": "1.0.69",
|
||||
"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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,52 +1,5 @@
|
||||
# chat-rn
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "chat-rn",
|
||||
"version": "1.0.72",
|
||||
"version": "1.0.66",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "expo export -p ios",
|
||||
@@ -13,12 +13,11 @@
|
||||
},
|
||||
"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",
|
||||
@@ -34,11 +33,16 @@
|
||||
"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-nitro-modules": "0.21.0",
|
||||
"react-native-polyfill-globals": "^3.1.0",
|
||||
"react-native-quick-crypto": "1.0.0-beta.12",
|
||||
"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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -9,7 +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 { JazzProvider, RNQuickCrypto } from "jazz-react-native";
|
||||
import { apiKey } from "./apiKey";
|
||||
import ChatScreen from "./chat";
|
||||
|
||||
@@ -50,6 +50,7 @@ function App() {
|
||||
sync={{
|
||||
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
|
||||
}}
|
||||
CryptoProvider={RNQuickCrypto}
|
||||
>
|
||||
<NavigationContainer linking={linking} ref={navigationRef}>
|
||||
<Stack.Navigator initialRouteName={initialRoute}>
|
||||
|
||||
@@ -20,7 +20,7 @@ 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, {});
|
||||
|
||||
|
||||
@@ -44,5 +44,4 @@ appId: com.jazz.chatrn
|
||||
|
||||
# logout
|
||||
- tapOn: "Logout"
|
||||
- assertVisible: "boorad"
|
||||
- assertVisible: "bro, low key, it do be like that tho"
|
||||
- assertVisible: "Anonymous user"
|
||||
|
||||
@@ -1,52 +1,5 @@
|
||||
# chat-vue
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "chat-vue",
|
||||
"version": "0.0.58",
|
||||
"version": "0.0.53",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -1,51 +1,5 @@
|
||||
# jazz-example-chat
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jazz-example-chat",
|
||||
"private": true,
|
||||
"version": "0.0.154",
|
||||
"version": "0.0.149",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -9,8 +9,8 @@
|
||||
"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",
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
} from "./ui.tsx";
|
||||
|
||||
export function ChatScreen(props: { chatID: ID<Chat> }) {
|
||||
const chat = useCoState(Chat, props.chatID, { resolve: { $each: true } });
|
||||
const chat = useCoState(Chat, props.chatID, [{}]);
|
||||
const [showNLastMessages, setShowNLastMessages] = useState(30);
|
||||
|
||||
if (!chat)
|
||||
|
||||
@@ -1,50 +1,5 @@
|
||||
# minimal-auth-clerk
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "clerk",
|
||||
"private": true,
|
||||
"version": "0.0.53",
|
||||
"version": "0.0.48",
|
||||
"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.10.9",
|
||||
"jazz-react-auth-clerk": "workspace:0.10.4",
|
||||
"jazz-tools": "workspace:*",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
|
||||
@@ -1,44 +1,5 @@
|
||||
# file-share-svelte
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "file-share-svelte",
|
||||
"version": "0.0.38",
|
||||
"version": "0.0.33",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -13,8 +13,8 @@
|
||||
"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",
|
||||
|
||||
@@ -1,51 +1,5 @@
|
||||
# form
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "form",
|
||||
"private": true,
|
||||
"version": "0.0.49",
|
||||
"version": "0.0.44",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -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 />,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { OrderThumbnail } from "./OrderThumbnail.tsx";
|
||||
|
||||
export function Orders() {
|
||||
const { me } = useAccount({
|
||||
resolve: { root: { orders: true } },
|
||||
root: { orders: [] },
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
1
examples/form/tsconfig.node.tsbuildinfo
Normal file
1
examples/form/tsconfig.node.tsbuildinfo
Normal file
File diff suppressed because one or more lines are too long
1
examples/form/tsconfig.tsbuildinfo
Normal file
1
examples/form/tsconfig.tsbuildinfo
Normal 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"}
|
||||
@@ -1,50 +1,5 @@
|
||||
# image-upload
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "image-upload",
|
||||
"private": true,
|
||||
"version": "0.0.51",
|
||||
"version": "0.0.46",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
import { useAccount } from "jazz-react";
|
||||
import ImageUpload from "./ImageUpload.tsx";
|
||||
|
||||
function App() {
|
||||
const { me, logOut } = useAccount();
|
||||
|
||||
return (
|
||||
<>
|
||||
<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>
|
||||
|
||||
@@ -46,12 +46,7 @@ export default function ImageUpload() {
|
||||
) : (
|
||||
<div>
|
||||
<label>Upload image</label>
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="file"
|
||||
accept="image/png, image/jpeg, image/gif"
|
||||
onChange={onImageChange}
|
||||
/>
|
||||
<input ref={inputRef} type="file" onChange={onImageChange} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -72,7 +72,8 @@ nav {
|
||||
.container {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
padding: 2rem 0.75rem;
|
||||
padding-right: 0.75rem;
|
||||
padding-left: 0.75rem;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,32 +1,5 @@
|
||||
# jazz-example-inspector
|
||||
|
||||
## 0.0.109
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [153dc99]
|
||||
- cojson@0.10.8
|
||||
- cojson-transport-ws@0.10.8
|
||||
|
||||
## 0.0.108
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [0f83320]
|
||||
- Updated dependencies [012022d]
|
||||
- cojson@0.10.7
|
||||
- cojson-transport-ws@0.10.7
|
||||
|
||||
## 0.0.107
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1d71ca1]
|
||||
- Updated dependencies [5c76e37]
|
||||
- hash-slash@0.2.2
|
||||
- cojson@0.10.6
|
||||
- cojson-transport-ws@0.10.6
|
||||
|
||||
## 0.0.106
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jazz-inspector-app",
|
||||
"private": true,
|
||||
"version": "0.0.109",
|
||||
"version": "0.0.106",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -16,9 +16,9 @@
|
||||
"@radix-ui/react-toast": "^1.1.4",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.0.0",
|
||||
"cojson": "workspace:0.10.8",
|
||||
"cojson-transport-ws": "workspace:0.10.8",
|
||||
"hash-slash": "workspace:0.2.2",
|
||||
"cojson": "workspace:0.10.4",
|
||||
"cojson-transport-ws": "workspace:0.10.4",
|
||||
"hash-slash": "workspace:0.2.1",
|
||||
"lucide-react": "^0.274.0",
|
||||
"qrcode": "^1.5.3",
|
||||
"react": "^18.3.1",
|
||||
|
||||
@@ -102,7 +102,6 @@ export default function CoJsonViewerApp() {
|
||||
if (coValueId) {
|
||||
setPage(coValueId);
|
||||
}
|
||||
setCoValueId("");
|
||||
};
|
||||
|
||||
if (
|
||||
@@ -119,22 +118,8 @@ export default function CoJsonViewerApp() {
|
||||
|
||||
return (
|
||||
<div className="w-full h-screen bg-gray-100 p-4 overflow-hidden flex flex-col">
|
||||
<div className="flex items-center mb-4 gap-4">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<Breadcrumbs path={path} onBreadcrumbClick={goToIndex} />
|
||||
<div className="flex-1">
|
||||
<form onSubmit={handleCoValueIdSubmit}>
|
||||
{path.length !== 0 && (
|
||||
<input
|
||||
className="border p-2 rounded-lg min-w-[21rem] font-mono"
|
||||
placeholder="co_z1234567890abcdef123456789"
|
||||
value={coValueId}
|
||||
onChange={(e) =>
|
||||
setCoValueId(e.target.value as CoID<RawCoValue>)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
<AccountSwitcher
|
||||
accounts={accounts}
|
||||
currentAccount={currentAccount}
|
||||
@@ -187,6 +172,7 @@ export default function CoJsonViewerApp() {
|
||||
type="button"
|
||||
className="border inline-block px-2 py-1.5 text-black rounded"
|
||||
onClick={() => {
|
||||
setCoValueId(currentAccount.id);
|
||||
setPage(currentAccount.id);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -18,8 +18,6 @@ export function ValueRenderer({
|
||||
compact?: boolean;
|
||||
onCoIDClick?: (childNode: CoID<RawCoValue>) => void;
|
||||
}) {
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
if (typeof json === "undefined" || json === undefined) {
|
||||
return <span className="text-gray-400">undefined</span>;
|
||||
}
|
||||
@@ -87,31 +85,15 @@ export function ValueRenderer({
|
||||
return (
|
||||
<span
|
||||
title={JSON.stringify(json, null, 2)}
|
||||
className="inline-block max-w-64"
|
||||
className="inline-block max-w-64 truncate"
|
||||
>
|
||||
{compact ? (
|
||||
<span>
|
||||
Object{" "}
|
||||
<span className="text-gray-500">({Object.keys(json).length})</span>
|
||||
<pre className="mt-1 text-sm whitespace-pre-wrap">
|
||||
{isExpanded
|
||||
? JSON.stringify(json, null, 2)
|
||||
: JSON.stringify(json, null, 2)
|
||||
.split("\n")
|
||||
.slice(0, 3)
|
||||
.join("\n") + (Object.keys(json).length > 2 ? "\n..." : "")}
|
||||
</pre>
|
||||
<button
|
||||
onClick={() => setIsExpanded(!isExpanded)}
|
||||
className="text-xs text-gray-500 hover:text-gray-700"
|
||||
>
|
||||
{isExpanded ? "Show less" : "Show more"}
|
||||
</button>
|
||||
</span>
|
||||
) : (
|
||||
<pre className="whitespace-pre-wrap">
|
||||
{JSON.stringify(json, null, 2)}
|
||||
</pre>
|
||||
JSON.stringify(json, null, 2)
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
|
||||
@@ -1,49 +1,5 @@
|
||||
# jazz-example-musicplayer
|
||||
|
||||
## 0.0.75
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.10.9
|
||||
|
||||
## 0.0.74
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2fb6428]
|
||||
- jazz-tools@0.10.8
|
||||
- jazz-inspector@0.10.8
|
||||
- jazz-react@0.10.8
|
||||
|
||||
## 0.0.73
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-react@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
- jazz-inspector@0.10.7
|
||||
|
||||
## 0.0.72
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1d71ca1]
|
||||
- Updated dependencies [ada802b]
|
||||
- jazz-react@0.10.6
|
||||
- jazz-tools@0.10.6
|
||||
- jazz-inspector@0.10.6
|
||||
|
||||
## 0.0.71
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [59ff77e]
|
||||
- jazz-tools@0.10.5
|
||||
- jazz-inspector@0.10.5
|
||||
- jazz-react@0.10.5
|
||||
|
||||
## 0.0.70
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jazz-example-music-player",
|
||||
"private": true,
|
||||
"version": "0.0.75",
|
||||
"version": "0.0.70",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -9,8 +9,8 @@
|
||||
"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": {
|
||||
"@radix-ui/react-dialog": "^1.1.4",
|
||||
@@ -22,8 +22,8 @@
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.0.0",
|
||||
"jazz-inspector": "workspace:*",
|
||||
"jazz-react": "workspace:0.10.9",
|
||||
"jazz-tools": "workspace:0.10.8",
|
||||
"jazz-react": "workspace:0.10.4",
|
||||
"jazz-tools": "workspace:0.10.4",
|
||||
"lucide-react": "^0.274.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
|
||||
@@ -24,7 +24,10 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
|
||||
* access rights to CoValues. We get it from the top-level provider `<WithJazz/>`.
|
||||
*/
|
||||
const { me } = useAccount({
|
||||
resolve: { root: { rootPlaylist: true, playlists: true } },
|
||||
root: {
|
||||
rootPlaylist: {},
|
||||
playlists: [],
|
||||
},
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
@@ -48,9 +51,8 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
|
||||
|
||||
const params = useParams<{ playlistId: ID<Playlist> }>();
|
||||
const playlistId = params.playlistId ?? me?.root._refs.rootPlaylist.id;
|
||||
|
||||
const playlist = useCoState(Playlist, playlistId, {
|
||||
resolve: { tracks: true },
|
||||
tracks: [],
|
||||
});
|
||||
|
||||
const isRootPlaylist = !params.playlistId;
|
||||
|
||||
@@ -27,11 +27,9 @@ export async function uploadMusicTracks(
|
||||
isExampleTrack: boolean = false,
|
||||
) {
|
||||
const { root } = await MusicaAccount.getMe().ensureLoaded({
|
||||
resolve: {
|
||||
root: {
|
||||
rootPlaylist: {
|
||||
tracks: true,
|
||||
},
|
||||
root: {
|
||||
rootPlaylist: {
|
||||
tracks: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -67,10 +65,8 @@ export async function uploadMusicTracks(
|
||||
|
||||
export async function createNewPlaylist() {
|
||||
const { root } = await MusicaAccount.getMe().ensureLoaded({
|
||||
resolve: {
|
||||
root: {
|
||||
playlists: true,
|
||||
},
|
||||
root: {
|
||||
playlists: [],
|
||||
},
|
||||
});
|
||||
|
||||
@@ -156,11 +152,9 @@ export async function updateMusicTrackTitle(track: MusicTrack, title: string) {
|
||||
|
||||
export async function updateActivePlaylist(playlist?: Playlist) {
|
||||
const { root } = await MusicaAccount.getMe().ensureLoaded({
|
||||
resolve: {
|
||||
root: {
|
||||
activePlaylist: true,
|
||||
rootPlaylist: true,
|
||||
},
|
||||
root: {
|
||||
activePlaylist: {},
|
||||
rootPlaylist: {},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -169,9 +163,7 @@ export async function updateActivePlaylist(playlist?: Playlist) {
|
||||
|
||||
export async function updateActiveTrack(track: MusicTrack) {
|
||||
const { root } = await MusicaAccount.getMe().ensureLoaded({
|
||||
resolve: {
|
||||
root: {},
|
||||
},
|
||||
root: {},
|
||||
});
|
||||
|
||||
root.activeTrack = track;
|
||||
@@ -181,23 +173,17 @@ export async function onAnonymousAccountDiscarded(
|
||||
anonymousAccount: MusicaAccount,
|
||||
) {
|
||||
const { root: anonymousAccountRoot } = await anonymousAccount.ensureLoaded({
|
||||
resolve: {
|
||||
root: {
|
||||
rootPlaylist: {
|
||||
tracks: {
|
||||
$each: true,
|
||||
},
|
||||
},
|
||||
root: {
|
||||
rootPlaylist: {
|
||||
tracks: [{}],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const me = await MusicaAccount.getMe().ensureLoaded({
|
||||
resolve: {
|
||||
root: {
|
||||
rootPlaylist: {
|
||||
tracks: true,
|
||||
},
|
||||
root: {
|
||||
rootPlaylist: {
|
||||
tracks: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ import { getNextTrack, getPrevTrack } from "./lib/getters";
|
||||
|
||||
export function useMediaPlayer() {
|
||||
const { me } = useAccount({
|
||||
resolve: { root: true },
|
||||
root: {},
|
||||
});
|
||||
|
||||
const playState = usePlayState();
|
||||
|
||||
@@ -14,10 +14,8 @@ export function InvitePage() {
|
||||
const playlist = await Playlist.load(playlistId, {});
|
||||
|
||||
const me = await MusicaAccount.getMe().ensureLoaded({
|
||||
resolve: {
|
||||
root: {
|
||||
playlists: true,
|
||||
},
|
||||
root: {
|
||||
playlists: [],
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -22,13 +22,9 @@ export function AuthModal({ open, onOpenChange }: AuthModalProps) {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const { me } = useAccount({
|
||||
resolve: {
|
||||
root: {
|
||||
rootPlaylist: {
|
||||
tracks: {
|
||||
$each: true,
|
||||
},
|
||||
},
|
||||
root: {
|
||||
rootPlaylist: {
|
||||
tracks: [{}],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -29,7 +29,9 @@ export function MusicTrackRow({
|
||||
const track = useCoState(MusicTrack, trackId);
|
||||
|
||||
const { me } = useAccount({
|
||||
resolve: { root: { playlists: { $each: true } } },
|
||||
root: {
|
||||
playlists: [{}],
|
||||
},
|
||||
});
|
||||
|
||||
const playlists = me?.root.playlists ?? [];
|
||||
|
||||
@@ -12,7 +12,9 @@ export function PlayerControls({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
|
||||
const isPlaying = playState.value === "play";
|
||||
|
||||
const activePlaylist = useAccount({
|
||||
resolve: { root: { activePlaylist: true } },
|
||||
root: {
|
||||
activePlaylist: {},
|
||||
},
|
||||
}).me?.root.activePlaylist;
|
||||
|
||||
useMediaEndListener(mediaPlayer.playNextTrack);
|
||||
@@ -23,7 +25,7 @@ export function PlayerControls({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
|
||||
});
|
||||
|
||||
const activeTrack = useCoState(MusicTrack, mediaPlayer.activeTrackId, {
|
||||
resolve: { waveform: true },
|
||||
waveform: {},
|
||||
});
|
||||
|
||||
if (!activeTrack) return null;
|
||||
|
||||
@@ -6,7 +6,9 @@ export function SidePanel() {
|
||||
const { playlistId } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const { me } = useAccount({
|
||||
resolve: { root: { playlists: { $each: true } } },
|
||||
root: {
|
||||
playlists: [{}],
|
||||
},
|
||||
});
|
||||
|
||||
function handleAllTracksClick(evt: React.MouseEvent<HTMLAnchorElement>) {
|
||||
|
||||
@@ -8,6 +8,7 @@ export function Waveform(props: { track: MusicTrack; height: number }) {
|
||||
const waveformData = useCoState(
|
||||
MusicTrackWaveform,
|
||||
track._refs.waveform.id,
|
||||
{},
|
||||
)?.data;
|
||||
const duration = track.duration;
|
||||
|
||||
|
||||
@@ -2,11 +2,9 @@ import { MusicaAccount } from "../1_schema";
|
||||
|
||||
export async function getNextTrack() {
|
||||
const me = await MusicaAccount.getMe().ensureLoaded({
|
||||
resolve: {
|
||||
root: {
|
||||
activePlaylist: {
|
||||
tracks: true,
|
||||
},
|
||||
root: {
|
||||
activePlaylist: {
|
||||
tracks: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -23,11 +21,9 @@ export async function getNextTrack() {
|
||||
|
||||
export async function getPrevTrack() {
|
||||
const me = await MusicaAccount.getMe().ensureLoaded({
|
||||
resolve: {
|
||||
root: {
|
||||
activePlaylist: {
|
||||
tracks: true,
|
||||
},
|
||||
root: {
|
||||
activePlaylist: {
|
||||
tracks: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@ export function useUploadExampleData() {
|
||||
|
||||
async function uploadOnboardingData() {
|
||||
const me = await MusicaAccount.getMe().ensureLoaded({
|
||||
resolve: { root: true },
|
||||
root: {},
|
||||
});
|
||||
|
||||
if (me.root.exampleDataLoaded) return;
|
||||
|
||||
26
examples/onboarding/.gitignore
vendored
Normal file
26
examples/onboarding/.gitignore
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
playwright-report
|
||||
420
examples/onboarding/CHANGELOG.md
Normal file
420
examples/onboarding/CHANGELOG.md
Normal file
@@ -0,0 +1,420 @@
|
||||
# jazz-example-onboarding
|
||||
|
||||
## 0.0.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.10.4
|
||||
- jazz-tools@0.10.4
|
||||
- jazz-browser-media-images@0.10.4
|
||||
|
||||
## 0.0.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d8582fc]
|
||||
- jazz-tools@0.10.3
|
||||
- jazz-browser-media-images@0.10.3
|
||||
- jazz-react@0.10.3
|
||||
|
||||
## 0.0.48
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.10.2
|
||||
- jazz-tools@0.10.2
|
||||
- jazz-browser-media-images@0.10.2
|
||||
|
||||
## 0.0.47
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5a63cba]
|
||||
- jazz-tools@0.10.1
|
||||
- jazz-browser-media-images@0.10.1
|
||||
- jazz-react@0.10.1
|
||||
|
||||
## 0.0.46
|
||||
|
||||
### 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.45
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.9.23
|
||||
- jazz-tools@0.9.23
|
||||
- jazz-browser-media-images@0.9.23
|
||||
|
||||
## 0.0.44
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-browser-media-images@0.9.22
|
||||
- jazz-react@0.9.22
|
||||
|
||||
## 0.0.43
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1be017d]
|
||||
- jazz-tools@0.9.21
|
||||
- jazz-browser-media-images@0.9.21
|
||||
- jazz-react@0.9.21
|
||||
|
||||
## 0.0.42
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b01cc1f]
|
||||
- jazz-tools@0.9.20
|
||||
- jazz-browser-media-images@0.9.20
|
||||
- jazz-react@0.9.20
|
||||
|
||||
## 0.0.41
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.9.19
|
||||
- jazz-tools@0.9.19
|
||||
- jazz-browser-media-images@0.9.19
|
||||
|
||||
## 0.0.40
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.9.18
|
||||
- jazz-tools@0.9.18
|
||||
- jazz-browser-media-images@0.9.18
|
||||
|
||||
## 0.0.39
|
||||
|
||||
### 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.38
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [24b3b6a]
|
||||
- jazz-tools@0.9.16
|
||||
- jazz-browser-media-images@0.9.16
|
||||
- jazz-react@0.9.16
|
||||
|
||||
## 0.0.37
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [7491711]
|
||||
- jazz-tools@0.9.15
|
||||
- jazz-browser-media-images@0.9.15
|
||||
- jazz-react@0.9.15
|
||||
|
||||
## 0.0.36
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3df93cc]
|
||||
- jazz-tools@0.9.14
|
||||
- jazz-browser-media-images@0.9.14
|
||||
- jazz-react@0.9.14
|
||||
|
||||
## 0.0.35
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.9.13
|
||||
- jazz-tools@0.9.13
|
||||
- jazz-browser-media-images@0.9.13
|
||||
|
||||
## 0.0.34
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.9.12
|
||||
- jazz-tools@0.9.12
|
||||
- jazz-browser-media-images@0.9.12
|
||||
|
||||
## 0.0.33
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.9.11
|
||||
- jazz-tools@0.9.11
|
||||
- jazz-browser-media-images@0.9.11
|
||||
|
||||
## 0.0.32
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5e83864]
|
||||
- jazz-react@0.9.10
|
||||
- jazz-tools@0.9.10
|
||||
- jazz-browser-media-images@0.9.10
|
||||
|
||||
## 0.0.31
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8eb9247]
|
||||
- jazz-tools@0.9.9
|
||||
- jazz-browser-media-images@0.9.9
|
||||
- jazz-react@0.9.9
|
||||
|
||||
## 0.0.30
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d1d773b]
|
||||
- jazz-tools@0.9.8
|
||||
- jazz-react@0.9.8
|
||||
- jazz-browser-media-images@0.9.8
|
||||
|
||||
## 0.0.29
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.9.4
|
||||
|
||||
## 0.0.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1b71969]
|
||||
- jazz-react@0.9.1
|
||||
- jazz-tools@0.9.1
|
||||
- jazz-browser-media-images@0.9.1
|
||||
|
||||
## 0.0.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [956a4d1]
|
||||
- Updated dependencies [8eda792]
|
||||
- jazz-react@0.9.0
|
||||
- jazz-tools@0.9.0
|
||||
- jazz-browser-media-images@0.9.0
|
||||
|
||||
## 0.0.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [dc62b95]
|
||||
- Updated dependencies [1de26f8]
|
||||
- jazz-tools@0.8.51
|
||||
- jazz-browser-media-images@0.8.51
|
||||
- jazz-react@0.8.51
|
||||
|
||||
## 0.0.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.8.50
|
||||
- jazz-tools@0.8.50
|
||||
- jazz-browser-media-images@0.8.50
|
||||
|
||||
## 0.0.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.8.49
|
||||
- jazz-tools@0.8.49
|
||||
- jazz-browser-media-images@0.8.49
|
||||
|
||||
## 0.0.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [635e824]
|
||||
- Updated dependencies [0a85982]
|
||||
- jazz-tools@0.8.48
|
||||
- jazz-browser-media-images@0.8.48
|
||||
- jazz-react@0.8.48
|
||||
|
||||
## 0.0.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [fa41f8e]
|
||||
- Updated dependencies [88d7d9a]
|
||||
- Updated dependencies [60e35ea]
|
||||
- jazz-tools@0.8.45
|
||||
- jazz-react@0.8.45
|
||||
- jazz-browser-media-images@0.8.45
|
||||
|
||||
## 0.0.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.8.44
|
||||
- jazz-tools@0.8.44
|
||||
- jazz-browser-media-images@0.8.44
|
||||
|
||||
## 0.0.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.8.41
|
||||
- jazz-tools@0.8.41
|
||||
- jazz-browser-media-images@0.8.41
|
||||
|
||||
## 0.0.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-browser-media-images@0.8.40
|
||||
- jazz-react@0.8.40
|
||||
|
||||
## 0.0.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [249eecb]
|
||||
- jazz-tools@0.8.39
|
||||
- jazz-browser-media-images@0.8.39
|
||||
- jazz-react@0.8.39
|
||||
|
||||
## 0.0.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.8.38
|
||||
- jazz-tools@0.8.38
|
||||
- jazz-browser-media-images@0.8.38
|
||||
|
||||
## 0.0.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.8.37
|
||||
- jazz-tools@0.8.37
|
||||
- jazz-browser-media-images@0.8.37
|
||||
|
||||
## 0.0.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [441fe27]
|
||||
- jazz-tools@0.8.36
|
||||
- jazz-react@0.8.36
|
||||
- jazz-browser-media-images@0.8.36
|
||||
|
||||
## 0.0.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [9212ab8]
|
||||
- Updated dependencies [8b87117]
|
||||
- jazz-react@0.8.35
|
||||
- jazz-tools@0.8.35
|
||||
- jazz-browser-media-images@0.8.35
|
||||
|
||||
## 0.0.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.8.34
|
||||
- jazz-tools@0.8.34
|
||||
- jazz-browser-media-images@0.8.34
|
||||
|
||||
## 0.0.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-browser-media-images@0.8.33
|
||||
- jazz-react@0.8.33
|
||||
|
||||
## 0.0.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [df42b2b]
|
||||
- jazz-tools@0.8.32
|
||||
- jazz-react@0.8.32
|
||||
- jazz-browser-media-images@0.8.32
|
||||
|
||||
## 0.0.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.8.31
|
||||
- jazz-tools@0.8.31
|
||||
- jazz-browser-media-images@0.8.31
|
||||
|
||||
## 0.0.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.8.30
|
||||
- jazz-tools@0.8.30
|
||||
- jazz-browser-media-images@0.8.30
|
||||
|
||||
## 0.0.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.8.29
|
||||
- jazz-tools@0.8.29
|
||||
- jazz-browser-media-images@0.8.29
|
||||
|
||||
## 0.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.8.28
|
||||
- jazz-tools@0.8.28
|
||||
- jazz-browser-media-images@0.8.28
|
||||
|
||||
## 0.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.8.27
|
||||
- jazz-tools@0.8.27
|
||||
- jazz-browser-media-images@0.8.27
|
||||
|
||||
## 0.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [59d37df]
|
||||
- jazz-react@0.8.26
|
||||
|
||||
## 0.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-browser-media-images@0.8.24
|
||||
- jazz-react@0.8.24
|
||||
|
||||
## 0.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d348c2d]
|
||||
- Updated dependencies [6902b5b]
|
||||
- Updated dependencies [1a0cd3d]
|
||||
- jazz-tools@0.8.23
|
||||
- jazz-react@0.8.23
|
||||
- jazz-browser-media-images@0.8.23
|
||||
|
||||
## 0.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [59cc64d]
|
||||
- jazz-react@0.8.22
|
||||
- jazz-browser-media-images@0.8.22
|
||||
4
examples/onboarding/Dockerfile
Normal file
4
examples/onboarding/Dockerfile
Normal file
@@ -0,0 +1,4 @@
|
||||
FROM caddy:2.7.3-alpine
|
||||
LABEL org.opencontainers.image.source="https://github.com/garden-co/jazz"
|
||||
|
||||
COPY ./dist /usr/share/caddy/
|
||||
60
examples/onboarding/README.md
Normal file
60
examples/onboarding/README.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# Onboarding example with Jazz and React
|
||||
|
||||
## Getting started
|
||||
|
||||
You can either
|
||||
1. Clone the jazz repository, and run the app within the monorepo.
|
||||
2. Or create a new Jazz project using this example as a template.
|
||||
|
||||
|
||||
### Using the example as a template
|
||||
|
||||
Create a new Jazz project, and use this example as a template.
|
||||
```bash
|
||||
npx create-jazz-app@latest --example onboarding --project-name onboarding
|
||||
```
|
||||
|
||||
Go to the new project directory.
|
||||
```bash
|
||||
cd onboarding
|
||||
```
|
||||
|
||||
Run the dev server.
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Using the monorepo
|
||||
|
||||
This requires `pnpm` to be installed, see [https://pnpm.io/installation](https://pnpm.io/installation).
|
||||
|
||||
Clone the jazz repository.
|
||||
```bash
|
||||
git clone https://github.com/garden-co/jazz.git
|
||||
```
|
||||
|
||||
Install and build dependencies.
|
||||
```bash
|
||||
pnpm i && npx turbo build
|
||||
```
|
||||
|
||||
Go to the example directory.
|
||||
```bash
|
||||
cd jazz/examples/onboarding/
|
||||
```
|
||||
|
||||
Start the dev server.
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
Open [http://localhost:5173](http://localhost:5173) with your browser to see the result.
|
||||
## Questions / problems / feedback
|
||||
|
||||
If you have feedback, let us know on [Discord](https://discord.gg/utDMjHYg42) or open an issue or PR to fix something that seems wrong.
|
||||
|
||||
## Configuration: sync server
|
||||
|
||||
By default, the example app uses [Jazz Cloud](https://jazz.tools/cloud) (`wss://cloud.jazz.tools`) - so cross-device use, invites and collaboration should just work.
|
||||
|
||||
You can also run a local sync server by running `npx cojson-simple-sync` and adding the query param `?sync=ws://localhost:4200` to the URL of the example app (for example: `http://localhost:5173/?peer=ws://localhost:4200`), or by setting the `sync` parameter of the `<JazzProvider>` provider component in [./src/main.tsx](./src/main.tsx).
|
||||
12
examples/onboarding/index.html
Normal file
12
examples/onboarding/index.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Jazz onboarding example</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
36
examples/onboarding/package.json
Normal file
36
examples/onboarding/package.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "jazz-example-onboarding",
|
||||
"private": true,
|
||||
"version": "0.0.50",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"format-and-lint": "biome check .",
|
||||
"format-and-lint:fix": "biome check . --write",
|
||||
"preview": "vite preview",
|
||||
"test": "playwright test",
|
||||
"test:ui": "playwright test --ui",
|
||||
"sync": "jazz-run sync"
|
||||
},
|
||||
"dependencies": {
|
||||
"jazz-browser-media-images": "workspace:*",
|
||||
"jazz-react": "workspace:*",
|
||||
"jazz-tools": "workspace:*",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.50.1",
|
||||
"@types/react": "^18.3.12",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"@vitejs/plugin-react": "^4.3.3",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"is-ci": "^3.0.1",
|
||||
"jazz-run": "workspace:*",
|
||||
"postcss": "^8.4.27",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "~5.6.2",
|
||||
"vite": "^6.0.11"
|
||||
}
|
||||
}
|
||||
46
examples/onboarding/playwright.config.ts
Normal file
46
examples/onboarding/playwright.config.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { defineConfig, devices } from "@playwright/test";
|
||||
import isCI from "is-ci";
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
export default defineConfig({
|
||||
testDir: "./tests",
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: true,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
forbidOnly: isCI,
|
||||
/* Retry on CI only */
|
||||
retries: isCI ? 2 : 0,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
workers: isCI ? 1 : undefined,
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
reporter: "html",
|
||||
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||
baseURL: "http://localhost:5173/",
|
||||
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: "on-first-retry",
|
||||
permissions: ["clipboard-read", "clipboard-write"],
|
||||
},
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
{
|
||||
name: "chromium",
|
||||
use: { ...devices["Desktop Chrome"] },
|
||||
},
|
||||
],
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
webServer: [
|
||||
{
|
||||
command: "pnpm preview --port 5173",
|
||||
url: "http://localhost:5173/",
|
||||
reuseExistingServer: !isCI,
|
||||
},
|
||||
],
|
||||
});
|
||||
6
examples/onboarding/postcss.config.js
Normal file
6
examples/onboarding/postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
BIN
examples/onboarding/public/jazz-logo-low-res.jpg
Normal file
BIN
examples/onboarding/public/jazz-logo-low-res.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 820 B |
100
examples/onboarding/src/App.tsx
Normal file
100
examples/onboarding/src/App.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
import { Button } from "@/components/Button.tsx";
|
||||
import { EmployeeList } from "@/pages/EmployeeList.tsx";
|
||||
import { EmployeeOnboading } from "@/pages/EmployeeOnboarding.tsx";
|
||||
import { NewEmployee } from "@/pages/NewEmployee.tsx";
|
||||
import { CoEmployee, EmployeeCoList } from "@/schema.ts";
|
||||
import { useAcceptInvite, useAccount, useCoState } from "jazz-react";
|
||||
import { ID } from "jazz-tools";
|
||||
import { useEffect } from "react";
|
||||
import {
|
||||
RouterProvider,
|
||||
createHashRouter,
|
||||
useNavigate,
|
||||
useParams,
|
||||
} from "react-router-dom";
|
||||
|
||||
function ImportEmployee({
|
||||
employeeListCoId,
|
||||
}: { employeeListCoId: ID<EmployeeCoList> }) {
|
||||
const { employeeCoId } = useParams();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const employees = useCoState(EmployeeCoList, employeeListCoId, [{}]);
|
||||
const employee = useCoState(CoEmployee, employeeCoId as ID<CoEmployee>, {});
|
||||
|
||||
useEffect(() => {
|
||||
if (!employee || !employees) return;
|
||||
|
||||
const exists = employees.find((employee) => employeeCoId === employee.id);
|
||||
|
||||
if (!exists) {
|
||||
employees.push(employee);
|
||||
}
|
||||
navigate("/");
|
||||
}, [employee, employees, navigate]);
|
||||
|
||||
return <div>Importing Employee ${employeeCoId} ...</div>;
|
||||
}
|
||||
|
||||
function AcceptInvite() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
useAcceptInvite({
|
||||
invitedObjectSchema: CoEmployee,
|
||||
onAccept: (employeeCoId) => {
|
||||
navigate(`/import/${employeeCoId}`);
|
||||
},
|
||||
});
|
||||
|
||||
return <p>Accepting invite...</p>;
|
||||
}
|
||||
|
||||
function App() {
|
||||
const { me, logOut } = useAccount();
|
||||
const employeeCoListId = me.profile?._refs.employees.id;
|
||||
|
||||
const router = createHashRouter([
|
||||
{
|
||||
path: "/",
|
||||
element: <EmployeeList employeeListCoId={employeeCoListId} />,
|
||||
},
|
||||
{
|
||||
path: "employee/new",
|
||||
element: <NewEmployee employeeListCoId={employeeCoListId} />,
|
||||
},
|
||||
{
|
||||
path: "/employee/:employeeCoId",
|
||||
element: <EmployeeOnboading />,
|
||||
},
|
||||
{
|
||||
path: "/import/:employeeCoId",
|
||||
element: <ImportEmployee employeeListCoId={employeeCoListId} />,
|
||||
},
|
||||
{
|
||||
path: "/invite/*",
|
||||
element: <AcceptInvite />,
|
||||
},
|
||||
]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<header className="flex flex-wrap space-x-8 max-w-screen-lg m-2">
|
||||
<h1 className="text-3xl font-extrabold">
|
||||
Jazz Onboarding Flow example
|
||||
</h1>
|
||||
<Button
|
||||
onClick={() => {
|
||||
window.location.href = "/";
|
||||
logOut();
|
||||
}}
|
||||
text="Log Out"
|
||||
/>
|
||||
</header>
|
||||
<main className="ml-2">
|
||||
{employeeCoListId && <RouterProvider router={router} />}
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
1
examples/onboarding/src/apiKey.ts
Normal file
1
examples/onboarding/src/apiKey.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const apiKey = "onboarding-example-jazz@garden.co";
|
||||
31
examples/onboarding/src/components/Button.tsx
Normal file
31
examples/onboarding/src/components/Button.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
const disabledClasses =
|
||||
"text-white bg-gray-400 dark:bg-gray-500 cursor-not-allowed";
|
||||
const regularClasses =
|
||||
"text-white bg-gradient-to-r from-green-400 via-green-500 to-green-600 hover:bg-gradient-to-br focus:ring-4 focus:outline-none focus:ring-green-300 dark:focus:ring-green-800";
|
||||
|
||||
export function Button({
|
||||
text,
|
||||
onClick,
|
||||
disabled,
|
||||
type = "button",
|
||||
...props
|
||||
}: {
|
||||
text: string;
|
||||
type?: "button" | "submit";
|
||||
onClick?: () => void;
|
||||
disabled?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<button
|
||||
{...props}
|
||||
onClick={onClick}
|
||||
type={type}
|
||||
disabled={disabled}
|
||||
className={`${
|
||||
disabled ? disabledClasses : regularClasses
|
||||
} text-base font-medium rounded-lg text-sm px-5 py-2.5 text-center me-2 mb-2`}
|
||||
>
|
||||
{text}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
19
examples/onboarding/src/components/ButtonLink.tsx
Normal file
19
examples/onboarding/src/components/ButtonLink.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
export function ButtonLink({
|
||||
to,
|
||||
children,
|
||||
}: {
|
||||
to: string;
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<Link
|
||||
className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800"
|
||||
to={to}
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
19
examples/onboarding/src/components/NavLink.tsx
Normal file
19
examples/onboarding/src/components/NavLink.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
export function NavLink({
|
||||
to,
|
||||
children,
|
||||
}: {
|
||||
to: string;
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<Link
|
||||
className="font-medium text-blue-600 dark:text-blue-500 hover:underline"
|
||||
to={to}
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
24
examples/onboarding/src/components/NavigateBack.tsx
Normal file
24
examples/onboarding/src/components/NavigateBack.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Button } from "./Button.tsx";
|
||||
|
||||
export function NavigateBack() {
|
||||
const navigate = useNavigate();
|
||||
const canGoBack = window.history.state.idx !== 0;
|
||||
|
||||
if (!canGoBack) return null;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Button onClick={() => navigate(-1)} text="< Back" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function NavigateButton({ text, to }: { text: string; to: string }) {
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<div>
|
||||
<Button onClick={() => navigate(to)} text={text} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
19
examples/onboarding/src/components/Stack.tsx
Normal file
19
examples/onboarding/src/components/Stack.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import React from "react";
|
||||
|
||||
export function Stack({
|
||||
children,
|
||||
horizontal,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
horizontal?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={`container flex ${
|
||||
horizontal ? "flex-row" : "flex-col"
|
||||
} col ${horizontal ? "space-x-4 flex-wrap" : "space-y-4"} p-4`}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
36
examples/onboarding/src/components/TextInput.tsx
Normal file
36
examples/onboarding/src/components/TextInput.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { ChangeEvent } from "react";
|
||||
|
||||
export function TextInput({
|
||||
id,
|
||||
value,
|
||||
label,
|
||||
onChange,
|
||||
disabled,
|
||||
}: {
|
||||
id: string;
|
||||
label: string;
|
||||
value: string;
|
||||
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
|
||||
disabled?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div>
|
||||
<label
|
||||
htmlFor={id}
|
||||
className="block mb-2 font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
{label}
|
||||
</label>
|
||||
<input
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
type="text"
|
||||
id={id}
|
||||
disabled={disabled}
|
||||
className="disabled:cursor-not-allowed bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
||||
placeholder="John"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
3
examples/onboarding/src/index.css
Normal file
3
examples/onboarding/src/index.css
Normal file
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
31
examples/onboarding/src/main.tsx
Normal file
31
examples/onboarding/src/main.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import App from "@/App.tsx";
|
||||
import "@/index.css";
|
||||
import { HRAccount } from "@/schema.ts";
|
||||
import { JazzProvider } from "jazz-react";
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import { apiKey } from "./apiKey";
|
||||
|
||||
const peer =
|
||||
(new URL(window.location.href).searchParams.get(
|
||||
"peer",
|
||||
) as `ws://${string}`) ?? `wss://cloud.jazz.tools/?key=${apiKey}`;
|
||||
|
||||
declare module "jazz-react" {
|
||||
interface Register {
|
||||
Account: HRAccount;
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||
<React.StrictMode>
|
||||
<JazzProvider
|
||||
AccountSchema={HRAccount}
|
||||
sync={{
|
||||
peer,
|
||||
}}
|
||||
>
|
||||
<App />
|
||||
</JazzProvider>
|
||||
</React.StrictMode>,
|
||||
);
|
||||
50
examples/onboarding/src/pages/EmployeeList.tsx
Normal file
50
examples/onboarding/src/pages/EmployeeList.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import { NavLink } from "@/components/NavLink.tsx";
|
||||
import { NavigateButton } from "@/components/NavigateBack.tsx";
|
||||
import { Stack } from "@/components/Stack.tsx";
|
||||
import { CoEmployee, EmployeeCoList } from "@/schema.ts";
|
||||
import { useCoState } from "jazz-react";
|
||||
import { ID } from "jazz-tools";
|
||||
|
||||
export function EmployeeList({
|
||||
employeeListCoId,
|
||||
}: {
|
||||
employeeListCoId: ID<EmployeeCoList>;
|
||||
}) {
|
||||
const employees = useCoState(EmployeeCoList, employeeListCoId, [{}]);
|
||||
|
||||
if (!employees) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<NavigateButton to="/employee/new" text={"Add New Employee"} />
|
||||
<ul className="max-w-md">
|
||||
{employees.map((employee: CoEmployee) =>
|
||||
employee.deleted ? null : (
|
||||
<li key={employee.id} className="flex flex-row space-x-8 w-full">
|
||||
<span>{employee._owner.myRole()}</span>
|
||||
<span className="w-1/3">
|
||||
<NavLink to={`/employee/${employee.id}`}>
|
||||
{employee.name}
|
||||
</NavLink>
|
||||
</span>
|
||||
{employee.finalStep?.done && <span>✅</span>}
|
||||
{employee._owner.myRole() === "admin" &&
|
||||
!employee.finalStep?.done && (
|
||||
<span
|
||||
onClick={() => {
|
||||
employee.deleted = true;
|
||||
}}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
🗑
|
||||
</span>
|
||||
)}
|
||||
</li>
|
||||
),
|
||||
)}
|
||||
</ul>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
240
examples/onboarding/src/pages/EmployeeOnboarding.tsx
Normal file
240
examples/onboarding/src/pages/EmployeeOnboarding.tsx
Normal file
@@ -0,0 +1,240 @@
|
||||
import { Button } from "@/components/Button.tsx";
|
||||
import { NavigateBack } from "@/components/NavigateBack.tsx";
|
||||
import { Stack } from "@/components/Stack.tsx";
|
||||
import { TextInput } from "@/components/TextInput.tsx";
|
||||
import { createImage } from "jazz-browser-media-images";
|
||||
import { useCoState } from "jazz-react";
|
||||
import { ProgressiveImg, createInviteLink } from "jazz-react";
|
||||
import { CoMap, ID } from "jazz-tools";
|
||||
import { ChangeEvent, ReactNode, useCallback } from "react";
|
||||
import { useParams } from "react-router";
|
||||
import {
|
||||
CoDocUploadStep,
|
||||
CoEmployee,
|
||||
CoFinalStep,
|
||||
CoInitialStep,
|
||||
} from "../schema.ts";
|
||||
|
||||
const Card = ({
|
||||
children,
|
||||
title,
|
||||
isDone,
|
||||
isActive,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
title: string;
|
||||
isDone: boolean;
|
||||
isActive?: boolean;
|
||||
}) => (
|
||||
<div
|
||||
className={`w-full p-4 bg-white border border-gray-200 rounded-lg shadow max-w-md ${
|
||||
isActive ? "border-gray-900 hover:bg-green-50 shadow-xl" : ""
|
||||
}`}
|
||||
>
|
||||
<Stack horizontal={true}>
|
||||
<h5 className="mb-2 text-2xl text-gray-900">{title}</h5>
|
||||
<h6 className="mb-2 text-2xl">
|
||||
{isDone ? "✅" : isActive ? "❓" : "⌛"}
|
||||
</h6>
|
||||
</Stack>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
const InfoCard = ({
|
||||
initialStep,
|
||||
canWrite,
|
||||
}: {
|
||||
initialStep: CoInitialStep;
|
||||
canWrite: boolean;
|
||||
}) => {
|
||||
const isDisabled = !initialStep.isCurrentStep() || !canWrite;
|
||||
|
||||
return (
|
||||
<Card
|
||||
title="Personal Info"
|
||||
isDone={initialStep?.done}
|
||||
isActive={initialStep.isCurrentStep()}
|
||||
>
|
||||
<Stack>
|
||||
<TextInput
|
||||
disabled={isDisabled}
|
||||
id="ssn"
|
||||
label="Social Security Number"
|
||||
value={initialStep.ssn || ""}
|
||||
onChange={({ target: { value } }) => (initialStep.ssn = value)}
|
||||
/>
|
||||
<TextInput
|
||||
disabled={isDisabled}
|
||||
id="address"
|
||||
label="Address"
|
||||
value={initialStep.address || ""}
|
||||
onChange={({ target: { value } }) => (initialStep.address = value)}
|
||||
/>
|
||||
{!initialStep.done && (
|
||||
<Button
|
||||
text={"Upload step >"}
|
||||
disabled={!initialStep.ssn || !initialStep.address || isDisabled}
|
||||
onClick={() => (initialStep.done = true)}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
const UploadCard = ({
|
||||
uploadStep,
|
||||
canWrite,
|
||||
}: {
|
||||
uploadStep: CoDocUploadStep;
|
||||
canWrite: boolean;
|
||||
}) => {
|
||||
const isDisabled = !uploadStep.isCurrentStep() || !canWrite;
|
||||
|
||||
const onImageSelected = useCallback(
|
||||
async (event: ChangeEvent<HTMLInputElement>) => {
|
||||
if (!event.target.files) return;
|
||||
|
||||
const image = await createImage(event.target.files[0], {
|
||||
owner: uploadStep._owner,
|
||||
});
|
||||
|
||||
uploadStep.photo = image;
|
||||
},
|
||||
[uploadStep],
|
||||
);
|
||||
|
||||
return (
|
||||
<Card
|
||||
title="Uploads"
|
||||
isDone={uploadStep?.done}
|
||||
isActive={uploadStep.isCurrentStep()}
|
||||
>
|
||||
<Stack>
|
||||
{uploadStep.photo && (
|
||||
<ProgressiveImg image={uploadStep.photo}>
|
||||
{({ src }) => (
|
||||
<img
|
||||
className="max-h-full max-w-full rounded-l-sm rounded-r-md shadow-lg p-2"
|
||||
src={src}
|
||||
/>
|
||||
)}
|
||||
</ProgressiveImg>
|
||||
)}
|
||||
|
||||
{!uploadStep.done && (
|
||||
<>
|
||||
<input
|
||||
type="file"
|
||||
disabled={isDisabled}
|
||||
onChange={onImageSelected}
|
||||
data-testid="file-upload"
|
||||
/>
|
||||
<Button
|
||||
text={"Confirmation step >"}
|
||||
disabled={isDisabled || !uploadStep.photo}
|
||||
onClick={() => (uploadStep.done = true)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
const ConfirmationCard = ({
|
||||
finalStep,
|
||||
editable,
|
||||
}: {
|
||||
finalStep: CoFinalStep;
|
||||
editable: boolean;
|
||||
}) => {
|
||||
const isDisabled = !finalStep.isCurrentStep() || !editable;
|
||||
return (
|
||||
<Card
|
||||
title="Confirmation by admin"
|
||||
isDone={finalStep?.done}
|
||||
isActive={finalStep.isCurrentStep()}
|
||||
>
|
||||
<Stack>
|
||||
{!finalStep.done && (
|
||||
<Button
|
||||
text="Confirmation by admin"
|
||||
disabled={isDisabled}
|
||||
onClick={() => (finalStep.done = true)}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export function EmployeeOnboading() {
|
||||
const { employeeCoId } = useParams();
|
||||
|
||||
const employee = useCoState(CoEmployee, employeeCoId as ID<CoEmployee>, {});
|
||||
|
||||
const handleInviteLinkCreation = useCallback(
|
||||
(role: "reader" | "writer") => {
|
||||
if (!employee) return;
|
||||
|
||||
const link = createInviteLink(employee, role);
|
||||
navigator.clipboard.writeText(link);
|
||||
alert("Invite link copied to clipboard!");
|
||||
},
|
||||
[employee],
|
||||
);
|
||||
|
||||
const isMeWriter = (step: CoMap): boolean => {
|
||||
return ["writer", "admin"].includes(step._owner.myRole() || "");
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Stack>
|
||||
<Stack horizontal={true}>
|
||||
<NavigateBack />
|
||||
{employee?._owner.myRole() === "admin" && (
|
||||
<Button
|
||||
text={"Invite a co-worker"}
|
||||
onClick={() => handleInviteLinkCreation("writer")}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
<h2 className="mb-2 text-2xl text-gray-900 font-semibold">
|
||||
{employee ? employee.name : "Loading..."}
|
||||
</h2>
|
||||
</Stack>
|
||||
|
||||
{employee && (
|
||||
<Stack>
|
||||
{employee.initialStep ? (
|
||||
<InfoCard
|
||||
initialStep={employee.initialStep}
|
||||
canWrite={isMeWriter(employee.initialStep)}
|
||||
/>
|
||||
) : (
|
||||
<div>Loading...</div>
|
||||
)}
|
||||
{employee.docUploadStep ? (
|
||||
<UploadCard
|
||||
uploadStep={employee.docUploadStep}
|
||||
canWrite={isMeWriter(employee.docUploadStep)}
|
||||
/>
|
||||
) : (
|
||||
<div>Loading...</div>
|
||||
)}
|
||||
{employee.finalStep ? (
|
||||
<ConfirmationCard
|
||||
finalStep={employee.finalStep}
|
||||
editable={isMeWriter(employee.finalStep)}
|
||||
/>
|
||||
) : (
|
||||
<div>Loading...</div>
|
||||
)}
|
||||
</Stack>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
89
examples/onboarding/src/pages/NewEmployee.tsx
Normal file
89
examples/onboarding/src/pages/NewEmployee.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Button } from "@/components/Button.tsx";
|
||||
import { NavigateBack } from "@/components/NavigateBack.tsx";
|
||||
import { Stack } from "@/components/Stack.tsx";
|
||||
import { TextInput } from "@/components/TextInput.tsx";
|
||||
import { useAccount, useCoState } from "jazz-react";
|
||||
import { Group, ID } from "jazz-tools";
|
||||
import { useCallback, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import {
|
||||
CoDocUploadStep,
|
||||
CoEmployee,
|
||||
CoFinalStep,
|
||||
CoInitialStep,
|
||||
EmployeeCoList,
|
||||
} from "../schema.ts";
|
||||
|
||||
export function NewEmployee({
|
||||
employeeListCoId,
|
||||
}: {
|
||||
employeeListCoId: ID<EmployeeCoList>;
|
||||
}) {
|
||||
const navigate = useNavigate();
|
||||
const { me } = useAccount();
|
||||
|
||||
const employees = useCoState(EmployeeCoList, employeeListCoId, [{}]);
|
||||
|
||||
const [employeeName, setEmployeeName] = useState<string>("");
|
||||
|
||||
const createEmployee = useCallback(() => {
|
||||
if (!employees) return;
|
||||
|
||||
const writerGroup = Group.create({ owner: me });
|
||||
const readerGroup = Group.create({ owner: me });
|
||||
readerGroup.addMember("everyone", "reader");
|
||||
|
||||
const initialStep = CoInitialStep.create(
|
||||
{ done: false, type: "initial" },
|
||||
{ owner: writerGroup },
|
||||
);
|
||||
|
||||
const docUploadStep = CoDocUploadStep.create(
|
||||
{ done: false, prevStep: initialStep, type: "upload" },
|
||||
{ owner: writerGroup },
|
||||
);
|
||||
|
||||
const finalStep = CoFinalStep.create(
|
||||
{ done: false, prevStep: docUploadStep, type: "final" },
|
||||
{ owner: readerGroup },
|
||||
);
|
||||
|
||||
const employee = CoEmployee.create(
|
||||
{
|
||||
name: employeeName,
|
||||
initialStep,
|
||||
docUploadStep,
|
||||
finalStep,
|
||||
},
|
||||
{ owner: writerGroup },
|
||||
);
|
||||
|
||||
employees.push(employee);
|
||||
setEmployeeName("");
|
||||
}, [employeeName, employees]);
|
||||
|
||||
return (
|
||||
<div className="w-96">
|
||||
<Stack>
|
||||
<NavigateBack />
|
||||
<form className="grid gap-3">
|
||||
<TextInput
|
||||
label="Employee name"
|
||||
id="employee-name"
|
||||
value={employeeName}
|
||||
onChange={({ target: { value } }) => setEmployeeName(value)}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={!employeeName}
|
||||
onClick={() => {
|
||||
createEmployee();
|
||||
navigate("/");
|
||||
}}
|
||||
text="Create Employee"
|
||||
/>
|
||||
</form>
|
||||
</Stack>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
76
examples/onboarding/src/schema.ts
Normal file
76
examples/onboarding/src/schema.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import {
|
||||
Account,
|
||||
CoList,
|
||||
CoMap,
|
||||
ImageDefinition,
|
||||
Profile,
|
||||
co,
|
||||
} from "jazz-tools";
|
||||
|
||||
type Steps = "initial" | "upload" | "final";
|
||||
|
||||
interface Step {
|
||||
type: Steps;
|
||||
prevStep: ReturnType<typeof co.ref> | undefined;
|
||||
done: boolean;
|
||||
|
||||
isCurrentStep(): boolean;
|
||||
}
|
||||
|
||||
export class CoInitialStep extends CoMap implements Step {
|
||||
type = co.literal("initial");
|
||||
ssn? = co.string;
|
||||
address? = co.string;
|
||||
done = co.boolean;
|
||||
prevStep = co.null;
|
||||
isCurrentStep() {
|
||||
return !this.done;
|
||||
}
|
||||
}
|
||||
|
||||
export class CoDocUploadStep extends CoMap implements Step {
|
||||
type = co.literal("upload");
|
||||
prevStep = co.ref(CoInitialStep);
|
||||
photo = co.ref(ImageDefinition, { optional: true });
|
||||
done = co.boolean;
|
||||
|
||||
isCurrentStep() {
|
||||
return !!(this.prevStep?.done && !this.done);
|
||||
}
|
||||
}
|
||||
|
||||
export class CoFinalStep extends CoMap implements Step {
|
||||
type = co.literal("final");
|
||||
prevStep = co.ref(CoDocUploadStep);
|
||||
done = co.boolean;
|
||||
|
||||
isCurrentStep() {
|
||||
return !!(this.prevStep?.done && !this.done);
|
||||
}
|
||||
}
|
||||
|
||||
export class CoEmployee extends CoMap {
|
||||
name = co.string;
|
||||
deleted? = co.boolean;
|
||||
initialStep = co.ref(CoInitialStep);
|
||||
docUploadStep = co.ref(CoDocUploadStep);
|
||||
finalStep = co.ref(CoFinalStep);
|
||||
}
|
||||
|
||||
export class EmployeeCoList extends CoList.Of(co.ref(CoEmployee)) {}
|
||||
|
||||
export class HRProfile extends Profile {
|
||||
employees = co.ref(EmployeeCoList);
|
||||
}
|
||||
|
||||
export class HRAccount extends Account {
|
||||
profile = co.ref(HRProfile)!;
|
||||
|
||||
migrate() {
|
||||
if (!this.profile._refs.employees) {
|
||||
this.profile.employees = EmployeeCoList.create([], {
|
||||
owner: this.profile._owner,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
1
examples/onboarding/src/vite-env.d.ts
vendored
Normal file
1
examples/onboarding/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
11
examples/onboarding/tailwind.config.ts
Normal file
11
examples/onboarding/tailwind.config.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { Config } from "tailwindcss";
|
||||
|
||||
const config: Config = {
|
||||
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
|
||||
export default config;
|
||||
96
examples/onboarding/tests/onboardingFlow.spec.ts
Normal file
96
examples/onboarding/tests/onboardingFlow.spec.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import {
|
||||
Browser,
|
||||
BrowserContext,
|
||||
Page,
|
||||
chromium,
|
||||
expect,
|
||||
test,
|
||||
} from "@playwright/test";
|
||||
import { EmployeeOnboardingPage } from "./pages/EmployeeOnboardingPage";
|
||||
import { HomePage } from "./pages/HomePage";
|
||||
import { LoginPage } from "./pages/LoginPage";
|
||||
|
||||
async function scrollToBottom(page: Page) {
|
||||
await page.evaluate(() => {
|
||||
window.scrollTo(0, document.body.scrollHeight);
|
||||
});
|
||||
}
|
||||
|
||||
test.describe("Admin onboarding flow", () => {
|
||||
let browser: Browser;
|
||||
let adminContext: BrowserContext;
|
||||
let writerContext: BrowserContext;
|
||||
|
||||
test.beforeAll(async () => {
|
||||
browser = await chromium.launch();
|
||||
adminContext = await browser.newContext();
|
||||
writerContext = await browser.newContext();
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await adminContext.close();
|
||||
await writerContext.close();
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
test("Create and delete flow", async () => {
|
||||
const adminPage = await adminContext.newPage();
|
||||
await adminPage.goto("/");
|
||||
const adminHomePage = new HomePage(adminPage);
|
||||
await adminHomePage.createEmployee("Paul");
|
||||
await adminHomePage.createEmployee("Sean");
|
||||
await adminHomePage.expectEmployee(["Sean", "admin"]);
|
||||
await adminHomePage.expectEmployee(["Paul", "admin"]);
|
||||
await adminHomePage.deleteEmployee("Sean");
|
||||
await adminHomePage.expectEmployeeDeleted("Sean");
|
||||
|
||||
await adminPage.close();
|
||||
});
|
||||
|
||||
test("Onboard flow", async () => {
|
||||
const adminPage = await adminContext.newPage();
|
||||
const writerPage = await writerContext.newPage();
|
||||
|
||||
await adminPage.goto("/");
|
||||
await writerPage.goto("/");
|
||||
|
||||
const adminHomePage = new HomePage(adminPage);
|
||||
await adminHomePage.createEmployee("Paul");
|
||||
await adminHomePage.expectEmployee(["Paul", "admin"]);
|
||||
await adminHomePage.navigateToEmployeeOnboardingPage("Paul");
|
||||
const adminOnboardingPage = new EmployeeOnboardingPage(adminPage);
|
||||
|
||||
// create invitation
|
||||
const invitation = await adminOnboardingPage.getShareLink();
|
||||
|
||||
// Wait for the invitation to be synced
|
||||
await writerPage.waitForTimeout(3000);
|
||||
|
||||
//fill out by invitee (writer)
|
||||
await writerPage.goto(invitation);
|
||||
|
||||
const writerHomePage = new HomePage(writerPage);
|
||||
await writerHomePage.expectEmployee(["Paul", "write"]);
|
||||
await writerHomePage.navigateToEmployeeOnboardingPage("Paul");
|
||||
const writerOnboardingPage = new EmployeeOnboardingPage(writerPage);
|
||||
await writerOnboardingPage.expectEmployeeName("Paul");
|
||||
await writerOnboardingPage.fillPersonalDetailsCardAndSave(
|
||||
"123-45-6789",
|
||||
"123 Elm Street",
|
||||
);
|
||||
await writerOnboardingPage.fillUploadCardAndSave(
|
||||
"./public/jazz-logo-low-res.jpg",
|
||||
);
|
||||
|
||||
// invitee cannot confirm the onboarding completion
|
||||
expect(
|
||||
writerOnboardingPage.finalConfirmationButton.isDisabled(),
|
||||
).toBeTruthy();
|
||||
|
||||
// final confirmation step by admin
|
||||
await scrollToBottom(adminPage);
|
||||
await adminOnboardingPage.finalConfirmationButton.click();
|
||||
await adminOnboardingPage.backButton.click();
|
||||
await adminHomePage.expectOnboardingCompleteForEmployee("Paul");
|
||||
});
|
||||
});
|
||||
92
examples/onboarding/tests/pages/EmployeeOnboardingPage.ts
Normal file
92
examples/onboarding/tests/pages/EmployeeOnboardingPage.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { Locator, Page, expect } from "@playwright/test";
|
||||
|
||||
export class EmployeeOnboardingPage {
|
||||
readonly page: Page;
|
||||
readonly shareButton: Locator;
|
||||
readonly backButton: Locator;
|
||||
readonly logoutButton: Locator;
|
||||
readonly finalConfirmationButton: Locator;
|
||||
readonly fileInput: Locator;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
this.shareButton = page.getByRole("button", {
|
||||
name: /invite a co-worker/i,
|
||||
});
|
||||
this.backButton = page.getByRole("button", {
|
||||
name: /back/i,
|
||||
});
|
||||
this.logoutButton = page.getByRole("button", {
|
||||
name: /log out/i,
|
||||
});
|
||||
this.finalConfirmationButton = this.page.getByRole("button", {
|
||||
name: /confirmation by admin/i,
|
||||
});
|
||||
|
||||
this.fileInput = page.getByTestId("file-upload");
|
||||
}
|
||||
|
||||
async uploadFile(value: string) {
|
||||
// Start waiting for file chooser before clicking. Note no await.
|
||||
const fileChooserPromise = this.page.waitForEvent("filechooser");
|
||||
|
||||
await this.fileInput.click();
|
||||
|
||||
const fileChooser = await fileChooserPromise;
|
||||
await fileChooser.setFiles(value);
|
||||
}
|
||||
|
||||
async expectEmployeeName(name: string) {
|
||||
await expect(
|
||||
this.page.getByRole("heading", {
|
||||
name: name,
|
||||
}),
|
||||
).toBeVisible();
|
||||
}
|
||||
|
||||
async fillPersonalDetailsCardAndSave(ssn: string, address: string) {
|
||||
const nextStepButton = this.page.getByRole("button", {
|
||||
name: /upload step >/i,
|
||||
});
|
||||
await expect(nextStepButton).toBeDisabled();
|
||||
|
||||
const ssnInput = this.page.getByLabel(/Social Security Number/i);
|
||||
await ssnInput.fill(ssn);
|
||||
|
||||
const addressInput = this.page.getByLabel(/Address/i);
|
||||
await addressInput.fill(address);
|
||||
|
||||
// save and hide the button
|
||||
await expect(nextStepButton).toBeEnabled();
|
||||
await nextStepButton.click();
|
||||
await expect(nextStepButton).not.toBeVisible();
|
||||
}
|
||||
|
||||
async fillUploadCardAndSave(file: string) {
|
||||
const nextStepButton = this.page.getByRole("button", {
|
||||
name: /confirmation step >/i,
|
||||
});
|
||||
await expect(nextStepButton).toBeDisabled();
|
||||
|
||||
await this.uploadFile(file);
|
||||
await expect(nextStepButton).toBeEnabled();
|
||||
await nextStepButton.click();
|
||||
await expect(nextStepButton).not.toBeVisible();
|
||||
}
|
||||
|
||||
async getShareLink() {
|
||||
await this.shareButton.click();
|
||||
|
||||
const inviteUrl = await this.page.evaluate(() =>
|
||||
navigator.clipboard.readText(),
|
||||
);
|
||||
|
||||
expect(inviteUrl).toBeTruthy();
|
||||
|
||||
return inviteUrl;
|
||||
}
|
||||
|
||||
async logout() {
|
||||
await this.logoutButton.click();
|
||||
}
|
||||
}
|
||||
66
examples/onboarding/tests/pages/HomePage.ts
Normal file
66
examples/onboarding/tests/pages/HomePage.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { Locator, Page, expect } from "@playwright/test";
|
||||
import { NewEmployeePage } from "./NewEmployeePage";
|
||||
|
||||
export class HomePage {
|
||||
readonly page: Page;
|
||||
readonly newEmployeeLink: Locator;
|
||||
readonly logoutButton: Locator;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
this.newEmployeeLink = page.getByRole("button", {
|
||||
name: "Add New Employee",
|
||||
});
|
||||
this.logoutButton = page.getByRole("button", {
|
||||
name: "Log Out",
|
||||
});
|
||||
}
|
||||
|
||||
async expectEmployee([name, role]: [string, string]) {
|
||||
const liElement = this.page.locator(
|
||||
`li:has-text("${name}"):has-text("${role}")`,
|
||||
);
|
||||
await expect(liElement).toBeVisible();
|
||||
}
|
||||
|
||||
async deleteEmployee(name: string) {
|
||||
const liElement = this.page.locator(`li:has-text("${name}")`);
|
||||
const deleteIcon = liElement.locator('span:has-text("🗑")');
|
||||
await deleteIcon.click();
|
||||
}
|
||||
|
||||
async expectOnboardingCompleteForEmployee(name: string) {
|
||||
const liElement = this.page.locator(`li:has-text("${name}")`);
|
||||
const completionIcon = liElement.locator('span:has-text("✅")');
|
||||
await expect(completionIcon).toBeVisible();
|
||||
}
|
||||
|
||||
async expectEmployeeDeleted(name: string) {
|
||||
const liElement = this.page.locator(`li:has-text("${name}")`);
|
||||
await expect(liElement).not.toBeVisible();
|
||||
}
|
||||
|
||||
async navigateToEmployeeOnboardingPage(name: string) {
|
||||
await this.page
|
||||
.getByRole("link", {
|
||||
name,
|
||||
})
|
||||
.click();
|
||||
}
|
||||
|
||||
async navigateToNewEmployee() {
|
||||
await this.newEmployeeLink.click();
|
||||
}
|
||||
|
||||
async createEmployee(name: string) {
|
||||
await this.navigateToNewEmployee();
|
||||
const newEmployeePage = new NewEmployeePage(this.page);
|
||||
|
||||
await newEmployeePage.fillEmployeeName(name);
|
||||
await newEmployeePage.submit();
|
||||
}
|
||||
|
||||
async logout() {
|
||||
await this.logoutButton.click();
|
||||
}
|
||||
}
|
||||
40
examples/onboarding/tests/pages/LoginPage.ts
Normal file
40
examples/onboarding/tests/pages/LoginPage.ts
Normal 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(url: string) {
|
||||
await this.page.goto(url);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
24
examples/onboarding/tests/pages/NewEmployeePage.ts
Normal file
24
examples/onboarding/tests/pages/NewEmployeePage.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { Locator, Page } from "@playwright/test";
|
||||
|
||||
export class NewEmployeePage {
|
||||
readonly page: Page;
|
||||
readonly employeeNameInput: Locator;
|
||||
readonly submitButton: Locator;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
this.employeeNameInput = page.getByLabel(/employee name/i);
|
||||
this.submitButton = page.getByRole("button", {
|
||||
name: /create employee/i,
|
||||
});
|
||||
}
|
||||
|
||||
async fillEmployeeName(value: string) {
|
||||
await this.employeeNameInput.clear();
|
||||
await this.employeeNameInput.fill(value);
|
||||
}
|
||||
|
||||
async submit() {
|
||||
await this.submitButton.click();
|
||||
}
|
||||
}
|
||||
27
examples/onboarding/tsconfig.json
Normal file
27
examples/onboarding/tsconfig.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2023", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
11
examples/onboarding/tsconfig.node.json
Normal file
11
examples/onboarding/tsconfig.node.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
17
examples/onboarding/vite.config.ts
Normal file
17
examples/onboarding/vite.config.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import path from "path";
|
||||
import react from "@vitejs/plugin-react-swc";
|
||||
import { defineConfig } from "vite";
|
||||
import topLevelAwait from "vite-plugin-top-level-await";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react(), topLevelAwait()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
minify: false,
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
// vite.config.ts
|
||||
import path from "path";
|
||||
import react from "file:///Users/brad/dev/jazz/node_modules/@vitejs/plugin-react-swc/index.mjs";
|
||||
import topLevelAwait from "file:///Users/brad/dev/jazz/node_modules/vite-plugin-top-level-await/exports/import.mjs";
|
||||
import { defineConfig } from "file:///Users/brad/dev/jazz/node_modules/vite/dist/node/index.js";
|
||||
var __vite_injected_original_dirname =
|
||||
"/Users/brad/dev/jazz/examples/onboarding";
|
||||
var vite_config_default = defineConfig({
|
||||
plugins: [react(), topLevelAwait()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__vite_injected_original_dirname, "./src"),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
minify: false,
|
||||
},
|
||||
});
|
||||
export { vite_config_default as default };
|
||||
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvVXNlcnMvYnJhZC9kZXYvamF6ei9leGFtcGxlcy9vbmJvYXJkaW5nXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ZpbGVuYW1lID0gXCIvVXNlcnMvYnJhZC9kZXYvamF6ei9leGFtcGxlcy9vbmJvYXJkaW5nL3ZpdGUuY29uZmlnLnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9Vc2Vycy9icmFkL2Rldi9qYXp6L2V4YW1wbGVzL29uYm9hcmRpbmcvdml0ZS5jb25maWcudHNcIjtpbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHJlYWN0IGZyb20gXCJAdml0ZWpzL3BsdWdpbi1yZWFjdC1zd2NcIjtcbmltcG9ydCB7IGRlZmluZUNvbmZpZyB9IGZyb20gXCJ2aXRlXCI7XG5pbXBvcnQgdG9wTGV2ZWxBd2FpdCBmcm9tIFwidml0ZS1wbHVnaW4tdG9wLWxldmVsLWF3YWl0XCI7XG5cbi8vIGh0dHBzOi8vdml0ZWpzLmRldi9jb25maWcvXG5leHBvcnQgZGVmYXVsdCBkZWZpbmVDb25maWcoe1xuICBwbHVnaW5zOiBbcmVhY3QoKSwgdG9wTGV2ZWxBd2FpdCgpXSxcbiAgcmVzb2x2ZToge1xuICAgIGFsaWFzOiB7XG4gICAgICBcIkBcIjogcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgXCIuL3NyY1wiKSxcbiAgICB9LFxuICB9LFxuICBidWlsZDoge1xuICAgIG1pbmlmeTogZmFsc2UsXG4gIH0sXG59KTtcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBMFMsT0FBTyxVQUFVO0FBQzNULE9BQU8sV0FBVztBQUNsQixTQUFTLG9CQUFvQjtBQUM3QixPQUFPLG1CQUFtQjtBQUgxQixJQUFNLG1DQUFtQztBQU16QyxJQUFPLHNCQUFRLGFBQWE7QUFBQSxFQUMxQixTQUFTLENBQUMsTUFBTSxHQUFHLGNBQWMsQ0FBQztBQUFBLEVBQ2xDLFNBQVM7QUFBQSxJQUNQLE9BQU87QUFBQSxNQUNMLEtBQUssS0FBSyxRQUFRLGtDQUFXLE9BQU87QUFBQSxJQUN0QztBQUFBLEVBQ0Y7QUFBQSxFQUNBLE9BQU87QUFBQSxJQUNMLFFBQVE7QUFBQSxFQUNWO0FBQ0YsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K
|
||||
@@ -1,45 +1,5 @@
|
||||
# organization
|
||||
|
||||
## 0.0.47
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.10.9
|
||||
|
||||
## 0.0.46
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2fb6428]
|
||||
- jazz-tools@0.10.8
|
||||
- jazz-react@0.10.8
|
||||
|
||||
## 0.0.45
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-react@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
|
||||
## 0.0.44
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1d71ca1]
|
||||
- Updated dependencies [ada802b]
|
||||
- jazz-react@0.10.6
|
||||
- jazz-tools@0.10.6
|
||||
|
||||
## 0.0.43
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [59ff77e]
|
||||
- jazz-tools@0.10.5
|
||||
- jazz-react@0.10.5
|
||||
|
||||
## 0.0.42
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "organization",
|
||||
"private": true,
|
||||
"version": "0.0.47",
|
||||
"version": "0.0.42",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -5,11 +5,11 @@ import { Organization } from "./schema.ts";
|
||||
|
||||
export function AcceptInvitePage() {
|
||||
const navigate = useNavigate();
|
||||
const { me } = useAccount({ resolve: { root: { organizations: true } } });
|
||||
const { me } = useAccount({ root: { organizations: [] } });
|
||||
|
||||
const onAccept = (organizationId: ID<Organization>) => {
|
||||
if (me?.root?.organizations) {
|
||||
Organization.load(organizationId).then((organization) => {
|
||||
Organization.load(organizationId, me, []).then((organization) => {
|
||||
if (organization) {
|
||||
// avoid duplicates
|
||||
const ids = me.root.organizations.map(
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Heading } from "./components/Heading.tsx";
|
||||
|
||||
export function HomePage() {
|
||||
const { me } = useAccount({
|
||||
resolve: { root: { organizations: true } },
|
||||
root: { organizations: [{}] },
|
||||
});
|
||||
|
||||
if (!me?.root.organizations) return;
|
||||
|
||||
@@ -3,7 +3,7 @@ import { UserIcon } from "lucide-react";
|
||||
|
||||
export function Layout({ children }: { children: React.ReactNode }) {
|
||||
const { me, logOut } = useAccount({
|
||||
resolve: { root: { draftOrganization: true } },
|
||||
root: { draftOrganization: {} },
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -13,7 +13,7 @@ export function OrganizationPage() {
|
||||
.organizationId;
|
||||
|
||||
const organization = useCoState(Organization, paramOrganizationId, {
|
||||
resolve: { projects: true },
|
||||
projects: [],
|
||||
});
|
||||
|
||||
if (!organization) return <p>Loading organization...</p>;
|
||||
|
||||
@@ -8,7 +8,7 @@ import { OrganizationForm } from "./OrganizationForm.tsx";
|
||||
|
||||
export function CreateOrganization() {
|
||||
const { me } = useAccount({
|
||||
resolve: { root: { draftOrganization: true, organizations: true } },
|
||||
root: { draftOrganization: {}, organizations: [] },
|
||||
});
|
||||
const [errors, setErrors] = useState<string[]>([]);
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -23,9 +23,7 @@ function Member({
|
||||
accountId,
|
||||
role,
|
||||
}: { accountId: ID<Account>; role?: string }) {
|
||||
const account = useCoState(Account, accountId, {
|
||||
resolve: { profile: true },
|
||||
});
|
||||
const account = useCoState(Account, accountId, { profile: {} });
|
||||
|
||||
if (!account?.profile) return;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user