Skip to content

Commit

Permalink
BC-3933 - draft-status / visibility of course-board to students (#3132)
Browse files Browse the repository at this point in the history
* add room card menus for boards

* added board menu to update visibility

* adjusted draft chip to layout from archive chip

---------

Co-authored-by: Odalys Adam <[email protected]>
Co-authored-by: Uwe Ilgenstein <[email protected]>
  • Loading branch information
3 people authored Mar 12, 2024
1 parent 05875b2 commit 55ad2bc
Show file tree
Hide file tree
Showing 30 changed files with 3,173 additions and 2,463 deletions.
8 changes: 8 additions & 0 deletions src/components/data-board/BoardApi.composable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,13 @@ export const useBoardApi = () => {
};
};

const updateBoardVisibilityCall = async (
boardId: string,
isVisible: boolean
) => {
return boardApi.boardControllerUpdateVisibility(boardId, { isVisible });
};

return {
fetchBoardCall,
createColumnCall,
Expand All @@ -218,6 +225,7 @@ export const useBoardApi = () => {
moveColumnCall,
moveElementCall,
updateBoardTitleCall,
updateBoardVisibilityCall,
updateCardHeightCall,
updateCardTitle,
updateColumnTitleCall,
Expand Down
12 changes: 12 additions & 0 deletions src/components/data-board/BoardApi.composable.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -520,4 +520,16 @@ describe("BoardApi.composable", () => {
);
});
});

describe("updateBoardVisibilityCall", () => {
it("should call boardControllerUpdateVisibility api", async () => {
const { updateBoardVisibilityCall } = useBoardApi();

await updateBoardVisibilityCall("board-id", true);
expect(boardApi.boardControllerUpdateVisibility).toHaveBeenCalledWith(
"board-id",
{ isVisible: true }
);
});
});
});
15 changes: 15 additions & 0 deletions src/components/data-board/BoardState.composable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const useBoardState = (id: string) => {
moveColumnCall,
updateBoardTitleCall,
updateColumnTitleCall,
updateBoardVisibilityCall,
createCardCall,
} = useBoardApi();
const { setEditModeId } = useSharedEditMode();
Expand Down Expand Up @@ -255,6 +256,19 @@ export const useBoardState = (id: string) => {
}
};

const updateBoardVisibility = async (newVisibility: boolean) => {
if (board.value === undefined) return;

try {
await updateBoardVisibilityCall(board.value.id, newVisibility);
board.value.isVisible = newVisibility;
} catch (error) {
handleError(error, {
404: notifyWithTemplateAndReload("notUpdated", "board"),
});
}
};

const notifyWithTemplateAndReload = (
errorType: ErrorType,
boardObjectType?: BoardObjectType
Expand Down Expand Up @@ -293,6 +307,7 @@ export const useBoardState = (id: string) => {
notifyWithTemplateAndReload,
reloadBoard,
updateBoardTitle,
updateBoardVisibility,
updateColumnTitle,
};
};
30 changes: 30 additions & 0 deletions src/components/data-board/BoardState.composable.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -624,4 +624,34 @@ describe("BoardState.composable", () => {
});
});
});

describe("updateBoardVisibility", () => {
it("should update board visibility", async () => {
const { updateBoardVisibility, board } = setup();
board.value = testBoard;

await updateBoardVisibility(true);
await nextTick();

expect(
mockedBoardApiCalls.updateBoardVisibilityCall
).toHaveBeenCalledWith(board.value.id, true);

expect(board.value.isVisible).toStrictEqual(true);
});

it("should handle error when api returns an error code", async () => {
const { updateBoardVisibility, board } = setup();
board.value = testBoard;

mockedBoardApiCalls.updateBoardVisibilityCall.mockRejectedValue(
setupErrorResponse()
);

await updateBoardVisibility(false);
await nextTick();

expect(mockedErrorHandlerCalls.handleError).toHaveBeenCalled();
});
});
});
26 changes: 23 additions & 3 deletions src/components/feature-board/board/Board.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,15 +248,21 @@ describe("Board", () => {
jest.clearAllMocks();
});

it("should call the board notifier when the user is teacher", () => {
it("should call the board notifier when the user is teacher", async () => {
jest.useFakeTimers();

setup();
expect(mockedBoardNotifierCalls.showInfo).toHaveBeenCalled();
jest.runAllTimers();

expect(mockedBoardNotifierCalls.showCustomNotifier).toHaveBeenCalled();
});

it("should not call the board notifier when the user is not a teacher", async () => {
defaultPermissions.isTeacher = false;
setup();
expect(mockedBoardNotifierCalls.showInfo).not.toHaveBeenCalled();
expect(
mockedBoardNotifierCalls.showCustomNotifier
).not.toHaveBeenCalled();
});
});

