Merge remote-tracking branch 'origin/master' into upgrade-php82

This commit is contained in:
Julien Fastré 2023-03-03 16:18:47 +01:00
commit 4dbb195b45
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
37 changed files with 578 additions and 190 deletions

1
.gitignore vendored
View File

@ -4,6 +4,7 @@ composer.phar
composer.lock composer.lock
docs/build/ docs/build/
node_modules/* node_modules/*
.php_cs.cache
.cache/* .cache/*
###> symfony/framework-bundle ### ###> symfony/framework-bundle ###

View File

@ -61,7 +61,7 @@ class LoadCalendarRange extends Fixture implements FixtureGroupInterface, Ordere
->setEmail('centreA@test.chill.social') ->setEmail('centreA@test.chill.social')
->setLocationType($type = new LocationType()) ->setLocationType($type = new LocationType())
->setPhonenumber1(PhoneNumberUtil::getInstance()->parse('+3287653812')); ->setPhonenumber1(PhoneNumberUtil::getInstance()->parse('+3287653812'));
$type->setTitle('Service'); $type->setTitle(['fr' => 'Service']);
$address->setStreet('Rue des Épaules')->setStreetNumber('14') $address->setStreet('Rue des Épaules')->setStreetNumber('14')
->setPostcode($postCode = new PostalCode()); ->setPostcode($postCode = new PostalCode());
$postCode->setCode('4145')->setName('Houte-Si-Plout')->setCountry( $postCode->setCode('4145')->setName('Houte-Si-Plout')->setCountry(

View File

@ -12,6 +12,8 @@ declare(strict_types=1);
namespace Chill\CalendarBundle\DataFixtures\ORM; namespace Chill\CalendarBundle\DataFixtures\ORM;
use Chill\CalendarBundle\Entity\Invite; use Chill\CalendarBundle\Entity\Invite;
use Chill\MainBundle\DataFixtures\ORM\LoadUsers;
use Chill\MainBundle\Entity\User;
use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Bundle\FixturesBundle\FixtureGroupInterface; use Doctrine\Bundle\FixturesBundle\FixtureGroupInterface;
use Doctrine\Persistence\ObjectManager; use Doctrine\Persistence\ObjectManager;
@ -33,14 +35,21 @@ class LoadInvite extends Fixture implements FixtureGroupInterface
public function load(ObjectManager $manager): void public function load(ObjectManager $manager): void
{ {
$arr = [ $arr = [
['name' => ['fr' => 'Rendez-vous décliné']], [
['name' => ['fr' => 'Rendez-vous accepté']], 'name' => ['fr' => 'Rendez-vous décliné'],
'status' => Invite::DECLINED,
],
[
'name' => ['fr' => 'Rendez-vous accepté'],
'status' => Invite::ACCEPTED,
],
]; ];
foreach ($arr as $a) { foreach ($arr as $a) {
echo 'Creating calendar invite : ' . $a['name']['fr'] . "\n"; echo 'Creating calendar invite : ' . $a['name']['fr'] . "\n";
$invite = (new Invite()) $invite = (new Invite())
->setStatus($a['name']); ->setStatus($a['status'])
->setUser($this->getRandomUser());
$manager->persist($invite); $manager->persist($invite);
$reference = 'Invite_' . $a['name']['fr']; $reference = 'Invite_' . $a['name']['fr'];
$this->addReference($reference, $invite); $this->addReference($reference, $invite);
@ -49,4 +58,11 @@ class LoadInvite extends Fixture implements FixtureGroupInterface
$manager->flush(); $manager->flush();
} }
private function getRandomUser(): User
{
$userRef = array_rand(LoadUsers::$refs);
return $this->getReference($userRef);
}
} }

View File

@ -17,30 +17,20 @@
<td class="eval"> <td class="eval">
<ul class="eval_title"> <ul class="eval_title">
<li> <li>
{{ mm.mimeIcon(d.storedObject.type) }} <div class="row">
{{ d.storedObject.title }} <div class="col text-start">
{% if d.dateTimeVersion < d.calendar.dateTimeVersion %} {{ d.storedObject.title }}
<span class="badge bg-danger">{{ 'chill_calendar.Document outdated'|trans }}</span> {% if d.dateTimeVersion < d.calendar.dateTimeVersion %}
{% endif %} <span class="badge bg-danger">{{ 'chill_calendar.Document outdated'|trans }}</span>
{% endif %}
<ul class="record_actions small inline"> </div>
{% if chill_document_is_editable(d.storedObject) and is_granted('CHILL_CALENDAR_DOC_EDIT', d) %} <div class="col-md-auto text-center">
<li> {{ mm.mimeIcon(d.storedObject.type) }}
<a href="{{ chill_path_add_return_path('chill_calendar_calendardoc_delete', {'id': d.id})}}" class="btn btn-delete"></a> </div>
</li> <div class="col col-lg-4 text-end">
<li> {{ d.storedObject|chill_document_button_group(d.storedObject.title, is_granted('CHILL_CALENDAR_DOC_EDIT', d), {'small': true}) }}
{{ d.storedObject|chill_document_edit_button }} </div>
</li> </div>
{% endif %}
{% if is_granted('CHILL_CALENDAR_DOC_EDIT', d) %}
<li>
<a href="{{ chill_path_add_return_path('chill_calendar_calendardoc_edit', {'id': d.id})}}" class="btn btn-edit"></a>
</li>
{% endif %}
<li>
{{ m.download_button(d.storedObject, d.storedObject.title) }}
</li>
</ul>
</li> </li>
</ul> </ul>
</td> </td>

View File

@ -10,13 +10,13 @@
{% block js %} {% block js %}
{{ parent() }} {{ parent() }}
{{ encore_entry_script_tags('mod_answer') }} {{ encore_entry_script_tags('mod_answer') }}
{{ encore_entry_script_tags('mod_async_upload') }} {{ encore_entry_script_tags('mod_document_action_buttons_group') }}
{% endblock %} {% endblock %}
{% block css %} {% block css %}
{{ parent() }} {{ parent() }}
{{ encore_entry_link_tags('mod_answer') }} {{ encore_entry_link_tags('mod_answer') }}
{{ encore_entry_link_tags('mod_async_upload') }} {{ encore_entry_link_tags('mod_document_action_buttons_group') }}
{% endblock %} {% endblock %}
{% block content %} {% block content %}

View File

@ -240,6 +240,7 @@ final class CalendarContext implements CalendarContextInterface
public function contextGenerationDataNormalize(DocGeneratorTemplate $template, $entity, array $data): array public function contextGenerationDataNormalize(DocGeneratorTemplate $template, $entity, array $data): array
{ {
$normalized = [];
$normalized['title'] = $data['title'] ?? ''; $normalized['title'] = $data['title'] ?? '';
foreach (['mainPerson', 'thirdParty'] as $k) { foreach (['mainPerson', 'thirdParty'] as $k) {
@ -253,6 +254,7 @@ final class CalendarContext implements CalendarContextInterface
public function contextGenerationDataDenormalize(DocGeneratorTemplate $template, $entity, array $data): array public function contextGenerationDataDenormalize(DocGeneratorTemplate $template, $entity, array $data): array
{ {
$denormalized = [];
$denormalized['title'] = $data['title']; $denormalized['title'] = $data['title'];
if (null !== ($data['mainPerson'] ?? null)) { if (null !== ($data['mainPerson'] ?? null)) {

View File

@ -16,14 +16,14 @@ window.addEventListener('DOMContentLoaded', function (e) {
filename: string, filename: string,
canEdit: string, canEdit: string,
storedObject: string, storedObject: string,
small: string, buttonSmall: string,
}; };
const const
storedObject = JSON.parse(datasets.storedObject) as StoredObject, storedObject = JSON.parse(datasets.storedObject) as StoredObject,
filename = datasets.filename, filename = datasets.filename,
canEdit = datasets.canEdit === '1', canEdit = datasets.canEdit === '1',
small = datasets.small === '1' small = datasets.buttonSmall === '1'
; ;
return { storedObject, filename, canEdit, small }; return { storedObject, filename, canEdit, small };

View File

@ -1,6 +1,6 @@
<template> <template>
<div v-if="'ready' === props.storedObject.status" class="dropdown"> <div v-if="'ready' === props.storedObject.status" class="dropdown">
<button :class="Object.assign({'btn': true, 'btn-outline-primary': true, 'dropdown-toggle': true, small: props.small})" type="button" data-bs-toggle="dropdown" aria-expanded="false"> <button :class="Object.assign({'btn': true, 'btn-outline-primary': true, 'dropdown-toggle': true, 'btn-sm': props.small})" type="button" data-bs-toggle="dropdown" aria-expanded="false">
Actions Actions
</button> </button>
<ul class="dropdown-menu"> <ul class="dropdown-menu">

View File

@ -157,7 +157,7 @@ final class WopiEditTwigExtensionRuntime implements RuntimeExtensionInterface
'document_json' => $this->normalizer->normalize($document, 'json', [AbstractNormalizer::GROUPS => ['read']]), 'document_json' => $this->normalizer->normalize($document, 'json', [AbstractNormalizer::GROUPS => ['read']]),
'title' => $title, 'title' => $title,
'can_edit' => $canEdit, 'can_edit' => $canEdit,
'options' => array_merge($options, self::DEFAULT_OPTIONS_TEMPLATE_BUTTON_GROUP), 'options' => array_merge(self::DEFAULT_OPTIONS_TEMPLATE_BUTTON_GROUP, $options),
]); ]);
} }

View File

@ -0,0 +1,65 @@
<?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\MainBundle\Controller;
use Chill\MainBundle\Form\AbsenceType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class AbsenceController extends AbstractController
{
/**
* @Route(
* "/{_locale}/absence",
* name="chill_main_user_absence_index",
* methods={"GET", "POST"}
* )
*/
public function setAbsence(Request $request)
{
$user = $this->getUser();
$form = $this->createForm(AbsenceType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->flush();
return $this->redirect($this->generateUrl('chill_main_user_absence_index'));
}
return $this->render('@ChillMain/Menu/absence.html.twig', [
'user' => $user,
'form' => $form->createView(),
]);
}
/**
* @Route(
* "/{_locale}/absence/unset",
* name="chill_main_user_absence_unset",
* methods={"GET", "POST"}
* )
*/
public function unsetAbsence(Request $request)
{
$user = $this->getUser();
$user->setAbsenceStart(null);
$em = $this->getDoctrine()->getManager();
$em->flush();
return $this->redirect($this->generateUrl('chill_main_user_absence_index'));
}
}

