Skip to content

Commit

Permalink
feat: add logic for articles and skeleton
Browse files Browse the repository at this point in the history
  • Loading branch information
sashtje committed Sep 2, 2023
1 parent d40e962 commit 2e360a7
Show file tree
Hide file tree
Showing 39 changed files with 616 additions and 17 deletions.
6 changes: 6 additions & 0 deletions extractedTranslations/en/articles.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"ArticleDetails": "",
"Произошла ошибка при загрузке статьи": "",
"Список статей": "",
"Статья не найдена": ""
}
5 changes: 5 additions & 0 deletions extractedTranslations/en/translation.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"": "",
" ": " ",
"ArticleDetails": "ArticleDetails",
"Profile page": "Profile page",
"decrement": "decrement",
"increment": "increment",
Expand Down Expand Up @@ -33,11 +34,15 @@
"Произошла непредвиденная ошибка": "Произошла непредвиденная ошибка",
"Произошла ошибка": "Произошла ошибка",
"Произошла ошибка при загрузке профиля": "Произошла ошибка при загрузке профиля",
"Произошла ошибка при загрузке статьи": {
"": ""
},
"Профиль": "Профиль",
"Редактировать": "Редактировать",
"Сохранить": "Сохранить",
"Список статей": "Список статей",
"Статья": "Статья",
"Статья не найдена": "Статья не найдена",
"Страна": "Страна",
"Страница не найдена": "Страница не найдена",
"Форма авторизации": "Форма авторизации",
Expand Down
5 changes: 5 additions & 0 deletions extractedTranslations/ru/translation.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"": "",
" ": " ",
"ArticleDetails": "ArticleDetails",
"Profile page": "Profile page",
"decrement": "decrement",
"increment": "increment",
Expand Down Expand Up @@ -33,11 +34,15 @@
"Произошла непредвиденная ошибка": "Произошла непредвиденная ошибка",
"Произошла ошибка": "Произошла ошибка",
"Произошла ошибка при загрузке профиля": "Произошла ошибка при загрузке профиля",
"Произошла ошибка при загрузке статьи": {
"": ""
},
"Профиль": "Профиль",
"Редактировать": "Редактировать",
"Сохранить": "Сохранить",
"Список статей": "Список статей",
"Статья": "Статья",
"Статья не найдена": "Статья не найдена",
"Страна": "Страна",
"Страница не найдена": "Страница не найдена",
"Форма авторизации": "Форма авторизации",
Expand Down
97 changes: 94 additions & 3 deletions json-server/db.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,109 @@
"author": "typicode"
}
],
"articles": [
{
"id": "1",
"title": "JavaScript news",
"subtitle": "Что нового в JS за 2023 год",
"img": "https://teknotower.com/wp-content/uploads/2020/11/js.png",
"views": 1022,
"createdAt": "01.09.2023",
"type": ["IT"],
"blocks": [
{
"id": "1",
"type": "TEXT",
"title": "Заголовок этого блока",
"paragraphs": [
"Программа, которую по традиции называют «Hello, world!», очень проста. Она выводит куда-либо фразу «Hello, world!», или другую подобную, средствами некоего языка.",
"JavaScript — это язык, программы на котором можно выполнять в разных средах. В нашем случае речь идёт о браузерах и о серверной платформе Node.js. Если до сих пор вы не написали ни строчки кода на JS и читаете этот текст в браузере, на настольном компьютере, это значит, что вы буквально в считанных секундах от своей первой JavaScript-программы.",
"Существуют и другие способы запуска JS-кода в браузере. Так, если говорить об обычном использовании программ на JavaScript, они загружаются в браузер для обеспечения работы веб-страниц. Как правило, код оформляют в виде отдельных файлов с расширением .js, которые подключают к веб-страницам, но программный код можно включать и непосредственно в код страницы. Всё это делается с помощью тега <script>. Когда браузер обнаруживает такой код, он выполняет его. Подробности о теге script можно посмотреть на сайте w3school.com. В частности, рассмотрим пример, демонстрирующий работу с веб-страницей средствами JavaScript, приведённый на этом ресурсе. Этот пример можно запустить и средствами данного ресурса (ищите кнопку Try it Yourself), но мы поступим немного иначе. А именно, создадим в каком-нибудь текстовом редакторе (например — в VS Code или в Notepad++) новый файл, который назовём hello.html, и добавим в него следующий код:"
]
},
{
"id": "4",
"type": "CODE",
"code": "<!DOCTYPE html>\n<html>\n <body>\n <p id=\"hello\"></p>\n\n <script>\n document.getElementById(\"hello\").innerHTML = \"Hello, world!\";\n </script>\n </body>\n</html>;"
},
{
"id": "5",
"type": "TEXT",
"title": "Заголовок этого блока",
"paragraphs": [
"Программа, которую по традиции называют «Hello, world!», очень проста. Она выводит куда-либо фразу «Hello, world!», или другую подобную, средствами некоего языка.",
"Существуют и другие способы запуска JS-кода в браузере. Так, если говорить об обычном использовании программ на JavaScript, они загружаются в браузер для обеспечения работы веб-страниц. Как правило, код оформляют в виде отдельных файлов с расширением .js, которые подключают к веб-страницам, но программный код можно включать и непосредственно в код страницы. Всё это делается с помощью тега <script>. Когда браузер обнаруживает такой код, он выполняет его. Подробности о теге script можно посмотреть на сайте w3school.com. В частности, рассмотрим пример, демонстрирующий работу с веб-страницей средствами JavaScript, приведённый на этом ресурсе. Этот пример можно запустить и средствами данного ресурса (ищите кнопку Try it Yourself), но мы поступим немного иначе. А именно, создадим в каком-нибудь текстовом редакторе (например — в VS Code или в Notepad++) новый файл, который назовём hello.html, и добавим в него следующий код:"
]
},
{
"id": "2",
"type": "IMAGE",
"src": "https://hsto.org/r/w1560/getpro/habr/post_images/d56/a02/ffc/d56a02ffc62949b42904ca00c63d8cc1.png",
"title": "Рисунок 1 - скриншот сайта"
},
{
"id": "3",
"type": "CODE",
"code": "const path = require('path');\n\nconst server = jsonServer.create();\n\nconst router = jsonServer.router(path.resolve(__dirname, 'db.json'));\n\nserver.use(jsonServer.defaults({}));\nserver.use(jsonServer.bodyParser);"
},
{
"id": "7",
"type": "TEXT",
"title": "Заголовок этого блока",
"paragraphs": [
"JavaScript — это язык, программы на котором можно выполнять в разных средах. В нашем случае речь идёт о браузерах и о серверной платформе Node.js. Если до сих пор вы не написали ни строчки кода на JS и читаете этот текст в браузере, на настольном компьютере, это значит, что вы буквально в считанных секундах от своей первой JavaScript-программы.",
"Существуют и другие способы запуска JS-кода в браузере. Так, если говорить об обычном использовании программ на JavaScript, они загружаются в браузер для обеспечения работы веб-страниц. Как правило, код оформляют в виде отдельных файлов с расширением .js, которые подключают к веб-страницам, но программный код можно включать и непосредственно в код страницы. Всё это делается с помощью тега <script>. Когда браузер обнаруживает такой код, он выполняет его. Подробности о теге script можно посмотреть на сайте w3school.com. В частности, рассмотрим пример, демонстрирующий работу с веб-страницей средствами JavaScript, приведённый на этом ресурсе. Этот пример можно запустить и средствами данного ресурса (ищите кнопку Try it Yourself), но мы поступим немного иначе. А именно, создадим в каком-нибудь текстовом редакторе (например — в VS Code или в Notepad++) новый файл, который назовём hello.html, и добавим в него следующий код:"
]
},
{
"id": "8",
"type": "IMAGE",
"src": "https://hsto.org/r/w1560/getpro/habr/post_images/d56/a02/ffc/d56a02ffc62949b42904ca00c63d8cc1.png",
"title": "Рисунок 1 - скриншот сайта"
},
{
"id": "9",
"type": "TEXT",
"title": "Заголовок этого блока",
"paragraphs": [
"JavaScript — это язык, программы на котором можно выполнять в разных средах. В нашем случае речь идёт о браузерах и о серверной платформе Node.js. Если до сих пор вы не написали ни строчки кода на JS и читаете этот текст в браузере, на настольном компьютере, это значит, что вы буквально в считанных секундах от своей первой JavaScript-программы."
]
}
]
}
],
"comments": [
{
"id": "1",
"body": "some comment",
"postId": "1"
"text": "some comment 1",
"articleId": "1",
"userId": "1"
},
{
"id": "2",
"text": "some comment 2",
"articleId": "1",
"userId": "1"
},
{
"id": "3",
"text": "some comment 3",
"articleId": "1",
"userId": "1"
}
],
"users": [
{
"id": "1",
"username": "admin",
"password": "123"
"password": "123",
"role": "ADMIN"
},
{
"id": "2",
"username": "user",
"password": "456",
"role": "USER"
}
],
"profile": {
Expand Down
4 changes: 0 additions & 4 deletions public/locales/en/article.json

This file was deleted.

6 changes: 6 additions & 0 deletions public/locales/en/articles.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"Список статей": "List of articles",
"Статья не найдена": "Article not found",
"Произошла ошибка при загрузке статьи": "An error occurred while loading the article",
"Articles page": "Articles"
}
3 changes: 2 additions & 1 deletion public/locales/en/profile.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@
"Нет данных": "No data",
"Имя и фамилия обязательны": "First and last name are required",
"Некорректный возраст": "Incorrect age",
"Некорректная страна": "Incorrect country"
"Некорректная страна": "Incorrect country",
"Profile page": "Profile"
}
4 changes: 0 additions & 4 deletions public/locales/ru/article.json