Expand Down Expand Up @@ -603,5 +609,19 @@ describe("Board", () => {
expect(mockedBoardStateCalls.reloadBoard).toHaveBeenCalled();
});
});

describe("@onUpdateBoardVisibility", () => {
it("should update board visibility", async () => {
const { wrapper } = setup();

const boardHeader = wrapper.findComponent({
name: "BoardHeader",
});
boardHeader.vm.$emit("update:visibility");
await nextTick();

expect(mockedBoardStateCalls.updateBoardVisibility).toHaveBeenCalled();
});
});
});
});
39 changes: 33 additions & 6 deletions src/components/feature-board/board/Board.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
:boardId="board.id"
:title="board.title"
:titlePlaceholder="$t('pages.room.boardCard.label.courseBoard')"
:isDraft="!board.isVisible"
@update:visibility="onUpdateBoardVisibility"
@update:title="onUpdateBoardTitle"
/>
<div class="d-flex flex-row flex-shrink-1">
Expand Down Expand Up @@ -84,7 +86,7 @@ import { ConfirmationDialog } from "@ui-confirmation-dialog";
import { LightBox } from "@ui-light-box";
import { extractDataAttribute, useBoardNotifier } from "@util-board";
import { useTouchDetection } from "@util-device-detection";
import { useMediaQuery } from "@vueuse/core";
import { useDebounceFn, useMediaQuery } from "@vueuse/core";
import { SortableEvent } from "sortablejs";
import { Sortable } from "sortablejs-vue3";
import {
Expand Down Expand Up @@ -118,7 +120,7 @@ export default defineComponent({
},
setup(props) {
const { t } = useI18n();
const { showInfo, resetNotifier } = useBoardNotifier();
const { resetNotifier, showCustomNotifier } = useBoardNotifier();
const { editModeId } = useSharedEditMode();
const isEditMode = computed(() => editModeId.value !== undefined);
const {
Expand All @@ -131,6 +133,7 @@ export default defineComponent({
moveColumn,
reloadBoard,
updateBoardTitle,
updateBoardVisibility,
updateColumnTitle,
} = useBoardState(toRef(props, "boardId").value);
Expand Down Expand Up @@ -221,6 +224,13 @@ export default defineComponent({
await reloadBoard();
};
const onUpdateBoardVisibility = async (newVisibility: boolean) => {
if (!hasEditPermission) return;
await updateBoardVisibility(newVisibility);
await setAlert();
};
const onUpdateCardPosition = async (_: unknown, cardMove: CardMove) => {
if (hasMovePermission) await moveCard(cardMove);
};
Expand All @@ -233,10 +243,8 @@ export default defineComponent({
if (hasEditPermission) await updateBoardTitle(newTitle);
};
onMounted(() => {
if (isTeacher) {
showInfo(t("components.board.alert.info.teacher"), false);
}
onMounted(async () => {
await setAlert();
});
const debounceTime = computed(() => {
Expand All @@ -247,6 +255,24 @@ export default defineComponent({
resetNotifier();
});
const setAlert = useDebounceFn(() => {
if (!isTeacher) return;
if (!board.value?.isVisible) {
showCustomNotifier(
t("components.board.alert.info.draft"),
"info",
10000
);
} else {
showCustomNotifier(
t("components.board.alert.info.teacher"),
"info",
10000
);
}
}, 100);
return {
board,
columnDropPlaceholderOptions,
Expand All @@ -267,6 +293,7 @@ export default defineComponent({
onMoveColumnRight,
onReloadBoard,
onUpdateBoardTitle,
onUpdateBoardVisibility,
onUpdateCardPosition,
onUpdateColumnTitle,
};
Expand Down
12 changes: 12 additions & 0 deletions src/components/feature-board/board/BoardHeader.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
useBoardPermissions,
useEditMode,
} from "@data-board";
import { BoardMenuActionEdit } from "@ui-board";
import { shallowMount } from "@vue/test-utils";
import { computed } from "vue";
import BoardAnyTitleInput from "../shared/BoardAnyTitleInput.vue";
Expand Down Expand Up @@ -77,6 +78,17 @@ describe("BoardHeader", () => {
});
});

describe("when the 'edit' menu button is clicked", () => {
it("should call startEditMode", async () => {
const { startEditMode, wrapper } = setup();

const editButton = wrapper.findComponent(BoardMenuActionEdit);
editButton.vm.$emit("click");

expect(startEditMode).toBeCalled();
});
});

describe("user permissions", () => {
describe("when user is not permitted to edit the board", () => {
it("should not find the BoardMenu in the DOM", () => {
Expand Down
Loading

0 comments on commit 55ad2bc

Please sign in to comment.