Skip to content

Commit 69963a0

Browse files
authored
Merge pull request #1 from NoroffFEU/api-client
Api client
2 parents a10654e + d7af0f1 commit 69963a0

16 files changed

+413
-248
lines changed

about.html

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>About</title>
7+
<link rel="stylesheet" href="css/style.css" />
8+
<link rel="stylesheet" href="css/navbarfooter.css" />
9+
<link rel="stylesheet" href="css/mainfonts.css" />
10+
11+
<!-- <link rel="colorvariations" href="css/variables.css" /> -->
12+
<style>
13+
@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap");
14+
@import url("https://fonts.googleapis.com/css2?family=Raleway:ital,wght@0,100..900;1,100..900&display=swap");
15+
</style>
16+
</head>
17+
<body>
18+
<header>
19+
<nav>
20+
<div id="top-line">
21+
<div class="line-one">
22+
<a href="index.html">Sprinkled Bliss</a>
23+
<h4>
24+
THIS BLOG IS ABOUT ALL OF THE SWEET PASTERY I MAKE EVERY DAY TO
25+
BRING JOY TO MY -AND YOUR LIFE
26+
</h4>
27+
</div>
28+
29+
<div class="line-two">
30+
<div id="hamburger-menu">
31+
<div class="menu-btn">
32+
<div class="line"></div>
33+
<div class="line"></div>
34+
<div class="line"></div>
35+
<div class="line"></div>
36+
</div>
37+
<div id="login-create">
38+
<div class="log-in"></div>
39+
<div class="create-account"></div>
40+
</div>
41+
</div>
42+
</div>
43+
</div>
44+
<div id="bottom-line">
45+
<div class="nav-btn">
46+
<a href="post/create.html" id="new-post"><h4>New post</h4></a>
47+
</div>
48+
<div class="nav-btn">
49+
<a href="index.html"><h4>Home</h4></a>
50+
</div>
51+
<div class="nav-btn">
52+
<a href="#"><h4>About</h4></a>
53+
</div>
54+
</div>
55+
</nav>
56+
</header>

account/login.html

+3-3
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ <h4>
4242
</div>
4343
<div id="bottom-line">
4444
<div class="nav-btn">
45-
<a href="../post/create.html"><h4>New post</h4></a>
45+
<a href="../post/create.html" id="new-post"><h4>New post</h4></a>
4646
</div>
4747
<div class="nav-btn">
4848
<a href="../index.html"><h4>Home</h4></a>
@@ -128,7 +128,7 @@ <h6>
128128
</h6>
129129
</div>
130130
</footer>
131-
<script src="/FED1-PE1-AilinMari/js/login.js"></script>
132-
<script src="/FED1-PE1-AilinMari/js/navbar.js"></script>
131+
<script src="/FED1-PE1-AilinMari/js/login.js" type="module"></script>
132+
<script src="/FED1-PE1-AilinMari/js/navbar.js" type="module"></script>
133133
</body>
134134
</html>

account/register.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ <h4>
4141
</div>
4242
<div id="bottom-line">
4343
<div class="nav-btn">
44-
<a href="../post/create.html"><h4>New post</h4></a>
44+
<a href="../post/create.html" id="new-post"><h4>New post</h4></a>
4545
</div>
4646
<div class="nav-btn">
4747
<a href="../index.html"><h4>Home</h4></a>

index.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@ <h4>
4343
</div>
4444
<div id="bottom-line">
4545
<div class="nav-btn">
46-
<a href="post/create.html"><h4>New post</h4></a>
46+
<a href="post/create.html" id="new-post"><h4>New post</h4></a>
4747
</div>
4848
<div class="nav-btn">
4949
<a href="index.html"><h4>Home</h4></a>
5050
</div>
5151
<div class="nav-btn">
52-
<a href="#"><h4>About</h4></a>
52+
<a href="about.html"><h4>About</h4></a>
5353
</div>
5454
</div>
5555
</nav>

js/api-client.js

