Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions src/routes/docs/tutorials/nextjs/step-4/+page.markdoc
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ Create a new file `hooks/useAuth.ts` and add the following code.
// hooks/useAuth.ts

import { useState, useEffect } from 'react';
import { account } from '../lib/appwrite';
import { account } from '@/lib/appwrite';
import { ID } from 'appwrite';
import type { Models } from 'appwrite';
import { useRouter } from 'next/navigation';

export function useAuth() {
const [current, setCurrent] = useState<Models.Session | null>(null);
const [current, setCurrent] = useState<Models.User<Models.Preferences> | null>(null);
const [loading, setLoading] = useState(true);
const router = useRouter();

Expand All @@ -46,16 +46,17 @@ export function useAuth() {
};

const login = async (email: string, password: string): Promise<void> => {
const session = await account.createEmailPasswordSession({
await account.createEmailPasswordSession({
email,
password
});
setCurrent(session);
const user = await account.get();
setCurrent(user);
router.push('/');
};

const logout = async (): Promise<void> => {
await account.deleteSession('current');
await account.deleteSession({ sessionId: 'current' });
setCurrent(null);
router.push('/');
};
Expand Down Expand Up @@ -97,7 +98,7 @@ We will define functions to handle form submissions and show either a signup or
'use client';

import { useState } from 'react';
import { useAuth } from '../../hooks/useAuth';
import { useAuth } from '@/hooks/useAuth';
import AuthForm from '../../components/AuthForm';

export default function LoginPage() {
Expand Down
4 changes: 2 additions & 2 deletions src/routes/docs/tutorials/nextjs/step-5/+page.markdoc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Create a new file `src/components/Navbar.tsx` and add the code below.
'use client';

import Link from 'next/link';
import { useAuth } from '../hooks/useAuth';
import { useAuth } from '@/hooks/useAuth';

export default function Navbar() {
const { current, logout } = useAuth();
Expand All @@ -28,7 +28,7 @@ export default function Navbar() {
<h3 className="u-stretch eyebrow-heading-1">Idea Tracker</h3>
{current ? (
<div className="main-header-end u-margin-inline-end-16">
<p>{current.providerUid}</p>
<p>{current.name || current.email}</p>
<button
className="button"
type="button"
Expand Down
49 changes: 28 additions & 21 deletions src/routes/docs/tutorials/nextjs/step-6/+page.markdoc
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,12 @@ We will add a new hook, `useIdeas`, to handle this functionality.
Create a new file `hooks/useIdeas.ts` and add the following code.

```ts
"use client";
// hooks/useIdeas.ts

import { useState, useEffect } from 'react';
import { ID, Query, Permission, type Models } from 'appwrite';
import { tablesDB } from '../lib/appwrite';
import {useState, useEffect} from 'react';
import {ID, Query, Permission, type Models} from 'appwrite';
import {tablesDB} from '@/lib/appwrite';

const databaseId = process.env.NEXT_PUBLIC_DATABASE_ID!;
const tableId = process.env.NEXT_PUBLIC_TABLE_ID!;
Expand All @@ -78,12 +79,15 @@ export function useIdeas() {
// Fetch the 10 most recent ideas from the database
const fetch = async (): Promise<void> => {
try {
const response = await tablesDB.listRows(
databaseId,
tableId,
[Query.orderDesc('$createdAt'), Query.limit(queryLimit)]
);
setCurrent(response.rows as Idea[]);
const response = await tablesDB.listRows<Idea>({
databaseId: databaseId,
tableId: tableId,
queries: [
Query.orderDesc('$createdAt'),
Query.limit(queryLimit)
],
});
setCurrent(response.rows);
} catch (error) {
console.error('Error fetching ideas:', error);
} finally {
Expand All @@ -92,28 +96,31 @@ export function useIdeas() {
};

// Add new idea to the database
const add = async (idea: Omit<Idea, '$id' | '$createdAt' | '$updatedAt' | '$permissions'>): Promise<void> => {
const add = async (ideaData: Omit<Idea, keyof Models.Row>): Promise<void> => {
try {
const response = await tablesDB.createRow(
databaseId,
tableId,
ID.unique(),
idea,
[
const response = await tablesDB.createRow<Idea>({
databaseId: databaseId,
tableId: tableId,
rowId: ID.unique(),
data: ideaData,
permissions: [
Permission.read('any'),
Permission.update(`user:${idea.userId}`),
Permission.delete(`user:${idea.userId}`)
Permission.update('user:' + ideaData.userId),
Permission.delete('user:' + ideaData.userId)
]
);
setCurrent(prev => [response as Idea, ...prev].slice(0, queryLimit));
});
setCurrent((prev) => {
const newList = [response, ...prev];
return newList.slice(0, queryLimit);
});
} catch (error) {
console.error('Error adding idea:', error);
}
};

const remove = async (id: string): Promise<void> => {
try {
await tablesDB.deleteRow(databaseId, tableId, id);
await tablesDB.deleteRow({databaseId: databaseId, tableId: tableId, rowId: id});
await fetch(); // Refetch ideas to ensure we have 10 items
} catch (error) {
console.error('Error removing idea:', error);
Expand Down
62 changes: 46 additions & 16 deletions src/routes/docs/tutorials/nextjs/step-7/+page.markdoc
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,44 @@ Create a new file `src/components/IdeasForm.tsx` and add the following code.
// src/components/IdeasForm.tsx
'use client';

import { useIdeas } from '../hooks/useIdeas';
import { useAuth } from '../hooks/useAuth';
import { useAuth } from '@/hooks/useAuth';
import type {Models} from "appwrite";

export default function IdeasForm() {
const { add } = useIdeas();
interface Idea extends Models.Row {
title: string;
description: string;
userId: string;
}

interface IdeasFormProps {
onAdd: (idea: Omit<Idea, keyof Models.Row>) => Promise<void>;
}

export default function IdeasForm({ onAdd }: IdeasFormProps) {
const { current: user } = useAuth();

const handleAddIdea = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();

if (!user) return;

const form = event.target as HTMLFormElement;
const formData = new FormData(form);

if (!user) return;


const postIdeaData = {
userId: user.userId,
userId: user.$id,
title: formData.get('title') as string,
description: formData.get('description') as string,
};

await add(postIdeaData);
form.reset();
try {
await onAdd(postIdeaData);
form.reset();
} catch (error) {
console.error("Failed to add idea:", error);
}
};

if (!user) {
Expand Down Expand Up @@ -98,11 +114,22 @@ Now we need to display the ideas from the database. Create a new file `src/compo
// src/components/IdeasList.tsx
'use client';

import { useIdeas } from '../hooks/useIdeas';
import { useAuth } from '../hooks/useAuth';
import {useAuth} from '@/hooks/useAuth';
import {Models} from "appwrite";

interface Idea extends Models.Row {
title: string;
description: string;
userId: string;
}

export default function IdeasList() {
const { current: ideas, loading, remove } = useIdeas();
interface IdeasListProps {
ideas: Idea[];
loading: boolean;
onRemove: (id: string) => Promise<void>;
}

export default function IdeasList({ ideas, loading, onRemove }: IdeasListProps) {
const { current: user } = useAuth();

if (loading) {
Expand Down Expand Up @@ -132,9 +159,9 @@ export default function IdeasList() {
</p>
)}
</div>
{user && user.userId === idea.userId && (
{user && user.$id === idea.userId && (
<button
onClick={() => remove(idea.$id)}
onClick={() => onRemove(idea.$id)}
className="button is-text u-padding-inline-8"
aria-label="Delete idea"
>
Expand All @@ -155,11 +182,14 @@ export default function IdeasList() {
Now let's update the home page to use our new components. Update `src/app/page.tsx`:

```tsx
'use client';
// src/app/page.tsx
import IdeasForm from '../components/IdeasForm';
import IdeasList from '../components/IdeasList';
import {useIdeas} from "@/hooks/useIdeas";

export default function Home() {
const { current: ideas, loading, add, remove } = useIdeas();
return (
<main className="u-padding-16">
<div className="container">
Expand All @@ -168,8 +198,8 @@ export default function Home() {
Track all your side project ideas in one place.
</p>
</div>
<IdeasForm />
<IdeasList />
<IdeasForm onAdd={add} />
<IdeasList ideas={ideas} loading={loading} onRemove={remove} />
</main>
);
}
Expand Down