11"use client" ;
2- import { useState } from "react" ;
2+ import { useEffect , useState } from "react" ;
33import { Circle , X } from "lucide-react" ;
44import Navbar from "../components/Navbar" ;
5+ import {
6+ useConnect ,
7+ useContract ,
8+ useReadContract ,
9+ useSendTransaction ,
10+ } from "@starknet-react/core" ;
11+ import { TODO_ABI } from "@/constants/abi" ;
12+ import { TODO_CONTRACT_ADDRESS } from "@/constants" ;
13+ import { shortString } from "starknet" ;
514
615type Todo = {
716 id : string ;
@@ -10,25 +19,63 @@ type Todo = {
1019} ;
1120
1221export default function TodoList ( ) {
13- const [ todos , setTodos ] = useState < Todo [ ] > ( [
14- { id : "1" , text : "Join Starknet Discord" , status : "pending" } ,
15- { id : "2" , text : "Write your first Cairo contract" , status : "pending" } ,
16- { id : "3" , text : "Deploy a dApp on Starknet" , status : "completed" } ,
17- ] ) ;
22+ const [ todos , setTodos ] = useState < Todo [ ] > ( ) ;
1823 const [ input , setInput ] = useState ( "" ) ;
1924
25+ const { sendAsync } = useSendTransaction ( { calls : [ ] } ) ;
26+ const { contract } = useContract ( {
27+ abi : TODO_ABI ,
28+ address : TODO_CONTRACT_ADDRESS ,
29+ } ) ;
30+
31+ const { data, isFetching, error } = useReadContract ( {
32+ abi : TODO_ABI ,
33+ address : TODO_CONTRACT_ADDRESS ,
34+ functionName : "get_todo_list" ,
35+ args : [ ] ,
36+ } ) ;
37+
2038 const addTodo = async ( ) => {
21- // add todo
39+ if ( ! input ) return ;
40+ if ( input . length > 31 ) alert ( "Text can not be more than 31 characters" ) ;
41+
42+ const calls = contract ?. populate ( "add_todo" , [ input ] ) ;
43+ if ( calls ) {
44+ await sendAsync ( [ calls ] ) ;
45+ alert ( "Todo added succesfully" ) ;
46+ }
2247 } ;
2348
24- const deleteTodo = async ( index : number ) => {
49+ const deleteTodo = async ( id : number ) => {
50+ const calls = contract ?. populate ( "delete_todo" , [ id ] ) ;
51+ if ( calls ) {
52+ await sendAsync ( [ calls ] ) ;
53+ alert ( "Todo deleted successfully" ) ;
54+ }
55+
2556 // delete todo
2657 } ;
2758
28- const toggleStatus = async ( index : number ) => {
29- // toggle status
59+ const toggleStatus = async ( id : number ) => {
60+ const calls = contract ?. populate ( "complete_todo" , [ id ] ) ;
61+ if ( calls ) {
62+ await sendAsync ( [ calls ] ) ;
63+ alert ( "Todo status changed successfully" ) ;
64+ }
3065 } ;
3166
67+ useEffect ( ( ) => {
68+ if ( data && Array . isArray ( data ) ) {
69+ const result = data . map ( ( todo ) => ( {
70+ id : shortString . decodeShortString ( todo . id . toString ( ) ) ,
71+ text : shortString . decodeShortString ( todo . todo_description . toString ( ) ) ,
72+ status : shortString . decodeShortString ( todo . status . toString ( ) ) ,
73+ } ) ) ;
74+
75+ setTodos ( result ) ;
76+ }
77+ } , [ data ] ) ;
78+
3279 return (
3380 < div className = "min-h-screen bg-[#0d1117] text-white " >
3481 < Navbar />
@@ -57,46 +104,50 @@ export default function TodoList() {
57104 </ button >
58105 </ div >
59106
60- < ul className = "space-y-5" >
61- { todos &&
62- todos . map ( ( { status, text } , index ) => (
63- < li
64- key = { index }
65- className = "flex items-center justify-between px-6 py-4 rounded-2xl bg-[#161b22] hover:shadow-lg transition-all duration-300 border border-transparent hover:border-[#5C94FF]"
66- >
67- < div
68- className = { `flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4 cursor-pointer ${
69- status == "completed"
70- ? "text-gray-500 line-through"
71- : "text-white font-medium"
72- } `}
73- onClick = { ( ) => toggleStatus ( index ) }
107+ { isFetching ? (
108+ < p className = "text-center" > Loading...</ p >
109+ ) : (
110+ < ul className = "space-y-5" >
111+ { todos &&
112+ todos . map ( ( { status, text, id } , index ) => (
113+ < li
114+ key = { index }
115+ className = "flex items-center justify-between px-6 py-4 rounded-2xl bg-[#161b22] hover:shadow-lg transition-all duration-300 border border-transparent hover:border-[#5C94FF]"
74116 >
75- < div className = "flex items-center gap-3" >
76- < Circle className = "text-[#5C94FF] w-5 h-5 shrink-0" />
77- < span className = "text-sm md:text-base" > { text } </ span >
78- </ div >
79-
80- < span
81- className = { `text-xs py-1 px-3 rounded-full font-semibold ${
117+ < div
118+ className = { `flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4 cursor-pointer ${
82119 status == "completed"
83- ? "bg-green-700 text-green-300 "
84- : "bg-yellow-700 text-yellow-300 "
120+ ? "text-gray-500 line-through "
121+ : "text-white font-medium "
85122 } `}
123+ onClick = { ( ) => toggleStatus ( Number ( id ) ) }
86124 >
87- { status }
88- </ span >
89- </ div >
125+ < div className = "flex items-center gap-3" >
126+ < Circle className = "text-[#5C94FF] w-5 h-5 shrink-0" />
127+ < span className = "text-sm md:text-base" > { text } </ span >
128+ </ div >
90129
91- < button
92- onClick = { ( ) => deleteTodo ( index ) }
93- className = "text-gray-400 hover:text-red-500 transition"
94- >
95- < X className = "w-5 h-5" />
96- </ button >
97- </ li >
98- ) ) }
99- </ ul >
130+ < span
131+ className = { `text-xs py-1 px-3 rounded-full font-semibold ${
132+ status == "completed"
133+ ? "bg-green-700 text-green-300"
134+ : "bg-yellow-700 text-yellow-300"
135+ } `}
136+ >
137+ { status }
138+ </ span >
139+ </ div >
140+
141+ < button
142+ onClick = { ( ) => deleteTodo ( index ) }
143+ className = "text-gray-400 hover:text-red-500 transition"
144+ >
145+ < X className = "w-5 h-5" />
146+ </ button >
147+ </ li >
148+ ) ) }
149+ </ ul >
150+ ) }
100151 </ div >
101152 </ div >
102153 </ div >
0 commit comments