From a274a29448dda72402d3be240decf2d8214d7b38 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 5 Apr 2024 16:40:50 -0400 Subject: [PATCH 1/4] react-native quick start added --- src/lib/components/FooterNav.svelte | 10 +- src/routes/docs/quick-starts/+page.svelte | 6 + .../quick-starts/react-native/+page.markdoc | 225 ++++++++++++++++++ 3 files changed, 238 insertions(+), 3 deletions(-) create mode 100644 src/routes/docs/quick-starts/react-native/+page.markdoc diff --git a/src/lib/components/FooterNav.svelte b/src/lib/components/FooterNav.svelte index c171bad3e8..c7eee45146 100644 --- a/src/lib/components/FooterNav.svelte +++ b/src/lib/components/FooterNav.svelte @@ -15,14 +15,18 @@ const links: Record = { 'Quick starts': [ - { label: 'Flutter', href: '/docs/quick-starts/flutter' }, + { label: 'Web', href: '/docs/quick-starts/web' }, { label: 'Next.js', href: '/docs/quick-starts/nextjs' }, + { label: 'React', href: '/docs/quick-starts/react' }, { label: 'Vue.js', href: '/docs/quick-starts/vue' }, + { label: 'Nuxt', href: '/docs/quick-starts/nuxt' }, { label: 'SvelteKit', href: '/docs/quick-starts/sveltekit' }, + { label: 'Refine', href: '/docs/quick-starts/refine' }, + { label: 'Angular', href: '/docs/quick-starts/angular' }, + { label: 'React Native', href: '/docs/quick-starts/react-native' }, + { label: 'Flutter', href: '/docs/quick-starts/flutter' }, { label: 'Apple', href: '/docs/quick-starts/apple' }, { label: 'Android', href: '/docs/quick-starts/android' }, - { label: 'Nuxt', href: '/docs/quick-starts/nuxt' }, - { label: 'Angular', href: '/docs/quick-starts/angular' }, { label: 'Qwik', href: '/docs/quick-starts/qwik' }, { label: 'Astro', href: '/docs/quick-starts/astro' } ], diff --git a/src/routes/docs/quick-starts/+page.svelte b/src/routes/docs/quick-starts/+page.svelte index a29a9b9e6f..e694ed2933 100644 --- a/src/routes/docs/quick-starts/+page.svelte +++ b/src/routes/docs/quick-starts/+page.svelte @@ -72,6 +72,12 @@ { title: 'Mobile and native', quickStarts: [ + { + title: 'React Native', + icon: 'icon-react-native', + image: '/images/blog/placeholder.png', + href: 'react-native' + }, { title: 'Flutter', icon: 'icon-flutter', diff --git a/src/routes/docs/quick-starts/react-native/+page.markdoc b/src/routes/docs/quick-starts/react-native/+page.markdoc new file mode 100644 index 0000000000..674add05b6 --- /dev/null +++ b/src/routes/docs/quick-starts/react-native/+page.markdoc @@ -0,0 +1,225 @@ +--- +layout: article +title: Start with React Native +description: Build React Native apps on iOS, Android, and other native platforms with Appwrite and learn how to use our powerful backend to add authentication, user management, file storage, and more. +difficulty: beginner +readtime: 10 +back: /docs/quick-starts +--- + +Learn how to setup your first React Native project powered by Appwrite. +The React Native SDK is still in `beta`. Proceed with caution if you plan to use this SDK in production. + +{% info title="React for web" %} +Looking to start with React for web? +Follow the [React quickstart](/docs/quick-starts/react) and [React tutorial](/docs/tutorials/react/step-1) flows. +{% /info %} + +{% section #step-1 step=1 title="Create React Native project" %} +Create a React Native project using [npx](https://www.npmjs.com/package/npx). + +```sh +npx create-expo-app my-app +cd my-app +``` +{% /section %} + +{% section #step-2 step=2 title="Create project" %} +Head to the [Appwrite Console](https://cloud.appwrite.io/console). + +{% only_dark %} +![Create project screen](/images/docs/quick-starts/dark/create-project.png) +{% /only_dark %} + +{% only_light %} +![Create project screen](/images/docs/quick-starts/create-project.png) +{% /only_light %} + +If this is your first time using Appwrite, create an account and create your first project. + +Then, under **Add a platform**, add a **Android app** or a **Apple app**. + +{% tabs %} +{% tabsitem #ios title="iOS" %} +Add your app **name** and **Bundle ID**. You can find your **Bundle Identifier** in the **General** tab for your app's primary target in XCode. + +{% only_dark %} +![Add a platform](/images/docs/quick-starts/dark/add-platform.png) +{% /only_dark %} + +{% only_light %} +![Add a platform](/images/docs/quick-starts/add-platform.png) +{% /only_light %} +{% /tabsitem %} + +{% tabsitem #android title="Android" %} +Add your app's **name** and **package name**, Your package name is generally the `applicationId` in your app-level [build.gradle](https://github.com/appwrite/playground-for-flutter/blob/master/android/app/build.gradle#L41) file. + +{% arrow_link + href="https://developer.android.com/build/configure-app-module" %} +Learn more about Android app module +{% /arrow_link %} +{% /tabsitem %} +{% /tabs %} + +You can skip optional steps. +{% /section %} + +{% section #step-3 step=3 title="Install Appwrite" %} +Install the Appwrite SDK for React Native and required dependencies. + +```sh +npx expo install react-native-appwrite react-native-url-polyfill +``` +{% /section %} + +{% section #step-4 step=4 title="Implement Appwrite" %} +Find your project's ID in the **Settings** page. + +{% only_dark %} +![Project settings screen](/images/docs/quick-starts/dark/project-id.png) +{% /only_dark %} + +{% only_light %} +![Project settings screen](/images/docs/quick-starts/project-id.png) +{% /only_light %} + +Open `App.js` and add the following code to it, replace `` with your project ID and `` with your application id or package name. + +This imports and initializes Appwrite and defines some basic authentication methods. + +```ts +import { StatusBar } from 'expo-status-bar'; +import { StyleSheet, Text, View, TextInput, TouchableOpacity } from 'react-native'; +import { Client, Account, ID } from 'react-native-appwrite'; +import React, { useState } from 'react'; + +let client; +let account; + +client = new Client(); +client + .setEndpoint('https://cloud.appwrite.io/v1') + .setProject('sisyphus') + .setPlatform('com.example.my-app'); + +account = new Account(client); +export default function App() { + const [loggedInUser, setLoggedInUser] = useState(null); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [name, setName] = useState(''); + + async function login(email, password) { + await account.createEmailSession(email, password); + setLoggedInUser(await account.get()); + } + + async function register(email, password, name) { + await account.create(ID.unique(), email, password, name); + await login(email, password); + setLoggedInUser(await account.get()); + } + return ( + // ... Implement your UI here + ); +} + +const styles = StyleSheet.create({ + // ... define some tyles +}); + +``` +{% /section %} + +{% section #step-5 step=5 title="Create a login form" %} +With `Client` and `Account` service initialized, you can now use them to make your first requests to Appwrite. + +Add the following components to your `App.js` file to create a simple login form. + +```ts + + + {loggedInUser ? `Logged in as ${loggedInUser.name}` : 'Not logged in'} + + + setEmail(text)} + /> + setPassword(text)} + secureTextEntry + /> + setName(text)} + /> + + login(email, password)} + > + Login + + + register(email, password, name)} + > + Register + + + { + await account.deleteSession('current'); + setLoggedInUser(null); + }} + > + Logout + + + +``` + +You can also add some simple styling to your app by adding the following styles to your `App.js` file. + +```ts +const styles = StyleSheet.create({ + root: { + marginTop: 40, + marginBottom: 40 + }, + input: { + height: 40, + borderColor: 'gray', + borderWidth: 1, + marginBottom: 10, + paddingHorizontal: 10, + }, + button: { + backgroundColor: 'gray', + padding: 10, + marginBottom: 10, + alignItems: 'center', + }, +}); +``` +{% /section %} + +{% section #step-6 step=6 title="All set" %} +Run your project with `npx expo start`. + +{% arrow_link + href="https://github.com/appwrite/playground-for-react-native" %} +Explore the React Native playground +{% /arrow_link %} +{% /section %} From af0bd5c9f3b2ca173b03a422d40e83c8d28eb4c8 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Sun, 7 Apr 2024 15:07:25 -0400 Subject: [PATCH 2/4] Fix react tutorial --- src/routes/docs/tutorials/react/step-6/+page.markdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/docs/tutorials/react/step-6/+page.markdoc b/src/routes/docs/tutorials/react/step-6/+page.markdoc index e90a9ed455..c22e85c8f7 100644 --- a/src/routes/docs/tutorials/react/step-6/+page.markdoc +++ b/src/routes/docs/tutorials/react/step-6/+page.markdoc @@ -50,7 +50,7 @@ export function IdeasProvider(props) { ID.unique(), idea ); - setIdeas((ideas) => [response.$id, ...ideas].slice(0, 10)); + setIdeas((ideas) => [response.documents, ...ideas].slice(0, 10)); } async function remove(id) { From 39f47ad8e33f320bdf27bbe611b474ae24d20f59 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Sun, 7 Apr 2024 16:42:15 -0400 Subject: [PATCH 3/4] Add react native tutorial, fix some mistakes found along the way --- .../tutorials/android/step-1/+page.markdoc | 2 +- .../tutorials/react-native/+layout.svelte | 10 ++ .../docs/tutorials/react-native/+layout.ts | 11 ++ .../docs/tutorials/react-native/+page.ts | 6 + .../react-native/step-1/+page.markdoc | 28 +++ .../react-native/step-2/+page.markdoc | 43 +++++ .../react-native/step-3/+page.markdoc | 60 +++++++ .../react-native/step-4/+page.markdoc | 166 ++++++++++++++++++ .../react-native/step-5/+page.markdoc | 106 +++++++++++ .../react-native/step-6/+page.markdoc | 137 +++++++++++++++ .../react-native/step-7/+page.markdoc | 131 ++++++++++++++ .../react-native/step-8/+page.markdoc | 14 ++ .../docs/tutorials/react/step-1/+page.markdoc | 2 +- .../docs/tutorials/react/step-6/+page.markdoc | 2 +- .../tutorials/refine/step-1/+page.markdoc | 2 +- .../tutorials/sveltekit/step-1/+page.markdoc | 2 +- .../docs/tutorials/vue/step-1/+page.markdoc | 2 +- 17 files changed, 718 insertions(+), 6 deletions(-) create mode 100644 src/routes/docs/tutorials/react-native/+layout.svelte create mode 100644 src/routes/docs/tutorials/react-native/+layout.ts create mode 100644 src/routes/docs/tutorials/react-native/+page.ts create mode 100644 src/routes/docs/tutorials/react-native/step-1/+page.markdoc create mode 100644 src/routes/docs/tutorials/react-native/step-2/+page.markdoc create mode 100644 src/routes/docs/tutorials/react-native/step-3/+page.markdoc create mode 100644 src/routes/docs/tutorials/react-native/step-4/+page.markdoc create mode 100644 src/routes/docs/tutorials/react-native/step-5/+page.markdoc create mode 100644 src/routes/docs/tutorials/react-native/step-6/+page.markdoc create mode 100644 src/routes/docs/tutorials/react-native/step-7/+page.markdoc create mode 100644 src/routes/docs/tutorials/react-native/step-8/+page.markdoc diff --git a/src/routes/docs/tutorials/android/step-1/+page.markdoc b/src/routes/docs/tutorials/android/step-1/+page.markdoc index 9cd25d5589..d038f3f840 100644 --- a/src/routes/docs/tutorials/android/step-1/+page.markdoc +++ b/src/routes/docs/tutorials/android/step-1/+page.markdoc @@ -17,7 +17,7 @@ This tutorial will introduce the following concepts: 2. Authentication 3. Databases and collections 4. Queries and pagination -5. Storage + # Prerequisites {% #prerequisites %} 1. Basic knowledge of Kotlin and Android development. diff --git a/src/routes/docs/tutorials/react-native/+layout.svelte b/src/routes/docs/tutorials/react-native/+layout.svelte new file mode 100644 index 0000000000..fb9fb3980f --- /dev/null +++ b/src/routes/docs/tutorials/react-native/+layout.svelte @@ -0,0 +1,10 @@ + + + diff --git a/src/routes/docs/tutorials/react-native/+layout.ts b/src/routes/docs/tutorials/react-native/+layout.ts new file mode 100644 index 0000000000..562b11506f --- /dev/null +++ b/src/routes/docs/tutorials/react-native/+layout.ts @@ -0,0 +1,11 @@ +import type { LayoutLoad } from './$types'; + +export const load: LayoutLoad = ({ url }) => { + const tutorials = import.meta.glob('./**/*.markdoc', { + eager: true + }); + return { + tutorials, + pathname: url.pathname + }; +}; diff --git a/src/routes/docs/tutorials/react-native/+page.ts b/src/routes/docs/tutorials/react-native/+page.ts new file mode 100644 index 0000000000..541bc7abce --- /dev/null +++ b/src/routes/docs/tutorials/react-native/+page.ts @@ -0,0 +1,6 @@ +import { redirect } from '@sveltejs/kit'; +import type { PageLoad } from './$types'; + +export const load: PageLoad = async () => { + redirect(303, '/docs/tutorials/react/step-1'); +}; diff --git a/src/routes/docs/tutorials/react-native/step-1/+page.markdoc b/src/routes/docs/tutorials/react-native/step-1/+page.markdoc new file mode 100644 index 0000000000..520ec13684 --- /dev/null +++ b/src/routes/docs/tutorials/react-native/step-1/+page.markdoc @@ -0,0 +1,28 @@ +--- +layout: tutorial +title: Build an ideas tracker with React Native +description: Learn to build a React Native app with no backend code using an Appwrite backend. +step: 1 +difficulty: beginner +readtime: 10 +category: Mobile and native +framework: React Native +--- + +**Idea tracker**: an app to track all the side project ideas that you'll start, but probably never finish. +In this tutorial, you will build Idea tracker with Appwrite and React Native. + +# Concepts {% #concepts %} + +This tutorial will introduce the following concepts: + +1. Setting up your first project +2. Authentication +3. Databases and collections +4. Queries and pagination + +# Prerequisites {% #prerequisites %} + +1. Android, iOS simulators, or a physical device to run the app +2. Have [Node.js](https://nodejs.org/en) and [NPM](https://www.npmjs.com/) installed on your computer +3. Basic knowledge of React Native and Expo \ No newline at end of file diff --git a/src/routes/docs/tutorials/react-native/step-2/+page.markdoc b/src/routes/docs/tutorials/react-native/step-2/+page.markdoc new file mode 100644 index 0000000000..42c2caf1eb --- /dev/null +++ b/src/routes/docs/tutorials/react-native/step-2/+page.markdoc @@ -0,0 +1,43 @@ +--- +layout: tutorial +title: Create app +description: Create a React Native app project and integrate with Appwrite. +step: 2 +--- + +# Create React Native project {% #create-react-project %} + +Create a React Native app with the `npm create` command. + +```sh +npx create-expo-app ideas-tracker +cd ideas-tracker +``` + +# Add dependencies {% #add-dependencies %} + +Install the React Native Appwrite SDK. + +```sh +npx expo install react-native-appwrite react-native-url-polyfill +``` + +Then, install React Navigation to help implement simple navigation logic. + +```sh +npm install @react-navigation/native @react-navigation/native-stack +``` + +Install peer dependencies needed for React Navigation. + +```sh +npx expo install react-native-screens react-native-safe-area-context +``` + +For iOS with bare React Native project, make sure you have CocoaPods installed. Then install the pods to complete the installation: + +``` +cd ios +pod install +cd .. +``` diff --git a/src/routes/docs/tutorials/react-native/step-3/+page.markdoc b/src/routes/docs/tutorials/react-native/step-3/+page.markdoc new file mode 100644 index 0000000000..ccb03ba4b6 --- /dev/null +++ b/src/routes/docs/tutorials/react-native/step-3/+page.markdoc @@ -0,0 +1,60 @@ +--- +layout: tutorial +title: Set up Appwrite +description: Import and initialize Appwrite for your React Native application. +step: 3 +--- + +# Create project {% #create-project %} + +Head to the [Appwrite Console](https://cloud.appwrite.io/console). + +{% only_dark %} +![Create project screen](/images/docs/quick-starts/dark/create-project.png) +{% /only_dark %} +{% only_light %} +![Create project screen](/images/docs/quick-starts/create-project.png) +{% /only_light %} + +If this is your first time using Appwrite, create an account and create your first project. + +Then, under **Add a platform**, add a **Android** or **Apple** platform with the package/bundle ID `com.example.idea-tracker`. + +{% only_dark %} +![Add a platform](/images/docs/quick-starts/dark/add-platform.png) +{% /only_dark %} +{% only_light %} +![Add a platform](/images/docs/quick-starts/add-platform.png) +{% /only_light %} + +You can skip optional steps. + +# Initialize Appwrite SDK {% #init-sdk %} + +To use Appwrite in our React Native app, you'll need to find our project ID. +Find your project's ID in the **Settings** page. + +{% only_dark %} +![Project settings screen](/images/docs/quick-starts/dark/project-id.png) +{% /only_dark %} +{% only_light %} +![Project settings screen](/images/docs/quick-starts/project-id.png) +{% /only_light %} + +Create a new file `lib/appwrite.js` to hold our Appwrite related code. +Only one instance of the `Client()` class should be created per app. +Add the following code to it, replacing `` with your project ID. + +```js +import { Client, Databases, Account } from "react-native-appwrite"; + +const client = new Client(); +client + .setEndpoint("https://cloud.appwrite.io/v1") + .setProject("") // Replace with your project ID + .setPlatform('com.example.idea-tracker'); + + +export const account = new Account(client); +export const databases = new Databases(client); +``` diff --git a/src/routes/docs/tutorials/react-native/step-4/+page.markdoc b/src/routes/docs/tutorials/react-native/step-4/+page.markdoc new file mode 100644 index 0000000000..cf273d8c2c --- /dev/null +++ b/src/routes/docs/tutorials/react-native/step-4/+page.markdoc @@ -0,0 +1,166 @@ +--- +layout: tutorial +title: Add authentication +description: Add authentication to your React Native application. +step: 4 +--- + +# User context {% #user-context %} + +In React Native, you can use [context](https://reactjs.org/docs/context.html) to share data between components. +You can use a context and a custom hook to manage our user's data. + +Create a new file `contexts/UserContext.jsx` and add the following code to it. + +```js +import { ID } from "react-native-appwrite"; +import { createContext, useContext, useEffect, useState } from "react"; +import { account } from "../lib/appwrite"; +import { toast } from "../lib/toast"; + + +const UserContext = createContext(); + +export function useUser() { + return useContext(UserContext); +} + +export function UserProvider(props) { + const [user, setUser] = useState(null); + + async function login(email, password) { + const loggedIn = await account.createEmailSession(email, password); + setUser(loggedIn); + toast('Welcome back. You are logged in'); + } + + async function logout() { + await account.deleteSession("current"); + setUser(null); + toast('Logged out'); + } + + async function register(email, password) { + await account.create(ID.unique(), email, password); + await login(email, password); + toast('Account created'); + } + + async function init() { + try { + const loggedIn = await account.get(); + setUser(loggedIn); + toast('Welcome back. You are logged in'); + } catch (err) { + setUser(null); + } + } + + useEffect(() => { + init(); + }, []); + + return ( + + {props.children} + + ); +} +``` + +Now, you can use the `useUser` hook to access the user's data from any component wrapped by this context's provider. + +# Display toasts {% #display-toasts %} + +For a better user experience, display toasts when the users perform an action, such as login, logout, create new ideas, etc. + +We can do this by creating a new file `lib/toast.js` and adding the following code to it. + +```js +import { ToastAndroid, Platform, AlertIOS } from 'react-native'; + +export function toast(msg) { + if (Platform.OS === 'android') { + ToastAndroid.show(msg, ToastAndroid.SHORT) + } else { + AlertIOS.alert(msg); + } +} +``` +# Login page {% #login-page %} + +Create a new file `views/Login.jsx` and add the following code to it. +this page contains a basic form to allow the user to login or register. +Notice how this page consumes the `useUser` hook to access the user's data and perform login and register actions. + +```js +import React, { useState } from 'react'; +import { View, Text, TextInput, Button, StyleSheet } from 'react-native'; +import { useUser } from '../contexts/UserContext'; + + +export default function LoginScreen() { + const user = useUser(); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + return ( + + Login or register + + + +