1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-22 11:52:21 +01:00

(feat) admin can refuse child's supporting document file

This commit is contained in:
Du Peng 2023-05-26 12:54:39 +02:00
parent f1d3fdf2de
commit 42946effe0
22 changed files with 172 additions and 24 deletions

View File

@ -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<SupportingDocumentType>;
onSuccess: (message: string) => void,
onError: (message: string) => void,
}
/**
* A form for creating or editing a child.
*/
export const ChildForm: React.FC<ChildFormProps> = ({ child, onSubmit, supportingDocumentsTypes, operator }) => {
export const ChildForm: React.FC<ChildFormProps> = ({ child, onSubmit, supportingDocumentsTypes, operator, onSuccess, onError }) => {
const { t } = useTranslation('public');
const { register, formState, handleSubmit, setValue, control } = useForm<Child>({
defaultValues: child
});
const output = useWatch<Child>({ control }); // eslint-disable-line
const [refuseModalIsOpen, setRefuseModalIsOpen] = useState<boolean>(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<ChildFormProps> = ({ 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 (
<div className="child-form">
{isPrivileged() &&
{!isPrivileged() &&
<div className="info-area">
{t('app.public.child_form.child_form_info')}
</div>
@ -113,6 +135,20 @@ export const ChildForm: React.FC<ChildFormProps> = ({ child, onSubmit, supportin
<FabButton type="button" onClick={handleSubmit(onSubmit)}>
{t('app.public.child_form.save')}
</FabButton>
{isPrivileged() &&
<div>
<FabButton className="refuse-btn" onClick={toggleRefuseModal}>{t('app.public.child_form.refuse_documents')}</FabButton>
<SupportingDocumentsRefusalModal
isOpen={refuseModalIsOpen}
proofOfIdentityTypes={supportingDocumentsTypes}
toggleModal={toggleRefuseModal}
operator={operator}
supportable={child}
documentType="Child"
onError={onError}
onSuccess={onSaveRefusalSuccess} />
</div>
}
</div>
</form>
</div>

View File

@ -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<SupportingDocumentType>;
}
@ -35,7 +35,7 @@ export const ChildModal: React.FC<ChildModalProps> = ({ child, isOpen, toggleMod
await ChildAPI.create(data);
}
toggleModal();
onSuccess(data, '');
onSuccess('');
} catch (error) {
onError(error);
}
@ -51,7 +51,14 @@ export const ChildModal: React.FC<ChildModalProps> = ({ child, isOpen, toggleMod
{(operator?.role === 'admin' || operator?.role === 'manager') &&
<ChildValidation child={child} onSuccess={onSuccess} onError={onError} />
}
<ChildForm child={child} onSubmit={handleSaveChild} supportingDocumentsTypes={supportingDocumentsTypes} operator={operator}/>
<ChildForm
child={child}
onSubmit={handleSaveChild}
supportingDocumentsTypes={supportingDocumentsTypes}
operator={operator}
onSuccess={onSuccess}
onError={onError}
/>
</FabModal>
);
};

View File

@ -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<ChildValidationProps> = ({ 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);

View File

@ -78,7 +78,7 @@ export const ChildrenList: React.FC<ChildrenListProps> = ({ 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);

View File

@ -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<SupportingDocumentType>,
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<SupportingDocumentsRefusalModalProps> = ({ isOpen, toggleModal, onSuccess, proofOfIdentityTypes, operator, member, onError }) => {
export const SupportingDocumentsRefusalModal: React.FC<SupportingDocumentsRefusalModalProps> = ({ isOpen, toggleModal, onSuccess, proofOfIdentityTypes, operator, supportable, onError, documentType }) => {
const { t } = useTranslation('admin');
const [data, setData] = useState<SupportingDocumentRefusal>({
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: ''
});

View File

@ -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<SupportingDocumentsValidationProps> = ({ operator, member, onSuccess, onError }) => {
const SupportingDocumentsValidation: React.FC<SupportingDocumentsValidationProps> = ({ operator, member, onSuccess, onError, documentType }) => {
const { t } = useTranslation('admin');
// list of supporting documents type
@ -112,7 +113,8 @@ const SupportingDocumentsValidation: React.FC<SupportingDocumentsValidationProps
proofOfIdentityTypes={documentsTypes}
toggleModal={toggleModal}
operator={operator}
member={member}
supportable={member}
documentType={documentType}
onError={onError}
onSuccess={onSaveRefusalSuccess}/>
</FabPanel>
@ -131,4 +133,4 @@ const SupportingDocumentsValidationWrapper: React.FC<SupportingDocumentsValidati
export { SupportingDocumentsValidationWrapper as SupportingDocumentsValidation };
Application.Components.component('supportingDocumentsValidation', react2angular(SupportingDocumentsValidationWrapper, ['operator', 'member', 'onSuccess', 'onError']));
Application.Components.component('supportingDocumentsValidation', react2angular(SupportingDocumentsValidationWrapper, ['operator', 'member', 'onSuccess', 'onError', 'documentType']));

View File

@ -70,6 +70,7 @@
<supporting-documents-validation
operator="currentUser"
member="user"
document-type="User"
on-error="onError"
on-success="onSuccess" />
</uib-tab>

View File

@ -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

View File

@ -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

View File

@ -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'))

View File

@ -0,0 +1,4 @@
# frozen_string_literal: true
json.title notification.notification_type
json.description t('.refusal')

View File

@ -0,0 +1,15 @@
<%= render 'notifications_mailer/shared/hello', recipient: @recipient %>
<p>
<%= 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')) %>
</p>
<ul>
<% @attached_object.supporting_document_types.each do |type| %>
<li><%= type.name %></li>
<% end %>
</ul>
<p>
<%= @attached_object.message %>
</p>

View File

@ -0,0 +1,16 @@
<%= render 'notifications_mailer/shared/hello', recipient: @recipient %>
<p>
<%= t('.body.user_child_supporting_document_files_refusal') %>
</p>
<ul>
<% @attached_object.supporting_document_types.each do |type| %>
<li><%= type.name %></li>
<% end %>
</ul>
<p>
<%= @attached_object.message %>
</p>
<p>
<%= t('.body.action') %>
</p>

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -449,6 +449,10 @@ en:
refusal: "Your supporting documents were refused"
notify_admin_user_supporting_document_refusal:
refusal: "Member's supporting document <strong><em>%{NAME}</strong></em> 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 <strong><em>%{NAME}</strong></em> was refused."
notify_user_order_is_ready:
order_ready: "Your command %{REFERENCE} is ready"
notify_user_order_is_canceled:

View File

@ -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 <strong><em>%{NAME}</strong></em> 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 <strong><em>%{NAME}</strong></em> a été refusé."
notify_user_order_is_ready:
order_ready: "Votre commande %{REFERENCE} est prête"
notify_user_order_is_canceled:

View File

@ -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:

View File

@ -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:

View File

@ -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