mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-09-26 16:45:01 +00:00
Compare commits
2 Commits
v4.2.1
...
385-invita
Author | SHA1 | Date | |
---|---|---|---|
95d9a75e46 | |||
90e3043c3d |
6
.changes/unreleased/Feature-20250808-120802.yaml
Normal file
6
.changes/unreleased/Feature-20250808-120802.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: Feature
|
||||||
|
body: Create invitation list in user menu
|
||||||
|
time: 2025-08-08T12:08:02.446361367+02:00
|
||||||
|
custom:
|
||||||
|
Issue: "385"
|
||||||
|
SchemaChange: No schema change
|
@@ -27,11 +27,11 @@ Chill is a comprehensive web application built as a set of Symfony bundles. It i
|
|||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
Note: This is a project which exists from a long time ago, and we found multiple structure inside each bundle. When having the choice, the developers should choose the new structure.
|
Note: This is a project that's existed for a long time, and throughout the years we've used multiple structures inside each bundle. When having the choice, the developers should choose the new structure.
|
||||||
|
|
||||||
The project follows a standard Symfony bundle structure:
|
The project follows a standard Symfony bundle structure:
|
||||||
- `/src/Bundle/`: Contains all the Chill bundles. The code is either at the root of the bundle directory, or within a `src/` directory (preferred). See psr4 mapping at the root's `composer.json`.
|
- `/src/Bundle/`: Contains all the Chill bundles. The code is either at the root of the bundle directory, or within a `src/` directory (preferred). See psr4 mapping at the root's `composer.json`.
|
||||||
- each bundle come with his own tests, either in the `Tests` directory (when the code is directly within the bundle directory (for instance `src/Bundle/ChillMainBundle/Tests`, `src/Bundle/ChillPersonBundle/Tests`)), or inside the `tests` directory, alongside to the `src/` sub-directory (example: `src/Bundle/ChillWopiBundle/tests`) (this is the preferred way).
|
- each bundle comes with its own tests, either in the `Tests` directory (when the code is directly within the bundle directory (for instance `src/Bundle/ChillMainBundle/Tests`, `src/Bundle/ChillPersonBundle/Tests`)), or inside the `tests` directory, alongside the `src/` sub-directory (example: `src/Bundle/ChillWopiBundle/tests`) (this is the preferred way).
|
||||||
- `/docs/`: Contains project documentation
|
- `/docs/`: Contains project documentation
|
||||||
|
|
||||||
Each bundle typically has the following structure:
|
Each bundle typically has the following structure:
|
||||||
@@ -46,13 +46,13 @@ Each bundle typically has the following structure:
|
|||||||
|
|
||||||
### A special word about TicketBundle
|
### A special word about TicketBundle
|
||||||
|
|
||||||
The ticket bundle is developed using a kind of "Command" pattern. The controller fill a "Command", and a "CommandHandler" handle this command. They are savec in the `src/Bundle/ChillTicketBundle/src/Action` directory.
|
The ticket bundle is developed using a kind of "Command" pattern. The controller fills a "Command," and a "CommandHandler" handles this command. They are saved in the `src/Bundle/ChillTicketBundle/src/Action` directory.
|
||||||
|
|
||||||
## Development Guidelines
|
## Development Guidelines
|
||||||
|
|
||||||
### Building and Configuration Instructions
|
### Building and Configuration Instructions
|
||||||
|
|
||||||
All the command should be run through the `symfony` command, which will configure the required variables.
|
All the commands should be run through the `symfony` command, which will configure the required variables.
|
||||||
|
|
||||||
For assets, we must ensure that we use node at version `^20.0.0`. This is done using `nvm use 20`.
|
For assets, we must ensure that we use node at version `^20.0.0`. This is done using `nvm use 20`.
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ For assets, we must ensure that we use node at version `^20.0.0`. This is done u
|
|||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
5. **Set Up the Database**:
|
6. **Set Up the Database**:
|
||||||
```bash
|
```bash
|
||||||
# Create the database
|
# Create the database
|
||||||
symfony console doctrine:database:create
|
symfony console doctrine:database:create
|
||||||
@@ -99,20 +99,20 @@ For assets, we must ensure that we use node at version `^20.0.0`. This is done u
|
|||||||
symfony console doctrine:fixtures:load
|
symfony console doctrine:fixtures:load
|
||||||
```
|
```
|
||||||
|
|
||||||
6. **Build Assets**:
|
7. **Build Assets**:
|
||||||
```bash
|
```bash
|
||||||
nvm use 20
|
nvm use 20
|
||||||
yarn run encore dev
|
yarn run encore dev
|
||||||
```
|
```
|
||||||
|
|
||||||
7. **Start the Development Server**:
|
8. **Start the Development Server**:
|
||||||
```bash
|
```bash
|
||||||
symfony server:start -d
|
symfony server:start -d
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Docker Setup
|
#### Docker Setup
|
||||||
|
|
||||||
The project includes Docker configuration for easier development:
|
The project includes a Docker configuration for easier development:
|
||||||
|
|
||||||
1. **Start Docker Services**:
|
1. **Start Docker Services**:
|
||||||
```bash
|
```bash
|
||||||
@@ -153,9 +153,9 @@ Key configuration files:
|
|||||||
|
|
||||||
Each time a doctrine entity is created, we generate migration to adapt the database.
|
Each time a doctrine entity is created, we generate migration to adapt the database.
|
||||||
|
|
||||||
The migration are created using the command `symfony console doctrine:migrations:diff --no-interaction --namespace <namespace>`, where the namespace is the relevant namespace for migration. As this is a bash script, do not forget to quote the `\` (`\` must become `\\` in your command).
|
The migration is created using the command `symfony console doctrine:migrations:diff --no-interaction --namespace <namespace>`, where the namespace is the relevant namespace for migration. As this is a bash script, remember to quote the `\` (`\` must become `\\` in your command).
|
||||||
|
|
||||||
Each bundle has his own namespace for migration (always ask me to confirm that command, with a list of updated / created entities so that I can confirm you that it is ok):
|
Each bundle has his own namespace for migration (always ask me to confirm that command with a list of updated / created entities so that I can confirm to you that it is ok):
|
||||||
|
|
||||||
- `Chill\Bundle\ActivityBundle` writes migrations to `Chill\Migrations\Activity`;
|
- `Chill\Bundle\ActivityBundle` writes migrations to `Chill\Migrations\Activity`;
|
||||||
- `Chill\Bundle\BudgetBundle` writes migrations to `Chill\Migrations\Budget`;
|
- `Chill\Bundle\BudgetBundle` writes migrations to `Chill\Migrations\Budget`;
|
||||||
@@ -183,7 +183,7 @@ Once created the, comment's classes should be removed and a description of the c
|
|||||||
|
|
||||||
When we need to use a DateTime or DateTimeImmutable that need to express "now", we prefer the usage of
|
When we need to use a DateTime or DateTimeImmutable that need to express "now", we prefer the usage of
|
||||||
`Symfony\Component\Clock\ClockInterface`, where possible. This is usually not possible in doctrine entities,
|
`Symfony\Component\Clock\ClockInterface`, where possible. This is usually not possible in doctrine entities,
|
||||||
where injection does not work when restoring an entity from database, but usually possible in services.
|
where injection does not work when restoring an entity from a database, but usually possible in services.
|
||||||
|
|
||||||
In test, we use `\Symfony\Component\Clock\MockClock` which is an implementation of `Symfony\Component\Clock\ClockInterface`
|
In test, we use `\Symfony\Component\Clock\MockClock` which is an implementation of `Symfony\Component\Clock\ClockInterface`
|
||||||
where we have full and easy control of the date.
|
where we have full and easy control of the date.
|
||||||
@@ -198,9 +198,9 @@ The project uses PHPUnit for testing. Each bundle has its own test suite, and th
|
|||||||
|
|
||||||
For creating mock, we prefer using prophecy (library phpspec/prophecy).
|
For creating mock, we prefer using prophecy (library phpspec/prophecy).
|
||||||
|
|
||||||
##### Useful helpers and tips that avoid create a mock
|
##### Useful helpers and tips that avoid creating a mock
|
||||||
|
|
||||||
Some notable implementations that are tests helper, and avoid to create a mock:
|
Some notable implementations that are test helpers and avoid creating a mock:
|
||||||
|
|
||||||
- `\Psr\Log\NullLogger`, an implementation of `\Psr\Log\LoggerInterface`;
|
- `\Psr\Log\NullLogger`, an implementation of `\Psr\Log\LoggerInterface`;
|
||||||
- `\Symfony\Component\Clock\MockClock`, an implementation of `Symfony\Component\Clock\ClockInterface` (already mentioned above);
|
- `\Symfony\Component\Clock\MockClock`, an implementation of `Symfony\Component\Clock\ClockInterface` (already mentioned above);
|
||||||
@@ -297,7 +297,7 @@ class TicketTest extends TestCase
|
|||||||
|
|
||||||
#### Test Database
|
#### Test Database
|
||||||
|
|
||||||
For tests that require a database, the project uses postgresql database filled by fixtures (usage of doctrine-fixtures). You can configure a different database for testing in the `.env.test` file.
|
For tests that require a database, the project uses a postgresql database filled with fixtures (usage of doctrine-fixtures). You can configure a different database for testing in the `.env.test` file.
|
||||||
|
|
||||||
### Code Quality Tools
|
### Code Quality Tools
|
||||||
|
|
||||||
|
@@ -266,7 +266,7 @@ class CalendarController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->getUser() instanceof User) {
|
if (!$this->getUser() instanceof User) {
|
||||||
throw new UnauthorizedHttpException('you are not an user');
|
throw new UnauthorizedHttpException('you are not a user');
|
||||||
}
|
}
|
||||||
|
|
||||||
$view = '@ChillCalendar/Calendar/listByUser.html.twig';
|
$view = '@ChillCalendar/Calendar/listByUser.html.twig';
|
||||||
|
@@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CalendarBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\CalendarBundle\Repository\InviteACLAwareRepository;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||||
|
use Doctrine\ORM\NonUniqueResultException;
|
||||||
|
use Doctrine\ORM\NoResultException;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
|
class MyInvitationsController extends AbstractController
|
||||||
|
{
|
||||||
|
public function __construct(private readonly InviteACLAwareRepository $inviteACLAwareRepository, private readonly PaginatorFactory $paginator) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NonUniqueResultException
|
||||||
|
* @throws NoResultException
|
||||||
|
*/
|
||||||
|
#[Route(path: '/{_locale}/calendar/invitations/my', name: 'chill_calendar_invitations_list_my')]
|
||||||
|
public function myInvitations(Request $request): Response
|
||||||
|
{
|
||||||
|
$this->denyAccessUnlessGranted('ROLE_USER');
|
||||||
|
|
||||||
|
$user = $this->getUser();
|
||||||
|
|
||||||
|
if (!$user instanceof User) {
|
||||||
|
throw new UnauthorizedHttpException('you are not a user');
|
||||||
|
}
|
||||||
|
|
||||||
|
$total = $this->inviteACLAwareRepository->countByUser($user);
|
||||||
|
$paginator = $this->paginator->create($total);
|
||||||
|
$invitations = $this->inviteACLAwareRepository->findByUser(
|
||||||
|
$user,
|
||||||
|
['createdAt' => 'DESC'],
|
||||||
|
$paginator->getCurrentPageFirstItemNumber(),
|
||||||
|
$paginator->getItemsPerPage()
|
||||||
|
);
|
||||||
|
|
||||||
|
dump($invitations);
|
||||||
|
|
||||||
|
$view = '@ChillCalendar/Invitations/listByUser.html.twig';
|
||||||
|
|
||||||
|
return $this->render($view, [
|
||||||
|
'invitations' => $invitations,
|
||||||
|
'paginator' => $paginator,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@@ -30,6 +30,13 @@ class UserMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
'order' => 9,
|
'order' => 9,
|
||||||
'icon' => 'tasks',
|
'icon' => 'tasks',
|
||||||
]);
|
]);
|
||||||
|
$menu->addChild('My invitations list', [
|
||||||
|
'route' => 'chill_calendar_invitations_list_my',
|
||||||
|
])
|
||||||
|
->setExtras([
|
||||||
|
'order' => 9,
|
||||||
|
'icon' => 'tasks',
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CalendarBundle\Repository;
|
||||||
|
|
||||||
|
use Chill\CalendarBundle\Entity\Invite;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Doctrine\ORM\NonUniqueResultException;
|
||||||
|
use Doctrine\ORM\NoResultException;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
|
||||||
|
readonly class InviteACLAwareRepository implements InviteACLAwareRepositoryInterface
|
||||||
|
{
|
||||||
|
public function __construct(private EntityManagerInterface $em) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NonUniqueResultException
|
||||||
|
* @throws NoResultException
|
||||||
|
*/
|
||||||
|
public function countByUser(User $user): int
|
||||||
|
{
|
||||||
|
return $this->buildQueryByUser($user)
|
||||||
|
->select('COUNT(i)')
|
||||||
|
->getQuery()
|
||||||
|
->getSingleScalarResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findByUser(User $user, ?array $orderBy = [], ?int $offset = null, ?int $limit = null): array
|
||||||
|
{
|
||||||
|
$qb = $this->buildQueryByUser($user)
|
||||||
|
->select('i');
|
||||||
|
|
||||||
|
foreach ($orderBy as $sort => $order) {
|
||||||
|
$qb->addOrderBy('i.'.$sort, $order);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $offset) {
|
||||||
|
$qb->setFirstResult($offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $limit) {
|
||||||
|
$qb->setMaxResults($limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $qb->getQuery()->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildQueryByUser(User $user): QueryBuilder
|
||||||
|
{
|
||||||
|
$qb = $this->em->createQueryBuilder()
|
||||||
|
->from(Invite::class, 'i');
|
||||||
|
|
||||||
|
$qb->where('i.user = :user');
|
||||||
|
|
||||||
|
$qb->setParameter('user', $user);
|
||||||
|
|
||||||
|
return $qb;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CalendarBundle\Repository;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
|
||||||
|
interface InviteACLAwareRepositoryInterface
|
||||||
|
{
|
||||||
|
public function countByUser(User $user): int;
|
||||||
|
|
||||||
|
public function findByUser(User $user, ?array $orderBy = [], ?int $offset = null, ?int $limit = null): array;
|
||||||
|
}
|
@@ -0,0 +1,172 @@
|
|||||||
|
{% if invitations|length > 0 %}
|
||||||
|
<div class="flex-table list-records">
|
||||||
|
|
||||||
|
{% for invitation in invitations %}
|
||||||
|
{% set calendar = invitation.getCalendar %}
|
||||||
|
|
||||||
|
{% if calendar is not null %}
|
||||||
|
<div class="item-bloc">
|
||||||
|
<div class="item-row main">
|
||||||
|
<div class="item-col">
|
||||||
|
<div class="wrap-header">
|
||||||
|
<div class="wl-row">
|
||||||
|
<div class="wl-col title">
|
||||||
|
<p class="date-label">
|
||||||
|
{% if calendar.endDate.diff(calendar.startDate).days >= 1 %}
|
||||||
|
{{ calendar.startDate|format_datetime('short', 'short') }}
|
||||||
|
- {{ calendar.endDate|format_datetime('short', 'short') }}
|
||||||
|
{% else %}
|
||||||
|
{{ calendar.startDate|format_datetime('short', 'short') }}
|
||||||
|
- {{ calendar.endDate|format_datetime('none', 'short') }}
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="duration short-message">
|
||||||
|
<i class="fa fa-fw fa-hourglass-end"></i>
|
||||||
|
{{ calendar.duration|date('%H:%I') }}
|
||||||
|
{% if false == calendar.sendSMS or null == calendar.sendSMS %}
|
||||||
|
<!-- no sms will be send -->
|
||||||
|
{% else %}
|
||||||
|
{% if calendar.smsStatus == 'sms_sent' %}
|
||||||
|
<span title="{{ 'SMS already sent'|trans }}" class="badge bg-info">
|
||||||
|
<i class="fa fa-check "></i>
|
||||||
|
<i class="fa fa-envelope "></i>
|
||||||
|
</span>
|
||||||
|
{% else %}
|
||||||
|
<span title="{{ 'Will send SMS'|trans }}" class="badge bg-info">
|
||||||
|
<i class="fa fa-envelope "></i>
|
||||||
|
<i class="fa fa-hourglass-end "></i>
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-col">
|
||||||
|
<ul class="list-content">
|
||||||
|
{% if calendar.mainUser is not empty %}
|
||||||
|
<span class="badge-user">{{ calendar.mainUser|chill_entity_render_box({'at_date': calendar.startDate}) }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if calendar.comment.comment is not empty
|
||||||
|
or calendar.users|length > 0
|
||||||
|
or calendar.thirdParties|length > 0
|
||||||
|
or calendar.users|length > 0 %}
|
||||||
|
<div class="item-row details separator">
|
||||||
|
<div class="item-col">
|
||||||
|
{% include '@ChillActivity/Activity/concernedGroups.html.twig' with {
|
||||||
|
'context': calendar.context == 'person' ? 'calendar_person' : 'calendar_accompanyingCourse',
|
||||||
|
'render': 'wrap-list',
|
||||||
|
'entity': calendar
|
||||||
|
} %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if calendar.comment.comment is not empty %}
|
||||||
|
<div class="item-row details separator">
|
||||||
|
<div class="item-col comment">
|
||||||
|
{{ calendar.comment|chill_entity_render_box( { 'limit_lines': 3, 'metadata': false } ) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if calendar.location is not empty %}
|
||||||
|
<div class="item-row separator">
|
||||||
|
<div>
|
||||||
|
{% if calendar.location.address is not same as(null) and calendar.location.name is not empty %}
|
||||||
|
<i class="fa fa-map-marker"></i>{% endif %}
|
||||||
|
{% if calendar.location.name is not empty %}{{ calendar.location.name }}{% endif %}
|
||||||
|
{% if calendar.location.address is not same as(null) %}{{ calendar.location.address|chill_entity_render_box({'multiline': false, 'with_picto': (calendar.location.name is empty)}) }}{% else %}
|
||||||
|
<i class="fa fa-map-marker"></i>{% endif %}
|
||||||
|
{% if calendar.location.phonenumber1 is not empty %}<i
|
||||||
|
class="fa fa-phone"></i> {{ calendar.location.phonenumber1|chill_format_phonenumber }}{% endif %}
|
||||||
|
{% if calendar.location.phonenumber2 is not empty %}<i
|
||||||
|
class="fa fa-phone"></i> {{ calendar.location.phonenumber2|chill_format_phonenumber }}{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="item-row separator column">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
{{ include('@ChillCalendar/Calendar/_documents.twig.html') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if calendar.activity is not null %}
|
||||||
|
<div class="item-row separator">
|
||||||
|
<div class="item-col">
|
||||||
|
<div class="wrap-list">
|
||||||
|
<div class="wl-row">
|
||||||
|
<div class="wl-col title"><h3>{{ 'Activity'|trans }}</h3></div>
|
||||||
|
<div class="wl-col list activity-linked">
|
||||||
|
<h2 class="badge-title">
|
||||||
|
<span class="title_label"></span>
|
||||||
|
<span class="title_action">
|
||||||
|
{{ calendar.activity.type.name | localize_translatable_string }}
|
||||||
|
|
||||||
|
{% if calendar.activity.emergency %}
|
||||||
|
<span class="badge bg-danger rounded-pill fs-6 float-end">{{ 'Emergency'|trans|upper }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li class="cancel">
|
||||||
|
<span class="createdBy">
|
||||||
|
{{ 'Created by'|trans }}
|
||||||
|
<b>{{ calendar.activity.createdBy|chill_entity_render_string({'at_date': calendar.activity.createdAt}) }}</b>, {{ 'on'|trans }} {{ calendar.activity.createdAt|format_datetime('short', 'short') }}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
{% if is_granted('CHILL_ACTIVITY_SEE', calendar.activity) %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ chill_path_add_return_path('chill_activity_activity_show', {'id': calendar.activity.id}) }}" class="btn btn-sm btn-show" ></a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="item-row separator">
|
||||||
|
<ul class="record_actions">
|
||||||
|
|
||||||
|
{% if (calendar.isInvited(app.user)) %}
|
||||||
|
{% set invite = calendar.inviteForUser(app.user) %}
|
||||||
|
<li>
|
||||||
|
<div invite-answer data-status="{{ invite.status|e('html_attr') }}"
|
||||||
|
data-calendar-id="{{ calendar.id|e('html_attr') }}"></div>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_show', { 'id': calendar.id}) }}"
|
||||||
|
class="btn btn-show "></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if invitations|length < paginator.getTotalItems %}
|
||||||
|
{{ chill_pagination(paginator) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
@@ -0,0 +1,27 @@
|
|||||||
|
{% extends "@ChillMain/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% set activeRouteKey = 'chill_calendar_invitations_list' %}
|
||||||
|
|
||||||
|
{% block title %}{{ 'My invitations list' |trans }}{% endblock title %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>{{ 'Invitation list' |trans }}</h1>
|
||||||
|
|
||||||
|
{% if invitations|length == 0 %}
|
||||||
|
<p class="chill-no-data-statement">
|
||||||
|
{{ "There is no invitation items."|trans }}
|
||||||
|
</p>
|
||||||
|
{% else %}
|
||||||
|
{{ include ('@ChillCalendar/Invitations/_list_item.html.twig') }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
{{ parent() }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block css %}
|
||||||
|
{{ parent() }}
|
||||||
|
{% endblock %}
|
Reference in New Issue
Block a user