+226
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
export class BlogApi {
2+
constructor() {
3+
this.baseUrl = "https://v2.api.noroff.dev";
4+
this.blogName = this.getBlogName();
5+
this.blogUrl = `${this.baseUrl}/blog/posts/${this.blogName}`;
6+
this.authUrl = `${this.baseUrl}/auth`;
7+
}
8+
9+
/**
10+
* Helper method for performing fetch requests.
11+
* @param {string} url - The endpoint URL.
12+
* @param {object} options - Fetch options.
13+
* @param {string} errorMessage - Error message for failures.
14+
* @returns {Promise<any>} Parsed JSON response.
15+
*/
16+
async _request(url, options, errorMessage) {
17+
try {
18+
const response = await fetch(url, options);
19+
if (!response.ok) {
20+
throw new Error(`${errorMessage}. Status: ${response.status}`);
21+
}
22+
return await response.json();
23+
} catch (error) {
24+
console.error(errorMessage, error);
25+
throw error;
26+
}
27+
}
28+
29+
/**
30+
* Retrieves the blog name from local storage.
31+
* @returns {string} The blog name.
32+
*/
33+
getBlogName() {
34+
const loggedInUserName = localStorage.getItem("name");
35+
return loggedInUserName ? loggedInUserName : "ailin_user";
36+
}
37+
38+
/**
39+
* Fetches a single blog post by ID.
40+
* @param {string} postId - The ID of the blog post.
41+
* @returns {Promise<any>} The blog post data.
42+
*/
43+
async getBlogpostByID(postId) {
44+
const url = `${this.blogUrl}/${postId}`;
45+
const { data } = await this._request(url, {}, "Error fetching blogpost");
46+
return data;
47+
}
48+
49+
/**
50+
* Fetches all blog posts.
51+
* @returns {Promise<any>} An array of blog posts.
52+
*/
53+
async getBlogposts() {
54+
const { data } = await this._request(
55+
this.blogUrl,
56+
{},
57+
"Error fetching blogposts"
58+
);
59+
return data;
60+
}
61+
62+
/**
63+
* Creates a new blog post.
64+
* @param {string} title - The title of the blog post.
65+
* @param {string} content - The body content.
66+
* @param {string} imageUrl - The URL of the media.
67+
* @param {string} [imageAlt="Default image description"] - The media description.
68+
* @returns {Promise<any>} The created blog post data.
69+
*/
70+
async createBlogpost(
71+
title,
72+
content,
73+
imageUrl,
74+
imageAlt = "Default image description"
75+
) {
76+
const accessToken = localStorage.getItem("accessToken");
77+
if (!accessToken) {
78+
// Navigation to login page can be handled here if needed.
79+
return;
80+
}
81+
const data = {
82+
title,
83+
body: content,
84+
media: {
85+
url: imageUrl,
86+
alt: imageAlt,
87+
},
88+
};
89+
90+
const options = {
91+
method: "POST",
92+
headers: {
93+
"Content-Type": "application/json",
94+
Authorization: `Bearer ${accessToken}`,
95+
},
96+
body: JSON.stringify(data),
97+
};
98+
99+
return await this._request(
100+
this.blogUrl,
101+
options,
102+
"Error creating blog post"
103+
);
104+
}
105+
106+
/**
107+
* Updates a blog post by ID.
108+
* @param {string} postId - The ID of the blog post.
109+
* @param {string} title - The title of the blog post.
110+
* @param {string} content - The body content.
111+
* @param {string} imageUrl - The URL of the media.
112+
* @param {string} [imageAlt="Default image description"] - The media description.
113+
* @returns {Promise<any>} The updated blog post data.
114+
*/
115+
async updateBlogpost(
116+
postId,
117+
title,
118+
content,
119+
imageUrl,
120+
imageAlt = "Default image description"
121+
) {
122+
const accessToken = localStorage.getItem("accessToken");
123+
if (!accessToken) {
124+
return;
125+
}
126+
const data = {
127+
title,
128+
body: content,
129+
media: {
130+
url: imageUrl,
131+
alt: imageAlt,
132+
},
133+
};
134+
135+
const options = {
136+
method: "PUT",
137+
headers: {
138+
"Content-Type": "application/json",
139+
Authorization: `Bearer ${accessToken}`,
140+
},
141+
body: JSON.stringify(data),
142+
};
143+
144+
return await this._request(
145+
`${this.blogUrl}/${postId}`,
146+
options,
147+
"Error updating blog post"
148+
);
149+
}
150+
151+
/**
152+
* Deletes a blog post by ID.
153+
* @param {string} postId - The ID of the blog post.
154+
* @returns {Promise<void>}
155+
*/
156+
async deleteBlogpost(postId) {
157+
const accessToken = localStorage.getItem("accessToken");
158+
if (!accessToken) {
159+
return;
160+
}
161+
const options = {
162+
method: "DELETE",
163+
headers: {
164+
Authorization: `Bearer ${accessToken}`,
165+
},
166+
};
167+
168+
await this._request(
169+
`${this.blogUrl}/${postId}`,
170+
options,
171+
"Error deleting blog post"
172+
);
173+
console.log("Blog post deleted:", postId);
174+
}
175+
176+
/**
177+
* Logs in a user.
178+
* @param {string} email - The user's email.
179+
* @param {string} password - The user's password.
180+
* @returns {Promise<any>} User data.
181+
*/
182+
async login(email, password) {
183+
const body = { email, password };
184+
const options = {
185+
method: "POST",
186+
headers: {
187+
"Content-Type": "application/json",
188+
accept: "application/json",
189+
},
190+
body: JSON.stringify(body),
191+
};
192+
193+
const { data } = await this._request(
194+
`${this.authUrl}/login`,
195+
options,
196+
"Login failed"
197+
);
198+
return data;
199+
}
200+
201+
/**
202+
* Registers a new user.
203+
* @param {string} name - The user's name.
204+
* @param {string} email - The user's email.
205+
* @param {string} password - The user's password.
206+
* @returns {Promise<any>} Registration data.
207+
*/
208+
async register(name, email, password) {
209+
const body = { name, email, password };
210+
const options = {
211+
method: "POST",
212+
headers: {
213+
"Content-Type": "application/json",
214+
accept: "application/json",
215+
},
216+
body: JSON.stringify(body),
217+
};
218+
219+
const { data } = await this._request(
220+
`${this.authUrl}/register`,
221+
options,
222+
"Registration failed"
223+
);
224+
return data;
225+
}
226+
}