This file was deleted.

6 changes: 6 additions & 0 deletions public/locales/ru/articles.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"Список статей": "Список статей",
"Статья не найдена": "Статья не найдена",
"Произошла ошибка при загрузке статьи": "Произошла ошибка при загрузке статьи",
"Articles page": "Статьи"
}
3 changes: 2 additions & 1 deletion public/locales/ru/profile.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@
"Нет данных": "Нет данных",
"Имя и фамилия обязательны": "Имя и фамилия обязательны",
"Некорректный возраст": "Некорректный возраст",
"Некорректная страна": "Некорректная страна"
"Некорректная страна": "Некорректная страна",
"Profile page": "Профиль"
}
2 changes: 2 additions & 0 deletions src/app/providers/StoreProvider/config/StateSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { CounterSchema } from 'entities/Counter';
import { UserSchema } from 'entities/User';
import { LoginSchema } from 'features/AuthByUsername';
import { ProfileSchema } from 'entities/Profile';
import { ArticleDetailsSchema } from 'entities/Article';

export interface StateSchema {
counter: CounterSchema,
Expand All @@ -16,6 +17,7 @@ export interface StateSchema {
// Async reducers
loginForm?: LoginSchema,
profile?: ProfileSchema,
articleDetails?: ArticleDetailsSchema,
}

export type StateSchemaKey = keyof StateSchema;
Expand Down
4 changes: 3 additions & 1 deletion src/app/styles/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@ body {

.page-wrapper {
flex-grow: 1;
padding: 20px;
padding: 20px 20px 20px 40px;
height: calc(100vh - var(--navbar-height));
overflow-y: auto;
}
4 changes: 4 additions & 0 deletions src/app/styles/themes/dark.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@
--secondary-color: #049604;
--inverted-primary-color: #0452ff;
--inverted-secondary-color: #0232c2;

// skeleton
--skeleton-color: #1515ad;
--skeleton-shadow: #2b2be8;
}
4 changes: 4 additions & 0 deletions src/app/styles/themes/light.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@
--secondary-color: #0232c2;
--inverted-primary-color: #04ff04;
--inverted-secondary-color: #049604;

// skeleton
--skeleton-color: #fff;
--skeleton-shadow: rgba(0 0 0 / 20%);
}
4 changes: 4 additions & 0 deletions src/app/styles/themes/orange.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@
--secondary-color: #d01f0e;
--inverted-primary-color: #dbd5dc;
--inverted-secondary-color: #faf4fb;