View File

@ -298,6 +298,8 @@ class ExportController extends AbstractController
'csrf_protection' => $isGenerate ? false : true, 'csrf_protection' => $isGenerate ? false : true,
]); ]);
// TODO: add a condition to be able to select a regroupment of centers?
if ('centers' === $step || 'generate_centers' === $step) { if ('centers' === $step || 'generate_centers' === $step) {
$builder->add('centers', PickCenterType::class, [ $builder->add('centers', PickCenterType::class, [
'export_alias' => $alias, 'export_alias' => $alias,

View File

@ -24,7 +24,7 @@ class Regroupment
/** /**
* @var Center * @var Center
* @ORM\ManyToMany( * @ORM\ManyToMany(
* targetEntity="Chill\MainBundle\Entity\Center" * targetEntity=Center::class
* ) * )
* @ORM\Id * @ORM\Id
*/ */
@ -43,7 +43,7 @@ class Regroupment
private bool $isActive = true; private bool $isActive = true;
/** /**
* @ORM\Column(type="string", length=15, options={"default": ""}, nullable=false) * @ORM\Column(type="text", options={"default": ""}, nullable=false)
*/ */
private string $name = ''; private string $name = '';
@ -52,7 +52,7 @@ class Regroupment
$this->centers = new ArrayCollection(); $this->centers = new ArrayCollection();
} }
public function getCenters(): ?Collection public function getCenters(): Collection
{ {
return $this->centers; return $this->centers;
} }

View File

@ -11,14 +11,15 @@ declare(strict_types=1);
namespace Chill\MainBundle\Entity; namespace Chill\MainBundle\Entity;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use RuntimeException; use RuntimeException;
use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Serializer\Annotation as Serializer; use Symfony\Component\Serializer\Annotation as Serializer;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use function in_array; use function in_array;
/** /**
@ -40,6 +41,11 @@ class User implements UserInterface
*/ */
protected ?int $id = null; protected ?int $id = null;
/**
* @ORM\Column(type="datetime_immutable", nullable=true)
*/
private ?DateTimeImmutable $absenceStart = null;
/** /**
* Array where SAML attributes's data are stored. * Array where SAML attributes's data are stored.
* *
@ -173,6 +179,11 @@ class User implements UserInterface
{ {
} }
public function getAbsenceStart(): ?DateTimeImmutable
{
return $this->absenceStart;
}
/** /**
* Get attributes. * Get attributes.
* *
@ -291,6 +302,11 @@ class User implements UserInterface
return $this->usernameCanonical; return $this->usernameCanonical;
} }
public function isAbsent(): bool
{
return null !== $this->getAbsenceStart() && $this->getAbsenceStart() <= new DateTimeImmutable('now');
}
/** /**
* @return bool * @return bool
*/ */
@ -355,6 +371,11 @@ class User implements UserInterface
} }
} }
public function setAbsenceStart(?DateTimeImmutable $absenceStart): void
{
$this->absenceStart = $absenceStart;
}
public function setAttributeByDomain(string $domain, string $key, $value): self public function setAttributeByDomain(string $domain, string $key, $value): self
{ {
$this->attributes[$domain][$key] = $value; $this->attributes[$domain][$key] = $value;

View File

@ -0,0 +1,38 @@
<?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\MainBundle\Form;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Form\Type\ChillDateType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class AbsenceType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('absenceStart', ChillDateType::class, [
'required' => true,
'input' => 'datetime_immutable',
'label' => 'absence.Absence start',
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => User::class,
]);
}
}

