mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-18 07:52:23 +01:00
(feat) child validation
This commit is contained in:
parent
3d542ce6d4
commit
ec1a736601
@ -4,7 +4,7 @@
|
||||
# Children are used to provide a way to manage multiple users in the family account
|
||||
class API::ChildrenController < API::APIController
|
||||
before_action :authenticate_user!
|
||||
before_action :set_child, only: %i[show update destroy]
|
||||
before_action :set_child, only: %i[show update destroy validate]
|
||||
|
||||
def index
|
||||
authorize Child
|
||||
@ -43,6 +43,17 @@ class API::ChildrenController < API::APIController
|
||||
head :no_content
|
||||
end
|
||||
|
||||
def validate
|
||||
authorize @child
|
||||
|
||||
cparams = params.require(:child).permit(:validated_at)
|
||||
if @child.update(validated_at: cparams[:validated_at].present? ? Time.current : nil)
|
||||
render :show, status: :ok, location: child_path(@child)
|
||||
else
|
||||
render json: @child.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_child
|
||||
|
@ -38,4 +38,9 @@ export default class ChildAPI {
|
||||
const res: AxiosResponse<void> = await apiClient.delete(`/api/children/${childId}`);
|
||||
return res?.data;
|
||||
}
|
||||
|
||||
static async validate (child: Child): Promise<Child> {
|
||||
const res: AxiosResponse<Child> = await apiClient.patch(`/api/children/${child.id}/validate`, { child });
|
||||
return res?.data;
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,11 @@ import { FabButton } from '../base/fab-button';
|
||||
import { FormFileUpload } from '../form/form-file-upload';
|
||||
import { FileType } from '../../models/file';
|
||||
import { SupportingDocumentType } from '../../models/supporting-document-type';
|
||||
import { User } from '../../models/user';
|
||||
|
||||
interface ChildFormProps {
|
||||
child: Child;
|
||||
operator: User;
|
||||
onSubmit: (data: Child) => void;
|
||||
supportingDocumentsTypes: Array<SupportingDocumentType>;
|
||||
}
|
||||
@ -18,7 +20,7 @@ interface ChildFormProps {
|
||||
/**
|
||||
* A form for creating or editing a child.
|
||||
*/
|
||||
export const ChildForm: React.FC<ChildFormProps> = ({ child, onSubmit, supportingDocumentsTypes }) => {
|
||||
export const ChildForm: React.FC<ChildFormProps> = ({ child, onSubmit, supportingDocumentsTypes, operator }) => {
|
||||
const { t } = useTranslation('public');
|
||||
|
||||
const { register, formState, handleSubmit, setValue, control } = useForm<Child>({
|
||||
@ -31,11 +33,20 @@ export const ChildForm: React.FC<ChildFormProps> = ({ child, onSubmit, supportin
|
||||
return supportingDocumentType ? supportingDocumentType.name : '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the current operator has administrative rights or is a normal member
|
||||
*/
|
||||
const isPrivileged = (): boolean => {
|
||||
return (operator?.role === 'admin' || operator?.role === 'manager');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="child-form">
|
||||
<div className="info-area">
|
||||
{t('app.public.child_form.child_form_info')}
|
||||
</div>
|
||||
{isPrivileged() &&
|
||||
<div className="info-area">
|
||||
{t('app.public.child_form.child_form_info')}
|
||||
</div>
|
||||
}
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<FormInput id="first_name"
|
||||
register={register}
|
||||
@ -69,6 +80,22 @@ export const ChildForm: React.FC<ChildFormProps> = ({ child, onSubmit, supportin
|
||||
label={t('app.public.child_form.email')}
|
||||
/>
|
||||
{output.supporting_document_files_attributes.map((sf, index) => {
|
||||
if (isPrivileged()) {
|
||||
return (
|
||||
<div key={index} className="document-type">
|
||||
<div className="type-name">{getSupportingDocumentsTypeName(sf.supporting_document_type_id)}</div>
|
||||
{sf.attachment_url && (
|
||||
<a href={sf.attachment_url} target="_blank" rel="noreferrer">
|
||||
<span className="filename">{sf.attachment}</span>
|
||||
<i className="fa fa-download"></i>
|
||||
</a>
|
||||
)}
|
||||
{!sf.attachment_url && (
|
||||
<div className="missing-file">{t('app.public.child_form.to_complete')}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<FormFileUpload key={index}
|
||||
defaultFile={sf as FileType}
|
||||
|
@ -5,12 +5,15 @@ import { Child } from '../../models/child';
|
||||
import ChildAPI from '../../api/child';
|
||||
import { ChildForm } from './child-form';
|
||||
import { SupportingDocumentType } from '../../models/supporting-document-type';
|
||||
import { ChildValidation } from './child-validation';
|
||||
import { User } from '../../models/user';
|
||||
|
||||
interface ChildModalProps {
|
||||
child?: Child;
|
||||
operator: User;
|
||||
isOpen: boolean;
|
||||
toggleModal: () => void;
|
||||
onSuccess: (child: Child) => void;
|
||||
onSuccess: (child: Child, msg: string) => void;
|
||||
onError: (error: string) => void;
|
||||
supportingDocumentsTypes: Array<SupportingDocumentType>;
|
||||
}
|
||||
@ -18,7 +21,7 @@ interface ChildModalProps {
|
||||
/**
|
||||
* A modal for creating or editing a child.
|
||||
*/
|
||||
export const ChildModal: React.FC<ChildModalProps> = ({ child, isOpen, toggleModal, onSuccess, onError, supportingDocumentsTypes }) => {
|
||||
export const ChildModal: React.FC<ChildModalProps> = ({ child, isOpen, toggleModal, onSuccess, onError, supportingDocumentsTypes, operator }) => {
|
||||
const { t } = useTranslation('public');
|
||||
|
||||
/**
|
||||
@ -32,7 +35,7 @@ export const ChildModal: React.FC<ChildModalProps> = ({ child, isOpen, toggleMod
|
||||
await ChildAPI.create(data);
|
||||
}
|
||||
toggleModal();
|
||||
onSuccess(data);
|
||||
onSuccess(data, '');
|
||||
} catch (error) {
|
||||
onError(error);
|
||||
}
|
||||
@ -45,7 +48,10 @@ export const ChildModal: React.FC<ChildModalProps> = ({ child, isOpen, toggleMod
|
||||
toggleModal={toggleModal}
|
||||
closeButton={true}
|
||||
confirmButton={false} >
|
||||
<ChildForm child={child} onSubmit={handleSaveChild} supportingDocumentsTypes={supportingDocumentsTypes}/>
|
||||
{(operator?.role === 'admin' || operator?.role === 'manager') &&
|
||||
<ChildValidation child={child} onSuccess={onSuccess} onError={onError} />
|
||||
}
|
||||
<ChildForm child={child} onSubmit={handleSaveChild} supportingDocumentsTypes={supportingDocumentsTypes} operator={operator}/>
|
||||
</FabModal>
|
||||
);
|
||||
};
|
||||
|
@ -0,0 +1,54 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import * as React from 'react';
|
||||
import Switch from 'react-switch';
|
||||
import _ from 'lodash';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Child } from '../../models/child';
|
||||
import ChildAPI from '../../api/child';
|
||||
import { TDateISO } from '../../typings/date-iso';
|
||||
|
||||
interface ChildValidationProps {
|
||||
child: Child
|
||||
onSuccess: (child: Child, message: string) => void,
|
||||
onError: (message: string) => void,
|
||||
}
|
||||
|
||||
/**
|
||||
* This component allows to configure boolean value for a setting.
|
||||
*/
|
||||
export const ChildValidation: React.FC<ChildValidationProps> = ({ child, onSuccess, onError }) => {
|
||||
const { t } = useTranslation('admin');
|
||||
|
||||
const [value, setValue] = useState<boolean>(!!(child?.validated_at));
|
||||
|
||||
useEffect(() => {
|
||||
setValue(!!(child?.validated_at));
|
||||
}, [child]);
|
||||
|
||||
/**
|
||||
* Callback triggered when the 'switch' is changed.
|
||||
*/
|
||||
const handleChanged = (_value: boolean) => {
|
||||
setValue(_value);
|
||||
const _child = _.clone(child);
|
||||
if (_value) {
|
||||
_child.validated_at = new Date().toISOString() as TDateISO;
|
||||
} else {
|
||||
_child.validated_at = null;
|
||||
}
|
||||
ChildAPI.validate(_child)
|
||||
.then((child: Child) => {
|
||||
onSuccess(child, t(`app.admin.child_validation.${_value ? 'validate' : 'invalidate'}_child_success`));
|
||||
}).catch(err => {
|
||||
setValue(!_value);
|
||||
onError(t(`app.admin.child_validation.${_value ? 'validate' : 'invalidate'}_child_error`) + err);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="child-validation">
|
||||
<label htmlFor="child-validation-switch">{t('app.admin.child_validation.validate_child')}</label>
|
||||
<Switch checked={value} id="child-validation-switch" onChange={handleChanged} className="switch"></Switch>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -15,7 +15,8 @@ import SupportingDocumentTypeAPI from '../../api/supporting-document-type';
|
||||
declare const Application: IApplication;
|
||||
|
||||
interface ChildrenListProps {
|
||||
currentUser: User;
|
||||
user: User;
|
||||
operator: User;
|
||||
onSuccess: (error: string) => void;
|
||||
onError: (error: string) => void;
|
||||
}
|
||||
@ -23,7 +24,7 @@ interface ChildrenListProps {
|
||||
/**
|
||||
* A list of children belonging to the current user.
|
||||
*/
|
||||
export const ChildrenList: React.FC<ChildrenListProps> = ({ currentUser, onError }) => {
|
||||
export const ChildrenList: React.FC<ChildrenListProps> = ({ user, operator, onError, onSuccess }) => {
|
||||
const { t } = useTranslation('public');
|
||||
|
||||
const [children, setChildren] = useState<Array<Child>>([]);
|
||||
@ -32,11 +33,11 @@ export const ChildrenList: React.FC<ChildrenListProps> = ({ currentUser, onError
|
||||
const [supportingDocumentsTypes, setSupportingDocumentsTypes] = useState<Array<SupportingDocumentType>>([]);
|
||||
|
||||
useEffect(() => {
|
||||
ChildAPI.index({ user_id: currentUser.id }).then(setChildren);
|
||||
ChildAPI.index({ user_id: user.id }).then(setChildren);
|
||||
SupportingDocumentTypeAPI.index({ document_type: 'Child' }).then(tData => {
|
||||
setSupportingDocumentsTypes(tData);
|
||||
});
|
||||
}, [currentUser]);
|
||||
}, [user]);
|
||||
|
||||
/**
|
||||
* Open the add child modal
|
||||
@ -44,7 +45,7 @@ export const ChildrenList: React.FC<ChildrenListProps> = ({ currentUser, onError
|
||||
const addChild = () => {
|
||||
setIsOpenChildModal(true);
|
||||
setChild({
|
||||
user_id: currentUser.id,
|
||||
user_id: user.id,
|
||||
supporting_document_files_attributes: supportingDocumentsTypes.map(t => {
|
||||
return { supporting_document_type_id: t.id };
|
||||
})
|
||||
@ -70,24 +71,36 @@ export const ChildrenList: React.FC<ChildrenListProps> = ({ currentUser, onError
|
||||
*/
|
||||
const deleteChild = (child: Child) => {
|
||||
ChildAPI.destroy(child.id).then(() => {
|
||||
ChildAPI.index({ user_id: currentUser.id }).then(setChildren);
|
||||
ChildAPI.index({ user_id: user.id }).then(setChildren);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle save child success from the API
|
||||
*/
|
||||
const handleSaveChildSuccess = () => {
|
||||
ChildAPI.index({ user_id: currentUser.id }).then(setChildren);
|
||||
const handleSaveChildSuccess = (_child: Child, msg: string) => {
|
||||
ChildAPI.index({ user_id: user.id }).then(setChildren);
|
||||
if (msg) {
|
||||
onSuccess(msg);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the current operator has administrative rights or is a normal member
|
||||
*/
|
||||
const isPrivileged = (): boolean => {
|
||||
return (operator?.role === 'admin' || operator?.role === 'manager');
|
||||
};
|
||||
|
||||
return (
|
||||
<section>
|
||||
<header>
|
||||
<h2>{t('app.public.children_list.heading')}</h2>
|
||||
<FabButton onClick={addChild}>
|
||||
{t('app.public.children_list.add_child')}
|
||||
</FabButton>
|
||||
{!isPrivileged() && (
|
||||
<FabButton onClick={addChild}>
|
||||
{t('app.public.children_list.add_child')}
|
||||
</FabButton>
|
||||
)}
|
||||
</header>
|
||||
|
||||
<div className="children-list">
|
||||
@ -95,7 +108,7 @@ export const ChildrenList: React.FC<ChildrenListProps> = ({ currentUser, onError
|
||||
<ChildItem key={child.id} child={child} onEdit={editChild} onDelete={deleteChild} />
|
||||
))}
|
||||
</div>
|
||||
<ChildModal child={child} isOpen={isOpenChildModal} toggleModal={() => setIsOpenChildModal(false)} onSuccess={handleSaveChildSuccess} onError={onError} supportingDocumentsTypes={supportingDocumentsTypes} />
|
||||
<ChildModal child={child} isOpen={isOpenChildModal} toggleModal={() => setIsOpenChildModal(false)} onSuccess={handleSaveChildSuccess} onError={onError} supportingDocumentsTypes={supportingDocumentsTypes} operator={operator} />
|
||||
</section>
|
||||
);
|
||||
};
|
||||
@ -108,4 +121,4 @@ const ChildrenListWrapper: React.FC<ChildrenListProps> = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
Application.Components.component('childrenList', react2angular(ChildrenListWrapper, ['currentUser', 'onSuccess', 'onError']));
|
||||
Application.Components.component('childrenList', react2angular(ChildrenListWrapper, ['user', 'operator', 'onSuccess', 'onError']));
|
||||
|
@ -201,6 +201,9 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
|
||||
// Global config: is the user validation required ?
|
||||
$scope.enableUserValidationRequired = settingsPromise.user_validation_required === 'true';
|
||||
|
||||
// Global config: is the child validation required ?
|
||||
$scope.enableChildValidationRequired = settingsPromise.child_validation_required === 'true';
|
||||
|
||||
// online payments (by card)
|
||||
$scope.onlinePayment = {
|
||||
showModal: false,
|
||||
@ -635,6 +638,9 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
|
||||
if (!user.booked) {
|
||||
return false;
|
||||
}
|
||||
if ($scope.enableChildValidationRequired && user.booked.type === 'Child' && !user.booked.validatedAt) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -731,7 +737,8 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
|
||||
key,
|
||||
name: child.first_name + ' ' + child.last_name,
|
||||
id: child.id,
|
||||
type: 'Child'
|
||||
type: 'Child',
|
||||
validatedAt: child.validated_at
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ export interface Child {
|
||||
phone?: string,
|
||||
birthday: TDateISODate,
|
||||
user_id: number,
|
||||
validated_at?: TDateISODate,
|
||||
supporting_document_files_attributes?: Array<{
|
||||
id?: number,
|
||||
supportable_id?: number,
|
||||
|
@ -631,7 +631,7 @@ angular.module('application.router', ['ui.router'])
|
||||
resolve: {
|
||||
eventPromise: ['Event', '$transition$', function (Event, $transition$) { return Event.get({ id: $transition$.params().id }).$promise; }],
|
||||
priceCategoriesPromise: ['PriceCategory', function (PriceCategory) { return PriceCategory.query().$promise; }],
|
||||
settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['booking_move_enable', 'booking_move_delay', 'booking_cancel_enable', 'booking_cancel_delay', 'event_explications_alert', 'online_payment_module', 'user_validation_required', 'user_validation_required_list']" }).$promise; }]
|
||||
settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['booking_move_enable', 'booking_move_delay', 'booking_cancel_enable', 'booking_cancel_delay', 'event_explications_alert', 'online_payment_module', 'user_validation_required', 'user_validation_required_list', 'child_validation_required']" }).$promise; }]
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
.user-validation {
|
||||
.user-validation, .child-validation {
|
||||
label {
|
||||
margin-bottom: 0;
|
||||
vertical-align: middle;
|
||||
|
@ -62,6 +62,10 @@
|
||||
|
||||
</uib-tab>
|
||||
|
||||
<uib-tab heading="{{ 'app.shared.user_admin.children' | translate }}" ng-if="$root.settings.familyAccount">
|
||||
<children-list user="user" operator="currentUser" on-success="onSuccess" on-error="onError" />
|
||||
</uib-tab>
|
||||
|
||||
<uib-tab heading="{{ 'app.admin.members_edit.supporting_documents' | translate }}" ng-show="hasProofOfIdentityTypes">
|
||||
<supporting-documents-validation
|
||||
operator="currentUser"
|
||||
|
@ -54,13 +54,20 @@
|
||||
<div class="row">
|
||||
<h3 class="m-l" translate>{{ 'app.admin.settings.family_account' }}</h3>
|
||||
<p class="alert alert-warning m-h-md" ng-bind-html="'app.admin.settings.family_account_info_html' | translate"></p>
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-10 col-md-offset-1">
|
||||
<boolean-setting name="'family_account'"
|
||||
settings="allSettings"
|
||||
label="'app.admin.settings.enable_family_account' | translate"
|
||||
on-success="onSuccess"
|
||||
on-error="onError">
|
||||
</div>
|
||||
<div class="col-md-10 col-md-offset-1">
|
||||
<boolean-setting name="'child_validation_required'"
|
||||
settings="allSettings"
|
||||
label="'app.admin.settings.child_validation_required_label' | translate"
|
||||
on-success="onSuccess"
|
||||
on-error="onError">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
@ -7,5 +7,5 @@
|
||||
</section>
|
||||
|
||||
|
||||
<children-list current-user="currentUser" on-success="onSuccess" on-error="onError" />
|
||||
<children-list user="currentUser" operator="currentUser" on-success="onSuccess" on-error="onError" />
|
||||
</div>
|
||||
|
@ -136,6 +136,12 @@
|
||||
class="form-control">
|
||||
<option value=""></option>
|
||||
</select>
|
||||
<uib-alert type="danger" ng-if="enableChildValidationRequired && user.booked && user.booked.type === 'Child' && !user.booked.validatedAt">
|
||||
<p class="text-sm">
|
||||
<i class="fa fa-warning"></i>
|
||||
<span translate>{{ 'app.shared.cart.child_validation_required_alert' }}</span>
|
||||
</p>
|
||||
</uib-alert>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -162,6 +168,12 @@
|
||||
class="form-control">
|
||||
<option value=""></option>
|
||||
</select>
|
||||
<uib-alert type="danger" ng-if="enableChildValidationRequired && user.booked && user.booked.type === 'Child' && !user.booked.validatedAt">
|
||||
<p class="text-sm">
|
||||
<i class="fa fa-warning"></i>
|
||||
<span translate>{{ 'app.shared.cart.child_validation_required_alert' }}</span>
|
||||
</p>
|
||||
</uib-alert>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -168,6 +168,7 @@ module SettingsHelper
|
||||
user_validation_required_list
|
||||
show_username_in_admin_list
|
||||
family_account
|
||||
child_validation_required
|
||||
store_module
|
||||
store_withdrawal_instructions
|
||||
store_hidden
|
||||
|
@ -11,14 +11,18 @@ class ChildPolicy < ApplicationPolicy
|
||||
end
|
||||
|
||||
def show?
|
||||
user.id == record.user_id
|
||||
user.privileged? || user.id == record.user_id
|
||||
end
|
||||
|
||||
def update?
|
||||
user.id == record.user_id
|
||||
user.privileged? || user.id == record.user_id
|
||||
end
|
||||
|
||||
def destroy?
|
||||
user.id == record.user_id
|
||||
user.privileged? || user.id == record.user_id
|
||||
end
|
||||
|
||||
def validate?
|
||||
user.privileged?
|
||||
end
|
||||
end
|
||||
|
@ -47,7 +47,7 @@ class SettingPolicy < ApplicationPolicy
|
||||
machines_banner_cta_url trainings_banner_active trainings_banner_text trainings_banner_cta_active trainings_banner_cta_label
|
||||
trainings_banner_cta_url events_banner_active events_banner_text events_banner_cta_active events_banner_cta_label
|
||||
events_banner_cta_url projects_list_member_filter_presence projects_list_date_filters_presence
|
||||
project_categories_filter_placeholder project_categories_wording family_account]
|
||||
project_categories_filter_placeholder project_categories_wording family_account child_validation_required]
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -1,6 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
json.extract! child, :id, :first_name, :last_name, :email, :birthday, :phone, :user_id
|
||||
json.extract! child, :id, :first_name, :last_name, :email, :birthday, :phone, :user_id, :validated_at
|
||||
json.supporting_document_files_attributes child.supporting_document_files do |f|
|
||||
json.id f.id
|
||||
json.supportable_id f.supportable_id
|
||||
@ -8,5 +8,5 @@ json.supporting_document_files_attributes child.supporting_document_files do |f|
|
||||
json.supporting_document_type_id f.supporting_document_type_id
|
||||
json.attachment f.attachment.file.filename
|
||||
json.attachment_name f.attachment_identifier
|
||||
json.attachment_url f.attachment_url
|
||||
json.attachment_url "/api/supporting_document_files/#{f.id}/download"
|
||||
end
|
||||
|
3
app/views/api/children/show.json.jbuilder
Normal file
3
app/views/api/children/show.json.jbuilder
Normal file
@ -0,0 +1,3 @@
|
||||
# forzen_string_literal: true
|
||||
|
||||
json.partial! 'child', child: @child
|
@ -1242,6 +1242,12 @@ en:
|
||||
validate_member_error: "An unexpected error occurred: unable to validate this member."
|
||||
invalidate_member_error: "An unexpected error occurred: unable to invalidate this member."
|
||||
validate_account: "Validate the account"
|
||||
child_validation:
|
||||
validate_child_success: "Child successfully validated"
|
||||
invalidate_child_success: "Child successfully invalidated"
|
||||
validate_child_error: "An unexpected error occurred: unable to validate this child."
|
||||
invalidate_child_error: "An unexpected error occurred: unable to invalidate this child."
|
||||
validate_child: "Validate the child"
|
||||
supporting_documents_refusal_form:
|
||||
refusal_comment: "Comment"
|
||||
comment_placeholder: "Please type a comment here"
|
||||
@ -1791,6 +1797,7 @@ en:
|
||||
family_account: "family account"
|
||||
family_account_info_html: "By activating this option, you offer your members the possibility to add their child(ren) to their own account. You can also request proof if you wish to validate them."
|
||||
enable_family_account: "Enable the Family Account option"
|
||||
child_validation_required_label: "Activate the account validation option for children"
|
||||
overlapping_options:
|
||||
training_reservations: "Trainings"
|
||||
machine_reservations: "Machines"
|
||||
|
@ -1242,6 +1242,12 @@ fr:
|
||||
validate_member_error: "Une erreur inattendue est survenue. Impossible de valider ce compte membre."
|
||||
invalidate_member_error: "Une erreur inattendue est survenue. Impossible d'invalider ce compte membre."
|
||||
validate_account: "Valider le compte"
|
||||
child_validation:
|
||||
validate_child_success: "Le compte enfant a bien été validé"
|
||||
invalidate_child_success: "Le compte enfant a bien été invalidé"
|
||||
validate_child_error: "Une erreur inattendue est survenue. Impossible de valider ce compte enfant."
|
||||
invalidate_child_error: "Une erreur inattendue est survenue. Impossible d'invalider ce compte enfant."
|
||||
validate_child: "Valider le compte enfant"
|
||||
supporting_documents_refusal_form:
|
||||
refusal_comment: "Commentaire"
|
||||
comment_placeholder: "Veuillez saisir un commentaire ici"
|
||||
@ -1791,6 +1797,7 @@ fr:
|
||||
family_account: "Compte famille"
|
||||
family_account_info_html: "En activant cette option, vous offrez à vos membres la possibilité d'ajouter sur leur propre compte leur(s) enfants. Vous pouvez aussi demander un justificatif si vous souhaitez les valider."
|
||||
enable_family_account: "Activer l'option Compte Famille"
|
||||
child_validation_required_label: "Activer l'option de validation des comptes enfants"
|
||||
overlapping_options:
|
||||
training_reservations: "Formations"
|
||||
machine_reservations: "Machines"
|
||||
|
@ -497,6 +497,7 @@ en:
|
||||
email: "Email"
|
||||
phone: "Phone"
|
||||
save: "Save"
|
||||
to_complete: "To complete"
|
||||
child_item:
|
||||
first_name: "First name of the child"
|
||||
last_name: "Last name of the child"
|
||||
|
@ -497,6 +497,7 @@ fr:
|
||||
email: "Courriel"
|
||||
phone: "Téléphone"
|
||||
save: "Enregistrer"
|
||||
to_complete: "À compléter"
|
||||
child_item:
|
||||
first_name: "Prénom de l'enfant"
|
||||
last_name: "Nom de l'enfant"
|
||||
|
@ -199,6 +199,7 @@ en:
|
||||
group_is_required: "Group is required."
|
||||
trainings: "Trainings"
|
||||
tags: "Tags"
|
||||
children: "Children"
|
||||
#machine/training slot modification modal
|
||||
confirm_modify_slot_modal:
|
||||
change_the_slot: "Change the slot"
|
||||
@ -372,6 +373,7 @@ en:
|
||||
user_tags: "User tags"
|
||||
no_tags: "No tags"
|
||||
user_validation_required_alert: "Warning!<br>Your administrator must validate your account. Then, you'll then be able to access all the booking features."
|
||||
child_validation_required_alert: "Warning!<br>Your administrator must validate your child account. Then, you'll then be able to book the event."
|
||||
# feature-tour modal
|
||||
tour:
|
||||
previous: "Previous"
|
||||
|
@ -199,6 +199,7 @@ fr:
|
||||
group_is_required: "Le groupe est requis."
|
||||
trainings: "Formations"
|
||||
tags: "Étiquettes"
|
||||
children: "Enfants"
|
||||
#machine/training slot modification modal
|
||||
confirm_modify_slot_modal:
|
||||
change_the_slot: "Modifier le créneau"
|
||||
@ -372,6 +373,7 @@ fr:
|
||||
user_tags: "Étiquettes de l'utilisateur"
|
||||
no_tags: "Aucune étiquette"
|
||||
user_validation_required_alert: "Attention !<br>Votre administrateur doit valider votre compte. Vous pourrez alors accéder à l'ensemble des fonctionnalités de réservation."
|
||||
child_validation_required_alert: "Attention !<br>Votre administrateur doit valider votre compte enfant. Vous pourrez alors réserver l'événement."
|
||||
#feature-tour modal
|
||||
tour:
|
||||
previous: "Précédent"
|
||||
|
@ -185,7 +185,9 @@ Rails.application.routes.draw do
|
||||
get 'withdrawal_instructions', on: :member
|
||||
end
|
||||
|
||||
resources :children, only: %i[index show create update destroy]
|
||||
resources :children do
|
||||
patch ':id/validate', action: 'validate', on: :collection
|
||||
end
|
||||
|
||||
# for admin
|
||||
resources :trainings do
|
||||
|
8
db/migrate/20230525101006_add_validated_at_to_child.rb
Normal file
8
db/migrate/20230525101006_add_validated_at_to_child.rb
Normal file
@ -0,0 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# add validated_at to child
|
||||
class AddValidatedAtToChild < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
add_column :children, :validated_at, :datetime
|
||||
end
|
||||
end
|
@ -734,3 +734,4 @@ Setting.set('projects_list_date_filters_presence', false) unless Setting.find_by
|
||||
Setting.set('project_categories_filter_placeholder', 'Toutes les catégories') unless Setting.find_by(name: 'project_categories_filter_placeholder').try(:value)
|
||||
Setting.set('project_categories_wording', 'Catégories') unless Setting.find_by(name: 'project_categories_wording').try(:value)
|
||||
Setting.set('family_account', false) unless Setting.find_by(name: 'family_account').try(:value)
|
||||
Setting.set('child_validation_required', false) unless Setting.find_by(name: 'child_validation_required').try(:value)
|
||||
|
@ -968,7 +968,8 @@ CREATE TABLE public.children (
|
||||
phone character varying,
|
||||
email character varying,
|
||||
created_at timestamp without time zone NOT NULL,
|
||||
updated_at timestamp without time zone NOT NULL
|
||||
updated_at timestamp without time zone NOT NULL,
|
||||
validated_at timestamp(6) without time zone
|
||||
);
|
||||
|
||||
|
||||
@ -9061,5 +9062,6 @@ INSERT INTO "schema_migrations" (version) VALUES
|
||||
('20230524110215');
|
||||
('20230626122844'),
|
||||
('20230626122947');
|
||||
('20230525101006');
|
||||
|
||||
|
||||
|
8
test/fixtures/history_values.yml
vendored
8
test/fixtures/history_values.yml
vendored
@ -890,3 +890,11 @@ history_value_105:
|
||||
created_at: '2023-03-31 14:38:40.000421'
|
||||
updated_at: '2023-03-31 14:38:40.000421'
|
||||
invoicing_profile_id: 1
|
||||
|
||||
history_value_102:
|
||||
id: 102
|
||||
setting_id: 101
|
||||
value: 'false'
|
||||
created_at: '2023-03-31 14:38:40.000421'
|
||||
updated_at: '2023-03-31 14:38:40.000421'
|
||||
invoicing_profile_id: 1
|
||||
|
6
test/fixtures/settings.yml
vendored
6
test/fixtures/settings.yml
vendored
@ -615,3 +615,9 @@ setting_104:
|
||||
name: family_account
|
||||
created_at: 2023-03-31 14:38:40.000421500 Z
|
||||
updated_at: 2023-03-31 14:38:40.000421500 Z
|
||||
|
||||
setting_101:
|
||||
id: 101
|
||||
name: child_validation_required
|
||||
created_at: 2023-03-31 14:38:40.000421500 Z
|
||||
updated_at: 2023-03-31 14:38:40.000421500 Z
|
||||
|
Loading…
x
Reference in New Issue
Block a user