mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-20 14:54:15 +01:00
(feat) add a custom banner for trainings
This commit is contained in:
parent
06a93391a2
commit
0778616345
@ -13,7 +13,7 @@ import { User } from '../../models/user';
|
||||
import { EditorialBlock } from '../editorial-block/editorial-block';
|
||||
import SettingAPI from '../../api/setting';
|
||||
import SettingLib from '../../lib/setting';
|
||||
import { SettingValue, machineBannerSettings } from '../../models/setting';
|
||||
import { SettingValue, machinesSettings } from '../../models/setting';
|
||||
|
||||
declare const Application: IApplication;
|
||||
|
||||
@ -46,16 +46,7 @@ export const MachinesList: React.FC<MachinesListProps> = ({ onError, onSuccess,
|
||||
|
||||
const [banner, setBanner] = useState<Record<string, SettingValue>>({});
|
||||
|
||||
// fetch Banner text and button from API
|
||||
const fetchBanner = async () => {
|
||||
SettingAPI.query(machineBannerSettings)
|
||||
.then(settings => {
|
||||
setBanner({ ...SettingLib.bulkMapToObject(settings) });
|
||||
})
|
||||
.catch(onError);
|
||||
};
|
||||
|
||||
// retrieve the full list of machines on component mount
|
||||
// retrieve the full list of machines and the machines Banner on component mount
|
||||
useEffect(() => {
|
||||
MachineAPI.index()
|
||||
.then(data => setAllMachines(data))
|
||||
@ -63,7 +54,11 @@ export const MachinesList: React.FC<MachinesListProps> = ({ onError, onSuccess,
|
||||
MachineCategoryAPI.index()
|
||||
.then(data => setMachineCategories(data))
|
||||
.catch(e => onError(e));
|
||||
fetchBanner();
|
||||
SettingAPI.query(machinesSettings)
|
||||
.then(settings => {
|
||||
setBanner({ ...SettingLib.bulkMapToObject(settings) });
|
||||
})
|
||||
.catch(onError);
|
||||
}, []);
|
||||
|
||||
// filter the machines shown when the full list was retrieved
|
||||
|
@ -9,7 +9,7 @@ import { FabButton } from '../base/fab-button';
|
||||
import { EditorialKeys, EditorialBlockForm } from '../editorial-block/editorial-block-form';
|
||||
import SettingAPI from '../../api/setting';
|
||||
import SettingLib from '../../lib/setting';
|
||||
import { SettingName, SettingValue, machineBannerSettings } from '../../models/setting';
|
||||
import { SettingName, SettingValue, machinesSettings } from '../../models/setting';
|
||||
|
||||
declare const Application: IApplication;
|
||||
|
||||
@ -47,7 +47,7 @@ export const MachinesSettings: React.FC<MachinesSettingsProps> = ({ onError, onS
|
||||
|
||||
/** On component mount, fetch existing Machines Banner Settings from API, and populate form with these values. */
|
||||
useEffect(() => {
|
||||
SettingAPI.query(machineBannerSettings)
|
||||
SettingAPI.query(machinesSettings)
|
||||
.then(settings => reset(SettingLib.bulkMapToObject(settings)))
|
||||
.catch(onError);
|
||||
}, []);
|
||||
|
@ -0,0 +1,52 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { IApplication } from '../../models/application';
|
||||
import { react2angular } from 'react2angular';
|
||||
import { Loader } from '../base/loader';
|
||||
import { EditorialBlock } from '../editorial-block/editorial-block';
|
||||
import SettingAPI from '../../api/setting';
|
||||
import SettingLib from '../../lib/setting';
|
||||
import { SettingValue, trainingsSettings } from '../../models/setting';
|
||||
|
||||
declare const Application: IApplication;
|
||||
|
||||
interface TrainingEditorialBlockProps {
|
||||
onError: (message: string) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* This component displays to Users the editorial block (banner) associated to trainings.
|
||||
*/
|
||||
export const TrainingEditorialBlock: React.FC<TrainingEditorialBlockProps> = ({ onError }) => {
|
||||
// Store Banner retrieved from API
|
||||
const [banner, setBanner] = useState<Record<string, SettingValue>>({});
|
||||
|
||||
// Retrieve the settings related to the Trainings Banner from the API
|
||||
useEffect(() => {
|
||||
SettingAPI.query(trainingsSettings)
|
||||
.then(settings => {
|
||||
setBanner({ ...SettingLib.bulkMapToObject(settings) });
|
||||
})
|
||||
.catch(onError);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
{banner.trainings_banner_active &&
|
||||
<EditorialBlock
|
||||
text={banner.trainings_banner_text}
|
||||
cta={banner.trainings_banner_cta_active && banner.trainings_banner_cta_label}
|
||||
url={banner.trainings_banner_cta_active && banner.trainings_banner_cta_url} />
|
||||
}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const TrainingEditorialBlockWrapper: React.FC<TrainingEditorialBlockProps> = (props) => {
|
||||
return (
|
||||
<Loader>
|
||||
<TrainingEditorialBlock {...props} />
|
||||
</Loader>
|
||||
);
|
||||
};
|
||||
|
||||
Application.Components.component('trainingEditorialBlock', react2angular(TrainingEditorialBlockWrapper, ['onError']));
|
@ -9,8 +9,8 @@ import { useForm, SubmitHandler, useWatch } from 'react-hook-form';
|
||||
import { FormSwitch } from '../form/form-switch';
|
||||
import { FormInput } from '../form/form-input';
|
||||
import { FabButton } from '../base/fab-button';
|
||||
import { EditorialBlockForm } from '../editorial-block/editorial-block-form';
|
||||
import { SettingName, SettingValue, trainingSettings } from '../../models/setting';
|
||||
import { EditorialKeys, EditorialBlockForm } from '../editorial-block/editorial-block-form';
|
||||
import { SettingName, SettingValue, trainingsSettings } from '../../models/setting';
|
||||
import SettingAPI from '../../api/setting';
|
||||
import SettingLib from '../../lib/setting';
|
||||
|
||||
@ -32,8 +32,17 @@ export const TrainingsSettings: React.FC<TrainingsSettingsProps> = ({ onError, o
|
||||
const isActiveAuthorizationValidity = useWatch({ control, name: 'trainings_authorization_validity' }) as boolean;
|
||||
const isActiveInvalidationRule = useWatch({ control, name: 'trainings_invalidation_rule' }) as boolean;
|
||||
|
||||
/** Link Trainings Banner Settings to generic keys expected by the Editorial Form */
|
||||
const bannerKeys: Record<EditorialKeys, SettingName> = {
|
||||
active_text_block: 'trainings_banner_active',
|
||||
text_block: 'trainings_banner_text',
|
||||
active_cta: 'trainings_banner_cta_active',
|
||||
cta_label: 'trainings_banner_cta_label',
|
||||
cta_url: 'trainings_banner_cta_url'
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
SettingAPI.query(trainingSettings)
|
||||
SettingAPI.query(trainingsSettings)
|
||||
.then(settings => {
|
||||
const data = SettingLib.bulkMapToObject(settings);
|
||||
reset(data);
|
||||
@ -63,6 +72,7 @@ export const TrainingsSettings: React.FC<TrainingsSettingsProps> = ({ onError, o
|
||||
<EditorialBlockForm register={register}
|
||||
control={control}
|
||||
formState={formState}
|
||||
keys={bannerKeys}
|
||||
info={t('app.admin.trainings_settings.generic_text_block_info')} />
|
||||
</div>
|
||||
|
||||
|
@ -14,6 +14,10 @@ import type { Machine } from '../../models/machine';
|
||||
import TrainingAPI from '../../api/training';
|
||||
import MachineAPI from '../../api/machine';
|
||||
import { EditDestroyButtons } from '../base/edit-destroy-buttons';
|
||||
import { EditorialBlock } from '../editorial-block/editorial-block';
|
||||
import { SettingValue, trainingsSettings } from '../../models/setting';
|
||||
import SettingAPI from '../../api/setting';
|
||||
import SettingLib from '../../lib/setting';
|
||||
|
||||
declare const Application: IApplication;
|
||||
|
||||
@ -31,6 +35,7 @@ export const Trainings: React.FC<TrainingsProps> = ({ onError, onSuccess }) => {
|
||||
const [trainings, setTrainings] = useState<Array<Training>>([]);
|
||||
const [machines, setMachines] = useState<Array<Machine>>([]);
|
||||
const [filter, setFilter] = useState<boolean>(null);
|
||||
const [banner, setBanner] = useState<Record<string, SettingValue>>({});
|
||||
|
||||
// Styles the React-select component
|
||||
const customStyles = {
|
||||
@ -45,7 +50,13 @@ export const Trainings: React.FC<TrainingsProps> = ({ onError, onSuccess }) => {
|
||||
})
|
||||
};
|
||||
|
||||
// At component mount, fetch Banner and Machines from API
|
||||
useEffect(() => {
|
||||
SettingAPI.query(trainingsSettings)
|
||||
.then(settings => {
|
||||
setBanner({ ...SettingLib.bulkMapToObject(settings) });
|
||||
})
|
||||
.catch(onError);
|
||||
MachineAPI.index({ disabled: false })
|
||||
.then(setMachines)
|
||||
.catch(onError);
|
||||
@ -114,6 +125,12 @@ export const Trainings: React.FC<TrainingsProps> = ({ onError, onSuccess }) => {
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{banner.trainings_banner_active &&
|
||||
<EditorialBlock
|
||||
text={banner.trainings_banner_text}
|
||||
cta={banner.trainings_banner_cta_active && banner.trainings_banner_cta_label}
|
||||
url={banner.trainings_banner_cta_active && banner.trainings_banner_cta_url} />
|
||||
}
|
||||
<div className="trainings-content">
|
||||
<div className='display'>
|
||||
<div className='filter'>
|
||||
|
@ -17,8 +17,8 @@
|
||||
/**
|
||||
* Public listing of the trainings
|
||||
*/
|
||||
Application.Controllers.controller('TrainingsController', ['$scope', '$state', 'trainingsPromise',
|
||||
function ($scope, $state, trainingsPromise) {
|
||||
Application.Controllers.controller('TrainingsController', ['$scope', '$state', 'trainingsPromise', 'growl',
|
||||
function ($scope, $state, trainingsPromise, growl) {
|
||||
// List of trainings
|
||||
$scope.trainings = trainingsPromise;
|
||||
|
||||
@ -31,6 +31,13 @@ Application.Controllers.controller('TrainingsController', ['$scope', '$state', '
|
||||
* Callback for the 'show' button
|
||||
*/
|
||||
$scope.showTraining = function (training) { $state.go('app.public.training_show', { id: training.slug }); };
|
||||
|
||||
/**
|
||||
* Callback triggered by react components
|
||||
*/
|
||||
$scope.onError = function (message) {
|
||||
growl.error(message);
|
||||
};
|
||||
}]);
|
||||
|
||||
/**
|
||||
|
@ -233,7 +233,7 @@ export const storeSettings = [
|
||||
'store_hidden'
|
||||
] as const;
|
||||
|
||||
export const trainingSettings = [
|
||||
export const trainingsSettings = [
|
||||
'trainings_auto_cancel',
|
||||
'trainings_auto_cancel_threshold',
|
||||
'trainings_auto_cancel_deadline',
|
||||
@ -241,9 +241,15 @@ export const trainingSettings = [
|
||||
'trainings_authorization_validity_duration',
|
||||
'trainings_invalidation_rule',
|
||||
'trainings_invalidation_rule_period'
|
||||
'trainings_auto_cancel_deadline',
|
||||
'trainings_banner_active',
|
||||
'trainings_banner_text',
|
||||
'trainings_banner_cta_active',
|
||||
'trainings_banner_cta_label',
|
||||
'trainings_banner_cta_url'
|
||||
] as const;
|
||||
|
||||
export const machineBannerSettings = [
|
||||
export const machinesSettings = [
|
||||
'machines_banner_active',
|
||||
'machines_banner_text',
|
||||
'machines_banner_cta_active',
|
||||
@ -277,8 +283,8 @@ export const allSettings = [
|
||||
...poymentSettings,
|
||||
...displaySettings,
|
||||
...storeSettings,
|
||||
...trainingSettings,
|
||||
...machineBannerSettings
|
||||
...trainingsSettings,
|
||||
...machinesSettings
|
||||
] as const;
|
||||
|
||||
export type SettingName = typeof allSettings[number];
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
|
||||
<section class="m-lg">
|
||||
<editorial-block></editorial-block>
|
||||
<training-editorial-block on-error="onError"></training-editorial-block>
|
||||
|
||||
<div class="row" ng-repeat="training in (trainings.length/3 | array)">
|
||||
|
||||
|
193
app/helpers/settings_helper.rb
Normal file
193
app/helpers/settings_helper.rb
Normal file
@ -0,0 +1,193 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Helpers methods listing all the settings used in setting.rb
|
||||
# The following list contains all the settings that can be customized from the Fab-manager's UI.
|
||||
# A few of them that are system settings, that should not be updated manually (uuid, origin...).
|
||||
|
||||
# rubocop:disable Metrics/ModuleLength
|
||||
module SettingsHelper
|
||||
# WARNING: when adding a new key, you may also want to add it in:
|
||||
# - config/locales/en.yml#settings
|
||||
# - app/frontend/src/javascript/models/setting.ts#SettingName
|
||||
# - db/seeds.rb (to set the default value)
|
||||
# - app/policies/setting_policy.rb#public_whitelist (if the setting can be read by anyone)
|
||||
# - test/fixtures/settings.yml (for backend testing)
|
||||
# - test/fixtures/history_values.yml (example value for backend testing)
|
||||
# - test/frontend/__fixtures__/settings.ts (example value for frontend testing)
|
||||
SETTINGS = %w[
|
||||
about_title
|
||||
about_body
|
||||
about_contacts
|
||||
privacy_draft
|
||||
privacy_body
|
||||
privacy_dpo
|
||||
twitter_name
|
||||
home_blogpost
|
||||
machine_explications_alert
|
||||
training_explications_alert
|
||||
training_information_message
|
||||
subscription_explications_alert
|
||||
invoice_logo
|
||||
invoice_reference
|
||||
invoice_code-active
|
||||
invoice_code-value
|
||||
invoice_order-nb
|
||||
invoice_VAT-active
|
||||
invoice_VAT-rate
|
||||
invoice_VAT-rate_Machine
|
||||
invoice_VAT-rate_Training
|
||||
invoice_VAT-rate_Space
|
||||
invoice_VAT-rate_Event
|
||||
invoice_VAT-rate_Subscription
|
||||
invoice_VAT-rate_Product
|
||||
invoice_text
|
||||
invoice_legals
|
||||
booking_window_start
|
||||
booking_window_end
|
||||
booking_move_enable
|
||||
booking_move_delay
|
||||
booking_cancel_enable
|
||||
booking_cancel_delay
|
||||
main_color
|
||||
secondary_color
|
||||
fablab_name
|
||||
name_genre
|
||||
reminder_enable
|
||||
reminder_delay
|
||||
event_explications_alert
|
||||
space_explications_alert
|
||||
visibility_yearly
|
||||
visibility_others
|
||||
reservation_deadline
|
||||
display_name_enable
|
||||
machines_sort_by
|
||||
accounting_sales_journal_code
|
||||
accounting_payment_card_code
|
||||
accounting_payment_card_label
|
||||
accounting_payment_card_journal_code
|
||||
accounting_payment_wallet_code
|
||||
accounting_payment_wallet_label
|
||||
accounting_payment_wallet_journal_code
|
||||
accounting_payment_other_code
|
||||
accounting_payment_other_label
|
||||
accounting_payment_other_journal_code
|
||||
accounting_wallet_code
|
||||
accounting_wallet_label
|
||||
accounting_wallet_journal_code
|
||||
accounting_VAT_code
|
||||
accounting_VAT_label
|
||||
accounting_VAT_journal_code
|
||||
accounting_subscription_code
|
||||
accounting_subscription_label
|
||||
accounting_Machine_code
|
||||
accounting_Machine_label
|
||||
accounting_Training_code
|
||||
accounting_Training_label
|
||||
accounting_Event_code
|
||||
accounting_Event_label
|
||||
accounting_Space_code
|
||||
accounting_Space_label
|
||||
accounting_Product_code
|
||||
accounting_Product_label
|
||||
hub_last_version
|
||||
hub_public_key
|
||||
fab_analytics
|
||||
link_name
|
||||
home_content
|
||||
home_css
|
||||
origin
|
||||
uuid
|
||||
phone_required
|
||||
tracking_id
|
||||
book_overlapping_slots
|
||||
slot_duration
|
||||
events_in_calendar
|
||||
spaces_module
|
||||
plans_module
|
||||
invoicing_module
|
||||
facebook_app_id
|
||||
twitter_analytics
|
||||
recaptcha_site_key
|
||||
recaptcha_secret_key
|
||||
feature_tour_display
|
||||
email_from
|
||||
disqus_shortname
|
||||
allowed_cad_extensions
|
||||
allowed_cad_mime_types
|
||||
openlab_app_id
|
||||
openlab_app_secret
|
||||
openlab_default
|
||||
online_payment_module
|
||||
stripe_public_key
|
||||
stripe_secret_key
|
||||
stripe_currency
|
||||
invoice_prefix
|
||||
confirmation_required
|
||||
wallet_module
|
||||
statistics_module
|
||||
upcoming_events_shown
|
||||
payment_schedule_prefix
|
||||
trainings_module
|
||||
address_required
|
||||
accounting_Error_code
|
||||
accounting_Error_label
|
||||
payment_gateway
|
||||
payzen_username
|
||||
payzen_password
|
||||
payzen_endpoint
|
||||
payzen_public_key
|
||||
payzen_hmac
|
||||
payzen_currency
|
||||
public_agenda_module
|
||||
renew_pack_threshold
|
||||
pack_only_for_subscription
|
||||
overlapping_categories
|
||||
extended_prices_in_same_day
|
||||
public_registrations
|
||||
accounting_Pack_code
|
||||
accounting_Pack_label
|
||||
facebook
|
||||
twitter
|
||||
viadeo
|
||||
linkedin
|
||||
instagram
|
||||
youtube
|
||||
vimeo
|
||||
dailymotion
|
||||
github
|
||||
echosciences
|
||||
pinterest
|
||||
lastfm
|
||||
flickr
|
||||
machines_module
|
||||
user_change_group
|
||||
user_validation_required
|
||||
user_validation_required_list
|
||||
show_username_in_admin_list
|
||||
store_module
|
||||
store_withdrawal_instructions
|
||||
store_hidden
|
||||
advanced_accounting
|
||||
external_id
|
||||
prevent_invoices_zero
|
||||
invoice_VAT-name
|
||||
trainings_auto_cancel
|
||||
trainings_auto_cancel_threshold
|
||||
trainings_auto_cancel_deadline
|
||||
trainings_authorization_validity
|
||||
trainings_authorization_validity_duration
|
||||
trainings_invalidation_rule
|
||||
trainings_invalidation_rule_period
|
||||
machines_banner_active
|
||||
machines_banner_text
|
||||
machines_banner_cta_active
|
||||
machines_banner_cta_label
|
||||
machines_banner_cta_url
|
||||
trainings_banner_active
|
||||
trainings_banner_text
|
||||
trainings_banner_cta_active
|
||||
trainings_banner_cta_label
|
||||
trainings_banner_cta_url
|
||||
].freeze
|
||||
end
|
||||
# rubocop:enable Metrics/ModuleLength
|
@ -6,186 +6,12 @@
|
||||
# A full history of the previous values is kept in database with the date and the author of the change
|
||||
# after_update callback is handled by SettingService
|
||||
class Setting < ApplicationRecord
|
||||
include SettingsHelper
|
||||
|
||||
has_many :history_values, dependent: :destroy
|
||||
# The following list contains all the settings that can be customized from the Fab-manager's UI.
|
||||
# A few of them that are system settings, that should not be updated manually (uuid, origin...).
|
||||
validates :name, inclusion:
|
||||
{ in: %w[about_title
|
||||
about_body
|
||||
about_contacts
|
||||
privacy_draft
|
||||
privacy_body
|
||||
privacy_dpo
|
||||
twitter_name
|
||||
home_blogpost
|
||||
machine_explications_alert
|
||||
training_explications_alert
|
||||
training_information_message
|
||||
subscription_explications_alert
|
||||
invoice_logo
|
||||
invoice_reference
|
||||
invoice_code-active
|
||||
invoice_code-value
|
||||
invoice_order-nb
|
||||
invoice_VAT-active
|
||||
invoice_VAT-rate
|
||||
invoice_VAT-rate_Machine
|
||||
invoice_VAT-rate_Training
|
||||
invoice_VAT-rate_Space
|
||||
invoice_VAT-rate_Event
|
||||
invoice_VAT-rate_Subscription
|
||||
invoice_VAT-rate_Product
|
||||
invoice_text
|
||||
invoice_legals
|
||||
booking_window_start
|
||||
booking_window_end
|
||||
booking_move_enable
|
||||
booking_move_delay
|
||||
booking_cancel_enable
|
||||
booking_cancel_delay
|
||||
main_color
|
||||
secondary_color
|
||||
fablab_name
|
||||
name_genre
|
||||
reminder_enable
|
||||
reminder_delay
|
||||
event_explications_alert
|
||||
space_explications_alert
|
||||
visibility_yearly
|
||||
visibility_others
|
||||
reservation_deadline
|
||||
display_name_enable
|
||||
machines_sort_by
|
||||
accounting_sales_journal_code
|
||||
accounting_payment_card_code
|
||||
accounting_payment_card_label
|
||||
accounting_payment_card_journal_code
|
||||
accounting_payment_wallet_code
|
||||
accounting_payment_wallet_label
|
||||
accounting_payment_wallet_journal_code
|
||||
accounting_payment_other_code
|
||||
accounting_payment_other_label
|
||||
accounting_payment_other_journal_code
|
||||
accounting_wallet_code
|
||||
accounting_wallet_label
|
||||
accounting_wallet_journal_code
|
||||
accounting_VAT_code
|
||||
accounting_VAT_label
|
||||
accounting_VAT_journal_code
|
||||
accounting_subscription_code
|
||||
accounting_subscription_label
|
||||
accounting_Machine_code
|
||||
accounting_Machine_label
|
||||
accounting_Training_code
|
||||
accounting_Training_label
|
||||
accounting_Event_code
|
||||
accounting_Event_label
|
||||
accounting_Space_code
|
||||
accounting_Space_label
|
||||
accounting_Product_code
|
||||
accounting_Product_label
|
||||
hub_last_version
|
||||
hub_public_key
|
||||
fab_analytics
|
||||
link_name
|
||||
home_content
|
||||
home_css
|
||||
origin
|
||||
uuid
|
||||
phone_required
|
||||
tracking_id
|
||||
book_overlapping_slots
|
||||
slot_duration
|
||||
events_in_calendar
|
||||
spaces_module
|
||||
plans_module
|
||||
invoicing_module
|
||||
facebook_app_id
|
||||
twitter_analytics
|
||||
recaptcha_site_key
|
||||
recaptcha_secret_key
|
||||
feature_tour_display
|
||||
email_from
|
||||
disqus_shortname
|
||||
allowed_cad_extensions
|
||||
allowed_cad_mime_types
|
||||
openlab_app_id
|
||||
openlab_app_secret
|
||||
openlab_default
|
||||
online_payment_module
|
||||
stripe_public_key
|
||||
stripe_secret_key
|
||||
stripe_currency
|
||||
invoice_prefix
|
||||
confirmation_required
|
||||
wallet_module
|
||||
statistics_module
|
||||
upcoming_events_shown
|
||||
payment_schedule_prefix
|
||||
trainings_module
|
||||
address_required
|
||||
accounting_Error_code
|
||||
accounting_Error_label
|
||||
payment_gateway
|
||||
payzen_username
|
||||
payzen_password
|
||||
payzen_endpoint
|
||||
payzen_public_key
|
||||
payzen_hmac
|
||||
payzen_currency
|
||||
public_agenda_module
|
||||
renew_pack_threshold
|
||||
pack_only_for_subscription
|
||||
overlapping_categories
|
||||
extended_prices_in_same_day
|
||||
public_registrations
|
||||
accounting_Pack_code
|
||||
accounting_Pack_label
|
||||
facebook
|
||||
twitter
|
||||
viadeo
|
||||
linkedin
|
||||
instagram
|
||||
youtube
|
||||
vimeo
|
||||
dailymotion
|
||||
github
|
||||
echosciences
|
||||
pinterest
|
||||
lastfm
|
||||
flickr
|
||||
machines_module
|
||||
user_change_group
|
||||
user_validation_required
|
||||
user_validation_required_list
|
||||
show_username_in_admin_list
|
||||
store_module
|
||||
store_withdrawal_instructions
|
||||
store_hidden
|
||||
advanced_accounting
|
||||
external_id
|
||||
prevent_invoices_zero
|
||||
invoice_VAT-name
|
||||
trainings_auto_cancel
|
||||
trainings_auto_cancel_threshold
|
||||
trainings_auto_cancel_deadline
|
||||
trainings_authorization_validity
|
||||
trainings_authorization_validity_duration
|
||||
trainings_invalidation_rule
|
||||
trainings_invalidation_rule_period
|
||||
machines_banner_active
|
||||
machines_banner_text
|
||||
machines_banner_cta_active
|
||||
machines_banner_cta_label
|
||||
machines_banner_cta_url] }
|
||||
# WARNING: when adding a new key, you may also want to add it in:
|
||||
# - config/locales/en.yml#settings
|
||||
# - app/frontend/src/javascript/models/setting.ts#SettingName
|
||||
# - db/seeds/settings.rb (to set the default value)
|
||||
# - app/policies/setting_policy.rb#public_whitelist (if the setting can be read by anyone)
|
||||
# - test/fixtures/settings.yml (for backend testing)
|
||||
# - test/fixtures/history_values.yml (example value for backend testing)
|
||||
# - test/frontend/__fixtures__/settings.ts (example value for frontend testing)
|
||||
|
||||
# The full list of settings is declared in SettingsHelper
|
||||
validates :name, inclusion: { in: SETTINGS }
|
||||
|
||||
def value
|
||||
last_value = history_values.order(HistoryValue.arel_table['created_at'].desc).limit(1).first
|
||||
|
@ -43,7 +43,9 @@ class SettingPolicy < ApplicationPolicy
|
||||
pack_only_for_subscription overlapping_categories public_registrations facebook twitter viadeo linkedin instagram
|
||||
youtube vimeo dailymotion github echosciences pinterest lastfm flickr machines_module user_change_group
|
||||
user_validation_required user_validation_required_list store_module store_withdrawal_instructions store_hidden
|
||||
external_id machines_banner_active machines_banner_text machines_banner_cta_active machines_banner_cta_label machines_banner_cta_url]
|
||||
external_id machines_banner_active machines_banner_text machines_banner_cta_active machines_banner_cta_label
|
||||
machines_banner_cta_url trainings_banner_active trainings_banner_text trainings_banner_cta_active trainings_banner_cta_label
|
||||
trainings_banner_cta_url]
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -777,6 +777,36 @@ export const settings: Array<Setting> = [
|
||||
value: 'https://www.sleede.com/',
|
||||
last_update: '2022-12-23T14:39:12+0100',
|
||||
localized: 'Url'
|
||||
},
|
||||
{
|
||||
name: 'trainings_banner_active',
|
||||
value: 'true',
|
||||
last_update: '2022-12-23T14:39:12+0100',
|
||||
localized: 'Custom banner is active'
|
||||
},
|
||||
{
|
||||
name: 'trainings_banner_text',
|
||||
value: 'Test for Banner Content in Trainings',
|
||||
last_update: '2022-12-23T14:39:12+0100',
|
||||
localized: 'Text of the custom banner'
|
||||
},
|
||||
{
|
||||
name: 'trainings_banner_cta_active',
|
||||
value: 'true',
|
||||
last_update: '2022-12-23T14:39:12+0100',
|
||||
localized: 'Custom banner has a button'
|
||||
},
|
||||
{
|
||||
name: 'trainings_banner_cta_label',
|
||||
value: 'Test for Banner Button in Trainings',
|
||||
last_update: '2022-12-23T14:39:12+0100',
|
||||
localized: 'Label'
|
||||
},
|
||||
{
|
||||
name: 'trainings_banner_cta_url',
|
||||
value: 'https://www.sleede.com/',
|
||||
last_update: '2022-12-23T14:39:12+0100',
|
||||
localized: 'Url'
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -0,0 +1,14 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { TrainingEditorialBlock } from '../../../../app/frontend/src/javascript/components/trainings/training-editorial-block';
|
||||
|
||||
// Trainings Editorial Block
|
||||
describe('Trainings Editorial Block', () => {
|
||||
test('should render a banner', async () => {
|
||||
const onError = jest.fn();
|
||||
|
||||
render(<TrainingEditorialBlock onError={onError} />);
|
||||
|
||||
await waitFor(() => screen.getByText('Test for Banner Content in Trainings'));
|
||||
await waitFor(() => screen.getByText('Test for Banner Button in Trainings'));
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user