Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/jc 720 anime list #9

Open
wants to merge 70 commits into
base: feature/JC-702-initialize-anime-app
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
7d25550
Create anime service JC-720
TebyakinaEkaterina Aug 16, 2024
18a697d
Create anime slice JC-720
TebyakinaEkaterina Aug 16, 2024
b52c3e0
Remove unused properties from anime model JC-720
TebyakinaEkaterina Aug 16, 2024
c2e5245
Add anime card component JC-720
TebyakinaEkaterina Aug 16, 2024
7ece2e8
Add edit form component JC-720
TebyakinaEkaterina Aug 16, 2024
997a5ca
Add filter form component JC-720
TebyakinaEkaterina Aug 16, 2024
045530a
Add anime list component JC-720
TebyakinaEkaterina Aug 16, 2024
450c490
Add anime page JC-720
TebyakinaEkaterina Aug 16, 2024
565c2c6
Setup routes for anime page JC-720
TebyakinaEkaterina Aug 16, 2024
ea2309d
Add scroll tracking JC-720
TebyakinaEkaterina Aug 19, 2024
583ea65
Create anime filter form JC-720
TebyakinaEkaterina Aug 19, 2024
4a77819
Add dtos for anime filter form JC-720
TebyakinaEkaterina Aug 19, 2024
c333eaf
Add mappers for anime filter form JC-720
TebyakinaEkaterina Aug 19, 2024
43d8305
Add models for anime filter form JC-720
TebyakinaEkaterina Aug 19, 2024
ffe7ab8
Add params to get anime list method JC-720
TebyakinaEkaterina Aug 19, 2024
e453719
Add anime type mappers JC-720
TebyakinaEkaterina Aug 19, 2024
a7ef693
Add css variable JC-720
TebyakinaEkaterina Aug 19, 2024
ce209f0
Rename header folder JC-720
TebyakinaEkaterina Aug 20, 2024
b94a00e
Update dtos JC-720
TebyakinaEkaterina Aug 20, 2024
4de1710
Update mappers JC-720
TebyakinaEkaterina Aug 20, 2024
f964c69
Update models JC-720
TebyakinaEkaterina Aug 20, 2024
e2bae26
Update anime service JC-720
TebyakinaEkaterina Aug 20, 2024
01cc01d
Update anime store JC-720
TebyakinaEkaterina Aug 20, 2024
4e86f99
Update anime type mapper JC-720
TebyakinaEkaterina Aug 20, 2024
8f6cd5e
Add progress component JC-720
TebyakinaEkaterina Aug 20, 2024
578f55c
Add progress component in app component JC-720
TebyakinaEkaterina Aug 20, 2024
62c7621
Fix JSDoc comments JC-720
TebyakinaEkaterina Aug 20, 2024
8fe6343
Remove barrel files JC-720
TebyakinaEkaterina Aug 20, 2024
34c2d2d
Rename css classes JC-720
TebyakinaEkaterina Aug 20, 2024
f95818f
Add anime types field component JC-720
TebyakinaEkaterina Aug 20, 2024
f66cc4f
Add anime search field component JC-720
TebyakinaEkaterina Aug 20, 2024
000c586
Add anime sort field component JC-720
TebyakinaEkaterina Aug 20, 2024
4f6f0b8
Update filter form using components for form fields
TebyakinaEkaterina Aug 20, 2024
bf0ca94
Fix JSDoc comment JC-702
TebyakinaEkaterina Aug 20, 2024
a093002
Update anime list component JC-720
TebyakinaEkaterina Aug 20, 2024
ae804d1
Update anime page by embedding logic in separate components JC-720
TebyakinaEkaterina Aug 20, 2024
524e589
Fix progress component display JC-720
TebyakinaEkaterina Aug 20, 2024
a8ce69e
Merge branch 'feature/JC-702-initialize-anime-app' into feature/JC-72…
TebyakinaEkaterina Aug 20, 2024
d09d334
Fix merge issues with imports JC-720
TebyakinaEkaterina Aug 20, 2024
1bb4157
Rename constant for url JC-720
TebyakinaEkaterina Aug 20, 2024
244c8ee
Add displaying messages about the anime list JC-720
TebyakinaEkaterina Aug 20, 2024
fc4938f
Fix comments JC-720
TebyakinaEkaterina Aug 20, 2024
551f99f
Remove unused fields from anime mapper JC-720
TebyakinaEkaterina Aug 20, 2024
a330daa
Remove default route JC-720
TebyakinaEkaterina Aug 20, 2024
2113f69
Add default route JC-720
TebyakinaEkaterina Aug 20, 2024
00a0291
Add constants for query params JC-720
TebyakinaEkaterina Aug 21, 2024
aeebd11
Update type checking in types changes handler JC-720
TebyakinaEkaterina Aug 21, 2024
5c0f2cd
Move constant out of the component JC-720
TebyakinaEkaterina Aug 21, 2024
1ee153f
Add hook for infinite scroll JC-720
TebyakinaEkaterina Aug 21, 2024
9b38de1
Add variable for scroll loading status JC-720
TebyakinaEkaterina Aug 21, 2024
6041de5
Add entity adapter to manage state JC-720
TebyakinaEkaterina Aug 21, 2024
c709f67
Remove unused type JC-720
TebyakinaEkaterina Aug 21, 2024
bb79f5f
Replace Link with NavLink JC-720
TebyakinaEkaterina Aug 21, 2024
52f5e05
Rename classes using camelCase JC-720
TebyakinaEkaterina Aug 21, 2024
08c6517
Fix JSDoc comments JC-720
TebyakinaEkaterina Aug 21, 2024
cc2e62b
Add enum for query params JC-720
TebyakinaEkaterina Aug 21, 2024
59b5d38
Remove redundant functions from the anime types mapper JC-720
TebyakinaEkaterina Aug 21, 2024
9b6a9d2
Rename method for fetching new page JC-720
TebyakinaEkaterina Aug 22, 2024
d303620
Add a generator of unique id for input label JC-720
TebyakinaEkaterina Aug 22, 2024
a4f8291
Rename isLoadingNextPage variable JC-720
TebyakinaEkaterina Aug 22, 2024
6a678e8
Replace addMany with upsertMany in fetchNewPage reducer JC-720
TebyakinaEkaterina Aug 22, 2024
92278ac
Improve html in anime sort field component JC-720
TebyakinaEkaterina Aug 22, 2024
0f5490e
Disabling naming convention rule for all mappers JC-720
TebyakinaEkaterina Aug 26, 2024
348388c
Improve component styles by remove calculations JC-720
TebyakinaEkaterina Aug 26, 2024
4663390
Fix multiple border issue JC-720
TebyakinaEkaterina Aug 26, 2024
b5be629
Fix em-dash issue JC-720
TebyakinaEkaterina Aug 26, 2024
5c225c0
Fix indents JC-720
TebyakinaEkaterina Aug 26, 2024
eabdcea
Rename css class JC-720
TebyakinaEkaterina Aug 26, 2024
68a9ca2
Move elements variable as close to return JC-720
TebyakinaEkaterina Aug 26, 2024
8417dfb
Fix hook for infinite scroll JC-720
TebyakinaEkaterina Aug 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions apps/react/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { BrowserRouter } from 'react-router-dom';
import { StyledEngineProvider } from '@mui/material';

