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:
21
src/generic/hooks.js
Normal file
21
src/generic/hooks.js
Normal 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]);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user