View File

@ -0,0 +1,84 @@
<?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\MainBundle\Form\DataMapper;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Regroupment;
use Chill\MainBundle\Repository\RegroupmentRepository;
use Exception;
use Symfony\Component\Form\DataMapperInterface;
use Symfony\Component\Form\FormInterface;
use function count;
class ExportPickCenterDataMapper implements DataMapperInterface
{
protected RegroupmentRepository $regroupmentRepository;
/**
* @param array|Center[] $data
* @param $forms
*
* @throws Exception
*
* @return mixed
*/
public function mapDataToForms($data, $forms)
{
if (null === $data) {
return;
}
/** @var array<string, FormInterface> $form */
$form = iterator_to_array($forms);
$pickedRegroupment = [];
foreach ($this->regroupmentRepository->findAll() as $regroupment) {
[$contained, $notContained] = $regroupment->getCenters()->partition(static function (Center $center) {
});
if (0 === count($notContained)) {
$pickedRegroupment[] = $regroupment;
}
}
$form['regroupment']->setData($pickedRegroupment);
$form['centers']->setData($data);
}
/**
* @param iterable $forms
* @param array $data
*
* @return void
*/
public function mapFormsToData($forms, &$data)
{
/** @var array<string, FormInterface> $forms */
$forms = iterator_to_array($forms);
$centers = [];
foreach ($forms['center']->getData() as $center) {
$centers[spl_object_hash($center)] = $center;
}
foreach ($forms['regroupment']->getData() as $regroupment) {
/** @var Regroupment $regroupment */
foreach ($regroupment->getCenters() as $center) {
$centers[spl_object_hash($center)] = $center;
}
}
$data = array_values($centers);
}
}

View File