import { RootRouter } from './routes/RootRouter';
import { Header } from './components/header/Header';
import { store } from './store/store';
import { Header } from './components/Header/Header';
import { Progress } from './components/Progress/Progress';

import './theme/styles.css';

/** App component. */
Expand All @@ -15,12 +17,11 @@ export const App: FC = () => (
<BrowserRouter>
<div>
<StyledEngineProvider injectFirst>
<Suspense fallback={<div>Brrr... here should be your loader component</div>}>
<Header />
<Header />
<Suspense fallback={<Progress />}>
andrey-gazzaev marked this conversation as resolved.
Show resolved Hide resolved
<RootRouter />
</Suspense>
</StyledEngineProvider>

</div>
</BrowserRouter>
</Provider>
Expand Down
4 changes: 1 addition & 3 deletions apps/react/src/api/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
/**
* Config for api url.
*/
/** Config for api url. */
export const CONFIG = {
apiUrl: import.meta.env.VITE_APP_API_BASE_URL ?? '',
};
12 changes: 12 additions & 0 deletions apps/react/src/api/dtos/animeFilterParamsDto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/** Params for request to the server. Contains data about anime list filters. */
export type AnimeFilterParamsDto = {

/** String for searching anime. */
readonly search?: string;

/** Selected anime types for filtering anime. */
readonly type__in?: string;

/** Sorting settings for sorting anime. */
readonly ordering?: string;
};
8 changes: 8 additions & 0 deletions apps/react/src/api/dtos/animeSortDto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/** Anime sorting settings. Indicates by which field and in which direction the sorting is performed. */
export enum AnimeSortDto {
AscendingEnglishTitle = 'title_eng',
DescendingEnglishTitle = '-title_eng',
AscendingStatus = 'status',
DescendingStatus = '-status',
None = '',
}
4 changes: 1 addition & 3 deletions apps/react/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ import axios from 'axios';

import { CONFIG } from './config';

/**
* Http const with base url.
*/
/** Http const with base url. */
export const http = axios.create({
baseURL: CONFIG.apiUrl,
});
24 changes: 24 additions & 0 deletions apps/react/src/api/mappers/animeFilterParamsMapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { AnimeFilterParams } from '@js-camp/react/models/animeFilterParams';
import { AnimeTypeMapper } from '@js-camp/core/mappers/anime-type.mapper';
import { AnimeType } from '@js-camp/core/models/anime-type';

import { AnimeFilterParamsDto } from '../dtos/animeFilterParamsDto';

import { AnimeSortMapper } from './animeSortMapper';

export namespace AnimeFilterParamsMapper {

/**
* Map anime filter params model to dto.
* @param params - Model with anime filter params for UI.
* @returns Anime filter params dto.
*/
export function toDto(params: AnimeFilterParams): AnimeFilterParamsDto {

return {
search: params.searchTerm,
ordering: AnimeSortMapper.toDto(params.sortingSettings),
type__in: params.selectedTypes.map((animeType: AnimeType) => AnimeTypeMapper.toDto(animeType)).join(','),
};
}
}
43 changes: 43 additions & 0 deletions apps/react/src/api/mappers/animeSortMapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { AnimeSort } from '@js-camp/react/models/animeSort';
import { checkIsEnumMember } from '@js-camp/core/utils/check-is-enum.util';

import { AnimeSortDto } from '../dtos/animeSortDto';

export namespace AnimeSortMapper {
const ANIME_SORT_MAP_TO_DTO: Readonly<Record<AnimeSort, AnimeSortDto>> = {
[AnimeSort.AscendingEnglishTitle]: AnimeSortDto.AscendingEnglishTitle,
[AnimeSort.DescendingEnglishTitle]: AnimeSortDto.DescendingEnglishTitle,
[AnimeSort.AscendingStatus]: AnimeSortDto.AscendingStatus,
[AnimeSort.DescendingStatus]: AnimeSortDto.DescendingStatus,
[AnimeSort.None]: AnimeSortDto.None,
};

/**
* Map anime sorting setting from model to dto.
* @param sortingSettings - Sorting settings model.
* @returns Sorting settings dto.
*/
export function toDto(sortingSettings: AnimeSort): AnimeSortDto {
return ANIME_SORT_MAP_TO_DTO[sortingSettings];
}

/**
* Map anime sorting setting from string to model.
* @param sortingSettings - Sorting settings string.
* @returns Sorting settings model.
*/
export function fromString(sortingSettings: string): AnimeSort {
assertIsAnimeSort(sortingSettings);
return sortingSettings;
}

/**
* Assert that value is typeof AnimeSort.
* @param value - Value for checking.
*/
function assertIsAnimeSort(value: unknown): asserts value is AnimeSort {
if (!checkIsEnumMember(value, AnimeSort)) {
throw new Error(`${value} is not a valid AnimeSort!`);
}
}
}
36 changes: 36 additions & 0 deletions apps/react/src/api/services/animeService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Anime } from '@js-camp/core/models/anime';
import { PaginationDto } from '@js-camp/core/dtos/pagination.dto';
import { AnimeDto } from '@js-camp/core/dtos/anime.dto';
import { AnimeMapper } from '@js-camp/core/mappers/anime.mapper';
import { AnimeFilterParams } from '@js-camp/react/models/animeFilterParams';
import { Pagination } from '@js-camp/core/models/pagination';
import { PaginationMapper } from '@js-camp/core/mappers/pagination.mapper';

