{!noBackdrop && (
@@ -80,4 +83,5 @@ Modal.propTypes = {
focusTrapSelector: PropTypes.string,
sheet: PropTypes.bool,
sheetAlign: PropTypes.oneOf(['center', 'left', 'right']),
+ showHeader: PropTypes.bool,
};
diff --git a/app/javascript/crayons/Modal/__stories__/Modal.stories.jsx b/app/javascript/crayons/Modal/__stories__/Modal.stories.jsx
index 5302c5c50..c22f4a1f4 100644
--- a/app/javascript/crayons/Modal/__stories__/Modal.stories.jsx
+++ b/app/javascript/crayons/Modal/__stories__/Modal.stories.jsx
@@ -45,6 +45,13 @@ export default {
defaultValue: { summary: true },
},
},
+ showHeader: {
+ description:
+ 'Whether or not to display the standard header (with title and close button). If `false`, make sure to provide an alternative close button.',
+ table: {
+ defaultValue: { summary: true },
+ },
+ },
backdropDismissible: {
description:
'If `backdrop` is visible you can also make it clickable so clicking it would dismiss the Modal',
@@ -110,6 +117,11 @@ const Template = (args) => {
)}
+ {!args.showHeader && (
+
+ )}
)}
@@ -125,6 +137,7 @@ Default.args = {
prompt: false,
centered: false,
sheet: false,
+ showHeader: true,
};
export const Prompt = Template.bind({});
@@ -137,6 +150,7 @@ Prompt.args = {
prompt: true,
centered: false,
sheet: false,
+ showHeader: true,
};
export const PromptCentered = Template.bind({});
@@ -149,6 +163,7 @@ PromptCentered.args = {
prompt: true,
centered: true,
sheet: false,
+ showHeader: true,
};
export const Sheet = Template.bind({});
@@ -160,6 +175,7 @@ Sheet.args = {
prompt: false,
centered: false,
sheet: true,
+ showHeader: true,
};
export const SheetLeftAligned = Template.bind({});
@@ -172,6 +188,7 @@ SheetLeftAligned.args = {
centered: false,
sheet: true,
sheetAlign: 'left',
+ showHeader: true,
};
export const SheetRightAligned = Template.bind({});
@@ -184,6 +201,7 @@ SheetRightAligned.args = {
centered: false,
sheet: true,
sheetAlign: 'right',
+ showHeader: true,
};
export const BackdropDismissible = Template.bind({});
@@ -195,6 +213,7 @@ BackdropDismissible.args = {
prompt: false,
centered: false,
sheet: false,
+ showHeader: true,
};
export const NoBackdrop = Template.bind({});
@@ -206,4 +225,17 @@ NoBackdrop.args = {
prompt: false,
centered: false,
sheet: false,
+ showHeader: true,
+};
+
+export const NoHeader = Template.bind({});
+NoHeader.args = {
+ size: undefined,
+ title: 'Modal title',
+ noBackdrop: false,
+ backdropDismissible: false,
+ prompt: false,
+ centered: false,
+ sheet: false,
+ showHeader: false,
};
diff --git a/app/javascript/packs/admin/users/controls.js b/app/javascript/packs/admin/users/controls.js
index ecfba05ab..e85d21870 100644
--- a/app/javascript/packs/admin/users/controls.js
+++ b/app/javascript/packs/admin/users/controls.js
@@ -1,4 +1,9 @@
import { INTERACTIVE_ELEMENTS_QUERY } from '@utilities/dropdownUtils';
+import {
+ showWindowModal,
+ closeWindowModal,
+ WINDOW_MODAL_ID,
+} from '@utilities/showModal';
const expandSearchButton = document.getElementById('expand-search-btn');
const expandFilterButton = document.getElementById('expand-filter-btn');
@@ -112,5 +117,28 @@ const toggleIndicator = ({ value, indicator }) => {
}
};
+/**
+ * Controls the triggering of the filters popover modal
+ */
+const initializeFilterPopoverButtons = () => {
+ document.querySelectorAll('.js-open-filter-modal-btn').forEach((button) => {
+ button.addEventListener('click', () => {
+ showWindowModal({
+ contentSelector: '.js-filters-modal',
+ showHeader: false,
+ sheet: true,
+ sheetAlign: 'right',
+ size: 'small',
+ onOpen: () => {
+ document
+ .querySelector(`#${WINDOW_MODAL_ID} .js-filter-modal-cancel-btn`)
+ .addEventListener('click', closeWindowModal);
+ },
+ });
+ });
+ });
+};
+
initializeExpandingSections();
initializeSectionIndicators();
+initializeFilterPopoverButtons();
diff --git a/app/javascript/utilities/showModal.jsx b/app/javascript/utilities/showModal.jsx
index d96433237..f66eb937c 100644
--- a/app/javascript/utilities/showModal.jsx
+++ b/app/javascript/utilities/showModal.jsx
@@ -21,19 +21,16 @@ const getModalImports = () => {
/**
* This helper function finds the HTML with the given contentSelector, and presents it inside a Preact modal.
- * Only one modal will be presented at any given time.
+ * Only one modal will be presented at any given time. All additional props will be passed directly to the Modal component.
*
* @param {Object} args
- * @param {string} args.title The title of the modal (presented at the top of the modal dialog)
* @param {string} args.contentSelector The CSS query to locate the HTML to be presented in the modal (e.g. '#my-modal-content')
- * @param {string} args.size The size prop for the modal ('small', 'medium', or 'large')
* @param {Function} args.onOpen A callback function to run when the modal opens. This can be useful, for example, to attach any event listeners to items inside the modal.
*/
export const showWindowModal = async ({
- title,
contentSelector,
- size = 'small',
onOpen,
+ ...modalProps
}) => {
const [{ Modal }, { render, h }] = await getModalImports();
@@ -49,14 +46,14 @@ export const showWindowModal = async ({
render(
{
render(null, currentModalContainer);
}}
- size={size}
focusTrapSelector={`#${WINDOW_MODAL_ID}`}
+ {...modalProps}
>
+<% if FeatureFlag.enabled?(:member_index_view) %>
+ <%= render "admin/users/index/filters_modal" %>
+<% end %>
diff --git a/app/views/admin/users/index/_controls.html.erb b/app/views/admin/users/index/_controls.html.erb
index 8a09ef232..c2580f59d 100644
--- a/app/views/admin/users/index/_controls.html.erb
+++ b/app/views/admin/users/index/_controls.html.erb
@@ -38,6 +38,9 @@