@ -13,55 +13,45 @@ namespace Chill\MainBundle\Form\Type\Export;
use Chill\MainBundle\Center\GroupingCenterInterface; use Chill\MainBundle\Center\GroupingCenterInterface;
use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Regroupment;
use Chill\MainBundle\Export\ExportManager; use Chill\MainBundle\Export\ExportManager;
use Chill\MainBundle\Form\DataMapper\ExportPickCenterDataMapper;
use Chill\MainBundle\Repository\RegroupmentRepository;
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface; use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserInterface;
use function array_intersect;
use function array_key_exists;
use function array_merge;
use function array_unique;
use function count; use function count;
use function in_array;
/** /**
* Pick centers amongst available centers for the user. * Pick centers amongst available centers for the user.
*/ */
class PickCenterType extends AbstractType final class PickCenterType extends AbstractType
{ {
public const CENTERS_IDENTIFIERS = 'c'; public const CENTERS_IDENTIFIERS = 'c';
protected AuthorizationHelperInterface $authorizationHelper; private AuthorizationHelperInterface $authorizationHelper;
protected ExportManager $exportManager; private ExportManager $exportManager;
/** private RegroupmentRepository $regroupmentRepository;
* @var array|GroupingCenterInterface[]
*/
protected array $groupingCenters = [];
protected UserInterface $user; private UserInterface $user;
public function __construct( public function __construct(
TokenStorageInterface $tokenStorage, TokenStorageInterface $tokenStorage,
ExportManager $exportManager, ExportManager $exportManager,
RegroupmentRepository $regroupmentRepository,
AuthorizationHelperInterface $authorizationHelper AuthorizationHelperInterface $authorizationHelper
) { ) {
$this->exportManager = $exportManager; $this->exportManager = $exportManager;
$this->user = $tokenStorage->getToken()->getUser(); $this->user = $tokenStorage->getToken()->getUser();
$this->authorizationHelper = $authorizationHelper; $this->authorizationHelper = $authorizationHelper;
} $this->regroupmentRepository = $regroupmentRepository;
public function addGroupingCenter(GroupingCenterInterface $grouping)
{
$this->groupingCenters[md5($grouping->getName())] = $grouping;
} }
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
@ -72,97 +62,33 @@ class PickCenterType extends AbstractType
$export->requiredRole() $export->requiredRole()
); );
$builder->add(self::CENTERS_IDENTIFIERS, EntityType::class, [ $builder->add('center', EntityType::class, [
'class' => Center::class, 'class' => Center::class,
'label' => 'center',
'choices' => $centers, 'choices' => $centers,
'multiple' => true, 'multiple' => true,
'expanded' => true, 'expanded' => true,
'choice_label' => static function (Center $c) { 'choice_label' => static function (Center $c) {
return $c->getName(); return $c->getName();
}, },
'data' => count($this->groupingCenters) > 0 ? null : $centers, 'data' => $centers,
]); ])
->add('regroupment', EntityType::class, [
if (count($this->groupingCenters) > 0) { 'class' => Regroupment::class,
$groupingBuilder = $builder->create('g', null, [ 'label' => 'regroupment',
'compound' => true, 'multiple' => true,
'expanded' => true,
'choices' => $this->regroupmentRepository->findAllActive(),
'choice_label' => static function (Regroupment $r) {
return $r->getName();
},
]); ]);
foreach ($this->groupingCenters as $key => $gc) { $builder->setDataMapper(new ExportPickCenterDataMapper());
$choices = $this->buildChoices($centers, $gc);
if (count($choices) > 0) {
$groupingBuilder->add($key, ChoiceType::class, [
'choices' => $choices,
'multiple' => true,
'expanded' => true,
'label' => $gc->getName(),
'required' => false,
]);
}
}
if ($groupingBuilder->count() > 0) {
$builder->add($groupingBuilder);
}
}
$builder->addModelTransformer(new CallbackTransformer(
function ($data) use ($centers) {
return $this->transform($data, $centers);
},
function ($data) use ($centers) {
return $this->reverseTransform($data, $centers);
}
));
} }
public function configureOptions(OptionsResolver $resolver) public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setRequired('export_alias'); $resolver->setRequired('export_alias');
} }
protected function buildChoices($reachablesCenters, GroupingCenterInterface $gc)
{
$result = [];
foreach ($gc->getGroups() as $group) {
foreach ($gc->getCentersForGroup($group) as $center) {
if (in_array($center, $reachablesCenters, true)) {
$result[$group] = $group;
}
}
}
return $result;
}
protected function reverseTransform($data, $centers)
{
$picked = $data[self::CENTERS_IDENTIFIERS]
instanceof \Doctrine\Common\Collections\Collection ?
$data[self::CENTERS_IDENTIFIERS]->toArray()
:
$data[self::CENTERS_IDENTIFIERS];
if (array_key_exists('g', $data)) {
foreach ($data['g'] as $gcid => $group) {
$picked =
array_merge(
array_intersect(
$this->groupingCenters[$gcid]->getCentersForGroup($group),
$centers
),
$picked
);
}
}
return array_unique($picked);
}
protected function transform($data, $centers)
{
return $data;
}
} }

View File

@ -15,6 +15,7 @@ use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Location; use Chill\MainBundle\Entity\Location;
use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\UserJob; use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\MainBundle\Form\Type\PickCivilityType; use Chill\MainBundle\Form\Type\PickCivilityType;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;
@ -110,6 +111,11 @@ class UserType extends AbstractType
return $qb; return $qb;
}, },
])
->add('absenceStart', ChillDateType::class, [
'required' => false,
'input' => 'datetime_immutable',
'label' => 'absence.Absence start',
]); ]);
// @phpstan-ignore-next-line // @phpstan-ignore-next-line

View File

@ -0,0 +1,66 @@
<?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\MainBundle\Repository;
use Chill\MainBundle\Entity\Regroupment;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\Persistence\ObjectRepository;
final class RegroupmentRepository implements ObjectRepository
{
private EntityRepository $repository;
public function __construct(EntityManagerInterface $entityManager)
{
$this->repository = $entityManager->getRepository(Regroupment::class);
}
public function find($id, $lockMode = null, $lockVersion = null): ?Regroupment
{
return $this->repository->find($id, $lockMode, $lockVersion);
}
/**
* @return Regroupment[]
*/
public function findAll(): array
{
return $this->repository->findAll();
}
public function findAllActive(): array
{
return $this->repository->findBy(['isActive' => true], ['name' => 'ASC']);
}
/**
* @param mixed|null $limit
* @param mixed|null $offset
*
* @return Regroupment[]
*/
public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array
{
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
}
public function findOneBy(array $criteria, ?array $orderBy = null): ?Regroupment
{
return $this->repository->findOneBy($criteria, $orderBy);
}
public function getClassName()
{
return Regroupment::class;
}
}

