mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-19 08:52:25 +01:00
(ui) Uniform layout for settings and form
This commit is contained in:
parent
a0508e689e
commit
98e10dc774
@ -23,17 +23,19 @@ export const AdvancedAccountingForm = <TFieldValues extends FieldValues>({ regis
|
|||||||
SettingAPI.get('advanced_accounting').then(res => setIsEnabled(res.value === 'true')).catch(onError);
|
SettingAPI.get('advanced_accounting').then(res => setIsEnabled(res.value === 'true')).catch(onError);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (<>
|
||||||
<div className="advanced-accounting-form">
|
{isEnabled && <>
|
||||||
{isEnabled && <div>
|
<header>
|
||||||
<p className='title'>{t('app.admin.advanced_accounting_form.title')}</p>
|
<p className="title">{t('app.admin.advanced_accounting_form.title')}</p>
|
||||||
|
</header>
|
||||||
|
<div className="content">
|
||||||
<FormInput register={register}
|
<FormInput register={register}
|
||||||
id="advanced_accounting_attributes.code"
|
id="advanced_accounting_attributes.code"
|
||||||
label={t('app.admin.advanced_accounting_form.code')} />
|
label={t('app.admin.advanced_accounting_form.code')} />
|
||||||
<FormInput register={register}
|
<FormInput register={register}
|
||||||
id="advanced_accounting_attributes.analytical_section"
|
id="advanced_accounting_attributes.analytical_section"
|
||||||
label={t('app.admin.advanced_accounting_form.analytical_section')} />
|
label={t('app.admin.advanced_accounting_form.analytical_section')} />
|
||||||
</div>}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</>}
|
||||||
|
</>);
|
||||||
};
|
};
|
||||||
|
@ -23,6 +23,7 @@ import AgeRangeAPI from '../../api/age-range';
|
|||||||
import { Plus, Trash } from 'phosphor-react';
|
import { Plus, Trash } from 'phosphor-react';
|
||||||
import FormatLib from '../../lib/format';
|
import FormatLib from '../../lib/format';
|
||||||
import EventPriceCategoryAPI from '../../api/event-price-category';
|
import EventPriceCategoryAPI from '../../api/event-price-category';
|
||||||
|
import SettingAPI from '../../api/setting';
|
||||||
import { UpdateRecurrentModal } from './update-recurrent-modal';
|
import { UpdateRecurrentModal } from './update-recurrent-modal';
|
||||||
import { AdvancedAccountingForm } from '../accounting/advanced-accounting-form';
|
import { AdvancedAccountingForm } from '../accounting/advanced-accounting-form';
|
||||||
|
|
||||||
@ -52,6 +53,7 @@ export const EventForm: React.FC<EventFormProps> = ({ action, event, onError, on
|
|||||||
const [priceCategoriesOptions, setPriceCategoriesOptions] = useState<Array<SelectOption<number>>>(null);
|
const [priceCategoriesOptions, setPriceCategoriesOptions] = useState<Array<SelectOption<number>>>(null);
|
||||||
const [isOpenRecurrentModal, setIsOpenRecurrentModal] = useState<boolean>(false);
|
const [isOpenRecurrentModal, setIsOpenRecurrentModal] = useState<boolean>(false);
|
||||||
const [updatingEvent, setUpdatingEvent] = useState<Event>(null);
|
const [updatingEvent, setUpdatingEvent] = useState<Event>(null);
|
||||||
|
const [isActiveAccounting, setIsActiveAccounting] = useState<boolean>(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
EventCategoryAPI.index()
|
EventCategoryAPI.index()
|
||||||
@ -66,6 +68,7 @@ export const EventForm: React.FC<EventFormProps> = ({ action, event, onError, on
|
|||||||
EventPriceCategoryAPI.index()
|
EventPriceCategoryAPI.index()
|
||||||
.then(data => setPriceCategoriesOptions(data.map(c => decorationToOption(c))))
|
.then(data => setPriceCategoriesOptions(data.map(c => decorationToOption(c))))
|
||||||
.catch(onError);
|
.catch(onError);
|
||||||
|
SettingAPI.get('advanced_accounting').then(res => setIsActiveAccounting(res.value === 'true')).catch(onError);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -153,7 +156,19 @@ export const EventForm: React.FC<EventFormProps> = ({ action, event, onError, on
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="event-form" onSubmit={handleSubmit(onSubmit)}>
|
<div className="event-form">
|
||||||
|
<header>
|
||||||
|
<h2>{t('app.admin.event_form.ACTION_title', { ACTION: action })}</h2>
|
||||||
|
<FabButton onClick={handleSubmit(onSubmit)} className="fab-button save-btn is-main">
|
||||||
|
{t('app.admin.event_form.save')}
|
||||||
|
</FabButton>
|
||||||
|
</header>
|
||||||
|
<form className="event-form-content" onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<section>
|
||||||
|
<header>
|
||||||
|
<p className="title">{t('app.admin.event_form.description')}</p>
|
||||||
|
</header>
|
||||||
|
<div className="content">
|
||||||
<FormInput register={register}
|
<FormInput register={register}
|
||||||
id="title"
|
id="title"
|
||||||
formState={formState}
|
formState={formState}
|
||||||
@ -190,9 +205,15 @@ export const EventForm: React.FC<EventFormProps> = ({ action, event, onError, on
|
|||||||
formState={formState}
|
formState={formState}
|
||||||
options={ageRangeOptions}
|
options={ageRangeOptions}
|
||||||
label={t('app.admin.event_form.age_range')} />}
|
label={t('app.admin.event_form.age_range')} />}
|
||||||
<div className="dates-times">
|
</div>
|
||||||
<h4>{t('app.admin.event_form.dates_and_opening_hours')}</h4>
|
</section>
|
||||||
<div className="dates">
|
|
||||||
|
<section>
|
||||||
|
<header>
|
||||||
|
<p className='title'>{t('app.admin.event_form.dates_and_opening_hours')}</p>
|
||||||
|
</header>
|
||||||
|
<div className="content">
|
||||||
|
<div className="grp">
|
||||||
<FormInput id="start_date"
|
<FormInput id="start_date"
|
||||||
type="date"
|
type="date"
|
||||||
register={register}
|
register={register}
|
||||||
@ -212,7 +233,7 @@ export const EventForm: React.FC<EventFormProps> = ({ action, event, onError, on
|
|||||||
formState={formState}
|
formState={formState}
|
||||||
tooltip={t('app.admin.event_form.all_day_help')}
|
tooltip={t('app.admin.event_form.all_day_help')}
|
||||||
onChange={setIsAllDay} />
|
onChange={setIsAllDay} />
|
||||||
{!isAllDay && <div className="times">
|
{!isAllDay && <div className="grp">
|
||||||
<FormInput id="start_time"
|
<FormInput id="start_time"
|
||||||
type="time"
|
type="time"
|
||||||
register={register}
|
register={register}
|
||||||
@ -226,7 +247,7 @@ export const EventForm: React.FC<EventFormProps> = ({ action, event, onError, on
|
|||||||
label={t('app.admin.event_form.end_time')}
|
label={t('app.admin.event_form.end_time')}
|
||||||
rules={{ required: !isAllDay }} />
|
rules={{ required: !isAllDay }} />
|
||||||
</div>}
|
</div>}
|
||||||
{action === 'create' && <div className="recurring">
|
{action === 'create' && <div className="grp">
|
||||||
<FormSelect options={buildRecurrenceOptions()}
|
<FormSelect options={buildRecurrenceOptions()}
|
||||||
control={control}
|
control={control}
|
||||||
formState={formState}
|
formState={formState}
|
||||||
@ -243,8 +264,13 @@ export const EventForm: React.FC<EventFormProps> = ({ action, event, onError, on
|
|||||||
rules={{ required: !['none', undefined].includes(output.recurrence) }} />
|
rules={{ required: !['none', undefined].includes(output.recurrence) }} />
|
||||||
</div>}
|
</div>}
|
||||||
</div>
|
</div>
|
||||||
<div className="seats-prices">
|
</section>
|
||||||
<h4>{t('app.admin.event_form.prices_and_availabilities')}</h4>
|
|
||||||
|
<section>
|
||||||
|
<header>
|
||||||
|
<p className="title">{t('app.admin.event_form.prices_and_availabilities')}</p>
|
||||||
|
</header>
|
||||||
|
<div className="content">
|
||||||
<FormInput register={register}
|
<FormInput register={register}
|
||||||
id="nb_total_places"
|
id="nb_total_places"
|
||||||
label={t('app.admin.event_form.seats_available')}
|
label={t('app.admin.event_form.seats_available')}
|
||||||
@ -257,6 +283,7 @@ export const EventForm: React.FC<EventFormProps> = ({ action, event, onError, on
|
|||||||
label={t('app.admin.event_form.standard_rate')}
|
label={t('app.admin.event_form.standard_rate')}
|
||||||
tooltip={t('app.admin.event_form.0_equal_free')}
|
tooltip={t('app.admin.event_form.0_equal_free')}
|
||||||
addOn={FormatLib.currencySymbol()} />
|
addOn={FormatLib.currencySymbol()} />
|
||||||
|
{/* TODO: need ui */}
|
||||||
{priceCategoriesOptions && <div className="additional-prices">
|
{priceCategoriesOptions && <div className="additional-prices">
|
||||||
{fields.map((price, index) => (
|
{fields.map((price, index) => (
|
||||||
<div key={index} className={`price-item ${output.event_price_categories_attributes && output.event_price_categories_attributes[index]?._destroy ? 'destroyed-item' : ''}`}>
|
<div key={index} className={`price-item ${output.event_price_categories_attributes && output.event_price_categories_attributes[index]?._destroy ? 'destroyed-item' : ''}`}>
|
||||||
@ -280,9 +307,15 @@ export const EventForm: React.FC<EventFormProps> = ({ action, event, onError, on
|
|||||||
</FabButton>
|
</FabButton>
|
||||||
</div>}
|
</div>}
|
||||||
</div>
|
</div>
|
||||||
<div className="attachments">
|
</section>
|
||||||
<div className='form-item-header event-files-header'>
|
|
||||||
<h4>{t('app.admin.event_form.attachments')}</h4>
|
<section>
|
||||||
|
<header>
|
||||||
|
<p className="title">{t('app.admin.event_form.attachments')}</p>
|
||||||
|
</header>
|
||||||
|
<div className="content">
|
||||||
|
<div className='form-item-header machine-files-header'>
|
||||||
|
<p>{t('app.admin.event_form.attached_files_pdf')}</p>
|
||||||
</div>
|
</div>
|
||||||
<FormMultiFileUpload setValue={setValue}
|
<FormMultiFileUpload setValue={setValue}
|
||||||
addButtonLabel={t('app.admin.event_form.add_a_new_file')}
|
addButtonLabel={t('app.admin.event_form.add_a_new_file')}
|
||||||
@ -292,16 +325,21 @@ export const EventForm: React.FC<EventFormProps> = ({ action, event, onError, on
|
|||||||
id="event_files_attributes"
|
id="event_files_attributes"
|
||||||
className="event-files" />
|
className="event-files" />
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{isActiveAccounting &&
|
||||||
|
<section>
|
||||||
<AdvancedAccountingForm register={register} onError={onError} />
|
<AdvancedAccountingForm register={register} onError={onError} />
|
||||||
<FabButton type="submit" className="is-info submit-btn">
|
</section>
|
||||||
{t('app.admin.event_form.ACTION_event', { ACTION: action })}
|
}
|
||||||
</FabButton>
|
|
||||||
<UpdateRecurrentModal isOpen={isOpenRecurrentModal}
|
<UpdateRecurrentModal isOpen={isOpenRecurrentModal}
|
||||||
toggleModal={toggleRecurrentModal}
|
toggleModal={toggleRecurrentModal}
|
||||||
event={updatingEvent}
|
event={updatingEvent}
|
||||||
onConfirmed={handleUpdateRecurrentConfirmed}
|
onConfirmed={handleUpdateRecurrentConfirmed}
|
||||||
datesChanged={datesHaveChanged()} />
|
datesChanged={datesHaveChanged()} />
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,7 +18,9 @@ import { AdvancedAccountingForm } from '../accounting/advanced-accounting-form';
|
|||||||
import { FormSelect } from '../form/form-select';
|
import { FormSelect } from '../form/form-select';
|
||||||
import { SelectOption } from '../../models/select';
|
import { SelectOption } from '../../models/select';
|
||||||
import MachineCategoryAPI from '../../api/machine-category';
|
import MachineCategoryAPI from '../../api/machine-category';
|
||||||
|
import SettingAPI from '../../api/setting';
|
||||||
import { MachineCategory } from '../../models/machine-category';
|
import { MachineCategory } from '../../models/machine-category';
|
||||||
|
import { FabAlert } from '../base/fab-alert';
|
||||||
|
|
||||||
declare const Application: IApplication;
|
declare const Application: IApplication;
|
||||||
|
|
||||||
@ -38,12 +40,15 @@ export const MachineForm: React.FC<MachineFormProps> = ({ action, machine, onErr
|
|||||||
const { t } = useTranslation('admin');
|
const { t } = useTranslation('admin');
|
||||||
|
|
||||||
const [machineCategories, setMachineCategories] = useState<Array<MachineCategory>>([]);
|
const [machineCategories, setMachineCategories] = useState<Array<MachineCategory>>([]);
|
||||||
|
const [isActiveAccounting, setIsActiveAccounting] = useState<boolean>(false);
|
||||||
|
|
||||||
// retrieve the full list of machine categories on component mount
|
// retrieve the full list of machine categories on component mount
|
||||||
|
// check advanced accounting activation
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
MachineCategoryAPI.index()
|
MachineCategoryAPI.index()
|
||||||
.then(data => setMachineCategories(data))
|
.then(data => setMachineCategories(data))
|
||||||
.catch(e => onError(e));
|
.catch(e => onError(e));
|
||||||
|
SettingAPI.get('advanced_accounting').then(res => setIsActiveAccounting(res.value === 'true')).catch(onError);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,7 +73,24 @@ export const MachineForm: React.FC<MachineFormProps> = ({ action, machine, onErr
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="machine-form" onSubmit={handleSubmit(onSubmit)}>
|
<div className="machine-form">
|
||||||
|
<header>
|
||||||
|
<h2>{t('app.admin.machine_form.ACTION_title', { ACTION: action })}</h2>
|
||||||
|
<FabButton onClick={handleSubmit(onSubmit)} className="fab-button save-btn is-main">
|
||||||
|
{t('app.admin.machine_form.save')}
|
||||||
|
</FabButton>
|
||||||
|
</header>
|
||||||
|
<form className="machine-form-content" onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
{action === 'create' &&
|
||||||
|
<FabAlert level='warning'>
|
||||||
|
{t('app.admin.machine_form.watch_out_when_creating_a_new_machine_its_prices_are_initialized_at_0_for_all_subscriptions')} {t('app.admin.machine_form.consider_changing_them_before_creating_any_reservation_slot')}
|
||||||
|
</FabAlert>
|
||||||
|
}
|
||||||
|
<section>
|
||||||
|
<header>
|
||||||
|
<p className="title">{t('app.admin.machine_form.description')}</p>
|
||||||
|
</header>
|
||||||
|
<div className="content">
|
||||||
<FormInput register={register} id="name"
|
<FormInput register={register} id="name"
|
||||||
formState={formState}
|
formState={formState}
|
||||||
rules={{ required: true }}
|
rules={{ required: true }}
|
||||||
@ -87,18 +109,26 @@ export const MachineForm: React.FC<MachineFormProps> = ({ action, machine, onErr
|
|||||||
rules={{ required: true }}
|
rules={{ required: true }}
|
||||||
label={t('app.admin.machine_form.description')}
|
label={t('app.admin.machine_form.description')}
|
||||||
limit={null}
|
limit={null}
|
||||||
heading bulletList blockquote link video image />
|
heading bulletList blockquote link image video />
|
||||||
<FormRichText control={control}
|
<FormRichText control={control}
|
||||||
id="spec"
|
id="spec"
|
||||||
rules={{ required: true }}
|
rules={{ required: true }}
|
||||||
label={t('app.admin.machine_form.technical_specifications')}
|
label={t('app.admin.machine_form.technical_specifications')}
|
||||||
limit={null}
|
limit={null}
|
||||||
heading bulletList blockquote link video image />
|
heading bulletList link />
|
||||||
<FormSelect options={buildOptions()}
|
<FormSelect options={buildOptions()}
|
||||||
control={control}
|
control={control}
|
||||||
id="machine_category_id"
|
id="machine_category_id"
|
||||||
formState={formState}
|
formState={formState}
|
||||||
label={t('app.admin.machine_form.category')} />
|
label={t('app.admin.machine_form.category')} />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<header>
|
||||||
|
<p className="title">{t('app.admin.machine_form.attachments')}</p>
|
||||||
|
</header>
|
||||||
|
<div className="content">
|
||||||
<div className='form-item-header machine-files-header'>
|
<div className='form-item-header machine-files-header'>
|
||||||
<p>{t('app.admin.machine_form.attached_files_pdf')}</p>
|
<p>{t('app.admin.machine_form.attached_files_pdf')}</p>
|
||||||
</div>
|
</div>
|
||||||
@ -109,7 +139,14 @@ export const MachineForm: React.FC<MachineFormProps> = ({ action, machine, onErr
|
|||||||
register={register}
|
register={register}
|
||||||
id="machine_files_attributes"
|
id="machine_files_attributes"
|
||||||
className="machine-files" />
|
className="machine-files" />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<header>
|
||||||
|
<p className="title">{t('app.admin.machine_form.settings')}</p>
|
||||||
|
</header>
|
||||||
|
<div className="content">
|
||||||
<FormSwitch control={control}
|
<FormSwitch control={control}
|
||||||
id="reservable"
|
id="reservable"
|
||||||
label={t('app.admin.machine_form.reservable')}
|
label={t('app.admin.machine_form.reservable')}
|
||||||
@ -119,11 +156,16 @@ export const MachineForm: React.FC<MachineFormProps> = ({ action, machine, onErr
|
|||||||
id="disabled"
|
id="disabled"
|
||||||
label={t('app.admin.machine_form.disable_machine')}
|
label={t('app.admin.machine_form.disable_machine')}
|
||||||
tooltip={t('app.admin.machine_form.disabled_help')} />
|
tooltip={t('app.admin.machine_form.disabled_help')} />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{isActiveAccounting &&
|
||||||
|
<section>
|
||||||
<AdvancedAccountingForm register={register} onError={onError} />
|
<AdvancedAccountingForm register={register} onError={onError} />
|
||||||
<FabButton type="submit" className="is-info submit-btn">
|
</section>
|
||||||
{t('app.admin.machine_form.ACTION_machine', { ACTION: action })}
|
}
|
||||||
</FabButton>
|
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
import { SubmitHandler, useForm, useWatch } from 'react-hook-form';
|
import { SubmitHandler, useForm, useWatch } from 'react-hook-form';
|
||||||
import SpaceAPI from '../../api/space';
|
import SpaceAPI from '../../api/space';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -14,6 +15,8 @@ import { FormMultiFileUpload } from '../form/form-multi-file-upload';
|
|||||||
import { FabButton } from '../base/fab-button';
|
import { FabButton } from '../base/fab-button';
|
||||||
import { Space } from '../../models/space';
|
import { Space } from '../../models/space';
|
||||||
import { AdvancedAccountingForm } from '../accounting/advanced-accounting-form';
|
import { AdvancedAccountingForm } from '../accounting/advanced-accounting-form';
|
||||||
|
import SettingAPI from '../../api/setting';
|
||||||
|
import { FabAlert } from '../base/fab-alert';
|
||||||
|
|
||||||
declare const Application: IApplication;
|
declare const Application: IApplication;
|
||||||
|
|
||||||
@ -32,6 +35,12 @@ export const SpaceForm: React.FC<SpaceFormProps> = ({ action, space, onError, on
|
|||||||
const output = useWatch<Space>({ control });
|
const output = useWatch<Space>({ control });
|
||||||
const { t } = useTranslation('admin');
|
const { t } = useTranslation('admin');
|
||||||
|
|
||||||
|
const [isActiveAccounting, setIsActiveAccounting] = useState<boolean>(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
SettingAPI.get('advanced_accounting').then(res => setIsActiveAccounting(res.value === 'true')).catch(onError);
|
||||||
|
}, []);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback triggered when the user validates the machine form: handle create or update
|
* Callback triggered when the user validates the machine form: handle create or update
|
||||||
*/
|
*/
|
||||||
@ -45,7 +54,24 @@ export const SpaceForm: React.FC<SpaceFormProps> = ({ action, space, onError, on
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="space-form" onSubmit={handleSubmit(onSubmit)}>
|
<div className="space-form">
|
||||||
|
<header>
|
||||||
|
<h2>{t('app.admin.space_form.ACTION_title', { ACTION: action })}</h2>
|
||||||
|
<FabButton onClick={handleSubmit(onSubmit)} className="fab-button save-btn is-main">
|
||||||
|
{t('app.admin.space_form.save')}
|
||||||
|
</FabButton>
|
||||||
|
</header>
|
||||||
|
<form className="space-form-content" onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
{action === 'create' &&
|
||||||
|
<FabAlert level='warning'>
|
||||||
|
{t('app.admin.space_form.watch_out_when_creating_a_new_space_its_prices_are_initialized_at_0_for_all_subscriptions')} {t('app.admin.space_form.consider_changing_its_prices_before_creating_any_reservation_slot')}
|
||||||
|
</FabAlert>
|
||||||
|
}
|
||||||
|
<section>
|
||||||
|
<header>
|
||||||
|
<p className="title">{t('app.admin.space_form.description')}</p>
|
||||||
|
</header>
|
||||||
|
<div className="content">
|
||||||
<FormInput register={register} id="name"
|
<FormInput register={register} id="name"
|
||||||
formState={formState}
|
formState={formState}
|
||||||
rules={{ required: true }}
|
rules={{ required: true }}
|
||||||
@ -75,8 +101,15 @@ export const SpaceForm: React.FC<SpaceFormProps> = ({ action, space, onError, on
|
|||||||
id="characteristics"
|
id="characteristics"
|
||||||
label={t('app.admin.space_form.characteristics')}
|
label={t('app.admin.space_form.characteristics')}
|
||||||
limit={null}
|
limit={null}
|
||||||
heading bulletList blockquote link video image />
|
heading bulletList link />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<header>
|
||||||
|
<p className="title">{t('app.admin.space_form.attachments')}</p>
|
||||||
|
</header>
|
||||||
|
<div className="content">
|
||||||
<div className='form-item-header space-files-header'>
|
<div className='form-item-header space-files-header'>
|
||||||
<p>{t('app.admin.space_form.attached_files_pdf')}</p>
|
<p>{t('app.admin.space_form.attached_files_pdf')}</p>
|
||||||
</div>
|
</div>
|
||||||
@ -87,16 +120,28 @@ export const SpaceForm: React.FC<SpaceFormProps> = ({ action, space, onError, on
|
|||||||
register={register}
|
register={register}
|
||||||
id="space_files_attributes"
|
id="space_files_attributes"
|
||||||
className="space-files" />
|
className="space-files" />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<header>
|
||||||
|
<p className="title">{t('app.admin.space_form.settings')}</p>
|
||||||
|
</header>
|
||||||
|
<div className="content">
|
||||||
<FormSwitch control={control}
|
<FormSwitch control={control}
|
||||||
id="disabled"
|
id="disabled"
|
||||||
label={t('app.admin.space_form.disable_space')}
|
label={t('app.admin.space_form.disable_space')}
|
||||||
tooltip={t('app.admin.space_form.disabled_help')} />
|
tooltip={t('app.admin.space_form.disabled_help')} />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{isActiveAccounting &&
|
||||||
|
<section>
|
||||||
<AdvancedAccountingForm register={register} onError={onError} />
|
<AdvancedAccountingForm register={register} onError={onError} />
|
||||||
<FabButton type="submit" className="is-info submit-btn">
|
</section>
|
||||||
{t('app.admin.space_form.ACTION_space', { ACTION: action })}
|
}
|
||||||
</FabButton>
|
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ import { SelectOption } from '../../models/select';
|
|||||||
import SettingAPI from '../../api/setting';
|
import SettingAPI from '../../api/setting';
|
||||||
import { Setting } from '../../models/setting';
|
import { Setting } from '../../models/setting';
|
||||||
import { AdvancedAccountingForm } from '../accounting/advanced-accounting-form';
|
import { AdvancedAccountingForm } from '../accounting/advanced-accounting-form';
|
||||||
import { FabPanel } from '../base/fab-panel';
|
import { FabAlert } from '../base/fab-alert';
|
||||||
|
|
||||||
declare const Application: IApplication;
|
declare const Application: IApplication;
|
||||||
|
|
||||||
@ -116,9 +116,24 @@ export const TrainingForm: React.FC<TrainingFormProps> = ({ action, training, on
|
|||||||
const urlRegex = /^(https?:\/\/)([^.]+)\.(.{2,30})(\/.*)*\/?$/;
|
const urlRegex = /^(https?:\/\/)([^.]+)\.(.{2,30})(\/.*)*\/?$/;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="training-form" onSubmit={handleSubmit(onSubmit)}>
|
<div className="training-form">
|
||||||
<FabPanel>
|
<header>
|
||||||
|
<h2>{t('app.admin.training_form.ACTION_title', { ACTION: action })}</h2>
|
||||||
|
<FabButton onClick={handleSubmit(onSubmit)} className="fab-button save-btn is-main">
|
||||||
|
{t('app.admin.training_form.save')}
|
||||||
|
</FabButton>
|
||||||
|
</header>
|
||||||
|
<form className='training-form-content'>
|
||||||
|
{action === 'create' &&
|
||||||
|
<FabAlert level='warning'>
|
||||||
|
{t('app.admin.training_form.beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero')} {t('app.admin.training_form.dont_forget_to_change_them_before_creating_slots_for_this_training')}
|
||||||
|
</FabAlert>
|
||||||
|
}
|
||||||
|
<section>
|
||||||
|
<header>
|
||||||
<p className="title">{t('app.admin.training_form.description')}</p>
|
<p className="title">{t('app.admin.training_form.description')}</p>
|
||||||
|
</header>
|
||||||
|
<div className="content">
|
||||||
<FormInput register={register} id="name"
|
<FormInput register={register} id="name"
|
||||||
formState={formState}
|
formState={formState}
|
||||||
rules={{ required: true }}
|
rules={{ required: true }}
|
||||||
@ -138,17 +153,22 @@ export const TrainingForm: React.FC<TrainingFormProps> = ({ action, training, on
|
|||||||
label={t('app.admin.training_form.description')}
|
label={t('app.admin.training_form.description')}
|
||||||
limit={null}
|
limit={null}
|
||||||
heading bulletList blockquote link />
|
heading bulletList blockquote link />
|
||||||
</FabPanel>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<FabPanel>
|
<section>
|
||||||
|
<header>
|
||||||
<p className="title">{t('app.admin.training_form.settings')}</p>
|
<p className="title">{t('app.admin.training_form.settings')}</p>
|
||||||
|
</header>
|
||||||
|
<div className="content">
|
||||||
{machineModule?.value === 'true' &&
|
{machineModule?.value === 'true' &&
|
||||||
<FormMultiSelect control={control}
|
<FormMultiSelect control={control}
|
||||||
id="machine_ids"
|
id="machine_ids"
|
||||||
formState={formState}
|
formState={formState}
|
||||||
label={t('app.admin.training_form.associated_machines')}
|
label={t('app.admin.training_form.associated_machines')}
|
||||||
tooltip={t('app.admin.training_form.associated_machines_help')}
|
tooltip={t('app.admin.training_form.associated_machines_help')}
|
||||||
loadOptions={loadMachines} />}
|
loadOptions={loadMachines} />
|
||||||
|
}
|
||||||
<FormInput register={register}
|
<FormInput register={register}
|
||||||
type="number"
|
type="number"
|
||||||
id="nb_total_places"
|
id="nb_total_places"
|
||||||
@ -164,17 +184,15 @@ export const TrainingForm: React.FC<TrainingFormProps> = ({ action, training, on
|
|||||||
id="disabled"
|
id="disabled"
|
||||||
label={t('app.admin.training_form.disable_training')}
|
label={t('app.admin.training_form.disable_training')}
|
||||||
tooltip={t('app.admin.training_form.disabled_help')} />
|
tooltip={t('app.admin.training_form.disabled_help')} />
|
||||||
</FabPanel>
|
|
||||||
|
|
||||||
<FabPanel>
|
|
||||||
<p className="title">
|
|
||||||
{t('app.admin.training_form.automatic_cancellation')}
|
|
||||||
<div className="fab-tooltip">
|
|
||||||
<span className="trigger"><i className="fa fa-question-circle" /></span>
|
|
||||||
<div className="content">{t('app.admin.training_form.automatic_cancellation_info')}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</p>
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<header>
|
||||||
|
<p className="title">{t('app.admin.training_form.automatic_cancellation')}</p>
|
||||||
|
<p className="description">{t('app.admin.training_form.automatic_cancellation_info')}</p>
|
||||||
|
</header>
|
||||||
|
<div className="content">
|
||||||
<FormSwitch id="active_cancellation" control={control}
|
<FormSwitch id="active_cancellation" control={control}
|
||||||
onChange={toggleCancellationSwitch} formState={formState}
|
onChange={toggleCancellationSwitch} formState={formState}
|
||||||
defaultValue={isActiveCancellation}
|
defaultValue={isActiveCancellation}
|
||||||
@ -197,17 +215,17 @@ export const TrainingForm: React.FC<TrainingFormProps> = ({ action, training, on
|
|||||||
nullable
|
nullable
|
||||||
label={t('app.admin.training_form.automatic_cancellation_deadline')} />
|
label={t('app.admin.training_form.automatic_cancellation_deadline')} />
|
||||||
</>}
|
</>}
|
||||||
</FabPanel>
|
|
||||||
|
|
||||||
<FabPanel>
|
|
||||||
<p className="title">
|
|
||||||
{t('app.admin.training_form.generic_text_block')}
|
|
||||||
<div className="fab-tooltip">
|
|
||||||
<span className="trigger"><i className="fa fa-question-circle" /></span>
|
|
||||||
<div className="content">{t('app.admin.training_form.generic_text_block_info')}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</p>
|
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<header>
|
||||||
|
<p className="title">{t('app.admin.training_form.generic_text_block')}</p>
|
||||||
|
<p className="description">{t('app.admin.training_form.generic_text_block_info')}</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div className="content">
|
||||||
<FormSwitch id="active_text_block" control={control}
|
<FormSwitch id="active_text_block" control={control}
|
||||||
onChange={toggleTextBlockSwitch} formState={formState}
|
onChange={toggleTextBlockSwitch} formState={formState}
|
||||||
defaultValue={isActiveTextBlock}
|
defaultValue={isActiveTextBlock}
|
||||||
@ -238,18 +256,16 @@ export const TrainingForm: React.FC<TrainingFormProps> = ({ action, training, on
|
|||||||
label={t('app.admin.training_form.cta_url')} />
|
label={t('app.admin.training_form.cta_url')} />
|
||||||
</>}
|
</>}
|
||||||
</>}
|
</>}
|
||||||
</FabPanel>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
{isActiveAccounting &&
|
{isActiveAccounting &&
|
||||||
<FabPanel>
|
<section>
|
||||||
<AdvancedAccountingForm register={register} onError={onError} />
|
<AdvancedAccountingForm register={register} onError={onError} />
|
||||||
</FabPanel>
|
</section>
|
||||||
}
|
}
|
||||||
|
|
||||||
<FabButton type="submit" className="fab-button save-btn is-main">
|
|
||||||
{t('app.admin.training_form.ACTION_training', { ACTION: action })}
|
|
||||||
</FabButton>
|
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -77,14 +77,16 @@ export const TrainingsSettings: React.FC<TrainingsSettingsProps> = () => {
|
|||||||
<div className="trainings-settings">
|
<div className="trainings-settings">
|
||||||
<header>
|
<header>
|
||||||
<h2>{t('app.admin.trainings_settings.title')}</h2>
|
<h2>{t('app.admin.trainings_settings.title')}</h2>
|
||||||
|
<FabButton onClick={handleSubmit(onSubmit)} className='save-btn is-main'>{t('app.admin.trainings_settings.save')}</FabButton>
|
||||||
</header>
|
</header>
|
||||||
<form onSubmit={handleSubmit(onSubmit)} className="trainings-settings-content">
|
<form className="trainings-settings-content">
|
||||||
<div className="settings-section">
|
<div className="settings-section">
|
||||||
<p className="section-title">{t('app.admin.trainings_settings.automatic_cancellation')}</p>
|
<header>
|
||||||
<FabAlert level="warning">
|
<p className="title">{t('app.admin.trainings_settings.automatic_cancellation')}</p>
|
||||||
{t('app.admin.trainings_settings.automatic_cancellation_info')}
|
<p className="description">{t('app.admin.trainings_settings.automatic_cancellation_info')}</p>
|
||||||
</FabAlert>
|
</header>
|
||||||
|
|
||||||
|
<div className="content">
|
||||||
<FormSwitch id="active_auto_cancellation" control={control}
|
<FormSwitch id="active_auto_cancellation" control={control}
|
||||||
onChange={toggleAutoCancellation} formState={formState}
|
onChange={toggleAutoCancellation} formState={formState}
|
||||||
defaultValue={isActiveAutoCancellation}
|
defaultValue={isActiveAutoCancellation}
|
||||||
@ -107,13 +109,15 @@ export const TrainingsSettings: React.FC<TrainingsSettingsProps> = () => {
|
|||||||
label={t('app.admin.trainings_settings.automatic_cancellation_deadline')} />
|
label={t('app.admin.trainings_settings.automatic_cancellation_deadline')} />
|
||||||
</>}
|
</>}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="settings-section">
|
<div className="settings-section">
|
||||||
<p className="section-title">{t('app.admin.trainings_settings.automatic_cancellation')}</p>
|
<header>
|
||||||
<FabAlert level="warning">
|
<p className="title">{t('app.admin.trainings_settings.generic_text_block')}</p>
|
||||||
{t('app.admin.trainings_settings.generic_text_block_info')}
|
<p className="description">{t('app.admin.trainings_settings.generic_text_block_info')}</p>
|
||||||
</FabAlert>
|
</header>
|
||||||
|
|
||||||
|
<div className="content">
|
||||||
<FormSwitch id="active_text_block" control={control}
|
<FormSwitch id="active_text_block" control={control}
|
||||||
onChange={toggleTextBlockSwitch} formState={formState}
|
onChange={toggleTextBlockSwitch} formState={formState}
|
||||||
defaultValue={isActiveTextBlock}
|
defaultValue={isActiveTextBlock}
|
||||||
@ -145,8 +149,7 @@ export const TrainingsSettings: React.FC<TrainingsSettingsProps> = () => {
|
|||||||
</>}
|
</>}
|
||||||
</>}
|
</>}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<FabButton type='submit' className='save-btn'>{t('app.admin.trainings_settings.save')}</FabButton>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.fab-panel {
|
.fab-panel {
|
||||||
background-color: #fff;
|
background-color: var(--gray-soft-lightest);
|
||||||
border: 1px solid #ddd;
|
border: 1px solid var(--gray-soft-dark);
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
|
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
|
||||||
margin: 30px 30px 30px 0;
|
margin: 30px 30px 30px 0;
|
||||||
@ -11,9 +11,9 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.panel-header {
|
.panel-header {
|
||||||
background-color: #f4f3f3;
|
background-color: var(--gray-soft-light);
|
||||||
padding: 18px 15px;
|
padding: 18px 15px;
|
||||||
border-bottom: 1px solid #ddd;
|
border-bottom: 1px solid var(--gray-soft-dark);
|
||||||
border-top-right-radius: var(--border-radius);
|
border-top-right-radius: var(--border-radius);
|
||||||
border-top-left-radius: var(--border-radius);
|
border-top-left-radius: var(--border-radius);
|
||||||
|
|
||||||
@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
&.no-header {
|
&.no-header {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
background-color: #f4f3f3;
|
background-color: var(--gray-soft-light);
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,14 +169,15 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
height: 0;
|
height: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 600px;
|
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
padding-bottom: calc(100% / 16 * 9);
|
padding-bottom: calc(100% / 16 * 9);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
//.container { max-width: 600px; }
|
||||||
|
|
||||||
iframe {
|
iframe {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
max-width: 100%;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,34 @@
|
|||||||
.event-form {
|
.event-form {
|
||||||
|
max-width: 1260px;
|
||||||
|
margin: 2.4rem auto 0;
|
||||||
|
padding: 0 3rem 6rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
& > header {
|
||||||
|
padding-bottom: 0;
|
||||||
|
@include header($sticky: true);
|
||||||
|
gap: 2.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 3.2rem;
|
||||||
|
|
||||||
|
.fab-alert { margin: 0; }
|
||||||
|
|
||||||
|
section { @include layout-settings; }
|
||||||
|
.save-btn { align-self: flex-start; }
|
||||||
|
}
|
||||||
|
|
||||||
.additional-prices {
|
.additional-prices {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
|
gap: 2.4rem;
|
||||||
|
|
||||||
.add-price {
|
.add-price {
|
||||||
max-width: fit-content;
|
max-width: fit-content;
|
||||||
margin-bottom: 1.6rem;
|
|
||||||
}
|
}
|
||||||
.price-item {
|
.price-item {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -22,12 +44,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.dates, .times, .price-item, .recurring {
|
.grp {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: column;
|
||||||
|
@media (min-width: 640px) {flex-direction: row; }
|
||||||
|
|
||||||
.form-item:first-child {
|
.form-item:first-child {
|
||||||
margin-right: 32px;
|
margin-right: 2.4rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.submit-btn {
|
.submit-btn {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
.form-switch {
|
.form-switch {
|
||||||
.form-item-header {
|
.form-item-header {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
.fab-tooltip .content {
|
.fab-tooltip .content {
|
||||||
max-width: min(75vw, 30ch);
|
max-width: min(75vw, 30ch);
|
||||||
|
@ -1,11 +1,30 @@
|
|||||||
.machine-form {
|
.machine-form {
|
||||||
|
max-width: 1260px;
|
||||||
|
margin: 2.4rem auto 0;
|
||||||
|
padding: 0 3rem 6rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
& > header {
|
||||||
|
padding-bottom: 0;
|
||||||
|
@include header($sticky: true);
|
||||||
|
gap: 2.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 3.2rem;
|
||||||
|
|
||||||
|
.fab-alert { margin: 0; }
|
||||||
|
|
||||||
|
section { @include layout-settings; }
|
||||||
|
.save-btn { align-self: flex-start; }
|
||||||
|
}
|
||||||
|
|
||||||
.machine-files-header.form-item-header p {
|
.machine-files-header.form-item-header p {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
.machine-files {
|
.machine-files {
|
||||||
margin-bottom: 1.4rem;
|
margin-bottom: 1.4rem;
|
||||||
}
|
}
|
||||||
.submit-btn {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,30 @@
|
|||||||
.space-form {
|
.space-form {
|
||||||
|
max-width: 1260px;
|
||||||
|
margin: 2.4rem auto 0;
|
||||||
|
padding: 0 3rem 6rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
& > header {
|
||||||
|
padding-bottom: 0;
|
||||||
|
@include header($sticky: true);
|
||||||
|
gap: 2.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 3.2rem;
|
||||||
|
|
||||||
|
.fab-alert { margin: 0; }
|
||||||
|
|
||||||
|
section { @include layout-settings; }
|
||||||
|
.save-btn { align-self: flex-start; }
|
||||||
|
}
|
||||||
|
|
||||||
.space-files-header.form-item-header p {
|
.space-files-header.form-item-header p {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
.space-files {
|
.space-files {
|
||||||
margin-bottom: 1.4rem;
|
margin-bottom: 1.4rem;
|
||||||
}
|
}
|
||||||
.submit-btn {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,6 @@
|
|||||||
header {
|
header {
|
||||||
@include header();
|
@include header();
|
||||||
grid-column: 2 / -2;
|
grid-column: 2 / -2;
|
||||||
.grpBtn {
|
|
||||||
display: flex;
|
|
||||||
& > *:not(:first-child) { margin-left: 2.4rem; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.fab-alert {
|
.fab-alert {
|
||||||
grid-column: 2 / -2;
|
grid-column: 2 / -2;
|
||||||
|
@ -9,10 +9,6 @@
|
|||||||
@include header();
|
@include header();
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
.grpBtn {
|
|
||||||
display: flex;
|
|
||||||
& > *:not(:first-child) { margin-left: 2.4rem; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,8 +23,6 @@
|
|||||||
padding: 0 0 2.4rem 0;
|
padding: 0 0 2.4rem 0;
|
||||||
|
|
||||||
.grpBtn {
|
.grpBtn {
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
button { display: none; }
|
button { display: none; }
|
||||||
.filters-toggle {
|
.filters-toggle {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -1,24 +1,23 @@
|
|||||||
// hide Angular tag for the grid
|
|
||||||
training-form { display: contents; }
|
|
||||||
|
|
||||||
.training-form {
|
.training-form {
|
||||||
grid-column: 2/-2;
|
max-width: 1260px;
|
||||||
|
margin: 2.4rem auto 0;
|
||||||
|
padding: 0 3rem 6rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
& > header {
|
||||||
|
padding-bottom: 0;
|
||||||
|
@include header($sticky: true);
|
||||||
gap: 2.4rem;
|
gap: 2.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
.fab-panel {
|
&-content {
|
||||||
width: 100%;
|
|
||||||
margin: 0;
|
|
||||||
.title {
|
|
||||||
@include text-base(600);
|
|
||||||
margin-bottom: 2.4rem;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
.fab-tooltip { margin-left: 1.6rem; }
|
gap: 3.2rem;
|
||||||
}
|
|
||||||
}
|
.fab-alert { margin: 0; }
|
||||||
.save-btn {
|
|
||||||
align-self: flex-start;
|
section { @include layout-settings; }
|
||||||
|
.save-btn { align-self: flex-start; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,37 +1,21 @@
|
|||||||
.trainings-settings {
|
.trainings-settings {
|
||||||
max-width: 1600px;
|
max-width: 1200px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding-bottom: 6rem;
|
padding-bottom: 6rem;
|
||||||
@include grid-col(12);
|
display: flex;
|
||||||
gap: 3.2rem;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
& > header {
|
||||||
header {
|
|
||||||
@include header();
|
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
grid-column: 2 / -2;
|
@include header($sticky: true);
|
||||||
|
gap: 2.4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-content {
|
&-content {
|
||||||
grid-column: 2 / -2;
|
display: flex;
|
||||||
@include grid-col(2);
|
flex-direction: column;
|
||||||
gap: 2.4rem 3.2rem;
|
gap: 3.2rem;
|
||||||
|
|
||||||
.settings-section { grid-column: 1 / -1; }
|
.settings-section { @include layout-settings; }
|
||||||
@media (min-width: 1024px) {
|
.save-btn { align-self: flex-start; }
|
||||||
.settings-section { grid-column: span 1; }
|
|
||||||
}
|
|
||||||
.section-title { @include title-base; }
|
|
||||||
.save-btn {
|
|
||||||
grid-column: 1 / -1;
|
|
||||||
justify-self: flex-start;
|
|
||||||
background-color: var(--main);
|
|
||||||
color: var(--gray-soft-lightest);
|
|
||||||
border: none;
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--main);
|
|
||||||
color: var(--gray-soft-lightest);
|
|
||||||
opacity: 0.75;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,10 +8,6 @@
|
|||||||
header {
|
header {
|
||||||
@include header();
|
@include header();
|
||||||
padding-bottom: 1.6rem;
|
padding-bottom: 1.6rem;
|
||||||
.grpBtn {
|
|
||||||
display: flex;
|
|
||||||
& > *:not(:first-child) { margin-left: 2.4rem; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&-content {
|
&-content {
|
||||||
@ -113,15 +109,3 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.trainings-container {
|
|
||||||
max-width: 1600px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 2.4rem 0 6rem;
|
|
||||||
@include grid-col(12);
|
|
||||||
gap: 2.4rem 3.2rem;
|
|
||||||
.alert {
|
|
||||||
margin: 0;
|
|
||||||
grid-column: 2/-2;
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,3 +3,41 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat($col-count, minmax(0, 1fr));
|
grid-template-columns: repeat($col-count, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin layout-settings {
|
||||||
|
padding-bottom: 3.2rem;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 2.4rem 3.2rem;
|
||||||
|
border-bottom: 1px solid var(--gray-soft);
|
||||||
|
&:last-of-type {
|
||||||
|
padding-bottom: 0;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.6rem;
|
||||||
|
.title {
|
||||||
|
@include title-base;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.description {
|
||||||
|
color: var(--gray-hard-lightest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .content {
|
||||||
|
padding: 1.6rem;
|
||||||
|
background-color: var(--gray-soft-light);
|
||||||
|
border: 1px solid var(--gray-soft-dark);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
grid-template-areas: "header content";
|
||||||
|
grid-template-columns: 1fr 2fr;
|
||||||
|
& > header { grid-area: header; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
<section class="heading b-b">
|
<section class="heading b-b">
|
||||||
<div class="row no-gutter">
|
<div class="row no-gutter">
|
||||||
<div class="col-md-1 hidden-xs">
|
<div class="col-sm-2 col-md-1 hidden-xs">
|
||||||
<section class="heading-btn">
|
<section class="heading-btn">
|
||||||
<a ng-click="cancel()"><i class="fas fa-long-arrow-alt-left "></i></a>
|
<a ng-click="cancel()"><i class="fas fa-long-arrow-alt-left "></i></a>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-11 b-l">
|
<div class="col-sm-10 col-md-11 b-l">
|
||||||
<section class="heading-title">
|
<section class="heading-title">
|
||||||
<h1 translate>{{ 'app.admin.trainings_new.add_a_new_training' }}</h1>
|
<h1 translate>{{ 'app.admin.trainings_new.add_a_new_training' }}</h1>
|
||||||
</section>
|
</section>
|
||||||
@ -13,10 +13,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div class="trainings-container" >
|
|
||||||
<div class="alert alert-warning" role="alert">
|
|
||||||
{{ 'app.admin.trainings_new.beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero' | translate }}
|
|
||||||
{{ 'app.admin.trainings_new.dont_forget_to_change_them_before_creating_slots_for_this_training' | translate }}
|
|
||||||
</div>
|
|
||||||
<training-form action="'create'" on-error="onError" on-success="onSuccess"></training-form>
|
<training-form action="'create'" on-error="onError" on-success="onSuccess"></training-form>
|
||||||
</div>
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
<div>
|
|
||||||
|
|
||||||
<section class="heading b-b">
|
<section class="heading b-b">
|
||||||
<div class="row no-gutter">
|
<div class="row no-gutter">
|
||||||
<div class="col-xs-2 col-sm-2 col-md-1">
|
<div class="col-xs-2 col-sm-2 col-md-1">
|
||||||
@ -15,13 +13,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
<div class="col-md-9 b-r nopadding">
|
|
||||||
<div class="panel panel-default bg-light m-lg">
|
|
||||||
<div class="panel-body m-r">
|
|
||||||
<event-form action="'create'" on-success="onSuccess" on-error="onError"></event-form>
|
<event-form action="'create'" on-success="onSuccess" on-error="onError"></event-form>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
<div>
|
|
||||||
|
|
||||||
<section class="heading b-b">
|
<section class="heading b-b">
|
||||||
<div class="row no-gutter">
|
<div class="row no-gutter">
|
||||||
<div class="col-xs-2 col-sm-2 col-md-1">
|
<div class="col-xs-2 col-sm-2 col-md-1">
|
||||||
@ -12,23 +10,7 @@
|
|||||||
<h1>{{ machine.name }}</h1>
|
<h1>{{ machine.name }}</h1>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xs-12 col-sm-12 col-md-3 b-t hide-b-md">
|
|
||||||
<section class="heading-actions wrapper">
|
|
||||||
<div class="btn btn-lg btn-block btn-default rounded m-t-xs" ng-click="cancel()" translate>{{ 'app.shared.buttons.cancel' }}</div>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
<div class="row no-gutter">
|
|
||||||
<div class="col-sm-12 col-md-12 col-lg-9 b-r-lg nopadding">
|
|
||||||
<div class="panel panel-default bg-light m-lg">
|
|
||||||
<div class="panel-body m-r">
|
|
||||||
<machine-form action="'update'" machine="machine" on-error="onError" on-success="onSuccess"></machine-form>
|
<machine-form action="'update'" machine="machine" on-error="onError" on-success="onSuccess"></machine-form>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
@ -9,27 +9,8 @@
|
|||||||
<section class="heading-title">
|
<section class="heading-title">
|
||||||
<h1 translate>{{ 'app.admin.machines_new.declare_a_new_machine' }}</h1>
|
<h1 translate>{{ 'app.admin.machines_new.declare_a_new_machine' }}</h1>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
<div class="row no-gutter" >
|
|
||||||
|
|
||||||
<div class="col-md-9 b-r nopadding">
|
|
||||||
|
|
||||||
<div class="m-lg alert alert-warning" role="alert">
|
|
||||||
{{ 'app.admin.machines_new.watch_out_when_creating_a_new_machine_its_prices_are_initialized_at_0_for_all_subscriptions' | translate}}
|
|
||||||
{{ 'app.admin.machines_new.consider_changing_them_before_creating_any_reservation_slot' | translate }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel panel-default bg-light m-lg">
|
|
||||||
<div class="panel-body m-r">
|
|
||||||
<machine-form action="'create'" on-error="onError" on-success="onSuccess"></machine-form>
|
<machine-form action="'create'" on-error="onError" on-success="onSuccess"></machine-form>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
@ -9,23 +9,8 @@
|
|||||||
<section class="heading-title">
|
<section class="heading-title">
|
||||||
<h1 translate translate-values="{NAME: space.name}">{{ 'app.admin.space_edit.edit_the_space_NAME' }}</h1>
|
<h1 translate translate-values="{NAME: space.name}">{{ 'app.admin.space_edit.edit_the_space_NAME' }}</h1>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
<div class="row no-gutter" >
|
|
||||||
|
|
||||||
<div class="col-md-9 b-r nopadding">
|
|
||||||
<div class="panel panel-default bg-light m-lg">
|
|
||||||
<div class="panel-body m-r">
|
|
||||||
<space-form action="'update'" space="space" on-success="onSuccess" on-error="onError"></space-form>
|
<space-form action="'update'" space="space" on-success="onSuccess" on-error="onError"></space-form>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-3"/>
|
|
||||||
</div>
|
|
||||||
|
@ -9,30 +9,8 @@
|
|||||||
<section class="heading-title">
|
<section class="heading-title">
|
||||||
<h1 translate>{{ 'app.admin.space_new.add_a_new_space' }}</h1>
|
<h1 translate>{{ 'app.admin.space_new.add_a_new_space' }}</h1>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
<div class="row no-gutter" >
|
|
||||||
|
|
||||||
<div class="col-md-9 b-r nopadding">
|
|
||||||
|
|
||||||
<div class="m-lg alert alert-warning" role="alert">
|
|
||||||
{{ 'app.admin.space_new.watch_out_when_creating_a_new_space_its_prices_are_initialized_at_0_for_all_subscriptions' | translate}}
|
|
||||||
{{ 'app.admin.space_new.consider_changing_its_prices_before_creating_any_reservation_slot' | translate }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel panel-default bg-light m-lg">
|
|
||||||
<div class="panel-body m-r">
|
|
||||||
<space-form action="'create'" on-success="onSuccess" on-error="onError"></space-form>
|
<space-form action="'create'" on-success="onSuccess" on-error="onError"></space-form>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-3"/>
|
|
||||||
</div>
|
|
||||||
|
@ -29,25 +29,32 @@ en:
|
|||||||
unable_to_delete: "Unable to delete the machine category: "
|
unable_to_delete: "Unable to delete the machine category: "
|
||||||
confirm_machine_category: "Do you really want to remove this machine category?"
|
confirm_machine_category: "Do you really want to remove this machine category?"
|
||||||
machine_form:
|
machine_form:
|
||||||
|
ACTION_title: "{ACTION, select, create{New} other{Update the}} machine"
|
||||||
|
watch_out_when_creating_a_new_machine_its_prices_are_initialized_at_0_for_all_subscriptions: "Watch out! When creating a new machine, its prices are initialized at 0 for all subscriptions."
|
||||||
|
consider_changing_them_before_creating_any_reservation_slot: "Consider changing them before creating any reservation slot."
|
||||||
|
description: "Description"
|
||||||
name: "Name"
|
name: "Name"
|
||||||
illustration: "Visual"
|
illustration: "Visual"
|
||||||
description: "Description"
|
|
||||||
technical_specifications: "Technical specifications"
|
technical_specifications: "Technical specifications"
|
||||||
category: "Category"
|
category: "Category"
|
||||||
|
attachments: "Attachments"
|
||||||
attached_files_pdf: "Attached files (pdf)"
|
attached_files_pdf: "Attached files (pdf)"
|
||||||
add_an_attachment: "Add an attachment"
|
add_an_attachment: "Add an attachment"
|
||||||
|
settings: "Settings"
|
||||||
disable_machine: "Disable machine"
|
disable_machine: "Disable machine"
|
||||||
disabled_help: "When disabled, the machine won't be reservable and won't appear by default in the machines list."
|
disabled_help: "When disabled, the machine won't be reservable and won't appear by default in the machines list."
|
||||||
reservable: "Can this machine be reserved?"
|
reservable: "Can this machine be reserved?"
|
||||||
reservable_help: "When disabled, the machine will be shown in the default list of machines, but without the reservation button. If you already have created some availability slots for this machine, you may want to remove them: do it from the admin agenda."
|
reservable_help: "When disabled, the machine will be shown in the default list of machines, but without the reservation button. If you already have created some availability slots for this machine, you may want to remove them: do it from the admin agenda."
|
||||||
ACTION_machine: "{ACTION, select, create{Create} other{Update}} the machine"
|
save: "Save"
|
||||||
create_success: "The machine was created successfully"
|
create_success: "The machine was created successfully"
|
||||||
update_success: "The machine was updated successfully"
|
update_success: "The machine was updated successfully"
|
||||||
training_form:
|
training_form:
|
||||||
|
ACTION_title: "{ACTION, select, create{New} other{Update the}} training"
|
||||||
|
beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero: "Beware, when creating a training, its reservation prices are initialized at zero."
|
||||||
|
dont_forget_to_change_them_before_creating_slots_for_this_training: "Don't forget to change them before creating slots for this training."
|
||||||
description: "Description"
|
description: "Description"
|
||||||
name: "Name"
|
name: "Name"
|
||||||
illustration: "Illustration"
|
illustration: "Illustration"
|
||||||
description: "Description"
|
|
||||||
add_a_new_training: "Add a new training"
|
add_a_new_training: "Add a new training"
|
||||||
validate_your_training: "Validate your training"
|
validate_your_training: "Validate your training"
|
||||||
settings: "Settings"
|
settings: "Settings"
|
||||||
@ -69,27 +76,34 @@ en:
|
|||||||
cta_switch: "Display a button"
|
cta_switch: "Display a button"
|
||||||
cta_label: "Button label"
|
cta_label: "Button label"
|
||||||
cta_url: "url"
|
cta_url: "url"
|
||||||
ACTION_training: "{ACTION, select, create{Create} other{Update}} the training"
|
save: "Save"
|
||||||
create_success: "The training was created successfully"
|
create_success: "The training was created successfully"
|
||||||
update_success: "The training was updated successfully"
|
update_success: "The training was updated successfully"
|
||||||
space_form:
|
space_form:
|
||||||
|
ACTION_title: "{ACTION, select, create{New} other{Update the}} space"
|
||||||
|
watch_out_when_creating_a_new_space_its_prices_are_initialized_at_0_for_all_subscriptions: "Watch out! When creating a new space, its prices are initialized at 0 for all subscriptions."
|
||||||
|
consider_changing_its_prices_before_creating_any_reservation_slot: "Consider changing its prices before creating any reservation slot."
|
||||||
name: "Name"
|
name: "Name"
|
||||||
illustration: "Illustration"
|
illustration: "Illustration"
|
||||||
description: "Description"
|
description: "Description"
|
||||||
characteristics: "Characteristics"
|
characteristics: "Characteristics"
|
||||||
|
attachments: "Attachments"
|
||||||
attached_files_pdf: "Attached files (pdf)"
|
attached_files_pdf: "Attached files (pdf)"
|
||||||
add_an_attachment: "Add an attachment"
|
add_an_attachment: "Add an attachment"
|
||||||
|
settings: "Settings"
|
||||||
default_seats: "Default number of seats"
|
default_seats: "Default number of seats"
|
||||||
disable_space: "Disable the space"
|
disable_space: "Disable the space"
|
||||||
disabled_help: "When disabled, the space won't be reservable and won't appear by default in the spaces list."
|
disabled_help: "When disabled, the space won't be reservable and won't appear by default in the spaces list."
|
||||||
ACTION_space: "{ACTION, select, create{Create} other{Update}} the space"
|
save: "Save"
|
||||||
create_success: "The space was created successfully"
|
create_success: "The space was created successfully"
|
||||||
update_success: "The space was updated successfully"
|
update_success: "The space was updated successfully"
|
||||||
event_form:
|
event_form:
|
||||||
|
ACTION_title: "{ACTION, select, create{New} other{Update the}} event"
|
||||||
title: "Title"
|
title: "Title"
|
||||||
matching_visual: "Matching visual"
|
matching_visual: "Matching visual"
|
||||||
description: "Description"
|
description: "Description"
|
||||||
attachments: "Attachments"
|
attachments: "Attachments"
|
||||||
|
attached_files_pdf: "Attached files (pdf)"
|
||||||
add_a_new_file: "Add a new file"
|
add_a_new_file: "Add a new file"
|
||||||
event_category: "Event category"
|
event_category: "Event category"
|
||||||
dates_and_opening_hours: "Dates and opening hours"
|
dates_and_opening_hours: "Dates and opening hours"
|
||||||
@ -111,7 +125,7 @@ en:
|
|||||||
event_themes: "Event themes"
|
event_themes: "Event themes"
|
||||||
age_range: "Age range"
|
age_range: "Age range"
|
||||||
add_price: "Add a price"
|
add_price: "Add a price"
|
||||||
ACTION_event: "{ACTION, select, create{Create} other{Update}} the event"
|
save: "Save"
|
||||||
create_success: "The event was created successfully"
|
create_success: "The event was created successfully"
|
||||||
events_updated: "{COUNT, plural, =1{One event was} other{{COUNT} Events were}} successfully updated"
|
events_updated: "{COUNT, plural, =1{One event was} other{{COUNT} Events were}} successfully updated"
|
||||||
events_not_updated: "{TOTAL, plural, =1{The event was} other{On {TOTAL} events {COUNT, plural, =1{one was} other{{COUNT} were}}}} not updated."
|
events_not_updated: "{TOTAL, plural, =1{The event was} other{On {TOTAL} events {COUNT, plural, =1{one was} other{{COUNT} were}}}} not updated."
|
||||||
@ -213,8 +227,6 @@ en:
|
|||||||
#add a new machine
|
#add a new machine
|
||||||
machines_new:
|
machines_new:
|
||||||
declare_a_new_machine: "Declare a new machine"
|
declare_a_new_machine: "Declare a new machine"
|
||||||
watch_out_when_creating_a_new_machine_its_prices_are_initialized_at_0_for_all_subscriptions: "Watch out! When creating a new machine, its prices are initialized at 0 for all subscriptions."
|
|
||||||
consider_changing_them_before_creating_any_reservation_slot: "Consider changing them before creating any reservation slot."
|
|
||||||
#machine edition
|
#machine edition
|
||||||
machines_edit:
|
machines_edit:
|
||||||
machine_edit: "Edit a machine"
|
machine_edit: "Edit a machine"
|
||||||
@ -440,8 +452,6 @@ en:
|
|||||||
#create a new training
|
#create a new training
|
||||||
trainings_new:
|
trainings_new:
|
||||||
add_a_new_training: "Add a new training"
|
add_a_new_training: "Add a new training"
|
||||||
beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero: "Beware, when creating a training, its reservation prices are initialized at zero."
|
|
||||||
dont_forget_to_change_them_before_creating_slots_for_this_training: "Don't forget to change them before creating slots for this training."
|
|
||||||
trainings_settings:
|
trainings_settings:
|
||||||
title: "Settings"
|
title: "Settings"
|
||||||
automatic_cancellation: "Trainings automatic cancellation"
|
automatic_cancellation: "Trainings automatic cancellation"
|
||||||
@ -1873,9 +1883,6 @@ en:
|
|||||||
#create a new space
|
#create a new space
|
||||||
space_new:
|
space_new:
|
||||||
add_a_new_space: "Add a new space"
|
add_a_new_space: "Add a new space"
|
||||||
watch_out_when_creating_a_new_space_its_prices_are_initialized_at_0_for_all_subscriptions: "Watch out! When creating a new space, its prices are initialized at 0 for all subscriptions."
|
|
||||||
consider_changing_its_prices_before_creating_any_reservation_slot: "Consider changing its prices before creating any reservation slot."
|
|
||||||
add_this_space: "Add this space"
|
|
||||||
#modify an exiting space
|
#modify an exiting space
|
||||||
space_edit:
|
space_edit:
|
||||||
edit_the_space_NAME: "Edit the space: {NAME}"
|
edit_the_space_NAME: "Edit the space: {NAME}"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user