From 9f7c52cd7d81e170368bb5242f12798b8f805328 Mon Sep 17 00:00:00 2001
From: tglide <26071571+TGlide@users.noreply.github.com>
Date: Thu, 26 Oct 2023 18:53:03 +0100
Subject: [PATCH 1/2] rewrite svelte tutorial

---
 .../tutorials/sveltekit/step-3/+page.markdoc  |   1 -
 .../tutorials/sveltekit/step-4/+page.markdoc  | 170 ++++++++++--------
 .../tutorials/sveltekit/step-5/+page.markdoc  |  56 +++---
 .../tutorials/sveltekit/step-6/+page.markdoc  |  82 ++++-----
 .../tutorials/sveltekit/step-7/+page.markdoc  | 158 ++++++++++------
 .../tutorials/sveltekit/step-8/+page.markdoc  |   9 -
 6 files changed, 253 insertions(+), 223 deletions(-)
 delete mode 100644 src/routes/docs/tutorials/sveltekit/step-8/+page.markdoc

diff --git a/src/routes/docs/tutorials/sveltekit/step-3/+page.markdoc b/src/routes/docs/tutorials/sveltekit/step-3/+page.markdoc
index 51a7938cd4f..f0756a7ada0 100644
--- a/src/routes/docs/tutorials/sveltekit/step-3/+page.markdoc
+++ b/src/routes/docs/tutorials/sveltekit/step-3/+page.markdoc
@@ -44,7 +44,6 @@ Only one instance of the `Client()` class should be created per app.
 Add the following code to it, replacing `<YOUR_PROJECT_ID>` with your project ID.
 
 ```js
-
 import { Client, Databases, Account } from "appwrite";
 
 const client = new Client();
diff --git a/src/routes/docs/tutorials/sveltekit/step-4/+page.markdoc b/src/routes/docs/tutorials/sveltekit/step-4/+page.markdoc
index 0b1b1cbe202..d7b9686e08b 100644
--- a/src/routes/docs/tutorials/sveltekit/step-4/+page.markdoc
+++ b/src/routes/docs/tutorials/sveltekit/step-4/+page.markdoc
@@ -7,51 +7,63 @@ step: 4
 
 # Using stores {% #using-stores %}
 
-In Svelte, [stores](https://svelte.dev/docs/svelte-store) are a way to manage state throughout your application.
+Svelte [stores](https://svelte.dev/docs/svelte-store) provide an easy way to manage state throughout your application.
 We'll use a store to keep track of our user's data.
 
-Create a new file `src/lib/stores/user.js` and add the following code to it.
+Create a new file `src/lib/user.js` and add the following code to it.
 
 ```js
