Skip to content

Commit 25dd030

Browse files
committed
feat: единый интерфейс для работы с model
1 parent 60c66bc commit 25dd030

File tree

12 files changed

+185
-172
lines changed

12 files changed

+185
-172
lines changed

src/js/fetchRssData.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import axios from "axios";
2-
import { errorsHandler } from "./model.js";
2+
import { model } from "./model/index.js";
33

44
export const fetchRssData = (link) => {
55
const proxyUrl = `https://allorigins.hexlet.app/raw?url=${encodeURIComponent(link)}&disableCache=true`;
@@ -10,9 +10,7 @@ export const fetchRssData = (link) => {
1010
return response.data;
1111
})
1212
.catch((error) => {
13-
errorsHandler(error, "fetch");
14-
console.error("fetching or parsing error:", error);
13+
model.error.handle(error, "fetch");
1514
throw error;
1615
});
1716
};
18-

src/js/index.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,3 @@ import "../i18n.js";
22
import { initApp } from "./main.js";
33

44
initApp();
5-
6-
// validateInput -> fetchRssData -> parseRss -> state -> render

src/js/main.js

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,23 @@
11
import { view } from "./view/index.js";
2-
import {
3-
updateInputValue,
4-
addRssFeed,
5-
validateInput,
6-
setActivePost,
7-
feedsChecking,
8-
} from "./model.js";
2+
import { model } from "./model/index.js";
93

