From 12dae1967443db3f583cdeb06ac6ffeb3a86cf96 Mon Sep 17 00:00:00 2001 From: kenyonyozi Date: Wed, 11 Jun 2025 16:04:12 +0300 Subject: [PATCH 1/6] add to do ui --- .env.example | 3 - package-lock.json | 10 + package.json | 1 + src/app/page.js | 880 ++++++++++++++++++++++++++++++-------------- src/lib/appwrite.js | 5 +- 5 files changed, 623 insertions(+), 276 deletions(-) delete mode 100644 .env.example diff --git a/.env.example b/.env.example deleted file mode 100644 index b38780d..0000000 --- a/.env.example +++ /dev/null @@ -1,3 +0,0 @@ -NEXT_PUBLIC_APPWRITE_ENDPOINT= -NEXT_PUBLIC_APPWRITE_PROJECT_ID= -NEXT_PUBLIC_APPWRITE_PROJECT_NAME= \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 372683d..c7fce78 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@appwrite.io/pink-icons": "^1.0.0", "@tailwindcss/postcss": "^4.0.14", "appwrite": "^16.1.0", + "date-fns": "^4.1.0", "next": "14.2.15", "postcss": "^8.5.3", "react": "^18", @@ -472,6 +473,15 @@ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", "license": "MIT" }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/detect-libc": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", diff --git a/package.json b/package.json index 2660285..415085b 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "@appwrite.io/pink-icons": "^1.0.0", "@tailwindcss/postcss": "^4.0.14", "appwrite": "^16.1.0", + "date-fns": "^4.1.0", "next": "14.2.15", "postcss": "^8.5.3", "react": "^18", diff --git a/src/app/page.js b/src/app/page.js index e6926f5..e21acf0 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -3,309 +3,647 @@ import "./app.css"; import "@appwrite.io/pink-icons"; import { useState, useEffect, useRef, useCallback } from "react"; -import { client } from "@/lib/appwrite"; -import { AppwriteException } from "appwrite"; +import { client, databases, storage } from "@/lib/appwrite"; +import { AppwriteException, ID } from "appwrite"; import NextjsLogo from "../static/nextjs-icon.svg"; import AppwriteLogo from "../static/appwrite-icon.svg"; import Image from "next/image"; export default function Home() { - const [detailHeight, setDetailHeight] = useState(55); - const [logs, setLogs] = useState([]); - const [status, setStatus] = useState("idle"); - const [showLogs, setShowLogs] = useState(false); + const [title, setTitle] = useState(''); + const [successMessage, setSuccessMessage] = useState(''); + const [completeMessage, setCompleteMessage] = useState(''); + const [failedMessage, setFailedMessage] = useState(''); + const [deleteMessage, setDeleteMessage] = useState(''); + const [tab, setTab] = useState('hi'); + const [todos, setTodos] = useState([]); - const detailsRef = useRef(null); + const fileInputRef = useRef(null); - const updateHeight = useCallback(() => { - if (detailsRef.current) { - setDetailHeight(detailsRef.current.clientHeight); - } - }, [logs, showLogs]); - useEffect(() => { - updateHeight(); - window.addEventListener("resize", updateHeight); - return () => window.removeEventListener("resize", updateHeight); - }, [updateHeight]); useEffect(() => { - if (!detailsRef.current) return; - detailsRef.current.addEventListener("toggle", updateHeight); - - return () => { - if (!detailsRef.current) return; - detailsRef.current.removeEventListener("toggle", updateHeight); - }; + fetchTodos(); }, []); - async function sendPing() { - if (status === "loading") return; - setStatus("loading"); + + const handleSubmit = async (e) => { + e.preventDefault(); + + const file = fileInputRef.current?.files?.[0]; + + if (!title.trim()) { + alert('Please enter a title.'); + return; + } + + if (!file) { + alert('Please attach a media file.'); + return; + } + try { - const result = await client.ping(); - const log = { - date: new Date(), - method: "GET", - path: "/v1/ping", - status: 200, - response: JSON.stringify(result), - }; - setLogs((prevLogs) => [log, ...prevLogs]); - setStatus("success"); + const results = await storage.createFile( + '6847c4e1001bb5fa1427', // bucketId + ID.unique(), // fileId + file, // file + ); + const result = await databases.createDocument( + '6847b5980033f7e274d8', // databaseId + '6847b5a9003c48843844', + ID.unique(), // documentId + { //data + title: title, + media: [results.$id], + status: 'pending' + }, + ); + + // Set success message + setSuccessMessage('Todo added successfully!'); + + // Optionally clear form fields + setTitle(''); + if (fileInputRef.current) fileInputRef.current.value = null; + + setTimeout(() => setSuccessMessage(''), 5000); + fetchTodos(); + } catch (err) { - const log = { - date: new Date(), - method: "GET", - path: "/v1/ping", - status: err instanceof AppwriteException ? err.code : 500, - response: - err instanceof AppwriteException - ? err.message - : "Something went wrong", - }; - setLogs((prevLogs) => [log, ...prevLogs]); - setStatus("error"); + console.error('Error uploading:', err); + alert('An error occurred.'); } - setShowLogs(true); - } + }; + + const fetchTodos = async () => { + try { + const response = await databases.listDocuments( + '6847b5980033f7e274d8', // databaseId + '6847b5a9003c48843844' // collectionId + ); + setTodos(response.documents); + } catch (error) { + console.error('Failed to fetch todos:', error); + } + }; + + const handleDelete = async (id) => { + try { + await databases.deleteDocument( + '6847b5980033f7e274d8', + '6847b5a9003c48843844', + // ID.unique(), // documentId + id + ); + // Set success message + setDeleteMessage('Todo Deleted'); + setTimeout(() => setDeleteMessage(''), 5000); + // Refresh the list + fetchTodos(); + } catch (error) { + console.error('Failed to delete todo:', error); + } + }; + + const completeTodos = todos.filter((todo) => todo.status === 'completed'); + const failedTodos = todos.filter((todo) => todo.status === 'failed'); + const pendingTodos = todos.filter((todo) => todo.status === 'pending'); + + + const handleComplete = async (id) => { + if (!id) { + console.error("Missing document ID"); + return; + } + + try { + await databases.updateDocument( + "6847b5980033f7e274d8", // Database ID + "6847b5a9003c48843844", // Collection ID + id, // Document ID + { status: "completed" } // Fields to update + ); + + // Set success message + setCompleteMessage('Todo marked completed!'); + + setTimeout(() => setCompleteMessage(''), 5000); + fetchTodos(); // Refresh the todo list + } catch (error) { + console.error("Failed to mark todo as complete:", error); + } + }; + + const handleFailed = async (id) => { + if (!id) { + console.error("Missing document ID"); + return; + } + + try { + await databases.updateDocument( + "6847b5980033f7e274d8", // Database ID + "6847b5a9003c48843844", // Collection ID + id, // Document ID + { status: "failed" } // Fields to update + ); + // Set success message + setFailedMessage('Todo marked failed!'); + + setTimeout(() => setFailedMessage(''), 5000); + fetchTodos(); // Refresh the todo list + } catch (error) { + console.error("Failed to mark todo as fail:", error); + } + }; + return (
-
-
-
- {"Next.js -
+
+

Todo Masterpiece

+

Organise your tasks with style and efficiency

+
+ +
+
+
{pendingTodos.length}
+
Total
-
-
-
-
+
+
{pendingTodos.length}
+
Pending
-
-
- {"Appwrite -
+
+
{completeTodos.length}
+
Completed
+
+ +
+
{failedTodos.length}
+
Failed
-
- {status === "loading" ? ( -
-
- - Loading... -
- Waiting for connection... -
- ) : status === "success" ? ( -

- Congratulations! -

- ) : ( -

- Check connection -

- )} - -

- {status === "success" ? ( - You connected your app successfully. - ) : status === "error" || status === "idle" ? ( - Send a ping to verify the connection - ) : null} -

- - -
- -
-
-

Edit your app

-

- Edit{" "} - app/page.js to - get started with building your app. -

+
+
+ +
- -
-
-

- Go to console -

- -
-

- Navigate to the console to control and oversee the Appwrite - services. -

-
-
- - -
-
-

- Explore docs -

- -
-

- Discover the full power of Appwrite by diving into our - documentation. -

-
-
- -
+ )} + + + + ); } diff --git a/src/lib/appwrite.js b/src/lib/appwrite.js index 537ab08..5d84560 100644 --- a/src/lib/appwrite.js +++ b/src/lib/appwrite.js @@ -1,4 +1,4 @@ -import { Client, Account, Databases } from "appwrite"; +import { Client, Account, Databases, Storage } from "appwrite"; const client = new Client() .setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT) @@ -6,5 +6,6 @@ const client = new Client() const account = new Account(client); const databases = new Databases(client); +const storage = new Storage(client); -export { client, account, databases }; +export { client, account, databases , storage}; From f0a9afe0d0e5d5befdba0da2161afb523c833323 Mon Sep 17 00:00:00 2001 From: kenyonyozi Date: Wed, 11 Jun 2025 16:05:09 +0300 Subject: [PATCH 2/6] remove console log --- src/app/page.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/app/page.js b/src/app/page.js index e21acf0..f7f00e6 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -139,7 +139,6 @@ export default function Home() { console.error("Missing document ID"); return; } - try { await databases.updateDocument( "6847b5980033f7e274d8", // Database ID @@ -157,7 +156,6 @@ export default function Home() { } }; - return (
Date: Wed, 11 Jun 2025 16:12:46 +0300 Subject: [PATCH 3/6] format doc --- src/app/page.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/page.js b/src/app/page.js index f7f00e6..e73caaf 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -148,7 +148,6 @@ export default function Home() { ); // Set success message setFailedMessage('Todo marked failed!'); - setTimeout(() => setFailedMessage(''), 5000); fetchTodos(); // Refresh the todo list } catch (error) { From 5a60cd0a35e7daee0c875593ee65046ff9ced8d5 Mon Sep 17 00:00:00 2001 From: kenyonyozi Date: Wed, 11 Jun 2025 17:03:54 +0300 Subject: [PATCH 4/6] fix build --- src/app/page.js | 2 -- src/lib/appwrite.js | 6 ++++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/page.js b/src/app/page.js index e73caaf..9bbc2cc 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -20,8 +20,6 @@ export default function Home() { const fileInputRef = useRef(null); - - useEffect(() => { fetchTodos(); }, []); diff --git a/src/lib/appwrite.js b/src/lib/appwrite.js index 5d84560..aeefa94 100644 --- a/src/lib/appwrite.js +++ b/src/lib/appwrite.js @@ -1,8 +1,10 @@ import { Client, Account, Databases, Storage } from "appwrite"; const client = new Client() - .setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT) - .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID); +.setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT ?? "") +.setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID ?? ""); + // .setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT) + // .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID); const account = new Account(client); const databases = new Databases(client); From 4757bb850a1e308a242a861736f1a09e48757546 Mon Sep 17 00:00:00 2001 From: kenyonyozi Date: Wed, 11 Jun 2025 18:11:23 +0300 Subject: [PATCH 5/6] add edit --- src/app/page.js | 158 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 131 insertions(+), 27 deletions(-) diff --git a/src/app/page.js b/src/app/page.js index 9bbc2cc..dcff9bf 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -15,9 +15,13 @@ export default function Home() { const [completeMessage, setCompleteMessage] = useState(''); const [failedMessage, setFailedMessage] = useState(''); const [deleteMessage, setDeleteMessage] = useState(''); + const [editMessage, setEditMessage] = useState(''); + const [isEditing, setIsEditing] = useState(''); + const [editTodo, setEditTodo] = useState(null); const [tab, setTab] = useState('hi'); const [todos, setTodos] = useState([]); + const fileInputRef = useRef(null); useEffect(() => { @@ -153,6 +157,37 @@ export default function Home() { } }; + const handleEdit = (todo) => { + setIsEditing(true); + setEditTodo(todo); + setTitle(todo.title); + }; + + const handleUpdate = async (e) => { + e.preventDefault(); + if (!editTodo) return; + + try { + await databases.updateDocument( + "6847b5980033f7e274d8", // Database ID + "6847b5a9003c48843844", // Collection ID + editTodo.$id, + { + title, + } + ); + // Set success message + setEditMessage('Todo Updated'); + setTimeout(() => setEditMessage(''), 5000); + setTitle(''); + setEditTodo(null); + setIsEditing(false); + fetchTodos(); + } catch (error) { + console.error('Failed to update todo:', error); + } + }; + return (
{deleteMessage}

)} + {editMessage && ( +

{editMessage}

+ )} + {pendingTodos.length === 0 && completeTodos.length === 0 && failedTodos.length === 0 ? (

No todos Added

) : ( - null + null )}
@@ -306,7 +345,6 @@ export default function Home() { /> ) : (
-
)} @@ -361,15 +399,37 @@ export default function Home() { )}
- + + + ) : ( + + )} + + + ) : ( + + )} + {isEditing && editTodo?.$id === todo.$id ? ( +
+ setTitle(e.target.value)} + className="mt-2 block w-full border rounded-sm border-gray-100 p-2 " + placeholder="What needs to be done?" + autoFocus + /> + + +
+ ) : ( + + )}
- + {/* top */}
{pendingTodos.length}
@@ -217,6 +224,7 @@ export default function Home() {
+ {/* tabs */}
- + {/* completed */}

Completed ({completeTodos.length})

{completeTodos.map((todo) => ( @@ -594,6 +603,7 @@ export default function Home() { ))}
+ {/* failed */}

Failed ({failedTodos.length})