-import { writable } from "svelte/store";
-import { ID } from "appwrite";
-import { goto } from "$app/navigation";
-import { account } from "$lib/appwrite";
-
-const store = writable(null);
-
-async function init() {
-  try {
-    store.set(await account.get());
-  } catch (e) {
-    store.set(null);
-  }
-}
-
-async function register(email, password, name) {
-  await account.create(ID.unique(), email, password, name);
-  await login(email, password);
-}
-
-async function login(email, password) {
-  await account.createEmailSession(email, password);
-  await init();
-  goto("/"); // Redirect to home page after login
-}
-
-async function logout() {
-  await account.deleteSession("current");
-  store.set(null);
-}
-
-// Expose the store's value with $user
-export const user = {
-  subscribe: store.subscribe, 
-  register,
-  login,
-  logout,
-  init,
+import { writable } from 'svelte/store';
+import { ID } from 'appwrite';
+import { goto } from '$app/navigation';
+import { account } from '$lib/appwrite';
+
+// Avoid auth calls in server-side, so that a user is not shared between requests
+const isBrowser = typeof window !== 'undefined';
+
+const createUser = () => {
+	const store = writable(null);
+
+	async function init() {
+		if (!isBrowser) return;
+		try {
+			store.set(await account.get());
+		} catch (e) {
+			store.set(null);
+		}
+	}
+
+	init();
+
+	async function register(email, password, name) {
+		if (!isBrowser) return;
+		await account.create(ID.unique(), email, password, name);
+		await login(email, password);
+	}
+
+	async function login(email, password) {
+		if (!isBrowser) return;
+		await account.createEmailSession(email, password);
+		await init();
+		goto('/'); // Redirect to home page after login
+	}
+
+	async function logout() {
+		await account.deleteSession('current');
+		store.set(null);
+	}
+
+	return {
+		// Exposes the store's value with $user
+		subscribe: store.subscribe,
+		register,
+		login,
+		logout,
+		init
+	};
 };
+
+export const user = createUser();
 ```
 
 # Login page {% #login-page %}
@@ -62,51 +74,59 @@ Create a new file `src/routes/login/+page.svelte` and add the following code to
 
 ```html
 <script>
-  import { user } from "$lib/stores/user";
-
-  const login = async (e) => {
-    e.preventDefault();
-    const formData = new FormData(e.target);
-    await user.login(formData.get("email"), formData.get("password"));
-  };
-
-  const register = async (e) => {
-    e.preventDefault();
-    const formData = new FormData(e.target);
-    await user.register(formData.get("email"), formData.get("password"), formData.get("name"));
-  };
+	import { user } from '$lib/user';
+
+	const login = async (e) => {
+		e.preventDefault();
+		const formData = new FormData(e.target);
+		await user.login(formData.get('email'), formData.get('password'));
+	};
+
+	const register = async (e) => {
+		e.preventDefault();
+		const formData = new FormData(e.target);
+		await user.register(formData.get('email'), formData.get('password'), formData.get('name'));
+	};
 </script>
 
 <h1>Login or register</h1>
 
 <form on:submit={login}>
-  <input type="email" placeholder="Email" name="email" required />
-  <input type="password" placeholder="Password" name="password" required />
-  <button type="submit">
-    Login
-  </button>
+	<label>
+		Email
+		<input type="email" placeholder="Email" name="email" required />
+	</label>
+	<label>
+		Password:
+		<input type="password" placeholder="Password" name="password" required />
+	</label>
+	<button type="submit"> Login </button>
 </form>
 
-
 <form on:submit={register}>
-  <input type="text" placeholder="Name" name="name" required />
-  <input type="email" placeholder="Email" name="email" required />
-  <input
-    type="password"
-    placeholder="Password"
-    name="password"
-    required
-    minlength="8"
-  />
-  <button type="submit">
-    Register
-  </button>
+	<label>
+		Name:
+		<input type="text" placeholder="Name" name="name" required />
+	</label>
+	<label>
+		Email:
+		<input type="email" placeholder="Email" name="email" required />
+	</label>
+	<label>
+		Password:
+		<input type="password" placeholder="Password" name="password" required minlength="8" />
+	</label>
+	<button type="submit"> Register </button>
 </form>
 
 <style>
-  form {
-    display: grid;
-    gap: 0.25rem;
-  }
+	form {
+		display: flex;
+		flex-direction: column;
+		align-items: flex-start;
+		gap: 0.25rem;
+
+		margin-block-end: 2rem;
+	}
 </style>
 ```
\ No newline at end of file
diff --git a/src/routes/docs/tutorials/sveltekit/step-5/+page.markdoc b/src/routes/docs/tutorials/sveltekit/step-5/+page.markdoc
index d0ed993fade..61b5dc1eb6e 100644
--- a/src/routes/docs/tutorials/sveltekit/step-5/+page.markdoc
+++ b/src/routes/docs/tutorials/sveltekit/step-5/+page.markdoc
@@ -8,49 +8,41 @@ step: 5
 We'll create a layout component, that's used by all pages, to display a navbar.
 The navbar will show a login button if the user is not logged in, and a logout button if the user is logged in.
 
-In this component, we can call our `user.init()` function to check if the user is logged in when the page loads.
-
 Create a new file `src/routes/+layout.svelte` and add the following code to it.
 
 ```html
 <script>
-  import { ideas } from "$lib/stores/ideas";
-  import { user } from "$lib/stores/user";
-  import { onMount } from "svelte";
-
-  onMount(async () => {
-    user.init();
-  });
+	import { user } from '$lib/user';
 </script>
 
 <nav>
-  <a href="/">Idea tracker</a>
-  {#if $user}
-    <div>
-      <span>{$user.name}</span>
-      <button type="button" on:click={user.logout}>Logout</button>
-    </div>
-  {:else}
-    <a href="/login">Login</a>
-  {/if}
+	<a href="/">Home</a>
+	{#if $user}
+		<div>
+			<span>{$user.name}</span>
+			<button type="button" on:click={user.logout}>Logout</button>
+		</div>
+	{:else}
+		<a href="/login">Login</a>
+	{/if}
 </nav>
 
 <slot />
 
 <style>
-  :global(*) {
-    font-family: sans-serif;
-  }
-
-  :global(body) {
-    margin: 1rem auto;
-    max-width: 30rem;
-  }
-
-  nav {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-  }
+	:global(*) {
+		font-family: sans-serif;
+	}
+
+	:global(body) {
+		margin: 1rem auto;
+		max-width: 30rem;
+	}
+
+	nav {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+	}
 </style>
 ```
\ No newline at end of file
diff --git a/src/routes/docs/tutorials/sveltekit/step-6/+page.markdoc b/src/routes/docs/tutorials/sveltekit/step-6/+page.markdoc
index a7343065452..d13bbfb0ba1 100644
--- a/src/routes/docs/tutorials/sveltekit/step-6/+page.markdoc
+++ b/src/routes/docs/tutorials/sveltekit/step-6/+page.markdoc
@@ -5,7 +5,8 @@ description: Add databases and queries to store user data in you SvelteKit proje
 step: 6
 ---
 # Create collection {% #create-collection %}
-In Appwrite, data is stored as a collection of documents. Create a collection in the [Appwrite Console](https://cloud.appwrite.io/) to store our ideas.
+In Appwrite, data is stored as a collection of documents. 
+Create a collection inside a database in the [Appwrite Console](https://cloud.appwrite.io/) to store our ideas.
 
 {% only_dark %}
 ![Create project screen](/images/docs/tutorials/dark/idea-tracker-collection.png)
@@ -14,64 +15,51 @@ In Appwrite, data is stored as a collection of documents. Create a collection in
 ![Create project screen](/images/docs/tutorials/idea-tracker-collection.png)
 {% /only_light %}
 
-Create a new collection with the following attributes:
-| Field       | Type   | Required |
-|-------------|--------|----------|
-| userId      | String | Yes      |
-| title       | String | Yes      |
-| description | String | No       |
+Create the following attributes within the collection:
+| Field       | Type   | Size | Required |
+| ----------- | ------ | ---- | -------- |
+| userId      | String | 36   | Yes      |
+| title       | String | 128  | Yes      |
+| description | String | 1024 | No       |
+
+For this tutorial, we'll also set the permissions to allow any users to read and write to the collection. 
+In a real-world scenario, you would probably want to restrict access to a certain group of users.
+
+# Managing ideas {% #getting-ideas %}
 
-# Add and remove methods {% #add-and-remove-methods %}
 Now that you have a collection to hold ideas, we can read and write to it from our app.
-Create a new file `src/lib/stores/ideas.js` and add the following code to it.
 
-```js
-import { writable } from "svelte/store";
-import { ID, Query } from "appwrite";
-import { databases } from "$lib/appwrite";
+Let's create some methods to manage ideas in our app.
 
-export const IDEAS_DATABASE_ID = "6508783c5dc784d544dd"; // Replace with your database ID
-export const IDEAS_COLLECTION_ID = "65087840ab307cb06883"; // Replace with your collection ID
+Create a new file `src/lib/ideas.js` and add the following code:
 
-const databases = new Databases(client);
+```js
+import { ID, Query } from 'appwrite';
+import { databases } from '$lib/appwrite';
 
-const store = writable([]);
+const IDEAS_DATABASE_ID = '<YOUR_DATABASE_ID>'; // Replace with your database ID
+const IDEAS_COLLECTION_ID = '<YOUR_COLLECTION_ID>'; // Replace with your collection ID
 
-async function init() {
-  const response = await databases.listDocuments(
-    IDEAS_DATABASE_ID,
-    IDEAS_COLLECTION_ID,
-    // Use a query to how the latest ideas first
-    [Query.orderDesc("$createdAt")]
-  );
-  store.set(response.documents);
+export async function getIdeas() {
+	return await databases.listDocuments(
+		IDEAS_DATABASE_ID,
+		IDEAS_COLLECTION_ID,
+		// Use a query to show the latest ideas first
+		[Query.orderDesc('$createdAt')]
+	);
 }
 
-async function add(userId, title, description) {
-  const response = await databases.createDocument(
-    IDEAS_DATABASE_ID,
-    IDEAS_COLLECTION_ID,
-    ID.unique(),
-    {
-      userId,
-      title,
-      description,
-    }
-  );
-  store.update((ideas) => [response, ...ideas]);
+export async function addIdea(userId, title, description) {
+	await databases.createDocument(IDEAS_DATABASE_ID, IDEAS_COLLECTION_ID, ID.unique(), {
+		userId,
+		title,
+		description
+	});
 }
 
-async function remove(id) {
-  await databases.deleteDocument(IDEAS_DATABASE_ID, IDEAS_COLLECTION_ID, id);
-  store.update((ideas) => ideas.filter((idea) => idea.$id !== id));
+export async function deleteIdea(id) {
+	await databases.deleteDocument(IDEAS_DATABASE_ID, IDEAS_COLLECTION_ID, id);
 }
-
-export const ideas = {
-  subscribe: store.subscribe, // Expose the store's value with $ideas
-  init,
-  add,
-  remove,
-};
 ```
 
 Remember to use a store to hold data returned from Appwrite Databases, so your components can be updated when the data changes.
\ No newline at end of file
diff --git a/src/routes/docs/tutorials/sveltekit/step-7/+page.markdoc b/src/routes/docs/tutorials/sveltekit/step-7/+page.markdoc
index e58dded3a4a..c9fd7a7a393 100644
--- a/src/routes/docs/tutorials/sveltekit/step-7/+page.markdoc
+++ b/src/routes/docs/tutorials/sveltekit/step-7/+page.markdoc
@@ -5,77 +5,117 @@ description: Add pagining and ordering to you SvelteKit application powered by A
 step: 7
 ---
 
-Using the `ideas` store, we can build a page to submit and view ideas.
+Using our created methods, we can build a page to submit and view ideas.
 
-Overwrite the contents of `src/routes/+page.svelte` with the following code.
+First, let's create a load function for our ideas page. This will load the latest ideas from the database.
+
+To do so, create a file called `src/routes/+page.js` with the following content:
+
+```js
+import { getIdeas } from '$lib/ideas';
+
+export async function load() {
+	return {
+		ideas: getIdeas()
+	};
+}
+```
+
+Simple as that! Now, let's create the page itself. Replace the contents in `src/routes/+page.svelte` with the following:
 
 ```html
 <script>
-  import { user } from "$lib/stores/user";
-  import { ideas } from "$lib/stores/ideas";
-
-  const add = (e) => {
-    e.preventDefault();
-    const formData = new FormData(e.target);
-    ideas.add($user.$id, formData.get("title"), formData.get("description"));
-  };
+	import { invalidateAll } from '$app/navigation';
+	import { addIdea, deleteIdea } from '$lib/ideas.js';
+	import { user } from '$lib/user.js';
+
+	export let data;
+
+	const add = async (e) => {
+		e.preventDefault();
+		const formEl = e.target;
+		const formData = new FormData(formEl);
+		await addIdea($user.$id, formData.get('title'), formData.get('description'));
+		invalidateAll();
+
+		// Reset form
+		formEl.reset();
+	};
+
+	const remove = async (id) => {
+		await deleteIdea(id);
+		invalidateAll();
+	};
 </script>
 
 {#if $user}
-  <section>
-    <h2>Submit Idea</h2>
-    <form on:submit={add}>
-      <input type="text" placeholder="Title" name="title" required  />
-      <textarea placeholder="Description" name="description" required />
-      <button type="submit">
-        Submit
-      </button>
-    </form>
-  </section>
+	<section>
+		<h2>Submit Idea</h2>
+		<form on:submit={add}>
+			<label>
+				Title
+				<input type="text" placeholder="Title" name="title" required />
+			</label>
+			<label>
+				Description
+				<textarea placeholder="Description" name="description" />
+			</label>
+			<button type="submit">Submit</button>
+		</form>
+	</section>
 {:else}
-  <section><p>Please login to submit an idea.</p></section>
+	<section><p>Please login to submit an idea.</p></section>
 {/if}
 
 <section>
-  <h2>Latest Ideas</h2>
-  <ul>
-    {#each $ideas as idea}
-      <li>
-        <strong>{idea.title}</strong>
-        <p>{idea.description}</p>
-        {#if $user && idea.userId === $user.$id}
-          <button type="button" on:click={() => ideas.remove(idea.$id)}>
-            Remove
-          </button>
-        {/if}
-      </li>
-    {:else}
-      <li>No ideas yet.</li>
-    {/each}
-  </ul>
+	<h2>Latest Ideas</h2>
+	{#if data.ideas.total === 0}
+		<p>No ideas yet.</p>
+	{:else}
+		<p>{data.ideas.total} ideas found</p>
+	{/if}
+	<ul>
+		{#each data.ideas.documents as idea}
+			<li>
+				<strong>{idea.title}</strong>
+				{#if idea.description}
+					<p>{idea.description}</p>
+				{/if}
+				{#if $user && idea.userId === $user.$id}
+					<button type="button" on:click={() => remove(idea.$id)}>Remove</button>
+				{/if}
+			</li>
+		{/each}
+	</ul>
 </section>
 
 <style>
-  section {
-    margin-bottom: 3rem;
-  }
-  form {
-    display: grid;
-    gap: 0.25rem;
-  }
-
-  ul {
-    list-style: none;
-    padding: 0;
-  }
-
-  li {
-    border-radius: 0.25em;
-    background-color: antiquewhite;
-    box-shadow: 8px 8px 4px 0 rgba(0, 0, 0, 0.1);
-    min-width: 20%;
-    padding: 1rem;
-    margin-bottom: 1rem;
-  }
+	section {
+		margin-bottom: 3rem;
+	}
+	form {
+		display: grid;
+		gap: 0.75rem;
+	}
+
+	label {
+		display: grid;
+		gap: 0.25rem;
+	}
+
+	ul {
+		list-style: none;
+		padding: 0;
+	}
+
+	li {
+		border-radius: 0.5rem;
+		border: 2px dashed pink;
+		min-width: 20%;
+		padding: 1rem;
+		margin-bottom: 1rem;
+	}
 </style>
-```
\ No newline at end of file
+```
+
+With this you have successfully created an Ideas Tracker! You can now submit ideas and view them.
\ No newline at end of file
diff --git a/src/routes/docs/tutorials/sveltekit/step-8/+page.markdoc b/src/routes/docs/tutorials/sveltekit/step-8/+page.markdoc
deleted file mode 100644
index 01d92b2f986..00000000000
--- a/src/routes/docs/tutorials/sveltekit/step-8/+page.markdoc
+++ /dev/null
@@ -1,9 +0,0 @@
----
-layout: tutorial
-title: Next steps
-description: View your SvelteKit project powered by Appwrite authentication and databases.
-step: 8
----
-
-# Test your project {% #test-project %}
-Run your project with `npm run dev` and open [http://localhost:5173](http://localhost:5173) in your browser.
\ No newline at end of file

From 25b36aeb7f1c256848aea2f9c73a6439683dee00 Mon Sep 17 00:00:00 2001
From: tglide <26071571+TGlide@users.noreply.github.com>
Date: Fri, 27 Oct 2023 17:39:08 +0100
Subject: [PATCH 2/2] refactor svelte quick start

---
 .../docs/quick-starts/sveltekit/+page.markdoc | 61 +++++++++++--------
 1 file changed, 34 insertions(+), 27 deletions(-)

diff --git a/src/routes/docs/quick-starts/sveltekit/+page.markdoc b/src/routes/docs/quick-starts/sveltekit/+page.markdoc
index 0206baa8917..997e89eaf49 100644
--- a/src/routes/docs/quick-starts/sveltekit/+page.markdoc
+++ b/src/routes/docs/quick-starts/sveltekit/+page.markdoc
@@ -35,7 +35,7 @@ You can skip optional steps.
 Create a SvelteKit project.
 
 ```sh
-npm create svelte@next my-app && cd my-app
+npm create svelte@next my-app && cd my-app && npm install
 ```
 {% /section %}
 {% section #step-3 step=3 title="Install Appwrite" %}
@@ -58,7 +58,7 @@ Find your project's ID in the **Settings** page.
 Create a new file `src/lib/appwrite.js` and add the following code to it, replace `<YOUR_PROJECT_ID>` with your project ID.
 
 ```js
-import { Client, Account} from 'appwrite';
+import { Client, Account } from 'appwrite';
 
 export const client = new Client();
 
@@ -71,7 +71,7 @@ export { ID } from 'appwrite';
 ```
 {% /section %}
 {% section #step-5 step=5 title="Create a login page" %}
-Create a new file `src/routes/index.svelte` and add the following code to it.
+Replace the contents of `src/routes/+page.svelte` with the following code.
 
 ```html
 <script>
@@ -79,45 +79,52 @@ Create a new file `src/routes/index.svelte` and add the following code to it.
 
     let loggedInUser = null;
 
-    let email = '';
-    let password = '';
-    let name = '';
-
     async function login(email, password) {
         await account.createEmailSession(email, password);
         loggedInUser = await account.get();
     }
+
+    async function register(email, password) {
+        await account.create(ID.unique(), email, password);
+        login(email, password);
+    }
+
+    function submit(e) {
+        e.preventDefault();
+        const formData = new FormData(e.target);
+        const type = e.submitter.dataset.type;
+        
+        if (type === "login") {
+            login(formData.get('email'), formData.get('password'));
+        } else if (type === "register") {
+            register(formData.get('email'), formData.get('password'));
+        }
+    }
+
+    function logout() {
+        await account.deleteSession('current');
+        loggedInUser = null;
+    }
 </script>
 
 <p>
     {loggedInUser ? `Logged in as ${loggedInUser.name}` : 'Not logged in'}
 </p>
 
-<form>
-    <input type="email" placeholder="Email" bind:value={email} />
-    <input type="password" placeholder="Password" bind:value={password} />
-    <input type="text" placeholder="Name" bind:value={name} />
-
-    <button type="button" on:click={() => login(email, password)}>Login</button>
-    <button
-        type="button"
-        on:click={async () => {
-            await account.create(ID.unique(), email, password, name);
-            login(email, password);
-        }}>Register</button>
-
-    <button
-        type="button"
-        on:click={async () => {
-            await account.deleteSession('current');
-            loggedInUser = null;
-        }}>Logout</button>
+<form on:submit={submit}>
+    <input type="email" placeholder="Email" name="email" required />
+    <input type="password" placeholder="Password" name="password" required />
+
+    <button type="submit" data-type="login">Login</button>
+    <button type="submit" data-type="register">Register</button>
 </form>
+
+<button on:click={logout}>Logout</button>
 ```
 {% /section %}
 
 {% section #step-6 step=6 title="All set" %}
-Run your project with `npm run dev -- --open --port 3000` and open [Localhost on Port 3000](http://localhost:3000) in your browser.
+Run your project with `npm run dev` and open [localhost on port 5173](http://localhost:5173) in your browser.
 {% /section %}
 
 
