article slice
This commit is contained in:
parent
43a73bc538
commit
779b091bd5
24
src/article/controller/articleViewModel.ts
Normal file
24
src/article/controller/articleViewModel.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import type { ArticleStore } from "../domain/articleStore";
|
||||
import { getArticleUseCase } from "../useCases/getArticleUseCase";
|
||||
import { useCallback, useEffect } from "react";
|
||||
|
||||
function useArticleViewModel(store: ArticleStore) {
|
||||
const _getArticle = useCallback(
|
||||
(id: string) => getArticleUseCase(store.getArticle, store.setArticle, id),
|
||||
[store.getArticle, store.setArticle]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (store.article != undefined) {
|
||||
_getArticle(store.article.id);
|
||||
}
|
||||
}, [store.article?.id]);
|
||||
|
||||
return {
|
||||
article: store.article,
|
||||
shouldShowLoading: typeof store.article === "undefined" || store.isLoading,
|
||||
hasError: store.hasError,
|
||||
};
|
||||
}
|
||||
|
||||
export { useArticleViewModel };
|
35
src/article/data/articleAPIService.ts
Normal file
35
src/article/data/articleAPIService.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import axios from "axios";
|
||||
import { Article } from "../domain/articleEntity";
|
||||
import { create } from "../domain/articleModel";
|
||||
import { FetchArticleByIdDTO } from "./dto/fetch_article_by_id_dto";
|
||||
import Failure from "core/failure";
|
||||
|
||||
async function getArticle(id: string): Promise<Article> {
|
||||
try {
|
||||
// await new Promise((res, _) => {
|
||||
// setTimeout(() => res(null), 2000);
|
||||
// });
|
||||
const response = await axios.get<FetchArticleByIdDTO>(
|
||||
`https://run.mocky.io/v3/62cd4581-d864-4d46-b1d6-02b45b5d1994/${id}`
|
||||
// `https://jsonplaceholder.typicode.com/posts/${id}`
|
||||
// `http://scipaper.ru/v1/papers/${id}`
|
||||
);
|
||||
const dto = response.data;
|
||||
return create({
|
||||
id: dto.id,
|
||||
topic: dto.topic,
|
||||
title: dto.title,
|
||||
authors: dto.authors,
|
||||
tags: dto.tags,
|
||||
summary: dto.summary,
|
||||
content: dto.content,
|
||||
});
|
||||
} catch (reason) {
|
||||
if (axios.isAxiosError(reason)) {
|
||||
throw Failure.fromReason(reason, "failures.services.load");
|
||||
}
|
||||
throw reason;
|
||||
}
|
||||
}
|
||||
|
||||
export { getArticle };
|
4
src/article/data/articleActionTypes.ts
Normal file
4
src/article/data/articleActionTypes.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export const SET_ARTICLE = "SET_ARTICLE";
|
||||
export const GET_ARTICLE = "GET_ARTICLE";
|
||||
export const GET_ARTICLE_SUCCESS = "GET_ARTICLE.success";
|
||||
export const GET_ARTICLE_FAILURE = "GET_ARTICLE.failure";
|
23
src/article/data/articleActions.ts
Normal file
23
src/article/data/articleActions.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import type { Article } from "../domain/articleEntity";
|
||||
import { getArticle as getArticleAPI } from "./articleAPIService";
|
||||
import * as actionTypes from "./articleActionTypes";
|
||||
import { dispatchStatus } from "../../store/index";
|
||||
|
||||
const setArticleAction = (article: Article) => (dispatch: any) =>
|
||||
dispatch({ type: actionTypes.SET_ARTICLE, article });
|
||||
|
||||
const getArticleAction = (id: string) => (dispatch: any) => {
|
||||
dispatch({ type: actionTypes.GET_ARTICLE });
|
||||
|
||||
return getArticleAPI(id)
|
||||
.then((article) => {
|
||||
dispatchStatus(actionTypes.GET_ARTICLE, ".success", article)(dispatch);
|
||||
return article;
|
||||
})
|
||||
.catch((reason) => {
|
||||
dispatchStatus(actionTypes.GET_ARTICLE, ".failure", reason)(dispatch);
|
||||
return reason;
|
||||
});
|
||||
};
|
||||
|
||||
export { setArticleAction, getArticleAction };
|
39
src/article/data/articleCommonStateStore.ts
Normal file
39
src/article/data/articleCommonStateStore.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { ArticleStore } from "../domain/articleStore";
|
||||
import type { Article } from "../domain/articleEntity";
|
||||
import { getArticle as getArticleAPI } from "./articleAPIService";
|
||||
|
||||
const useArticleCommonStore = (): ArticleStore => {
|
||||
const [isLoading, setLoading] = useState<boolean>(false);
|
||||
const [hasError, setError] = useState<boolean>(false);
|
||||
const [article, setArticleState] = useState<Article | undefined>();
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const getArticle = useCallback(
|
||||
async (id: string) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const article = await getArticleAPI(id);
|
||||
setArticleState(article);
|
||||
setLoading(false);
|
||||
return article;
|
||||
} catch (error) {
|
||||
setError(true);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
return {
|
||||
article: article,
|
||||
isLoading,
|
||||
hasError,
|
||||
setArticle: setArticleState,
|
||||
getArticle,
|
||||
};
|
||||
};
|
||||
|
||||
export { useArticleCommonStore };
|
33
src/article/data/articleReducer.ts
Normal file
33
src/article/data/articleReducer.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { AnyAction } from "@reduxjs/toolkit";
|
||||
import { Article } from "article/domain/articleEntity";
|
||||
import type { ArticleStore } from "../domain/articleStore";
|
||||
import * as actionTypes from "./articleActionTypes";
|
||||
|
||||
type ArticleStoreState = Omit<ArticleStore, "getArticle" | "setArticle">;
|
||||
|
||||
const INITIAL_STATE: ArticleStoreState = {
|
||||
article: undefined,
|
||||
isLoading: false,
|
||||
hasError: false,
|
||||
};
|
||||
|
||||
const articleReducer = (
|
||||
state: ArticleStoreState = INITIAL_STATE,
|
||||
action: AnyAction
|
||||
): ArticleStoreState => {
|
||||
switch (action.type) {
|
||||
case actionTypes.SET_ARTICLE:
|
||||
return { ...state, article: action.article };
|
||||
case actionTypes.GET_ARTICLE:
|
||||
return { ...state, isLoading: true };
|
||||
case actionTypes.GET_ARTICLE_SUCCESS:
|
||||
return { ...state, isLoading: false, article: action.payload };
|
||||
case actionTypes.GET_ARTICLE_FAILURE:
|
||||
return { ...state, hasError: true, isLoading: false };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export { articleReducer };
|
||||
export type { ArticleStoreState };
|
35
src/article/data/articleStoreImplementation.ts
Normal file
35
src/article/data/articleStoreImplementation.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { ArticleStore } from "../domain/articleStore";
|
||||
import type { Article } from "../domain/articleEntity";
|
||||
import type { ArticleStoreState } from "../data/articleReducer";
|
||||
import { getArticleAction, setArticleAction } from "./articleActions";
|
||||
import { RootState, useAppSelector } from "store";
|
||||
|
||||
const articleSelector = (state: RootState): ArticleStoreState => state.article;
|
||||
|
||||
const useArticleStore = (): ArticleStore => {
|
||||
const { isLoading, article, hasError } = useAppSelector(articleSelector);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const setArticle = useCallback(
|
||||
(article: Article) => setArticleAction(article)(dispatch),
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const getArticle = useCallback(
|
||||
(id: string) => getArticleAction(id)(dispatch),
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
return {
|
||||
article: article,
|
||||
isLoading,
|
||||
hasError,
|
||||
setArticle,
|
||||
getArticle,
|
||||
};
|
||||
};
|
||||
|
||||
export { useArticleStore };
|
9
src/article/data/dto/fetch_article_by_id_dto.ts
Normal file
9
src/article/data/dto/fetch_article_by_id_dto.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export interface FetchArticleByIdDTO {
|
||||
id: string;
|
||||
topic: string;
|
||||
title: string;
|
||||
authors: string[];
|
||||
tags: string[];
|
||||
summary: string;
|
||||
content: string;
|
||||
}
|
9
src/article/domain/articleEntity.ts
Normal file
9
src/article/domain/articleEntity.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export interface Article {
|
||||
id: string;
|
||||
topic: string;
|
||||
title: string;
|
||||
authors: string[];
|
||||
tags: string[];
|
||||
summary: string;
|
||||
content: string;
|
||||
}
|
14
src/article/domain/articleModel.ts
Normal file
14
src/article/domain/articleModel.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { CreateArticleParams } from "article/useCases/params/create_article_params";
|
||||
import { Article } from "./articleEntity";
|
||||
|
||||
const create = (props: CreateArticleParams): Article => ({
|
||||
id: props.id,
|
||||
topic: props.topic,
|
||||
title: props.title,
|
||||
authors: props.authors,
|
||||
tags: props.tags,
|
||||
summary: props.summary,
|
||||
content: props.content,
|
||||
});
|
||||
|
||||
export { create };
|
14
src/article/domain/articleStore.ts
Normal file
14
src/article/domain/articleStore.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import type { Article } from "./articleEntity";
|
||||
|
||||
interface ArticleStore {
|
||||
// State
|
||||
article: Article | undefined;
|
||||
isLoading: boolean;
|
||||
hasError: boolean;
|
||||
|
||||
// Actions
|
||||
setArticle(article?: Article): void;
|
||||
getArticle(identifier: string): Promise<Article | null>;
|
||||
}
|
||||
|
||||
export type { ArticleStore };
|
16
src/article/useCases/getArticleUseCase.ts
Normal file
16
src/article/useCases/getArticleUseCase.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { Article } from "article/domain/articleEntity";
|
||||
import type { ArticleStore } from "../domain/articleStore";
|
||||
|
||||
const getArticleUseCase = async (
|
||||
getArticle: ArticleStore["getArticle"],
|
||||
setArticle: ArticleStore["setArticle"],
|
||||
id: Article["id"]
|
||||
): Promise<Article | null> => {
|
||||
const article = await getArticle(id);
|
||||
if (article) {
|
||||
await setArticle(article);
|
||||
}
|
||||
return article;
|
||||
};
|
||||
|
||||
export { getArticleUseCase };
|
9
src/article/useCases/params/create_article_params.ts
Normal file
9
src/article/useCases/params/create_article_params.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export interface CreateArticleParams {
|
||||
id: string;
|
||||
topic: string;
|
||||
title: string;
|
||||
authors: string[];
|
||||
tags: string[];
|
||||
summary: string;
|
||||
content: string;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user