Compare commits

...

19 Commits

Author SHA1 Message Date
91a850563e Build with no warnings 2022-11-13 02:17:34 +03:00
be4587f7cc Added loading state for getting data from redux store 2022-11-13 01:53:51 +03:00
4312533d5c Removed deprecated "setup" command from make container command 2022-11-13 01:19:40 +03:00
962f8cb145 Restored original develop Dockerfile 2022-11-13 01:18:28 +03:00
d755be1f95 Updated view model for article 2022-11-13 01:16:11 +03:00
e20831fbfc Fixed 404 error on "article/info/$id" pages 2022-11-12 23:55:00 +03:00
fecce76fe1 Improved loading content of and article with saving them in redux store
When article was loaded once than it will be cached in redux store.
On the next loading of article content it will be get from store
2022-11-12 23:41:31 +03:00
335218fdd9 Merge pull request 'fix/fetch-article-loop' (#178) from fix/fetch-article-loop into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/178
2022-11-12 14:11:20 +00:00
35170d4558 Merge pull request 'topic resolved' (#177) from fix/topic into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/177
2022-11-12 14:10:10 +00:00
5d28da2f0a Merge pull request 'The overlaping in the navbar resolved' (#176) from fix/navbar-overlap into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/176
2022-11-12 14:09:51 +00:00
f677bffc16 Merge pull request 'fix/burger-translation' (#175) from fix/burger-translation into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/175
2022-11-12 14:09:29 +00:00
69d09bb8a4 Remove unused imports 2022-11-11 18:58:32 +03:00
d3d1d9d1af Fetch article useCase added 2022-11-11 18:57:16 +03:00
salar.sali
355a9af985 topic resolved 2022-11-11 08:53:01 -05:00
salar.sali
a4a8116d32 The overlaping in the navbar resolved 2022-11-11 05:16:02 -05:00
salar.sali
a4ef589ca9 The translation in burger component resolved 2022-11-11 05:03:34 -05:00
8d3115d878 Updated style for MD code view 2022-11-09 17:35:25 +03:00
eb17ae6377 Merge pull request 'dockerfile-envs fixe, three bugs in select.tsx,typography/Link.tsx, and typography/RouterLink.tsx fixed' (#174) from bugfix/dockerfile-envs into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/174
2022-10-31 17:54:56 +00:00
moeidheidari
181a225eff dockerfile-envs fixe, three bugs in select.tsx,typography/Link.tsx, and typography/RouterLink.tsx fixed 2022-10-31 20:50:33 +03:00
49 changed files with 4151 additions and 4275 deletions

View File

@ -1,5 +1,5 @@
.env*
!.env.production
.env.production
node_modules
build
.vscode

6
.env Normal file
View File

@ -0,0 +1,6 @@
REACT_APP_CMS_BASE_URL=http://api.scipaper.ru
REACT_APP_CMS_APP_NAME=scipaper
REACT_APP_OPENID_PROVIDER_URL=http://auth.techpal.ru/auth/realms/master/protocol/openid-connect/auth?client_id=techpal&response_type=code
REACT_APP_INTEGRATOR_URL=http://api.scipaper.ru
REACT_APP_INTEGRATOR_API_VERSION=/v1
REACT_APP_GRAPHQL_URL=/graphql

View File

@ -1,6 +1,6 @@
REACT_APP_CMS_BASE_URL=http://scipaper.ru
REACT_APP_CMS_BASE_URL=http://api.scipaper.ru
REACT_APP_CMS_APP_NAME=scipaper
REACT_APP_OPENID_PROVIDER_URL=http://auth.techpal.ru/auth/realms/master/protocol/openid-connect/auth?client_id=techpal&response_type=code
REACT_APP_INTEGRATOR_URL=http://scipaper.ru
REACT_APP_INTEGRATOR_URL=http://api.scipaper.ru
REACT_APP_INTEGRATOR_API_VERSION=/v1
REACT_APP_GRAPHQL_URL=/graphql

View File

@ -1,6 +1,6 @@
REACT_APP_CMS_BASE_URL=http://scipaper.ru
REACT_APP_CMS_BASE_URL=http://api.scipaper.ru
REACT_APP_CMS_APP_NAME=scipaper
REACT_APP_OPENID_PROVIDER_URL=http://auth.techpal.ru/auth/realms/master/protocol/openid-connect/auth?client_id=techpal&response_type=code
REACT_APP_INTEGRATOR_URL=http://scipaper.ru
REACT_APP_INTEGRATOR_URL=http://api.scipaper.ru
REACT_APP_INTEGRATOR_API_VERSION=/v1
REACT_APP_GRAPHQL_URL=/graphql

View File

@ -1,41 +1,30 @@
# Install dependencies only when needed
FROM node:16-alpine AS deps
FROM node:fermium-alpine AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
WORKDIR /home/app/
COPY package.json package-lock.json ./
RUN npm ci
# Rebuild the source code only when needed
FROM node:16-alpine AS builder
ENV NODE_ENV production
WORKDIR /app
# Copy dependencies from deps stage
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# Bundle static assets with nginx
FROM node:16-alpine as production
FROM node:fermium-alpine as production
# Copy built assets from builder
WORKDIR /app
COPY --from=builder /app/build .
WORKDIR /home/app/
COPY --from=deps ./home/app/node_modules ./node_modules
COPY . .
# Expose ports
EXPOSE 3000
COPY .env.production .
ENV NODE_ENV production
ENV USER_NAME=node_user USER_UID=2000 GROUP_NAME=node_group GROUP_UID=2000
RUN npm i -g serve \
&& deluser --remove-home node \
RUN deluser --remove-home node \
&& addgroup --g ${GROUP_UID} -S ${GROUP_NAME} \
&& adduser -D -S -s /sbin/nologin -u ${USER_UID} -G ${GROUP_NAME} ${USER_NAME}\
&& chown -R ${USER_NAME}:${GROUP_NAME} "/app/"
&& adduser -D -S -s /sbin/nologin -u ${USER_UID} -G ${GROUP_NAME} ${USER_NAME}
USER "${USER_NAME}"
CMD serve -s .
ENTRYPOINT [ "npm","start"]

View File

@ -12,7 +12,7 @@ dev: setup
test: setup
npm run test
container: setup
container:
docker build -t ${PROJECT_NAME} .
clean:

8057
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
"@fortawesome/free-brands-svg-icons": "^6.2.0",
"@fortawesome/free-solid-svg-icons": "^6.2.0",
"@fortawesome/react-fontawesome": "^0.2.0",
"@headlessui/react": "^1.6.6",
"@headlessui/react": "^1.7.3",
"@reduxjs/toolkit": "^1.8.3",
"@types/node": "^16.11.47",
"@types/react": "^18.0.15",
@ -24,9 +24,9 @@
"i18next-http-backend": "^1.4.1",
"jwt-decode": "^3.1.2",
"lodash": "^4.17.21",
"react": "^18.2.0",
"react": "^18.1.0",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^18.2.0",
"react-dom": "^18.1.0",
"react-hotkeys": "^2.0.0",
"react-i18next": "^11.18.3",
"react-loading-skeleton": "^3.1.0",

View File

@ -1,6 +1,9 @@
#! /bin/bash
# no verbose
set +x
# save env to file
printenv > .env.production
# config
envFilename='.env.production'
resolvingPath='/usr/share/nginx/html'

44
src/article/controller/articleViewModel.ts Normal file → Executable file
View File

@ -1,22 +1,42 @@
import type { ArticleStore } from "../domain/articleStore";
import { getArticleUseCase } from "../useCases/getArticleUseCase";
import { useCallback, useEffect } from "react";
import { GetArticleUseCase } from "article/useCases/getArticleUseCase";
import { FetchArticleUseCase } from "article/useCases/fetchArticleUseCase";
import { useParams } from "react-router-dom";
function useArticleViewModel(store: ArticleStore) {
const _getArticle = useCallback(
(id: string) => getArticleUseCase(store.getArticle, store.setArticle, id),
[store.getArticle, store.setArticle]
function useArticleViewModel(
store: ArticleStore,
fetchArticleUseCase: FetchArticleUseCase,
getArticleUseCase: GetArticleUseCase,
) {
const { id } = useParams();
const getArticle = useCallback(
(
articleID: string,
getArticleUseCase: GetArticleUseCase,
fetchArticleUseCase: FetchArticleUseCase
) => {
getArticleUseCase.call(articleID).catch((_) => fetchArticleUseCase.call(articleID));
},
[]
);
useEffect(() => {
if (store.article != undefined) {
_getArticle(store.article.id);
}
}, [store.article?.id]);
useEffect(
() => {
getArticle(id ?? '', getArticleUseCase, fetchArticleUseCase);
},
[
id,
getArticle,
getArticleUseCase,
fetchArticleUseCase
],
);
return {
article: store.article,
shouldShowLoading: typeof store.article === "undefined" || store.isLoading,
article: store.currentArticle,
shouldShowLoading: store.isLoading,
hasError: store.hasError,
};
}

4
src/article/data/articleAPIService.ts Normal file → Executable file
View File

@ -7,7 +7,7 @@ import { integratorApiClient } from "core/httpClient";
const articleEndpoint = "/papers/"
async function getArticle(id: string): Promise<Article> {
async function fetchArticle(id: string): Promise<Article> {
try {
const response = await integratorApiClient.get<FetchArticleByIdDTO>(
// `https://run.mocky.io/v3/62cd4581-d864-4d46-b1d6-02b45b5d1994/${id}`
@ -33,4 +33,4 @@ async function getArticle(id: string): Promise<Article> {
}
}
export { getArticle };
export { fetchArticle };

0
src/article/data/articleActionTypes.ts Normal file → Executable file
View File

26
src/article/data/articleActions.ts Normal file → Executable file
View File

@ -1,23 +1,25 @@
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 setArticleAction = (article: Article, articlesList: Array<Article>) => (dispatch: any) => {
if (!articlesList.includes(article)) {
const updatedList = articlesList.concat([article]);
dispatch({ type: actionTypes.SET_ARTICLE, article, updatedList });
}
}
const getArticleAction = (id: string) => (dispatch: any) => {
dispatch({ type: actionTypes.GET_ARTICLE });
return getArticleAPI(id)
.then((article) => {
const getArticleAction = (id: string, articles: Array<Article>) => (dispatch: any) => {
const filteredArray = articles.filter((e) => e.id == id);
if (filteredArray.length > 0) {
const article = filteredArray[0];
dispatchStatus(actionTypes.GET_ARTICLE, ".success", article)(dispatch);
return article;
})
.catch((reason) => {
}
const reason = 'Article not in the store';
dispatchStatus(actionTypes.GET_ARTICLE, ".failure", reason)(dispatch);
return reason;
});
return null;
};
export { setArticleAction, getArticleAction };

45
src/article/data/articleCommonStateStore.ts Normal file → Executable file
View File

@ -2,37 +2,58 @@ 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 [currentArticle, setCurrentArticle] = useState<Article | null>(null);
const [articles, setArticlesState] = useState<Array<Article>>([]);
const dispatch = useDispatch();
const getArticle = useCallback(
async (id: string) => {
(id: string) => {
setLoading(true);
try {
const article = await getArticleAPI(id);
setArticleState(article);
setLoading(false);
return article;
} catch (error) {
if (typeof currentArticle === undefined) {
const fromStore = findArticleFromStore(id);
if (typeof fromStore === undefined) {
setError(true);
return null;
}
setCurrentArticle(fromStore);
setLoading(false);
return fromStore;
}
setLoading(false);
return currentArticle;
},
[dispatch]
);
const findArticleFromStore = (id: string): Article | null => {
const filteredArray = articles.filter((e) => e.id == id);
if (filteredArray.length > 0) {
return filteredArray[0];
}
return null;
}
const setNewArticle = (newArticle: Article) => {
setCurrentArticle(newArticle);
if (!articles.includes(newArticle)) {
setArticlesState(articles.concat([newArticle]));
} else if (articles.length == 0) {
setArticlesState([newArticle]);
}
}
return {
article: article,
articles: articles,
currentArticle: currentArticle,
isLoading,
hasError,
setArticle: setArticleState,
getArticle,
setArticle: setNewArticle,
getArticle: getArticle,
};
};

9
src/article/data/articleReducer.ts Normal file → Executable file
View File

@ -5,7 +5,8 @@ import * as actionTypes from "./articleActionTypes";
type ArticleStoreState = Omit<ArticleStore, "getArticle" | "setArticle">;
const INITIAL_STATE: ArticleStoreState = {
article: undefined,
articles: [],
currentArticle: null,
isLoading: false,
hasError: false,
};
@ -16,13 +17,13 @@ const articleReducer = (
): ArticleStoreState => {
switch (action.type) {
case actionTypes.SET_ARTICLE:
return { ...state, article: action.article };
return { ...state, articles: action.updatedList, currentArticle: action.article, hasError: typeof action.article === undefined, isLoading: false };
case actionTypes.GET_ARTICLE:
return { ...state, isLoading: true };
case actionTypes.GET_ARTICLE_SUCCESS:
return { ...state, isLoading: false, article: action.payload };
return { ...state, isLoading: false, currentArticle: action.payload };
case actionTypes.GET_ARTICLE_FAILURE:
return { ...state, hasError: true, isLoading: false };
return { ...state, hasError: false, isLoading: true };
default:
return state;
}

9
src/article/data/articleStoreImplementation.ts Normal file → Executable file
View File

@ -9,22 +9,23 @@ import { RootState, useAppSelector } from "store";
const articleSelector = (state: RootState): ArticleStoreState => state.article;
const useArticleStore = (): ArticleStore => {
const { isLoading, article, hasError } = useAppSelector(articleSelector);
const { isLoading, hasError, currentArticle, articles } = useAppSelector(articleSelector);
const dispatch = useDispatch();
const setArticle = useCallback(
(article: Article) => setArticleAction(article)(dispatch),
(article: Article) => setArticleAction(article, articles)(dispatch),
[dispatch]
);
const getArticle = useCallback(
(id: string) => getArticleAction(id)(dispatch),
(id: string) => getArticleAction(id, articles)(dispatch),
[dispatch]
);
return {
article: article,
articles: articles,
currentArticle: currentArticle,
isLoading,
hasError,
setArticle,

0
src/article/data/dto/fetch_article_by_id_dto.ts Normal file → Executable file
View File

0
src/article/domain/articleEntity.ts Normal file → Executable file
View File

0
src/article/domain/articleModel.ts Normal file → Executable file
View File

7
src/article/domain/articleStore.ts Normal file → Executable file
View File

@ -1,13 +1,14 @@
import { Article } from './articleEntity';
interface ArticleStore {
// State
article: Article | undefined;
articles: Array<Article>;
currentArticle: Article | null;
isLoading: boolean;
hasError: boolean;
// Actions
setArticle(article?: Article): void;
getArticle(identifier: string): Promise<Article | null>;
setArticle(article: Article): void;
getArticle(identifier: string): Article | null;
}
export type { ArticleStore };

View File

@ -0,0 +1,29 @@
import { Article } from "article/domain/articleEntity";
import { ArticleStore } from "article/domain/articleStore";
class FetchArticleUseCase {
/* ------------------------------ Dependencies ------------------------------ */
_fetchArticleCallback: (id: string) => Promise<Article | null>;
_store: ArticleStore;
/* -------------------------------------------------------------------------- */
constructor(
fetchArticle: (id: string) => Promise<Article | null>,
store: ArticleStore,
) {
this._fetchArticleCallback = fetchArticle;
this._store = store;
}
/* ----------------------------- Implementation ----------------------------- */
async call(id: string): Promise<Article | null> {
return this._fetchArticleCallback(id).then((article) => {
if (article != null) {
this._store.setArticle(article);
}
return article;
})
}
/* -------------------------------------------------------------------------- */
}
export { FetchArticleUseCase };

31
src/article/useCases/getArticleUseCase.ts Normal file → Executable file
View File

@ -1,16 +1,25 @@
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);
class GetArticleUseCase {
/* ------------------------------ Dependencies ------------------------------ */
_store: ArticleStore;
/* -------------------------------------------------------------------------- */
constructor(
store: ArticleStore,
) {
this._store = store;
}
/* ----------------------------- Implementation ----------------------------- */
async call(id: string): Promise<Article> {
const storedArticle = this._store.getArticle(id);
if (storedArticle != null) {
this._store.setArticle(storedArticle);
return storedArticle;
}
throw new Error('Article not found');
}
/* -------------------------------------------------------------------------- */
}
return article;
};
export { getArticleUseCase };
export { GetArticleUseCase };

0
src/article/useCases/params/create_article_params.ts Normal file → Executable file
View File

0
src/assets/lotties/notFoundAnimation.json Normal file → Executable file
View File

12
src/components/ArticleSearchResult.tsx Normal file → Executable file
View File

@ -27,17 +27,15 @@ export const ArticleSearchResult = ({ searchItem }: Props) => {
<Article className=" pt-6 pb-3 ">
<div className="flex flex-row justify-between">
<Article.Breadcumbs emphasis="low" className="flex flex-wrap flex-row">
{[
`${searchItem.topic}`,
`${searchItem.topic}`,
`${searchItem.topic}`,
`${searchItem.topic}`,
]}
{[`${searchItem.topic}`]}
</Article.Breadcumbs>
<Article.SubscriptionsButtons />
</div>
<Article.Title linkTo={`/article/info/${searchItem.id}`} className="text-2xl">
<Article.Title
linkTo={`/article/info/${searchItem.id}`}
className="text-2xl"
>
{searchItem.title}
</Article.Title>
<Article.Authors emphasis="low" className="flex flex-wrap flex-row">

26
src/components/Burger.tsx Normal file → Executable file
View File

@ -21,10 +21,12 @@ import { ReactComponent as SVGFile } from "assets/svg/file.svg";
import { ReactComponent as SVGEye } from "assets/svg/eye.svg";
import { ReactComponent as SVGArrowUp } from "assets/svg/arrow-up.svg";
import { ReactComponent as SVGCaretDown } from "assets/svg/caret-down.svg";
import { useTranslation } from "react-i18next";
type Props = React.ComponentPropsWithoutRef<"div">;
const Burger = (props: Props) => {
const { t, i18n } = useTranslation();
return (
<div {...props}>
<Menu as="div" className="relative inline-block text-left z-30">
@ -46,13 +48,15 @@ const Burger = (props: Props) => {
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items
className="origin-top-right absolute right-0 mt-5 w-44 rounded-md
className="origin-top-right absolute right-0 mt-5 w-48 rounded-md
shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none"
>
<div className="py-1">
<Disclosure>
<Disclosure.Button className="uppercase text-base px-2 py-1">
<Link className="text-[#096DD9]">create new</Link>
<Link className="text-[#096DD9]">
{t("navbar.createNew")}
</Link>
</Disclosure.Button>
</Disclosure>
<hr />
@ -66,7 +70,7 @@ const Burger = (props: Props) => {
text-base
"
>
my library
<span>{t("navbar.library.navTitle")}</span>
<SVGArrowUp
className={`${
open ? "rotate-180 transform" : "rotate-360"
@ -83,7 +87,7 @@ const Burger = (props: Props) => {
"
>
<SVGFile className="stroke-black w-4 h-4" />
My Publications
<span>{t("navbar.library.publications")}</span>
</Disclosure.Panel>
</Link>
@ -96,7 +100,7 @@ const Burger = (props: Props) => {
"
>
<SVGFavoriteOutlined className="stroke-black w-4 h-4" />
My Favorites
<span>{t("navbar.library.favorites")}</span>
</Disclosure.Panel>
</Link>
@ -109,7 +113,7 @@ const Burger = (props: Props) => {
"
>
<SVGFolder className="stroke-black fill-black w-4 h-4" />
My Collections
<span>{t("navbar.library.collections")}</span>
</Disclosure.Panel>
</Link>
@ -122,7 +126,7 @@ const Burger = (props: Props) => {
"
>
<SVGEye className="stroke-black w-4 h-4" />
Recent Viewed
<span>{t("navbar.library.recentViewed")}</span>
</Disclosure.Panel>
</Link>
</>
@ -140,7 +144,7 @@ const Burger = (props: Props) => {
text-base
"
>
About
<span>{t("navbar.about.navTitle")}</span>
<SVGArrowUp
className={`${
open ? "rotate-180 transform" : "rotate-360"
@ -156,7 +160,7 @@ const Burger = (props: Props) => {
text-base
"
>
About Freeland
<span>{t("navbar.about.aboutProject")}</span>
</Disclosure.Panel>
</Link>
@ -168,7 +172,7 @@ const Burger = (props: Props) => {
text-base
"
>
Contact Us
<span>{t("navbar.about.contacts")}</span>
</Disclosure.Panel>
</Link>
@ -180,7 +184,7 @@ const Burger = (props: Props) => {
text-base
"
>
Help
<span>{t("navbar.about.help")}</span>
</Disclosure.Panel>
</Link>
</>

0
src/components/Disclosure.tsx Normal file → Executable file
View File

0
src/components/Filters/AppiledFilters.tsx Normal file → Executable file
View File

0
src/components/Filters/Filter.tsx Normal file → Executable file
View File

0
src/components/Filters/IProdutct.ts Normal file → Executable file
View File

0
src/components/Filters/SearchFilterBar.tsx Normal file → Executable file
View File

0
src/components/Filters/functions/debounce.ts Normal file → Executable file
View File

0
src/components/Loader/Loader.css Normal file → Executable file
View File

0
src/components/Loader/Loader.tsx Normal file → Executable file
View File

0
src/components/LocalizationButton.tsx Normal file → Executable file
View File

5
src/components/Markdown.tsx Normal file → Executable file
View File

@ -14,9 +14,8 @@ import Heading from "./typography/Heading";
/* Code */
/* -------------------------------------------------------------------------- */
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { dark } from "react-syntax-highlighter/dist/esm/styles/prism";
import { oneLight } from "react-syntax-highlighter/dist/esm/styles/prism";
import Link from "./typography/Link";
import style from "react-syntax-highlighter/dist/esm/styles/hljs/a11y-dark";
export type Props = {
markdown: string;
@ -153,7 +152,7 @@ const Markdown = ({ markdown }: Props) => {
return !inline && match ? (
<SyntaxHighlighter
children={String(children).replace(/\n$/, "")}
style={dark}
style={oneLight}
language={match[1]}
PreTag="div"
/>

0
src/components/SearchResultsSection.tsx Normal file → Executable file
View File

0
src/components/SearchSection.tsx Normal file → Executable file
View File

View File

@ -83,7 +83,7 @@ function Select<T>({
}: Props<T>): JSX.Element {
return (
<div className={classNames("top-16 w-60", className)}>
<Listbox value={value} {...props} onChange={onChange}>
<Listbox value={value as any } {...props} onChange={onChange}>
<div className="relative">
<Listbox.Button
className={classNames([

17
src/components/fetchAnArticle/AnArticle.tsx Normal file → Executable file
View File

@ -10,19 +10,20 @@ import { SVGSearch } from "components/icons";
import BaseLayout from "components/BaseLayout";
import Typography from "components/typography/Typography";
import { useTranslation } from "react-i18next";
import { FetchArticleUseCase } from "article/useCases/fetchArticleUseCase";
import { GetArticleUseCase } from "article/useCases/getArticleUseCase";
import { fetchArticle } from "article/data/articleAPIService";
const AnArticle = () => {
const store = useArticleStore();
const { article, hasError, shouldShowLoading } = useArticleViewModel(store);
const { article, hasError, shouldShowLoading } = useArticleViewModel(
store,
new FetchArticleUseCase(fetchArticle, store),
new GetArticleUseCase(store),
);
const { i18n, t } = useTranslation();
const { id } = useParams();
const newId = `${id}`;
useEffect(() => {
store.getArticle(newId);
}, [id]);
if (hasError) {
return <NotFound />;
}

14
src/components/fetchAnArticle/AnArticleBody.tsx Normal file → Executable file
View File

@ -13,15 +13,17 @@ import BaseLayout from "components/BaseLayout";
import Container from "components/Container";
import NotFound from "./NotFound";
import Markdown from "components/Markdown";
import { FetchArticleUseCase } from "article/useCases/fetchArticleUseCase";
import { GetArticleUseCase } from "article/useCases/getArticleUseCase";
import { fetchArticle } from "article/data/articleAPIService";
const AnArticleBody = () => {
const store = useArticleStore();
const { article, hasError, shouldShowLoading } = useArticleViewModel(store);
const { id } = useParams();
const newId = `${id}`;
useEffect(() => {
store.getArticle(newId);
}, [id]);
const { article, hasError, shouldShowLoading } = useArticleViewModel(
store,
new FetchArticleUseCase(fetchArticle, store),
new GetArticleUseCase(store),
);
if (hasError) <NotFound />;
return (
<BaseLayout>

0
src/components/fetchAnArticle/AskeletonArticle.tsx Normal file → Executable file
View File

0
src/components/fetchAnArticle/NotFound.tsx Normal file → Executable file
View File

View File

@ -80,7 +80,7 @@ const Header = () => {
<ContextMenu
emphasis="high"
button={t("navbar.library.navTitle")}
className="border-none uppercase"
className="border-none uppercase z-40"
>
<ContextMenuAction
caption={t("navbar.library.publications")}
@ -112,7 +112,7 @@ const Header = () => {
<ContextMenu
emphasis="high"
button={t("navbar.about.navTitle")}
className="border-none uppercase"
className="border-none uppercase z-40"
>
<ContextMenuAction
caption={t("navbar.about.aboutProject")}

0
src/components/search/SearchBar.tsx Normal file → Executable file
View File

View File

@ -47,6 +47,7 @@ export default function Link({
typeof style === "function"
? style({
isActive: true,
isPending: false
})
: style
}

View File

@ -15,7 +15,7 @@ export function RouterLink({
return (
<NavLink
to={to}
className={classNames({ "pointer-events-none": disabled }, className)}
className={classNames({ "pointer-events-none": disabled }, className as string)}
>
{children}
</NavLink>

0
src/pages/SearchResultsPage.tsx Normal file → Executable file
View File