View File

@ -35,6 +35,7 @@ export interface User {
id: number; id: number;
username: string; username: string;
text: string; text: string;
text_without_absence: string;
email: string; email: string;
user_job: Job; user_job: Job;
label: string; label: string;

View File

@ -1,8 +1,7 @@
<template> <template>
<span class="chill-entity entity-user"> <span class="chill-entity entity-user">
{{ user.label }} {{ user.label }}
<span class="user-job" v-if="user.user_job !== null">({{ user.user_job.label.fr }})</span> <span class="user-job" v-if="user.user_job !== null">({{ user.user_job.label.fr }})</span> <span class="main-scope" v-if="user.main_scope !== null">({{ user.main_scope.name.fr }})</span> <span v-if="user.isAbsent" class="badge bg-danger rounded-pill" :title="Absent">A</span>
<span class="main-scope" v-if="user.main_scope !== null">({{ user.main_scope.name.fr }})</span>
</span> </span>
</template> </template>

View File

@ -6,4 +6,7 @@
{%- if opts['main_scope'] and user.mainScope is not null %} {%- if opts['main_scope'] and user.mainScope is not null %}
<span class="main-scope">({{ user.mainScope.name|localize_translatable_string }})</span> <span class="main-scope">({{ user.mainScope.name|localize_translatable_string }})</span>
{%- endif -%} {%- endif -%}
{%- if opts['absence'] and user.isAbsent %}
<span class="badge bg-danger rounded-pill" title="{{ 'absence.Absent'|trans|escape('html_attr') }}">{{ 'absence.A'|trans }}</span>
{%- endif -%}
</span> </span>

View File

@ -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> <info@champs-libres.coop> / <http://www.champs-libres.coop>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -22,39 +22,33 @@
{% block content %} {% block content %}
<div class="col-md-10"> <div class="col-md-10">
{{ include('@ChillMain/Export/_breadcrumb.html.twig') }} {{ include('@ChillMain/Export/_breadcrumb.html.twig') }}
<h1>{{ export.title|trans }}</h1> <h1>{{ export.title|trans }}</h1>
<p>{{ export.description|trans }}</p> <p>{{ export.description|trans }}</p>
{{ form_start(form) }} {{ form_start(form) }}
<section class="center mb-4"> <section class="center mb-4">
<h2>{{ 'Pick centers'|trans }}</h2> <h2>{{ 'Pick centers'|trans }}</h2>
<p>{{ 'The export will contains only data from the picked centers.'|trans }} <p>{{ 'The export will contains only data from the picked centers.'|trans }}
{{ 'This will eventually restrict your possibilities in filtering the data.'|trans }}</p> {{ 'This will eventually restrict your possibilities in filtering the data.'|trans }}</p>
{{ form_widget(form.centers.c) }} <h3 class="m-3">{{ 'Center'|trans }}</h3>
{{ form_widget(form.centers.center) }}
{% if form.centers.children.g is defined %}
<h3 class="m-3">{{ 'Pick aggregated centers'|trans }}</h3>
<h3>{{ 'Pick aggregated centers'|trans }}</h3> {{ form_widget(form.centers.regroupment) }}
{% for f in form.centers.children.g.children %}
{{ form_row(f) }}
{% endfor %}
{% endif %}
</section> </section>
<p>{{ form_widget(form.submit, { 'attr' : { 'class' : 'btn btn-action btn-create' }, 'label' : 'Go to export options' } ) }}</p> <p>{{ form_widget(form.submit, { 'attr' : { 'class' : 'btn btn-action btn-create' }, 'label' : 'Go to export options' } ) }}</p>
{{ form_end(form) }} {{ form_end(form) }}
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -1,15 +1,15 @@
<div class="col-10 mt-5"> <div class="col-10 mt-5">
{# vue component #} {# vue component #}
<div id="homepage_widget"></div> <div id="homepage_widget"></div>
{% include '@ChillMain/Homepage/fast_actions.html.twig' %} {% include '@ChillMain/Homepage/fast_actions.html.twig' %}
</div> </div>
{% block css %} {% block css %}
{{ encore_entry_link_tags('page_homepage_widget') }} {{ encore_entry_link_tags('page_homepage_widget') }}
{% endblock %} {% endblock %}
{% block js %} {% block js %}
{{ encore_entry_script_tags('page_homepage_widget') }} {{ encore_entry_script_tags('page_homepage_widget') }}
{% endblock %} {% endblock %}

View File

@ -0,0 +1,43 @@
{% extends '@ChillMain/Admin/layout.html.twig' %}
{% block title %}
{{ 'absence.My absence'|trans }}
{% endblock title %}
{% block content %}
<div class="col-md-10">
<h2>{{ 'absence.My absence'|trans }}</h2>
{% if user.absenceStart is not null %}
<div>
<p>{{ 'absence.You are listed as absent, as of'|trans }} {{ user.absenceStart|format_date('long') }}</p>
<ul class="record_actions sticky-form-buttons">
<li>
<a href="{{ path('chill_main_user_absence_unset') }}"
class="btn btn-delete">{{ 'absence.Unset absence'|trans }}</a>
</li>
</ul>
</div>
{% else %}
<div>
<p class="chill-no-data-statement">{{ 'absence.No absence listed'|trans }}</p>
</div>
<div>
{{ form_start(form) }}
{{ form_row(form.absenceStart) }}
<ul class="record_actions sticky-form-buttons">
<li>
<button class="btn btn-save" type="submit">
{{ 'Save'|trans }}
</button>
</li>
</ul>
{{ form_end(form) }}
</div>
{% endif %}
</div>
{% endblock %}

View File

@ -2,20 +2,21 @@
{% block admin_content %} {% block admin_content %}
{% embed '@ChillMain/CRUD/_index.html.twig' %} {% embed '@ChillMain/CRUD/_index.html.twig' %}
{% block index_header %} {% block index_header %}
<h1>{{"Users"|trans}}</h1> <h1>{{"Users"|trans}}</h1>
{% endblock %} {% endblock %}
{% block filter_order %}{{ filter_order|chill_render_filter_order_helper }}{% endblock %} {% block filter_order %}{{ filter_order|chill_render_filter_order_helper }}{% endblock %}
{% block table_entities_thead_tr %} {% block table_entities_thead_tr %}
<th>{{ 'Active'|trans }}</th> <th>{{ 'Active'|trans }}</th>
<th>{{ 'absence.Is absent'|trans }}</th>
<th>{{ 'Username'|trans }}</th> <th>{{ 'Username'|trans }}</th>
<th>{{ 'Datas'|trans }}</th> <th>{{ 'Datas'|trans }}</th>
<th>{{ 'Actions'|trans }}</th> <th>{{ 'Actions'|trans }}</th>
{% endblock %} {% endblock %}
{% block table_entities_tbody %} {% block table_entities_tbody %}
{% for entity in entities %} {% for entity in entities %}
<tr> <tr>
@ -26,6 +27,13 @@
<i class="fa fa-square-o"></i> <i class="fa fa-square-o"></i>
{% endif %} {% endif %}
</td> </td>
<td>
{% if entity.isAbsent %}
<i class="fa fa-check-square-o"></i>
{% else %}
<i class="fa fa-square-o"></i>
{% endif %}
</td>
<td> <td>
{# {#
{% if entity.civility is not null %} {% if entity.civility is not null %}
@ -64,13 +72,13 @@
<li> <li>
<a class="btn btn-edit" title="{{ 'Edit'|trans }}" href="{{ path('chill_crud_admin_user_edit', { 'id': entity.id }) }}"></a> <a class="btn btn-edit" title="{{ 'Edit'|trans }}" href="{{ path('chill_crud_admin_user_edit', { 'id': entity.id }) }}"></a>
</li> </li>
{% if allow_change_password is same as(true) %} {% if allow_change_password is same as(true) %}
<li> <li>
<a class="btn btn-chill-red" href="{{ path('admin_user_edit_password', { 'id' : entity.id }) }}" title="{{ 'Edit password'|trans|e('html_attr') }}"><i class="fa fa-ellipsis-h"></i></a> <a class="btn btn-chill-red" href="{{ path('admin_user_edit_password', { 'id' : entity.id }) }}" title="{{ 'Edit password'|trans|e('html_attr') }}"><i class="fa fa-ellipsis-h"></i></a>
</li> </li>
{% endif %} {% endif %}
{% if is_granted('ROLE_ALLOWED_TO_SWITCH') %} {% if is_granted('ROLE_ALLOWED_TO_SWITCH') %}
<li> <li>
<a class="btn btn-chill-blue" href="{{ path('chill_main_homepage', {'_switch_user': entity.username }) }}" title="{{ "Impersonate"|trans|e('html_attr') }}"><i class="fa fa-user-secret"></i></a> <a class="btn btn-chill-blue" href="{{ path('chill_main_homepage', {'_switch_user': entity.username }) }}" title="{{ "Impersonate"|trans|e('html_attr') }}"><i class="fa fa-user-secret"></i></a>
@ -81,9 +89,9 @@
</tr> </tr>
{% endfor %} {% endfor %}
{% endblock %} {% endblock %}
{% block pagination %}{{ chill_pagination(paginator) }}{% endblock %} {% block pagination %}{{ chill_pagination(paginator) }}{% endblock %}
{% block list_actions %} {% block list_actions %}
<ul class="record_actions sticky-form-buttons"> <ul class="record_actions sticky-form-buttons">
<li class='cancel'> <li class='cancel'>
@ -94,6 +102,6 @@
</li> </li>
</ul> </ul>
{% endblock list_actions %} {% endblock list_actions %}
{% endembed %} {% endembed %}
{% endblock %} {% endblock %}

View File

@ -69,18 +69,26 @@
{% block content %} {% block content %}
<div class="col-8 main_search"> <div class="col-8 main_search">
{% if app.user.isAbsent %}
<div class="d-flex flex-row mb-5 alert alert-warning" role="alert">
<p class="m-2">{{'absence.You are marked as being absent'|trans }}</p>
<span class="ms-auto">
<a class="btn btn-remove" title="Modifier" href="{{ path('chill_main_user_absence_index') }}">{{ 'absence.Unset absence'|trans }}</a>
</span>
</div>
{% endif %}
<h2>{{ 'Search'|trans }}</h2> <h2>{{ 'Search'|trans }}</h2>
<form action="{{ path('chill_main_search') }}" method="get"> <form action="{{ path('chill_main_search') }}" method="get">
<input class="form-control form-control-lg" name="q" type="search" placeholder="{{ 'Search persons, ...'|trans }}" /> <input class="form-control form-control-lg" name="q" type="search" placeholder="{{ 'Search persons, ...'|trans }}" />
<center> <div class="text-center">
<button type="submit" class="btn btn-lg btn-warning mt-3"> <button type="submit" class="btn btn-lg btn-warning mt-3">
<i class="fa fa-fw fa-search"></i> {{ 'Search'|trans }} <i class="fa fa-fw fa-search"></i> {{ 'Search'|trans }}
</button> </button>
<a class="btn btn-lg btn-misc mt-3" href="{{ path('chill_main_advanced_search_list') }}"> <a class="btn btn-lg btn-misc mt-3" href="{{ path('chill_main_advanced_search_list') }}">
<i class="fa fa-fw fa-search"></i> {{ 'Advanced search'|trans }} <i class="fa fa-fw fa-search"></i> {{ 'Advanced search'|trans }}
</a> </a>
</center> </div>
</form> </form>
</div> </div>

View File

@ -78,6 +78,15 @@ class UserMenuBuilder implements LocalMenuBuilderInterface
$nbNotifications = $this->notificationByUserCounter->countUnreadByUser($user); $nbNotifications = $this->notificationByUserCounter->countUnreadByUser($user);
//TODO add an icon? How exactly? For example a clock icon...
$menu
->addChild($this->translator->trans('absence.Set absence date'), [
'route' => 'chill_main_user_absence_index',
])
->setExtras([
'order' => -8888888,
]);
$menu $menu
->addChild( ->addChild(
$this->translator->trans('notification.My notifications with counter', ['nb' => $nbNotifications]), $this->translator->trans('notification.My notifications with counter', ['nb' => $nbNotifications]),

View File

@ -31,6 +31,7 @@ class UserNormalizer implements ContextAwareNormalizerInterface, NormalizerAware
'id' => '', 'id' => '',
'username' => '', 'username' => '',
'text' => '', 'text' => '',
'text_without_absent' => '',
'label' => '', 'label' => '',
'email' => '', 'email' => '',
]; ];
@ -82,11 +83,13 @@ class UserNormalizer implements ContextAwareNormalizerInterface, NormalizerAware
'id' => $object->getId(), 'id' => $object->getId(),
'username' => $object->getUsername(), 'username' => $object->getUsername(),
'text' => $this->userRender->renderString($object, []), 'text' => $this->userRender->renderString($object, []),
'text_without_absent' => $this->userRender->renderString($object, ['absence' => false]),
'label' => $object->getLabel(), 'label' => $object->getLabel(),
'email' => (string) $object->getEmail(), 'email' => (string) $object->getEmail(),
'user_job' => $this->normalizer->normalize($object->getUserJob(), $format, $userJobContext), 'user_job' => $this->normalizer->normalize($object->getUserJob(), $format, $userJobContext),
'main_center' => $this->normalizer->normalize($object->getMainCenter(), $format, $centerContext), 'main_center' => $this->normalizer->normalize($object->getMainCenter(), $format, $centerContext),
'main_scope' => $this->normalizer->normalize($object->getMainScope(), $format, $scopeContext), 'main_scope' => $this->normalizer->normalize($object->getMainScope(), $format, $scopeContext),
'isAbsent' => $object->isAbsent(),
]; ];
if ('docgen' === $format) { if ('docgen' === $format) {

View File

@ -13,8 +13,10 @@ namespace Chill\MainBundle\Templating\Entity;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Symfony\Component\Templating\EngineInterface; use DateTimeImmutable;
use Symfony\Component\Templating\EngineInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use function array_merge; use function array_merge;
class UserRender implements ChillEntityRenderInterface class UserRender implements ChillEntityRenderInterface
@ -22,16 +24,20 @@ class UserRender implements ChillEntityRenderInterface
public const DEFAULT_OPTIONS = [ public const DEFAULT_OPTIONS = [
'main_scope' => true, 'main_scope' => true,
'user_job' => true, 'user_job' => true,
'absence' => true,
]; ];
private EngineInterface $engine; private EngineInterface $engine;
private TranslatableStringHelper $translatableStringHelper; private TranslatableStringHelper $translatableStringHelper;
public function __construct(TranslatableStringHelper $translatableStringHelper, EngineInterface $engine) private TranslatorInterface $translator;
public function __construct(TranslatableStringHelper $translatableStringHelper, EngineInterface $engine, TranslatorInterface $translator)
{ {
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
$this->engine = $engine; $this->engine = $engine;
$this->translator = $translator;
} }
public function renderBox($entity, array $options): string public function renderBox($entity, array $options): string
@ -63,6 +69,10 @@ class UserRender implements ChillEntityRenderInterface
->localize($entity->getMainScope()->getName()) . ')'; ->localize($entity->getMainScope()->getName()) . ')';
} }
if ($entity->isAbsent() && $opts['absence']) {
$str .= ' (' . $this->translator->trans('absence.Absent') . ')';
}
return $str; return $str;
} }

