Skip to content

Commit 853217e

Browse files
authored
Develop (#6)
* add service for database & Auth * updated * revising * updated * errors resolved * updated * resolved tinymce RTE error
1 parent 6bd0439 commit 853217e

File tree

6 files changed

+269
-88
lines changed

6 files changed

+269
-88
lines changed

src/components/PostCard.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react'
2-
import {Link} from "react-router-dom"
2+
import { Link } from "react-router-dom"
33
import appwriteService from "../appwrite/config.js"
44

55
//* to take the user to the post when he clicks on a post
@@ -15,9 +15,9 @@ function PostCard({
1515
className='w-full justify-center mb-4'
1616
>
1717
<img src={appwriteService.getFilePreview(featuredImage)}
18-
//* this featured image is coming from config.js from the appwrite folder in src. appwriteservice is the instance of a service that intract with appwrite. getfilepreview() is a method provided by this service to retrieve a preview URL for a file stored in Appwrite's storage. featuredImage is a prop passed to the PostCard component
1918
alt={title}
2019
className='rounded-xl'
20+
//* this featured image is coming from config.js from the appwrite folder in src. appwriteservice is the instance of a service that intract with appwrite. getfilepreview() is a method provided by this service to retrieve a preview URL for a file stored in Appwrite's storage. featuredImage is a prop passed to the PostCard component
2121
/>
2222
</div>
2323
<h2 className='text-xl font-bold'>{title}</h2>

src/components/RTE.jsx

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@ import {Editor} from "@tinymce/tinymce-react"
55
//* Real Time Editor (TinyMCE)
66
//? for this purpose TinyMCE is used
77

8-
//* Real Time Editor (TinyMCE)
9-
10-
//? for this purpose TinyMCE is used
11-
128
function RTE({
139
name, control, label, defaultValue = ""
1410
}) {
@@ -27,31 +23,55 @@ function RTE({
2723
defaultValue={defaultValue} // Ensure default value is passed
2824
render={({field: {onChange, value}}) => (
2925
<Editor
26+
apiKey='qtbgqygyym3ge1iyd6pirieis90hezuz1pe6a4qwzb5z9uu8'
3027
value={value || defaultValue} // Initialize with the current value or default
3128
init={{
3229
branding: false,
3330
height: 500,
3431
menubar: true,
3532
apiKey: apiKey,
36-
plugins: [ //? same from the documentation of tinymce
37-
"image",
38-
"advlist",
39-
"autolink",
40-
"lists",
41-
"link",
42-
"image",
43-
"charmap",
44-
"preview",
45-
"anchor",
46-
"searchreplace",
47-
"visualblocks",
48-
"code",
49-
"fullscreen",
50-
"insertdatetime",
51-
"media",
52-
"table",
53-
"help",
54-
"wordcount"
33+
plugins: [
34+
//? same from the documentation of tinymce as needed
35+
// Core editing features
36+
'anchor',
37+
'autolink',
38+
'charmap',
39+
'codesample',
40+
'emoticons',
41+
'image',
42+
'link',
43+
'lists',
44+
'media',
45+
'searchreplace',
46+
'table',
47+
'visualblocks',
48+
'wordcount',
49+
'checklist',
50+
'mediaembed',
51+
'casechange',
52+
'export',
53+
'formatpainter',
54+
'pageembed',
55+
'a11ychecker',
56+
'tinymcespellchecker',
57+
'permanentpen',
58+
'powerpaste',
59+
'advtable',
60+
'advcode',
61+
'editimage',
62+
'advtemplate',
63+
'mentions',
64+
'tableofcontents',
65+
'footnotes',
66+
'mergetags',
67+
'autocorrect',
68+
'typography',
69+
'inlinecss',
70+
'markdown',
71+
// Early access to document converters
72+
'importword',
73+
'exportword',
74+
'exportpdf'
5575
],
5676
toolbar:
5777
"undo redo | blocks | image | bold italic forecolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | help",

src/components/post-form/PostForm.jsx

Lines changed: 61 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,53 +4,74 @@ import Button from "../Button"
44
import Input from "../Input"
55
import RTE from "../RTE"
66
import Select from "../Select"
7-
import appwriteSerice from "../../appwrite/config"
7+
import appwriteService from "../../appwrite/config"
88
import {useSelector } from "react-redux"
99
import {useNavigate} from "react-router-dom"
1010

1111
//* this is the most important form because it uses almost everything that we have built so far
1212

13-
export default function PostForm({post})
13+
export default function PostForm({ post })
1414
{
15-
const {register, handleSubmit, watch, setValue, control, getValues} = useForm({ //? this will duplicate the post
15+
const {register, handleSubmit, watch, setValue, control, getValues, formState: { errors } } = useForm({ //? this will duplicate the post
1616
defaultValues: {
1717
tittle: post?.title || "",
1818
slug: post?.slug || "",
1919
content: post?.content || "",
2020
status: post?.status || "active"
2121
}
22-
})
22+
});
2323

2424
const navigate = useNavigate()
25-
const userData = useSelector((state) => state.auth.userData)
25+
const userData = useSelector((state) => state.auth.userData);
2626

2727
const submit = async(data) => {
28-
if (post) {
29-
const file = data.image[0] ? await appwriteSerice.uploadFile(data.image[0]) : null
3028

31-
if (file) { //? if we already have the post
32-
appwriteSerice.deleteFile(post.featuredImage)
33-
}
34-
const dbPost = await appwriteSerice.updatePost(post.$id, {
35-
...data,
36-
featuredImage: file ? file.$id : undefined
37-
})
38-
if (dbPost) {
39-
navigate(`/post/${dbPost.$id}`)
40-
}
41-
} else { //? if we are uploading a fresh post
42-
const file = await appwriteSerice.uploadFile(data.image[0])
43-
if (file) {
44-
const fileId = file.$id
45-
data.featuredImage = fileId
46-
const dbPost = await appwriteSerice.createPost({...data, userId: userData.$id})
47-
48-
if (dbPost) {
49-
navigate(`/post/${dbPost.$id}`)
29+
// if (post) {
30+
// const file = data.image[0] ? await appwriteSerice.uploadFile(data.image[0]) : null
31+
32+
// if (file) { //? if we already have the post
33+
// appwriteSerice.deleteFile(post.featuredImage)
34+
// }
35+
// const dbPost = await appwriteSerice.updatePost(post.$id, {
36+
// ...data,
37+
// featuredImage: file ? file.$id : undefined
38+
// })
39+
// if (dbPost) {
40+
// navigate(`/post/${dbPost.$id}`)
41+
// }
42+
// } else { //? if we are uploading a fresh post
43+
// const file = await appwriteSerice.uploadFile(data.image[0])
44+
// if (file) {
45+
// const fileId = file.$id
46+
// data.featuredImage = fileId
47+
// const dbPost = await appwriteSerice.createPost({...data, userId: userData.$id})
48+
49+
// if (dbPost) {
50+
// navigate(`/post/${dbPost.$id}`)
51+
// }
52+
// }
53+
// }
54+
55+
56+
try {
57+
let fileId;
58+
if (data.image[0]) {
59+
const file = await appwriteService.uploadFile(data.image[0]);
60+
fileId = file?.$id;
61+
if (post?.featuredImage) {
62+
await appwriteService.deleteFile(post.featuredImage);
5063
}
5164
}
52-
}
5365

66+
const dbPost = post
67+
? await appwriteService.updatePost(post.$id, { ...data, featuredImage: fileId })
68+
: await appwriteService.createPost({ ...data, featuredImage: fileId, userId: userData.$id });
69+
70+
if (dbPost) navigate(`/post/${dbPost.$id}`);
71+
} catch (error) {
72+
console.error("Error in submission:", error);
73+
// Display an error notification to the user
74+
}
5475
}
5576

5677
const slugTransform = useCallback((value) => { //? to create slug from the title
@@ -66,6 +87,7 @@ export default function PostForm({post})
6687
}
6788
})
6889
}, [watch, slugTransform, setValue])
90+
6991
return (
7092
<form onSubmit={handleSubmit(submit)}
7193
className="flex flex-wrap"
@@ -75,8 +97,11 @@ export default function PostForm({post})
7597
label="Title"
7698
placeholder="Title"
7799
className="mb-4"
78-
{...register("title", {required: true})} //? we have to register input inside the hooks so that they are available as values (...register)
100+
{...register("title", { required: true })} //? we have to register input inside the hooks so that they are available as values (...register)
79101
/>
102+
{errors.title && <p className="text-red-500">{errors.title.message}</p>}
103+
104+
80105
<Input
81106
label="Slug :"
82107
placeholder="Slug"
@@ -85,6 +110,8 @@ export default function PostForm({post})
85110
onInput={(e) => { //? this input field is setting some values
86111
setValue("slug", slugTransform(e.currentTarget.value), {shouldValidate: true})
87112
}}
113+
// {errors.slug && <p className="text-red-500">{errors.slug.message}</p>}
114+
88115
/>
89116
<RTE
90117
label="Content: "
@@ -102,6 +129,9 @@ export default function PostForm({post})
102129
accept="image/png, image/jpg, image/jpeg" //? what type of data to accept
103130
{...register("image", {required: !post})}
104131
/>
132+
{errors.image && <p className="text-red-500">{errors.image.message}</p>}
133+
134+
105135
{post && (
106136
<div className="w-full mb-4">
107137
<img src={appwriteSerice.getFilePreview(post.featuredImage)} alt={post.title}
@@ -116,6 +146,9 @@ export default function PostForm({post})
116146
className="mb-4"
117147
{...register("status", {required: true})}
118148
/>
149+
{errors.status && <p className="text-red-500">{errors.status.message}</p>}
150+
151+
119152
<Button
120153
type="submit"
121154
bgColor={post ? "bg-green-500": undefined}

src/main.jsx

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react'
22
import ReactDOM from 'react-dom/client'
33
import App from './App.jsx'
44
import './index.css'
5-
import {createBrowserRouter, RouterProvider} from "react-router-dom"
5+
import { createBrowserRouter, RouterProvider } from "react-router-dom";
66
import { Provider } from 'react-redux'
77
import store from "./store/store.js"
88

@@ -15,13 +15,17 @@ import AddPost from "./pages/AddPost.jsx"
1515
import EditPost from "./pages/EditPost.jsx"
1616
import Post from "./pages/Post.jsx"
1717

18+
19+
20+
//? when we import and use createBrowserRouter
21+
1822
const router = createBrowserRouter([
1923
{
2024
path: "/",
2125
element: <App />,
2226
children: [ //? all the subpaths go into children
2327
{
24-
path: "/",
28+
path: "/React-appwrite_blogApp",
2529
element: <Home />
2630
},
2731
{
@@ -70,17 +74,89 @@ const router = createBrowserRouter([
7074
<Protected authentication>
7175
<Post />
7276
</Protected>
73-
)
74-
}
75-
]
76-
}
77-
])
77+
),
78+
},
79+
],
80+
},
81+
],
82+
{
83+
basename: '/React-appwrite_blogApp'
84+
} // Set the basename for routing, which will comes first from every component
85+
86+
);
7887

7988

8089
ReactDOM.createRoot(document.getElementById('root')).render(
8190
<React.StrictMode>
8291
<Provider store={store}>
8392
<RouterProvider router={router} />
8493
</Provider>
85-
</React.StrictMode>,
86-
)
94+
</React.StrictMode>
95+
)
96+
97+
98+
99+
100+
//? when we import and use { import {BrowserRouter, Routes, Route} from "react-router-dom" }
101+
102+
// ReactDOM.createRoot(document.getElementById("root")).render(
103+
// <React.StrictMode>
104+
// <Provider store={store}>
105+
// <BrowserRouter>
106+
// <Routes>
107+
// <Route path="/" element={<App />}>
108+
// <Route index element={<Home />} />
109+
// <Route
110+
// path="/login"
111+
// element={
112+
// <Protected authentication={false}>
113+
// <Login />
114+
// </Protected>
115+
// }
116+
// />
117+
// <Route
118+
// path="/signup"
119+
// element={
120+
// <Protected authentication={false}>
121+
// <Signup />
122+
// </Protected>
123+
// }
124+
// />
125+
// <Route
126+
// path="/all-posts"
127+
// element={
128+
// <Protected authentication>
129+
// <AllPosts />
130+
// </Protected>
131+
// }
132+
// />
133+
// <Route
134+
// path="/add-post"
135+
// element={
136+
// <Protected authentication>
137+
// <AddPost />
138+
// </Protected>
139+
// }
140+
// />
141+
// <Route
142+
// path="/edit-post/:slug"
143+
// element={
144+
// <Protected authentication>
145+
// <EditPost />
146+
// </Protected>
147+
// }
148+
// />
149+
// <Route
150+
// path="/post/:slug"
151+
// element={
152+
// <Protected authentication>
153+
// <Post />
154+
// </Protected>
155+
// }
156+
// />
157+
// </Route>
158+
// </Routes>
159+
// </BrowserRouter>
160+
// </Provider>
161+
// </React.StrictMode>
162+
// );

0 commit comments

Comments
 (0)