Commit ee6945e8 by Damien Moulard

Merge branch '7386-info-modale-for-adherents' into 'develop'

display informative modale to user, customable by admin

See merge request cooperatic/kohinos-tav!124
parents c715bd64 0320fd1c
......@@ -339,6 +339,14 @@ sonata_admin:
icon: '<i class="fa fa-shopping-basket"></i>'
items:
- admin.productsFamily
sonata.admin.informationPopup:
keep_open: false
on_top: true
label: "Popups d'information"
label_catalogue: SonataAdminBundle
icon: '<i class="fa fa-exclamation-circle"></i>'
items:
- admin.informationPopup
sonata.admin.group.globalparameter:
keep_open: false
on_top: true
......
......@@ -680,6 +680,16 @@ services:
label: "Familles de Produits"
public: true
admin.informationPopup:
class: App\Admin\InformationPopupAdmin
arguments: [~, App\Entity\InformationPopup, ~]
tags:
- name: sonata.admin
manager_type: orm
group: "Popups d'information"
label: "Popups d'information"
public: true
sonata.media.provider.csv:
class: App\Admin\ImportProvider
tags:
......
/*
Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
CKEditor 4 LTS ("Long Term Support") is available under the terms of the Extended Support Model.
*/
CKEDITOR.dialog.add("anchor",function(c){function f(b,a){return b.createFakeElement(b.document.createElement("a",{attributes:a}),"cke_anchor","anchor")}return{title:c.lang.link.anchor.title,minWidth:300,minHeight:60,getModel:function(b){var a=b.getSelection();b=a.getRanges()[0];a=a.getSelectedElement();b.shrink(CKEDITOR.SHRINK_ELEMENT);(a=b.getEnclosedNode())&&a.type===CKEDITOR.NODE_TEXT&&(a=a.getParent());a&&!a.is("a")&&(a=a.getAscendant("a")||a);b=a&&a.type===CKEDITOR.NODE_ELEMENT&&("anchor"===
a.data("cke-real-element-type")||a.is("a"))?a:void 0;return b||null},onOk:function(){var b=CKEDITOR.tools.trim(this.getValueOf("info","txtName")),b={id:b,name:b,"data-cke-saved-name":b},a=this.getModel(c);if(a)a.data("cke-realelement")?(b=f(c,b),b.replace(a),CKEDITOR.env.ie&&c.getSelection().selectElement(b)):a.setAttributes(b);else if(a=(a=c.getSelection())&&a.getRanges()[0],a.collapsed)b=f(c,b),a.insertNode(b);else{CKEDITOR.env.ie&&9>CKEDITOR.env.version&&(b["class"]="cke_anchor");var d=a.clone();
d.enlarge(CKEDITOR.ENLARGE_ELEMENT);for(var e=new CKEDITOR.dom.walker(d),d=d.collapsed?d.startContainer:e.next(),g=a.createBookmark();d;)d.type===CKEDITOR.NODE_ELEMENT&&d.getAttribute("data-cke-saved-name")&&(d.remove(!0),e.reset()),d=e.next();a.moveToBookmark(g);b=new CKEDITOR.style({element:"a",attributes:b});b.type=CKEDITOR.STYLE_INLINE;b.applyToRange(a)}},onShow:function(){var b=c.getSelection(),a=this.getModel(c),d=a&&a.data("cke-realelement");if(a=d?CKEDITOR.plugins.link.tryRestoreFakeAnchor(c,
a):CKEDITOR.plugins.link.getSelectedLink(c)){var e=a.data("cke-saved-name");this.setValueOf("info","txtName",e||"");!d&&b.selectElement(a)}this.getContentElement("info","txtName").focus()},contents:[{id:"info",label:c.lang.link.anchor.title,accessKey:"I",elements:[{type:"text",id:"txtName",label:c.lang.link.anchor.name,required:!0,validate:function(){var b=this.getValue();return b?/[\u0020\u0009\u000a\u000c\u000d]/g.test(b)?(alert(c.lang.link.anchor.errorWhitespace),!1):!0:(alert(c.lang.link.anchor.errorName),
!1)}}]}]}});
\ No newline at end of file
/*
Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
CKEditor 4 LTS ("Long Term Support") is available under the terms of the Extended Support Model.
*/
(function(){function u(){var c=this.getDialog(),p=c._.editor,n=p.config.linkPhoneRegExp,q=p.config.linkPhoneMsg,p=CKEDITOR.dialog.validate.notEmpty(p.lang.link.noTel).apply(this);if(!c.getContentElement("info","linkType")||"tel"!=c.getValueOf("info","linkType"))return!0;if(!0!==p)return p;if(n)return CKEDITOR.dialog.validate.regex(n,q).call(this)}CKEDITOR.dialog.add("link",function(c){function p(a,b){var c=a.createRange();c.setStartBefore(b);c.setEndAfter(b);return c}var n=CKEDITOR.plugins.link,q,
t=function(){var a=this.getDialog(),b=a.getContentElement("target","popupFeatures"),a=a.getContentElement("target","linkTargetName"),r=this.getValue();if(b&&a)switch(b=b.getElement(),b.hide(),a.setValue(""),r){case "frame":a.setLabel(c.lang.link.targetFrameName);a.getElement().show();break;case "popup":b.show();a.setLabel(c.lang.link.targetPopupName);a.getElement().show();break;default:a.setValue(r),a.getElement().hide()}},d=function(a){a.target&&this.setValue(a.target[this.id]||"")},g=function(a){a.advanced&&
this.setValue(a.advanced[this.id]||"")},e=function(a){a.target||(a.target={});a.target[this.id]=this.getValue()||""},k=function(a){a.advanced||(a.advanced={});a.advanced[this.id]=this.getValue()||""},h=c.lang.common,b=c.lang.link,l;return{title:b.title,minWidth:"moono-lisa"==(CKEDITOR.skinName||c.config.skin)?450:350,minHeight:240,getModel:function(a){return n.getSelectedLink(a,!0)[0]||null},contents:[{id:"info",label:b.info,title:b.info,elements:[{type:"text",id:"linkDisplayText",label:b.displayText,
setup:function(){this.enable();this.setValue(c.getSelection().getSelectedText());q=this.getValue()},commit:function(a){a.linkText=this.isEnabled()?this.getValue():""}},{id:"linkType",type:"select",label:b.type,"default":"url",items:[[b.toUrl,"url"],[b.toAnchor,"anchor"],[b.toEmail,"email"],[b.toPhone,"tel"]],onChange:function(){var a=this.getDialog(),b=["urlOptions","anchorOptions","emailOptions","telOptions"],r=this.getValue(),f=a.definition.getContents("upload"),f=f&&f.hidden;"url"==r?(c.config.linkShowTargetTab&&
a.showPage("target"),f||a.showPage("upload")):(a.hidePage("target"),f||a.hidePage("upload"));for(f=0;f<b.length;f++){var m=a.getContentElement("info",b[f]);m&&(m=m.getElement().getParent().getParent(),b[f]==r+"Options"?m.show():m.hide())}a.layout()},setup:function(a){this.setValue(a.type||"url")},commit:function(a){a.type=this.getValue()}},{type:"vbox",id:"urlOptions",children:[{type:"hbox",widths:["25%","75%"],children:[{id:"protocol",type:"select",label:h.protocol,items:[["http://‎","http://"],
["https://‎","https://"],["ftp://‎","ftp://"],["news://‎","news://"],[b.other,""]],"default":c.config.linkDefaultProtocol,setup:function(a){a.url&&this.setValue(a.url.protocol||"")},commit:function(a){a.url||(a.url={});a.url.protocol=this.getValue()}},{type:"text",id:"url",label:h.url,required:!0,onLoad:function(){this.allowOnChange=!0},onKeyUp:function(){this.allowOnChange=!1;var a=this.getDialog().getContentElement("info","protocol"),b=this.getValue(),c=/^((javascript:)|[#\/\.\?])/i,f=/^(http|https|ftp|news):\/\/(?=.)/i.exec(b);
f?(this.setValue(b.substr(f[0].length)),a.setValue(f[0].toLowerCase())):c.test(b)&&a.setValue("");this.allowOnChange=!0},onChange:function(){if(this.allowOnChange)this.onKeyUp()},validate:function(){var a=this.getDialog();return a.getContentElement("info","linkType")&&"url"!=a.getValueOf("info","linkType")?!0:!c.config.linkJavaScriptLinksAllowed&&/javascript\:/.test(this.getValue())?(alert(h.invalidValue),!1):this.getDialog().fakeObj?!0:CKEDITOR.dialog.validate.notEmpty(b.noUrl).apply(this)},setup:function(a){this.allowOnChange=
!1;a.url&&this.setValue(a.url.url);this.allowOnChange=!0},commit:function(a){this.onChange();a.url||(a.url={});a.url.url=this.getValue();this.allowOnChange=!1}}],setup:function(){this.getDialog().getContentElement("info","linkType")||this.getElement().show()}},{type:"button",id:"browse",hidden:"true",filebrowser:"info:url",label:h.browseServer}]},{type:"vbox",id:"anchorOptions",width:260,align:"center",padding:0,children:[{type:"fieldset",id:"selectAnchorText",label:b.selectAnchor,setup:function(){l=
n.getEditorAnchors(c);this.getElement()[l&&l.length?"show":"hide"]()},children:[{type:"hbox",id:"selectAnchor",children:[{type:"select",id:"anchorName","default":"",label:b.anchorName,style:"width: 100%;",items:[[""]],setup:function(a){this.clear();this.add("");if(l)for(var b=0;b<l.length;b++)l[b].name&&this.add(l[b].name);a.anchor&&this.setValue(a.anchor.name);(a=this.getDialog().getContentElement("info","linkType"))&&"email"==a.getValue()&&this.focus()},commit:function(a){a.anchor||(a.anchor={});
a.anchor.name=this.getValue()}},{type:"select",id:"anchorId","default":"",label:b.anchorId,style:"width: 100%;",items:[[""]],setup:function(a){this.clear();this.add("");if(l)for(var b=0;b<l.length;b++)l[b].id&&this.add(l[b].id);a.anchor&&this.setValue(a.anchor.id)},commit:function(a){a.anchor||(a.anchor={});a.anchor.id=this.getValue()}}],setup:function(){this.getElement()[l&&l.length?"show":"hide"]()}}]},{type:"html",id:"noAnchors",style:"text-align: center;",html:'\x3cdiv role\x3d"note" tabIndex\x3d"-1"\x3e'+
CKEDITOR.tools.htmlEncode(b.noAnchors)+"\x3c/div\x3e",focus:!0,setup:function(){this.getElement()[l&&l.length?"hide":"show"]()}}],setup:function(){this.getDialog().getContentElement("info","linkType")||this.getElement().hide()}},{type:"vbox",id:"emailOptions",padding:1,children:[{type:"text",id:"emailAddress",label:b.emailAddress,required:!0,validate:function(){var a=this.getDialog();return a.getContentElement("info","linkType")&&"email"==a.getValueOf("info","linkType")?CKEDITOR.dialog.validate.notEmpty(b.noEmail).apply(this):
!0},setup:function(a){a.email&&this.setValue(a.email.address);(a=this.getDialog().getContentElement("info","linkType"))&&"email"==a.getValue()&&this.select()},commit:function(a){a.email||(a.email={});a.email.address=this.getValue()}},{type:"text",id:"emailSubject",label:b.emailSubject,setup:function(a){a.email&&this.setValue(a.email.subject)},commit:function(a){a.email||(a.email={});a.email.subject=this.getValue()}},{type:"textarea",id:"emailBody",label:b.emailBody,rows:3,"default":"",setup:function(a){a.email&&
this.setValue(a.email.body)},commit:function(a){a.email||(a.email={});a.email.body=this.getValue()}}],setup:function(){this.getDialog().getContentElement("info","linkType")||this.getElement().hide()}},{type:"vbox",id:"telOptions",padding:1,children:[{type:"tel",id:"telNumber",label:b.phoneNumber,required:!0,validate:u,setup:function(a){a.tel&&this.setValue(a.tel);(a=this.getDialog().getContentElement("info","linkType"))&&"tel"==a.getValue()&&this.select()},commit:function(a){a.tel=this.getValue()}}],
setup:function(){this.getDialog().getContentElement("info","linkType")||this.getElement().hide()}}]},{id:"target",requiredContent:"a[target]",label:b.target,title:b.target,elements:[{type:"hbox",widths:["50%","50%"],children:[{type:"select",id:"linkTargetType",label:h.target,"default":"notSet",style:"width : 100%;",items:[[h.notSet,"notSet"],[b.targetFrame,"frame"],[b.targetPopup,"popup"],[h.targetNew,"_blank"],[h.targetTop,"_top"],[h.targetSelf,"_self"],[h.targetParent,"_parent"]],onChange:t,setup:function(a){a.target&&
this.setValue(a.target.type||"notSet");t.call(this)},commit:function(a){a.target||(a.target={});a.target.type=this.getValue()}},{type:"text",id:"linkTargetName",label:b.targetFrameName,"default":"",setup:function(a){a.target&&this.setValue(a.target.name)},commit:function(a){a.target||(a.target={});a.target.name=this.getValue().replace(/([^\x00-\x7F]|\s)/gi,"")}}]},{type:"vbox",width:"100%",align:"center",padding:2,id:"popupFeatures",children:[{type:"fieldset",label:b.popupFeatures,children:[{type:"hbox",
children:[{type:"checkbox",id:"resizable",label:b.popupResizable,setup:d,commit:e},{type:"checkbox",id:"status",label:b.popupStatusBar,setup:d,commit:e}]},{type:"hbox",children:[{type:"checkbox",id:"location",label:b.popupLocationBar,setup:d,commit:e},{type:"checkbox",id:"toolbar",label:b.popupToolbar,setup:d,commit:e}]},{type:"hbox",children:[{type:"checkbox",id:"menubar",label:b.popupMenuBar,setup:d,commit:e},{type:"checkbox",id:"fullscreen",label:b.popupFullScreen,setup:d,commit:e}]},{type:"hbox",
children:[{type:"checkbox",id:"scrollbars",label:b.popupScrollBars,setup:d,commit:e},{type:"checkbox",id:"dependent",label:b.popupDependent,setup:d,commit:e}]},{type:"hbox",children:[{type:"text",widths:["50%","50%"],labelLayout:"horizontal",label:h.width,id:"width",setup:d,commit:e},{type:"text",labelLayout:"horizontal",widths:["50%","50%"],label:b.popupLeft,id:"left",setup:d,commit:e}]},{type:"hbox",children:[{type:"text",labelLayout:"horizontal",widths:["50%","50%"],label:h.height,id:"height",
setup:d,commit:e},{type:"text",labelLayout:"horizontal",label:b.popupTop,widths:["50%","50%"],id:"top",setup:d,commit:e}]}]}]}]},{id:"upload",label:b.upload,title:b.upload,hidden:!0,filebrowser:"uploadButton",elements:[{type:"file",id:"upload",label:h.upload,style:"height:40px",size:29},{type:"fileButton",id:"uploadButton",label:h.uploadSubmit,filebrowser:"info:url","for":["upload","upload"]}]},{id:"advanced",label:b.advanced,title:b.advanced,elements:[{type:"vbox",padding:1,children:[{type:"hbox",
widths:["45%","35%","20%"],children:[{type:"text",id:"advId",requiredContent:"a[id]",label:b.id,setup:g,commit:k},{type:"select",id:"advLangDir",requiredContent:"a[dir]",label:b.langDir,"default":"",style:"width:110px",items:[[h.notSet,""],[b.langDirLTR,"ltr"],[b.langDirRTL,"rtl"]],setup:g,commit:k},{type:"text",id:"advAccessKey",requiredContent:"a[accesskey]",width:"80px",label:b.acccessKey,maxLength:1,setup:g,commit:k}]},{type:"hbox",widths:["45%","35%","20%"],children:[{type:"text",label:b.name,
id:"advName",requiredContent:"a[name]",setup:g,commit:k},{type:"text",label:b.langCode,id:"advLangCode",requiredContent:"a[lang]",width:"110px","default":"",setup:g,commit:k},{type:"text",label:b.tabIndex,id:"advTabIndex",requiredContent:"a[tabindex]",width:"80px",maxLength:5,setup:g,commit:k}]}]},{type:"vbox",padding:1,children:[{type:"hbox",widths:["45%","55%"],children:[{type:"text",label:b.advisoryTitle,requiredContent:"a[title]","default":"",id:"advTitle",setup:g,commit:k},{type:"text",label:b.advisoryContentType,
requiredContent:"a[type]","default":"",id:"advContentType",setup:g,commit:k}]},{type:"hbox",widths:["45%","55%"],children:[{type:"text",label:b.cssClasses,requiredContent:"a(cke-xyz)","default":"",id:"advCSSClasses",setup:g,commit:k},{type:"text",label:b.charset,requiredContent:"a[charset]","default":"",id:"advCharset",setup:g,commit:k}]},{type:"hbox",widths:["45%","55%"],children:[{type:"text",label:b.rel,requiredContent:"a[rel]","default":"",id:"advRel",setup:g,commit:k},{type:"text",label:b.styles,
requiredContent:"a{cke-xyz}","default":"",id:"advStyles",validate:CKEDITOR.dialog.validate.inlineStyle(c.lang.common.invalidInlineStyle),setup:g,commit:k}]},{type:"hbox",widths:["45%","55%"],children:[{type:"checkbox",id:"download",requiredContent:"a[download]",label:b.download,setup:function(a){void 0!==a.download&&this.setValue("checked","checked")},commit:function(a){this.getValue()&&(a.download=this.getValue())}}]}]}]}],onShow:function(){var a=this.getParentEditor(),b=a.getSelection(),c=this.getContentElement("info",
"linkDisplayText").getElement().getParent().getParent(),f=n.getSelectedLink(a,!0),m=f[0]||null;m&&m.hasAttribute("href")&&(b.getSelectedElement()||b.isInTable()||b.selectElement(m));b=n.parseLinkAttributes(a,m);1>=f.length&&n.showDisplayTextForElement(m,a)?c.show():c.hide();this._.selectedElements=f;this.setupContent(b)},onOk:function(){var a={};this.commitContent(a);if(this._.selectedElements.length){var b=this._.selectedElements,h=n.getLinkAttributes(c,a),f=[],m,l,d,g,e,k;for(k=0;k<b.length;k++){g=
b[k];l=g.data("cke-saved-href");m=a.linkText&&q!=a.linkText;d=l==q;l="email"==a.type&&l=="mailto:"+q;g.setAttributes(h.set);g.removeAttributes(h.removed);if(m)e=a.linkText;else if(d||l)e="email"==a.type?a.email.address:h.set["data-cke-saved-href"];e&&g.setText(e);f.push(p(c,g))}c.getSelection().selectRanges(f);delete this._.selectedElements}else{b=n.getLinkAttributes(c,a);h=c.getSelection().getRanges();f=new CKEDITOR.style({element:"a",attributes:b.set});m=[];f.type=CKEDITOR.STYLE_INLINE;for(g=0;g<
h.length;g++){d=h[g];d.collapsed?(e=new CKEDITOR.dom.text(a.linkText||("email"==a.type?a.email.address:b.set["data-cke-saved-href"]),c.document),d.insertNode(e),d.selectNodeContents(e)):q!==a.linkText&&(e=new CKEDITOR.dom.text(a.linkText,c.document),d.shrink(CKEDITOR.SHRINK_TEXT),c.editable().extractHtmlFromRange(d),d.insertNode(e));e=d._find("a");for(k=0;k<e.length;k++)e[k].remove(!0);f.applyToRange(d,c);m.push(d)}c.getSelection().selectRanges(m)}},onLoad:function(){c.config.linkShowAdvancedTab||
this.hidePage("advanced");c.config.linkShowTargetTab||this.hidePage("target")},onFocus:function(){var a=this.getContentElement("info","linkType");a&&"url"==a.getValue()&&(a=this.getContentElement("info","url"),a.select())}}})})();
\ No newline at end of file
<?php
namespace App\Admin;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use FOS\CKEditorBundle\Form\Type\CKEditorType;
/**
* Administration des popups d'information.
* Ces popup sont à destination des utilisateurs (adhérents uniquement pour l'instant),
* et s'ouvrent automatiquement au lancement de l'application,
* tant que l'utilisateur n'a pas cliqué sur le bouton de confirmation
*
* KOHINOS : Outil de gestion de Monnaie Locale Complémentaire
*/
class InformationPopupAdmin extends AbstractAdmin
{
protected function configureFormFields(FormMapper $form): void
{
$form
->add('title', TextType::class, [
'label' => 'Titre',
'required' => true,
])
->add('content', CKEditorType::class, [
'label' => 'Contenu',
'required' => true,
])
->add('validationButtonText', TextType::class, [
'label' => 'Texte du bouton de validation',
'required' => true,
'attr' => [
'placeholder' => 'Par exemple : "J\'ai compris", "Ok"...',
]
])
->add('closingButtonText', TextType::class, [
'label' => 'Texte du bouton de fermeture',
'required' => true,
'attr' => [
'placeholder' => 'Par exemple : "Annuler", "Fermer pour l\'instant"...',
]
])
->add('enabled', null, [
'label' => 'Activé ?',
'help' => 'Une seule popup d\'information peut être active à la fois. Activer cette popup désactivera toutes les autres.'
]);
}
public function postPersist($informationPopup)
{
$this->disableOtherPopups($informationPopup);
}
public function preUpdate($informationPopup)
{
$this->disableOtherPopups($informationPopup);
}
/**
* Only one popup should be enabled at a time.
* If enableling a popup in the admin, disable the rest.
*/
private function disableOtherPopups($informationPopup)
{
if (true == $informationPopup->getEnabled()) {
$em = $this->getConfigurationPool()->getContainer()->get('doctrine')->getManager();
$qb = $em->createQueryBuilder();
$qb->update('App\Entity\InformationPopup', 'e')
->set('e.enabled', ':newValue')
->where('e.id != :id')
->setParameter('newValue', 0)
->setParameter('id', $informationPopup->getId());
$query = $qb->getQuery();
$query->execute();
}
}
protected function configureDatagridFilters(DatagridMapper $datagrid): void
{
$datagrid
->add('title', null, [
'label' => 'Titre'
]);
}
protected function configureListFields(ListMapper $list): void
{
$list
->addIdentifier('title', null, [
'label' => 'Titre'
])
->add('enabled', null, [
'label' => 'Activé ?',
]);
}
}
\ No newline at end of file
......@@ -12,6 +12,8 @@ use App\Entity\Reconversion;
use App\Entity\TransactionPrestataireAdherent;
use App\Entity\User;
use App\Entity\TransactionAdherentPrestataire;
use App\Entity\InformationPopup;
use App\Entity\InformationPopupUser;
use App\Enum\MoyenEnum;
use App\Form\Type\CotiserFormType;
use App\Form\Type\DonAdherentFormType;
......@@ -561,4 +563,31 @@ class UserController extends AbstractController
return $this->render('@kohinos/tav/payment_done_page.html.twig', $templateData);
}
/**
* Register that the connected user (currently only adherents) has clicked on the popup validation button,
* So it's not shown to him/her again.
*
* @Route("/user/setUserValidatedInformationPopup", name="set_user_validated_information_popup")
* @IsGranted({"ROLE_ADHERENT"})
*/
public function setUserValidatedInformationPopupAction(Request $request)
{
$user = $this->security->getUser();
$activePopup = $this->em->getRepository(InformationPopup::class)->findOneBy(['enabled' => true]);
$activePopupUser = $this->em->getRepository(InformationPopupUser::class)->findOneBy(['informationPopup' => $activePopup, 'user' => $user]);
if (null === $activePopupUser) {
$activePopupUser = new InformationPopupUser();
$activePopupUser->setInformationPopup($activePopup);
$activePopupUser->setUser($user);
}
$activePopupUser->setHasValidated(true);
$this->em->persist($activePopupUser);
$this->em->flush();
return $this->redirectToRoute('index');
}
}
<?php
namespace App\Entity;
use App\Repository\InformationPopupRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Ramsey\Uuid\Doctrine\UuidGenerator;
/**
* @ORM\Entity(repositoryClass=InformationPopupRepository::class)
*/
class InformationPopup
{
/**
* @var \Ramsey\Uuid\UuidInterface
*
* @ORM\Id
* @ORM\Column(type="uuid", unique=true)
* @ORM\GeneratedValue(strategy="CUSTOM")
* @ORM\CustomIdGenerator(class=UuidGenerator::class)
*/
protected $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $title;
/**
* @ORM\Column(type="text")
*/
private $content;
/**
* @ORM\Column(type="string", length=100)
*/
private $validationButtonText;
/**
* @ORM\Column(type="string", length=100)
*/
private $closingButtonText;
/**
* Don't use EnablableEntityTrait as it is true by default.
* Only one InformationPopup should be active at a time.
*
* @ORM\Column(type="boolean", options={"default": false})
*/
private $enabled = false;
/**
* @ORM\OneToMany(targetEntity=InformationPopupUser::class, mappedBy="informationPopup", orphanRemoval=true)
*/
private $informationPopupUsers;
public function __construct()
{
$this->informationPopupUsers = new ArrayCollection();
}
public function __toString(): string
{
return $this->getTitle();
}
public function getId()
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(string $content): self
{
$this->content = $content;
return $this;
}
public function getValidationButtonText(): ?string
{
return $this->validationButtonText;
}
public function setValidationButtonText(string $validationButtonText): self
{
$this->validationButtonText = $validationButtonText;
return $this;
}
public function getClosingButtonText(): ?string
{
return $this->closingButtonText;
}
public function setClosingButtonText(string $closingButtonText): self
{
$this->closingButtonText = $closingButtonText;
return $this;
}
public function getEnabled(): ?bool
{
return $this->enabled;
}
public function setEnabled(bool $enabled): self
{
$this->enabled = $enabled;
return $this;
}
/**
* @return Collection<int, InformationPopupUser>
*/
public function getInformationPopupUsers(): Collection
{
return $this->informationPopupUsers;
}
public function addInformationPopupUser(InformationPopupUser $informationPopupUser): self
{
if (!$this->informationPopupUsers->contains($informationPopupUser)) {
$this->informationPopupUsers[] = $informationPopupUser;
$informationPopupUser->setInformationPopup($this);
}
return $this;
}
public function removeInformationPopupUser(InformationPopupUser $informationPopupUser): self
{
if ($this->informationPopupUsers->removeElement($informationPopupUser)) {
// set the owning side to null (unless already changed)
if ($informationPopupUser->getInformationPopup() === $this) {
$informationPopupUser->setInformationPopup(null);
}
}
return $this;
}
}
<?php
namespace App\Entity;
use App\Repository\InformationPopupUserRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=InformationPopupUserRepository::class)
*/
class InformationPopupUser
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity=InformationPopup::class, inversedBy="informationPopupUsers")
* @ORM\JoinColumn(nullable=false)
*/
private $informationPopup;
/**
* @ORM\ManyToOne(targetEntity=User::class)
* @ORM\JoinColumn(nullable=false)
*/
private $user;
/**
* @ORM\Column(type="boolean", options={"default": false})
*/
private $hasValidated = false;
public function getId(): ?int
{
return $this->id;
}
public function getInformationPopup(): ?InformationPopup
{
return $this->informationPopup;
}
public function setInformationPopup(?InformationPopup $informationPopup): self
{
$this->informationPopup = $informationPopup;
return $this;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): self
{
$this->user = $user;
return $this;
}
public function getHasValidated(): ?bool
{
return $this->hasValidated;
}
public function setHasValidated(bool $hasValidated): self
{
$this->hasValidated = $hasValidated;
return $this;
}
}
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250109101735 extends AbstractMigration
{
public function getDescription() : string
{
return '';
}
public function up(Schema $schema) : void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE information_popup (id CHAR(36) NOT NULL COMMENT \'(DC2Type:uuid)\', title VARCHAR(255) NOT NULL, content LONGTEXT NOT NULL, validation_button_text VARCHAR(100) NOT NULL, closing_button_text VARCHAR(100) NOT NULL, enabled TINYINT(1) DEFAULT \'0\' NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_general_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE information_popup_user (id INT AUTO_INCREMENT NOT NULL, information_popup_id CHAR(36) NOT NULL COMMENT \'(DC2Type:uuid)\', user_id CHAR(36) NOT NULL COMMENT \'(DC2Type:uuid)\', has_validated TINYINT(1) DEFAULT \'0\' NOT NULL, INDEX IDX_9AA7FF00FBB63E47 (information_popup_id), INDEX IDX_9AA7FF00A76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_general_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE information_popup_user ADD CONSTRAINT FK_9AA7FF00FBB63E47 FOREIGN KEY (information_popup_id) REFERENCES information_popup (id)');
$this->addSql('ALTER TABLE information_popup_user ADD CONSTRAINT FK_9AA7FF00A76ED395 FOREIGN KEY (user_id) REFERENCES user (id)');
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE information_popup_user DROP FOREIGN KEY FK_9AA7FF00FBB63E47');
$this->addSql('DROP TABLE information_popup');
$this->addSql('DROP TABLE information_popup_user');
}
}
<?php
namespace App\Repository;
use App\Entity\InformationPopup;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\ORMException;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<InformationPopup>
*
* @method InformationPopup|null find($id, $lockMode = null, $lockVersion = null)
* @method InformationPopup|null findOneBy(array $criteria, array $orderBy = null)
* @method InformationPopup[] findAll()
* @method InformationPopup[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class InformationPopupRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, InformationPopup::class);
}
/**
* @throws ORMException
* @throws OptimisticLockException
*/
public function add(InformationPopup $entity, bool $flush = true): void
{
$this->_em->persist($entity);
if ($flush) {
$this->_em->flush();
}
}
/**
* @throws ORMException
* @throws OptimisticLockException
*/
public function remove(InformationPopup $entity, bool $flush = true): void
{
$this->_em->remove($entity);
if ($flush) {
$this->_em->flush();
}
}
// /**
// * @return InformationPopup[] Returns an array of InformationPopup objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('i')
->andWhere('i.exampleField = :val')
->setParameter('val', $value)
->orderBy('i.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?InformationPopup
{
return $this->createQueryBuilder('i')
->andWhere('i.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}
<?php
namespace App\Repository;
use App\Entity\InformationPopupUser;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\ORMException;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<InformationPopupUser>
*
* @method InformationPopupUser|null find($id, $lockMode = null, $lockVersion = null)
* @method InformationPopupUser|null findOneBy(array $criteria, array $orderBy = null)
* @method InformationPopupUser[] findAll()
* @method InformationPopupUser[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class InformationPopupUserRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, InformationPopupUser::class);
}
/**
* @throws ORMException
* @throws OptimisticLockException
*/
public function add(InformationPopupUser $entity, bool $flush = true): void
{
$this->_em->persist($entity);
if ($flush) {
$this->_em->flush();
}
}
/**
* @throws ORMException
* @throws OptimisticLockException
*/
public function remove(InformationPopupUser $entity, bool $flush = true): void
{
$this->_em->remove($entity);
if ($flush) {
$this->_em->flush();
}
}
// /**
// * @return InformationPopupUser[] Returns an array of InformationPopupUser objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('i')
->andWhere('i.exampleField = :val')
->setParameter('val', $value)
->orderBy('i.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?InformationPopupUser
{
return $this->createQueryBuilder('i')
->andWhere('i.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}
......@@ -23,6 +23,8 @@ use App\Entity\Prestataire;
use App\Entity\Rubrique;
use App\Entity\Siege;
use App\Entity\User;
use App\Entity\InformationPopup;
use App\Entity\InformationPopupUser;
use App\Enum\CurrencyEnum;
use App\Flux\AccountableInterface;
use App\Utils\CotisationUtils;
......@@ -109,6 +111,8 @@ class AppExtension extends AbstractExtension
new \Twig_SimpleFunction('parameter', function ($name) {
return $this->container->getParameter($name);
}),
new \Twig_SimpleFunction('showInformationModal', [$this, 'showInformationModal']),
new \Twig_SimpleFunction('getInformationPopupData', [$this, 'getInformationPopupData']),
];
}
......@@ -576,4 +580,38 @@ class AppExtension extends AbstractExtension
{
return $this->tavCotisationUtils->checkExistingRecurringPayment($userEmail);
}
/**
* Display an informative modale destined to users at app loading, if conditions are required.
*
* Conditions :
* - user is adherent (forced for now)
* - user hasn't clicked on the modal validation button yet (InformationPopupUser instance not created or exists with hasValidated property at false)
*/
public function showInformationModal()
{
$user = $this->security->getUser();
if (null != $user && $this->security->isGranted('ROLE_ADHERENT')) {
// There should be only one enabled popup at a given time
$activePopup = $this->em->getRepository(InformationPopup::class)->findOneBy(['enabled' => true]);
if (!is_null($activePopup)) {
$activePopupUser = $this->em->getRepository(InformationPopupUser::class)->findOneBy(['informationPopup' => $activePopup, 'user' => $user]);
if (null == $activePopupUser || false == $activePopupUser->getHasValidated()) {
return true;
}
}
}
return false;
}
/**
* If the information modale is shown, get its data
*/
public function getInformationPopupData()
{
return $this->em->getRepository(InformationPopup::class)->findOneBy(['enabled' => true]);
}
}
......@@ -66,6 +66,7 @@
{% include '@kohinos/common/modale_choix_groupe.html.twig' %}
{% include '@kohinos/common/modale_confirmation_transaction.html.twig' %}
{% include '@kohinos/common/modale_info_for_users.html.twig' %}
<!-- HEADER -->
{% block header %}
......@@ -100,6 +101,16 @@
});
</script>
{% endif %}
{# AFFICHAGE DE LA MODALE INFORMATIVE #}
{% if showInformationModal() %}
<script>
$(document).ready(function() {
$('#infoForUserModal').modal('show');
});
</script>
{% endif %}
{% if app.request.query.get('showmlcadhesionmodal') %}
<script>
$(document).ready(function() {
......
<!-- Modal -->
{% set informationPopupData = getInformationPopupData() %}
<div class="modal fade" id="infoForUserModal" tabindex="-1" role="dialog" aria-labelledby="infoForUserModalTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
{% if informationPopupData %}
<div class="modal-header">
<h5 class="modal-title" id="infoForUserModalTitle">{{ informationPopupData.title }}</h5>
</div>
<div class="modal-body">
{{ informationPopupData.content|raw }}
</div>
<div class="modal-footer">
<a href='{{ path('set_user_validated_information_popup') }}' class="btn btn-primary">{{ informationPopupData.validationButtonText }}</a>
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ informationPopupData.closingButtonText }}</button>
</div>
{% endif %}
</div>
</div>
</div>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment