All files / src/store/features/entities/reducers worldReducers.ts

93.75% Statements 30/32
81.82% Branches 9/11
80% Functions 4/5
93.75% Lines 30/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96                  46x   46x       46x                   46x 3x 3x 3x     3x     2x       3x 3x 2x   3x 2x       3x 3x 3x 3x     3x 3x     3x 2x 2x 2x 2x 2x 2x                         46x                         46x         46x  
import {
  PayloadAction,
  CaseReducer,
  SliceCaseReducers,
} from "@reduxjs/toolkit";
import {
  EntitiesState,
  SceneNormalized,
} from "shared/lib/entities/entitiesTypes";
import { applyReparentFolderToCollection } from "shared/lib/entities/entitiesHelpers";
import { Note } from "shared/lib/resources/types";
import {
  localSceneSelectById,
  localNoteSelectById,
} from "store/features/entities/helpers";
import { MIN_WORLD_ENTITY_X, MIN_WORLD_ENTITY_Y } from "consts";
 
const moveWorldEntities: CaseReducer<
  EntitiesState,
  PayloadAction<{
    entityId: string;
    additionalEntityIds: string[];
    x: number;
    y: number;
  }>
> = (state, action) => {
  const scene = localSceneSelectById(state, action.payload.entityId);
  const note = localNoteSelectById(state, action.payload.entityId);
  const entity = scene || note;
 
  const additionalEntities: (SceneNormalized | Note)[] =
    action.payload.additionalEntityIds
      .map(
        (id) =>
          localSceneSelectById(state, id) || localNoteSelectById(state, id),
      )
      .filter(Boolean);
 
  if (entity) {
    const minSelectionX = Math.min(
      ...additionalEntities.map((e) => (e ? e.x - entity.x : 0)),
    );
    const minSelectionY = Math.min(
      ...additionalEntities.map((e) => (e ? e.y - entity.y : 0)),
    );
 
    // Based on full selection determine minX and minY for current entity
    const newX = Math.max(MIN_WORLD_ENTITY_X - minSelectionX, action.payload.x);
    const newY = Math.max(MIN_WORLD_ENTITY_Y - minSelectionY, action.payload.y);
    const diffX = newX - entity.x;
    const diffY = newY - entity.y;
 
    // Move entity
    entity.x = newX;
    entity.y = newY;
 
    // Move additionally selected entities by same amount
    for (const additionalEntity of additionalEntities) {
      if (additionalEntity.id !== action.payload.entityId) {
        if (additionalEntity) {
          const newX = Math.max(MIN_WORLD_ENTITY_X, additionalEntity.x + diffX);
          const newY = Math.max(MIN_WORLD_ENTITY_Y, additionalEntity.y + diffY);
          additionalEntity.x = newX;
          additionalEntity.y = newY;
        }
      }
    }
  }
};
 
const reparentWorldFolder: CaseReducer<
  EntitiesState,
  PayloadAction<{
    fromPath: string;
    toPath: string;
  }>
> = (state, action) => {
  applyReparentFolderToCollection(
    state.scenes.entities,
    action.payload.fromPath,
    action.payload.toPath,
  );
  applyReparentFolderToCollection(
    state.notes.entities,
    action.payload.fromPath,
    action.payload.toPath,
  );
};
 
const worldReducers = {
  moveWorldEntities,
  reparentWorldFolder,
} satisfies SliceCaseReducers<EntitiesState>;
 
export default worldReducers;