// skeleton
--skeleton-color: #fff;
--skeleton-shadow: rgba(0 0 0 / 20%);
}
8 changes: 8 additions & 0 deletions src/entities/Article/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export { ArticleDetails } from './ui/ArticleDetails/ArticleDetails';
export { Article } from './model/types/article';
export { ArticleDetailsSchema } from './model/types/articleDetailsSchema';
export {
getArticleDetails,
getArticleDetailsIsLoading,
getArticleDetailsError,
} from './model/selectors/getArticleDetails/getArticleDetails';
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { StateSchema } from 'app/providers/StoreProvider';

export const getArticleDetails = (state: StateSchema) => state.articleDetails?.data;
export const getArticleDetailsIsLoading = (state: StateSchema) => state.articleDetails?.isLoading;
export const getArticleDetailsError = (state: StateSchema) => state.articleDetails?.error;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { createAsyncThunk } from '@reduxjs/toolkit';

import { ThunkConfig } from 'app/providers/StoreProvider';

import { Article } from '../../types/article';

export const fetchArticleById = createAsyncThunk<Article, string, ThunkConfig<string>>(
'getArticleDetails/fetchArticleById',
async (articleId, thunkAPI) => {
const { extra, rejectWithValue } = thunkAPI;

try {
const response = await extra.api.get<Article>(`/articles/${articleId}`);

if (!response.data) {
throw new Error();
}

return response.data;
} catch (e) {
console.log(e);
return rejectWithValue('error');
}
},
);
35 changes: 35 additions & 0 deletions src/entities/Article/model/slice/articleDetailsSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';

