From ec1a736601d78799738e991bba9760cc04e318d7 Mon Sep 17 00:00:00 2001 From: Du Peng Date: Thu, 25 May 2023 20:17:37 +0200 Subject: [PATCH] (feat) child validation --- app/controllers/api/children_controller.rb | 13 ++++- app/frontend/src/javascript/api/child.ts | 5 ++ .../components/family-account/child-form.tsx | 35 ++++++++++-- .../components/family-account/child-modal.tsx | 14 +++-- .../family-account/child-validation.tsx | 54 +++++++++++++++++++ .../family-account/children-list.tsx | 39 +++++++++----- .../src/javascript/controllers/events.js.erb | 9 +++- app/frontend/src/javascript/models/child.ts | 1 + app/frontend/src/javascript/router.js | 2 +- .../modules/user/user-validation.scss | 2 +- .../templates/admin/members/edit.html | 4 ++ .../templates/admin/settings/compte.html | 9 +++- .../templates/dashboard/children.html | 2 +- app/frontend/templates/events/show.html | 12 +++++ app/helpers/settings_helper.rb | 1 + app/policies/child_policy.rb | 10 ++-- app/policies/setting_policy.rb | 2 +- app/views/api/children/_child.json.jbuilder | 4 +- app/views/api/children/show.json.jbuilder | 3 ++ config/locales/app.admin.en.yml | 7 +++ config/locales/app.admin.fr.yml | 7 +++ config/locales/app.public.en.yml | 1 + config/locales/app.public.fr.yml | 1 + config/locales/app.shared.en.yml | 2 + config/locales/app.shared.fr.yml | 2 + config/routes.rb | 4 +- ...0230525101006_add_validated_at_to_child.rb | 8 +++ db/seeds/settings.rb | 1 + db/structure.sql | 4 +- test/fixtures/history_values.yml | 8 +++ test/fixtures/settings.yml | 6 +++ 31 files changed, 237 insertions(+), 35 deletions(-) create mode 100644 app/frontend/src/javascript/components/family-account/child-validation.tsx create mode 100644 app/views/api/children/show.json.jbuilder create mode 100644 db/migrate/20230525101006_add_validated_at_to_child.rb diff --git a/app/controllers/api/children_controller.rb b/app/controllers/api/children_controller.rb index bd51d18b5..55b2437e6 100644 --- a/app/controllers/api/children_controller.rb +++ b/app/controllers/api/children_controller.rb @@ -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 diff --git a/app/frontend/src/javascript/api/child.ts b/app/frontend/src/javascript/api/child.ts index 586964973..04a5d373a 100644 --- a/app/frontend/src/javascript/api/child.ts +++ b/app/frontend/src/javascript/api/child.ts @@ -38,4 +38,9 @@ export default class ChildAPI { const res: AxiosResponse = await apiClient.delete(`/api/children/${childId}`); return res?.data; } + + static async validate (child: Child): Promise { + const res: AxiosResponse = await apiClient.patch(`/api/children/${child.id}/validate`, { child }); + return res?.data; + } } diff --git a/app/frontend/src/javascript/components/family-account/child-form.tsx b/app/frontend/src/javascript/components/family-account/child-form.tsx index 33834ebe8..ea99b10d4 100644 --- a/app/frontend/src/javascript/components/family-account/child-form.tsx +++ b/app/frontend/src/javascript/components/family-account/child-form.tsx @@ -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; } @@ -18,7 +20,7 @@ interface ChildFormProps { /** * A form for creating or editing a child. */ -export const ChildForm: React.FC = ({ child, onSubmit, supportingDocumentsTypes }) => { +export const ChildForm: React.FC = ({ child, onSubmit, supportingDocumentsTypes, operator }) => { const { t } = useTranslation('public'); const { register, formState, handleSubmit, setValue, control } = useForm({ @@ -31,11 +33,20 @@ export const ChildForm: React.FC = ({ 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 (
-
- {t('app.public.child_form.child_form_info')} -
+ {isPrivileged() && +
+ {t('app.public.child_form.child_form_info')} +
+ }
= ({ child, onSubmit, supportin label={t('app.public.child_form.email')} /> {output.supporting_document_files_attributes.map((sf, index) => { + if (isPrivileged()) { + return ( +
+
{getSupportingDocumentsTypeName(sf.supporting_document_type_id)}
+ {sf.attachment_url && ( + + {sf.attachment} + + + )} + {!sf.attachment_url && ( +
{t('app.public.child_form.to_complete')}
+ )} +
+ ); + } return ( void; - onSuccess: (child: Child) => void; + onSuccess: (child: Child, msg: string) => void; onError: (error: string) => void; supportingDocumentsTypes: Array; } @@ -18,7 +21,7 @@ interface ChildModalProps { /** * A modal for creating or editing a child. */ -export const ChildModal: React.FC = ({ child, isOpen, toggleModal, onSuccess, onError, supportingDocumentsTypes }) => { +export const ChildModal: React.FC = ({ child, isOpen, toggleModal, onSuccess, onError, supportingDocumentsTypes, operator }) => { const { t } = useTranslation('public'); /** @@ -32,7 +35,7 @@ export const ChildModal: React.FC = ({ 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 = ({ child, isOpen, toggleMod toggleModal={toggleModal} closeButton={true} confirmButton={false} > - + {(operator?.role === 'admin' || operator?.role === 'manager') && + + } + ); }; diff --git a/app/frontend/src/javascript/components/family-account/child-validation.tsx b/app/frontend/src/javascript/components/family-account/child-validation.tsx new file mode 100644 index 000000000..f98a8e172 --- /dev/null +++ b/app/frontend/src/javascript/components/family-account/child-validation.tsx @@ -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 = ({ child, onSuccess, onError }) => { + const { t } = useTranslation('admin'); + + const [value, setValue] = useState(!!(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 ( +
+ + +
+ ); +}; diff --git a/app/frontend/src/javascript/components/family-account/children-list.tsx b/app/frontend/src/javascript/components/family-account/children-list.tsx index 4e3e18e46..6b1f4aab0 100644 --- a/app/frontend/src/javascript/components/family-account/children-list.tsx +++ b/app/frontend/src/javascript/components/family-account/children-list.tsx @@ -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 = ({ currentUser, onError }) => { +export const ChildrenList: React.FC = ({ user, operator, onError, onSuccess }) => { const { t } = useTranslation('public'); const [children, setChildren] = useState>([]); @@ -32,11 +33,11 @@ export const ChildrenList: React.FC = ({ currentUser, onError const [supportingDocumentsTypes, setSupportingDocumentsTypes] = useState>([]); 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 = ({ 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 = ({ 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 (

{t('app.public.children_list.heading')}

- - {t('app.public.children_list.add_child')} - + {!isPrivileged() && ( + + {t('app.public.children_list.add_child')} + + )}
@@ -95,7 +108,7 @@ export const ChildrenList: React.FC = ({ currentUser, onError ))}
- setIsOpenChildModal(false)} onSuccess={handleSaveChildSuccess} onError={onError} supportingDocumentsTypes={supportingDocumentsTypes} /> + setIsOpenChildModal(false)} onSuccess={handleSaveChildSuccess} onError={onError} supportingDocumentsTypes={supportingDocumentsTypes} operator={operator} />
); }; @@ -108,4 +121,4 @@ const ChildrenListWrapper: React.FC = (props) => { ); }; -Application.Components.component('childrenList', react2angular(ChildrenListWrapper, ['currentUser', 'onSuccess', 'onError'])); +Application.Components.component('childrenList', react2angular(ChildrenListWrapper, ['user', 'operator', 'onSuccess', 'onError'])); diff --git a/app/frontend/src/javascript/controllers/events.js.erb b/app/frontend/src/javascript/controllers/events.js.erb index 5782994be..763b866a7 100644 --- a/app/frontend/src/javascript/controllers/events.js.erb +++ b/app/frontend/src/javascript/controllers/events.js.erb @@ -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 }); } } diff --git a/app/frontend/src/javascript/models/child.ts b/app/frontend/src/javascript/models/child.ts index be33bdec6..bc00f1fb1 100644 --- a/app/frontend/src/javascript/models/child.ts +++ b/app/frontend/src/javascript/models/child.ts @@ -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, diff --git a/app/frontend/src/javascript/router.js b/app/frontend/src/javascript/router.js index 8c8db892d..6ff669be2 100644 --- a/app/frontend/src/javascript/router.js +++ b/app/frontend/src/javascript/router.js @@ -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; }] } }) diff --git a/app/frontend/src/stylesheets/modules/user/user-validation.scss b/app/frontend/src/stylesheets/modules/user/user-validation.scss index 81a741931..2c160f181 100644 --- a/app/frontend/src/stylesheets/modules/user/user-validation.scss +++ b/app/frontend/src/stylesheets/modules/user/user-validation.scss @@ -1,4 +1,4 @@ -.user-validation { +.user-validation, .child-validation { label { margin-bottom: 0; vertical-align: middle; diff --git a/app/frontend/templates/admin/members/edit.html b/app/frontend/templates/admin/members/edit.html index c3479225e..796a30430 100644 --- a/app/frontend/templates/admin/members/edit.html +++ b/app/frontend/templates/admin/members/edit.html @@ -62,6 +62,10 @@ + + + +

{{ 'app.admin.settings.family_account' }}

-
+
+
+ +
diff --git a/app/frontend/templates/dashboard/children.html b/app/frontend/templates/dashboard/children.html index 8f5c2c17d..9f81ef21c 100644 --- a/app/frontend/templates/dashboard/children.html +++ b/app/frontend/templates/dashboard/children.html @@ -7,5 +7,5 @@ - +
diff --git a/app/frontend/templates/events/show.html b/app/frontend/templates/events/show.html index 72cd5aa07..f54a21616 100644 --- a/app/frontend/templates/events/show.html +++ b/app/frontend/templates/events/show.html @@ -136,6 +136,12 @@ class="form-control"> + +

+ + {{ 'app.shared.cart.child_validation_required_alert' }} +

+
@@ -162,6 +168,12 @@ class="form-control"> + +

+ + {{ 'app.shared.cart.child_validation_required_alert' }} +

+
diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb index 8e60fe4e1..99994e1de 100644 --- a/app/helpers/settings_helper.rb +++ b/app/helpers/settings_helper.rb @@ -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 diff --git a/app/policies/child_policy.rb b/app/policies/child_policy.rb index 6dfdba968..e5f9a3232 100644 --- a/app/policies/child_policy.rb +++ b/app/policies/child_policy.rb @@ -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 diff --git a/app/policies/setting_policy.rb b/app/policies/setting_policy.rb index 7c8001bef..a0292fa62 100644 --- a/app/policies/setting_policy.rb +++ b/app/policies/setting_policy.rb @@ -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 ## diff --git a/app/views/api/children/_child.json.jbuilder b/app/views/api/children/_child.json.jbuilder index d65d54e3c..029921ecf 100644 --- a/app/views/api/children/_child.json.jbuilder +++ b/app/views/api/children/_child.json.jbuilder @@ -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 diff --git a/app/views/api/children/show.json.jbuilder b/app/views/api/children/show.json.jbuilder new file mode 100644 index 000000000..c97cd198b --- /dev/null +++ b/app/views/api/children/show.json.jbuilder @@ -0,0 +1,3 @@ +# forzen_string_literal: true + +json.partial! 'child', child: @child diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index eca3e8e05..140eb587e 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -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" diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index f477117d5..a8a08de1d 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -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" diff --git a/config/locales/app.public.en.yml b/config/locales/app.public.en.yml index 6d7f2b66d..25471d52a 100644 --- a/config/locales/app.public.en.yml +++ b/config/locales/app.public.en.yml @@ -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" diff --git a/config/locales/app.public.fr.yml b/config/locales/app.public.fr.yml index f7ddb0f08..ecf3f4c92 100644 --- a/config/locales/app.public.fr.yml +++ b/config/locales/app.public.fr.yml @@ -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" diff --git a/config/locales/app.shared.en.yml b/config/locales/app.shared.en.yml index bfe88a627..be26b070d 100644 --- a/config/locales/app.shared.en.yml +++ b/config/locales/app.shared.en.yml @@ -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!
Your administrator must validate your account. Then, you'll then be able to access all the booking features." + child_validation_required_alert: "Warning!
Your administrator must validate your child account. Then, you'll then be able to book the event." # feature-tour modal tour: previous: "Previous" diff --git a/config/locales/app.shared.fr.yml b/config/locales/app.shared.fr.yml index 8bf660c5d..2338a1e1e 100644 --- a/config/locales/app.shared.fr.yml +++ b/config/locales/app.shared.fr.yml @@ -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 !
Votre administrateur doit valider votre compte. Vous pourrez alors accéder à l'ensemble des fonctionnalités de réservation." + child_validation_required_alert: "Attention !
Votre administrateur doit valider votre compte enfant. Vous pourrez alors réserver l'événement." #feature-tour modal tour: previous: "Précédent" diff --git a/config/routes.rb b/config/routes.rb index ebc40bbbc..a0a1be6e5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 diff --git a/db/migrate/20230525101006_add_validated_at_to_child.rb b/db/migrate/20230525101006_add_validated_at_to_child.rb new file mode 100644 index 000000000..a8c3167e9 --- /dev/null +++ b/db/migrate/20230525101006_add_validated_at_to_child.rb @@ -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 diff --git a/db/seeds/settings.rb b/db/seeds/settings.rb index 92d932a82..1f8e50c33 100644 --- a/db/seeds/settings.rb +++ b/db/seeds/settings.rb @@ -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) diff --git a/db/structure.sql b/db/structure.sql index c9bb14c2d..1e0fb0d6f 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -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'); diff --git a/test/fixtures/history_values.yml b/test/fixtures/history_values.yml index 5738b7399..0873324af 100644 --- a/test/fixtures/history_values.yml +++ b/test/fixtures/history_values.yml @@ -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 diff --git a/test/fixtures/settings.yml b/test/fixtures/settings.yml index 8e8326214..fb456559e 100644 --- a/test/fixtures/settings.yml +++ b/test/fixtures/settings.yml @@ -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