diff --git a/tutorial-react-ts/src/App.tsx b/tutorial-react-ts/src/App.tsx
index 3d7ded3..5559269 100644
--- a/tutorial-react-ts/src/App.tsx
+++ b/tutorial-react-ts/src/App.tsx
@@ -1,33 +1,11 @@
-import { useState } from 'react'
-import reactLogo from './assets/react.svg'
-import viteLogo from '/vite.svg'
import './App.css'
+import BlogApp from './blog/blogApp'
function App() {
- const [count, setCount] = useState(0)
return (
<>
-
- Vite + React
-
-
-
- Edit src/App.tsx
and save to test HMR
-
-
-
- Click on the Vite and React logos to learn more
-
+
>
)
}
diff --git a/tutorial-react-ts/src/blog/blogApp.tsx b/tutorial-react-ts/src/blog/blogApp.tsx
new file mode 100644
index 0000000..2b6729f
--- /dev/null
+++ b/tutorial-react-ts/src/blog/blogApp.tsx
@@ -0,0 +1,24 @@
+import { PostType } from "./definitions/PostType";
+import PostItem from "./ui/PostItem";
+import useHandlePost from "./hooks/useHandlePost";
+
+function BlogApp() {
+
+ const { posts, handleUpdate, handleDelete, handleAddPost } = useHandlePost();
+
+ return (
+
+ {posts.map((post: PostType) => (
+
+ ))}
+
+
);
+}
+
+export default BlogApp
+
+
diff --git a/tutorial-react-ts/src/blog/definitions/PostActionType.ts b/tutorial-react-ts/src/blog/definitions/PostActionType.ts
new file mode 100644
index 0000000..8d327c9
--- /dev/null
+++ b/tutorial-react-ts/src/blog/definitions/PostActionType.ts
@@ -0,0 +1,8 @@
+import { PostType } from "./PostType";
+
+
+
+export type PostActionType = { type: "SET_POSTS"; payload: PostType[]; } |
+{ type: "ADD_POST"; payload: PostType; } |
+{ type: "UPDATE_POST"; payload: { id: number; updatedFields: Partial; }; } |
+{ type: "DELETE_POST"; payload: number; };
diff --git a/tutorial-react-ts/src/blog/definitions/PostItemProps.tsx b/tutorial-react-ts/src/blog/definitions/PostItemProps.tsx
new file mode 100644
index 0000000..d409315
--- /dev/null
+++ b/tutorial-react-ts/src/blog/definitions/PostItemProps.tsx
@@ -0,0 +1,8 @@
+import { PostType } from "./PostType";
+
+
+export type PostItemProps = {
+ post: PostType;
+ handleUpdate: (id: number) => void;
+ handleDelete: (id: number) => void;
+};
diff --git a/tutorial-react-ts/src/blog/definitions/PostType.tsx b/tutorial-react-ts/src/blog/definitions/PostType.tsx
new file mode 100644
index 0000000..bd20633
--- /dev/null
+++ b/tutorial-react-ts/src/blog/definitions/PostType.tsx
@@ -0,0 +1,8 @@
+
+export type PostType = {
+ userId: number;
+ id: number;
+ title: string;
+ body: string;
+};
+
diff --git a/tutorial-react-ts/src/blog/hooks/useHandlePost.tsx b/tutorial-react-ts/src/blog/hooks/useHandlePost.tsx
new file mode 100644
index 0000000..eb14bd5
--- /dev/null
+++ b/tutorial-react-ts/src/blog/hooks/useHandlePost.tsx
@@ -0,0 +1,29 @@
+import usePostData from "./usePostData";
+
+function useHandlePost() {
+
+ const { posts,postFunctions } = usePostData()
+
+ const handleAddPost = () => {
+ const newPost = {
+ title: 'Titolo',
+ userId: 1,
+ body: 'Paragrafo inserito'
+ };
+ postFunctions.AddPost(newPost);
+ };
+
+ const handleUpdate = (id: number) => {
+ postFunctions.UpdatePost(id, {
+ title: 'Nuovo Titolo',
+ body: 'Contenuto aggiornato'
+ });
+ };
+
+ const handleDelete = (id: number) => {
+ postFunctions.DeletePost(id);
+ };
+ return { posts,handleUpdate, handleDelete, handleAddPost };
+}
+
+export default useHandlePost
\ No newline at end of file
diff --git a/tutorial-react-ts/src/blog/hooks/usePostData.ts b/tutorial-react-ts/src/blog/hooks/usePostData.ts
new file mode 100644
index 0000000..01af650
--- /dev/null
+++ b/tutorial-react-ts/src/blog/hooks/usePostData.ts
@@ -0,0 +1,92 @@
+import { useEffect, useReducer } from "react";
+import {postReducer} from "../reducer/postReducer";
+import { PostType } from "../definitions/PostType";
+
+function usePostData() {
+ const [posts,dispatch] = useReducer(postReducer,[])
+
+ useEffect(() => {
+ fetch("https://jsonplaceholder.typicode.com/posts")
+ .then((response) => response.json())
+ .then((data) => dispatch({type:'SET_POSTS', payload:data}));
+ }, []);
+
+ const postFunctions = {
+ AddPost: (newPost: Omit) => {
+ fetch("https://jsonplaceholder.typicode.com/posts", {
+ method: "POST",
+ body: JSON.stringify({
+ title: newPost.title,
+ body: newPost.body,
+ userId: newPost.userId
+ }),
+ headers: {
+ "Content-type": "application/json; charset=UTF-8",
+ },
+ })
+ .then((response) => {
+ if (!response.ok) throw new Error("Errore nell'invio del post");
+ return response.json();
+ })
+ .then((json) => {
+ dispatch({type:'ADD_POST', payload:json})
+ console.log("Post aggiunto:", json);
+ })
+ .catch((error) => console.error("Errore:", error));
+ },
+ UpdatePost: (id: number, updateFields: Partial) => {
+ const postUpdate = posts.find((post:PostType) => post.id === id)
+
+ if (!postUpdate) {
+ console.error(`Post non trovato per l'id:`, id);
+ return
+ }
+
+
+ fetch(`https://jsonplaceholder.typicode.com/posts/${id}`, {
+ method: "PUT",
+ body: JSON.stringify({
+ ...postUpdate,
+ ...updateFields,
+ }),
+ headers: {
+ "Content-type": "application/json; charset=UTF-8",
+ },
+ })
+ .then((response) => {
+ if (!response.ok) throw new Error("Errore nell'aggiornamento del post");
+ return response.json();
+ })
+ .then((json) => {
+ dispatch({type:'UPDATE_POST', payload:{id,updatedFields:json}})
+ window.confirm("Post aggiornato");
+ })
+ .catch((error) => console.error("Errore:", error));
+ },
+ DeletePost: (id: number) => {
+ if (!window.confirm("Sei sicuro di voler eliminare questo post?")) return;
+
+ fetch(`https://jsonplaceholder.typicode.com/posts/${id}`, {
+ method: "DELETE",
+ })
+ .then((response) => {
+ if (!response.ok) throw new Error("Errore nell'eliminazione del post");
+ window.confirm(`Post con ID ${id} eliminato con successo.`);
+ dispatch({type:'DELETE_POST', payload:id})
+ })
+ .catch((error) =>
+ console.error("Errore durante l'eliminazione del post:", error)
+ );
+ }
+ }
+
+
+ return {
+ posts,
+ postFunctions
+ }
+}
+export default usePostData
+
+
+
diff --git a/tutorial-react-ts/src/blog/reducer/postReducer.ts b/tutorial-react-ts/src/blog/reducer/postReducer.ts
new file mode 100644
index 0000000..dac7ac3
--- /dev/null
+++ b/tutorial-react-ts/src/blog/reducer/postReducer.ts
@@ -0,0 +1,23 @@
+import { PostActionType } from "../definitions/PostActionType";
+import { PostType } from "../definitions/PostType";
+
+
+export function postReducer(state: PostType[], action: PostActionType) {
+ switch (action.type) {
+ case 'SET_POSTS':
+ return action.payload
+ case 'ADD_POST':
+ return [...state, action.payload]
+
+ case "UPDATE_POST":
+ return state.map((post) =>
+ post.id === action.payload.id ?
+ { ...post, ...action.payload.updatedFields }
+ : post
+ )
+ case "DELETE_POST":
+ return state.filter((post) => post.id !== action.payload)
+ default:
+ return state;
+ }
+}
\ No newline at end of file
diff --git a/tutorial-react-ts/src/blog/ui/PostItem.tsx b/tutorial-react-ts/src/blog/ui/PostItem.tsx
new file mode 100644
index 0000000..630ca78
--- /dev/null
+++ b/tutorial-react-ts/src/blog/ui/PostItem.tsx
@@ -0,0 +1,16 @@
+import { PostItemProps } from "../definitions/PostItemProps";
+
+export function PostItem(props: PostItemProps) {
+
+ const {post, handleUpdate, handleDelete} = props;
+
+ return (
+
+
{post.title}
+
{post.body}
+
+
+
+ );
+}
+export default PostItem;