From 42946effe0add42f9c209a1ccb43425c066fafde Mon Sep 17 00:00:00 2001 From: Du Peng Date: Fri, 26 May 2023 12:54:39 +0200 Subject: [PATCH] (feat) admin can refuse child's supporting document file --- .../components/family-account/child-form.tsx | 42 +++++++++++++++++-- .../components/family-account/child-modal.tsx | 13 ++++-- .../family-account/child-validation.tsx | 6 +-- .../family-account/children-list.tsx | 2 +- .../supporting-documents-refusal-modal.tsx | 10 +++-- .../supporting-documents-validation.tsx | 8 ++-- .../templates/admin/members/edit.html | 1 + app/models/child.rb | 4 ++ .../supporting_document_refusal_service.rb | 24 +++++++---- ..._supporting_document_refusal.json.jbuilder | 5 +++ ..._supporting_document_refusal.json.jbuilder | 4 ++ ...child_supporting_document_refusal.html.erb | 15 +++++++ ...child_supporting_document_refusal.html.erb | 16 +++++++ config/locales/app.logged.en.yml | 1 + config/locales/app.logged.fr.yml | 1 + config/locales/app.public.en.yml | 1 + config/locales/app.public.fr.yml | 1 + config/locales/en.yml | 4 ++ config/locales/fr.yml | 4 ++ config/locales/mails.en.yml | 9 ++++ config/locales/mails.fr.yml | 9 ++++ db/seeds/notification_types.rb | 16 +++++++ 22 files changed, 172 insertions(+), 24 deletions(-) create mode 100644 app/views/api/notifications/_notify_admin_user_child_supporting_document_refusal.json.jbuilder create mode 100644 app/views/api/notifications/_notify_user_child_supporting_document_refusal.json.jbuilder create mode 100644 app/views/notifications_mailer/notify_admin_user_child_supporting_document_refusal.html.erb create mode 100644 app/views/notifications_mailer/notify_user_child_supporting_document_refusal.html.erb 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 ea99b10d4..c65631d2c 100644 --- a/app/frontend/src/javascript/components/family-account/child-form.tsx +++ b/app/frontend/src/javascript/components/family-account/child-form.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState } from 'react'; import { useForm, useWatch } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import moment from 'moment'; @@ -9,25 +9,32 @@ import { FormFileUpload } from '../form/form-file-upload'; import { FileType } from '../../models/file'; import { SupportingDocumentType } from '../../models/supporting-document-type'; import { User } from '../../models/user'; +import { SupportingDocumentsRefusalModal } from '../supporting-documents/supporting-documents-refusal-modal'; interface ChildFormProps { child: Child; operator: User; onSubmit: (data: Child) => void; supportingDocumentsTypes: Array; + onSuccess: (message: string) => void, + onError: (message: string) => void, } /** * A form for creating or editing a child. */ -export const ChildForm: React.FC = ({ child, onSubmit, supportingDocumentsTypes, operator }) => { +export const ChildForm: React.FC = ({ child, onSubmit, supportingDocumentsTypes, operator, onSuccess, onError }) => { const { t } = useTranslation('public'); const { register, formState, handleSubmit, setValue, control } = useForm({ defaultValues: child }); const output = useWatch({ control }); // eslint-disable-line + const [refuseModalIsOpen, setRefuseModalIsOpen] = useState(false); + /** + * get the name of the supporting document type by id + */ const getSupportingDocumentsTypeName = (id: number): string => { const supportingDocumentType = supportingDocumentsTypes.find((supportingDocumentType) => supportingDocumentType.id === id); return supportingDocumentType ? supportingDocumentType.name : ''; @@ -40,9 +47,24 @@ export const ChildForm: React.FC = ({ child, onSubmit, supportin return (operator?.role === 'admin' || operator?.role === 'manager'); }; + /** + * Open/closes the modal dialog to refuse the documents + */ + const toggleRefuseModal = (): void => { + setRefuseModalIsOpen(!refuseModalIsOpen); + }; + + /** + * Callback triggered when the refusal was successfully saved + */ + const onSaveRefusalSuccess = (message: string): void => { + setRefuseModalIsOpen(false); + onSuccess(message); + }; + return (
- {isPrivileged() && + {!isPrivileged() &&
{t('app.public.child_form.child_form_info')}
@@ -113,6 +135,20 @@ export const ChildForm: React.FC = ({ child, onSubmit, supportin {t('app.public.child_form.save')} + {isPrivileged() && +
+ {t('app.public.child_form.refuse_documents')} + +
+ }
diff --git a/app/frontend/src/javascript/components/family-account/child-modal.tsx b/app/frontend/src/javascript/components/family-account/child-modal.tsx index e2f7d4e7c..acc75e9f4 100644 --- a/app/frontend/src/javascript/components/family-account/child-modal.tsx +++ b/app/frontend/src/javascript/components/family-account/child-modal.tsx @@ -13,7 +13,7 @@ interface ChildModalProps { operator: User; isOpen: boolean; toggleModal: () => void; - onSuccess: (child: Child, msg: string) => void; + onSuccess: (msg: string) => void; onError: (error: string) => void; supportingDocumentsTypes: Array; } @@ -35,7 +35,7 @@ export const ChildModal: React.FC = ({ child, isOpen, toggleMod await ChildAPI.create(data); } toggleModal(); - onSuccess(data, ''); + onSuccess(''); } catch (error) { onError(error); } @@ -51,7 +51,14 @@ export const ChildModal: React.FC = ({ child, isOpen, toggleMod {(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 index f98a8e172..1705ad6cf 100644 --- a/app/frontend/src/javascript/components/family-account/child-validation.tsx +++ b/app/frontend/src/javascript/components/family-account/child-validation.tsx @@ -9,7 +9,7 @@ import { TDateISO } from '../../typings/date-iso'; interface ChildValidationProps { child: Child - onSuccess: (child: Child, message: string) => void, + onSuccess: (message: string) => void, onError: (message: string) => void, } @@ -37,8 +37,8 @@ export const ChildValidation: React.FC = ({ child, onSucce _child.validated_at = null; } ChildAPI.validate(_child) - .then((child: Child) => { - onSuccess(child, t(`app.admin.child_validation.${_value ? 'validate' : 'invalidate'}_child_success`)); + .then(() => { + onSuccess(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); 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 6b1f4aab0..efcac3275 100644 --- a/app/frontend/src/javascript/components/family-account/children-list.tsx +++ b/app/frontend/src/javascript/components/family-account/children-list.tsx @@ -78,7 +78,7 @@ export const ChildrenList: React.FC = ({ user, operator, onEr /** * Handle save child success from the API */ - const handleSaveChildSuccess = (_child: Child, msg: string) => { + const handleSaveChildSuccess = (msg: string) => { ChildAPI.index({ user_id: user.id }).then(setChildren); if (msg) { onSuccess(msg); diff --git a/app/frontend/src/javascript/components/supporting-documents/supporting-documents-refusal-modal.tsx b/app/frontend/src/javascript/components/supporting-documents/supporting-documents-refusal-modal.tsx index 0439a5c8e..6a436af10 100644 --- a/app/frontend/src/javascript/components/supporting-documents/supporting-documents-refusal-modal.tsx +++ b/app/frontend/src/javascript/components/supporting-documents/supporting-documents-refusal-modal.tsx @@ -5,6 +5,7 @@ import { FabModal } from '../base/fab-modal'; import { SupportingDocumentType } from '../../models/supporting-document-type'; import { SupportingDocumentRefusal } from '../../models/supporting-document-refusal'; import { User } from '../../models/user'; +import { Child } from '../../models/child'; import SupportingDocumentRefusalAPI from '../../api/supporting-document-refusal'; import { SupportingDocumentsRefusalForm } from './supporting-documents-refusal-form'; @@ -15,20 +16,21 @@ interface SupportingDocumentsRefusalModalProps { onError: (message: string) => void, proofOfIdentityTypes: Array, operator: User, - member: User + supportable: User | Child, + documentType: 'User' | 'Child', } /** * Modal dialog to notify the member that his documents are refused */ -export const SupportingDocumentsRefusalModal: React.FC = ({ isOpen, toggleModal, onSuccess, proofOfIdentityTypes, operator, member, onError }) => { +export const SupportingDocumentsRefusalModal: React.FC = ({ isOpen, toggleModal, onSuccess, proofOfIdentityTypes, operator, supportable, onError, documentType }) => { const { t } = useTranslation('admin'); const [data, setData] = useState({ id: null, operator_id: operator.id, - supportable_id: member.id, - supportable_type: 'User', + supportable_id: supportable.id, + supportable_type: documentType, supporting_document_type_ids: [], message: '' }); diff --git a/app/frontend/src/javascript/components/supporting-documents/supporting-documents-validation.tsx b/app/frontend/src/javascript/components/supporting-documents/supporting-documents-validation.tsx index 94a6c0f2b..8bb43b9bc 100644 --- a/app/frontend/src/javascript/components/supporting-documents/supporting-documents-validation.tsx +++ b/app/frontend/src/javascript/components/supporting-documents/supporting-documents-validation.tsx @@ -19,6 +19,7 @@ declare const Application: IApplication; interface SupportingDocumentsValidationProps { operator: User, member: User + documentType: 'User' | 'Child', onSuccess: (message: string) => void, onError: (message: string) => void, } @@ -26,7 +27,7 @@ interface SupportingDocumentsValidationProps { /** * This component shows a list of supporting documents file of member, admin can download and valid **/ -const SupportingDocumentsValidation: React.FC = ({ operator, member, onSuccess, onError }) => { +const SupportingDocumentsValidation: React.FC = ({ operator, member, onSuccess, onError, documentType }) => { const { t } = useTranslation('admin'); // list of supporting documents type @@ -112,7 +113,8 @@ const SupportingDocumentsValidation: React.FC @@ -131,4 +133,4 @@ const SupportingDocumentsValidationWrapper: React.FC diff --git a/app/models/child.rb b/app/models/child.rb index 7dd5c70ed..07c59c4c6 100644 --- a/app/models/child.rb +++ b/app/models/child.rb @@ -17,4 +17,8 @@ class Child < ApplicationRecord def validate_age errors.add(:birthday, I18n.t('.errors.messages.birthday_less_than_18_years_ago')) if birthday.blank? || birthday > 18.years.ago end + + def full_name + "#{(first_name || '').humanize.titleize} #{(last_name || '').humanize.titleize}" + end end diff --git a/app/services/supporting_document_refusal_service.rb b/app/services/supporting_document_refusal_service.rb index 42c78d68f..612983747 100644 --- a/app/services/supporting_document_refusal_service.rb +++ b/app/services/supporting_document_refusal_service.rb @@ -14,13 +14,23 @@ class SupportingDocumentRefusalService def self.create(supporting_document_refusal) saved = supporting_document_refusal.save - if saved && supporting_document_refusal.supportable_type == 'User' - NotificationCenter.call type: 'notify_admin_user_supporting_document_refusal', - receiver: User.admins_and_managers, - attached_object: supporting_document_refusal - NotificationCenter.call type: 'notify_user_supporting_document_refusal', - receiver: supporting_document_refusal.supportable, - attached_object: supporting_document_refusal + if saved + case supporting_document_refusal.supportable_type + when 'User' + NotificationCenter.call type: 'notify_admin_user_supporting_document_refusal', + receiver: User.admins_and_managers, + attached_object: supporting_document_refusal + NotificationCenter.call type: 'notify_user_supporting_document_refusal', + receiver: supporting_document_refusal.supportable, + attached_object: supporting_document_refusal + when 'Child' + NotificationCenter.call type: 'notify_admin_user_child_supporting_document_refusal', + receiver: User.admins_and_managers, + attached_object: SupportingDocumentRefusal.last + NotificationCenter.call type: 'notify_user_child_supporting_document_refusal', + receiver: SupportingDocumentRefusal.last.supportable.user, + attached_object: SupportingDocumentRefusal.last + end end saved end diff --git a/app/views/api/notifications/_notify_admin_user_child_supporting_document_refusal.json.jbuilder b/app/views/api/notifications/_notify_admin_user_child_supporting_document_refusal.json.jbuilder new file mode 100644 index 000000000..9d95c480d --- /dev/null +++ b/app/views/api/notifications/_notify_admin_user_child_supporting_document_refusal.json.jbuilder @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +json.title notification.notification_type +json.description t('.refusal', + NAME: notification.attached_object&.supportable&.full_name || t('api.notifications.deleted_user')) diff --git a/app/views/api/notifications/_notify_user_child_supporting_document_refusal.json.jbuilder b/app/views/api/notifications/_notify_user_child_supporting_document_refusal.json.jbuilder new file mode 100644 index 000000000..5a0cb327e --- /dev/null +++ b/app/views/api/notifications/_notify_user_child_supporting_document_refusal.json.jbuilder @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +json.title notification.notification_type +json.description t('.refusal') diff --git a/app/views/notifications_mailer/notify_admin_user_child_supporting_document_refusal.html.erb b/app/views/notifications_mailer/notify_admin_user_child_supporting_document_refusal.html.erb new file mode 100644 index 000000000..bb97ca950 --- /dev/null +++ b/app/views/notifications_mailer/notify_admin_user_child_supporting_document_refusal.html.erb @@ -0,0 +1,15 @@ +<%= render 'notifications_mailer/shared/hello', recipient: @recipient %> + +

+ <%= t('.body.user_child_supporting_document_files_refusal', + NAME: @attached_object&.supportable&.full_name || t('api.notifications.deleted_user'), + OPERATOR: @attached_object&.operator&.profile&.full_name || t('api.notifications.deleted_user')) %> +

+
    + <% @attached_object.supporting_document_types.each do |type| %> +
  • <%= type.name %>
  • + <% end %> +
+

+ <%= @attached_object.message %> +

diff --git a/app/views/notifications_mailer/notify_user_child_supporting_document_refusal.html.erb b/app/views/notifications_mailer/notify_user_child_supporting_document_refusal.html.erb new file mode 100644 index 000000000..7596b4e58 --- /dev/null +++ b/app/views/notifications_mailer/notify_user_child_supporting_document_refusal.html.erb @@ -0,0 +1,16 @@ +<%= render 'notifications_mailer/shared/hello', recipient: @recipient %> + +

+ <%= t('.body.user_child_supporting_document_files_refusal') %> +

+
    + <% @attached_object.supporting_document_types.each do |type| %> +
  • <%= type.name %>
  • + <% end %> +
+

+ <%= @attached_object.message %> +

+

+ <%= t('.body.action') %> +

diff --git a/config/locales/app.logged.en.yml b/config/locales/app.logged.en.yml index b904d16eb..325bce3a2 100644 --- a/config/locales/app.logged.en.yml +++ b/config/locales/app.logged.en.yml @@ -291,6 +291,7 @@ en: notify_admin_import_complete: "An import is done" notify_admin_user_group_changed: "A user has changed his group" notify_admin_user_supporting_document_refusal: "A supporting document has been rejected" + notify_admin_user_child_supporting_document_refusal: "A supporting document of child has been rejected" notify_admin_user_supporting_document_files_created: "A user has uploaded a supporting document" notify_admin_user_supporting_document_files_updated: "A user has updated a supporting document" notify_admin_member_create_reservation: "A member books a reservation" diff --git a/config/locales/app.logged.fr.yml b/config/locales/app.logged.fr.yml index de8004863..1e3a76683 100644 --- a/config/locales/app.logged.fr.yml +++ b/config/locales/app.logged.fr.yml @@ -291,6 +291,7 @@ fr: notify_admin_import_complete: "Un import est terminé" notify_admin_user_group_changed: "Un utilisateur a changé de groupe" notify_admin_user_supporting_document_refusal: "Un justificatif a été refusé" + notify_admin_user_child_supporting_document_refusal: "Un justificatif de l'enfant a été refusé" notify_admin_user_supporting_document_files_created: "Un utilisateur a téléversé un justificatif" notify_admin_user_supporting_document_files_updated: "Un utilisateur a mis à jour un justificatif" notify_admin_member_create_reservation: "Un membre fait une réservation" diff --git a/config/locales/app.public.en.yml b/config/locales/app.public.en.yml index 04786736e..a033552dc 100644 --- a/config/locales/app.public.en.yml +++ b/config/locales/app.public.en.yml @@ -492,6 +492,7 @@ en: phone: "Phone" save: "Save" to_complete: "To complete" + refuse_documents: "Refusing the documents" 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 810682530..564097f84 100644 --- a/config/locales/app.public.fr.yml +++ b/config/locales/app.public.fr.yml @@ -492,6 +492,7 @@ fr: phone: "Téléphone" save: "Enregistrer" to_complete: "À compléter" + refuse_documents: "Refuser les documents" child_item: first_name: "Prénom de l'enfant" last_name: "Nom de l'enfant" diff --git a/config/locales/en.yml b/config/locales/en.yml index f3b148b89..4106c6df1 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -449,6 +449,10 @@ en: refusal: "Your supporting documents were refused" notify_admin_user_supporting_document_refusal: refusal: "Member's supporting document %{NAME} was refused." + notify_user_child_supporting_document_refusal: + refusal: "Your child's supporting documents were refused" + notify_admin_user_child_supporting_document_refusal: + refusal: "Child's supporting document %{NAME} was refused." notify_user_order_is_ready: order_ready: "Your command %{REFERENCE} is ready" notify_user_order_is_canceled: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 092b677cd..c85575406 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -449,6 +449,10 @@ fr: refusal: "Vos pièces justificatives ont été refusées" notify_admin_user_supporting_document_refusal: refusal: "Le justificatif du membre %{NAME} a été refusé." + notify_user_child_supporting_document_refusal: + refusal: "Vos pièces justificatives de l'enfant ont été refusées" + notify_admin_user_child_supporting_document_refusal: + refusal: "Le justificatif de l'enfant %{NAME} a été refusé." notify_user_order_is_ready: order_ready: "Votre commande %{REFERENCE} est prête" notify_user_order_is_canceled: diff --git a/config/locales/mails.en.yml b/config/locales/mails.en.yml index 6151da3c6..3b3ac8981 100644 --- a/config/locales/mails.en.yml +++ b/config/locales/mails.en.yml @@ -406,6 +406,15 @@ en: subject: "A member's supporting documents were refused" body: user_supporting_document_files_refusal: "Member %{NAME}'s supporting documents were rejected by %{OPERATOR}:" + notify_user_child_supporting_document_refusal: + subject: "Your child's supporting documents were refused" + body: + user_child_supporting_document_files_refusal: "Your supporting documents were refused:" + action: "Please re-upload some new supporting documents." + notify_admin_user_child_supporting_document_refusal: + subject: "A child's supporting documents were refused" + body: + user_child_supporting_document_files_refusal: "Child %{NAME}'s supporting documents were rejected by %{OPERATOR}:" shared: hello: "Hello %{user_name}" notify_user_order_is_ready: diff --git a/config/locales/mails.fr.yml b/config/locales/mails.fr.yml index 0517ad9e2..23b94146d 100644 --- a/config/locales/mails.fr.yml +++ b/config/locales/mails.fr.yml @@ -406,6 +406,15 @@ fr: subject: "Les justificatifs d'un membre ont été refusés" body: user_supporting_document_files_refusal: "Le justificatif du membre %{NAME} a été refusé par %{OPERATOR} :" + notify_user_child_supporting_document_refusal: + subject: "Vos pièces justificatives de l'enfant ont été refusées" + body: + user_child_supporting_document_files_refusal: "Vos pièces justificatives ont été refusées :" + action: "Veuillez téléverser de nouvelles pièces justificatives." + notify_admin_user_child_supporting_document_refusal: + subject: "Les justificatifs d'un enfant ont été refusés" + body: + user_child_supporting_document_files_refusal: "Le justificatif de l'enfant %{NAME} a été refusé par %{OPERATOR} :" shared: hello: "Bonjour %{user_name}" notify_user_order_is_ready: diff --git a/db/seeds/notification_types.rb b/db/seeds/notification_types.rb index 8dbe8dc68..d73b0be90 100644 --- a/db/seeds/notification_types.rb +++ b/db/seeds/notification_types.rb @@ -31,3 +31,19 @@ unless NotificationType.find_by(name: 'notify_member_reservation_limit_reached') is_configurable: false ) end + +unless NotificationType.find_by(name: 'notify_admin_user_child_supporting_document_refusal') + NotificationType.create!( + name: 'notify_admin_user_child_supporting_document_refusal', + category: 'supporting_documents', + is_configurable: true + ) +end + +unless NotificationType.find_by(name: 'notify_user_child_supporting_document_refusal') + NotificationType.create!( + name: 'notify_user_child_supporting_document_refusal', + category: 'supporting_documents', + is_configurable: false + ) +end