diff --git a/config/webpack/webpack.common.js b/config/webpack/webpack.common.js index 97ca87b631..c9105942e9 100644 --- a/config/webpack/webpack.common.js +++ b/config/webpack/webpack.common.js @@ -169,6 +169,7 @@ module.exports = { "@ui-kebab-menu": getDir("src/modules/ui/kebab-menu"), "@ui-layout": getDir("src/modules/ui/layout"), "@ui-light-box": getDir("src/modules/ui/light-box"), + "@ui-line-clamp": getDir("src/modules/ui/line-clamp"), "@ui-preview-image": getDir("src/modules/ui/preview-image"), "@ui-room-details": getDir("src/modules/ui/room-details"), "@ui-skip-link": getDir("src/modules/ui/skip-link"), diff --git a/src/components/organisms/vCustomDialog.vue b/src/components/organisms/vCustomDialog.vue index 8e503755e0..706dedebaa 100644 --- a/src/components/organisms/vCustomDialog.vue +++ b/src/components/organisms/vCustomDialog.vue @@ -6,7 +6,7 @@ @click:outside="closeDialog" @keydown.esc="closeDialog" > - + diff --git a/src/modules/data/board/Board.store.ts b/src/modules/data/board/Board.store.ts index e06a91adba..eeb3a9ed6f 100644 --- a/src/modules/data/board/Board.store.ts +++ b/src/modules/data/board/Board.store.ts @@ -324,7 +324,7 @@ export const useBoardStore = defineStore("boardStore", () => { const deleteBoardSuccess = (payload: DeleteBoardSuccessPayload) => { if (payload.isOwnAction === true) { router.replace({ - name: "rooms-id", + name: "room-details", params: { id: roomId.value }, }); return; diff --git a/src/modules/data/board/Board.store.unit.ts b/src/modules/data/board/Board.store.unit.ts index d5a62b912f..2bdc64d6e2 100644 --- a/src/modules/data/board/Board.store.unit.ts +++ b/src/modules/data/board/Board.store.unit.ts @@ -1196,7 +1196,7 @@ describe("BoardStore", () => { }); expect(router.replace).toHaveBeenCalledWith({ - name: "rooms-id", + name: "room-details", params: { id: "roomId" }, }); }); diff --git a/src/modules/data/room/RoomCreate.state.ts b/src/modules/data/room/RoomCreate.state.ts index 12d6e390e8..8a1c607a13 100644 --- a/src/modules/data/room/RoomCreate.state.ts +++ b/src/modules/data/room/RoomCreate.state.ts @@ -1,5 +1,5 @@ -import { RoomApiFactory, RoomColor } from "@/serverApi/v3"; -import { RoomCreateParams, RoomItem } from "@/types/room/Room"; +import { RoomApiFactory } from "@/serverApi/v3"; +import { RoomCreateParams, RoomItem, RoomColorEnum } from "@/types/room/Room"; import { $axios, mapAxiosErrorToResponseError } from "@/utils/api"; import { ref } from "vue"; @@ -9,7 +9,7 @@ export const useRoomCreateState = () => { const roomData = ref({ name: "", - color: RoomColor.BlueGrey, + color: RoomColorEnum.BlueGrey, startDate: undefined, endDate: undefined, }); diff --git a/src/modules/data/room/RoomCreate.state.unit.ts b/src/modules/data/room/RoomCreate.state.unit.ts index 8f17f278b3..f6613980d2 100644 --- a/src/modules/data/room/RoomCreate.state.unit.ts +++ b/src/modules/data/room/RoomCreate.state.unit.ts @@ -6,7 +6,7 @@ import { useApplicationError } from "@/composables/application-error.composable" import { initializeAxios, mapAxiosErrorToResponseError } from "@/utils/api"; import setupStores from "@@/tests/test-utils/setupStores"; import ApplicationErrorModule from "@/store/application-error"; -import { RoomCreateParams } from "@/types/room/Room"; +import { RoomCreateParams, RoomColorEnum } from "@/types/room/Room"; import { ref } from "vue"; import { apiResponseErrorFactory, @@ -73,7 +73,7 @@ describe("useRoomCreateState", () => { describe("createRoom", () => { const roomData = ref({ name: "Room 1", - color: serverApi.RoomColor.BlueGrey, + color: RoomColorEnum.BlueGrey, startDate: undefined, endDate: undefined, }); diff --git a/src/modules/data/room/RoomDetails.store.ts b/src/modules/data/room/RoomDetails.store.ts index 02a288c5a0..af82c1c601 100644 --- a/src/modules/data/room/RoomDetails.store.ts +++ b/src/modules/data/room/RoomDetails.store.ts @@ -1,7 +1,13 @@ import { RoomBoardItem, RoomDetails } from "@/types/room/Room"; import { ref } from "vue"; import { defineStore } from "pinia"; -import { RoomApiFactory } from "@/serverApi/v3"; +import { + BoardApiFactory, + BoardLayout, + BoardParentType, + CreateBoardBodyParams, + RoomApiFactory, +} from "@/serverApi/v3"; import { $axios, mapAxiosErrorToResponseError } from "@/utils/api"; import { createApplicationError } from "@/utils/create-application-error.factory"; @@ -17,6 +23,7 @@ export const useRoomDetailsStore = defineStore("roomDetailsStore", () => { const roomBoards = ref([]); const roomApi = RoomApiFactory(undefined, "/v3", $axios); + const boardApi = BoardApiFactory(undefined, "/v3", $axios); const fetchRoom = async (id: string) => { try { @@ -38,6 +45,22 @@ export const useRoomDetailsStore = defineStore("roomDetailsStore", () => { } }; + const createBoard = async ( + roomId: string, + layout: BoardLayout, + title: string + ) => { + const params: CreateBoardBodyParams = { + title: title, + parentId: roomId, + parentType: BoardParentType.Room, + layout, + }; + const boardId = (await boardApi.boardControllerCreateBoard(params)).data.id; + + return boardId; + }; + const resetState = () => { isLoading.value = true; room.value = undefined; @@ -51,6 +74,7 @@ export const useRoomDetailsStore = defineStore("roomDetailsStore", () => { return { deactivateRoom, fetchRoom, + createBoard, isLoading, resetState, room, diff --git a/src/modules/data/room/RoomDetails.store.unit.ts b/src/modules/data/room/RoomDetails.store.unit.ts index ae0bca7fa4..b14e8b6d23 100644 --- a/src/modules/data/room/RoomDetails.store.unit.ts +++ b/src/modules/data/room/RoomDetails.store.unit.ts @@ -8,6 +8,7 @@ import { initializeAxios, mapAxiosErrorToResponseError } from "@/utils/api"; import { apiResponseErrorFactory, axiosErrorFactory, + mockApiResponse, } from "@@/tests/test-utils"; jest.mock("@/utils/api"); @@ -35,12 +36,14 @@ const setupErrorResponse = (message = "NOT_FOUND", code = 404) => { describe("useRoomDetailsStore", () => { let roomApiMock: DeepMocked; + let boardApiMock: DeepMocked; let axiosMock: DeepMocked; let mockedCreateApplicationErrorCalls: ReturnType; beforeEach(() => { setActivePinia(createPinia()); roomApiMock = createMock(); + boardApiMock = createMock(); axiosMock = createMock(); mockedCreateApplicationErrorCalls = createMock>(); @@ -49,6 +52,7 @@ describe("useRoomDetailsStore", () => { ); jest.spyOn(serverApi, "RoomApiFactory").mockReturnValue(roomApiMock); + jest.spyOn(serverApi, "BoardApiFactory").mockReturnValue(boardApiMock); initializeAxios(axiosMock); }); @@ -135,4 +139,30 @@ describe("useRoomDetailsStore", () => { expect(store.room).toBeUndefined(); }); }); + + describe("createBoard", () => { + it("should call createBoard api", async () => { + const { store } = setup(); + const boardId = "board-id"; + const roomId = "room-id"; + const layout = serverApi.BoardLayout.Columns; + const title = "title"; + + boardApiMock.boardControllerCreateBoard.mockResolvedValue( + mockApiResponse({ + data: { id: boardId }, + }) + ); + + const result = await store.createBoard(roomId, layout, title); + + expect(result).toBe(boardId); + expect(boardApiMock.boardControllerCreateBoard).toHaveBeenCalledWith({ + title, + parentId: roomId, + parentType: serverApi.BoardParentType.Room, + layout, + }); + }); + }); }); diff --git a/src/modules/data/room/RoomEdit.state.ts b/src/modules/data/room/RoomEdit.state.ts index 6ba2853c07..5dcac87131 100644 --- a/src/modules/data/room/RoomEdit.state.ts +++ b/src/modules/data/room/RoomEdit.state.ts @@ -1,5 +1,9 @@ -import { RoomApiFactory, RoomColor } from "@/serverApi/v3"; -import { RoomDetails, RoomUpdateParams } from "@/types/room/Room"; +import { RoomApiFactory } from "@/serverApi/v3"; +import { + RoomDetails, + RoomUpdateParams, + RoomColorEnum, +} from "@/types/room/Room"; import { $axios, mapAxiosErrorToResponseError } from "@/utils/api"; import { createApplicationError } from "@/utils/create-application-error.factory"; import { ref } from "vue"; @@ -19,7 +23,7 @@ export const useRoomEditState = () => { const roomData = ref({ name: "", - color: RoomColor.BlueGrey, + color: RoomColorEnum.BlueGrey, startDate: undefined, endDate: undefined, }); diff --git a/src/modules/data/room/RoomEdit.state.unit.ts b/src/modules/data/room/RoomEdit.state.unit.ts index 52bf187f5b..fc1cc125b4 100644 --- a/src/modules/data/room/RoomEdit.state.unit.ts +++ b/src/modules/data/room/RoomEdit.state.unit.ts @@ -10,6 +10,7 @@ import { apiResponseErrorFactory, axiosErrorFactory, } from "@@/tests/test-utils"; +import { RoomColorEnum } from "@/types/room/Room"; jest.mock("@/utils/api"); const mockedMapAxiosErrorToResponseError = jest.mocked( @@ -105,7 +106,7 @@ describe("useRoomEditState", () => { expect(isLoading.value).toBe(true); const params = { name: "room-name", - color: serverApi.RoomColor.BlueGrey, + color: RoomColorEnum.BlueGrey, }; await updateRoom("room-id", params); @@ -123,7 +124,7 @@ describe("useRoomEditState", () => { const { updateRoom, isLoading } = setup(); const params = { name: "room-name", - color: serverApi.RoomColor.BlueGrey, + color: RoomColorEnum.BlueGrey, }; roomApiMock.roomControllerUpdateRoom.mockRejectedValue({ code: 404 }); diff --git a/src/modules/data/room/Rooms.state.unit.ts b/src/modules/data/room/Rooms.state.unit.ts index b5ad2d8f0f..09440ba79b 100644 --- a/src/modules/data/room/Rooms.state.unit.ts +++ b/src/modules/data/room/Rooms.state.unit.ts @@ -10,6 +10,7 @@ import { apiResponseErrorFactory, axiosErrorFactory, } from "@@/tests/test-utils"; +import { RoomColorEnum } from "@/types/room/Room"; jest.mock("@/utils/api"); const mockedMapAxiosErrorToResponseError = jest.mocked( @@ -125,7 +126,7 @@ describe("useRoomsState", () => { { id: "1", name: "Room 1", - color: serverApi.RoomColor.BlueGrey, + color: RoomColorEnum.BlueGrey, schoolId: "6749dd4e657d98af622e370c", createdAt: "2024.11.18", updatedAt: "2024.11.18", diff --git a/src/modules/feature/board/board/Board.unit.ts b/src/modules/feature/board/board/Board.unit.ts index b7339b7fef..03d68e7045 100644 --- a/src/modules/feature/board/board/Board.unit.ts +++ b/src/modules/feature/board/board/Board.unit.ts @@ -882,7 +882,7 @@ describe("Board", () => { expect(wrapperVM.isBoardVisible).toBe(false); expect(router.replace).toHaveBeenCalledWith({ - name: "rooms-id", + name: "room-details", params: { id: mockRoomId }, }); expect( diff --git a/src/modules/feature/board/board/Board.vue b/src/modules/feature/board/board/Board.vue index 4b7bac62ad..05d59f0475 100644 --- a/src/modules/feature/board/board/Board.vue +++ b/src/modules/feature/board/board/Board.vue @@ -322,7 +322,7 @@ watch( setAlert(); if (!(isBoardVisible.value || isTeacher)) { - router.replace({ name: "rooms-id", params: { id: roomId.value } }); + router.replace({ name: "room-details", params: { id: roomId.value } }); applicationErrorModule.setError( createApplicationError( HttpStatusCode.Forbidden, diff --git a/src/modules/feature/room/BoardGrid.vue b/src/modules/feature/room/BoardGrid.vue index 0439c5bdc0..25f86243e3 100644 --- a/src/modules/feature/room/BoardGrid.vue +++ b/src/modules/feature/room/BoardGrid.vue @@ -4,6 +4,7 @@ v-for="(board, index) in boards" :key="board.id" cols="12" + sm="6" md="4" xl="3" > diff --git a/src/modules/feature/room/BoardTile.unit.ts b/src/modules/feature/room/BoardTile.unit.ts index 6229d21a97..3ae2b7eaef 100644 --- a/src/modules/feature/room/BoardTile.unit.ts +++ b/src/modules/feature/room/BoardTile.unit.ts @@ -42,7 +42,7 @@ describe("@feature-room/BoardTile", () => { it("should display tile in draft style", () => { const { wrapper } = setup({ board: mockBoard, index: 0 }); - expect(wrapper.classes()).toContain("board-is-draft"); + expect(wrapper.classes()).toContain("opacity-70"); }); }); }); diff --git a/src/modules/feature/room/BoardTile.vue b/src/modules/feature/room/BoardTile.vue index 2f643bd0f4..7e8659437c 100644 --- a/src/modules/feature/room/BoardTile.vue +++ b/src/modules/feature/room/BoardTile.vue @@ -1,23 +1,26 @@ @@ -28,6 +31,7 @@ import { RoomBoardItem } from "@/types/room/Room"; import { mdiViewAgendaOutline, mdiViewDashboardOutline } from "@icons/material"; import { computed, PropType, toRef } from "vue"; import { useI18n } from "vue-i18n"; +import { LineClamp } from "@ui-line-clamp"; const props = defineProps({ board: { type: Object as PropType, required: true }, @@ -35,7 +39,6 @@ const props = defineProps({ }); const { t } = useI18n(); - const board = toRef(props, "board"); const isListBoard = computed(() => { @@ -50,6 +53,7 @@ const subtitleIcon = computed(() => { const icon = isListBoard.value ? mdiViewAgendaOutline : mdiViewDashboardOutline; + return icon; }); @@ -62,6 +66,7 @@ const subtitleText = computed(() => { const suffix = ` - ${t("common.words.draft")}`; return text + suffix; } + return text; }); @@ -69,17 +74,3 @@ const boardPath = computed(() => { return `/boards/${board.value.id}`; }); - - diff --git a/src/modules/feature/room/RoomColorPicker/RoomColorPicker.unit.ts b/src/modules/feature/room/RoomColorPicker/RoomColorPicker.unit.ts index 68459cdc87..9bc9964f9b 100644 --- a/src/modules/feature/room/RoomColorPicker/RoomColorPicker.unit.ts +++ b/src/modules/feature/room/RoomColorPicker/RoomColorPicker.unit.ts @@ -5,7 +5,7 @@ import { import { mount } from "@vue/test-utils"; import { ComponentProps } from "vue-component-type-helpers"; import RoomColorPicker from "./RoomColorPicker.vue"; -import { RoomColor } from "@/serverApi/v3"; +import { RoomColorEnum } from "@/types/room/Room"; describe("@feature-room/RoomColorPicker", () => { const setup = (props?: ComponentProps) => { @@ -42,7 +42,7 @@ describe("@feature-room/RoomColorPicker", () => { describe("when a color is given", () => { it("should render given color as selected", () => { - const { wrapper } = setup({ color: RoomColor.Red }); + const { wrapper } = setup({ color: RoomColorEnum.Red }); const selectedColor = wrapper.findComponent( "[data-testid=color-swatch-red]" diff --git a/src/modules/feature/room/RoomColorPicker/RoomColorPicker.vue b/src/modules/feature/room/RoomColorPicker/RoomColorPicker.vue index bd8f65954e..b338f94c02 100644 --- a/src/modules/feature/room/RoomColorPicker/RoomColorPicker.vue +++ b/src/modules/feature/room/RoomColorPicker/RoomColorPicker.vue @@ -5,7 +5,7 @@ role="radiogroup" aria-labelledby="room-color-label" > -