js/blogpost.js

+6-28
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
const sprinkledBliss = "https://v2.api.noroff.dev/blog/posts/ailin_user";
1+
import { BlogApi } from "./api-client.js";
2+
let blogApi = new BlogApi();
23

34
const urlParams = new URLSearchParams(window.location.search);
45
const postId = urlParams.get("id");
56

67
async function getBlogpostByID() {
78
try {
8-
const response = await fetch(`${sprinkledBliss}/${postId}`);
9-
const { data } = await response.json();
9+
let blogpost = await blogApi.getBlogpostByID(postId);
1010

11-
renderBlogpostbyId(data);
11+
renderBlogpostbyId(blogpost);
1212
} catch (error) {
1313
console.error("Error fetching blogpost", error);
1414
}
@@ -83,32 +83,10 @@ function renderBlogpostbyId(blogpost) {
8383
}
8484

8585
async function deleteBlogpost(postId) {
86-
const url = `https://v2.api.noroff.dev/blog/posts/ailin_user/${postId}`;
87-
const accessToken = localStorage.getItem("accessToken");
88-
if (!accessToken) {
89-
console.error("Please log in.");
90-
return;
91-
}
92-
93-
try {
94-
const response = await fetch(url, {
95-
method: "DELETE",
96-
headers: {
97-
Authorization: `Bearer ${accessToken}`,
98-
},
99-
});
100-
101-
if (!response.ok) {
102-
throw new Error("Failed to delete blog post");
103-
}
86+
await blogApi.deleteBlogpost(postId);
10487

105-
console.log("Blog post deleted:", postId);
88+
window.location.href = `../index.html`;
10689

107-
// Fetch the updated list of blog posts
108-
await getBlogpost();
109-
} catch (error) {
110-
console.error("Error deleting blog post", error);
111-
}
11290
}
11391

11492

0 commit comments

Comments
 (0)