Skip to content
Snippets Groups Projects
Commit 18e5b773 authored by Tadeusz Miesiąc's avatar Tadeusz Miesiąc
Browse files

Merge branch 'feature/setup-redux-async' into 'development'

Feature/setup redux async

See merge request !16
parents f65ae074 5435ce93
No related branches found
No related tags found
3 merge requests!223reset the pin numbers before search results are fetch (so the results will be...,!16Feature/setup redux async,!15Feature/setup redux
Pipeline #78829 failed
Showing
with 518 additions and 2212 deletions
...@@ -65,7 +65,9 @@ ...@@ -65,7 +65,9 @@
"**/jest.setup.ts", // jest setup "**/jest.setup.ts", // jest setup
"**/setupTests.ts" "**/setupTests.ts"
], ],
"optionalDependencies": false "optionalDependencies": false,
"peerDependencies": false,
"packageDir": "./"
} }
], ],
"indent": ["error", 2], "indent": ["error", 2],
...@@ -83,6 +85,12 @@ ...@@ -83,6 +85,12 @@
"rules": { "rules": {
"@typescript-eslint/explicit-function-return-type": "error" "@typescript-eslint/explicit-function-return-type": "error"
} }
},
{
// feel free to replace with your preferred file pattern - eg. 'src/**/*Slice.ts'
"files": ["src/**/*.slice.ts", "src/**/*.reducers.ts"],
// avoid state param assignment
"rules": { "no-param-reassign": ["error", { "props": false }] }
} }
], ],
"settings": { "settings": {
......
/// <reference types="next" /> /// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" /> /// <reference types="next/navigation-types/compat/navigation" />
// NOTE: This file should not be edited // NOTE: This file should not be edited
......
This diff is collapsed.
import { AppWrapper } from '@/components/AppWrapper';
import type { AppProps } from 'next/app';
const MyApp = ({ Component, pageProps }: AppProps): JSX.Element => (
<AppWrapper>
<Component {...pageProps} />
</AppWrapper>
);
export default MyApp;
import { useSelector } from 'react-redux';
import { selectSearchValue } from '@/redux/search/search.selectors';
import { setSearchValue } from '@/redux/search/search.slice';
import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
import { getProjectById } from '@/redux/project/project.thunks';
const ReduxPage = (): JSX.Element => {
const dispatch = useAppDispatch();
const searchValue = useSelector(selectSearchValue);
const triggerSyncUpdate = (): void => {
// eslint-disable-next-line prefer-template
const newValue = searchValue + 'test';
dispatch(setSearchValue(newValue));
dispatch(getProjectById('pd_map_winter_23'));
};
return (
<div>
{searchValue}
<button type="button" onClick={triggerSyncUpdate}>
sync update
</button>
</div>
);
};
export default ReduxPage;
import { ReactNode } from 'react';
import { Provider } from 'react-redux';
import { store } from '@/redux/store';
interface AppWrapperProps {
children: ReactNode;
}
export const AppWrapper = ({ children }: AppWrapperProps): JSX.Element => (
<Provider store={store}>{children}</Provider>
);
export { AppWrapper } from './AppWrapper.component';
...@@ -3,6 +3,6 @@ import avatarImg from '@/assets/images/user-avatar.png'; ...@@ -3,6 +3,6 @@ import avatarImg from '@/assets/images/user-avatar.png';
export const UserAvatar = (): JSX.Element => ( export const UserAvatar = (): JSX.Element => (
<div className="w-8 h-8 mr-7" data-testid="user-avatar"> <div className="w-8 h-8 mr-7" data-testid="user-avatar">
<Image src={avatarImg} alt="user avatar" height={32} width={32} /> <Image src={avatarImg} alt="user avatar" width={32} height={32} />
</div> </div>
); );
export const BASE_API_URL = 'https://corsproxy.io/?https://pdmap.uni.lu/minerva/api';
import { z } from 'zod';
export const disease = z.object({
link: z.string(),
type: z.string(),
resource: z.string(),
id: z.number(),
annotatorClassName: z.string(),
});
import { z } from 'zod';
export const organism = z.object({
link: z.string(),
type: z.string(),
resource: z.string(),
id: z.number(),
annotatorClassName: z.string(),
});
import { z } from 'zod';
import { disease } from './disease';
import { organism } from './organism';
export const projectSchema = z.object({
version: z.string(),
disease,
organism,
idObject: z.number(),
status: z.string(),
directory: z.string(),
progress: z.number(),
notifyEmail: z.string(),
logEntries: z.boolean(),
name: z.string(),
sharedInMinervaNet: z.boolean(),
owner: z.string(),
projectId: z.string(),
creationDate: z.string(),
mapCanvasType: z.string(),
overviewImageViews: z.array(
z.object({
idObject: z.number(),
filename: z.string(),
width: z.number(),
height: z.number(),
links: z.array(
z.union([
z.object({
idObject: z.number(),
polygon: z.array(z.object({ x: z.number(), y: z.number() })),
imageLinkId: z.number(),
type: z.string(),
}),
z.object({
idObject: z.number(),
polygon: z.array(z.object({ x: z.number(), y: z.number() })),
zoomLevel: z.number(),
modelPoint: z.object({ x: z.number(), y: z.number() }),
modelLinkId: z.number(),
type: z.string(),
}),
]),
),
}),
),
});
import { useDispatch } from 'react-redux';
import { AppDispatch } from '@/redux/store';
export const useAppDispatch: () => AppDispatch = useDispatch;
import { useSelector } from 'react-redux';
import type { TypedUseSelectorHook } from 'react-redux';
import { RootState } from '@/redux/store';
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
import { ActionReducerMapBuilder } from '@reduxjs/toolkit';
import { ProjectState } from '@/redux/project/project.types';
import { getProjectById } from '@/redux/project/project.thunks';
export const getProjectByIdReducer = (builder: ActionReducerMapBuilder<ProjectState>): void => {
builder.addCase(getProjectById.fulfilled, (state, action) => {
state.data = action.payload;
state.loading = 'succeeded';
});
};
import { createSlice } from '@reduxjs/toolkit';
import { ProjectState } from '@/redux/project/project.types';
import { getProjectByIdReducer } from './project.reducers';
const initialState: ProjectState = {
data: [],
loading: 'idle',
error: { name: '', message: '' },
};
const projectSlice = createSlice({
name: 'project',
initialState,
reducers: {},
extraReducers: builder => {
getProjectByIdReducer(builder);
},
});
export default projectSlice.reducer;
import { createAsyncThunk } from '@reduxjs/toolkit';
import { axiosInstance } from '@/services/api/utils/axiosInstance';
import { Project } from '@/types/api';
import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
import { projectSchema } from '@/models/project';
export const getProjectById = createAsyncThunk(
'project/getUsersByIdStatus',
async (id: string): Promise<Project | undefined> => {
const response = await axiosInstance.get<Project>(`projects/${id}`);
const isDataValid = validateDataUsingZodSchema(response.data, projectSchema);
return isDataValid ? response.data : undefined;
},
);
import { Project } from '@/types/api';
export type ProjectState = {
data: Project | undefined | [];
loading: 'idle' | 'pending' | 'succeeded' | 'failed';
error: Error;
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment