feat: Sidebar refactor and add support for discussions sidebar. (#762)

squash!: remove unnecessary styling and migrate to bootstrap and other review feedback
This commit is contained in:
Kshitij Sobti
2022-03-07 19:26:05 +05:30
committed by GitHub
parent 1bbcc6d052
commit f004d0ab3c
46 changed files with 954 additions and 537 deletions

21
src/generic/hooks.js Normal file
View File

@@ -0,0 +1,21 @@
/* eslint-disable import/prefer-default-export */
import { useEffect, useRef } from 'react';
export function useEventListener(type, handler) {
// We use this ref so that we can hold a reference to the currently active event listener.
const eventListenerRef = useRef(null);
useEffect(() => {
// If we currently have an event listener, remove it.
if (eventListenerRef.current !== null) {
global.removeEventListener(type, eventListenerRef.current);
eventListenerRef.current = null;
}
// Now add our new handler as the event listener.
global.addEventListener(type, handler);
// And then save it to our ref for next time.
eventListenerRef.current = handler;
// When the component finally unmounts, use the ref to remove the correct handler.
return () => global.removeEventListener(type, eventListenerRef.current);
}, [type, handler]);
}

View File

@@ -1,19 +1,22 @@
/* eslint-disable no-param-reassign */
import { createSlice } from '@reduxjs/toolkit';
function add(state, modelType, model) {
const { id } = model;
function add(state, modelType, model, idField) {
idField = idField ?? 'id';
const id = model[idField];
if (state[modelType] === undefined) {
state[modelType] = {};
}
state[modelType][id] = model;
}
function update(state, modelType, model) {
function update(state, modelType, model, idField) {
idField = idField ?? 'id';
const id = model[idField];
if (state[modelType] === undefined) {
state[modelType] = {};
}
state[modelType][model.id] = { ...state[modelType][model.id], ...model };
state[modelType][id] = { ...state[modelType][id], ...model };
}
function remove(state, modelType, id) {
@@ -29,28 +32,28 @@ const slice = createSlice({
initialState: {},
reducers: {
addModel: (state, { payload }) => {
const { modelType, model } = payload;
add(state, modelType, model);
const { modelType, model, idField } = payload;
add(state, modelType, model, idField);
},
addModels: (state, { payload }) => {
const { modelType, models } = payload;
models.forEach(model => add(state, modelType, model));
const { modelType, models, idField } = payload;
models.forEach(model => add(state, modelType, model, idField));
},
addModelsMap: (state, { payload }) => {
const { modelType, modelsMap } = payload;
Object.values(modelsMap).forEach(model => add(state, modelType, model));
const { modelType, modelsMap, idField } = payload;
Object.values(modelsMap).forEach(model => add(state, modelType, model, idField));
},
updateModel: (state, { payload }) => {
const { modelType, model } = payload;
update(state, modelType, model);
const { modelType, model, idField } = payload;
update(state, modelType, model, idField);
},
updateModels: (state, { payload }) => {
const { modelType, models } = payload;
models.forEach(model => update(state, modelType, model));
const { modelType, models, idField } = payload;
models.forEach(model => update(state, modelType, model, idField));
},
updateModelsMap: (state, { payload }) => {
const { modelType, modelsMap } = payload;
Object.values(modelsMap).forEach(model => update(state, modelType, model));
const { modelType, modelsMap, idField } = payload;
Object.values(modelsMap).forEach(model => update(state, modelType, model, idField));
},
removeModel: (state, { payload }) => {
const { modelType, id } = payload;

View File

@@ -126,7 +126,7 @@ describe('Upgrade Notification', () => {
});
expect(screen.getByRole('heading', { name: 'Course Access Expiration' })).toBeInTheDocument();
expect(screen.getByText('12 hours left')).toBeInTheDocument();
expect(screen.getByText(/You will lose all access to this course.*?on/s).textContent).toMatch('You will lose all access to this course, including any progress, on April 13.');
expect(screen.getByText(/You will lose all access to this course.*?on/s)).toHaveTextContent('You will lose all access to this course, including any progress, on April 13.');
expect(screen.getByText(/Upgrading your course enables you/s).textContent).toMatch('Upgrading your course enables you to pursue a verified certificate and unlocks numerous features. Learn more about the benefits of upgrading.');
expect(screen.getByRole('link', { name: 'Upgrade for $149' })).toBeInTheDocument();
});