View File

@ -138,9 +138,9 @@ services:
autowire: true autowire: true
autoconfigure: true autoconfigure: true
Chill\MainBundle\Form\RegroupmentType: Chill\MainBundle\Form\AbsenceType: ~
autowire: true Chill\MainBundle\Form\DataMapper\RegroupmentDataMapper: ~
autoconfigure: true Chill\MainBundle\Form\RegroupmentType: ~
Chill\MainBundle\Form\DataTransformer\IdToLocationDataTransformer: ~ Chill\MainBundle\Form\DataTransformer\IdToLocationDataTransformer: ~
Chill\MainBundle\Form\DataTransformer\IdToUserDataTransformer: ~ Chill\MainBundle\Form\DataTransformer\IdToUserDataTransformer: ~

View File

@ -0,0 +1,37 @@
<?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\Migrations\Main;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20230111160610 extends AbstractMigration
{
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE users DROP absenceStart');
}
public function getDescription(): string
{
return 'Add absence property to user';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE users ADD absenceStart TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
$this->addSql('COMMENT ON COLUMN users.absenceStart IS \'(DC2Type:datetime_immutable)\'');
}
}

View File

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace Chill\Migrations\Main;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20230301155213 extends AbstractMigration
{
public function getDescription(): string
{
return 'Alter type to TEXT for regroupment.name';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE regroupment ALTER name TYPE TEXT');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE regroupment ALTER name TYPE VARCHAR(15)');
}
}

View File

@ -584,3 +584,17 @@ saved_export:
Export is deleted: L'export est supprimé Export is deleted: L'export est supprimé
Saved export is saved!: L'export est enregistré Saved export is saved!: L'export est enregistré
Created on %date%: Créé le %date% Created on %date%: Créé le %date%
absence:
# single letter for absence
A: A
My absence: Mon absence
Unset absence: Supprimer la date d'absence
Set absence date: Indiquer une date d'absence
Absence start: Absent à partir du
Absent: Absent
You are marked as being absent: Vous êtes indiqué absent.
You are listed as absent, as of: Votre absence est indiquée à partir du
No absence listed: Aucune absence indiquée.
Is absent: Absent?

View File

@ -11,11 +11,13 @@ declare(strict_types=1);
namespace Chill\PersonBundle\DataFixtures\ORM; namespace Chill\PersonBundle\DataFixtures\ORM;
use Chill\MainBundle\DataFixtures\ORM\LoadCenters;
use Chill\MainBundle\DataFixtures\ORM\LoadPostalCodes; use Chill\MainBundle\DataFixtures\ORM\LoadPostalCodes;
use Chill\MainBundle\Entity\Address; use Chill\MainBundle\Entity\Address;
use Chill\MainBundle\Entity\PostalCode; use Chill\MainBundle\Entity\PostalCode;
use Chill\PersonBundle\Entity\Household\Household; use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Household\MembersEditorFactory; use Chill\PersonBundle\Household\MembersEditorFactory;
use DateInterval; use DateInterval;
use DateTime; use DateTime;
@ -192,14 +194,20 @@ class LoadHousehold extends Fixture implements DependentFixtureInterface
private function preparePersonIds() private function preparePersonIds()
{ {
$centers = LoadCenters::$centers;
// @TODO: Remove this and make this service stateless // @TODO: Remove this and make this service stateless
$this->personIds = $this->em $this->personIds = $this->em
->createQuery( ->createQuery(
'SELECT p.id FROM ' . Person::class . ' p ' . 'SELECT p.id FROM ' . Person::class . ' p ' .
'JOIN p.center c ' . 'WHERE EXISTS( ' .
'WHERE c.name = :center ' 'SELECT 1 FROM ' . PersonCenterHistory::class . ' pch ' .
'JOIN pch.center c ' .
'WHERE pch.person = p.id ' .
'AND c.name IN (:authorized_centers)' .
')'
) )
->setParameter('center', 'Center A') ->setParameter('authorized_centers', $centers)
->getScalarResult(); ->getScalarResult();
shuffle($this->personIds); shuffle($this->personIds);

View File

@ -22,7 +22,12 @@
<i>{{ $t('course.open_at') }}{{ $d(accompanyingCourse.openingDate.datetime, 'text') }}</i> <i>{{ $t('course.open_at') }}{{ $d(accompanyingCourse.openingDate.datetime, 'text') }}</i>
</span> </span>
<span v-if="accompanyingCourse.user" class="d-md-block ms-3 ms-md-0"> <span v-if="accompanyingCourse.user" class="d-md-block ms-3 ms-md-0">
<span class="item-key">{{ $t('course.referrer') }}:</span> <b>{{ accompanyingCourse.user.text }}</b> <span class="item-key">{{ $t('course.referrer') }}:</span>&nbsp;
<b>{{ accompanyingCourse.user.text }}</b>
<template v-if="accompanyingCourse.user.isAbsent">
&nbsp;
<span class="badge bg-danger rounded-pill" title="Absent">A</span>
</template>
</span> </span>
</span> </span>
</span> </span>
@ -59,13 +64,15 @@
import ToggleFlags from './Banner/ToggleFlags'; import ToggleFlags from './Banner/ToggleFlags';
import SocialIssue from './Banner/SocialIssue.vue'; import SocialIssue from './Banner/SocialIssue.vue';
import PersonsAssociated from './Banner/PersonsAssociated.vue'; import PersonsAssociated from './Banner/PersonsAssociated.vue';
import UserRenderBoxBadge from 'ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge.vue';
export default { export default {
name: 'Banner', name: 'Banner',
components: { components: {
ToggleFlags, ToggleFlags,
SocialIssue, SocialIssue,
PersonsAssociated PersonsAssociated,
UserRenderBoxBadge,
}, },
computed: { computed: {
accompanyingCourse() { accompanyingCourse() {

View File

@ -29,7 +29,8 @@ const appMessages = {
emergency: "urgent", emergency: "urgent",
confidential: "confidentiel", confidential: "confidentiel",
regular: "régulier", regular: "régulier",
occasional: "ponctuel" occasional: "ponctuel",
absent: "Absent",
}, },
origin: { origin: {
title: "Origine de la demande", title: "Origine de la demande",

View File

@ -1,9 +1,7 @@
<template> <template>
<div class="container usercontainer"> <div class="container usercontainer">
<div class="user-identification"> <div class="user-identification">
<span class="name"> <user-render-box-badge :user="item.result"></user-render-box-badge>
{{ item.result.text }}
</span>
</div> </div>
</div> </div>
<div class="right_actions"> <div class="right_actions">
@ -16,10 +14,12 @@
<script> <script>
import BadgeEntity from 'ChillMainAssets/vuejs/_components/BadgeEntity.vue'; import BadgeEntity from 'ChillMainAssets/vuejs/_components/BadgeEntity.vue';
import UserRenderBoxBadge from 'ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge.vue';
export default { export default {
name: 'SuggestionUser', name: 'SuggestionUser',
components: { components: {
UserRenderBoxBadge,
BadgeEntity BadgeEntity
}, },
props: ['item'], props: ['item'],