mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-09 03:54:23 +01:00
(ui) integration
This commit is contained in:
parent
e17c0be064
commit
c019f3ad3e
@ -10,6 +10,7 @@ import { FileType } from '../../models/file';
|
|||||||
import { SupportingDocumentType } from '../../models/supporting-document-type';
|
import { SupportingDocumentType } from '../../models/supporting-document-type';
|
||||||
import { User } from '../../models/user';
|
import { User } from '../../models/user';
|
||||||
import { SupportingDocumentsRefusalModal } from '../supporting-documents/supporting-documents-refusal-modal';
|
import { SupportingDocumentsRefusalModal } from '../supporting-documents/supporting-documents-refusal-modal';
|
||||||
|
import { FabAlert } from '../base/fab-alert';
|
||||||
|
|
||||||
interface ChildFormProps {
|
interface ChildFormProps {
|
||||||
child: Child;
|
child: Child;
|
||||||
@ -65,11 +66,12 @@ export const ChildForm: React.FC<ChildFormProps> = ({ child, onSubmit, supportin
|
|||||||
return (
|
return (
|
||||||
<div className="child-form">
|
<div className="child-form">
|
||||||
{!isPrivileged() &&
|
{!isPrivileged() &&
|
||||||
<div className="info-area">
|
<FabAlert level='info'>
|
||||||
{t('app.public.child_form.child_form_info')}
|
<p>{t('app.public.child_form.child_form_info')}</p>
|
||||||
</div>
|
</FabAlert>
|
||||||
}
|
}
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<div className="grp">
|
||||||
<FormInput id="first_name"
|
<FormInput id="first_name"
|
||||||
register={register}
|
register={register}
|
||||||
rules={{ required: true }}
|
rules={{ required: true }}
|
||||||
@ -82,6 +84,8 @@ export const ChildForm: React.FC<ChildFormProps> = ({ child, onSubmit, supportin
|
|||||||
formState={formState}
|
formState={formState}
|
||||||
label={t('app.public.child_form.last_name')}
|
label={t('app.public.child_form.last_name')}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="grp">
|
||||||
<FormInput id="birthday"
|
<FormInput id="birthday"
|
||||||
register={register}
|
register={register}
|
||||||
rules={{ required: true, validate: (value) => moment(value).isAfter(moment().subtract(18, 'year')) }}
|
rules={{ required: true, validate: (value) => moment(value).isAfter(moment().subtract(18, 'year')) }}
|
||||||
@ -97,28 +101,16 @@ export const ChildForm: React.FC<ChildFormProps> = ({ child, onSubmit, supportin
|
|||||||
label={t('app.public.child_form.phone')}
|
label={t('app.public.child_form.phone')}
|
||||||
type="tel"
|
type="tel"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
<FormInput id="email"
|
<FormInput id="email"
|
||||||
register={register}
|
register={register}
|
||||||
formState={formState}
|
formState={formState}
|
||||||
label={t('app.public.child_form.email')}
|
label={t('app.public.child_form.email')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{!isPrivileged() && <>
|
||||||
|
<h3 className="missing-file">{t('app.public.child_form.supporting_documents')}</h3>
|
||||||
{output.supporting_document_files_attributes.map((sf, index) => {
|
{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 (
|
return (
|
||||||
<FormFileUpload key={index}
|
<FormFileUpload key={index}
|
||||||
defaultFile={sf as FileType}
|
defaultFile={sf as FileType}
|
||||||
@ -131,14 +123,46 @@ export const ChildForm: React.FC<ChildFormProps> = ({ child, onSubmit, supportin
|
|||||||
formState={formState} />
|
formState={formState} />
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
</>}
|
||||||
|
|
||||||
<div className="actions">
|
<div className="actions">
|
||||||
<FabButton type="button" onClick={handleSubmit(onSubmit)}>
|
<FabButton type="button" className='is-secondary' onClick={handleSubmit(onSubmit)}>
|
||||||
{t('app.public.child_form.save')}
|
{t('app.public.child_form.save')}
|
||||||
</FabButton>
|
</FabButton>
|
||||||
{isPrivileged() &&
|
</div>
|
||||||
<div>
|
|
||||||
<FabButton className="refuse-btn" onClick={toggleRefuseModal}>{t('app.public.child_form.refuse_documents')}</FabButton>
|
{isPrivileged() && <>
|
||||||
|
<h3 className="missing-file">{t('app.public.child_form.supporting_documents')}</h3>
|
||||||
|
<div className="document-list">
|
||||||
|
{output.supporting_document_files_attributes.map((sf, index) => {
|
||||||
|
return (
|
||||||
|
<div key={index} className="document-list-item">
|
||||||
|
<span className="type">{getSupportingDocumentsTypeName(sf.supporting_document_type_id)}</span>
|
||||||
|
{sf.attachment_url && (
|
||||||
|
<div className='file'>
|
||||||
|
<p>{sf.attachment}</p>
|
||||||
|
<a href={sf.attachment_url} target="_blank" rel="noreferrer" className='fab-button is-black'>
|
||||||
|
<span className="fab-button--icon-only"><i className="fas fa-eye"></i></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!sf.attachment_url && (
|
||||||
|
<div className="missing">
|
||||||
|
<p>{t('app.public.child_form.to_complete')}</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</>}
|
||||||
|
|
||||||
|
{isPrivileged() && <>
|
||||||
|
<FabAlert level='info'>
|
||||||
|
<p>{t('app.public.child_form.refuse_documents_info')}</p>
|
||||||
|
</FabAlert>
|
||||||
|
<div className="actions">
|
||||||
|
<FabButton className="refuse-btn is-secondary" onClick={toggleRefuseModal}>{t('app.public.child_form.refuse_documents')}</FabButton>
|
||||||
<SupportingDocumentsRefusalModal
|
<SupportingDocumentsRefusalModal
|
||||||
isOpen={refuseModalIsOpen}
|
isOpen={refuseModalIsOpen}
|
||||||
proofOfIdentityTypes={supportingDocumentsTypes}
|
proofOfIdentityTypes={supportingDocumentsTypes}
|
||||||
@ -149,8 +173,7 @@ export const ChildForm: React.FC<ChildFormProps> = ({ child, onSubmit, supportin
|
|||||||
onError={onError}
|
onError={onError}
|
||||||
onSuccess={onSaveRefusalSuccess} />
|
onSuccess={onSaveRefusalSuccess} />
|
||||||
</div>
|
</div>
|
||||||
}
|
</>}
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -5,9 +5,11 @@ import { FabButton } from '../base/fab-button';
|
|||||||
import FormatLib from '../../lib/format';
|
import FormatLib from '../../lib/format';
|
||||||
import { DeleteChildModal } from './delete-child-modal';
|
import { DeleteChildModal } from './delete-child-modal';
|
||||||
import ChildAPI from '../../api/child';
|
import ChildAPI from '../../api/child';
|
||||||
|
import { PencilSimple, Trash, UserSquare } from 'phosphor-react';
|
||||||
|
|
||||||
interface ChildItemProps {
|
interface ChildItemProps {
|
||||||
child: Child;
|
child: Child;
|
||||||
|
size: 'sm' | 'lg';
|
||||||
onEdit: (child: Child) => void;
|
onEdit: (child: Child) => void;
|
||||||
onDelete: (error: string) => void;
|
onDelete: (error: string) => void;
|
||||||
onError: (error: string) => void;
|
onError: (error: string) => void;
|
||||||
@ -16,7 +18,7 @@ interface ChildItemProps {
|
|||||||
/**
|
/**
|
||||||
* A child item.
|
* A child item.
|
||||||
*/
|
*/
|
||||||
export const ChildItem: React.FC<ChildItemProps> = ({ child, onEdit, onDelete, onError }) => {
|
export const ChildItem: React.FC<ChildItemProps> = ({ child, size, onEdit, onDelete, onError }) => {
|
||||||
const { t } = useTranslation('public');
|
const { t } = useTranslation('public');
|
||||||
const [isOpenDeleteChildModal, setIsOpenDeleteChildModal] = React.useState<boolean>(false);
|
const [isOpenDeleteChildModal, setIsOpenDeleteChildModal] = React.useState<boolean>(false);
|
||||||
|
|
||||||
@ -38,22 +40,29 @@ export const ChildItem: React.FC<ChildItemProps> = ({ child, onEdit, onDelete, o
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="child-item">
|
<div className={`child-item ${size} ${child.validated_at ? 'is-validated' : ''}`}>
|
||||||
<div className="child-lastname">
|
<div className='status'>
|
||||||
|
<UserSquare size={24} weight="light" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<span>{t('app.public.child_item.last_name')}</span>
|
<span>{t('app.public.child_item.last_name')}</span>
|
||||||
<div>{child.last_name}</div>
|
<p>{child.last_name}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="child-firstname">
|
<div>
|
||||||
<span>{t('app.public.child_item.first_name')}</span>
|
<span>{t('app.public.child_item.first_name')}</span>
|
||||||
<div>{child.first_name}</div>
|
<p>{child.first_name}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="date">
|
<div>
|
||||||
<span>{t('app.public.child_item.birthday')}</span>
|
<span>{t('app.public.child_item.birthday')}</span>
|
||||||
<div>{FormatLib.date(child.birthday)}</div>
|
<p>{FormatLib.date(child.birthday)}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="actions">
|
<div className="actions edit-destroy-buttons">
|
||||||
<FabButton icon={<i className="fa fa-edit" />} onClick={() => onEdit(child)} className="edit-button" />
|
<FabButton onClick={() => onEdit(child)} className="edit-btn">
|
||||||
<FabButton icon={<i className="fa fa-trash" />} onClick={toggleDeleteChildModal} className="delete-button" />
|
<PencilSimple size={20} weight="fill" />
|
||||||
|
</FabButton>
|
||||||
|
<FabButton onClick={toggleDeleteChildModal} className="delete-btn">
|
||||||
|
<Trash size={20} weight="fill" />
|
||||||
|
</FabButton>
|
||||||
<DeleteChildModal isOpen={isOpenDeleteChildModal} toggleModal={toggleDeleteChildModal} child={child} onDelete={deleteChild} />
|
<DeleteChildModal isOpen={isOpenDeleteChildModal} toggleModal={toggleDeleteChildModal} child={child} onDelete={deleteChild} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,9 +14,10 @@ import SupportingDocumentTypeAPI from '../../api/supporting-document-type';
|
|||||||
|
|
||||||
declare const Application: IApplication;
|
declare const Application: IApplication;
|
||||||
|
|
||||||
interface ChildrenListProps {
|
interface ChildrenDashboardProps {
|
||||||
user: User;
|
user: User;
|
||||||
operator: User;
|
operator: User;
|
||||||
|
adminPanel?: boolean;
|
||||||
onSuccess: (error: string) => void;
|
onSuccess: (error: string) => void;
|
||||||
onError: (error: string) => void;
|
onError: (error: string) => void;
|
||||||
}
|
}
|
||||||
@ -24,7 +25,7 @@ interface ChildrenListProps {
|
|||||||
/**
|
/**
|
||||||
* A list of children belonging to the current user.
|
* A list of children belonging to the current user.
|
||||||
*/
|
*/
|
||||||
export const ChildrenList: React.FC<ChildrenListProps> = ({ user, operator, onError, onSuccess }) => {
|
export const ChildrenDashboard: React.FC<ChildrenDashboardProps> = ({ user, operator, adminPanel, onError, onSuccess }) => {
|
||||||
const { t } = useTranslation('public');
|
const { t } = useTranslation('public');
|
||||||
|
|
||||||
const [children, setChildren] = useState<Array<Child>>([]);
|
const [children, setChildren] = useState<Array<Child>>([]);
|
||||||
@ -92,19 +93,24 @@ export const ChildrenList: React.FC<ChildrenListProps> = ({ user, operator, onEr
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section className='children-dashboard'>
|
||||||
<header>
|
<header>
|
||||||
<h2>{t('app.public.children_list.heading')}</h2>
|
{adminPanel
|
||||||
|
? <h2>{t('app.public.children_dashboard.heading')}</h2>
|
||||||
|
: <h2>{t('app.public.children_dashboard.member_heading')}</h2>
|
||||||
|
}
|
||||||
{!isPrivileged() && (
|
{!isPrivileged() && (
|
||||||
<FabButton onClick={addChild}>
|
<div className="grpBtn">
|
||||||
{t('app.public.children_list.add_child')}
|
<FabButton className="main-action-btn" onClick={addChild}>
|
||||||
|
{t('app.public.children_dashboard.add_child')}
|
||||||
</FabButton>
|
</FabButton>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div className="children-list">
|
<div className="children-list">
|
||||||
{children.map(child => (
|
{children.map(child => (
|
||||||
<ChildItem key={child.id} child={child} onEdit={editChild} onDelete={handleDeleteChildSuccess} onError={onError} />
|
<ChildItem key={child.id} child={child} size='lg' onEdit={editChild} onDelete={handleDeleteChildSuccess} onError={onError} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<ChildModal child={child} isOpen={isOpenChildModal} toggleModal={() => setIsOpenChildModal(false)} onSuccess={handleSaveChildSuccess} onError={onError} supportingDocumentsTypes={supportingDocumentsTypes} operator={operator} />
|
<ChildModal child={child} isOpen={isOpenChildModal} toggleModal={() => setIsOpenChildModal(false)} onSuccess={handleSaveChildSuccess} onError={onError} supportingDocumentsTypes={supportingDocumentsTypes} operator={operator} />
|
||||||
@ -112,12 +118,12 @@ export const ChildrenList: React.FC<ChildrenListProps> = ({ user, operator, onEr
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ChildrenListWrapper: React.FC<ChildrenListProps> = (props) => {
|
const ChildrenDashboardWrapper: React.FC<ChildrenDashboardProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<Loader>
|
<Loader>
|
||||||
<ChildrenList {...props} />
|
<ChildrenDashboard {...props} />
|
||||||
</Loader>
|
</Loader>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
Application.Components.component('childrenList', react2angular(ChildrenListWrapper, ['user', 'operator', 'onSuccess', 'onError']));
|
Application.Components.component('childrenDashboard', react2angular(ChildrenDashboardWrapper, ['user', 'operator', 'adminPanel', 'onSuccess', 'onError']));
|
@ -75,9 +75,10 @@ export const FormFileUpload = <TFieldValues extends FieldValues>({ id, label, re
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`form-file-upload ${label ? 'with-label' : ''} ${classNames}`}>
|
<div className={`form-file-upload ${label ? 'with-label' : ''} ${classNames}`}>
|
||||||
{hasFile() && (
|
{hasFile()
|
||||||
<span>{file.attachment_name}</span>
|
? <span>{file.attachment_name}</span>
|
||||||
)}
|
: <span className='placeholder'>{t('app.shared.form_file_upload.placeholder')}</span>
|
||||||
|
}
|
||||||
<div className="actions">
|
<div className="actions">
|
||||||
{file?.id && file?.attachment_url && (
|
{file?.id && file?.attachment_url && (
|
||||||
<a href={file.attachment_url}
|
<a href={file.attachment_url}
|
||||||
|
@ -15,6 +15,7 @@ import SupportingDocumentTypeAPI from '../../api/supporting-document-type';
|
|||||||
import { FabPanel } from '../base/fab-panel';
|
import { FabPanel } from '../base/fab-panel';
|
||||||
import { FabAlert } from '../base/fab-alert';
|
import { FabAlert } from '../base/fab-alert';
|
||||||
import { FabButton } from '../base/fab-button';
|
import { FabButton } from '../base/fab-button';
|
||||||
|
import { PencilSimple, Trash } from 'phosphor-react';
|
||||||
|
|
||||||
declare const Application: IApplication;
|
declare const Application: IApplication;
|
||||||
|
|
||||||
@ -248,12 +249,12 @@ const SupportingDocumentsTypesList: React.FC<SupportingDocumentsTypesListProps>
|
|||||||
<td>{getGroupsNames(poit.group_ids)}</td>
|
<td>{getGroupsNames(poit.group_ids)}</td>
|
||||||
<td>{poit.name}</td>
|
<td>{poit.name}</td>
|
||||||
<td>
|
<td>
|
||||||
<div className="buttons">
|
<div className="edit-destroy-buttons">
|
||||||
<FabButton className="edit-btn" onClick={editType(poit)}>
|
<FabButton className="edit-btn" onClick={editType(poit)}>
|
||||||
<i className="fa fa-edit" />
|
<PencilSimple size={20} weight="fill" />
|
||||||
</FabButton>
|
</FabButton>
|
||||||
<FabButton className="delete-btn" onClick={destroyType(poit.id)}>
|
<FabButton className="delete-btn" onClick={destroyType(poit.id)}>
|
||||||
<i className="fa fa-trash" />
|
<Trash size={20} weight="fill" />
|
||||||
</FabButton>
|
</FabButton>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@ -292,38 +293,26 @@ const SupportingDocumentsTypesList: React.FC<SupportingDocumentsTypesListProps>
|
|||||||
onSuccess={onDestroySuccess}
|
onSuccess={onDestroySuccess}
|
||||||
onError={onError}/>
|
onError={onError}/>
|
||||||
|
|
||||||
<table>
|
<div className="document-list">
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th className="name">
|
|
||||||
<a onClick={setTypeOrder('name')}>
|
|
||||||
{t('app.admin.settings.account.supporting_documents_types_list.name')}
|
|
||||||
<i className={orderClassName('name')} />
|
|
||||||
</a>
|
|
||||||
</th>
|
|
||||||
<th className="actions"></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{supportingDocumentsTypes.map(poit => {
|
{supportingDocumentsTypes.map(poit => {
|
||||||
return (
|
return (
|
||||||
<tr key={poit.id}>
|
<div key={poit.id} className="document-list-item">
|
||||||
<td>{poit.name}</td>
|
<div className='file'>
|
||||||
<td>
|
<p>{poit.name}</p>
|
||||||
<div className="buttons">
|
<div className="edit-destroy-buttons">
|
||||||
<FabButton className="edit-btn" onClick={editType(poit)}>
|
<FabButton className="edit-btn" onClick={editType(poit)}>
|
||||||
<i className="fa fa-edit" />
|
<PencilSimple size={20} weight="fill" />
|
||||||
</FabButton>
|
</FabButton>
|
||||||
<FabButton className="delete-btn" onClick={destroyType(poit.id)}>
|
<FabButton className="delete-btn" onClick={destroyType(poit.id)}>
|
||||||
<i className="fa fa-trash" />
|
<Trash size={20} weight="fill" />
|
||||||
</FabButton>
|
</FabButton>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</tbody>
|
</div>
|
||||||
</table>
|
|
||||||
{!hasTypes() && (
|
{!hasTypes() && (
|
||||||
<p className="no-types-info">
|
<p className="no-types-info">
|
||||||
<HtmlTranslate trKey="app.admin.settings.account.supporting_documents_types_list.no_types" />
|
<HtmlTranslate trKey="app.admin.settings.account.supporting_documents_types_list.no_types" />
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { Member } from '../../models/member';
|
||||||
|
import { Child } from '../../models/child';
|
||||||
|
import ChildAPI from '../../api/child';
|
||||||
|
import { FabButton } from '../base/fab-button';
|
||||||
|
import { CaretDown, User, Users } from 'phosphor-react';
|
||||||
|
import { ChildItem } from '../family-account/child-item';
|
||||||
|
import { EditDestroyButtons } from '../base/edit-destroy-buttons';
|
||||||
|
|
||||||
|
interface MembersListItemProps {
|
||||||
|
member: Member,
|
||||||
|
onError: (message: string) => void,
|
||||||
|
onSuccess: (message: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Members list
|
||||||
|
*/
|
||||||
|
export const MembersListItem: React.FC<MembersListItemProps> = ({ member, onError, onSuccess }) => {
|
||||||
|
const { t } = useTranslation('admin');
|
||||||
|
|
||||||
|
const [children, setChildren] = useState<Array<Child>>([]);
|
||||||
|
const [childrenList, setChildrenList] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
ChildAPI.index({ user_id: member.id }).then(setChildren);
|
||||||
|
}, [member]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect to the given user edition page
|
||||||
|
*/
|
||||||
|
const toMemberEdit = (memberId: number): void => {
|
||||||
|
window.location.href = `/#!/admin/members/${memberId}/edit`;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={member.id} className={`members-list-item ${member.validated_at ? 'is-validated' : ''} ${member.need_completion ? 'is-incomplet' : ''}`}>
|
||||||
|
<div className="left-col">
|
||||||
|
<div className='status'>
|
||||||
|
{(children.length > 0)
|
||||||
|
? <Users size={24} weight="bold" />
|
||||||
|
: <User size={24} weight="bold" />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
{(children.length > 0) &&
|
||||||
|
<FabButton onClick={() => setChildrenList(!childrenList)} className={`toggle ${childrenList ? 'open' : ''}`}>
|
||||||
|
<CaretDown size={24} weight="bold" />
|
||||||
|
</FabButton>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="member">
|
||||||
|
<div className="member-infos">
|
||||||
|
<div>
|
||||||
|
<span>{t('app.admin.members_list_item.surname')}</span>
|
||||||
|
<p>{member.profile.last_name}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>{t('app.admin.members_list_item.first_name')}</span>
|
||||||
|
<p>{member.profile.first_name}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>{t('app.admin.members_list_item.phone')}</span>
|
||||||
|
<p>{member.profile.phone || '---'}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>{t('app.admin.members_list_item.email')}</span>
|
||||||
|
<p>{member.email}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>{t('app.admin.members_list_item.group')}</span>
|
||||||
|
<p>{member.group.name}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>{t('app.admin.members_list_item.subscription')}</span>
|
||||||
|
<p>{member.subscribed_plan?.name || '---'}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="member-actions">
|
||||||
|
{/* TODO: <EditDestroyButtons> */}
|
||||||
|
<EditDestroyButtons onError={onError}
|
||||||
|
onEdit={() => toMemberEdit(member.id)}
|
||||||
|
onDeleteSuccess={() => onSuccess}
|
||||||
|
itemId={member.id}
|
||||||
|
itemType={t('app.admin.members_list_item.item_type')}
|
||||||
|
destroy={() => new Promise(() => console.log(`Delete member ${member.id}`))} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{ (children.length > 0) &&
|
||||||
|
<div className={`member-children ${childrenList ? 'open' : ''}`}>
|
||||||
|
<hr />
|
||||||
|
{children.map(child => (
|
||||||
|
<ChildItem key={child.id} child={child} size='sm' onEdit={() => console.log('edit child')} onDelete={() => console.log('delete child')} onError={onError} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
37
app/frontend/src/javascript/components/user/members-list.tsx
Normal file
37
app/frontend/src/javascript/components/user/members-list.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { IApplication } from '../../models/application';
|
||||||
|
import { Loader } from '../base/loader';
|
||||||
|
import { react2angular } from 'react2angular';
|
||||||
|
import { Member } from '../../models/member';
|
||||||
|
import { MembersListItem } from './members-list-item';
|
||||||
|
|
||||||
|
declare const Application: IApplication;
|
||||||
|
|
||||||
|
interface MembersListProps {
|
||||||
|
members: Member[],
|
||||||
|
onError: (message: string) => void,
|
||||||
|
onSuccess: (message: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Members list
|
||||||
|
*/
|
||||||
|
export const MembersList: React.FC<MembersListProps> = ({ members, onError, onSuccess }) => {
|
||||||
|
return (
|
||||||
|
<div className="members-list">
|
||||||
|
{members.map(member => (
|
||||||
|
<MembersListItem key={member.id} member={member} onError={onError} onSuccess={onSuccess} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const MembersListWrapper: React.FC<MembersListProps> = (props) => {
|
||||||
|
return (
|
||||||
|
<Loader>
|
||||||
|
<MembersList {...props} />
|
||||||
|
</Loader>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Application.Components.component('membersList', react2angular(MembersListWrapper, ['members', 'onError', 'onSuccess']));
|
47
app/frontend/src/javascript/models/member.ts
Normal file
47
app/frontend/src/javascript/models/member.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { TDateISO } from '../typings/date-iso';
|
||||||
|
|
||||||
|
export interface Member {
|
||||||
|
maxMembers: number
|
||||||
|
id: number
|
||||||
|
username: string
|
||||||
|
email: string
|
||||||
|
profile: {
|
||||||
|
first_name: string
|
||||||
|
last_name: string
|
||||||
|
phone: string
|
||||||
|
}
|
||||||
|
need_completion?: boolean
|
||||||
|
group: {
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
subscribed_plan?: Plan
|
||||||
|
validated_at: TDateISO
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Plan {
|
||||||
|
id: number
|
||||||
|
base_name: string
|
||||||
|
name: string
|
||||||
|
amount: number
|
||||||
|
interval: string
|
||||||
|
interval_count: number
|
||||||
|
training_credit_nb: number
|
||||||
|
training_credits: [
|
||||||
|
{
|
||||||
|
training_id: number
|
||||||
|
},
|
||||||
|
{
|
||||||
|
training_id: number
|
||||||
|
}
|
||||||
|
]
|
||||||
|
machine_credits: [
|
||||||
|
{
|
||||||
|
machine_id: number
|
||||||
|
hours: number
|
||||||
|
},
|
||||||
|
{
|
||||||
|
machine_id: number
|
||||||
|
hours: number
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -52,6 +52,9 @@
|
|||||||
@import "modules/events/event-form";
|
@import "modules/events/event-form";
|
||||||
@import "modules/events/update-recurrent-modal";
|
@import "modules/events/update-recurrent-modal";
|
||||||
@import "modules/events/events-settings.scss";
|
@import "modules/events/events-settings.scss";
|
||||||
|
@import "modules/family-account/child-form";
|
||||||
|
@import "modules/family-account/child-item";
|
||||||
|
@import "modules/family-account/children-dashboard";
|
||||||
@import "modules/form/abstract-form-item";
|
@import "modules/form/abstract-form-item";
|
||||||
@import "modules/form/form-input";
|
@import "modules/form/form-input";
|
||||||
@import "modules/form/form-multi-file-upload";
|
@import "modules/form/form-multi-file-upload";
|
||||||
@ -181,8 +184,6 @@
|
|||||||
@import "modules/tour";
|
@import "modules/tour";
|
||||||
@import "modules/wallet-info";
|
@import "modules/wallet-info";
|
||||||
|
|
||||||
@import "modules/family-account/child-item";
|
|
||||||
|
|
||||||
@import "app.responsive";
|
@import "app.responsive";
|
||||||
|
|
||||||
@import "overrides";
|
@import "overrides";
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
.edit-destroy-buttons {
|
.edit-destroy-buttons {
|
||||||
|
width: fit-content;
|
||||||
|
flex-shrink: 0;
|
||||||
border-radius: var(--border-radius-sm);
|
border-radius: var(--border-radius-sm);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
button {
|
button {
|
||||||
@include btn;
|
@include btn;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
animation: 0.3s ease-out slideInFromTop;
|
animation: 0.3s ease-out slideInFromTop;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 90px;
|
top: 90px;
|
||||||
|
max-width: 100vw;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
|
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
.child-form {
|
||||||
|
.grp {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
@media (min-width: 640px) {flex-direction: row; }
|
||||||
|
|
||||||
|
.form-item:first-child { margin-right: 2.4rem; }
|
||||||
|
}
|
||||||
|
|
||||||
|
hr { width: 100%; }
|
||||||
|
.actions {
|
||||||
|
align-self: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.document-list {
|
||||||
|
margin-bottom: 1.6rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.6rem;
|
||||||
|
|
||||||
|
&-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.8rem;
|
||||||
|
.type {
|
||||||
|
@include text-sm;
|
||||||
|
}
|
||||||
|
.file,
|
||||||
|
.missing {
|
||||||
|
padding: 0.8rem 0.8rem 0.8rem 1.6rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
border: 1px solid var(--gray-soft-dark);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
p { margin: 0; }
|
||||||
|
}
|
||||||
|
.missing {
|
||||||
|
background-color: var(--gray-soft-light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,62 @@
|
|||||||
.child-item {
|
.child-item {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: repeat(3, min-content);
|
grid-template-columns: min-content 1fr;
|
||||||
grid-template-columns: 1fr 1fr;
|
align-items: flex-start;
|
||||||
gap: 1.6rem 2.4rem;
|
gap: 1.6rem 2.4rem;
|
||||||
align-items: center;
|
background-color: var(--gray-soft-lightest);
|
||||||
|
&.lg {
|
||||||
padding: 1.6rem;
|
padding: 1.6rem;
|
||||||
border: 1px solid var(--gray-soft-dark);
|
border: 1px solid var(--gray-soft-dark);
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
background-color: var(--gray-soft-lightest);
|
}
|
||||||
|
&.sm {
|
||||||
|
.actions button {
|
||||||
|
height: 3rem !important;
|
||||||
|
min-height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > div:not(.actions) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
span {
|
||||||
|
@include text-xs;
|
||||||
|
color: var(--gray-hard-light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
@include text-base(600);
|
||||||
|
}
|
||||||
|
&.sm p {
|
||||||
|
@include text-sm(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
grid-row: 1/5;
|
||||||
|
align-self: stretch;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
&.is-validated .status svg {
|
||||||
|
color: var(--success-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
align-self: center;
|
||||||
|
justify-self: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
grid-template-columns: min-content repeat(3, 1fr);
|
||||||
|
.status { grid-row: auto; }
|
||||||
|
.actions {
|
||||||
|
grid-column-end: -1;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
grid-template-columns: min-content repeat(3, 1fr) max-content;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
.children-dashboard {
|
||||||
|
max-width: 1600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding-bottom: 6rem;
|
||||||
|
@include grid-col(12);
|
||||||
|
gap: 3.2rem;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
header {
|
||||||
|
@include header();
|
||||||
|
padding-bottom: 0;
|
||||||
|
grid-column: 2 / -2;
|
||||||
|
}
|
||||||
|
.children-list {
|
||||||
|
grid-column: 2 / -2;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.6rem;
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,8 @@
|
|||||||
margin-bottom: 1.6rem;
|
margin-bottom: 1.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.placeholder { color: var(--gray-soft-darkest); }
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -2,3 +2,108 @@
|
|||||||
width: 16px;
|
width: 16px;
|
||||||
height: 21px;
|
height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.members-list {
|
||||||
|
width: 100%;
|
||||||
|
margin: 2.4rem 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2.4rem;
|
||||||
|
|
||||||
|
&-item {
|
||||||
|
width: 100%;
|
||||||
|
padding: 1.6rem;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 48px 1fr;
|
||||||
|
gap: 1.6rem 2.4rem;
|
||||||
|
border: 1px solid var(--gray-soft-dark);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
background-color: var(--gray-soft-lightest);
|
||||||
|
&.is-validated .left-col .status svg { color: var(--success-dark); }
|
||||||
|
&.is-incomplet .left-col .status svg { color: var(--alert); }
|
||||||
|
|
||||||
|
.left-col {
|
||||||
|
grid-row: span 2;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
.status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle {
|
||||||
|
height: fit-content;
|
||||||
|
background-color: var(--gray-soft);
|
||||||
|
border: none;
|
||||||
|
svg { transition: transform 0.5s ease-in-out; }
|
||||||
|
&.open svg { transform: rotate(-180deg); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.member {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2.4rem;
|
||||||
|
&-infos {
|
||||||
|
flex: 1;
|
||||||
|
display: grid;
|
||||||
|
gap: 1.6rem;
|
||||||
|
|
||||||
|
& > div:not(.actions) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
span {
|
||||||
|
@include text-xs;
|
||||||
|
color: var(--gray-hard-light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
@include text-base(600);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
&-actions {
|
||||||
|
align-self: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-children {
|
||||||
|
max-height: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.6rem;
|
||||||
|
overflow-y: hidden;
|
||||||
|
transition: max-height 0.5s ease-in-out;
|
||||||
|
&.open {
|
||||||
|
max-height: 17rem;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr { margin: 0; }
|
||||||
|
.child-item:last-of-type { padding-bottom: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.member-infos {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.member {
|
||||||
|
flex-direction: row;
|
||||||
|
&-actions {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width: 1220px) {
|
||||||
|
.member-infos {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -37,6 +37,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
|
margin-bottom: 1.6rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@ -54,22 +55,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
.document-list {
|
||||||
thead > tr {
|
display: grid;
|
||||||
th.group-name,
|
grid-template-columns: repeat(auto-fill, minmax(min-content, 50rem));
|
||||||
th.name {
|
gap: 1.6rem;
|
||||||
width: 40%
|
|
||||||
}
|
|
||||||
th.actions {
|
|
||||||
width: 20%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tbody {
|
&-item {
|
||||||
.buttons {
|
display: flex;
|
||||||
.edit-btn {
|
flex-direction: column;
|
||||||
margin-right: 5px;
|
gap: 0.8rem;
|
||||||
|
.type {
|
||||||
|
@include text-sm;
|
||||||
}
|
}
|
||||||
|
.file {
|
||||||
|
padding: 0.8rem 0.8rem 0.8rem 1.6rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
border: 1px solid var(--gray-soft-dark);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
p { margin: 0; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,3 +9,7 @@
|
|||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.child-validation {
|
||||||
|
margin: 0 0 2rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
@ -63,7 +63,7 @@
|
|||||||
</uib-tab>
|
</uib-tab>
|
||||||
|
|
||||||
<uib-tab heading="{{ 'app.shared.user_admin.children' | translate }}" ng-if="$root.settings.familyAccount">
|
<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" />
|
<children-dashboard user="user" operator="currentUser" admin-panel="true" on-success="onSuccess" on-error="onError" />
|
||||||
</uib-tab>
|
</uib-tab>
|
||||||
|
|
||||||
<uib-tab heading="{{ 'app.admin.members_edit.supporting_documents' | translate }}" ng-show="hasProofOfIdentityTypes">
|
<uib-tab heading="{{ 'app.admin.members_edit.supporting_documents' | translate }}" ng-show="hasProofOfIdentityTypes">
|
||||||
|
@ -17,11 +17,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<button type="button" class="btn btn-warning m-t m-b" ui-sref="app.admin.members_new" translate>
|
<button type="button" class="btn btn-warning m-b" ui-sref="app.admin.members_new" translate>
|
||||||
{{ 'app.admin.members.add_a_new_member' }}
|
{{ 'app.admin.members.add_a_new_member' }}
|
||||||
</button>
|
</button>
|
||||||
<div class="pull-right exports-buttons" ng-show="isAuthorized('admin')">
|
<div class="pull-right exports-buttons m-b" ng-show="isAuthorized('admin')">
|
||||||
<a class="btn btn-default" ng-href="api/members/export_members.xlsx" target="export-frame" ng-click="alertExport('members')">
|
<a class="btn btn-default" ng-href="api/members/export_members.xlsx" target="export-frame" ng-click="alertExport('members')">
|
||||||
<i class="fa fa-file-excel-o"></i> {{ 'app.admin.members.members' | translate }}
|
<i class="fa fa-file-excel-o"></i> {{ 'app.admin.members.members' | translate }}
|
||||||
</a>
|
</a>
|
||||||
@ -34,46 +35,8 @@
|
|||||||
<iframe name="export-frame" height="0" width="0" class="none"></iframe>
|
<iframe name="export-frame" height="0" width="0" class="none"></iframe>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class="table members-list">
|
<members-list members="members" on-success="onSuccess" onError="onError" />
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th style="width:4%" class="hidden-xs" ng-if="enableUserValidationRequired"></th>
|
|
||||||
<th style="width:8%" ng-show="displayUsername"><a ng-click="setOrderMember('username')">{{ 'app.admin.members.username' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': member.order=='username', 'fa fa-sort-alpha-desc': member.order=='-username', 'fa fa-arrows-v': member.order }"></i></a></th>
|
|
||||||
<th style="width:14%"><a ng-click="setOrderMember('last_name')">{{ 'app.admin.members.surname' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': member.order=='last_name', 'fa fa-sort-alpha-desc': member.order=='-last_name', 'fa fa-arrows-v': member.order }"></i></a></th>
|
|
||||||
<th style="width:14%"><a ng-click="setOrderMember('first_name')">{{ 'app.admin.members.first_name' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': member.order=='first_name', 'fa fa-sort-alpha-desc': member.order=='-first_name', 'fa fa-arrows-v': member.order }"></i></a></th>
|
|
||||||
<th style="width:14%" class="hidden-xs"><a ng-click="setOrderMember('email')">{{ 'app.admin.members.email' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': member.order=='email', 'fa fa-sort-alpha-desc': member.order=='-email', 'fa fa-arrows-v': member.order }"></i></a></th>
|
|
||||||
<th style="width:8%" class="hidden-xs hidden-sm hidden-md"><a ng-click="setOrderMember('phone')">{{ 'app.admin.members.phone' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-numeric-asc': member.order=='phone', 'fa fa-sort-numeric-desc': member.order=='-phone', 'fa fa-arrows-v': member.order }"></i></a></th>
|
|
||||||
<th style="width:13%" class="hidden-xs hidden-sm"><a ng-click="setOrderMember('group')">{{ 'app.admin.members.user_type' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': member.order=='group', 'fa fa-sort-alpha-desc': member.order=='-group', 'fa fa-arrows-v': member.order }"></i></a></th>
|
|
||||||
<th style="width:13%" class="hidden-xs hidden-sm hidden-md"><a ng-click="setOrderMember('plan')">{{ 'app.admin.members.subscription' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': member.order=='plan', 'fa fa-sort-alpha-desc': member.order=='-plan', 'fa fa-arrows-v': member.order }"></i></a></th>
|
|
||||||
<th style="width:12%" class="buttons-col"></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr ng-repeat="m in members">
|
|
||||||
<td class="text-center" ng-if="enableUserValidationRequired">
|
|
||||||
<span ng-class="{ 'text-success': !!m.validated_at }"><i class="fa fa-user-check"></i></span>
|
|
||||||
</td>
|
|
||||||
<td class="text-c" ng-show="displayUsername">{{ m.username }}</td>
|
|
||||||
<td class="text-c">{{ m.profile.last_name }}</td>
|
|
||||||
<td class="text-c">{{ m.profile.first_name }}</td>
|
|
||||||
<td class="hidden-xs">{{ m.email }}</td>
|
|
||||||
<td class="hidden-xs hidden-sm hidden-md">{{ m.profile.phone }}</td>
|
|
||||||
<td class="text-u-c text-sm hidden-xs hidden-sm">{{ m.group.name }}</td>
|
|
||||||
<td class="hidden-xs hidden-sm hidden-md">{{ m.subscribed_plan | humanReadablePlanName }}</td>
|
|
||||||
<td>
|
|
||||||
<div class="buttons">
|
|
||||||
<button class="btn btn-default edit-member" ui-sref="app.admin.members_edit({id: m.id})">
|
|
||||||
<i class="fa fa-edit"></i>
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-danger delete-member" ng-click="deleteMember(m.id)" ng-show="isAuthorized('admin')">
|
|
||||||
<i class="fa fa-trash"></i>
|
|
||||||
</button>
|
|
||||||
<span class="label label-danger text-white" ng-show="m.need_completion" translate>{{ 'app.shared.user_admin.incomplete_profile' }}</span>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<button class="btn btn-warning show-more" ng-click="showNextMembers()" ng-hide="member.noMore"><i class="fa fa-search-plus" aria-hidden="true"></i> {{ 'app.admin.members.display_more_users' | translate }}</button>
|
<button class="btn btn-warning show-more" ng-click="showNextMembers()" ng-hide="member.noMore"><i class="fa fa-search-plus" aria-hidden="true"></i> {{ 'app.admin.members.display_more_users' | translate }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,5 +7,5 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
<children-list user="currentUser" operator="currentUser" on-success="onSuccess" on-error="onError" />
|
<children-dashboard user="currentUser" operator="currentUser" on-success="onSuccess" on-error="onError" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
|
|
||||||
<div class="col-sm-12 col-md-12 col-lg-4">
|
<div class="col-sm-12 col-md-12 col-lg-4">
|
||||||
|
|
||||||
<section class="widget panel b-a m" ng-if="event.event_files_attributes">
|
<section class="widget panel b-a m" ng-if="event.event_files_attributes.length">
|
||||||
<div class="panel-heading b-b">
|
<div class="panel-heading b-b">
|
||||||
<span class="badge bg-warning pull-right">{{event.event_files_attributes.length}}</span>
|
<span class="badge bg-warning pull-right">{{event.event_files_attributes.length}}</span>
|
||||||
<h3 translate>{{ 'app.public.events_show.downloadable_documents' }}</h3>
|
<h3 translate>{{ 'app.public.events_show.downloadable_documents' }}</h3>
|
||||||
@ -72,8 +72,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel-content wrapper">
|
<div class="panel-content wrapper">
|
||||||
|
<div>
|
||||||
|
<span ng-if="event.event_type === 'nominative'" class="v-middle badge text-base bg-event" translate="">{{ 'app.public.events_show.event_type.nominative' }}</span>
|
||||||
|
<span ng-if="event.event_type === 'family'" class="v-middle badge text-base bg-event" translate="">{{ 'app.public.events_show.event_type.family' }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h5>{{event.category.name}}</h5>
|
|
||||||
<dl class="text-sm">
|
<dl class="text-sm">
|
||||||
<dt ng-repeat="theme in event.event_themes">
|
<dt ng-repeat="theme in event.event_themes">
|
||||||
<i class="fa fa-tags" aria-hidden="true"></i> {{theme.name}}
|
<i class="fa fa-tags" aria-hidden="true"></i> {{theme.name}}
|
||||||
@ -136,17 +139,17 @@
|
|||||||
class="form-control">
|
class="form-control">
|
||||||
<option value=""></option>
|
<option value=""></option>
|
||||||
</select>
|
</select>
|
||||||
<uib-alert type="danger" ng-if="enableChildValidationRequired && user.booked && user.booked.type === 'Child' && !user.booked.validatedAt">
|
<uib-alert type="danger" ng-if="enableChildValidationRequired && user.booked && user.booked.type === 'Child' && !user.booked.validatedAt" style="margin-bottom: 0.8rem;">
|
||||||
<p class="text-sm">
|
<span class="text-sm">
|
||||||
<i class="fa fa-warning"></i>
|
<i class="fa fa-warning"></i>
|
||||||
<span translate>{{ 'app.shared.cart.child_validation_required_alert' }}</span>
|
<span translate>{{ 'app.shared.cart.child_validation_required_alert' }}</span>
|
||||||
</p>
|
</span>
|
||||||
</uib-alert>
|
</uib-alert>
|
||||||
<uib-alert type="danger" ng-if="user.booked && user.booked.type === 'Child' && !isUnder18YearsAgo(user.booked.birthday)">
|
<uib-alert type="danger" ng-if="user.booked && user.booked.type === 'Child' && !isUnder18YearsAgo(user.booked.birthday)" style="margin-bottom: 0.8rem;">
|
||||||
<p class="text-sm">
|
<span class="text-sm">
|
||||||
<i class="fa fa-warning"></i>
|
<i class="fa fa-warning"></i>
|
||||||
<span translate>{{ 'app.shared.cart.child_birthday_must_be_under_18_years_ago_alert' }}</span>
|
<span translate>{{ 'app.shared.cart.child_birthday_must_be_under_18_years_ago_alert' }}</span>
|
||||||
</p>
|
</span>
|
||||||
</uib-alert>
|
</uib-alert>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,8 +12,11 @@
|
|||||||
</ui-select-choices>
|
</ui-select-choices>
|
||||||
</ui-select>
|
</ui-select>
|
||||||
{{member}}
|
{{member}}
|
||||||
<div class="alert alert-danger m-t" style="margin-bottom: 0 !important;" ng-if="enableUserValidationRequired && ctrl.member.id && !ctrl.member.validated_at">
|
<uib-alert type="danger" ng-if="enableUserValidationRequired && ctrl.member.id && !ctrl.member.validated_at" style="margin-bottom: 0;">
|
||||||
|
<span class="text-sm">
|
||||||
|
<i class="fa fa-warning"></i>
|
||||||
<span translate>{{ 'app.shared.member_select.member_not_validated' }}</span>
|
<span translate>{{ 'app.shared.member_select.member_not_validated' }}</span>
|
||||||
</div>
|
</span>
|
||||||
|
</uib-alert>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1189,6 +1189,14 @@ en:
|
|||||||
member_filter_all: "All"
|
member_filter_all: "All"
|
||||||
member_filter_not_confirmed: "Unconfirmed"
|
member_filter_not_confirmed: "Unconfirmed"
|
||||||
member_filter_inactive_for_3_years: "Inactive for 3 years"
|
member_filter_inactive_for_3_years: "Inactive for 3 years"
|
||||||
|
members_list_item:
|
||||||
|
item_type: "member"
|
||||||
|
surname: "Surname"
|
||||||
|
first_name: "First name"
|
||||||
|
phone: "Phone"
|
||||||
|
email: "Email"
|
||||||
|
group: "Group"
|
||||||
|
subscription: "Subscription"
|
||||||
#add a member
|
#add a member
|
||||||
members_new:
|
members_new:
|
||||||
add_a_member: "Add a member"
|
add_a_member: "Add a member"
|
||||||
@ -1885,7 +1893,7 @@ en:
|
|||||||
no_groups_info: "Supporting documents are necessarily applied to groups.<br>If you do not have any group yet, you can create one from the \"Users/Groups\" page (button on the right)."
|
no_groups_info: "Supporting documents are necessarily applied to groups.<br>If you do not have any group yet, you can create one from the \"Users/Groups\" page (button on the right)."
|
||||||
create_groups: "Create groups"
|
create_groups: "Create groups"
|
||||||
supporting_documents_type_title: "Supporting documents requests"
|
supporting_documents_type_title: "Supporting documents requests"
|
||||||
add_type: "New supporting documents request"
|
add_type: "Add new document"
|
||||||
group_name: "Group"
|
group_name: "Group"
|
||||||
name: "Supporting documents"
|
name: "Supporting documents"
|
||||||
no_types: "You do not have any supporting documents requests.<br>Make sure you have created at least one group in order to add a request."
|
no_types: "You do not have any supporting documents requests.<br>Make sure you have created at least one group in order to add a request."
|
||||||
|
@ -312,6 +312,9 @@ en:
|
|||||||
event_description: "Event description"
|
event_description: "Event description"
|
||||||
downloadable_documents: "Downloadable documents"
|
downloadable_documents: "Downloadable documents"
|
||||||
information_and_booking: "Information and booking"
|
information_and_booking: "Information and booking"
|
||||||
|
event_type:
|
||||||
|
family: "Family event"
|
||||||
|
nominative: "Nominative event"
|
||||||
dates: "Dates"
|
dates: "Dates"
|
||||||
beginning: "Beginning:"
|
beginning: "Beginning:"
|
||||||
ending: "Ending:"
|
ending: "Ending:"
|
||||||
@ -477,25 +480,28 @@ en:
|
|||||||
member_select:
|
member_select:
|
||||||
select_a_member: "Select a member"
|
select_a_member: "Select a member"
|
||||||
start_typing: "Start typing..."
|
start_typing: "Start typing..."
|
||||||
children_list:
|
children_dashboard:
|
||||||
heading: "My children"
|
heading: "Children"
|
||||||
|
member_heading: "My Children"
|
||||||
add_child: "Add a child"
|
add_child: "Add a child"
|
||||||
child_modal:
|
child_modal:
|
||||||
edit_child: "Edit child"
|
edit_child: "Edit child"
|
||||||
new_child: "New child"
|
new_child: "New child"
|
||||||
child_form:
|
child_form:
|
||||||
child_form_info: "Note that you can only add your children under 18 years old. Supporting documents are requested by your administrator, they will be useful to validate your child's account and authorize the reservation of events."
|
child_form_info: "Please note that you can only add a child under the age of 18. Supporting documents are requested by your administrator, they will be useful to validate your child's account and authorize the reservation of events."
|
||||||
first_name: "First name"
|
first_name: "First name"
|
||||||
last_name: "Last name"
|
last_name: "Last name"
|
||||||
birthday: "Birthday"
|
birthday: "Birthday"
|
||||||
email: "Email"
|
email: "Email"
|
||||||
phone: "Phone"
|
phone: "Phone"
|
||||||
save: "Save"
|
save: "Save"
|
||||||
|
supporting_documents: "Supporting documents"
|
||||||
to_complete: "To complete"
|
to_complete: "To complete"
|
||||||
refuse_documents: "Refusing the documents"
|
refuse_documents_info: "You can refuse a selection of documents by clicking on the following button."
|
||||||
|
refuse_documents: "Refuse documents"
|
||||||
child_item:
|
child_item:
|
||||||
first_name: "First name of the child"
|
first_name: "Child first name"
|
||||||
last_name: "Last name of the child"
|
last_name: "Child last name"
|
||||||
birthday: "Birthday"
|
birthday: "Birthday"
|
||||||
deleted: "The child has been deleted."
|
deleted: "The child has been deleted."
|
||||||
unable_to_delete: "Unable to delete the child."
|
unable_to_delete: "Unable to delete the child."
|
||||||
|
@ -477,7 +477,7 @@ fr:
|
|||||||
member_select:
|
member_select:
|
||||||
select_a_member: "Sélectionnez un membre"
|
select_a_member: "Sélectionnez un membre"
|
||||||
start_typing: "Commencez à écrire..."
|
start_typing: "Commencez à écrire..."
|
||||||
children_list:
|
children_dashboard:
|
||||||
heading: "Mes enfants"
|
heading: "Mes enfants"
|
||||||
add_child: "Ajouter un enfant"
|
add_child: "Ajouter un enfant"
|
||||||
child_modal:
|
child_modal:
|
||||||
|
@ -165,7 +165,7 @@ en:
|
|||||||
member_select:
|
member_select:
|
||||||
select_a_member: "Select a member"
|
select_a_member: "Select a member"
|
||||||
start_typing: "Start typing..."
|
start_typing: "Start typing..."
|
||||||
member_not_validated: "Warning:<br> The member was not validated."
|
member_not_validated: "This member has not yet been validated."
|
||||||
#payment modal
|
#payment modal
|
||||||
abstract_payment_modal:
|
abstract_payment_modal:
|
||||||
online_payment: "Online payment"
|
online_payment: "Online payment"
|
||||||
@ -368,9 +368,9 @@ en:
|
|||||||
slot_tags: "Slot tags"
|
slot_tags: "Slot tags"
|
||||||
user_tags: "User tags"
|
user_tags: "User tags"
|
||||||
no_tags: "No 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."
|
user_validation_required_alert: "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."
|
child_validation_required_alert: "Your administrator must validate your child account. Then, you'll then be able to book the event."
|
||||||
child_birthday_must_be_under_18_years_ago_alert: "Warning!<br>Your child must be under 18 years ago. Then, you'll then be able to book the event."
|
child_birthday_must_be_under_18_years_ago_alert: "Your child must be under 18. Then, you'll then be able to book the event."
|
||||||
# feature-tour modal
|
# feature-tour modal
|
||||||
tour:
|
tour:
|
||||||
previous: "Previous"
|
previous: "Previous"
|
||||||
@ -443,6 +443,7 @@ en:
|
|||||||
select_all: "Select all"
|
select_all: "Select all"
|
||||||
unselect_all: "Unselect all"
|
unselect_all: "Unselect all"
|
||||||
form_file_upload:
|
form_file_upload:
|
||||||
|
placeholder: "Add a file"
|
||||||
browse: "Browse"
|
browse: "Browse"
|
||||||
edit: "Edit"
|
edit: "Edit"
|
||||||
form_image_upload:
|
form_image_upload:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user