104
export const initApp = () => {
115
view.ui.renderUIText();
12-
feedsChecking();
6+
model.update.startFeedChecks();
137

148
const input = document.querySelector("#url-input");
159
const form = document.querySelector("#rss-form");
1610
const postsContainer = document.querySelector(".posts");
1711
const closeModalBtns = document.querySelectorAll('[data-bs-dismiss="modal"]');
1812

1913
input.addEventListener("input", (e) => {
20-
updateInputValue(e.target.value);
14+
model.form.updateInputValue(e.target.value);
2115
});
2216

2317
form.addEventListener("submit", (e) => {
2418
e.preventDefault();
25-
validateInput()
26-
.then(() => addRssFeed())
19+
model.form.validateInput()
20+
.then(() => model.feed.add())
2721
.catch((error) => {
2822
console.log("валидация не пройдена:", error.message);
2923
});
@@ -32,13 +26,13 @@ export const initApp = () => {
3226
postsContainer.addEventListener("click", (e) => {
3327
const button = e.target.closest(".modal-btn");
3428
if (button && button.dataset.id) {
35-
setActivePost(button.dataset.id);
29+
model.post.setActive(button.dataset.id);
3630
}
3731
});
3832

3933
closeModalBtns.forEach((btn) => {
4034
btn.addEventListener('click', () => {
41-
setActivePost(null);
35+
model.post.setActive(null);
4236
});
4337
});
4438
};

src/js/model.js

Lines changed: 0 additions & 144 deletions
This file was deleted.

src/js/model/error.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import state from "../state.js";
2+
3+
export const handle = (error, type) => {
4+
switch (type) {
5+
case "fetch":
6+
console.error("Network error:", type, error);
7+
state.ui.error = "network";
8+
break;
9+
case "parse":
10+
console.error("Parse error:", type, error);
11+
state.ui.error = "noRss";
12+
break;
13+
default:
14+
console.error("Unknown error:", error);
15+
state.ui.error = "no_details";
16+
break;
17+
}
18+
};

src/js/model/feed.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import state from "../state";
2+
import { fetchRssData } from "../fetchRssData.js";
3+
import { parseRss } from "../parseRss.js";
4+
5+
import { addNew } from "./post.js";
6+
import { handle } from "./error.js";
7+
8+
export const fetchAndParse = (url) => {
9+
state.ui.pending = true;
10+
// state.ui.error = null;
11+
return fetchRssData(url)
12+
.then((xmlString) => {
13+
state.ui.pending = false;
14+
state.ui.success = true;
15+
return parseRss(xmlString);
16+
})
17+
.catch((error) => {
18+
state.ui.pending = false;
19+
handle(error, error.message === "noRss" ? "parse" : "fetch");
20+
throw error;
21+
});
22+
};
23+
24+
export const updateState = ({ channel, items }) => {
25+
state.feeds.push(channel);
26+
state.feedsList.push(state.form.inputValue);
27+
addNew(items);
28+
state.form.inputValue = "";
29+
// state.ui.error = null;
30+
};
31+
32+
export const add = () => {
33+
const url = state.form.inputValue;
34+
return fetchAndParse(url)
35+
.then(({ channel, items }) => {
36+
updateState({ channel, items });
37+
// state.ui.error = null;
38+
})
39+
.catch((error) => {
40+
handle(error, error.message === "noRss" ? "parse" : "fetch");
41+
throw error;
42+
});
43+
};

src/js/model/form.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import * as yup from "yup";
2+
3+
import state from "../state.js";
4+
5+
const schema = yup
6+
.string()
7+
.url("notUrl")
8+
.required("required")
9+
.test(
10+
"no-duplicate",
11+
"exists",
12+
(value) => !state.feedsList.includes(value)
13+
);
14+
15+
export const validateInput = () => {
16+
state.ui.success = false;
17+
return schema
18+
.validate(state.form.inputValue)
19+
.then(() => {
20+
state.ui.error = null;
21+
return state.form.inputValue;
22+
})
23+
.catch((error) => {
24+
state.ui.error = error.errors.join();
25+
throw error;
26+
});
27+
};
28+
29+
export const updateInputValue = (value) => {
30+
if (value === null) return;
31+
state.form.inputValue = value;
32+
if (state.ui.error) state.ui.error = null;
33+
};

src/js/model/index.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as update from "./update.js";
2+
import * as form from "./form.js";
3+
import * as feed from "./feed.js";
4+
import * as post from "./post.js";
5+
import * as error from "./error.js";
6+
7+
export const model = {
8+
form,
9+
feed,
10+
post,
11+
update,
12+
error,
13+
};

src/js/model/post.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import state from "../state.js";
2+
3+
export const addNew = (posts) => {
4+
const existingIds = new Set(state.posts.map((post) => post.id));
5+
const newPosts = posts
6+
.filter((post) => !existingIds.has(post.id))
7+
.map((post) => ({ ...post, viewed: false }));
8+
state.posts.unshift(...newPosts);
9+
};
10+
11+
export const setActive = (id) => {
12+
if (id === null) {
13+
state.activeItem = null;
14+
return;
15+
}
16+
state.activeItem = state.posts.find((post) => post.id === id);
17+
};
18+
19+
export const markAsRead = (id) => {
20+
const post = state.posts.find((post) => post.id === id);
21+
if (post && !post.viewed) {
22+
post.viewed = true;
23+
}
24+
};

src/js/model/update.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import state from "../state.js";
2+
import { fetchAndParse } from "./feed.js";
3+
import { addNew } from "./post.js";
4+
5+
export const checkFeeds = () => {
6+
const promises = state.feedsList.map((feed) => {
7+
return fetchAndParse(feed)
8+
.then(({ items }) => {
9+
return items;
10+
})
11+
.catch((error) => {
12+
console.error("Ошибка проверки фида:", feed, error.message);
13+
return [];
14+
});
15+
});
16+
17+
return Promise.all(promises).then((results) => {
18+
const newPosts = results.flat();
19+
addNew(newPosts);
20+
});
21+
};
22+
23+
export const startFeedChecks = () => {
24+
if (state.feeds.length === 0) {
25+
return;
26+
}
27+
checkFeeds()
28+
.then(() => {
29+
setTimeout(startFeedChecks, 10000);
30+
})
31+
.catch((error) => {
32+
console.error(error.message);
33+
setTimeout(startFeedChecks, 10000);
34+
});
35+
};
36+

0 commit comments

Comments
 (0)