docbrown/app/javascript/packs/admin/displayAds.jsx
Joshua Wehner dc1ab81401
Allow DisplayAd to target users via audience segmentation (#19284)
* Trying some models for audience segmentation

* AudienceSegment basics

* Attach AudienceSegment to DisplayAd

* Possibly use a DUS to populate AudienceSegments

* Add to display ad form UI

* Add to display ad API

* Refresh strategy for audience segments

* Add user_id to async ads query

* Maybe :testing -> :manual, for no-refresh segment

* Test & tweak segment refresh

* Testing audience_segment#refresh logic

* Coverage: testing human_readable

* Scope segment refresh to recently active users

* Tweak logic for when to refresh

* Tweak experience levels to match SettingsHelper

* Test for front-end logic

* Fix test, hope this helps coverage?

* Better test names

* One worker for all, many workers for each, perform_bulk

* Fix audience segment UI, needs to use id, not enum

* cron/schedule should RefreshAll

* Singular id in RefreshWorker
2023-04-25 08:41:10 -04:00

173 lines
4.3 KiB
JavaScript

import { h, render } from 'preact';
import { Tags } from '../../display-ad/tags';
Document.prototype.ready = new Promise((resolve) => {
if (document.readyState !== 'loading') {
return resolve();
}
document.addEventListener('DOMContentLoaded', () => resolve());
return null;
});
/**
* A callback that sets the hidden 'js-tags-textfield' with the selection string that was chosen via the
* MultiSelectAutocomplete component.
*
* @param {String} selectionString The selected tags represented as a string (e.g. "webdev, git, career")
*/
function saveTags(selectionString) {
document.getElementsByClassName('js-tags-textfield')[0].value =
selectionString;
}
/**
* Shows and Renders a Tags preact component for the Targeted Tag(s) field
*/
function showTagsField() {
const displayAdsTargetedTags = document.getElementById(
'display-ad-targeted-tags',
);
if (displayAdsTargetedTags) {
displayAdsTargetedTags.classList.remove('hidden');
render(
<Tags onInput={saveTags} defaultValue={defaultTagValues()} />,
displayAdsTargetedTags,
);
}
}
/**
* Hides the Targeted Tag(s) field
*/
function hideTagsField() {
const displayAdsTargetedTags = document.getElementById(
'display-ad-targeted-tags',
);
displayAdsTargetedTags?.classList.add('hidden');
}
/**
* Clears the content (i.e. value) of the hidden tags textfield
*/
function clearTagList() {
const hiddenTagsField =
document.getElementsByClassName('js-tags-textfield')[0];
hiddenTagsField.value = ' ';
}
/**
* Returns the value of the hidden text field to eventually pass as
* default values to the MultiSelectAutocomplete component.
*/
function defaultTagValues() {
let defaultValue = '';
const hiddenTagsField =
document.getElementsByClassName('js-tags-textfield')[0];
if (hiddenTagsField) {
defaultValue = hiddenTagsField.value.trim();
}
return defaultValue;
}
function displayUserTargets() {
const userTargetField = document.getElementsByClassName(
'js-audience-segment',
)[0].parentElement;
if (userTargetField) {
userTargetField.classList.remove('hidden');
}
}
function hideUserTargets() {
const userTargetField = document.getElementsByClassName(
'js-audience-segment',
)[0].parentElement;
if (userTargetField) {
userTargetField.classList.add('hidden');
}
}
function clearUserTargetSelection() {
const userTargetSelect = document.getElementsByClassName(
'js-audience-segment',
)[0];
if (userTargetSelect) {
userTargetSelect.value = '';
}
}
/**
* Shows and Renders Exclude Article IDs group
*/
function showExcludeIds() {
const excludeField = document.getElementsByClassName(
'js-exclude-ids-textfield',
)[0].parentElement;
excludeField?.classList.remove('hidden');
}
/**
* Hides the Exclude Article IDs group
*/
function hideExcludeIds() {
const excludeField = document.getElementsByClassName(
'js-exclude-ids-textfield',
)[0].parentElement;
excludeField?.classList.add('hidden');
}
/**
* Clears the content (i.e. value) of the Exclude Article IDs group
*/
function clearExcludeIds() {
const excludeField = document.getElementsByClassName(
'js-exclude-ids-textfield',
)[0];
if (excludeField) {
excludeField.value = '';
}
}
/**
* Shows and sets up the Targeted Tag(s) field if the placement area value is "post_comments".
* Listens for change events on the select placement area dropdown
* and shows and hides the Targeted Tag(s) appropriately.
*/
document.ready.then(() => {
const select = document.getElementsByClassName('js-placement-area')[0];
const articleSpecificPlacement = ['post_comments', 'post_sidebar'];
if (articleSpecificPlacement.includes(select.value)) {
showTagsField();
showExcludeIds();
}
select.addEventListener('change', (event) => {
if (articleSpecificPlacement.includes(event.target.value)) {
showTagsField();
showExcludeIds();
} else {
hideTagsField();
clearTagList();
hideExcludeIds();
clearExcludeIds();
}
});
const userRadios = document.querySelectorAll('input[name=display_to]');
userRadios.forEach((radio) => {
radio.addEventListener('change', (event) => {
if (event.target.value == 'logged_in') {
displayUserTargets();
} else {
hideUserTargets();
clearUserTargetSelection();
}
});
});
});