Compare commits

..

15 Commits

Author SHA1 Message Date
d324718646 Two requests fixed 2022-11-14 12:27:05 +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 4175 additions and 4299 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,43 @@
# Install dependencies only when needed
FROM node:16-alpine AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
# Install dependencies of project
FROM node:fermium-alpine AS dependencies
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
WORKDIR /home/app/
COPY package.json ./
RUN npm i
# 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
# Build application to bunch of static files
FROM node:fermium-alpine AS builder
WORKDIR /home/app/
COPY --from=dependencies ./home/app/node_modules ./node_modules
COPY . .
RUN npm run build
# Bundle static assets with nginx
FROM node:16-alpine as production
# NGINX image
FROM nginx:1.21.6 as production
# Copy built assets from builder
WORKDIR /app
COPY --from=builder /app/build .
COPY --from=builder /home/app/build /usr/share/nginx/html
# Add nginx.config
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Copy setup nginx entrypoint file
COPY ./scripts/entrypoint.sh .
# Expose ports
EXPOSE 3000
EXPOSE 80
COPY .env.production .
# Execute script
RUN chmod +x ./entrypoint.sh
ENV NODE_ENV production
ENV USER_NAME=node_user USER_UID=2000 GROUP_NAME=node_group GROUP_UID=2000
# ENV USER_NAME=node_user USER_UID=2000 GROUP_NAME=node_group GROUP_UID=2000
RUN npm i -g serve \
&& 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/"
# 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}
# USER "${USER_NAME}"
ENTRYPOINT ["./entrypoint.sh"]
USER "${USER_NAME}"
CMD serve -s .
# Start serving
CMD ["nginx", "-g", "daemon off;"]

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'

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

@ -1,22 +1,31 @@
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(
// () => {
// getArticleUseCase.call(id ?? '').catch((_) => fetchArticleUseCase.call(id ?? ''));
// console.log(id);
// },
// [id]
// );
useEffect(() => {
if (store.article != undefined) {
_getArticle(store.article.id);
}
}, [store.article?.id]);
getArticleUseCase.call(id ?? '').catch((_) => fetchArticleUseCase.call(id ?? ''));
}, []);
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;
}
setLoading(false);
setCurrentArticle(fromStore);
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,
};
};

7
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,11 +17,11 @@ 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 };
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 };
default:

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>

View File

@ -25,7 +25,6 @@ if (!rootElement) throw new Error("Failed to find the root element");
const root = ReactDOM.createRoot(rootElement);
root.render(
<Provider store={store}>
<React.StrictMode>
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
@ -46,7 +45,6 @@ root.render(
<Route path="/*" element={<NotFound />}></Route>
</Routes>
</BrowserRouter>
</React.StrictMode>
</Provider>
);

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