From 9ece454e0d2968f51834efee7aa204a8d8c2f66d Mon Sep 17 00:00:00 2001 From: Daniel Steigerwald Date: Tue, 5 Dec 2023 00:07:27 +0100 Subject: [PATCH] Update Next.js example --- examples/nextjs/app/page.tsx | 83 +++++++++++++++++++++--------------- examples/nextjs/package.json | 22 +++++----- 2 files changed, 59 insertions(+), 46 deletions(-) diff --git a/examples/nextjs/app/page.tsx b/examples/nextjs/app/page.tsx index b38a44c60..0a15fa876 100644 --- a/examples/nextjs/app/page.tsx +++ b/examples/nextjs/app/page.tsx @@ -2,7 +2,22 @@ import { TreeFormatter } from "@effect/schema"; import * as S from "@effect/schema/Schema"; -import * as Evolu from "@evolu/react"; +import { + EvoluProvider, + NonEmptyString1000, + SqliteBoolean, + String, + canUseDom, + cast, + createEvolu, + id, + jsonArrayFrom, + parseMnemonic, + useEvolu, + useEvoluError, + useOwner, + useQuery, +} from "@evolu/react"; import { Effect, Exit } from "effect"; import { ChangeEvent, @@ -14,23 +29,23 @@ import { useState, } from "react"; -const TodoId = Evolu.id("Todo"); +const TodoId = id("Todo"); type TodoId = S.Schema.To; -const TodoCategoryId = Evolu.id("TodoCategory"); +const TodoCategoryId = id("TodoCategory"); type TodoCategoryId = S.Schema.To; -const NonEmptyString50 = Evolu.String.pipe( +const NonEmptyString50 = String.pipe( S.minLength(1), S.maxLength(50), - S.brand("NonEmptyString50"), + S.brand("NonEmptyString50") ); type NonEmptyString50 = S.Schema.To; const TodoTable = S.struct({ id: TodoId, - title: Evolu.NonEmptyString1000, - isCompleted: S.nullable(Evolu.SqliteBoolean), + title: NonEmptyString1000, + isCompleted: S.nullable(SqliteBoolean), categoryId: S.nullable(TodoCategoryId), }); type TodoTable = S.Schema.To; @@ -49,18 +64,16 @@ const Database = S.struct({ todo: TodoTable, todoCategory: TodoCategoryTable, }); +type Database = S.Schema.To; -const evolu = Evolu.create(Database); - -// React Hooks -const { useEvolu, useEvoluError, useQuery, useOwner } = evolu; +const evolu = createEvolu(Database); const createFixtures = (): Promise => Promise.all( evolu.loadQueries([ evolu.createQuery((db) => db.selectFrom("todo").selectAll()), evolu.createQuery((db) => db.selectFrom("todoCategory").selectAll()), - ]), + ]) ).then(([todos, categories]) => { if (todos.row || categories.row) return; @@ -69,16 +82,16 @@ const createFixtures = (): Promise => }); evolu.create("todo", { - title: S.parseSync(Evolu.NonEmptyString1000)("Try React Suspense"), + title: S.parseSync(NonEmptyString1000)("Try React Suspense"), categoryId: notUrgentCategoryId, }); }); const isRestoringOwner = (isRestoringOwner?: boolean): boolean => { - if (!Evolu.canUseDom) return false; + if (!canUseDom) return false; const key = 'evolu:isRestoringOwner"'; if (isRestoringOwner != null) - localStorage.setItem(key, String(isRestoringOwner)); + localStorage.setItem(key, isRestoringOwner.toString()); return localStorage.getItem(key) === "true"; }; @@ -95,7 +108,7 @@ const NextJsExample = memo(function NextJsExample() { }); return ( - <> +

@@ -116,7 +129,7 @@ const NextJsExample = memo(function NextJsExample() {

- + ); }); @@ -144,29 +157,29 @@ const todosWithCategories = evolu.createQuery((db) => db .selectFrom("todo") .select(["id", "title", "isCompleted", "categoryId"]) - .where("isDeleted", "is not", Evolu.cast(true)) + .where("isDeleted", "is not", cast(true)) // Filter null value and ensure non-null type. Evolu will provide a helper. .where("title", "is not", null) - .$narrowType<{ title: Evolu.NonEmptyString1000 }>() + .$narrowType<{ title: NonEmptyString1000 }>() .orderBy("createdAt") // https://kysely.dev/docs/recipes/relations .select((eb) => [ - Evolu.jsonArrayFrom( + jsonArrayFrom( eb .selectFrom("todoCategory") .select(["todoCategory.id", "todoCategory.name"]) - .where("isDeleted", "is not", Evolu.cast(true)) - .orderBy("createdAt"), + .where("isDeleted", "is not", cast(true)) + .orderBy("createdAt") ).as("categories"), - ]), + ]) ); const Todos: FC = () => { - const { create } = useEvolu(); const { rows } = useQuery(todosWithCategories); + const { create } = useEvolu(); const handleAddTodoClick = (): void => { - prompt(Evolu.NonEmptyString1000, "What needs to be done?", (title) => { + prompt(NonEmptyString1000, "What needs to be done?", (title) => { create("todo", { title }); }); }; @@ -190,14 +203,14 @@ const TodoItem = memo<{ }>(function TodoItem({ row: { id, title, isCompleted, categoryId, categories }, }) { - const { update } = useEvolu(); + const { update } = useEvolu(); const handleToggleCompletedClick = (): void => { update("todo", { id, isCompleted: !isCompleted }); }; const handleRenameClick = (): void => { - prompt(Evolu.NonEmptyString1000, "New Name", (title) => { + prompt(NonEmptyString1000, "New Name", (title) => { update("todo", { id, title }); }); }; @@ -270,15 +283,15 @@ const todoCategories = evolu.createQuery((db) => db .selectFrom("todoCategory") .select(["id", "name", "json"]) - .where("isDeleted", "is not", Evolu.cast(true)) + .where("isDeleted", "is not", cast(true)) // Filter null value and ensure non-null type. Evolu will provide a helper. .where("name", "is not", null) .$narrowType<{ name: NonEmptyString50 }>() - .orderBy("createdAt"), + .orderBy("createdAt") ); const TodoCategories: FC = () => { - const { create } = useEvolu(); + const { create } = useEvolu(); const { rows } = useQuery(todoCategories); // Evolu automatically parses JSONs into typed objects. @@ -308,7 +321,7 @@ const TodoCategories: FC = () => { const TodoCategoryItem = memo<{ row: Pick; }>(function TodoItem({ row: { id, name } }) { - const { update } = useEvolu(); + const { update } = useEvolu(); const handleRenameClick = (): void => { prompt(NonEmptyString50, "Category Name", (name) => { @@ -337,8 +350,8 @@ const OwnerActions: FC = () => { const [showMnemonic, setShowMnemonic] = useState(false); const handleRestoreOwnerClick = (): void => { - prompt(Evolu.NonEmptyString1000, "Your Mnemonic", (mnemonic) => { - Evolu.parseMnemonic(mnemonic) + prompt(NonEmptyString1000, "Your Mnemonic", (mnemonic) => { + parseMnemonic(mnemonic) .pipe(Effect.runPromiseExit) .then( Exit.match({ @@ -349,7 +362,7 @@ const OwnerActions: FC = () => { isRestoringOwner(true); evolu.restoreOwner(mnemonic); }, - }), + }) ); }); }; @@ -404,7 +417,7 @@ const Button: FC<{ const prompt = ( schema: S.Schema, message: string, - onSuccess: (value: To) => void, + onSuccess: (value: To) => void ): void => { const value = window.prompt(message); if (value == null) return; // on cancel diff --git a/examples/nextjs/package.json b/examples/nextjs/package.json index 96babf96b..fee19a17f 100644 --- a/examples/nextjs/package.json +++ b/examples/nextjs/package.json @@ -9,20 +9,20 @@ "lint": "next lint" }, "dependencies": { - "@evolu/react": "^2.0.7", + "@evolu/react": "^3.0.0", "next": "14.0.3", - "react": "^18", - "react-dom": "^18" + "react": "^18.2.0", + "react-dom": "^18.2.0" }, "devDependencies": { - "@types/node": "^20", - "@types/react": "^18", - "@types/react-dom": "^18", - "autoprefixer": "^10.0.1", - "eslint": "^8", + "@types/node": "^20.10.3", + "@types/react": "^18.2.42", + "@types/react-dom": "^18.2.17", + "autoprefixer": "^10.4.16", + "eslint": "^8.55.0", "eslint-config-next": "14.0.3", - "postcss": "^8", - "tailwindcss": "^3.3.0", - "typescript": "^5" + "postcss": "^8.4.32", + "tailwindcss": "^3.3.6", + "typescript": "^5.3.2" } }