mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-20 14:43:49 +00:00
Merge branch 'master' into 110_extend_thirdparty
This commit is contained in:
@@ -1141,7 +1141,7 @@ class CRUDController extends AbstractController
|
||||
*/
|
||||
protected function getPaginatorFactory(): PaginatorFactory
|
||||
{
|
||||
return $this->container->get('chill_main.paginator_factory');
|
||||
return $this->container->get(PaginatorFactory::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\MainBundle\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Chill\MainBundle\Repository\NotificationRepository;
|
||||
use Chill\MainBundle\Notification\NotificationRenderer;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||
|
||||
|
||||
/**
|
||||
* @Route("/{_locale}/notification")
|
||||
*/
|
||||
class NotificationController extends AbstractController
|
||||
{
|
||||
private $security;
|
||||
|
||||
public function __construct(Security $security)
|
||||
{
|
||||
$this->security = $security;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @Route("/show", name="chill_main_notification_show")
|
||||
*/
|
||||
public function showAction(
|
||||
NotificationRepository $notificationRepository, NotificationRenderer $notificationRenderer,
|
||||
PaginatorFactory $paginatorFactory)
|
||||
{
|
||||
$currentUser = $this->security->getUser();
|
||||
|
||||
$notificationsNbr = $notificationRepository->countAllForAttendee(($currentUser));
|
||||
$paginator = $paginatorFactory->create($notificationsNbr);
|
||||
|
||||
$notifications = $notificationRepository->findAllForAttendee(
|
||||
$currentUser,
|
||||
$limit=$paginator->getItemsPerPage(),
|
||||
$offset= $paginator->getCurrentPage()->getFirstItemNumber());
|
||||
|
||||
$templateData = array();
|
||||
foreach ($notifications as $notification) {
|
||||
$data = [
|
||||
'template' => $notificationRenderer->getTemplate($notification),
|
||||
'template_data' => $notificationRenderer->getTemplateData($notification),
|
||||
'notification' => $notification
|
||||
];
|
||||
$templateData[] = $data;
|
||||
}
|
||||
|
||||
return $this->render('@ChillMain/Notification/show.html.twig', [
|
||||
'datas' => $templateData,
|
||||
'notifications' => $notifications,
|
||||
'paginator' => $paginator,
|
||||
]);
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\MainBundle\Notification;
|
||||
|
||||
use Chill\MainBundle\Entity\Notification;
|
||||
use Chill\PersonBundle\Notification\AccompanyingPeriodNotificationRenderer;
|
||||
use Chill\ActivityBundle\Notification\ActivityNotificationRenderer;
|
||||
|
||||
final class NotificationRenderer
|
||||
{
|
||||
private array $renderers;
|
||||
|
||||
public function __construct(
|
||||
AccompanyingPeriodNotificationRenderer $accompanyingPeriodNotificationRenderer,
|
||||
ActivityNotificationRenderer $activityNotificationRenderer)
|
||||
{
|
||||
// TODO configure automatically
|
||||
// TODO CREER UNE INTERFACE POUR ETRE SUR QUE LES RENDERERS SONT OK
|
||||
|
||||
$this->renderers[] = $accompanyingPeriodNotificationRenderer;
|
||||
$this->renderers[] = $activityNotificationRenderer;
|
||||
}
|
||||
|
||||
private function getRenderer(Notification $notification)
|
||||
{
|
||||
foreach ($this->renderers as $renderer) {
|
||||
if($renderer->supports($notification)) {
|
||||
return $renderer;
|
||||
}
|
||||
}
|
||||
|
||||
throw new \Exception('No renderer for '. $notification);
|
||||
}
|
||||
|
||||
public function getTemplate(Notification $notification)
|
||||
{
|
||||
return $this->getRenderer($notification)->getTemplate();
|
||||
}
|
||||
|
||||
public function getTemplateData(Notification $notification)
|
||||
{
|
||||
return $this->getRenderer($notification)->getTemplateData($notification);
|
||||
}
|
||||
}
|
@@ -23,6 +23,8 @@ use Chill\MainBundle\Entity\Notification;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Doctrine\ORM\Query;
|
||||
|
||||
final class NotificationRepository implements ObjectRepository
|
||||
{
|
||||
@@ -59,8 +61,54 @@ final class NotificationRepository implements ObjectRepository
|
||||
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
|
||||
}
|
||||
|
||||
private function queryAllForAttendee(User $addressee, bool $countQuery=False): Query
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('n');
|
||||
|
||||
$select = 'n';
|
||||
if($countQuery) {
|
||||
$select = 'count(n)';
|
||||
}
|
||||
|
||||
$qb
|
||||
->select($select)
|
||||
->join('n.addressees', 'a')
|
||||
->where('a = :addressee')
|
||||
->setParameter('addressee', $addressee);
|
||||
|
||||
return $qb->getQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function countAllForAttendee(User $addressee): int // TODO passer à attendees avec S
|
||||
{
|
||||
$query = $this->queryAllForAttendee($addressee, $countQuery=True);
|
||||
|
||||
return $query->getSingleScalarResult();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Notification[]
|
||||
*/
|
||||
public function findAllForAttendee(User $addressee, $limit = null, $offset = null): array // TODO passer à attendees avec S
|
||||
{
|
||||
$query = $this->queryAllForAttendee($addressee);
|
||||
|
||||
if($limit) {
|
||||
$query = $query->setMaxResults($limit);
|
||||
}
|
||||
|
||||
if($offset) {
|
||||
$query = $query->setFirstResult($offset);
|
||||
}
|
||||
|
||||
return $query->getResult();
|
||||
}
|
||||
|
||||
public function getClassName() {
|
||||
return Notification::class;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,12 +1,14 @@
|
||||
/*
|
||||
* NOTE 2021.04
|
||||
* scss/chillmain.scss is the main sass file for the new chill.2
|
||||
* scratch will be replaced by bootstrap, please avoid to edit in modules/scratch/_custom.scss
|
||||
*
|
||||
* when possible, try to use bootstrap html class
|
||||
*/
|
||||
// Access to Bootstrap variables and mixins
|
||||
@import '~ChillMainAssets/module/bootstrap/shared';
|
||||
|
||||
@import '~ChillMainAssets/module/bootstrap/bootstrap';
|
||||
// Chill mixins
|
||||
@import './scss/mixins';
|
||||
|
||||
// Chill entity render box system
|
||||
@import './scss/render_box';
|
||||
|
||||
// Chill flex responsive table/block presentation
|
||||
@import './scss/flex_table';
|
||||
|
||||
/*
|
||||
* Specific rules
|
||||
@@ -22,6 +24,7 @@ div.banner {
|
||||
.id-number {
|
||||
font-weight: lighter;
|
||||
font-size: 50%;
|
||||
margin-left: 0.5em;
|
||||
&:before { content: '(n°'; }
|
||||
&:after { content: ')'; }
|
||||
}
|
||||
@@ -37,165 +40,5 @@ div.banner {
|
||||
&:before { content: '('; }
|
||||
&:after { content: ')'; }
|
||||
}
|
||||
div.members {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
span.badge-member {
|
||||
border: 1px solid #ffffff3b;
|
||||
color: #ffffff;
|
||||
padding: 0.4em 0.8em;
|
||||
margin-right: 0.3em;
|
||||
border-radius: 8px;
|
||||
&.holder {
|
||||
order: -1;
|
||||
}
|
||||
&.child {
|
||||
order: 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* FLEX RESPONSIVE TABLE/BLOCK PRESENTATION
|
||||
*/
|
||||
div.flex-bloc,
|
||||
div.flex-table {
|
||||
h2, h3, h4, dl, p {
|
||||
margin: 0;
|
||||
}
|
||||
h2, h3, h4 {
|
||||
color: var(--bs-chill-blue);
|
||||
}
|
||||
div.item-bloc {
|
||||
// We use box-shadow instead of border
|
||||
// to avoid to manage border double-width
|
||||
// when blocs are resized for small screen !
|
||||
// Then we can simulate border-collapse: collapse (table)
|
||||
box-shadow:
|
||||
1px 0 0 0 var(--bs-dark),
|
||||
0 1px 0 0 var(--bs-dark),
|
||||
1px 1px 0 0 var(--bs-dark), /* fix the corner */
|
||||
1px 0 0 0 var(--bs-dark) inset,
|
||||
0 1px 0 0 var(--bs-dark) inset;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Bloc appearance
|
||||
*/
|
||||
div.flex-bloc {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: stretch;
|
||||
align-content: stretch;
|
||||
|
||||
div.item-bloc {
|
||||
flex-grow: 0; flex-shrink: 1; flex-basis: 33%;
|
||||
margin: 0;
|
||||
padding: 1em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
div.item-row {
|
||||
flex-grow: 1; flex-shrink: 1; flex-basis: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
div.item-col {
|
||||
&:first-child {
|
||||
flex-grow: 0; flex-shrink: 0; flex-basis: auto;
|
||||
}
|
||||
&:last-child {
|
||||
flex-grow: 1; flex-shrink: 1; flex-basis: auto;
|
||||
display: flex;
|
||||
|
||||
.list-content { // ul, dl, or div
|
||||
}
|
||||
ul.record_actions {
|
||||
margin: 0;
|
||||
align-self: flex-end;
|
||||
flex-grow: 1; flex-shrink: 0; flex-basis: auto;
|
||||
li {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 945px) { margin: auto -0.2em; }
|
||||
@media only screen and (max-width: 935px) { margin: auto -0.5em; }
|
||||
@media only screen and (max-width: 920px) { margin: auto -0.9em; }
|
||||
@media only screen and (max-width: 900px) {
|
||||
flex-direction: column;
|
||||
margin: auto 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Table appearance
|
||||
*/
|
||||
div.flex-table {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
align-content: stretch;
|
||||
|
||||
div.item-bloc {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1em;
|
||||
&:nth-child(even) {
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
|
||||
div.item-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
&:not(:first-child) {
|
||||
margin-top: 0.5em;
|
||||
border-top: 1px dotted #0000004f;
|
||||
padding-top: 0.5em;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
div.item-col {
|
||||
&:first-child {
|
||||
flex-grow: 0; flex-shrink: 0; flex-basis: 33%;
|
||||
}
|
||||
&:last-child {
|
||||
flex-grow: 1; flex-shrink: 1; flex-basis: auto;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
.list-content { // ul, dl, or div
|
||||
}
|
||||
ul.record_actions {
|
||||
margin: 0;
|
||||
align-self: flex-start;
|
||||
flex-grow: 1; flex-shrink: 0; flex-basis: auto;
|
||||
li {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 900px) {
|
||||
flex-direction: column;
|
||||
div.item-col {
|
||||
&:last-child {
|
||||
ul.record_actions {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// neutralize
|
||||
div.chill_address div.chill_address_address p { text-indent: 0; }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* FLEX RESPONSIVE TABLE/BLOCK PRESENTATION
|
||||
*/
|
||||
div.flex-bloc,
|
||||
div.flex-table {
|
||||
h2, h3, h4, dl, p {
|
||||
margin: 0;
|
||||
}
|
||||
h2, h3, h4 {
|
||||
color: var(--bs-chill-blue);
|
||||
}
|
||||
div.item-bloc {
|
||||
@include border-collapse;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Bloc appearance
|
||||
*/
|
||||
div.flex-bloc {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: stretch;
|
||||
align-content: stretch;
|
||||
|
||||
div.item-bloc {
|
||||
flex-grow: 0; flex-shrink: 1; flex-basis: auto;
|
||||
margin: 0;
|
||||
padding: 1em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
div.item-row {
|
||||
flex-grow: 1; flex-shrink: 1; flex-basis: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
div.item-col {
|
||||
&:first-child {
|
||||
flex-grow: 0; flex-shrink: 0; flex-basis: auto;
|
||||
padding-bottom: 0.5em;
|
||||
border-bottom: 1px dotted #0000004f;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
&:last-child {
|
||||
flex-grow: 1; flex-shrink: 1; flex-basis: auto;
|
||||
display: flex;
|
||||
|
||||
.list-content { // ul, dl, or div
|
||||
}
|
||||
ul.record_actions {
|
||||
margin: 0;
|
||||
align-self: flex-end;
|
||||
flex-grow: 1; flex-shrink: 0; flex-basis: auto;
|
||||
li {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Table appearance
|
||||
*/
|
||||
div.flex-table {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
align-content: stretch;
|
||||
|
||||
div.item-bloc {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1em;
|
||||
&:nth-child(even) {
|
||||
background-color: $gray-200;
|
||||
}
|
||||
|
||||
div.item-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
&:not(:first-child) {
|
||||
margin-top: 0.5em;
|
||||
border-top: 1px dotted #0000004f;
|
||||
padding-top: 0.5em;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
div.item-col {
|
||||
&:first-child {
|
||||
flex-grow: 0; flex-shrink: 0; flex-basis: 33%;
|
||||
}
|
||||
&:last-child {
|
||||
flex-grow: 1; flex-shrink: 1; flex-basis: auto;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
.list-content { // ul, dl, or div
|
||||
}
|
||||
ul.record_actions {
|
||||
margin: 0;
|
||||
align-self: flex-start;
|
||||
flex-grow: 1; flex-shrink: 0; flex-basis: auto;
|
||||
li {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 900px) {
|
||||
flex-direction: column;
|
||||
div.item-col {
|
||||
&:last-child {
|
||||
ul.record_actions {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// neutralize
|
||||
div.chill_address div.chill_address_address p { text-indent: 0; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
|
||||
// We use box-shadow instead of border
|
||||
// to avoid to manage border double-width
|
||||
// Then we can simulate border-collapse: collapse (table)
|
||||
|
||||
@mixin border-collapse {
|
||||
box-shadow:
|
||||
1px 0 0 0 var(--bs-dark),
|
||||
0 1px 0 0 var(--bs-dark),
|
||||
1px 1px 0 0 var(--bs-dark), /* fix the corner */
|
||||
1px 0 0 0 var(--bs-dark) inset,
|
||||
0 1px 0 0 var(--bs-dark) inset;
|
||||
}
|
||||
|
@@ -0,0 +1,95 @@
|
||||
// generic rules
|
||||
section.chill-entity {
|
||||
|
||||
// display inline for render raw
|
||||
// have no effect for render label, bloc !
|
||||
display: inline;
|
||||
|
||||
// don't break flex cascade with section tag
|
||||
div.flex-bloc & {
|
||||
display: flex;
|
||||
flex-grow: 1; flex-shrink: 1; flex-basis: auto;
|
||||
}
|
||||
}
|
||||
|
||||
// specific rules
|
||||
.chill-entity {
|
||||
|
||||
// used for: entity-person, entity-thirdparty
|
||||
&.entity-person,
|
||||
&.entity-thirdparty {
|
||||
|
||||
div.entity-label {
|
||||
div.denomination {
|
||||
&.h3 {
|
||||
font-size: 1.3em;
|
||||
font-weight: 700;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
span.badge {
|
||||
margin-left: 0.3em;
|
||||
}
|
||||
span.altnames,
|
||||
span.id-number {
|
||||
font-weight: lighter;
|
||||
font-size: 50%;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
span.id-number {
|
||||
&:before { content: '(n°'; }
|
||||
&:after { content: ')'; }
|
||||
}
|
||||
}
|
||||
p.moreinfo {}
|
||||
}
|
||||
div.entity-bloc {}
|
||||
}
|
||||
|
||||
// used for addresses
|
||||
&.entity-address {
|
||||
|
||||
.address {
|
||||
font-size: 98%;
|
||||
font-variant: small-caps;
|
||||
|
||||
&.multiline {
|
||||
margin: 0.7em 0;
|
||||
p {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
&.delimiter {
|
||||
p:not(:first-child):before {
|
||||
content: ' — ';
|
||||
}
|
||||
}
|
||||
p {
|
||||
display: inline-block;
|
||||
margin: 0 0 0 1.5em;
|
||||
text-indent: -1.5em;
|
||||
|
||||
&.street {
|
||||
span.streetnumber {
|
||||
&::before { content: ", "; }
|
||||
}
|
||||
}
|
||||
&.postcode {
|
||||
span.code {}
|
||||
span.name {}
|
||||
}
|
||||
&.country {}
|
||||
}
|
||||
}
|
||||
|
||||
.noaddress {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
span.address-valid {
|
||||
&.address-since {}
|
||||
&.address-until {}
|
||||
}
|
||||
}
|
||||
}
|
@@ -7,17 +7,10 @@
|
||||
* Enable / disable bootstrap assets
|
||||
*/
|
||||
|
||||
// Bootstrap configuration files are shared with chill entrypoint
|
||||
@import "shared";
|
||||
|
||||
// scss-docs-start import-stack
|
||||
// Configuration
|
||||
@import "bootstrap/scss/functions";
|
||||
|
||||
/* replace by CHILL variables */
|
||||
//@import "bootstrap/scss/variables";
|
||||
@import "custom/_variables";
|
||||
|
||||
@import "bootstrap/scss/mixins";
|
||||
@import "bootstrap/scss/utilities";
|
||||
|
||||
// Layout & components
|
||||
@import "bootstrap/scss/root";
|
||||
@import "bootstrap/scss/reboot";
|
||||
@@ -59,3 +52,4 @@
|
||||
|
||||
// CHILL custom
|
||||
@import "custom";
|
||||
@import "custom/_debug";
|
||||
|
@@ -0,0 +1,19 @@
|
||||
body {
|
||||
position: relative;
|
||||
div.responsive {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
background-color: #4a4d50;
|
||||
color: white;
|
||||
padding: 0.5em;
|
||||
z-index: 10000;
|
||||
|
||||
@media (max-width: 576px) { &::after { content: 'XS'; }}
|
||||
@media (min-width: 576px) { &::after { content: 'SM'; }}
|
||||
@media (min-width: 768px) { &::after { content: 'MD'; }}
|
||||
@media (min-width: 992px) { &::after { content: 'LG'; }}
|
||||
@media (min-width: 1200px) { &::after { content: 'XL'; }}
|
||||
@media (min-width: 1400px) { &::after { content: 'XXL'; }}
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
// Configuration
|
||||
@import "bootstrap/scss/functions";
|
||||
|
||||
/*
|
||||
* Replaced by CHILL variables
|
||||
* it is necessary to keep the possibility of making a diff with original !
|
||||
* original: "bootstrap/scss/variables";
|
||||
*/
|
||||
@import "custom/_variables";
|
||||
|
||||
@import "bootstrap/scss/mixins";
|
||||
@import "bootstrap/scss/utilities";
|
||||
|
||||
|
@@ -1,23 +1,22 @@
|
||||
<template>
|
||||
<div class='person-address__create'>
|
||||
<div>
|
||||
<h2 v-if="!edit">{{ $t('create_a_new_address') }}</h2>
|
||||
<h2 v-else>{{ $t('edit_a_new_address') }}</h2>
|
||||
<add-address
|
||||
@addNewAddress="addNewAddress">
|
||||
</add-address>
|
||||
</div>
|
||||
<div>
|
||||
<show-address
|
||||
v-if="address"
|
||||
v-bind:address="address">
|
||||
</show-address>
|
||||
</div>
|
||||
<div class="chill-entity entity-address">
|
||||
|
||||
<h2 v-if="!edit">{{ $t('create_a_new_address') }}</h2>
|
||||
<h2 v-else>{{ $t('edit_address') }}</h2>
|
||||
|
||||
<show-address
|
||||
v-if="address"
|
||||
v-bind:address="address">
|
||||
</show-address>
|
||||
|
||||
<add-address
|
||||
@addNewAddress="addNewAddress">
|
||||
</add-address>
|
||||
</div>
|
||||
|
||||
|
||||
<div v-if="!edit" class='person-address__valid'>
|
||||
<h2>{{ $t('date') }}</h2>
|
||||
|
||||
|
||||
<div class="input-group mb-3">
|
||||
<span class="input-group-text" id="validFrom"><i class="fa fa-fw fa-calendar"></i></span>
|
||||
<input type="date" class="form-control form-control-lg" name="validFrom"
|
||||
@@ -25,7 +24,7 @@
|
||||
v-model="validFrom"
|
||||
aria-describedby="validFrom" />
|
||||
</div>
|
||||
|
||||
|
||||
<div v-if="errors.length > 0">
|
||||
{{ errors }}
|
||||
</div>
|
||||
|
@@ -3,7 +3,7 @@
|
||||
{{ $t('add_an_address_title') }}
|
||||
</button>
|
||||
<button v-else class="btn btn-create mt-4" @click="openModal">
|
||||
{{ $t('edit_an_address_title') }}
|
||||
{{ $t('edit_address') }}
|
||||
</button>
|
||||
|
||||
<teleport to="body">
|
||||
@@ -18,19 +18,19 @@
|
||||
|
||||
<template v-slot:body>
|
||||
<div class="address-form">
|
||||
|
||||
|
||||
<h4 class="h3">{{ $t('select_an_address_title') }}
|
||||
<span v-if="loading">
|
||||
<i class="fa fa-circle-o-notch fa-spin fa-lg"></i>
|
||||
</span>
|
||||
</h4>
|
||||
|
||||
|
||||
<div class="row my-3">
|
||||
<div class="col-lg-6">
|
||||
|
||||
<div class="col-lg-6">
|
||||
|
||||
<div class="form-check">
|
||||
<input type="checkbox"
|
||||
class="form-check-input"
|
||||
class="form-check-input"
|
||||
id="isNoAddress"
|
||||
v-model="isNoAddress"
|
||||
v-bind:value="value" />
|
||||
@@ -38,18 +38,18 @@
|
||||
{{ $t('isNoAddress') }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
<country-selection
|
||||
v-bind:address="address"
|
||||
v-bind:getCities="getCities">
|
||||
</country-selection>
|
||||
|
||||
|
||||
<city-selection
|
||||
v-bind:address="address"
|
||||
v-bind:focusOnAddress="focusOnAddress"
|
||||
v-bind:getReferenceAddresses="getReferenceAddresses">
|
||||
</city-selection>
|
||||
|
||||
|
||||
<address-selection
|
||||
v-if="!isNoAddress"
|
||||
v-bind:address="address"
|
||||
@@ -58,15 +58,15 @@
|
||||
|
||||
</div>
|
||||
<div class="col-lg-6 mt-3 mt-lg-0">
|
||||
|
||||
|
||||
<address-map
|
||||
v-bind:address="address"
|
||||
ref="addressMap">
|
||||
</address-map>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<address-more
|
||||
v-if="!isNoAddress"
|
||||
v-bind:address="address">
|
||||
|
@@ -1,36 +1,54 @@
|
||||
<template>
|
||||
<div class="chill_address_address chill_address_address--multiline">
|
||||
<div v-if="address.text">
|
||||
{{ address.text }}
|
||||
<div class="address multiline">
|
||||
<p v-if="address.text"
|
||||
class="street">
|
||||
{{ address.text }}
|
||||
</p>
|
||||
<p v-if="address.postcode"
|
||||
class="postcode">
|
||||
{{ address.postcode.name }}
|
||||
</p>
|
||||
<p v-if="address.country"
|
||||
class="country">
|
||||
{{ address.country.name.fr }}
|
||||
</p>
|
||||
|
||||
<div v-if="address.floor">
|
||||
<span class="floor">
|
||||
<b>{{ $t('floor') }}</b>: {{ address.floor }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="address.corridor">
|
||||
<span class="corridor">
|
||||
<b>{{ $t('corridor') }}</b>: {{ address.corridor }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="address.steps">
|
||||
<span class="steps">
|
||||
<b>{{ $t('steps') }}</b>: {{ address.steps }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="address.flat">
|
||||
<span class="flat">
|
||||
<b>{{ $t('flat') }}</b>: {{ address.flat }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="address.buildingName">
|
||||
<span class="buildingName">
|
||||
<b>{{ $t('buildingName') }}</b>: {{ address.buildingName }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="address.extra">
|
||||
<span class="extra">
|
||||
<b>{{ $t('extra') }}</b>: {{ address.extra }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="address.distribution">
|
||||
<span class="distribution">
|
||||
<b>{{ $t('distribution') }}</b>: {{ address.distribution }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="address.postcode">
|
||||
{{ address.postcode.name }}
|
||||
</div>
|
||||
<div v-if="address.country">
|
||||
{{ address.country.name.fr }}
|
||||
</div>
|
||||
<div v-if="address.floor">
|
||||
<span>{{ $t('floor') }}</span>: {{ address.floor }}
|
||||
</div>
|
||||
<div v-if="address.corridor">
|
||||
<span>{{ $t('corridor') }}</span>: {{ address.corridor }}
|
||||
</div>
|
||||
<div v-if="address.steps">
|
||||
<span>{{ $t('steps') }}</span>: {{ address.steps }}
|
||||
</div>
|
||||
<div v-if="address.flat">
|
||||
<span>{{ $t('flat') }}</span>: {{ address.flat }}
|
||||
</div>
|
||||
<div v-if="address.buildingName">
|
||||
<span>{{ $t('buildingName') }}</span>: {{ address.buildingName }}
|
||||
</div>
|
||||
<div v-if="address.extra">
|
||||
<span>{{ $t('extra') }}</span>: {{ address.extra }}
|
||||
</div>
|
||||
<div v-if="address.distribution">
|
||||
<span>{{ $t('distribution') }}</span>: {{ address.distribution }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@@ -3,7 +3,7 @@ const addressMessages = {
|
||||
add_an_address_title: 'Créer une adresse',
|
||||
edit_an_address_title: 'Modifier une adresse',
|
||||
create_a_new_address: 'Créer une nouvelle adresse',
|
||||
edit_a_new_address: 'Modifier l\'adresse',
|
||||
edit_address: 'Modifier l\'adresse',
|
||||
select_an_address_title: 'Sélectionner une adresse',
|
||||
fill_an_address: 'Compléter l\'adresse',
|
||||
select_country: 'Choisir le pays',
|
||||
|
@@ -1,16 +0,0 @@
|
||||
<div class="chill_address">
|
||||
{% if options['has_no_address'] == true and address.isNoAddress == true %}
|
||||
<div class="chill_address_is_noaddress">{{ 'address.consider homeless'|trans }}</div>
|
||||
{% endif %}
|
||||
<div class="chill_address_address {% if options['multiline'] %}chill_address_address--multiline{% endif %}">
|
||||
{% if address.street is not empty %}<p class="street street1">{{ address.street }}</p>{% endif %}
|
||||
{% if address.streetNumber is not empty %}<p class="street street2">{{ address.streetNumber }}</p>{% endif %}
|
||||
{% if address.postCode is not empty %}
|
||||
<p class="postalCode"><span class="code">{{ address.postCode.code }}</span> <span class="name">{{ address.postCode.name }}</span></p>
|
||||
<p class="country">{{ address.postCode.country.name|localize_translatable_string }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{%- if options['with_valid_from'] == true -%}
|
||||
<span class="address_since">{{ 'Since %date%'|trans( { '%date%' : address.validFrom|format_date('long') } ) }}</span>
|
||||
{%- endif -%}
|
||||
</div>
|
@@ -1,21 +0,0 @@
|
||||
{%- macro _render(address, options) -%}
|
||||
{%- set options = { 'with_valid_from' : true }|merge(options|default({})) -%}
|
||||
{%- set options = { 'has_no_address' : false }|merge(options|default({})) -%}
|
||||
{%- set options = { 'with_icon' : false }|merge(options|default({})) -%}
|
||||
<div class="chill_address">
|
||||
{% if options['has_no_address'] == true and address.isNoAddress == true %}
|
||||
<div class="chill_address_is_noaddress">{{ 'address.consider homeless'|trans }}</div>
|
||||
{% endif %}
|
||||
<div class="chill_address_address">{% if options['with_icon'] == true %}<i class="fa fa-fw fa-map-marker"></i>{% endif %}
|
||||
{% if address.street is not empty %}<p class="street street1">{{ address.street }}</p>{% endif %}
|
||||
{% if address.streetNumber is not empty %}<p class="street street2">{{ address.streetNumber }}</p>{% endif %}
|
||||
{% if address.postCode is not empty %}
|
||||
<p class="postalCode"><span class="code">{{ address.postCode.code }}</span> <span class="name">{{ address.postCode.name }}</span></p>
|
||||
<p class="country">{{ address.postCode.country.name|localize_translatable_string }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{%- if options['with_valid_from'] == true -%}
|
||||
<span class="address_since">{{ 'Since %date%'|trans( { '%date%' : address.validFrom|format_date('long') } ) }}</span>
|
||||
{%- endif -%}
|
||||
</div>
|
||||
{%- endmacro -%}
|
@@ -0,0 +1,121 @@
|
||||
{#
|
||||
Template to render an address
|
||||
|
||||
OPTIONS
|
||||
* render string ['list'|'bloc'|'inline']
|
||||
* with_valid_from bool start date
|
||||
* with_valid_to bool end date
|
||||
* with_picto bool add a forkawesome pictogram
|
||||
* with_delimiter bool add a delimiter between fragments
|
||||
* has_no_address bool
|
||||
* multiline bool multiline display
|
||||
* extended_infos bool add extra informations (step, floor, etc.)
|
||||
|
||||
#}
|
||||
{% macro raw(address, options) %}
|
||||
{% if address.street is not empty %}
|
||||
<p class="street">{{ address.street }}
|
||||
{% if address.streetNumber is not empty %}
|
||||
<span class="streetnumber">{{ address.streetNumber }}</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if options['extended_infos'] %}
|
||||
{{ _self.extended(address, options) }}
|
||||
{% endif %}
|
||||
{% if address.postCode is not empty %}
|
||||
<p class="postcode">
|
||||
<span class="code">{{ address.postCode.code }}</span>
|
||||
<span class="name">{{ address.postCode.name }}</span>
|
||||
</p>
|
||||
<p class="country">{{ address.postCode.country.name|localize_translatable_string }}</p>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro extended(address, options) %}
|
||||
{% if address.floor is not empty %}
|
||||
<span class="floor">{{ address.floor }}</span>
|
||||
{% endif %}
|
||||
{% if address.corridor is not empty %}
|
||||
<span class="corridor">{{ address.corridor }}</span>
|
||||
{% endif %}
|
||||
{% if address.steps is not empty %}
|
||||
<span class="steps">{{ address.steps }}</span>
|
||||
{% endif %}
|
||||
{% if address.buildingName is not empty %}
|
||||
<span class="buildingName">{{ address.buildingName }}</span>
|
||||
{% endif %}
|
||||
{% if address.flat is not empty %}
|
||||
<span class="flat">{{ address.flat }}</span>
|
||||
{% endif %}
|
||||
{% if address.distribution is not empty %}
|
||||
<span class="distribution">{{ address.distribution }}</span>
|
||||
{% endif %}
|
||||
{% if address.extra is not empty %}
|
||||
<span class="extra">{{ address.extra }}</span>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro inline(address, options) %}
|
||||
{% if options['has_no_address'] == true and address.isNoAddress == true %}
|
||||
<span class="noaddress">
|
||||
{{ 'address.consider homeless'|trans }}
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="address{% if options['multiline'] %} multiline{% endif %}{% if options['with_delimiter'] %} delimiter{% endif %}">
|
||||
{{ _self.raw(address, options) }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{{ _self.validity(address, options) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro validity(address, options) %}
|
||||
{%- if options['with_valid_from'] == true -%}
|
||||
<span class="address-valid address-since">
|
||||
{{ 'Since %date%'|trans( { '%date%' : address.validFrom|format_date('long') } ) }}
|
||||
</span>
|
||||
{%- endif -%}
|
||||
{%- if options['with_valid_to'] == true -%}
|
||||
<span class="address-valid address-until">
|
||||
{{ 'Until %date%'|trans( { '%date%' : address.validTo|format_date('long') } ) }}
|
||||
</span>
|
||||
{%- endif -%}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{%- if render == 'list' -%}
|
||||
<li class="chill-entity entity-address">
|
||||
{% if options['with_picto'] %}
|
||||
<i class="fa fa-li fa-map-marker"></i>
|
||||
{% endif %}
|
||||
{{ _self.inline(address, options) }}
|
||||
</li>
|
||||
{%- endif -%}
|
||||
|
||||
{%- if render == 'inline' -%}
|
||||
<span class="chill-entity entity-address">
|
||||
{% if options['with_picto'] %}
|
||||
<i class="fa fa-fw fa-map-marker"></i>
|
||||
{% endif %}
|
||||
{{ _self.inline(address, options) }}
|
||||
</span>
|
||||
{%- endif -%}
|
||||
|
||||
{%- if render == 'bloc' -%}
|
||||
<div class="chill-entity entity-address">
|
||||
{% if options['has_no_address'] == true and address.isNoAddress == true %}
|
||||
<div class="noaddress">
|
||||
{{ 'address.consider homeless'|trans }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="address{% if options['multiline'] %} multiline{% endif %}{% if options['with_delimiter'] %} delimiter{% endif %}">
|
||||
{% if options['with_picto'] %}
|
||||
<i class="fa fa-fw fa-map-marker"></i>
|
||||
{% endif %}
|
||||
{{ _self.raw(address, options) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{{ _self.validity(address, options) }}
|
||||
</div>
|
||||
{%- endif -%}
|
||||
|
@@ -60,14 +60,22 @@
|
||||
{{- form_errors(form) -}}
|
||||
</div>
|
||||
{%- else -%}
|
||||
{{- form_label(form) -}}
|
||||
<div class="{{ block('form_group_class') }}">
|
||||
{{- form_widget(form, widget_attr) -}}
|
||||
{{- form_help(form) -}}
|
||||
{{- form_errors(form) -}}
|
||||
</div>
|
||||
{% if form.vars.hideLabel is not defined or form.vars.hideLabel == false %}
|
||||
{{- form_label(form) -}}
|
||||
<div class="{{ block('form_group_class') }}">
|
||||
{{- form_widget(form, widget_attr) -}}
|
||||
{{- form_help(form) -}}
|
||||
{{- form_errors(form) -}}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="col-sm">
|
||||
{{- form_widget(form, widget_attr) -}}
|
||||
{{- form_help(form) -}}
|
||||
{{- form_errors(form) -}}
|
||||
</div>
|
||||
{% endif %}
|
||||
{%- endif -%}
|
||||
{##}</div>
|
||||
</div>
|
||||
{%- endif -%}
|
||||
{%- endblock form_row %}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{#
|
||||
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||
<info@champs-libres.coop> / <http://www.champs-libres.coop>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@@ -19,15 +19,15 @@
|
||||
{% block form_row %}
|
||||
{% apply spaceless %}
|
||||
{% if form.vars.hideLabel is not defined or form.vars.hideLabel == false %}
|
||||
<div class="container-fluid mb-2">
|
||||
<div class="mb-2">
|
||||
<div class="row">
|
||||
<div class="{% apply spaceless %}
|
||||
{% if attr.class is defined and ('cf-title' in attr.class or 'cf-fields' in attr.class ) %}
|
||||
col-12
|
||||
col-sm-12
|
||||
{% elseif attr.class is defined and 'multiple-cf-inline' in attr.class %}
|
||||
col-2 col-md-4 clear
|
||||
col-sm-2 col-md-4 clear
|
||||
{% else %}
|
||||
col-4 clear
|
||||
col-sm-4 clear
|
||||
{% endif %}
|
||||
{% endapply %}">
|
||||
{% if attr.class is not defined or ('cf-title' not in attr.class and 'cf-fields' not in attr.class ) %}
|
||||
@@ -36,13 +36,13 @@
|
||||
</div>
|
||||
<div class="{% apply spaceless %}
|
||||
{% if attr.class is defined and 'cf-title' in attr.class %}
|
||||
col-12
|
||||
col-sm-12
|
||||
{% elseif attr.class is defined and 'cf-fields' in attr.class %}
|
||||
col-12 parent
|
||||
col-sm-12 parent
|
||||
{% elseif attr.class is defined and 'multiple-cf-inline' in attr.class %}
|
||||
col-2 col-md-8 multiple-cf-inline
|
||||
col-sm-2 col-md-8 multiple-cf-inline
|
||||
{% else %}
|
||||
col-8
|
||||
col-sm-8
|
||||
{% endif %}
|
||||
{% endapply %}">
|
||||
{{ form_widget(form) }}
|
||||
@@ -55,7 +55,7 @@
|
||||
{% endif %}
|
||||
{% endapply %}
|
||||
{% endblock form_row %}
|
||||
|
||||
|
||||
{% block choice_widget_expanded %}
|
||||
{% apply spaceless %}
|
||||
<div {{ block('widget_container_attributes') }} class="choice-widget-expanded">
|
||||
@@ -125,7 +125,7 @@
|
||||
</div>
|
||||
{%- endif -%}
|
||||
{%- endblock time_widget -%}
|
||||
|
||||
|
||||
{% block form_errors %}
|
||||
{% apply spaceless %}
|
||||
{% if errors|length > 0 %}
|
||||
@@ -140,27 +140,27 @@
|
||||
|
||||
{% block _formatter__aggregator_placement_csv_formatter_row %}
|
||||
<h3>{{ form_label(form) }}</h3>
|
||||
|
||||
|
||||
{{ form_row(form.order) }}
|
||||
|
||||
|
||||
{{ form_row(form.position) }}
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block _formatter__aggregator_placement_spreadsheet_formatter_row %}
|
||||
<h3>{{ form_label(form) }}</h3>
|
||||
|
||||
|
||||
{{ form_row(form.order) }}
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block chill_collection_widget %}
|
||||
<div class="chill-collection">
|
||||
<ul class="list-entry"
|
||||
data-collection-name="{{ form.vars.name|escape('html_attr') }}"
|
||||
data-collection-identifier="{{ form.vars.identifier|escape('html_attr') }}"
|
||||
data-collection-button-remove-label="{{ form.vars.button_remove_label|trans|e }}"
|
||||
data-collection-allow-add="{{ form.vars.allow_add|escape('html_attr') }}"
|
||||
<ul class="list-entry"
|
||||
data-collection-name="{{ form.vars.name|escape('html_attr') }}"
|
||||
data-collection-identifier="{{ form.vars.identifier|escape('html_attr') }}"
|
||||
data-collection-button-remove-label="{{ form.vars.button_remove_label|trans|e }}"
|
||||
data-collection-allow-add="{{ form.vars.allow_add|escape('html_attr') }}"
|
||||
data-collection-allow-delete="{{ form.vars.allow_delete|escape('html_attr') }}">
|
||||
{% for entry in form %}
|
||||
<li class="entry" data-collection-is-persisted="1">
|
||||
@@ -172,14 +172,14 @@
|
||||
</ul>
|
||||
|
||||
{% if form.vars.allow_add == 1 %}
|
||||
<button class="add-entry btn btn-misc"
|
||||
data-collection-add-target="{{ form.vars.name|escape('html_attr') }}"
|
||||
<button class="add-entry btn btn-misc"
|
||||
data-collection-add-target="{{ form.vars.name|escape('html_attr') }}"
|
||||
data-form-prototype="{{ ('<div>' ~ form_widget(form.vars.prototype) ~ '</div>')|escape('html_attr') }}" >
|
||||
<i class="fa fa-plus fa-fw"></i>
|
||||
{{ form.vars.button_add_label|trans }}
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
@@ -0,0 +1 @@
|
||||
<div class="responsive"></div>
|
@@ -0,0 +1,42 @@
|
||||
{% extends "@ChillMain/layout.html.twig" %}
|
||||
|
||||
{% block content %}
|
||||
<div id="container content">
|
||||
<div class="grid-8 centered">
|
||||
<h1>{{ "Notifications list" | trans }}</h1>
|
||||
<!-- TODO : UNREAD & READ -->
|
||||
|
||||
{%for data in datas %}
|
||||
{% set notification = data.notification %}
|
||||
|
||||
<dl class="chill_view_data">
|
||||
<dt class="inline">{{ 'Message'|trans }}</dt>
|
||||
<dd>{{ notification.message }}</dd>
|
||||
</dl>
|
||||
|
||||
<dl class="chill_view_data">
|
||||
<dt class="inline">{{ 'Date'|trans }}</dt>
|
||||
<dd>{{ notification.date | date('long') }}</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
<dl class="chill_view_data">
|
||||
<dt class="inline">{{ 'Sender'|trans }}</dt>
|
||||
<dd>{{ notification.sender }}</dd>
|
||||
</dl>
|
||||
|
||||
<dl class="chill_view_data">
|
||||
<dt class="inline">{{ 'Addressees'|trans }}</dt>
|
||||
<dd>{{ notification.addressees |join(', ') }}</dd>
|
||||
</dl>
|
||||
|
||||
<dl class="chill_view_data">
|
||||
<dt class="inline">{{ 'Entity'|trans }}</dt>
|
||||
<dd>
|
||||
{% include data.template with data.template_data %}
|
||||
</dd>
|
||||
</dl>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
@@ -1 +1 @@
|
||||
{% if nb > 0 %}<span class="notification-counter">{{ nb }}</span>{% endif %}
|
||||
{% if nb > 0 %}<span class="badge rounded-pill bg-danger notification-counter">{{ nb }}</span>{% endif %}
|
||||
|
@@ -38,6 +38,9 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{#
|
||||
{{ include('@ChillMain/Layout/_debug.html.twig') }}
|
||||
#}
|
||||
{{ include('@ChillMain/Layout/_header.html.twig') }}
|
||||
|
||||
{% block top_banner %}{#
|
||||
@@ -50,30 +53,23 @@
|
||||
{% block sublayout_content %}
|
||||
<div class="row justify-content-center my-5">
|
||||
|
||||
{# Flash messages ! #}
|
||||
{% if app.session.flashbag.all()|length > 0 %}
|
||||
<div class="col-8 mb-5 flash_message">
|
||||
{% for flashMessage in app.session.flashbag.get('success') %}
|
||||
<div class="col-8 mb-5 alert alert-success flash_message">
|
||||
<span>{{ flashMessage|raw }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% for flashMessage in app.session.flashbag.get('success') %}
|
||||
<div class="col-8 alert alert-success flash_message">
|
||||
<span>{{ flashMessage|raw }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% for flashMessage in app.session.flashbag.get('error') %}
|
||||
<div class="col-8 mb-5 alert alert-danger flash_message">
|
||||
<span>{{ flashMessage|raw }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% for flashMessage in app.session.flashbag.get('error') %}
|
||||
<div class="col-8 alert alert-danger flash_message">
|
||||
<span>{{ flashMessage|raw }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% for flashMessage in app.session.flashbag.get('notice') %}
|
||||
<div class="col-8 alert alert-warning flash_message">
|
||||
<span>{{ flashMessage|raw }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% for flashMessage in app.session.flashbag.get('notice') %}
|
||||
<div class="col-8 mb-5 alert alert-warning flash_message">
|
||||
<span>{{ flashMessage|raw }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-8 main_search">
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{#
|
||||
* Copyright (C) 2014-2021, Champs Libres Cooperative SCRLFS,
|
||||
* Copyright (C) 2014-2021, Champs Libres Cooperative SCRLFS,
|
||||
<info@champs-libres.coop> / <http://www.champs-libres.coop>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@@ -27,30 +27,23 @@
|
||||
<div class="row">
|
||||
<div class="col-md-9 my-5">
|
||||
|
||||
{# Flash messages ! #}
|
||||
{% if app.session.flashbag.all()|length > 0 %}
|
||||
<div class="row justify-content-center mb-5">
|
||||
{% for flashMessage in app.session.flashbag.get('success') %}
|
||||
<div class="col-8 mb-5 alert alert-success flash_message">
|
||||
<span>{{ flashMessage|raw }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% for flashMessage in app.session.flashbag.get('success') %}
|
||||
<div class="col-8 alert alert-success flash_message">
|
||||
<span>{{ flashMessage|raw }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% for flashMessage in app.session.flashbag.get('error') %}
|
||||
<div class="col-8 mb-5 alert alert-danger flash_message">
|
||||
<span>{{ flashMessage|raw }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% for flashMessage in app.session.flashbag.get('error') %}
|
||||
<div class="col-8 alert alert-danger flash_message">
|
||||
<span>{{ flashMessage|raw }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% for flashMessage in app.session.flashbag.get('notice') %}
|
||||
<div class="col-8 alert alert-warning flash_message">
|
||||
<span>{{ flashMessage|raw }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% for flashMessage in app.session.flashbag.get('notice') %}
|
||||
<div class="col-8 mb-5 alert alert-warning flash_message">
|
||||
<span>{{ flashMessage|raw }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% block layout_wvm_content %}<!-- content of the layoutWithVerticalMenu is empty -->
|
||||
{% endblock %}
|
||||
|
@@ -28,11 +28,11 @@ abstract class AbstractChillEntityRender implements ChillEntityRenderInterface
|
||||
{
|
||||
protected function getDefaultOpeningBox($classSuffix): string
|
||||
{
|
||||
return '<span class="chill-entity chill-entity__'.$classSuffix.'">';
|
||||
return '<section class="chill-entity entity-'.$classSuffix.'">';
|
||||
}
|
||||
|
||||
protected function getDefaultClosingBox(): string
|
||||
{
|
||||
return '</span>';
|
||||
return '</section>';
|
||||
}
|
||||
}
|
||||
|
@@ -10,16 +10,20 @@ class AddressRender implements ChillEntityRenderInterface
|
||||
private EngineInterface $templating;
|
||||
|
||||
public const DEFAULT_OPTIONS = [
|
||||
'with_valid_from' => true,
|
||||
'with_valid_from' => false,
|
||||
'with_valid_to' => false,
|
||||
'with_picto' => false,
|
||||
'with_delimiter' => false,
|
||||
'has_no_address' => false,
|
||||
'multiline' => true,
|
||||
'extended_infos' => false
|
||||
];
|
||||
|
||||
public function __construct(EngineInterface $templating)
|
||||
{
|
||||
$this->templating = $templating;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@@ -56,11 +60,12 @@ class AddressRender implements ChillEntityRenderInterface
|
||||
*/
|
||||
public function renderBox($addr, array $options): string
|
||||
{
|
||||
$options = \array_merge(self::DEFAULT_OPTIONS, $options);
|
||||
$options = \array_merge(self::DEFAULT_OPTIONS, $options);
|
||||
|
||||
return $this->templating
|
||||
->render('@ChillMain/Address/entity_render.html.twig', [
|
||||
->render('@ChillMain/Entity/address.html.twig', [
|
||||
'address' => $addr,
|
||||
'render' => $options['render'] ?? 'bloc',
|
||||
'options' => $options
|
||||
]);
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* This class provide a set of tests for exports.
|
||||
*
|
||||
*
|
||||
* The tests provided by this class will check basic things, like
|
||||
* the type of value are conform to the expected, etc.
|
||||
*
|
||||
@@ -34,45 +34,45 @@ use Symfony\Component\HttpFoundation\Request;
|
||||
*/
|
||||
abstract class AbstractExportTest extends WebTestCase
|
||||
{
|
||||
|
||||
|
||||
use PrepareClientTrait;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create an instance of the report to test
|
||||
*
|
||||
*
|
||||
* @return \Chill\MainBundle\Export\ExportInterface an instance of the export to test
|
||||
*/
|
||||
public abstract function getExport();
|
||||
|
||||
|
||||
/**
|
||||
* Create possible combinaison of data (produced by the form).
|
||||
*
|
||||
*
|
||||
* This data will be used to generate data providers using this data.
|
||||
*
|
||||
*
|
||||
* @return array an array of data. Example : `array( array(), array('fields' => array(1,2,3), ...)` where an empty array and `array(1,2,3)` are possible values
|
||||
*/
|
||||
public abstract function getFormData();
|
||||
|
||||
|
||||
/**
|
||||
* get the possible modifiers which could apply in combination to this
|
||||
* get the possible modifiers which could apply in combination to this
|
||||
* export.
|
||||
* .
|
||||
*
|
||||
* @return array of string[] an array which contains an array of possible modifiers. Example : `array( array('modifier_1', 'modifier_2'), array('modifier_1'), ...)`
|
||||
* .
|
||||
*
|
||||
* @return array of string[] an array which contains an array of possible modifiers. Example : `array( array('modifier_1', 'modifier_2'), array('modifier_1'), ...)`
|
||||
*/
|
||||
abstract public function getModifiersCombination();
|
||||
|
||||
|
||||
/**
|
||||
* Return an array usable as ACL
|
||||
*
|
||||
*
|
||||
* If this method is overridden, the returned result must be an array
|
||||
* with this form :
|
||||
*
|
||||
*
|
||||
* ```
|
||||
* array(
|
||||
* array(
|
||||
* 'center' => //center instance
|
||||
* array(
|
||||
* 'center' => //center instance
|
||||
* 'circles' => array(// array of circles instances )
|
||||
* )
|
||||
* );
|
||||
@@ -84,15 +84,15 @@ abstract class AbstractExportTest extends WebTestCase
|
||||
if (static::$kernel === null) {
|
||||
static::bootKernel();
|
||||
}
|
||||
|
||||
|
||||
$em = static::$kernel->getContainer()
|
||||
->get('doctrine.orm.entity_manager');
|
||||
|
||||
|
||||
$centers = $em->getRepository('ChillMainBundle:Center')
|
||||
->findAll();
|
||||
$circles = $em->getRepository('ChillMainBundle:Scope')
|
||||
->findAll();
|
||||
|
||||
|
||||
if (count($centers) === 0) {
|
||||
throw new \RuntimeException("No center found. Did you forget to "
|
||||
. "run `doctrine:fixtures:load` command before ?");
|
||||
@@ -101,7 +101,7 @@ abstract class AbstractExportTest extends WebTestCase
|
||||
throw new \RuntimeException("No circle found. Did you forget to "
|
||||
. "run `doctrine:fixtures:load` command before ?");
|
||||
}
|
||||
|
||||
|
||||
return array([
|
||||
'center' => $centers[0],
|
||||
'circles' => [
|
||||
@@ -115,204 +115,203 @@ abstract class AbstractExportTest extends WebTestCase
|
||||
public function testGetType()
|
||||
{
|
||||
$export = $this->getExport();
|
||||
|
||||
$this->assertInternalType('string', $export->getType(),
|
||||
|
||||
$this->assertInternalType('string', $export->getType(),
|
||||
"Assert that the `getType` method return a string");
|
||||
$this->assertNotEmpty($export->getType(), "Assert that the `getType` method"
|
||||
. " does not return an empty string.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test that the description is not empty
|
||||
*/
|
||||
public function testGetDescription()
|
||||
{
|
||||
$export = $this->getExport();
|
||||
|
||||
$this->assertInternalType('string', $export->getDescription(),
|
||||
|
||||
$this->assertInternalType('string', $export->getDescription(),
|
||||
"Assert that the `getDescription` method return a string");
|
||||
$this->assertNotEmpty($export->getDescription(),
|
||||
$this->assertNotEmpty($export->getDescription(),
|
||||
"Assert that the `getDescription` method does not return an empty "
|
||||
. "string.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* create data for `ìnitiateQuery` method
|
||||
*/
|
||||
public function dataProviderInitiateQuery()
|
||||
{
|
||||
$acl = $this->getAcl();
|
||||
|
||||
|
||||
foreach($this->getModifiersCombination() as $modifiers) {
|
||||
|
||||
|
||||
foreach($this->getFormData() as $data) {
|
||||
|
||||
|
||||
yield array($modifiers, $acl, $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function dataProviderGetQueryKeys()
|
||||
{
|
||||
foreach($this->getFormData() as $data) {
|
||||
yield array($data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* test that the query returned is a QueryBuilder or a NativeQuery.
|
||||
*
|
||||
*
|
||||
* If the query is a QueryBuilder, test that select and from is not empty.
|
||||
*
|
||||
* If the query is a native sql, test the query is not empty (length is
|
||||
*
|
||||
* If the query is a native sql, test the query is not empty (length is
|
||||
* > 0).
|
||||
*
|
||||
*
|
||||
* @dataProvider dataProviderInitiateQuery
|
||||
*/
|
||||
public function testInitiateQuery($modifiers, $acl, $data)
|
||||
{
|
||||
var_dump($data);
|
||||
$query = $this->getExport()->initiateQuery($modifiers, $acl, $data);
|
||||
|
||||
|
||||
$this->assertTrue($query instanceof QueryBuilder || $query instanceof NativeQuery,
|
||||
sprintf("Assert that the returned query is an instance of %s or %s",
|
||||
sprintf("Assert that the returned query is an instance of %s or %s",
|
||||
QueryBuilder::class, Query::class));
|
||||
|
||||
|
||||
if ($query instanceof QueryBuilder) {
|
||||
|
||||
|
||||
$this->assertGreaterThanOrEqual(1, count($query->getDQLPart('select')),
|
||||
"assert there is at least one 'select' part");
|
||||
|
||||
|
||||
$this->assertGreaterThanOrEqual(1, count($query->getDQLPart('from')),
|
||||
"assert there is at least one 'from' part");
|
||||
|
||||
|
||||
} elseif ($query instanceof NativeQuery) {
|
||||
$this->assertNotEmpty($query->getSQL(),
|
||||
$this->assertNotEmpty($query->getSQL(),
|
||||
"check that the SQL query is not empty");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test that supportsModifier return :
|
||||
*
|
||||
*
|
||||
* - an array of string, if the query is a QueryBuilder ;
|
||||
* - nothing, if the query is a native SQL
|
||||
*
|
||||
*
|
||||
* @dataProvider dataProviderInitiateQuery
|
||||
*/
|
||||
public function testSupportsModifier($modifiers, $acl, $data)
|
||||
{
|
||||
$export = $this->getExport();
|
||||
$query = $export->initiateQuery($modifiers, $acl, $data);
|
||||
|
||||
|
||||
if ($query instanceof QueryBuilder) {
|
||||
$this->assertContainsOnly('string', $export->supportsModifiers(),
|
||||
"Test that the `supportsModifiers` method returns only strings");
|
||||
} elseif ($query instanceof NativeQuery) {
|
||||
$this->assertTrue($export->supportsModifiers() === null ||
|
||||
$this->assertTrue($export->supportsModifiers() === null ||
|
||||
count($export->supportsModifiers()) === 0,
|
||||
"Test that the `supportsModifier` methods returns null or an empty array");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test required role is an instance of Role
|
||||
*/
|
||||
public function testRequiredRole()
|
||||
{
|
||||
$role = $this->getExport()->requiredRole();
|
||||
|
||||
$this->assertInstanceOf(Role::class, $role,
|
||||
|
||||
$this->assertInstanceOf(Role::class, $role,
|
||||
sprintf("test that the returned value of `requiredRole` is an instance "
|
||||
. "of %s", Role::class));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test the formatters type are string
|
||||
*/
|
||||
public function testGetAllowedFormattersType()
|
||||
{
|
||||
$formattersTypes = $this->getExport()->getAllowedFormattersTypes();
|
||||
|
||||
|
||||
$this->assertContainsOnly("string", $formattersTypes,
|
||||
"Test that the method `getAllowedFormattersTypes` returns an array of string");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test that the query keys are strings
|
||||
*
|
||||
*
|
||||
* @param array $data
|
||||
* @dataProvider dataProviderGetQueryKeys
|
||||
*/
|
||||
public function testGetQueryKeys(array $data)
|
||||
{
|
||||
$queryKeys = $this->getExport()->getQueryKeys($data);
|
||||
|
||||
|
||||
$this->assertContainsOnly("string", $queryKeys,
|
||||
"test that the query keys returned by `getQueryKeys` are only strings");
|
||||
$this->assertGreaterThanOrEqual(1, count($queryKeys),
|
||||
"test that there are at least one query key returned");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Test that
|
||||
*
|
||||
*
|
||||
* Test that
|
||||
*
|
||||
* - the results have a correct form (are arrays or traversable)
|
||||
* - each key in a row are present in getQueryKeys ;
|
||||
* - each returned object of the `getLabels` method is callable
|
||||
* - each result can be converted to string using this callable
|
||||
* - each of this callable can provide a string for '_header'
|
||||
*
|
||||
*
|
||||
* @param string[] $modifiers
|
||||
* @param array $acl
|
||||
* @param array $data
|
||||
*
|
||||
*
|
||||
* @dataProvider dataProviderInitiateQuery
|
||||
*/
|
||||
public function testGetResultsAndLabels($modifiers, $acl, array $data)
|
||||
{
|
||||
// it is more convenient to group the `getResult` and `getLabels` test
|
||||
// due to the fact that testing both methods use the same tools.
|
||||
|
||||
|
||||
$queryKeys = $this->getExport()->getQueryKeys($data);
|
||||
$query = $this->getExport()->initiateQuery($modifiers, $acl, $data);
|
||||
|
||||
|
||||
// limit the result for the query for performance reason (only for QueryBuilder,
|
||||
// not possible in NativeQuery)
|
||||
if ($query instanceof QueryBuilder) {
|
||||
$query->setMaxResults(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$results = $this->getExport()->getResult($query, $data);
|
||||
|
||||
$this->assertInternalType('array', $results,
|
||||
|
||||
$this->assertInternalType('array', $results,
|
||||
"assert that the returned result is an array");
|
||||
|
||||
|
||||
if (count($results) === 0) {
|
||||
$this->markTestIncomplete("The result is empty. We cannot process tests "
|
||||
. "on results");
|
||||
}
|
||||
|
||||
|
||||
// testing the result
|
||||
$result = $results[0];
|
||||
|
||||
|
||||
$this->assertTrue( $result instanceof \Traversable || is_array($result),
|
||||
"test that each row in the result is traversable or an array");
|
||||
|
||||
|
||||
foreach ($result as $key => $value) {
|
||||
$this->assertContains($key, $queryKeys,
|
||||
"test that each key is present in `getQueryKeys`");
|
||||
|
||||
|
||||
$closure = $this->getExport()->getLabels($key, array($value), $data);
|
||||
|
||||
|
||||
$this->assertTrue(is_callable($closure, false),
|
||||
"test that the `getLabels` for key is a callable");
|
||||
$this->assertTrue(is_string((string) call_user_func($closure, $value)),
|
||||
sprintf("test that the callable return by `getLabels` for key %s "
|
||||
. "is a string or an be converted to a string", $key));
|
||||
|
||||
|
||||
$this->assertTrue(
|
||||
// conditions
|
||||
is_string((string) call_user_func($closure, '_header'))
|
||||
@@ -322,13 +321,13 @@ abstract class AbstractExportTest extends WebTestCase
|
||||
sprintf("Test that the callable return by `getLabels` for key %s "
|
||||
. "can provide an header", $key)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test that the translated title of the export is present the list,
|
||||
* Test that the translated title of the export is present the list,
|
||||
* and that the list of exports (under `/fr/exports/`) is still successfull
|
||||
*/
|
||||
public function testListExportPage()
|
||||
@@ -338,17 +337,17 @@ abstract class AbstractExportTest extends WebTestCase
|
||||
$export = $this->getExport();
|
||||
$prophet= new \Prophecy\Prophet;
|
||||
$container = static::$kernel->getContainer();
|
||||
|
||||
|
||||
// store the locale in a request
|
||||
$request = new Request();
|
||||
$request->setLocale('fr');
|
||||
$container->get('request_stack')->push($request);
|
||||
// translate the title
|
||||
$title = $container->get('translator')->trans($export->getTitle());
|
||||
|
||||
|
||||
// performs the request to /fr/exports
|
||||
$crawler = $client->request('GET', '/fr/exports/');
|
||||
|
||||
|
||||
// and finally make tests
|
||||
$this->assertTrue($client->getResponse()->isSuccessful(),
|
||||
"test that the response of /fr/exports/ is successful");
|
||||
|
@@ -34,6 +34,10 @@ chill_password_recover:
|
||||
resource: "@ChillMainBundle/config/routes/password_recover.yaml"
|
||||
prefix: "public/{_locale}/password"
|
||||
|
||||
chill_main_notification:
|
||||
resource: "@ChillMainBundle/config/routes/notification.yaml"
|
||||
prefix: "{_locale}/notification"
|
||||
|
||||
chill_crud:
|
||||
resource: "@ChillMainBundle"
|
||||
type: CRUD
|
||||
|
@@ -33,3 +33,8 @@ services:
|
||||
$logger: '@Psr\Log\LoggerInterface'
|
||||
$validator: '@Symfony\Component\Validator\Validator\ValidatorInterface'
|
||||
tags: ['controller.service_arguments']
|
||||
|
||||
Chill\MainBundle\Controller\NotificationController:
|
||||
arguments:
|
||||
$security: '@Symfony\Component\Security\Core\Security'
|
||||
tags: ['controller.service_arguments']
|
||||
|
@@ -4,7 +4,11 @@ services:
|
||||
$logger: '@Psr\Log\LoggerInterface'
|
||||
$twig: '@Twig\Environment'
|
||||
$mailer: '@swiftmailer.mailer.default'
|
||||
# $mailerTransporter: '@swiftmailer.transport'
|
||||
# $mailerTransporter: '@swiftmailer.transport'
|
||||
$router: '@Symfony\Component\Routing\RouterInterface'
|
||||
$translator: '@Symfony\Component\Translation\TranslatorInterface'
|
||||
$routeParameters: '%chill_main.notifications%'
|
||||
|
||||
Chill\MainBundle\Notification\NotificationRenderer:
|
||||
autoconfigure: true
|
||||
autowire: true
|
||||
|
@@ -2,6 +2,8 @@ services:
|
||||
chill_main.paginator_factory:
|
||||
class: Chill\MainBundle\Pagination\PaginatorFactory
|
||||
public: true
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
arguments:
|
||||
- "@request_stack"
|
||||
- "@router"
|
||||
|
@@ -0,0 +1,6 @@
|
||||
years_old: >-
|
||||
{age, plural,
|
||||
one {# an}
|
||||
many {# ans}
|
||||
other {# ans}
|
||||
}
|
Reference in New Issue
Block a user