feat: "Add content" sidebar on each library home page (#1065)
This commit is contained in:
69
src/generic/toast-context/index.test.tsx
Normal file
69
src/generic/toast-context/index.test.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { initializeMockApp } from '@edx/frontend-platform';
|
||||
import { AppProvider } from '@edx/frontend-platform/react';
|
||||
import { ToastContext, ToastProvider } from '.';
|
||||
import initializeStore from '../../store';
|
||||
|
||||
export interface WraperProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const TestComponentToShow = () => {
|
||||
const { showToast } = React.useContext(ToastContext);
|
||||
|
||||
React.useEffect(() => {
|
||||
showToast('This is the toast!');
|
||||
}, [showToast]);
|
||||
|
||||
return <div>Content</div>;
|
||||
};
|
||||
|
||||
const TestComponentToClose = () => {
|
||||
const { showToast, closeToast } = React.useContext(ToastContext);
|
||||
|
||||
React.useEffect(() => {
|
||||
showToast('This is the toast!');
|
||||
closeToast();
|
||||
}, [showToast]);
|
||||
|
||||
return <div>Content</div>;
|
||||
};
|
||||
|
||||
let store;
|
||||
const RootWrapper = ({ children }: WraperProps) => (
|
||||
<AppProvider store={store}>
|
||||
<ToastProvider>
|
||||
{children}
|
||||
</ToastProvider>
|
||||
</AppProvider>
|
||||
);
|
||||
|
||||
describe('<ToastProvider />', () => {
|
||||
beforeEach(() => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
username: 'abc123',
|
||||
administrator: true,
|
||||
roles: [],
|
||||
},
|
||||
});
|
||||
store = initializeStore();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should show toast', async () => {
|
||||
render(<RootWrapper><TestComponentToShow /></RootWrapper>);
|
||||
expect(await screen.findByText('This is the toast!')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should close toast', async () => {
|
||||
render(<RootWrapper><TestComponentToClose /></RootWrapper>);
|
||||
expect(await screen.findByText('Content')).toBeInTheDocument();
|
||||
expect(screen.queryByText('This is the toast!')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
57
src/generic/toast-context/index.tsx
Normal file
57
src/generic/toast-context/index.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import React from 'react';
|
||||
import { Toast } from '@openedx/paragon';
|
||||
|
||||
export interface ToastContextData {
|
||||
toastMessage: string | null;
|
||||
showToast: (message: string) => void;
|
||||
closeToast: () => void;
|
||||
}
|
||||
|
||||
export interface ToastProviderProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Global context to keep track of popup message(s) that appears to user after
|
||||
* they take an action like creating or deleting something.
|
||||
*/
|
||||
export const ToastContext = React.createContext({
|
||||
toastMessage: null,
|
||||
showToast: () => {},
|
||||
closeToast: () => {},
|
||||
} as ToastContextData);
|
||||
|
||||
/**
|
||||
* React component to provide `ToastContext` to the app
|
||||
*/
|
||||
export const ToastProvider = (props: ToastProviderProps) => {
|
||||
// TODO, We can convert this to a queue of messages,
|
||||
// see: https://github.com/open-craft/frontend-app-course-authoring/pull/38#discussion_r1638990647
|
||||
|
||||
const [toastMessage, setToastMessage] = React.useState<string | null>(null);
|
||||
|
||||
React.useEffect(() => () => {
|
||||
// Cleanup function to avoid updating state on unmounted component
|
||||
setToastMessage(null);
|
||||
}, []);
|
||||
|
||||
const showToast = React.useCallback((message) => setToastMessage(message), [setToastMessage]);
|
||||
const closeToast = React.useCallback(() => setToastMessage(null), [setToastMessage]);
|
||||
|
||||
const context = React.useMemo(() => ({
|
||||
toastMessage,
|
||||
showToast,
|
||||
closeToast,
|
||||
}), [toastMessage, showToast, closeToast]);
|
||||
|
||||
return (
|
||||
<ToastContext.Provider value={context}>
|
||||
{props.children}
|
||||
{ toastMessage && (
|
||||
<Toast show={toastMessage !== null} onClose={closeToast}>
|
||||
{toastMessage}
|
||||
</Toast>
|
||||
)}
|
||||
</ToastContext.Provider>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user