mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-12-01 12:24:28 +01:00
Merge branch 'spaces_multiprices' into dev
This commit is contained in:
commit
1b2be4a19e
@ -36,7 +36,7 @@ class API::PricesController < API::ApiController
|
|||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
authorize @price
|
authorize @price
|
||||||
@price.destroy
|
@price.safe_destroy
|
||||||
head :no_content
|
head :no_content
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -12,4 +12,5 @@ export default class SpaceAPI {
|
|||||||
const res: AxiosResponse<Space> = await apiClient.get(`/api/spaces/${id}`);
|
const res: AxiosResponse<Space> = await apiClient.get(`/api/spaces/${id}`);
|
||||||
return res?.data;
|
return res?.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -64,8 +64,8 @@ export const ConfigurePacksButton: React.FC<ConfigurePacksButtonProps> = ({ pack
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="configure-group">
|
<div className="configure-packs-button">
|
||||||
<button className="configure-group-button" onClick={toggleShowList}>
|
<button className="packs-button" onClick={toggleShowList}>
|
||||||
<i className="fas fa-box" />
|
<i className="fas fa-box" />
|
||||||
</button>
|
</button>
|
||||||
{showList && <FabPopover title={t('app.admin.configure_packs_button.packs')} headerButton={renderAddButton()} className="fab-popover__right">
|
{showList && <FabPopover title={t('app.admin.configure_packs_button.packs')} headerButton={renderAddButton()} className="fab-popover__right">
|
||||||
@ -73,7 +73,7 @@ export const ConfigurePacksButton: React.FC<ConfigurePacksButtonProps> = ({ pack
|
|||||||
{packs?.map(p =>
|
{packs?.map(p =>
|
||||||
<li key={p.id} className={p.disabled ? 'disabled' : ''}>
|
<li key={p.id} className={p.disabled ? 'disabled' : ''}>
|
||||||
{formatDuration(p.minutes)} - {FormatLib.price(p.amount)}
|
{formatDuration(p.minutes)} - {FormatLib.price(p.amount)}
|
||||||
<span className="group-actions">
|
<span className="pack-actions">
|
||||||
<EditPack onSuccess={handleSuccess} onError={onError} pack={p} />
|
<EditPack onSuccess={handleSuccess} onError={onError} pack={p} />
|
||||||
<DeletePack onSuccess={handleSuccess} onError={onError} pack={p} />
|
<DeletePack onSuccess={handleSuccess} onError={onError} pack={p} />
|
||||||
</span>
|
</span>
|
||||||
|
@ -42,8 +42,8 @@ const DeletePackComponent: React.FC<DeletePackProps> = ({ onSuccess, onError, pa
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="delete-group">
|
<div className="delete-pack">
|
||||||
<FabButton type='button' className="delete-group-button" icon={<i className="fa fa-trash" />} onClick={toggleDeletionModal} />
|
<FabButton type='button' className="remove-pack-button" icon={<i className="fa fa-trash" />} onClick={toggleDeletionModal} />
|
||||||
<FabModal title={t('app.admin.delete_pack.delete_pack')}
|
<FabModal title={t('app.admin.delete_pack.delete_pack')}
|
||||||
isOpen={deletionModal}
|
isOpen={deletionModal}
|
||||||
toggleModal={toggleDeletionModal}
|
toggleModal={toggleDeletionModal}
|
||||||
|
@ -54,15 +54,16 @@ export const EditPack: React.FC<EditPackProps> = ({ pack, onSuccess, onError })
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="edit-group">
|
<div className="edit-pack">
|
||||||
<FabButton type='button' icon={<i className="fas fa-edit" />} onClick={handleRequestEdit} />
|
<FabButton type='button' className="edit-pack-button" icon={<i className="fas fa-edit" />} onClick={handleRequestEdit} />
|
||||||
<FabModal isOpen={isOpen}
|
<FabModal isOpen={isOpen}
|
||||||
toggleModal={toggleModal}
|
toggleModal={toggleModal}
|
||||||
title={t('app.admin.edit_pack.edit_pack')}
|
title={t('app.admin.edit_pack.edit_pack')}
|
||||||
|
className="edit-pack-modal"
|
||||||
closeButton
|
closeButton
|
||||||
confirmButton={t('app.admin.edit_pack.confirm_changes')}
|
confirmButton={t('app.admin.edit_pack.confirm_changes')}
|
||||||
onConfirmSendFormId="edit-group">
|
onConfirmSendFormId="edit-pack">
|
||||||
{packData && <PackForm formId="edit-group" onSubmit={handleUpdate} pack={packData} />}
|
{packData && <PackForm formId="edit-pack" onSubmit={handleUpdate} pack={packData} />}
|
||||||
</FabModal>
|
</FabModal>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -107,7 +107,7 @@ const MachinesPricing: React.FC<MachinesPricingProps> = ({ onError, onSuccess })
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="pricing-list">
|
<div className="machines-pricing">
|
||||||
<FabAlert level="warning">
|
<FabAlert level="warning">
|
||||||
<p><HtmlTranslate trKey="app.admin.machines_pricing.prices_match_machine_hours_rates_html"/></p>
|
<p><HtmlTranslate trKey="app.admin.machines_pricing.prices_match_machine_hours_rates_html"/></p>
|
||||||
<p><HtmlTranslate trKey="app.admin.machines_pricing.prices_calculated_on_hourly_rate_html" options={{ DURATION: `${EXEMPLE_DURATION}`, RATE: examplePrice('hourly_rate'), PRICE: examplePrice('final_price') }} /></p>
|
<p><HtmlTranslate trKey="app.admin.machines_pricing.prices_calculated_on_hourly_rate_html" options={{ DURATION: `${EXEMPLE_DURATION}`, RATE: examplePrice('hourly_rate'), PRICE: examplePrice('final_price') }} /></p>
|
||||||
|
@ -103,7 +103,7 @@ export const PackForm: React.FC<PackFormProps> = ({ formId, onSubmit, pack }) =>
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form id={formId} onSubmit={handleSubmit} className="group-form">
|
<form id={formId} onSubmit={handleSubmit} className="pack-form">
|
||||||
<label htmlFor="hours">{t('app.admin.pack_form.hours')} *</label>
|
<label htmlFor="hours">{t('app.admin.pack_form.hours')} *</label>
|
||||||
<FabInput id="hours"
|
<FabInput id="hours"
|
||||||
type="number"
|
type="number"
|
||||||
|
@ -28,7 +28,14 @@ export const ConfigureExtendedPriceButton: React.FC<ConfigureExtendedPriceButton
|
|||||||
const [showList, setShowList] = useState<boolean>(false);
|
const [showList, setShowList] = useState<boolean>(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open/closes the popover listing the existing extended prices
|
* Return the number of minutes, user-friendly formatted
|
||||||
|
*/
|
||||||
|
const formatDuration = (minutes: number): string => {
|
||||||
|
return t('app.admin.configure_extended_prices_button.extended_price_DURATION', { DURATION: minutes });
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open/closes the popover listing the existing packs
|
||||||
*/
|
*/
|
||||||
const toggleShowList = (): void => {
|
const toggleShowList = (): void => {
|
||||||
setShowList(!showList);
|
setShowList(!showList);
|
||||||
@ -57,22 +64,22 @@ export const ConfigureExtendedPriceButton: React.FC<ConfigureExtendedPriceButton
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="configure-group">
|
<div className="configure-extended-prices-button">
|
||||||
<button className="configure-group-button" onClick={toggleShowList}>
|
<button className="extended-prices-button" onClick={toggleShowList}>
|
||||||
<i className="fas fa-stopwatch" />
|
<i className="fas fa-stopwatch" />
|
||||||
</button>
|
</button>
|
||||||
{showList && <FabPopover title={t('app.admin.configure_extendedPrices_button.extendedPrices')} headerButton={renderAddButton()} className="fab-popover__right">
|
{showList && <FabPopover title={t('app.admin.configure_extended_prices_button.extended_prices')} headerButton={renderAddButton()} className="fab-popover__right">
|
||||||
<ul>
|
<ul>
|
||||||
{extendedPrices?.map(extendedPrice =>
|
{extendedPrices?.map(extendedPrice =>
|
||||||
<li key={extendedPrice.id}>
|
<li key={extendedPrice.id}>
|
||||||
{extendedPrice.duration} {t('app.admin.calendar.minutes')} - {FormatLib.price(extendedPrice.amount)}
|
{formatDuration(extendedPrice.duration)} - {FormatLib.price(extendedPrice.amount)}
|
||||||
<span className="group-actions">
|
<span className="extended-prices-actions">
|
||||||
<EditExtendedPrice onSuccess={handleSuccess} onError={onError} price={extendedPrice} />
|
<EditExtendedPrice onSuccess={handleSuccess} onError={onError} price={extendedPrice} />
|
||||||
<DeleteExtendedPrice onSuccess={handleSuccess} onError={onError} price={extendedPrice} />
|
<DeleteExtendedPrice onSuccess={handleSuccess} onError={onError} price={extendedPrice} />
|
||||||
</span>
|
</span>
|
||||||
</li>)}
|
</li>)}
|
||||||
</ul>
|
</ul>
|
||||||
{extendedPrices?.length === 0 && <span>{t('app.admin.configure_extendedPrices_button.no_extendedPrices')}</span>}
|
{extendedPrices?.length === 0 && <span>{t('app.admin.configure_extended_prices_button.no_extended_prices')}</span>}
|
||||||
</FabPopover>}
|
</FabPopover>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -43,24 +43,24 @@ export const CreateExtendedPrice: React.FC<CreateExtendedPriceProps> = ({ onSucc
|
|||||||
// create it on the API
|
// create it on the API
|
||||||
PriceAPI.create(newExtendedPrice)
|
PriceAPI.create(newExtendedPrice)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
onSuccess(t('app.admin.create_extendedPrice.extendedPrice_successfully_created'));
|
onSuccess(t('app.admin.create_extended_price.extended_price_successfully_created'));
|
||||||
toggleModal();
|
toggleModal();
|
||||||
})
|
})
|
||||||
.catch(error => onError(error));
|
.catch(error => onError(error));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="create-pack">
|
<div className="create-extended-price">
|
||||||
<button className="add-pack-button" onClick={toggleModal}><i className="fas fa-plus"/></button>
|
<button className="add-price-button" onClick={toggleModal}><i className="fas fa-plus"/></button>
|
||||||
<FabModal isOpen={isOpen}
|
<FabModal isOpen={isOpen}
|
||||||
toggleModal={toggleModal}
|
toggleModal={toggleModal}
|
||||||
title={t('app.admin.create_extendedPrice.new_extendedPrice')}
|
title={t('app.admin.create_extended_price.new_extended_price')}
|
||||||
className="new-pack-modal"
|
className="new-extended-price-modal"
|
||||||
closeButton
|
closeButton
|
||||||
confirmButton={t('app.admin.create_extendedPrice.create_extendedPrice')}
|
confirmButton={t('app.admin.create_extended_price.create_extended_price')}
|
||||||
onConfirmSendFormId="new-extended-price">
|
onConfirmSendFormId="new-extended-price">
|
||||||
<FabAlert level="info">
|
<FabAlert level="info">
|
||||||
{t('app.admin.create_extendedPrice.new_extendedPrice_info', { TYPE: priceableType })}
|
{t('app.admin.create_extended_price.new_extended_price_info', { TYPE: priceableType })}
|
||||||
</FabAlert>
|
</FabAlert>
|
||||||
<ExtendedPriceForm formId="new-extended-price" onSubmit={handleSubmit} />
|
<ExtendedPriceForm formId="new-extended-price" onSubmit={handleSubmit} />
|
||||||
</FabModal>
|
</FabModal>
|
||||||
|
@ -33,23 +33,23 @@ export const DeleteExtendedPrice: React.FC<DeleteExtendedPriceProps> = ({ onSucc
|
|||||||
*/
|
*/
|
||||||
const onDeleteConfirmed = (): void => {
|
const onDeleteConfirmed = (): void => {
|
||||||
PriceAPI.destroy(price.id).then(() => {
|
PriceAPI.destroy(price.id).then(() => {
|
||||||
onSuccess(t('app.admin.delete_extendedPrice.extendedPrice_deleted'));
|
onSuccess(t('app.admin.delete_extended_price.extended_price_deleted'));
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
onError(t('app.admin.delete_extendedPrice.unable_to_delete') + error);
|
onError(t('app.admin.delete_extended_price.unable_to_delete') + error);
|
||||||
});
|
});
|
||||||
toggleDeletionModal();
|
toggleDeletionModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="delete-group">
|
<div className="delete-extended-price">
|
||||||
<FabButton type='button' className="delete-group-button" icon={<i className="fa fa-trash" />} onClick={toggleDeletionModal} />
|
<FabButton type='button' className="remove-price-button" icon={<i className="fa fa-trash" />} onClick={toggleDeletionModal} />
|
||||||
<FabModal title={t('app.admin.delete_extendedPrice.delete_extendedPrice')}
|
<FabModal title={t('app.admin.delete_extended_price.delete_extended_price')}
|
||||||
isOpen={deletionModal}
|
isOpen={deletionModal}
|
||||||
toggleModal={toggleDeletionModal}
|
toggleModal={toggleDeletionModal}
|
||||||
closeButton={true}
|
closeButton={true}
|
||||||
confirmButton={t('app.admin.delete_extendedPrice.confirm_delete')}
|
confirmButton={t('app.admin.delete_extended_price.confirm_delete')}
|
||||||
onConfirm={onDeleteConfirmed}>
|
onConfirm={onDeleteConfirmed}>
|
||||||
<span>{t('app.admin.delete_extendedPrice.delete_confirmation')}</span>
|
<span>{t('app.admin.delete_extended_price.delete_confirmation')}</span>
|
||||||
</FabModal>
|
</FabModal>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -42,7 +42,7 @@ export const EditExtendedPrice: React.FC<EditExtendedPriceProps> = ({ price, onS
|
|||||||
const handleUpdate = (price: Price): void => {
|
const handleUpdate = (price: Price): void => {
|
||||||
PriceAPI.update(price)
|
PriceAPI.update(price)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
onSuccess(t('app.admin.edit_extendedPrice.extendedPrice_successfully_updated'));
|
onSuccess(t('app.admin.edit_extended_price.extended_price_successfully_updated'));
|
||||||
setExtendedPriceData(price);
|
setExtendedPriceData(price);
|
||||||
toggleModal();
|
toggleModal();
|
||||||
})
|
})
|
||||||
@ -50,15 +50,16 @@ export const EditExtendedPrice: React.FC<EditExtendedPriceProps> = ({ price, onS
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="edit-group">
|
<div className="edit-extended-price">
|
||||||
<FabButton type='button' icon={<i className="fas fa-edit" />} onClick={handleRequestEdit} />
|
<FabButton type='button' className="edit-price-button" icon={<i className="fas fa-edit" />} onClick={handleRequestEdit} />
|
||||||
<FabModal isOpen={isOpen}
|
<FabModal isOpen={isOpen}
|
||||||
toggleModal={toggleModal}
|
toggleModal={toggleModal}
|
||||||
title={t('app.admin.edit_extendedPrice.edit_extendedPrice')}
|
title={t('app.admin.edit_extended_price.edit_extended_price')}
|
||||||
|
className="edit-pack-modal"
|
||||||
closeButton
|
closeButton
|
||||||
confirmButton={t('app.admin.edit_extendedPrice.confirm_changes')}
|
confirmButton={t('app.admin.edit_extended_price.confirm_changes')}
|
||||||
onConfirmSendFormId="edit-group">
|
onConfirmSendFormId="edit-extended-price">
|
||||||
{extendedPriceData && <ExtendedPriceForm formId="edit-group" onSubmit={handleUpdate} price={extendedPriceData} />}
|
{extendedPriceData && <ExtendedPriceForm formId="edit-extended-price" onSubmit={handleUpdate} price={extendedPriceData} />}
|
||||||
</FabModal>
|
</FabModal>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -9,7 +9,7 @@ declare let Fablab: IFablab;
|
|||||||
|
|
||||||
interface ExtendedPriceFormProps {
|
interface ExtendedPriceFormProps {
|
||||||
formId: string,
|
formId: string,
|
||||||
onSubmit: (pack: Price) => void,
|
onSubmit: (price: Price) => void,
|
||||||
price?: Price,
|
price?: Price,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,8 +49,8 @@ export const ExtendedPriceForm: React.FC<ExtendedPriceFormProps> = ({ formId, on
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form id={formId} onSubmit={handleSubmit} className="group-form">
|
<form id={formId} onSubmit={handleSubmit} className="extended-price-form">
|
||||||
<label htmlFor="duration">{t('app.admin.calendar.minutes')} *</label>
|
<label htmlFor="duration">{t('app.admin.extended_price_form.duration')} *</label>
|
||||||
<FabInput id="duration"
|
<FabInput id="duration"
|
||||||
type="number"
|
type="number"
|
||||||
defaultValue={extendedPriceData?.duration || ''}
|
defaultValue={extendedPriceData?.duration || ''}
|
||||||
|
@ -101,16 +101,17 @@ const SpacesPricing: React.FC<SpacesPricingProps> = ({ onError, onSuccess }) =>
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="pricing-list">
|
<div className="spaces-pricing">
|
||||||
<FabAlert level="warning">
|
<FabAlert level="warning">
|
||||||
<p><HtmlTranslate trKey="app.admin.pricing.these_prices_match_space_hours_rates_html"/></p>
|
<p><HtmlTranslate trKey="app.admin.spaces_pricing.prices_match_space_hours_rates_html"/></p>
|
||||||
<p><HtmlTranslate trKey="app.admin.pricing.prices_calculated_on_hourly_rate_html" options={{ DURATION: `${EXEMPLE_DURATION}`, RATE: examplePrice('hourly_rate'), PRICE: examplePrice('final_price') }} /></p>
|
<p><HtmlTranslate trKey="app.admin.spaces_pricing.prices_calculated_on_hourly_rate_html" options={{ DURATION: `${EXEMPLE_DURATION}`, RATE: examplePrice('hourly_rate'), PRICE: examplePrice('final_price') }} /></p>
|
||||||
<p>{t('app.admin.pricing.you_can_override')}</p>
|
<p>{t('app.admin.spaces_pricing.you_can_override')}</p>
|
||||||
|
<p>{t('app.admin.spaces_pricing.extended_prices')}</p>
|
||||||
</FabAlert>
|
</FabAlert>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{t('app.admin.pricing.spaces')}</th>
|
<th>{t('app.admin.spaces_pricing.spaces')}</th>
|
||||||
{groups?.map(group => <th key={group.id} className="group-name">{group.name}</th>)}
|
{groups?.map(group => <th key={group.id} className="group-name">{group.name}</th>)}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -57,12 +57,18 @@
|
|||||||
@import "modules/machines/machines-filters";
|
@import "modules/machines/machines-filters";
|
||||||
@import "modules/machines/required-training-modal";
|
@import "modules/machines/required-training-modal";
|
||||||
@import "modules/user/avatar";
|
@import "modules/user/avatar";
|
||||||
@import "modules/pricing/pricing-list";
|
|
||||||
@import "modules/pricing/editable-price";
|
@import "modules/pricing/editable-price";
|
||||||
@import "modules/pricing/configure-group-button";
|
@import "modules/pricing/machines/machines-pricing";
|
||||||
@import "modules/pricing/group-form";
|
@import "modules/pricing/machines/configure-packs-button";
|
||||||
@import "modules/pricing/delete-group";
|
@import "modules/pricing/machines/pack-form";
|
||||||
@import "modules/pricing/edit-group";
|
@import "modules/pricing/machines/delete-pack";
|
||||||
|
@import "modules/pricing/machines/edit-pack";
|
||||||
|
@import "modules/pricing/machines/create-pack";
|
||||||
|
@import "modules/pricing/spaces/configure-extended-prices-button";
|
||||||
|
@import "modules/pricing/spaces/create-extended-price";
|
||||||
|
@import "modules/pricing/spaces/delete-extended-price";
|
||||||
|
@import "modules/pricing/spaces/edit-extended-price";
|
||||||
|
@import "modules/pricing/spaces/spaces-pricing";
|
||||||
@import "modules/settings/check-list-setting";
|
@import "modules/settings/check-list-setting";
|
||||||
@import "modules/prepaid-packs/propose-packs-modal";
|
@import "modules/prepaid-packs/propose-packs-modal";
|
||||||
@import "modules/prepaid-packs/packs-summary";
|
@import "modules/prepaid-packs/packs-summary";
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
.configure-group {
|
.configure-packs-button {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&-button {
|
.packs-button {
|
||||||
border: 1px solid #d0cccc;
|
border: 1px solid #d0cccc;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -18,13 +18,6 @@
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.popover-title {
|
|
||||||
.add-pack-button {
|
|
||||||
position: absolute;
|
|
||||||
right: 5px;
|
|
||||||
top: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-content {
|
.popover-content {
|
||||||
ul {
|
ul {
|
||||||
@ -44,7 +37,7 @@
|
|||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-actions button {
|
.pack-actions button {
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
line-height: 10px;
|
line-height: 10px;
|
@ -0,0 +1,7 @@
|
|||||||
|
.create-pack {
|
||||||
|
.add-pack-button {
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
top: 10px;
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
.delete-group {
|
.delete-pack {
|
||||||
display: inline;
|
display: inline;
|
||||||
|
|
||||||
&-button {
|
.remove-pack-button {
|
||||||
background-color: #cb1117;
|
background-color: #cb1117;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
@ -1,3 +1,3 @@
|
|||||||
.edit-group {
|
.edit-pack {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
.machines-pricing {
|
||||||
|
.fab-alert {
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
overflow-y: scroll;
|
||||||
|
thead > tr > th:first-child {
|
||||||
|
width: 20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead > tr > th.group-name {
|
||||||
|
width: 20%;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead > tr > th {
|
||||||
|
vertical-align: bottom;
|
||||||
|
border-bottom: 2px solid #ddd;
|
||||||
|
padding: 8px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody > tr > td {
|
||||||
|
padding: 8px;
|
||||||
|
line-height: 1.5;
|
||||||
|
vertical-align: top;
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
.group-form {
|
.pack-form {
|
||||||
.interval-inputs {
|
.interval-inputs {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -0,0 +1,49 @@
|
|||||||
|
.configure-extended-prices-button {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 6px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.extended-prices-button {
|
||||||
|
border: 1px solid #d0cccc;
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 6px;
|
||||||
|
box-shadow: 0 1px 1px 0 #abaaaa;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #b9b9b9;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover-content {
|
||||||
|
ul {
|
||||||
|
padding-left: 19px;
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
&::before {
|
||||||
|
content: '\f466';
|
||||||
|
font-family: 'Font Awesome 5 Free';
|
||||||
|
position: absolute;
|
||||||
|
left: 11px;
|
||||||
|
font-weight: 800;
|
||||||
|
font-size: 12px;
|
||||||
|
vertical-align: middle;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.extended-prices-actions button {
|
||||||
|
font-size: 10px;
|
||||||
|
vertical-align: middle;
|
||||||
|
line-height: 10px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
.create-extended-price {
|
||||||
|
.add-price-button {
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
top: 10px;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
.delete-extended-price {
|
||||||
|
display: inline;
|
||||||
|
|
||||||
|
.remove-price-button {
|
||||||
|
background-color: #cb1117;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
.edit-extended-price {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
.extended-price-form {
|
||||||
|
.interval-inputs {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.select-interval {
|
||||||
|
min-width: 49%;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
.pricing-list {
|
.spaces-pricing {
|
||||||
.fab-alert {
|
.fab-alert {
|
||||||
margin: 15px 0;
|
margin: 15px 0;
|
||||||
}
|
}
|
||||||
@ -28,4 +28,4 @@
|
|||||||
border-top: 1px solid #ddd;
|
border-top: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,4 +8,8 @@ class Price < ApplicationRecord
|
|||||||
|
|
||||||
validates :priceable, :group_id, :amount, presence: true
|
validates :priceable, :group_id, :amount, presence: true
|
||||||
validates :priceable_id, uniqueness: { scope: %i[priceable_type plan_id group_id duration] }
|
validates :priceable_id, uniqueness: { scope: %i[priceable_type plan_id group_id duration] }
|
||||||
|
|
||||||
|
def safe_destroy
|
||||||
|
destroy unless duration == 60
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -369,6 +369,11 @@ en:
|
|||||||
status_disabled: "Disabled"
|
status_disabled: "Disabled"
|
||||||
status_all: "All"
|
status_all: "All"
|
||||||
spaces_pricing:
|
spaces_pricing:
|
||||||
|
prices_match_space_hours_rates_html: "The prices below match one hour of space reservation, <strong>without subscription</strong>."
|
||||||
|
prices_calculated_on_hourly_rate_html: "All the prices will be automatically calculated based on the hourly rate defined here.<br/><em>For example</em>, if you define an hourly rate at {RATE}: a slot of {DURATION} minutes, will be charged <strong>{PRICE}</strong>."
|
||||||
|
you_can_override: "You can override this duration for each availability you create in the agenda. The price will then be adjusted accordingly."
|
||||||
|
extended_prices: "Moreover, you can define extended prices which will apply in priority over the hourly rate below. Extended prices allow you, for example, to set a favorable price for a booking of several hours."
|
||||||
|
spaces: "Spaces"
|
||||||
price_updated: "Price successfully updated"
|
price_updated: "Price successfully updated"
|
||||||
machines_pricing:
|
machines_pricing:
|
||||||
prices_match_machine_hours_rates_html: "The prices below match one hour of machine usage, <strong>without subscription</strong>."
|
prices_match_machine_hours_rates_html: "The prices below match one hour of machine usage, <strong>without subscription</strong>."
|
||||||
@ -380,10 +385,12 @@ en:
|
|||||||
packs: "Prepaid packs"
|
packs: "Prepaid packs"
|
||||||
no_packs: "No packs for now"
|
no_packs: "No packs for now"
|
||||||
pack_DURATION: "{DURATION} hours"
|
pack_DURATION: "{DURATION} hours"
|
||||||
configure_extendedPrices_button:
|
configure_extended_prices_button:
|
||||||
extendedPrices: "Extended prices"
|
extended_prices: "Extended prices"
|
||||||
no_extendedPrices: "No extended price for now"
|
no_extended_prices: "No extended price for now"
|
||||||
extended_prices_form:
|
extended_price_DURATION: "{DURATION} minutes"
|
||||||
|
extended_price_form:
|
||||||
|
duration: "Duration (minutes)"
|
||||||
amount: "Price"
|
amount: "Price"
|
||||||
pack_form:
|
pack_form:
|
||||||
hours: "Hours"
|
hours: "Hours"
|
||||||
@ -411,21 +418,21 @@ en:
|
|||||||
edit_pack: "Edit the pack"
|
edit_pack: "Edit the pack"
|
||||||
confirm_changes: "Confirm changes"
|
confirm_changes: "Confirm changes"
|
||||||
pack_successfully_updated: "The prepaid pack was successfully updated."
|
pack_successfully_updated: "The prepaid pack was successfully updated."
|
||||||
create_extendedPrice:
|
create_extended_price:
|
||||||
new_extendedPrice: "New extended price"
|
new_extended_price: "New extended price"
|
||||||
new_extendedPrice_info: "Extended prices allows you to define prices based on custom durations, intead on the default hourly rates."
|
new_extended_price_info: "Extended prices allows you to define prices based on custom durations, instead of the default hourly rates."
|
||||||
create_extendedPrice: "Create extended price"
|
create_extended_price: "Create extended price"
|
||||||
extendedPrice_successfully_created: "The new extended price was successfully created."
|
extended_price_successfully_created: "The new extended price was successfully created."
|
||||||
delete_extendedPrice:
|
delete_extended_price:
|
||||||
extendedPrice_deleted: "The extended price was successfully deleted."
|
extended_price_deleted: "The extended price was successfully deleted."
|
||||||
unable_to_delete: "Unable to delete the extended price: "
|
unable_to_delete: "Unable to delete the extended price: "
|
||||||
delete_extendedPrice: "Delete the extended price"
|
delete_extended_price: "Delete the extended price"
|
||||||
confirm_delete: "Delete"
|
confirm_delete: "Delete"
|
||||||
delete_confirmation: "Are you sure you want to delete this extended price? This won't be possible if it was already bought by users."
|
delete_confirmation: "Are you sure you want to delete this extended price?"
|
||||||
edit_extendedPrice:
|
edit_extended_price:
|
||||||
edit_extendedPrice: "Edit the extended price"
|
edit_extended_price: "Edit the extended price"
|
||||||
confirm_changes: "Confirm changes"
|
confirm_changes: "Confirm changes"
|
||||||
extendedPrice_successfully_updated: "The extended price was successfully updated."
|
extended_price_successfully_updated: "The extended price was successfully updated."
|
||||||
#ajouter un code promotionnel
|
#ajouter un code promotionnel
|
||||||
coupons_new:
|
coupons_new:
|
||||||
add_a_coupon: "Add a coupon"
|
add_a_coupon: "Add a coupon"
|
||||||
|
Loading…
Reference in New Issue
Block a user