import { fetchArticleById } from '../services/fetchArticleById/fetchArticleById';
import { ArticleDetailsSchema } from '../types/articleDetailsSchema';
import { Article } from '../types/article';

const initialState: ArticleDetailsSchema = {
isLoading: false,
error: undefined,
data: undefined,
};

export const articleDetailsSlice = createSlice({
name: 'articleDetails',
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchArticleById.pending, (state) => {
state.error = undefined;
state.isLoading = true;
})
.addCase(fetchArticleById.fulfilled, (state, action: PayloadAction<Article>) => {
state.isLoading = false;
state.data = action.payload;
})
.addCase(fetchArticleById.rejected, (state, action) => {
state.isLoading = false;
state.error = action.payload;
});
},
});

export const { actions: articleDetailsActions } = articleDetailsSlice;
export const { reducer: articleDetailsReducer } = articleDetailsSlice;
46 changes: 46 additions & 0 deletions src/entities/Article/model/types/article.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
export enum ArticleBlockType {
TEXT = 'TEXT',
CODE = 'CODE',
IMAGE = 'IMAGE'
}

export interface ArticleBlockBase {
id: string;
type: ArticleBlockType;
}

export interface ArticleTextBlock extends ArticleBlockBase {
type: ArticleBlockType.TEXT;
title?: string;
paragraphs: string[];
}

export interface ArticleCodeBlock extends ArticleBlockBase {
type: ArticleBlockType.CODE;
code: string;
}

export interface ArticleImageBlock extends ArticleBlockBase {
type: ArticleBlockType.IMAGE;
src: string;
title: string;
}

export type ArticleBlock = ArticleTextBlock | ArticleCodeBlock | ArticleImageBlock;

export enum ArticleType {
IT = 'IT',
SCIENCE = 'SCIENCE',
ECONOMICS = 'ECONOMICS'
}

export interface Article {
id: string;
title: string;
subtitle: string;
img: string;
views: number;
createdAt: string;
type: ArticleType[];
blocks: ArticleBlock[];
}
7 changes: 7 additions & 0 deletions src/entities/Article/model/types/articleDetailsSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Article } from './article';

export interface ArticleDetailsSchema {
isLoading: boolean;
error?: string;
data?: Article;
}
Loading

0 comments on commit 2e360a7

Please sign in to comment.