1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-18 07:52:23 +01:00

(ui) Uniform layout for settings and form

This commit is contained in:
vincent 2023-01-16 12:28:53 +01:00 committed by Sylvain
parent a0508e689e
commit 98e10dc774
26 changed files with 795 additions and 675 deletions

View File

@ -23,17 +23,19 @@ export const AdvancedAccountingForm = <TFieldValues extends FieldValues>({ regis
SettingAPI.get('advanced_accounting').then(res => setIsEnabled(res.value === 'true')).catch(onError);
}, []);
return (
<div className="advanced-accounting-form">
{isEnabled && <div>
<p className='title'>{t('app.admin.advanced_accounting_form.title')}</p>
return (<>
{isEnabled && <>
<header>
<p className="title">{t('app.admin.advanced_accounting_form.title')}</p>
</header>
<div className="content">
<FormInput register={register}
id="advanced_accounting_attributes.code"
label={t('app.admin.advanced_accounting_form.code')} />
<FormInput register={register}
id="advanced_accounting_attributes.analytical_section"
label={t('app.admin.advanced_accounting_form.analytical_section')} />
</div>}
</div>
);
</>}
</>);
};

View File

@ -23,6 +23,7 @@ import AgeRangeAPI from '../../api/age-range';
import { Plus, Trash } from 'phosphor-react';
import FormatLib from '../../lib/format';
import EventPriceCategoryAPI from '../../api/event-price-category';
import SettingAPI from '../../api/setting';
import { UpdateRecurrentModal } from './update-recurrent-modal';
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 [isOpenRecurrentModal, setIsOpenRecurrentModal] = useState<boolean>(false);
const [updatingEvent, setUpdatingEvent] = useState<Event>(null);
const [isActiveAccounting, setIsActiveAccounting] = useState<boolean>(false);
useEffect(() => {
EventCategoryAPI.index()
@ -66,6 +68,7 @@ export const EventForm: React.FC<EventFormProps> = ({ action, event, onError, on
EventPriceCategoryAPI.index()
.then(data => setPriceCategoriesOptions(data.map(c => decorationToOption(c))))
.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 (
<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}
id="title"
formState={formState}
@ -190,9 +205,15 @@ export const EventForm: React.FC<EventFormProps> = ({ action, event, onError, on
formState={formState}
options={ageRangeOptions}
label={t('app.admin.event_form.age_range')} />}
<div className="dates-times">
<h4>{t('app.admin.event_form.dates_and_opening_hours')}</h4>
<div className="dates">
</div>
</section>
<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"
type="date"
register={register}
@ -212,7 +233,7 @@ export const EventForm: React.FC<EventFormProps> = ({ action, event, onError, on
formState={formState}
tooltip={t('app.admin.event_form.all_day_help')}
onChange={setIsAllDay} />
{!isAllDay && <div className="times">
{!isAllDay && <div className="grp">
<FormInput id="start_time"
type="time"
register={register}
@ -226,7 +247,7 @@ export const EventForm: React.FC<EventFormProps> = ({ action, event, onError, on
label={t('app.admin.event_form.end_time')}
rules={{ required: !isAllDay }} />
</div>}
{action === 'create' && <div className="recurring">
{action === 'create' && <div className="grp">
<FormSelect options={buildRecurrenceOptions()}
control={control}
formState={formState}
@ -243,8 +264,13 @@ export const EventForm: React.FC<EventFormProps> = ({ action, event, onError, on
rules={{ required: !['none', undefined].includes(output.recurrence) }} />
</div>}
</div>
<div className="seats-prices">
<h4>{t('app.admin.event_form.prices_and_availabilities')}</h4>
</section>
<section>
<header>
<p className="title">{t('app.admin.event_form.prices_and_availabilities')}</p>
</header>
<div className="content">
<FormInput register={register}
id="nb_total_places"
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')}
tooltip={t('app.admin.event_form.0_equal_free')}
addOn={FormatLib.currencySymbol()} />
{/* TODO: need ui */}
{priceCategoriesOptions && <div className="additional-prices">
{fields.map((price, index) => (
<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>
</div>}
</div>
<div className="attachments">
<div className='form-item-header event-files-header'>
<h4>{t('app.admin.event_form.attachments')}</h4>
</section>
<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>
<FormMultiFileUpload setValue={setValue}
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"
className="event-files" />
</div>
</section>
{isActiveAccounting &&
<section>
<AdvancedAccountingForm register={register} onError={onError} />
<FabButton type="submit" className="is-info submit-btn">
{t('app.admin.event_form.ACTION_event', { ACTION: action })}
</FabButton>
</section>
}
<UpdateRecurrentModal isOpen={isOpenRecurrentModal}
toggleModal={toggleRecurrentModal}
event={updatingEvent}
onConfirmed={handleUpdateRecurrentConfirmed}
datesChanged={datesHaveChanged()} />
</form>
</div>
);
};

View File

@ -18,7 +18,9 @@ import { AdvancedAccountingForm } from '../accounting/advanced-accounting-form';
import { FormSelect } from '../form/form-select';
import { SelectOption } from '../../models/select';
import MachineCategoryAPI from '../../api/machine-category';
import SettingAPI from '../../api/setting';
import { MachineCategory } from '../../models/machine-category';
import { FabAlert } from '../base/fab-alert';
declare const Application: IApplication;
@ -38,12 +40,15 @@ export const MachineForm: React.FC<MachineFormProps> = ({ action, machine, onErr
const { t } = useTranslation('admin');
const [machineCategories, setMachineCategories] = useState<Array<MachineCategory>>([]);
const [isActiveAccounting, setIsActiveAccounting] = useState<boolean>(false);
// retrieve the full list of machine categories on component mount
// check advanced accounting activation
useEffect(() => {
MachineCategoryAPI.index()
.then(data => setMachineCategories(data))
.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 (
<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"
formState={formState}
rules={{ required: true }}
@ -87,18 +109,26 @@ export const MachineForm: React.FC<MachineFormProps> = ({ action, machine, onErr
rules={{ required: true }}
label={t('app.admin.machine_form.description')}
limit={null}
heading bulletList blockquote link video image />
heading bulletList blockquote link image video />
<FormRichText control={control}
id="spec"
rules={{ required: true }}
label={t('app.admin.machine_form.technical_specifications')}
limit={null}
heading bulletList blockquote link video image />
heading bulletList link />
<FormSelect options={buildOptions()}
control={control}
id="machine_category_id"
formState={formState}
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'>
<p>{t('app.admin.machine_form.attached_files_pdf')}</p>
</div>
@ -109,7 +139,14 @@ export const MachineForm: React.FC<MachineFormProps> = ({ action, machine, onErr
register={register}
id="machine_files_attributes"
className="machine-files" />
</div>
</section>
<section>
<header>
<p className="title">{t('app.admin.machine_form.settings')}</p>
</header>
<div className="content">
<FormSwitch control={control}
id="reservable"
label={t('app.admin.machine_form.reservable')}
@ -119,11 +156,16 @@ export const MachineForm: React.FC<MachineFormProps> = ({ action, machine, onErr
id="disabled"
label={t('app.admin.machine_form.disable_machine')}
tooltip={t('app.admin.machine_form.disabled_help')} />
</div>
</section>
{isActiveAccounting &&
<section>
<AdvancedAccountingForm register={register} onError={onError} />
<FabButton type="submit" className="is-info submit-btn">
{t('app.admin.machine_form.ACTION_machine', { ACTION: action })}
</FabButton>
</section>
}
</form>
</div>
);
};

View File

@ -1,4 +1,5 @@
import * as React from 'react';
import { useEffect, useState } from 'react';
import { SubmitHandler, useForm, useWatch } from 'react-hook-form';
import SpaceAPI from '../../api/space';
import { useTranslation } from 'react-i18next';
@ -14,6 +15,8 @@ import { FormMultiFileUpload } from '../form/form-multi-file-upload';
import { FabButton } from '../base/fab-button';
import { Space } from '../../models/space';
import { AdvancedAccountingForm } from '../accounting/advanced-accounting-form';
import SettingAPI from '../../api/setting';
import { FabAlert } from '../base/fab-alert';
declare const Application: IApplication;
@ -32,6 +35,12 @@ export const SpaceForm: React.FC<SpaceFormProps> = ({ action, space, onError, on
const output = useWatch<Space>({ control });
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
*/
@ -45,7 +54,24 @@ export const SpaceForm: React.FC<SpaceFormProps> = ({ action, space, onError, on
};
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"
formState={formState}
rules={{ required: true }}
@ -75,8 +101,15 @@ export const SpaceForm: React.FC<SpaceFormProps> = ({ action, space, onError, on
id="characteristics"
label={t('app.admin.space_form.characteristics')}
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'>
<p>{t('app.admin.space_form.attached_files_pdf')}</p>
</div>
@ -87,16 +120,28 @@ export const SpaceForm: React.FC<SpaceFormProps> = ({ action, space, onError, on
register={register}
id="space_files_attributes"
className="space-files" />
</div>
</section>
<section>
<header>
<p className="title">{t('app.admin.space_form.settings')}</p>
</header>
<div className="content">
<FormSwitch control={control}
id="disabled"
label={t('app.admin.space_form.disable_space')}
tooltip={t('app.admin.space_form.disabled_help')} />
</div>
</section>
{isActiveAccounting &&
<section>
<AdvancedAccountingForm register={register} onError={onError} />
<FabButton type="submit" className="is-info submit-btn">
{t('app.admin.space_form.ACTION_space', { ACTION: action })}
</FabButton>
</section>
}
</form>
</div>
);
};

View File

@ -20,7 +20,7 @@ import { SelectOption } from '../../models/select';
import SettingAPI from '../../api/setting';
import { Setting } from '../../models/setting';
import { AdvancedAccountingForm } from '../accounting/advanced-accounting-form';
import { FabPanel } from '../base/fab-panel';
import { FabAlert } from '../base/fab-alert';
declare const Application: IApplication;
@ -116,9 +116,24 @@ export const TrainingForm: React.FC<TrainingFormProps> = ({ action, training, on
const urlRegex = /^(https?:\/\/)([^.]+)\.(.{2,30})(\/.*)*\/?$/;
return (
<form className="training-form" onSubmit={handleSubmit(onSubmit)}>
<FabPanel>
<div className="training-form">
<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>
</header>
<div className="content">
<FormInput register={register} id="name"
formState={formState}
rules={{ required: true }}
@ -138,17 +153,22 @@ export const TrainingForm: React.FC<TrainingFormProps> = ({ action, training, on
label={t('app.admin.training_form.description')}
limit={null}
heading bulletList blockquote link />
</FabPanel>
</div>
</section>
<FabPanel>
<section>
<header>
<p className="title">{t('app.admin.training_form.settings')}</p>
</header>
<div className="content">
{machineModule?.value === 'true' &&
<FormMultiSelect control={control}
id="machine_ids"
formState={formState}
label={t('app.admin.training_form.associated_machines')}
tooltip={t('app.admin.training_form.associated_machines_help')}
loadOptions={loadMachines} />}
loadOptions={loadMachines} />
}
<FormInput register={register}
type="number"
id="nb_total_places"
@ -164,17 +184,15 @@ export const TrainingForm: React.FC<TrainingFormProps> = ({ action, training, on
id="disabled"
label={t('app.admin.training_form.disable_training')}
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>
</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}
onChange={toggleCancellationSwitch} formState={formState}
defaultValue={isActiveCancellation}
@ -197,17 +215,17 @@ export const TrainingForm: React.FC<TrainingFormProps> = ({ action, training, on
nullable
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>
</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}
onChange={toggleTextBlockSwitch} formState={formState}
defaultValue={isActiveTextBlock}
@ -238,18 +256,16 @@ export const TrainingForm: React.FC<TrainingFormProps> = ({ action, training, on
label={t('app.admin.training_form.cta_url')} />
</>}
</>}
</FabPanel>
</div>
</section>
{isActiveAccounting &&
<FabPanel>
<section>
<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>
</div>
);
};

View File

@ -77,14 +77,16 @@ export const TrainingsSettings: React.FC<TrainingsSettingsProps> = () => {
<div className="trainings-settings">
<header>
<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>
<form onSubmit={handleSubmit(onSubmit)} className="trainings-settings-content">
<form className="trainings-settings-content">
<div className="settings-section">
<p className="section-title">{t('app.admin.trainings_settings.automatic_cancellation')}</p>
<FabAlert level="warning">
{t('app.admin.trainings_settings.automatic_cancellation_info')}
</FabAlert>
<header>
<p className="title">{t('app.admin.trainings_settings.automatic_cancellation')}</p>
<p className="description">{t('app.admin.trainings_settings.automatic_cancellation_info')}</p>
</header>
<div className="content">
<FormSwitch id="active_auto_cancellation" control={control}
onChange={toggleAutoCancellation} formState={formState}
defaultValue={isActiveAutoCancellation}
@ -107,13 +109,15 @@ export const TrainingsSettings: React.FC<TrainingsSettingsProps> = () => {
label={t('app.admin.trainings_settings.automatic_cancellation_deadline')} />
</>}
</div>
</div>
<div className="settings-section">
<p className="section-title">{t('app.admin.trainings_settings.automatic_cancellation')}</p>
<FabAlert level="warning">
{t('app.admin.trainings_settings.generic_text_block_info')}
</FabAlert>
<header>
<p className="title">{t('app.admin.trainings_settings.generic_text_block')}</p>
<p className="description">{t('app.admin.trainings_settings.generic_text_block_info')}</p>
</header>
<div className="content">
<FormSwitch id="active_text_block" control={control}
onChange={toggleTextBlockSwitch} formState={formState}
defaultValue={isActiveTextBlock}
@ -145,8 +149,7 @@ export const TrainingsSettings: React.FC<TrainingsSettingsProps> = () => {
</>}
</>}
</div>
<FabButton type='submit' className='save-btn'>{t('app.admin.trainings_settings.save')}</FabButton>
</div>
</form>
</div>
);

View File

@ -1,6 +1,6 @@
.fab-panel {
background-color: #fff;
border: 1px solid #ddd;
background-color: var(--gray-soft-lightest);
border: 1px solid var(--gray-soft-dark);
border-radius: var(--border-radius);
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
margin: 30px 30px 30px 0;
@ -11,9 +11,9 @@
overflow: hidden;
.panel-header {
background-color: #f4f3f3;
background-color: var(--gray-soft-light);
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-left-radius: var(--border-radius);
@ -28,7 +28,7 @@
&.no-header {
padding: 15px;
background-color: #f4f3f3;
background-color: var(--gray-soft-light);
border-radius: var(--border-radius);
}
}

View File

@ -169,14 +169,15 @@
position: relative;
height: 0;
width: 100%;
max-width: 600px;
margin: 1rem 0;
padding-bottom: calc(100% / 16 * 9);
overflow: hidden;
//.container { max-width: 600px; }
iframe {
position: absolute;
max-width: 100%;
width: 100%;
height: 100%;
inset: 0;
}
}

View File

@ -1,12 +1,34 @@
.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 {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 2.4rem;
.add-price {
max-width: fit-content;
margin-bottom: 1.6rem;
}
.price-item {
width: 100%;
@ -22,12 +44,13 @@
}
}
}
.dates, .times, .price-item, .recurring {
.grp {
display: flex;
flex-direction: row;
flex-direction: column;
@media (min-width: 640px) {flex-direction: row; }
.form-item:first-child {
margin-right: 32px;
margin-right: 2.4rem;
}
}
.submit-btn {

View File

@ -1,6 +1,7 @@
.form-switch {
.form-item-header {
margin-bottom: 0;
cursor: pointer;
.fab-tooltip .content {
max-width: min(75vw, 30ch);

View File

@ -1,11 +1,30 @@
.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 {
cursor: default;
}
.machine-files {
margin-bottom: 1.4rem;
}
.submit-btn {
float: right;
}
}

View File

@ -1,11 +1,30 @@
.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 {
cursor: default;
}
.space-files {
margin-bottom: 1.4rem;
}
.submit-btn {
float: right;
}
}

View File

@ -8,10 +8,6 @@
header {
@include header();
grid-column: 2 / -2;
.grpBtn {
display: flex;
& > *:not(:first-child) { margin-left: 2.4rem; }
}
}
.fab-alert {
grid-column: 2 / -2;

View File

@ -9,10 +9,6 @@
@include header();
padding-bottom: 0;
grid-column: 1 / -1;
.grpBtn {
display: flex;
& > *:not(:first-child) { margin-left: 2.4rem; }
}
}
}

View File

@ -23,8 +23,6 @@
padding: 0 0 2.4rem 0;
.grpBtn {
display: flex;
align-items: center;
button { display: none; }
.filters-toggle {
cursor: pointer;

View File

@ -1,24 +1,23 @@
// hide Angular tag for the grid
training-form { display: contents; }
.training-form {
grid-column: 2/-2;
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;
}
.fab-panel {
width: 100%;
margin: 0;
.title {
@include text-base(600);
margin-bottom: 2.4rem;
&-content {
display: flex;
align-items: center;
.fab-tooltip { margin-left: 1.6rem; }
}
}
.save-btn {
align-self: flex-start;
flex-direction: column;
gap: 3.2rem;
.fab-alert { margin: 0; }
section { @include layout-settings; }
.save-btn { align-self: flex-start; }
}
}

View File

@ -1,37 +1,21 @@
.trainings-settings {
max-width: 1600px;
max-width: 1200px;
margin: 0 auto;
padding-bottom: 6rem;
@include grid-col(12);
gap: 3.2rem;
align-items: flex-start;
header {
@include header();
display: flex;
flex-direction: column;
& > header {
padding-bottom: 0;
grid-column: 2 / -2;
@include header($sticky: true);
gap: 2.4rem;
}
&-content {
grid-column: 2 / -2;
@include grid-col(2);
gap: 2.4rem 3.2rem;
display: flex;
flex-direction: column;
gap: 3.2rem;
.settings-section { grid-column: 1 / -1; }
@media (min-width: 1024px) {
.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;
}
}
.settings-section { @include layout-settings; }
.save-btn { align-self: flex-start; }
}
}

View File

@ -8,10 +8,6 @@
header {
@include header();
padding-bottom: 1.6rem;
.grpBtn {
display: flex;
& > *:not(:first-child) { margin-left: 2.4rem; }
}
}
&-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;
}
}

View File

@ -3,3 +3,41 @@
display: grid;
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; }
}
}

View File

@ -1,11 +1,11 @@
<section class="heading b-b">
<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">
<a ng-click="cancel()"><i class="fas fa-long-arrow-alt-left "></i></a>
</section>
</div>
<div class="col-md-11 b-l">
<div class="col-sm-10 col-md-11 b-l">
<section class="heading-title">
<h1 translate>{{ 'app.admin.trainings_new.add_a_new_training' }}</h1>
</section>
@ -13,10 +13,4 @@
</div>
</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>
</div>

View File

@ -1,5 +1,3 @@
<div>
<section class="heading b-b">
<div class="row no-gutter">
<div class="col-xs-2 col-sm-2 col-md-1">
@ -15,13 +13,4 @@
</div>
</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>
</div>
</div>
</div>
</div>

View File

@ -1,5 +1,3 @@
<div>
<section class="heading b-b">
<div class="row no-gutter">
<div class="col-xs-2 col-sm-2 col-md-1">
@ -12,23 +10,7 @@
<h1>{{ machine.name }}</h1>
</section>
</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>
</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>
</div>
</div>
</div>
</div>
</div>

View File

@ -9,27 +9,8 @@
<section class="heading-title">
<h1 translate>{{ 'app.admin.machines_new.declare_a_new_machine' }}</h1>
</section>
</div>
</div>
</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>
</div>
</div>
</div>
</div>

View File

@ -9,23 +9,8 @@
<section class="heading-title">
<h1 translate translate-values="{NAME: space.name}">{{ 'app.admin.space_edit.edit_the_space_NAME' }}</h1>
</section>
</div>
</div>
</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>
</div>
</div>
</div>
<div class="col-md-3"/>
</div>

View File

@ -9,30 +9,8 @@
<section class="heading-title">
<h1 translate>{{ 'app.admin.space_new.add_a_new_space' }}</h1>
</section>
</div>
</div>
</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>
</div>
</div>
</div>
<div class="col-md-3"/>
</div>

View File

@ -29,25 +29,32 @@ en:
unable_to_delete: "Unable to delete the machine category: "
confirm_machine_category: "Do you really want to remove this machine category?"
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"
illustration: "Visual"
description: "Description"
technical_specifications: "Technical specifications"
category: "Category"
attachments: "Attachments"
attached_files_pdf: "Attached files (pdf)"
add_an_attachment: "Add an attachment"
settings: "Settings"
disable_machine: "Disable machine"
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_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"
update_success: "The machine was updated successfully"
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"
name: "Name"
illustration: "Illustration"
description: "Description"
add_a_new_training: "Add a new training"
validate_your_training: "Validate your training"
settings: "Settings"
@ -69,27 +76,34 @@ en:
cta_switch: "Display a button"
cta_label: "Button label"
cta_url: "url"
ACTION_training: "{ACTION, select, create{Create} other{Update}} the training"
save: "Save"
create_success: "The training was created successfully"
update_success: "The training was updated successfully"
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"
illustration: "Illustration"
description: "Description"
characteristics: "Characteristics"
attachments: "Attachments"
attached_files_pdf: "Attached files (pdf)"
add_an_attachment: "Add an attachment"
settings: "Settings"
default_seats: "Default number of seats"
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."
ACTION_space: "{ACTION, select, create{Create} other{Update}} the space"
save: "Save"
create_success: "The space was created successfully"
update_success: "The space was updated successfully"
event_form:
ACTION_title: "{ACTION, select, create{New} other{Update the}} event"
title: "Title"
matching_visual: "Matching visual"
description: "Description"
attachments: "Attachments"
attached_files_pdf: "Attached files (pdf)"
add_a_new_file: "Add a new file"
event_category: "Event category"
dates_and_opening_hours: "Dates and opening hours"
@ -111,7 +125,7 @@ en:
event_themes: "Event themes"
age_range: "Age range"
add_price: "Add a price"
ACTION_event: "{ACTION, select, create{Create} other{Update}} the event"
save: "Save"
create_success: "The event was created successfully"
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."
@ -213,8 +227,6 @@ en:
#add a new machine
machines_new:
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
machines_edit:
machine_edit: "Edit a machine"
@ -440,8 +452,6 @@ en:
#create a new training
trainings_new:
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:
title: "Settings"
automatic_cancellation: "Trainings automatic cancellation"
@ -1873,9 +1883,6 @@ en:
#create a new space
space_new:
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
space_edit:
edit_the_space_NAME: "Edit the space: {NAME}"