Skip to content
Snippets Groups Projects
Commit d0a3bf9d authored by Adrian Orłów's avatar Adrian Orłów
Browse files

feat: add map base data

parent 52ef7073
No related branches found
No related tags found
2 merge requests!223reset the pin numbers before search results are fetch (so the results will be...,!43feat: add map full data mgmt
Pipeline #80212 passed
Showing
with 248 additions and 26 deletions
NEXT_PUBLIC_BASE_API_URL = 'https://corsproxy.io/?https://pdmap.uni.lu/minerva/api'
BASE_MAP_IMAGES_URL = 'https://pdmap.uni.lu'
NEXT_PUBLIC_PROJECT_ID = 'pd_map_winter_23'
\ No newline at end of file
......@@ -4,6 +4,12 @@ const nextConfig = {
experimental: {
fontLoaders: [{ loader: '@next/font/google', options: { subsets: ['latin'] } }],
},
env: {
BASE_API_URL: process.env.NEXT_PUBLIC_BASE_API_URL || '',
BASE_MAP_IMAGES_URL: process.env.BASE_MAP_IMAGES_URL || '',
PROJECT_ID: process.env.NEXT_PUBLIC_PROJECT_ID || '',
ZOD_SEED: 997,
},
};
module.exports = nextConfig;
export const BASE_API_URL = process.env.NEXT_PUBLIC_BASE_API_URL || '';
export const BASE_MAP_IMAGES_URL = process.env.BASE_MAP_IMAGES_URL || '';
export const PROJECT_ID = process.env.NEXT_PUBLIC_PROJECT_ID || '';
export const ZOD_SEED = 997;
import { z } from 'zod';
export const mapBackground = z.object({
id: z.number(),
name: z.string(),
defaultOverlay: z.boolean(),
project: z.object({ projectId: z.string() }),
creator: z.object({ login: z.string() }),
status: z.string(),
progress: z.number(),
description: z.null(),
order: z.number(),
images: z.array(
z.object({
id: z.number(),
model: z.object({ id: z.number() }),
projectBackground: z.object({ id: z.number() }),
path: z.string(),
}),
),
});
import { z } from 'zod';
export const mapModel = z.object({
idObject: z.number(),
width: z.number(),
height: z.number(),
defaultCenterX: z.number().nullable(),
defaultCenterY: z.number().nullable(),
description: z.string(),
name: z.string(),
defaultZoomLevel: z.number().nullable(),
tileSize: z.number(),
references: z.array(z.unknown()),
authors: z.array(z.unknown()),
creationDate: z.unknown(),
modificationDates: z.array(z.unknown()),
minZoom: z.number(),
maxZoom: z.number(),
});
import { z } from 'zod';
export const mapOverlay = z.object({
name: z.string(),
googleLicenseConsent: z.boolean(),
creator: z.string(),
description: z.string(),
genomeType: z.null(),
genomeVersion: z.null(),
idObject: z.number(),
publicOverlay: z.boolean(),
type: z.string(),
order: z.number(),
});
import { z } from 'zod';
export const overviewImageView = 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 { z } from 'zod';
import { disease } from './disease';
import { organism } from './organism';
import { overviewImageView } from './overviewImageView';
export const projectSchema = z.object({
version: z.string(),
......@@ -18,30 +19,5 @@ export const projectSchema = z.object({
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(),
}),
]),
),
}),
),
overviewImageViews: z.array(overviewImageView),
});
......@@ -9,4 +9,11 @@ export const apiPath = {
`projects/${PROJECT_ID}/miRnas:search?query=${searchQuery}`,
getChemicalsStringWithQuery: (searchQuery: string): string =>
`projects/${PROJECT_ID}/chemicals:search?query=${searchQuery}`,
getAllModelsByProjectIdQuery: (projectId: string): string => `projects/${projectId}/models/*/`,
getAllOverlaysByProjectIdQuery: (
projectId: string,
{ publicOverlay }: { publicOverlay: boolean },
): string => `projects/${projectId}/overlays/?publicOverlay=${String(publicOverlay)}`,
getAllBackgroundsByProjectIdQuery: (projectId: string): string =>
`projects/${projectId}/backgrounds/`,
};
import { createSelector } from '@reduxjs/toolkit';
import { mapDataSelector } from '../map/map.selectors';
import { rootSelector } from '../root/root.selectors';
export const backgroundsSelector = createSelector(rootSelector, state => state.backgrounds);
export const backgroundsDataSelector = createSelector(
backgroundsSelector,
backgrounds => backgrounds.data || [],
);
export const currentBackgroundSelector = createSelector(
backgroundsDataSelector,
mapDataSelector,
(backgrounds, mapData) => backgrounds.find(background => background.id === mapData.backgroundId),
);
export const currentBackgroundImageSelector = createSelector(
mapDataSelector,
currentBackgroundSelector,
(mapData, background) =>
background ? background.images.find(image => image.model.id === mapData.modelId) : undefined,
);
export const currentBackgroundImagePathSelector = createSelector(
currentBackgroundImageSelector,
image => (image ? image.path : ''),
);
import { ActionReducerMapBuilder } from '@reduxjs/toolkit';
import { getAllBackgroundsByProjectId } from './backgrounds.thunks';
import { BackgroundsState } from './backgrounds.types';
export const getAllBackgroundsByProjectIdReducer = (
builder: ActionReducerMapBuilder<BackgroundsState>,
): void => {
builder.addCase(getAllBackgroundsByProjectId.fulfilled, (state, action) => {
state.data = action.payload || [];
state.loading = 'succeeded';
});
};
import { createSlice } from '@reduxjs/toolkit';
import { getAllBackgroundsByProjectIdReducer } from './backgrounds.reducers';
import { BackgroundsState } from './backgrounds.types';
const initialState: BackgroundsState = {
data: [],
loading: 'idle',
error: { name: '', message: '' },
};
const backgroundsState = createSlice({
name: 'backgrounds',
initialState,
reducers: {},
extraReducers: builder => {
getAllBackgroundsByProjectIdReducer(builder);
},
});
export default backgroundsState.reducer;
import { mapBackground } from '@/models/mapBackground';
import { axiosInstance } from '@/services/api/utils/axiosInstance';
import { MapBackground } from '@/types/models';
import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
import { createAsyncThunk } from '@reduxjs/toolkit';
import { z } from 'zod';
import { apiPath } from '../apiPath';
export const getAllBackgroundsByProjectId = createAsyncThunk(
'models/getAllBackgroundsByProjectId',
async (projectId: string): Promise<MapBackground[]> => {
const response = await axiosInstance.get<MapBackground[]>(
apiPath.getAllBackgroundsByProjectIdQuery(projectId),
);
const isDataValid = validateDataUsingZodSchema(response.data, z.array(mapBackground));
return isDataValid ? response.data : [];
},
);
import { FetchDataState } from '@/types/fetchDataState';
import { MapBackground } from '@/types/models';
export type BackgroundsState = FetchDataState<MapBackground[] | []>;
......@@ -11,6 +11,7 @@ export const MAP_DATA_INITIAL_STATE: MapData = {
projectId: PROJECT_ID,
meshId: '',
modelId: 0,
backgroundId: 0,
overlaysIds: [],
position: DEFAULT_CENTER_POINT,
show: {
......
......@@ -13,6 +13,7 @@ export type MapData = {
projectId: string;
meshId: string;
modelId: number;
backgroundId: number;
overlaysIds: number[];
size: MapSize;
position: Point;
......
import { getAllModelsByProjectId } from '@/redux/models/models.thunks';
import { ActionReducerMapBuilder } from '@reduxjs/toolkit';
import { ModelsState } from './models.types';
export const getAllModelsByProjectIdReducer = (
builder: ActionReducerMapBuilder<ModelsState>,
): void => {
builder.addCase(getAllModelsByProjectId.fulfilled, (state, action) => {
state.data = action.payload || [];
state.loading = 'succeeded';
});
};
import { rootSelector } from '@/redux/root/root.selectors';
import { createSelector } from '@reduxjs/toolkit';
import { mapDataSelector } from '../map/map.selectors';
export const modelsSelector = createSelector(rootSelector, state => state.models);
export const modelsDataSelector = createSelector(modelsSelector, models => models.data || []);
export const currentModelSelector = createSelector(
modelsSelector,
mapDataSelector,
(models, mapData) => models.find(model => model.idObject === mapData.modelId),
);
import { createSlice } from '@reduxjs/toolkit';
import { getAllModelsByProjectIdReducer } from './models.reducers';
import { ModelsState } from './models.types';
const initialState: ModelsState = {
data: [],
loading: 'idle',
error: { name: '', message: '' },
};
const modelsSlice = createSlice({
name: 'models',
initialState,
reducers: {},
extraReducers: builder => {
getAllModelsByProjectIdReducer(builder);
},
});
export default modelsSlice.reducer;
import { mapModel } from '@/models/mapModel';
import { axiosInstance } from '@/services/api/utils/axiosInstance';
import { MapModel } from '@/types/models';
import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
import { createAsyncThunk } from '@reduxjs/toolkit';
import { z } from 'zod';
import { apiPath } from '../apiPath';
export const getAllModelsByProjectId = createAsyncThunk(
'models/getAllModelsByProjectId',
async (projectId: string): Promise<MapModel[]> => {
const response = await axiosInstance.get<MapModel[]>(
apiPath.getAllModelsByProjectIdQuery(projectId),
);
const isDataValid = validateDataUsingZodSchema(response.data, z.array(mapModel));
return isDataValid ? response.data : [];
},
);
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