import { http } from '..';
import { AnimeFilterParamsMapper } from '../mappers/animeFilterParamsMapper';

const ANIME_LIST_URL = 'anime/anime/list-cursor/';

export namespace AnimeService {

/**
* Fetches a list of anime.
* @param params - Params for filtering anime.
*/
export async function fetchList(params: AnimeFilterParams): Promise<Pagination<Anime>> {
const { data } = await http.get<PaginationDto<AnimeDto>>(ANIME_LIST_URL, {
params: AnimeFilterParamsMapper.toDto(params),
});

return PaginationMapper.fromDto(data, AnimeMapper.fromDto);
}

/**
* Fetches a new page of anime list.
* @param newPageUrl - Url of new page.
*/
export async function fetchPageByUrl(newPageUrl: string): Promise<Pagination<Anime>> {
const { data } = await http.get<PaginationDto<AnimeDto>>(newPageUrl);
return PaginationMapper.fromDto(data, AnimeMapper.fromDto);
}
}
12 changes: 12 additions & 0 deletions apps/react/src/components/Progress/Progress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { FC, memo } from 'react';
import { Box, CircularProgress } from '@mui/material';

/** Component to show the loading process. */
const ProgressComponent: FC = () => (
<Box sx={{ display: 'flex', justifyContent: 'center', padding: 2 }}>
<CircularProgress />
</Box>
);

/** Memoized progress component. */
export const Progress = memo(ProgressComponent);
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.card {
padding: var(--space-m);
height: 100%;
}

.title {
font-size: var(--font-size-lg);
font-weight: var(--font-weight-semibold);
padding: var(--space-s) 0;
}

.information {
padding: var(--space-s) 0;
}
42 changes: 42 additions & 0 deletions apps/react/src/features/anime/components/AnimeCard/AnimeCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { memo, FC } from 'react';
import { useParams, Link } from 'react-router-dom';
import { Button, Paper, Typography } from '@mui/material';

import { ANIME_PATH, EDIT_ANIME_PATH } from '../../routes';

import styles from './AnimeCard.module.css';

/** Card with anime data. */
const AnimeCardComponent: FC = () => {

const { id } = useParams<{ id: string; }>();

const linkToEdit = `/${ANIME_PATH}/${id}/${EDIT_ANIME_PATH}`;

return (
<Paper
elevation={3}
className={styles.card}
>
<h2 className={styles.title}>
Item Name
</h2>
<div>
<Typography className={styles.information}>
Information about item with id = {id}
</Typography>
<Button
variant="outlined"
component={Link}
to={linkToEdit}
>
Edit
</Button>
</div>
</Paper>
);

};

/** Memoized anime card. */
export const AnimeCard = memo(AnimeCardComponent);
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { FC, memo } from 'react';

/** Anime edit form. */
const AnimeEditFormComponent: FC = () => (
<form>
Edit form
</form>
);

/** Memoized anime edit form. */
export const AnimeEditForm = memo(AnimeEditFormComponent);
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.form {
display: flex;
flex-direction: column;
gap: var(--space-xs);
padding: var(--space-s);
}

.row {
display: flex;
flex-direction: row;
align-items: center;
gap: var(--space-xs);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { memo, FC } from 'react';

import { AnimeSearchField } from '../AnimeSearchField/AnimeSearchField';
import { AnimeTypesField } from '../AnimeTypesField/AnimeTypesField';
import { AnimeSortField } from '../AnimeSortField/AnimeSortField';

import styles from './AnimeFilterForm.module.css';

/** Anime filter form. */
const AnimeFilterFormComponent: FC = () => (
<form className={styles.form}>
<div className={styles.row}>
<AnimeSearchField />
<AnimeTypesField />
</div>
<div className={styles.row}>
<AnimeSortField />
</div>
</form>
);

/** Memoized filter form. */
export const AnimeFilterForm = memo(AnimeFilterFormComponent);
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
.list {
overflow-y: auto;
padding-top: 0;
}

.item {
border-top: 1px var(--border-color) solid;
color: var(--primary-font-color);
display: flex;
flex-direction: row;
gap: var(--space-s);
cursor: pointer;
}

.item:hover,
.item:focus {
background-color: var(--hover-color);
}

.cover {
border-radius: 50%;
width: 80px;
height: 80px;
object-fit: cover;
}

.property {
display: flex;
align-items: center;
gap: var(--space-xs);
}

.propertyTitle {
white-space: nowrap;
font-size: var(--font-size-sm);
font-weight: var(--font-weight-semibold);
}

.propertyValue {
max-width: 100%;

/* Disable to use -webkit */
/* stylelint-disable-next-line value-no-vendor-prefix */
display: -webkit-box;
line-clamp: 1;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
font-size: var(--font-size-sm);
font-weight: var(--font-weight-regular);
}

.message {
text-align: center;
}
Loading
Loading