Commit 9796cd68 by Yvon Kerdoncuff

Merge remote-tracking branch 'origin/develop' into sprint-2-montpellier

parents 81f7495f 6c87fc12
......@@ -433,4 +433,8 @@ form[name="formEncaissement"] label {
.tav-cotisation-payment-form {
display: none;
margin-top: 1rem;
}
#infoForUserModal .modal-body {
word-break: break-all;
}
\ No newline at end of file
......@@ -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
......
......@@ -681,6 +681,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:
......
......@@ -791,6 +791,11 @@ App\Entity\GlobalParameter:
description: "Numéro de téléphone à afficher dans le formulaire de contact si défini"
value: ''
mandatory: 1
gp31:
name: "RECONVERSION_FREQUENCY_HELP_TEXT"
description: "Texte d'explication à destination des prestataires pour le champ Fréquence de reconversion dans leur espace personnel"
value: 'Caisse Alimentaire Commune'
mandatory: 1
App\Entity\Siege:
......
......@@ -791,6 +791,11 @@ App\Entity\GlobalParameter:
description: "Numéro de téléphone à afficher dans le formulaire de contact si défini"
value: ''
mandatory: 1
gp31:
name: "RECONVERSION_FREQUENCY_HELP_TEXT"
description: "Texte d'explication à destination des prestataires pour le champ Fréquence de reconversion dans leur espace personnel"
value: 'Caisse Alimentaire Commune'
mandatory: 1
App\Entity\Siege:
......
This source diff could not be displayed because it is too large. You can view the blob instead.
CKEDITOR.dialog.add("anchor",(function(e){function t(e,t){return e.createFakeElement(e.document.createElement("a",{attributes:t}),"cke_anchor","anchor")}return{title:e.lang.link.anchor.title,minWidth:300,minHeight:60,onOk:function(){var n=CKEDITOR.tools.trim(this.getValueOf("info","txtName")),a={id:n,name:n,"data-cke-saved-name":n};this._.selectedElement?this._.selectedElement.data("cke-realelement")?((n=t(e,a)).replace(this._.selectedElement),CKEDITOR.env.ie&&e.getSelection().selectElement(n)):this._.selectedElement.setAttributes(a):(n=(n=e.getSelection())&&n.getRanges()[0]).collapsed?(a=t(e,a),n.insertNode(a)):(CKEDITOR.env.ie&&9>CKEDITOR.env.version&&(a.class="cke_anchor"),(a=new CKEDITOR.style({element:"a",attributes:a})).type=CKEDITOR.STYLE_INLINE,a.applyToRange(n))},onHide:function(){delete this._.selectedElement},onShow:function(){var t,n=e.getSelection();t=n.getRanges()[0];var a=n.getSelectedElement();t.shrink(CKEDITOR.SHRINK_ELEMENT),t=(a=t.getEnclosedNode())&&a.type===CKEDITOR.NODE_ELEMENT&&("anchor"===a.data("cke-real-element-type")||a.is("a"))?a:void 0;var l=(a=t&&t.data("cke-realelement"))?CKEDITOR.plugins.link.tryRestoreFakeAnchor(e,t):CKEDITOR.plugins.link.getSelectedLink(e);if(l){this._.selectedElement=l;var i=l.data("cke-saved-name");this.setValueOf("info","txtName",i||""),!a&&n.selectElement(l),t&&(this._.selectedElement=t)}this.getContentElement("info","txtName").focus()},contents:[{id:"info",label:e.lang.link.anchor.title,accessKey:"I",elements:[{type:"text",id:"txtName",label:e.lang.link.anchor.name,required:!0,validate:function(){return!!this.getValue()||(alert(e.lang.link.anchor.errorName),!1)}}]}]}}));
\ No newline at end of file
!function(){function e(){var e=this.getDialog(),t=(l=e._.editor).config.linkPhoneRegExp,i=l.config.linkPhoneMsg,l=CKEDITOR.dialog.validate.notEmpty(l.lang.link.noTel).apply(this);return!e.getContentElement("info","linkType")||"tel"!=e.getValueOf("info","linkType")||(!0!==l?l:t?CKEDITOR.dialog.validate.regex(t,i).call(this):void 0)}CKEDITOR.dialog.add("link",(function(t){function i(e,t){var i=e.createRange();return i.setStartBefore(t),i.setEndAfter(t),i}var l,n,a=CKEDITOR.plugins.link,o=function(){var e=(i=this.getDialog()).getContentElement("target","popupFeatures"),i=i.getContentElement("target","linkTargetName"),l=this.getValue();if(e&&i)switch(e=e.getElement(),e.hide(),i.setValue(""),l){case"frame":i.setLabel(t.lang.link.targetFrameName),i.getElement().show();break;case"popup":e.show(),i.setLabel(t.lang.link.targetPopupName),i.getElement().show();break;default:i.setValue(l),i.getElement().hide()}},s=function(e){e.target&&this.setValue(e.target[this.id]||"")},d=function(e){e.advanced&&this.setValue(e.advanced[this.id]||"")},r=function(e){e.target||(e.target={}),e.target[this.id]=this.getValue()||""},h=function(e){e.advanced||(e.advanced={}),e.advanced[this.id]=this.getValue()||""},u=t.lang.common,p=t.lang.link;return{title:p.title,minWidth:"moono-lisa"==(CKEDITOR.skinName||t.config.skin)?450:350,minHeight:240,contents:[{id:"info",label:p.info,title:p.info,elements:[{type:"text",id:"linkDisplayText",label:p.displayText,setup:function(){this.enable(),this.setValue(t.getSelection().getSelectedText()),l=this.getValue()},commit:function(e){e.linkText=this.isEnabled()?this.getValue():""}},{id:"linkType",type:"select",label:p.type,default:"url",items:[[p.toUrl,"url"],[p.toAnchor,"anchor"],[p.toEmail,"email"],[p.toPhone,"tel"]],onChange:function(){var e=this.getDialog(),i=["urlOptions","anchorOptions","emailOptions","telOptions"],l=this.getValue(),n=(n=e.definition.getContents("upload"))&&n.hidden;for("url"==l?(t.config.linkShowTargetTab&&e.showPage("target"),n||e.showPage("upload")):(e.hidePage("target"),n||e.hidePage("upload")),n=0;n<i.length;n++){var a=e.getContentElement("info",i[n]);a&&(a=a.getElement().getParent().getParent(),i[n]==l+"Options"?a.show():a.hide())}e.layout()},setup:function(e){this.setValue(e.type||"url")},commit:function(e){e.type=this.getValue()}},{type:"vbox",id:"urlOptions",children:[{type:"hbox",widths:["25%","75%"],children:[{id:"protocol",type:"select",label:u.protocol,default:"http://",items:[["http://‎","http://"],["https://‎","https://"],["ftp://‎","ftp://"],["news://‎","news://"],[p.other,""]],setup:function(e){e.url&&this.setValue(e.url.protocol||"")},commit:function(e){e.url||(e.url={}),e.url.protocol=this.getValue()}},{type:"text",id:"url",label:u.url,required:!0,onLoad:function(){this.allowOnChange=!0},onKeyUp:function(){this.allowOnChange=!1;var e=this.getDialog().getContentElement("info","protocol"),t=this.getValue(),i=/^(http|https|ftp|news):\/\/(?=.)/i.exec(t);i?(this.setValue(t.substr(i[0].length)),e.setValue(i[0].toLowerCase())):/^((javascript:)|[#\/\.\?])/i.test(t)&&e.setValue(""),this.allowOnChange=!0},onChange:function(){this.allowOnChange&&this.onKeyUp()},validate:function(){var e=this.getDialog();return!(!e.getContentElement("info","linkType")||"url"==e.getValueOf("info","linkType"))||(!t.config.linkJavaScriptLinksAllowed&&/javascript\:/.test(this.getValue())?(alert(u.invalidValue),!1):!!this.getDialog().fakeObj||CKEDITOR.dialog.validate.notEmpty(p.noUrl).apply(this))},setup:function(e){this.allowOnChange=!1,e.url&&this.setValue(e.url.url),this.allowOnChange=!0},commit:function(e){this.onChange(),e.url||(e.url={}),e.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:u.browseServer}]},{type:"vbox",id:"anchorOptions",width:260,align:"center",padding:0,children:[{type:"fieldset",id:"selectAnchorText",label:p.selectAnchor,setup:function(){n=a.getEditorAnchors(t),this.getElement()[n&&n.length?"show":"hide"]()},children:[{type:"hbox",id:"selectAnchor",children:[{type:"select",id:"anchorName",default:"",label:p.anchorName,style:"width: 100%;",items:[[""]],setup:function(e){if(this.clear(),this.add(""),n)for(var t=0;t<n.length;t++)n[t].name&&this.add(n[t].name);e.anchor&&this.setValue(e.anchor.name),(e=this.getDialog().getContentElement("info","linkType"))&&"email"==e.getValue()&&this.focus()},commit:function(e){e.anchor||(e.anchor={}),e.anchor.name=this.getValue()}},{type:"select",id:"anchorId",default:"",label:p.anchorId,style:"width: 100%;",items:[[""]],setup:function(e){if(this.clear(),this.add(""),n)for(var t=0;t<n.length;t++)n[t].id&&this.add(n[t].id);e.anchor&&this.setValue(e.anchor.id)},commit:function(e){e.anchor||(e.anchor={}),e.anchor.id=this.getValue()}}],setup:function(){this.getElement()[n&&n.length?"show":"hide"]()}}]},{type:"html",id:"noAnchors",style:"text-align: center;",html:'<div role="note" tabIndex="-1">'+CKEDITOR.tools.htmlEncode(p.noAnchors)+"</div>",focus:!0,setup:function(){this.getElement()[n&&n.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:p.emailAddress,required:!0,validate:function(){var e=this.getDialog();return!e.getContentElement("info","linkType")||"email"!=e.getValueOf("info","linkType")||CKEDITOR.dialog.validate.notEmpty(p.noEmail).apply(this)},setup:function(e){e.email&&this.setValue(e.email.address),(e=this.getDialog().getContentElement("info","linkType"))&&"email"==e.getValue()&&this.select()},commit:function(e){e.email||(e.email={}),e.email.address=this.getValue()}},{type:"text",id:"emailSubject",label:p.emailSubject,setup:function(e){e.email&&this.setValue(e.email.subject)},commit:function(e){e.email||(e.email={}),e.email.subject=this.getValue()}},{type:"textarea",id:"emailBody",label:p.emailBody,rows:3,default:"",setup:function(e){e.email&&this.setValue(e.email.body)},commit:function(e){e.email||(e.email={}),e.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:p.phoneNumber,required:!0,validate:e,setup:function(e){e.tel&&this.setValue(e.tel),(e=this.getDialog().getContentElement("info","linkType"))&&"tel"==e.getValue()&&this.select()},commit:function(e){e.tel=this.getValue()}}],setup:function(){this.getDialog().getContentElement("info","linkType")||this.getElement().hide()}}]},{id:"target",requiredContent:"a[target]",label:p.target,title:p.target,elements:[{type:"hbox",widths:["50%","50%"],children:[{type:"select",id:"linkTargetType",label:u.target,default:"notSet",style:"width : 100%;",items:[[u.notSet,"notSet"],[p.targetFrame,"frame"],[p.targetPopup,"popup"],[u.targetNew,"_blank"],[u.targetTop,"_top"],[u.targetSelf,"_self"],[u.targetParent,"_parent"]],onChange:o,setup:function(e){e.target&&this.setValue(e.target.type||"notSet"),o.call(this)},commit:function(e){e.target||(e.target={}),e.target.type=this.getValue()}},{type:"text",id:"linkTargetName",label:p.targetFrameName,default:"",setup:function(e){e.target&&this.setValue(e.target.name)},commit:function(e){e.target||(e.target={}),e.target.name=this.getValue().replace(/([^\x00-\x7F]|\s)/gi,"")}}]},{type:"vbox",width:"100%",align:"center",padding:2,id:"popupFeatures",children:[{type:"fieldset",label:p.popupFeatures,children:[{type:"hbox",children:[{type:"checkbox",id:"resizable",label:p.popupResizable,setup:s,commit:r},{type:"checkbox",id:"status",label:p.popupStatusBar,setup:s,commit:r}]},{type:"hbox",children:[{type:"checkbox",id:"location",label:p.popupLocationBar,setup:s,commit:r},{type:"checkbox",id:"toolbar",label:p.popupToolbar,setup:s,commit:r}]},{type:"hbox",children:[{type:"checkbox",id:"menubar",label:p.popupMenuBar,setup:s,commit:r},{type:"checkbox",id:"fullscreen",label:p.popupFullScreen,setup:s,commit:r}]},{type:"hbox",children:[{type:"checkbox",id:"scrollbars",label:p.popupScrollBars,setup:s,commit:r},{type:"checkbox",id:"dependent",label:p.popupDependent,setup:s,commit:r}]},{type:"hbox",children:[{type:"text",widths:["50%","50%"],labelLayout:"horizontal",label:u.width,id:"width",setup:s,commit:r},{type:"text",labelLayout:"horizontal",widths:["50%","50%"],label:p.popupLeft,id:"left",setup:s,commit:r}]},{type:"hbox",children:[{type:"text",labelLayout:"horizontal",widths:["50%","50%"],label:u.height,id:"height",setup:s,commit:r},{type:"text",labelLayout:"horizontal",label:p.popupTop,widths:["50%","50%"],id:"top",setup:s,commit:r}]}]}]}]},{id:"upload",label:p.upload,title:p.upload,hidden:!0,filebrowser:"uploadButton",elements:[{type:"file",id:"upload",label:u.upload,style:"height:40px",size:29},{type:"fileButton",id:"uploadButton",label:u.uploadSubmit,filebrowser:"info:url",for:["upload","upload"]}]},{id:"advanced",label:p.advanced,title:p.advanced,elements:[{type:"vbox",padding:1,children:[{type:"hbox",widths:["45%","35%","20%"],children:[{type:"text",id:"advId",requiredContent:"a[id]",label:p.id,setup:d,commit:h},{type:"select",id:"advLangDir",requiredContent:"a[dir]",label:p.langDir,default:"",style:"width:110px",items:[[u.notSet,""],[p.langDirLTR,"ltr"],[p.langDirRTL,"rtl"]],setup:d,commit:h},{type:"text",id:"advAccessKey",requiredContent:"a[accesskey]",width:"80px",label:p.acccessKey,maxLength:1,setup:d,commit:h}]},{type:"hbox",widths:["45%","35%","20%"],children:[{type:"text",label:p.name,id:"advName",requiredContent:"a[name]",setup:d,commit:h},{type:"text",label:p.langCode,id:"advLangCode",requiredContent:"a[lang]",width:"110px",default:"",setup:d,commit:h},{type:"text",label:p.tabIndex,id:"advTabIndex",requiredContent:"a[tabindex]",width:"80px",maxLength:5,setup:d,commit:h}]}]},{type:"vbox",padding:1,children:[{type:"hbox",widths:["45%","55%"],children:[{type:"text",label:p.advisoryTitle,requiredContent:"a[title]",default:"",id:"advTitle",setup:d,commit:h},{type:"text",label:p.advisoryContentType,requiredContent:"a[type]",default:"",id:"advContentType",setup:d,commit:h}]},{type:"hbox",widths:["45%","55%"],children:[{type:"text",label:p.cssClasses,requiredContent:"a(cke-xyz)",default:"",id:"advCSSClasses",setup:d,commit:h},{type:"text",label:p.charset,requiredContent:"a[charset]",default:"",id:"advCharset",setup:d,commit:h}]},{type:"hbox",widths:["45%","55%"],children:[{type:"text",label:p.rel,requiredContent:"a[rel]",default:"",id:"advRel",setup:d,commit:h},{type:"text",label:p.styles,requiredContent:"a{cke-xyz}",default:"",id:"advStyles",validate:CKEDITOR.dialog.validate.inlineStyle(t.lang.common.invalidInlineStyle),setup:d,commit:h}]},{type:"hbox",widths:["45%","55%"],children:[{type:"checkbox",id:"download",requiredContent:"a[download]",label:p.download,setup:function(e){void 0!==e.download&&this.setValue("checked","checked")},commit:function(e){this.getValue()&&(e.download=this.getValue())}}]}]}]}],onShow:function(){var e=this.getParentEditor(),t=e.getSelection(),i=this.getContentElement("info","linkDisplayText").getElement().getParent().getParent(),l=a.getSelectedLink(e,!0),n=l[0]||null;n&&n.hasAttribute("href")&&(t.getSelectedElement()||t.isInTable()||t.selectElement(n)),t=a.parseLinkAttributes(e,n),1>=l.length&&a.showDisplayTextForElement(n,e)?i.show():i.hide(),this._.selectedElements=l,this.setupContent(t)},onOk:function(){var e={};if(this.commitContent(e),this._.selectedElements.length){var n,o,s,d,r,h=this._.selectedElements,u=a.getLinkAttributes(t,e),p=[];for(r=0;r<h.length;r++)o=(n=h[r]).data("cke-saved-href"),s=n.getHtml(),n.setAttributes(u.set),n.removeAttributes(u.removed),e.linkText&&l!=e.linkText?d=e.linkText:(o==s||"email"==e.type&&-1!=s.indexOf("@"))&&(d="email"==e.type?e.email.address:u.set["data-cke-saved-href"]),d&&n.setText(d),p.push(i(t,n));t.getSelection().selectRanges(p),delete this._.selectedElements}else{for(h=a.getLinkAttributes(t,e),u=t.getSelection().getRanges(),n=[],(p=new CKEDITOR.style({element:"a",attributes:h.set})).type=CKEDITOR.STYLE_INLINE,s=0;s<u.length;s++){for((o=u[s]).collapsed?(d=new CKEDITOR.dom.text(e.linkText||("email"==e.type?e.email.address:h.set["data-cke-saved-href"]),t.document),o.insertNode(d),o.selectNodeContents(d)):l!==e.linkText&&(d=new CKEDITOR.dom.text(e.linkText,t.document),o.shrink(CKEDITOR.SHRINK_TEXT),t.editable().extractHtmlFromRange(o),o.insertNode(d)),d=o._find("a"),r=0;r<d.length;r++)d[r].remove(!0);p.applyToRange(o,t),n.push(o)}t.getSelection().selectRanges(n)}},onLoad:function(){t.config.linkShowAdvancedTab||this.hidePage("advanced"),t.config.linkShowTargetTab||this.hidePage("target")},onFocus:function(){var e=this.getContentElement("info","linkType");e&&"url"==e.getValue()&&(e=this.getContentElement("info","url")).select()}}}))}();
\ No newline at end of file
......@@ -6,7 +6,7 @@
"/build/app.3644f7b2.js"
],
"css": [
"/build/app.8a3f698b.css"
"/build/app.ec67f059.css"
]
},
"admin": {
......
{
"build/app.css": "/build/app.8a3f698b.css",
"build/app.css": "/build/app.ec67f059.css",
"build/app.js": "/build/app.3644f7b2.js",
"build/admin.css": "/build/admin.4de55830.css",
"build/admin.js": "/build/admin.a08fea06.js",
......@@ -85,6 +85,7 @@
"build/ckeditor/lang/fr.js": "/build/ckeditor/lang/fr.js",
"build/ckeditor/skins/moono-lisa/dialog.css": "/build/ckeditor/skins/moono-lisa/dialog.css",
"build/ckeditor/skins/moono/dialog.css": "/build/ckeditor/skins/moono/dialog.css",
"build/ckeditor/plugins/link/dialogs/link.js": "/build/ckeditor/plugins/link/dialogs/link.js",
"build/ckeditor/lang/en.js": "/build/ckeditor/lang/en.js",
"build/ckeditor/skins/kama/dialog_iequirks.css": "/build/ckeditor/skins/kama/dialog_iequirks.css",
"build/ckeditor/skins/kama/dialog_ie7.css": "/build/ckeditor/skins/kama/dialog_ie7.css",
......@@ -112,6 +113,7 @@
"build/ckeditor/skins/kama/skin.js": "/build/ckeditor/skins/kama/skin.js",
"build/ckeditor/contents.css": "/build/ckeditor/contents.css",
"build/ckeditor/skins/moono/images/hidpi/close.png": "/build/ckeditor/skins/moono/images/hidpi/close.png",
"build/ckeditor/plugins/link/dialogs/anchor.js": "/build/ckeditor/plugins/link/dialogs/anchor.js",
"build/ckeditor/skins/moono/images/hidpi/lock.png": "/build/ckeditor/skins/moono/images/hidpi/lock.png",
"build/ckeditor/skins/moono-lisa/images/hidpi/refresh.png": "/build/ckeditor/skins/moono-lisa/images/hidpi/refresh.png",
"build/images/source-sans-pro-v14-latin-300.svg": "/build/images/source-sans-pro-v14-latin-300.4e7fe004.svg",
......@@ -125,6 +127,7 @@
"build/ckeditor/plugins/flash/lang/fr.js": "/build/ckeditor/plugins/flash/lang/fr.js",
"build/ckeditor/plugins/forms/lang/en.js": "/build/ckeditor/plugins/forms/lang/en.js",
"build/ckeditor/plugins/docprops/lang/en.js": "/build/ckeditor/plugins/docprops/lang/en.js",
"build/ckeditor/plugins/link/images/hidpi/anchor.png": "/build/ckeditor/plugins/link/images/hidpi/anchor.png",
"build/ckeditor/skins/moono-lisa/images/hidpi/lock-open.png": "/build/ckeditor/skins/moono-lisa/images/hidpi/lock-open.png",
"build/ckeditor/skins/moono-lisa/images/hidpi/lock.png": "/build/ckeditor/skins/moono-lisa/images/hidpi/lock.png",
"build/ckeditor/skins/moono/images/refresh.png": "/build/ckeditor/skins/moono/images/refresh.png",
......@@ -134,6 +137,7 @@
"build/ckeditor/skins/moono/images/lock.png": "/build/ckeditor/skins/moono/images/lock.png",
"build/ckeditor/skins/moono/images/lock-open.png": "/build/ckeditor/skins/moono/images/lock-open.png",
"build/ckeditor/skins/moono-lisa/images/refresh.png": "/build/ckeditor/skins/moono-lisa/images/refresh.png",
"build/ckeditor/plugins/link/images/anchor.png": "/build/ckeditor/plugins/link/images/anchor.png",
"build/ckeditor/config.js": "/build/ckeditor/config.js",
"build/ckeditor/plugins/liststyle/lang/fr.js": "/build/ckeditor/plugins/liststyle/lang/fr.js",
"build/ckeditor/skins/moono-lisa/images/close.png": "/build/ckeditor/skins/moono-lisa/images/close.png",
......
(()=>{"use strict";var e={913:()=>{try{self["workbox:core:6.5.1"]&&_()}catch(e){}},977:()=>{try{self["workbox:precaching:6.5.1"]&&_()}catch(e){}},80:()=>{try{self["workbox:routing:6.5.1"]&&_()}catch(e){}},873:()=>{try{self["workbox:strategies:6.5.1"]&&_()}catch(e){}}},t={};function s(a){var n=t[a];if(void 0!==n)return n.exports;var r=t[a]={exports:{}};return e[a](r,r.exports,s),r.exports}(()=>{s(913);const e=(e,...t)=>{let s=e;return t.length>0&&(s+=` :: ${JSON.stringify(t)}`),s};class t extends Error{constructor(t,s){super(e(t,s)),this.name=t,this.details=s}}const a={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},n=e=>[a.prefix,e,a.suffix].filter((e=>e&&e.length>0)).join("-"),r=e=>e||n(a.precache),i=e=>e||n(a.runtime);function c(e,t){const s=t();return e.waitUntil(s),s}s(977);function o(e){if(!e)throw new t("add-to-cache-list-unexpected-type",{entry:e});if("string"==typeof e){const t=new URL(e,location.href);return{cacheKey:t.href,url:t.href}}const{revision:s,url:a}=e;if(!a)throw new t("add-to-cache-list-unexpected-type",{entry:e});if(!s){const e=new URL(a,location.href);return{cacheKey:e.href,url:e.href}}const n=new URL(a,location.href),r=new URL(a,location.href);return n.searchParams.set("__WB_REVISION__",s),{cacheKey:n.href,url:r.href}}class h{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:e,state:t})=>{t&&(t.originalRequest=e)},this.cachedResponseWillBeUsed=async({event:e,state:t,cachedResponse:s})=>{if("install"===e.type&&t&&t.originalRequest&&t.originalRequest instanceof Request){const e=t.originalRequest.url;s?this.notUpdatedURLs.push(e):this.updatedURLs.push(e)}return s}}}class l{constructor({precacheController:e}){this.cacheKeyWillBeUsed=async({request:e,params:t})=>{const s=(null==t?void 0:t.cacheKey)||this._precacheController.getCacheKeyForURL(e.url);return s?new Request(s,{headers:e.headers}):e},this._precacheController=e}}let u;async function f(e,s){let a=null;if(e.url){a=new URL(e.url).origin}if(a!==self.location.origin)throw new t("cross-origin-copy-response",{origin:a});const n=e.clone(),r={headers:new Headers(n.headers),status:n.status,statusText:n.statusText},i=s?s(r):r,c=function(){if(void 0===u){const e=new Response("");if("body"in e)try{new Response(e.body),u=!0}catch(e){u=!1}u=!1}return u}()?n.body:await n.blob();return new Response(c,i)}function d(e,t){const s=new URL(e);for(const e of t)s.searchParams.delete(e);return s.href}class p{constructor(){this.promise=new Promise(((e,t)=>{this.resolve=e,this.reject=t}))}}const g=new Set;s(873);function y(e){return"string"==typeof e?new Request(e):e}class w{constructor(e,t){this._cacheKeys={},Object.assign(this,t),this.event=t.event,this._strategy=e,this._handlerDeferred=new p,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map;for(const e of this._plugins)this._pluginStateMap.set(e,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){const{event:s}=this;let a=y(e);if("navigate"===a.mode&&s instanceof FetchEvent&&s.preloadResponse){const e=await s.preloadResponse;if(e)return e}const n=this.hasCallback("fetchDidFail")?a.clone():null;try{for(const e of this.iterateCallbacks("requestWillFetch"))a=await e({request:a.clone(),event:s})}catch(e){if(e instanceof Error)throw new t("plugin-error-request-will-fetch",{thrownErrorMessage:e.message})}const r=a.clone();try{let e;e=await fetch(a,"navigate"===a.mode?void 0:this._strategy.fetchOptions);for(const t of this.iterateCallbacks("fetchDidSucceed"))e=await t({event:s,request:r,response:e});return e}catch(e){throw n&&await this.runCallbacks("fetchDidFail",{error:e,event:s,originalRequest:n.clone(),request:r.clone()}),e}}async fetchAndCachePut(e){const t=await this.fetch(e),s=t.clone();return this.waitUntil(this.cachePut(e,s)),t}async cacheMatch(e){const t=y(e);let s;const{cacheName:a,matchOptions:n}=this._strategy,r=await this.getCacheKey(t,"read"),i=Object.assign(Object.assign({},n),{cacheName:a});s=await caches.match(r,i);for(const e of this.iterateCallbacks("cachedResponseWillBeUsed"))s=await e({cacheName:a,matchOptions:n,cachedResponse:s,request:r,event:this.event})||void 0;return s}async cachePut(e,s){const a=y(e);var n;await(n=0,new Promise((e=>setTimeout(e,n))));const r=await this.getCacheKey(a,"write");if(!s)throw new t("cache-put-with-no-response",{url:(i=r.url,new URL(String(i),location.href).href.replace(new RegExp(`^${location.origin}`),""))});var i;const c=await this._ensureResponseSafeToCache(s);if(!c)return!1;const{cacheName:o,matchOptions:h}=this._strategy,l=await self.caches.open(o),u=this.hasCallback("cacheDidUpdate"),f=u?await async function(e,t,s,a){const n=d(t.url,s);if(t.url===n)return e.match(t,a);const r=Object.assign(Object.assign({},a),{ignoreSearch:!0}),i=await e.keys(t,r);for(const t of i)if(n===d(t.url,s))return e.match(t,a)}(l,r.clone(),["__WB_REVISION__"],h):null;try{await l.put(r,u?c.clone():c)}catch(e){if(e instanceof Error)throw"QuotaExceededError"===e.name&&await async function(){for(const e of g)await e()}(),e}for(const e of this.iterateCallbacks("cacheDidUpdate"))await e({cacheName:o,oldResponse:f,newResponse:c.clone(),request:r,event:this.event});return!0}async getCacheKey(e,t){const s=`${e.url} | ${t}`;if(!this._cacheKeys[s]){let a=e;for(const e of this.iterateCallbacks("cacheKeyWillBeUsed"))a=y(await e({mode:t,request:a,event:this.event,params:this.params}));this._cacheKeys[s]=a}return this._cacheKeys[s]}hasCallback(e){for(const t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(const s of this.iterateCallbacks(e))await s(t)}*iterateCallbacks(e){for(const t of this._strategy.plugins)if("function"==typeof t[e]){const s=this._pluginStateMap.get(t),a=a=>{const n=Object.assign(Object.assign({},a),{state:s});return t[e](n)};yield a}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){let e;for(;e=this._extendLifetimePromises.shift();)await e}destroy(){this._handlerDeferred.resolve(null)}async _ensureResponseSafeToCache(e){let t=e,s=!1;for(const e of this.iterateCallbacks("cacheWillUpdate"))if(t=await e({request:this.request,response:t,event:this.event})||void 0,s=!0,!t)break;return s||t&&200!==t.status&&(t=void 0),t}}class m extends class{constructor(e={}){this.cacheName=i(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){const[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});const t=e.event,s="string"==typeof e.request?new Request(e.request):e.request,a="params"in e?e.params:void 0,n=new w(this,{event:t,request:s,params:a}),r=this._getResponse(n,s,t);return[r,this._awaitComplete(r,n,s,t)]}async _getResponse(e,s,a){let n;await e.runCallbacks("handlerWillStart",{event:a,request:s});try{if(n=await this._handle(s,e),!n||"error"===n.type)throw new t("no-response",{url:s.url})}catch(t){if(t instanceof Error)for(const r of e.iterateCallbacks("handlerDidError"))if(n=await r({error:t,event:a,request:s}),n)break;if(!n)throw t}for(const t of e.iterateCallbacks("handlerWillRespond"))n=await t({event:a,request:s,response:n});return n}async _awaitComplete(e,t,s,a){let n,r;try{n=await e}catch(r){}try{await t.runCallbacks("handlerDidRespond",{event:a,request:s,response:n}),await t.doneWaiting()}catch(e){e instanceof Error&&(r=e)}if(await t.runCallbacks("handlerDidComplete",{event:a,request:s,response:n,error:r}),t.destroy(),r)throw r}}{constructor(e={}){e.cacheName=r(e.cacheName),super(e),this._fallbackToNetwork=!1!==e.fallbackToNetwork,this.plugins.push(m.copyRedirectedCacheableResponsesPlugin)}async _handle(e,t){const s=await t.cacheMatch(e);return s||(t.event&&"install"===t.event.type?await this._handleInstall(e,t):await this._handleFetch(e,t))}async _handleFetch(e,s){let a;const n=s.params||{};if(!this._fallbackToNetwork)throw new t("missing-precache-entry",{cacheName:this.cacheName,url:e.url});{0;const t=n.integrity,r=e.integrity,i=!r||r===t;if(a=await s.fetch(new Request(e,{integrity:r||t})),t&&i){this._useDefaultCacheabilityPluginIfNeeded();await s.cachePut(e,a.clone());0}}return a}async _handleInstall(e,s){this._useDefaultCacheabilityPluginIfNeeded();const a=await s.fetch(e);if(!await s.cachePut(e,a.clone()))throw new t("bad-precaching-response",{url:e.url,status:a.status});return a}_useDefaultCacheabilityPluginIfNeeded(){let e=null,t=0;for(const[s,a]of this.plugins.entries())a!==m.copyRedirectedCacheableResponsesPlugin&&(a===m.defaultPrecacheCacheabilityPlugin&&(e=s),a.cacheWillUpdate&&t++);0===t?this.plugins.push(m.defaultPrecacheCacheabilityPlugin):t>1&&null!==e&&this.plugins.splice(e,1)}}m.defaultPrecacheCacheabilityPlugin={cacheWillUpdate:async({response:e})=>!e||e.status>=400?null:e},m.copyRedirectedCacheableResponsesPlugin={cacheWillUpdate:async({response:e})=>e.redirected?await f(e):e};class _{constructor({cacheName:e,plugins:t=[],fallbackToNetwork:s=!0}={}){this._urlsToCacheKeys=new Map,this._urlsToCacheModes=new Map,this._cacheKeysToIntegrities=new Map,this._strategy=new m({cacheName:r(e),plugins:[...t,new l({precacheController:this})],fallbackToNetwork:s}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this._strategy}precache(e){this.addToCacheList(e),this._installAndActiveListenersAdded||(self.addEventListener("install",this.install),self.addEventListener("activate",this.activate),this._installAndActiveListenersAdded=!0)}addToCacheList(e){const s=[];for(const a of e){"string"==typeof a?s.push(a):a&&void 0===a.revision&&s.push(a.url);const{cacheKey:e,url:n}=o(a),r="string"!=typeof a&&a.revision?"reload":"default";if(this._urlsToCacheKeys.has(n)&&this._urlsToCacheKeys.get(n)!==e)throw new t("add-to-cache-list-conflicting-entries",{firstEntry:this._urlsToCacheKeys.get(n),secondEntry:e});if("string"!=typeof a&&a.integrity){if(this._cacheKeysToIntegrities.has(e)&&this._cacheKeysToIntegrities.get(e)!==a.integrity)throw new t("add-to-cache-list-conflicting-integrities",{url:n});this._cacheKeysToIntegrities.set(e,a.integrity)}if(this._urlsToCacheKeys.set(n,e),this._urlsToCacheModes.set(n,r),s.length>0){const e=`Workbox is precaching URLs without revision info: ${s.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(e)}}}install(e){return c(e,(async()=>{const t=new h;this.strategy.plugins.push(t);for(const[t,s]of this._urlsToCacheKeys){const a=this._cacheKeysToIntegrities.get(s),n=this._urlsToCacheModes.get(t),r=new Request(t,{integrity:a,cache:n,credentials:"same-origin"});await Promise.all(this.strategy.handleAll({params:{cacheKey:s},request:r,event:e}))}const{updatedURLs:s,notUpdatedURLs:a}=t;return{updatedURLs:s,notUpdatedURLs:a}}))}activate(e){return c(e,(async()=>{const e=await self.caches.open(this.strategy.cacheName),t=await e.keys(),s=new Set(this._urlsToCacheKeys.values()),a=[];for(const n of t)s.has(n.url)||(await e.delete(n),a.push(n.url));return{deletedURLs:a}}))}getURLsToCacheKeys(){return this._urlsToCacheKeys}getCachedURLs(){return[...this._urlsToCacheKeys.keys()]}getCacheKeyForURL(e){const t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForCacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){const t=e instanceof Request?e.url:e,s=this.getCacheKeyForURL(t);if(s){return(await self.caches.open(this.strategy.cacheName)).match(s)}}createHandlerBoundToURL(e){const s=this.getCacheKeyForURL(e);if(!s)throw new t("non-precached-url",{url:e});return t=>(t.request=new Request(e),t.params=Object.assign({cacheKey:s},t.params),this.strategy.handle(t))}}let R;const v=()=>(R||(R=new _),R);s(80);const C=e=>e&&"object"==typeof e?e:{handle:e};class b{constructor(e,t,s="GET"){this.handler=C(t),this.match=e,this.method=s}setCatchHandler(e){this.catchHandler=C(e)}}class q extends b{constructor(e,t,s){super((({url:t})=>{const s=e.exec(t.href);if(s&&(t.origin===location.origin||0===s.index))return s.slice(1)}),t,s)}}class U{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener("fetch",(e=>{const{request:t}=e,s=this.handleRequest({request:t,event:e});s&&e.respondWith(s)}))}addCacheListener(){self.addEventListener("message",(e=>{if(e.data&&"CACHE_URLS"===e.data.type){const{payload:t}=e.data;0;const s=Promise.all(t.urlsToCache.map((t=>{"string"==typeof t&&(t=[t]);const s=new Request(...t);return this.handleRequest({request:s,event:e})})));e.waitUntil(s),e.ports&&e.ports[0]&&s.then((()=>e.ports[0].postMessage(!0)))}}))}handleRequest({request:e,event:t}){const s=new URL(e.url,location.href);if(!s.protocol.startsWith("http"))return void 0;const a=s.origin===location.origin,{params:n,route:r}=this.findMatchingRoute({event:t,request:e,sameOrigin:a,url:s});let i=r&&r.handler;const c=e.method;if(!i&&this._defaultHandlerMap.has(c)&&(i=this._defaultHandlerMap.get(c)),!i)return void 0;let o;try{o=i.handle({url:s,request:e,event:t,params:n})}catch(e){o=Promise.reject(e)}const h=r&&r.catchHandler;return o instanceof Promise&&(this._catchHandler||h)&&(o=o.catch((async a=>{if(h){0;try{return await h.handle({url:s,request:e,event:t,params:n})}catch(e){e instanceof Error&&(a=e)}}if(this._catchHandler)return this._catchHandler.handle({url:s,request:e,event:t});throw a}))),o}findMatchingRoute({url:e,sameOrigin:t,request:s,event:a}){const n=this._routes.get(s.method)||[];for(const r of n){let n;const i=r.match({url:e,sameOrigin:t,request:s,event:a});if(i)return n=i,(Array.isArray(n)&&0===n.length||i.constructor===Object&&0===Object.keys(i).length||"boolean"==typeof i)&&(n=void 0),{route:r,params:n}}return{}}setDefaultHandler(e,t="GET"){this._defaultHandlerMap.set(t,C(e))}setCatchHandler(e){this._catchHandler=C(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new t("unregister-route-but-not-found-with-method",{method:e.method});const s=this._routes.get(e.method).indexOf(e);if(!(s>-1))throw new t("unregister-route-route-not-registered");this._routes.get(e.method).splice(s,1)}}let L;class k extends b{constructor(e,t){super((({request:s})=>{const a=e.getURLsToCacheKeys();for(const n of function*(e,{ignoreURLParametersMatching:t=[/^utm_/,/^fbclid$/],directoryIndex:s="index.html",cleanURLs:a=!0,urlManipulation:n}={}){const r=new URL(e,location.href);r.hash="",yield r.href;const i=function(e,t=[]){for(const s of[...e.searchParams.keys()])t.some((e=>e.test(s)))&&e.searchParams.delete(s);return e}(r,t);if(yield i.href,s&&i.pathname.endsWith("/")){const e=new URL(i.href);e.pathname+=s,yield e.href}if(a){const e=new URL(i.href);e.pathname+=".html",yield e.href}if(n){const e=n({url:r});for(const t of e)yield t.href}}(s.url,t)){const t=a.get(n);if(t){return{cacheKey:t,integrity:e.getIntegrityForCacheKey(t)}}}}),e.strategy)}}function K(e){const s=v();!function(e,s,a){let n;if("string"==typeof e){const t=new URL(e,location.href);n=new b((({url:e})=>e.href===t.href),s,a)}else if(e instanceof RegExp)n=new q(e,s,a);else if("function"==typeof e)n=new b(e,s,a);else{if(!(e instanceof b))throw new t("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});n=e}(L||(L=new U,L.addFetchListener(),L.addCacheListener()),L).registerRoute(n)}(new k(s,e))}var T;(function(e){v().precache(e)})([{'revision':null,'url':'/build/admin.4de55830.css'},{'revision':null,'url':'/build/admin.a08fea06.js'},{'revision':'ad79405d542b397996a3079203114b42','url':'/build/admin.a08fea06.js.LICENSE.txt'},{'revision':null,'url':'/build/app.3644f7b2.js'},{'revision':'4ff7361e3c3e359ae88c5fae5738746d','url':'/build/app.3644f7b2.js.LICENSE.txt'},{'revision':null,'url':'/build/app.8a3f698b.css'},{'revision':null,'url':'/build/fonts/fa-brands-400.3dc44d22.woff2'},{'revision':null,'url':'/build/fonts/fa-regular-400.3dc6ca01.woff2'},{'revision':null,'url':'/build/fonts/fa-solid-900.496d5fc1.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-300.d2c7d5c5.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-600.17c0392c.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-600italic.cc34c6e7.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-700.ed37bc60.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-900.476756cd.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-italic.a07cb9c5.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-regular.f74389bd.woff2'},{'revision':null,'url':'/build/images/fa-brands-400.05d20183.svg'},{'revision':null,'url':'/build/images/fa-regular-400.9a0810d6.svg'},{'revision':null,'url':'/build/images/fa-solid-900.a838c42a.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-300.4e7fe004.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-600.cf2758ae.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-600italic.7249d863.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-700.3e4b9e19.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-900.060d8c51.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-italic.08dc9b1c.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-regular.3bb9538c.svg'},{'revision':null,'url':'/build/runtime.6ad5c9da.js'}]),K(T),self.addEventListener("fetch",(function(e){e.respondWith(caches.match(e.request).then((function(t){return t||fetch(e.request)})).catch((function(){return caches.match("/offline.html")})))}))})()})();
\ No newline at end of file
(()=>{"use strict";var e={913:()=>{try{self["workbox:core:6.5.1"]&&_()}catch(e){}},977:()=>{try{self["workbox:precaching:6.5.1"]&&_()}catch(e){}},80:()=>{try{self["workbox:routing:6.5.1"]&&_()}catch(e){}},873:()=>{try{self["workbox:strategies:6.5.1"]&&_()}catch(e){}}},t={};function s(a){var n=t[a];if(void 0!==n)return n.exports;var r=t[a]={exports:{}};return e[a](r,r.exports,s),r.exports}(()=>{s(913);const e=(e,...t)=>{let s=e;return t.length>0&&(s+=` :: ${JSON.stringify(t)}`),s};class t extends Error{constructor(t,s){super(e(t,s)),this.name=t,this.details=s}}const a={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},n=e=>[a.prefix,e,a.suffix].filter((e=>e&&e.length>0)).join("-"),r=e=>e||n(a.precache),i=e=>e||n(a.runtime);function c(e,t){const s=t();return e.waitUntil(s),s}s(977);function o(e){if(!e)throw new t("add-to-cache-list-unexpected-type",{entry:e});if("string"==typeof e){const t=new URL(e,location.href);return{cacheKey:t.href,url:t.href}}const{revision:s,url:a}=e;if(!a)throw new t("add-to-cache-list-unexpected-type",{entry:e});if(!s){const e=new URL(a,location.href);return{cacheKey:e.href,url:e.href}}const n=new URL(a,location.href),r=new URL(a,location.href);return n.searchParams.set("__WB_REVISION__",s),{cacheKey:n.href,url:r.href}}class h{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:e,state:t})=>{t&&(t.originalRequest=e)},this.cachedResponseWillBeUsed=async({event:e,state:t,cachedResponse:s})=>{if("install"===e.type&&t&&t.originalRequest&&t.originalRequest instanceof Request){const e=t.originalRequest.url;s?this.notUpdatedURLs.push(e):this.updatedURLs.push(e)}return s}}}class l{constructor({precacheController:e}){this.cacheKeyWillBeUsed=async({request:e,params:t})=>{const s=(null==t?void 0:t.cacheKey)||this._precacheController.getCacheKeyForURL(e.url);return s?new Request(s,{headers:e.headers}):e},this._precacheController=e}}let u;async function f(e,s){let a=null;if(e.url){a=new URL(e.url).origin}if(a!==self.location.origin)throw new t("cross-origin-copy-response",{origin:a});const n=e.clone(),r={headers:new Headers(n.headers),status:n.status,statusText:n.statusText},i=s?s(r):r,c=function(){if(void 0===u){const e=new Response("");if("body"in e)try{new Response(e.body),u=!0}catch(e){u=!1}u=!1}return u}()?n.body:await n.blob();return new Response(c,i)}function d(e,t){const s=new URL(e);for(const e of t)s.searchParams.delete(e);return s.href}class p{constructor(){this.promise=new Promise(((e,t)=>{this.resolve=e,this.reject=t}))}}const g=new Set;s(873);function y(e){return"string"==typeof e?new Request(e):e}class w{constructor(e,t){this._cacheKeys={},Object.assign(this,t),this.event=t.event,this._strategy=e,this._handlerDeferred=new p,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map;for(const e of this._plugins)this._pluginStateMap.set(e,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){const{event:s}=this;let a=y(e);if("navigate"===a.mode&&s instanceof FetchEvent&&s.preloadResponse){const e=await s.preloadResponse;if(e)return e}const n=this.hasCallback("fetchDidFail")?a.clone():null;try{for(const e of this.iterateCallbacks("requestWillFetch"))a=await e({request:a.clone(),event:s})}catch(e){if(e instanceof Error)throw new t("plugin-error-request-will-fetch",{thrownErrorMessage:e.message})}const r=a.clone();try{let e;e=await fetch(a,"navigate"===a.mode?void 0:this._strategy.fetchOptions);for(const t of this.iterateCallbacks("fetchDidSucceed"))e=await t({event:s,request:r,response:e});return e}catch(e){throw n&&await this.runCallbacks("fetchDidFail",{error:e,event:s,originalRequest:n.clone(),request:r.clone()}),e}}async fetchAndCachePut(e){const t=await this.fetch(e),s=t.clone();return this.waitUntil(this.cachePut(e,s)),t}async cacheMatch(e){const t=y(e);let s;const{cacheName:a,matchOptions:n}=this._strategy,r=await this.getCacheKey(t,"read"),i=Object.assign(Object.assign({},n),{cacheName:a});s=await caches.match(r,i);for(const e of this.iterateCallbacks("cachedResponseWillBeUsed"))s=await e({cacheName:a,matchOptions:n,cachedResponse:s,request:r,event:this.event})||void 0;return s}async cachePut(e,s){const a=y(e);var n;await(n=0,new Promise((e=>setTimeout(e,n))));const r=await this.getCacheKey(a,"write");if(!s)throw new t("cache-put-with-no-response",{url:(i=r.url,new URL(String(i),location.href).href.replace(new RegExp(`^${location.origin}`),""))});var i;const c=await this._ensureResponseSafeToCache(s);if(!c)return!1;const{cacheName:o,matchOptions:h}=this._strategy,l=await self.caches.open(o),u=this.hasCallback("cacheDidUpdate"),f=u?await async function(e,t,s,a){const n=d(t.url,s);if(t.url===n)return e.match(t,a);const r=Object.assign(Object.assign({},a),{ignoreSearch:!0}),i=await e.keys(t,r);for(const t of i)if(n===d(t.url,s))return e.match(t,a)}(l,r.clone(),["__WB_REVISION__"],h):null;try{await l.put(r,u?c.clone():c)}catch(e){if(e instanceof Error)throw"QuotaExceededError"===e.name&&await async function(){for(const e of g)await e()}(),e}for(const e of this.iterateCallbacks("cacheDidUpdate"))await e({cacheName:o,oldResponse:f,newResponse:c.clone(),request:r,event:this.event});return!0}async getCacheKey(e,t){const s=`${e.url} | ${t}`;if(!this._cacheKeys[s]){let a=e;for(const e of this.iterateCallbacks("cacheKeyWillBeUsed"))a=y(await e({mode:t,request:a,event:this.event,params:this.params}));this._cacheKeys[s]=a}return this._cacheKeys[s]}hasCallback(e){for(const t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(const s of this.iterateCallbacks(e))await s(t)}*iterateCallbacks(e){for(const t of this._strategy.plugins)if("function"==typeof t[e]){const s=this._pluginStateMap.get(t),a=a=>{const n=Object.assign(Object.assign({},a),{state:s});return t[e](n)};yield a}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){let e;for(;e=this._extendLifetimePromises.shift();)await e}destroy(){this._handlerDeferred.resolve(null)}async _ensureResponseSafeToCache(e){let t=e,s=!1;for(const e of this.iterateCallbacks("cacheWillUpdate"))if(t=await e({request:this.request,response:t,event:this.event})||void 0,s=!0,!t)break;return s||t&&200!==t.status&&(t=void 0),t}}class m extends class{constructor(e={}){this.cacheName=i(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){const[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});const t=e.event,s="string"==typeof e.request?new Request(e.request):e.request,a="params"in e?e.params:void 0,n=new w(this,{event:t,request:s,params:a}),r=this._getResponse(n,s,t);return[r,this._awaitComplete(r,n,s,t)]}async _getResponse(e,s,a){let n;await e.runCallbacks("handlerWillStart",{event:a,request:s});try{if(n=await this._handle(s,e),!n||"error"===n.type)throw new t("no-response",{url:s.url})}catch(t){if(t instanceof Error)for(const r of e.iterateCallbacks("handlerDidError"))if(n=await r({error:t,event:a,request:s}),n)break;if(!n)throw t}for(const t of e.iterateCallbacks("handlerWillRespond"))n=await t({event:a,request:s,response:n});return n}async _awaitComplete(e,t,s,a){let n,r;try{n=await e}catch(r){}try{await t.runCallbacks("handlerDidRespond",{event:a,request:s,response:n}),await t.doneWaiting()}catch(e){e instanceof Error&&(r=e)}if(await t.runCallbacks("handlerDidComplete",{event:a,request:s,response:n,error:r}),t.destroy(),r)throw r}}{constructor(e={}){e.cacheName=r(e.cacheName),super(e),this._fallbackToNetwork=!1!==e.fallbackToNetwork,this.plugins.push(m.copyRedirectedCacheableResponsesPlugin)}async _handle(e,t){const s=await t.cacheMatch(e);return s||(t.event&&"install"===t.event.type?await this._handleInstall(e,t):await this._handleFetch(e,t))}async _handleFetch(e,s){let a;const n=s.params||{};if(!this._fallbackToNetwork)throw new t("missing-precache-entry",{cacheName:this.cacheName,url:e.url});{0;const t=n.integrity,r=e.integrity,i=!r||r===t;if(a=await s.fetch(new Request(e,{integrity:r||t})),t&&i){this._useDefaultCacheabilityPluginIfNeeded();await s.cachePut(e,a.clone());0}}return a}async _handleInstall(e,s){this._useDefaultCacheabilityPluginIfNeeded();const a=await s.fetch(e);if(!await s.cachePut(e,a.clone()))throw new t("bad-precaching-response",{url:e.url,status:a.status});return a}_useDefaultCacheabilityPluginIfNeeded(){let e=null,t=0;for(const[s,a]of this.plugins.entries())a!==m.copyRedirectedCacheableResponsesPlugin&&(a===m.defaultPrecacheCacheabilityPlugin&&(e=s),a.cacheWillUpdate&&t++);0===t?this.plugins.push(m.defaultPrecacheCacheabilityPlugin):t>1&&null!==e&&this.plugins.splice(e,1)}}m.defaultPrecacheCacheabilityPlugin={cacheWillUpdate:async({response:e})=>!e||e.status>=400?null:e},m.copyRedirectedCacheableResponsesPlugin={cacheWillUpdate:async({response:e})=>e.redirected?await f(e):e};class _{constructor({cacheName:e,plugins:t=[],fallbackToNetwork:s=!0}={}){this._urlsToCacheKeys=new Map,this._urlsToCacheModes=new Map,this._cacheKeysToIntegrities=new Map,this._strategy=new m({cacheName:r(e),plugins:[...t,new l({precacheController:this})],fallbackToNetwork:s}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this._strategy}precache(e){this.addToCacheList(e),this._installAndActiveListenersAdded||(self.addEventListener("install",this.install),self.addEventListener("activate",this.activate),this._installAndActiveListenersAdded=!0)}addToCacheList(e){const s=[];for(const a of e){"string"==typeof a?s.push(a):a&&void 0===a.revision&&s.push(a.url);const{cacheKey:e,url:n}=o(a),r="string"!=typeof a&&a.revision?"reload":"default";if(this._urlsToCacheKeys.has(n)&&this._urlsToCacheKeys.get(n)!==e)throw new t("add-to-cache-list-conflicting-entries",{firstEntry:this._urlsToCacheKeys.get(n),secondEntry:e});if("string"!=typeof a&&a.integrity){if(this._cacheKeysToIntegrities.has(e)&&this._cacheKeysToIntegrities.get(e)!==a.integrity)throw new t("add-to-cache-list-conflicting-integrities",{url:n});this._cacheKeysToIntegrities.set(e,a.integrity)}if(this._urlsToCacheKeys.set(n,e),this._urlsToCacheModes.set(n,r),s.length>0){const e=`Workbox is precaching URLs without revision info: ${s.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(e)}}}install(e){return c(e,(async()=>{const t=new h;this.strategy.plugins.push(t);for(const[t,s]of this._urlsToCacheKeys){const a=this._cacheKeysToIntegrities.get(s),n=this._urlsToCacheModes.get(t),r=new Request(t,{integrity:a,cache:n,credentials:"same-origin"});await Promise.all(this.strategy.handleAll({params:{cacheKey:s},request:r,event:e}))}const{updatedURLs:s,notUpdatedURLs:a}=t;return{updatedURLs:s,notUpdatedURLs:a}}))}activate(e){return c(e,(async()=>{const e=await self.caches.open(this.strategy.cacheName),t=await e.keys(),s=new Set(this._urlsToCacheKeys.values()),a=[];for(const n of t)s.has(n.url)||(await e.delete(n),a.push(n.url));return{deletedURLs:a}}))}getURLsToCacheKeys(){return this._urlsToCacheKeys}getCachedURLs(){return[...this._urlsToCacheKeys.keys()]}getCacheKeyForURL(e){const t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForCacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){const t=e instanceof Request?e.url:e,s=this.getCacheKeyForURL(t);if(s){return(await self.caches.open(this.strategy.cacheName)).match(s)}}createHandlerBoundToURL(e){const s=this.getCacheKeyForURL(e);if(!s)throw new t("non-precached-url",{url:e});return t=>(t.request=new Request(e),t.params=Object.assign({cacheKey:s},t.params),this.strategy.handle(t))}}let R;const v=()=>(R||(R=new _),R);s(80);const C=e=>e&&"object"==typeof e?e:{handle:e};class b{constructor(e,t,s="GET"){this.handler=C(t),this.match=e,this.method=s}setCatchHandler(e){this.catchHandler=C(e)}}class q extends b{constructor(e,t,s){super((({url:t})=>{const s=e.exec(t.href);if(s&&(t.origin===location.origin||0===s.index))return s.slice(1)}),t,s)}}class U{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener("fetch",(e=>{const{request:t}=e,s=this.handleRequest({request:t,event:e});s&&e.respondWith(s)}))}addCacheListener(){self.addEventListener("message",(e=>{if(e.data&&"CACHE_URLS"===e.data.type){const{payload:t}=e.data;0;const s=Promise.all(t.urlsToCache.map((t=>{"string"==typeof t&&(t=[t]);const s=new Request(...t);return this.handleRequest({request:s,event:e})})));e.waitUntil(s),e.ports&&e.ports[0]&&s.then((()=>e.ports[0].postMessage(!0)))}}))}handleRequest({request:e,event:t}){const s=new URL(e.url,location.href);if(!s.protocol.startsWith("http"))return void 0;const a=s.origin===location.origin,{params:n,route:r}=this.findMatchingRoute({event:t,request:e,sameOrigin:a,url:s});let i=r&&r.handler;const c=e.method;if(!i&&this._defaultHandlerMap.has(c)&&(i=this._defaultHandlerMap.get(c)),!i)return void 0;let o;try{o=i.handle({url:s,request:e,event:t,params:n})}catch(e){o=Promise.reject(e)}const h=r&&r.catchHandler;return o instanceof Promise&&(this._catchHandler||h)&&(o=o.catch((async a=>{if(h){0;try{return await h.handle({url:s,request:e,event:t,params:n})}catch(e){e instanceof Error&&(a=e)}}if(this._catchHandler)return this._catchHandler.handle({url:s,request:e,event:t});throw a}))),o}findMatchingRoute({url:e,sameOrigin:t,request:s,event:a}){const n=this._routes.get(s.method)||[];for(const r of n){let n;const i=r.match({url:e,sameOrigin:t,request:s,event:a});if(i)return n=i,(Array.isArray(n)&&0===n.length||i.constructor===Object&&0===Object.keys(i).length||"boolean"==typeof i)&&(n=void 0),{route:r,params:n}}return{}}setDefaultHandler(e,t="GET"){this._defaultHandlerMap.set(t,C(e))}setCatchHandler(e){this._catchHandler=C(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new t("unregister-route-but-not-found-with-method",{method:e.method});const s=this._routes.get(e.method).indexOf(e);if(!(s>-1))throw new t("unregister-route-route-not-registered");this._routes.get(e.method).splice(s,1)}}let L;class k extends b{constructor(e,t){super((({request:s})=>{const a=e.getURLsToCacheKeys();for(const n of function*(e,{ignoreURLParametersMatching:t=[/^utm_/,/^fbclid$/],directoryIndex:s="index.html",cleanURLs:a=!0,urlManipulation:n}={}){const r=new URL(e,location.href);r.hash="",yield r.href;const i=function(e,t=[]){for(const s of[...e.searchParams.keys()])t.some((e=>e.test(s)))&&e.searchParams.delete(s);return e}(r,t);if(yield i.href,s&&i.pathname.endsWith("/")){const e=new URL(i.href);e.pathname+=s,yield e.href}if(a){const e=new URL(i.href);e.pathname+=".html",yield e.href}if(n){const e=n({url:r});for(const t of e)yield t.href}}(s.url,t)){const t=a.get(n);if(t){return{cacheKey:t,integrity:e.getIntegrityForCacheKey(t)}}}}),e.strategy)}}function K(e){const s=v();!function(e,s,a){let n;if("string"==typeof e){const t=new URL(e,location.href);n=new b((({url:e})=>e.href===t.href),s,a)}else if(e instanceof RegExp)n=new q(e,s,a);else if("function"==typeof e)n=new b(e,s,a);else{if(!(e instanceof b))throw new t("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});n=e}(L||(L=new U,L.addFetchListener(),L.addCacheListener()),L).registerRoute(n)}(new k(s,e))}var T;(function(e){v().precache(e)})([{'revision':null,'url':'/build/admin.4de55830.css'},{'revision':null,'url':'/build/admin.a08fea06.js'},{'revision':'ad79405d542b397996a3079203114b42','url':'/build/admin.a08fea06.js.LICENSE.txt'},{'revision':null,'url':'/build/app.3644f7b2.js'},{'revision':'4ff7361e3c3e359ae88c5fae5738746d','url':'/build/app.3644f7b2.js.LICENSE.txt'},{'revision':null,'url':'/build/app.ec67f059.css'},{'revision':null,'url':'/build/fonts/fa-brands-400.3dc44d22.woff2'},{'revision':null,'url':'/build/fonts/fa-regular-400.3dc6ca01.woff2'},{'revision':null,'url':'/build/fonts/fa-solid-900.496d5fc1.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-300.d2c7d5c5.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-600.17c0392c.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-600italic.cc34c6e7.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-700.ed37bc60.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-900.476756cd.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-italic.a07cb9c5.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-regular.f74389bd.woff2'},{'revision':null,'url':'/build/images/fa-brands-400.05d20183.svg'},{'revision':null,'url':'/build/images/fa-regular-400.9a0810d6.svg'},{'revision':null,'url':'/build/images/fa-solid-900.a838c42a.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-300.4e7fe004.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-600.cf2758ae.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-600italic.7249d863.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-700.3e4b9e19.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-900.060d8c51.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-italic.08dc9b1c.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-regular.3bb9538c.svg'},{'revision':null,'url':'/build/runtime.6ad5c9da.js'}]),K(T),self.addEventListener("fetch",(function(e){e.respondWith(caches.match(e.request).then((function(t){return t||fetch(e.request)})).catch((function(){return caches.match("/offline.html")})))}))})()})();
\ No newline at end of file
......@@ -184,8 +184,10 @@ class DonAdmin extends AbstractAdmin
public function getExportFields()
{
$ssaFriendlyTypeNames = $this->getConfigurationPool()->getContainer()->getParameter('tav_env')
&& $this->getConfigurationPool()->getContainer()->getParameter('ssa_friendly_flux_type_names');
return [
'Id' => 'expediteur',
'Id' => $ssaFriendlyTypeNames ? 'expediteur.email' : 'expediteur',
'Groupe' => 'expediteur.groupe.name',
'Type' => 'type',
'Montant' => 'montant',
......
......@@ -64,6 +64,7 @@ class FluxAdmin extends AbstractAdmin
$collection->clearExcept(['list', 'export']);
}
//Where is this method used ?
protected function configureExportFields(): array
{
$ssaFriendlyTypeNames = $this->getConfigurationPool()->getContainer()->getParameter('tav_env')
......@@ -104,7 +105,7 @@ class FluxAdmin extends AbstractAdmin
->add('montant', 'decimal', ['label' => 'Montant', 'attributes' => ['fraction_digits' => 2]])
->add('expediteur', null, ['label' => 'Expediteur'])
->add('destinataire', null, ['label' => 'Destinataire'])
->add('operateur', null, ['label' => 'Operateur'])
->add($ssaFriendlyTypeNames ? 'operateur.email' : 'operateur', null, ['label' => 'Operateur'])
->addIdentifier('reference', null, ['label' => 'Reference'])
// @TODO : ajouter le verify uniquement si l'on souhaite (param url)=> sinon c'est beaucoup trop long...
// ->addIdentifier('verify', null, array('label' => 'Vérifié'))
......@@ -249,7 +250,7 @@ class FluxAdmin extends AbstractAdmin
'Montant' => 'montant',
'Expediteur' => 'expediteur',
'Destinataire' => 'destinataire',
'Operateur' => 'operateur',
'Operateur' => $ssaFriendlyTypeNames ? 'operateur.email' : 'operateur',
'Moyen' => 'moyen',
'Reference' => 'reference',
];
......
<?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", "J\'ai bien effectué l\'action"...',
],
'help' => 'Le clic sur ce bouton entraînera la fermeture définitive de cette popup pour cet utilisateur, il est donc conseillé d\'y renseigner un texte explicite.'
])
->add('closingButtonText', TextType::class, [
'label' => 'Texte du bouton de fermeture',
'required' => true,
'attr' => [
'placeholder' => 'Par exemple : "Fermer pour l\'instant", "Je le ferai plus tard"...',
]
])
->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
......@@ -146,8 +146,8 @@ class SendCcasTransactionsExportToPrestatairesCommand extends Command
if ($previousAnonymousToken !== $row['anonymous_token']) {
$this->fputcsvSeparatedBySemicolon($file, [
'TOTAL ' . $previousAnonymousToken,
$clientTotal,
$nf->format($clientTotal),
number_format($clientTotal, 2),
$this->currencySpellout($nf, $clientTotal),
'',
]);
$clientTotal = 0;
......@@ -156,8 +156,8 @@ class SendCcasTransactionsExportToPrestatairesCommand extends Command
//Write transaction line
$this->fputcsvSeparatedBySemicolon($file, [
$row['anonymous_token'],
$row['montant'],
$this->currencySpellout($nf, $row['montant']),
number_format(floatval($row['montant']), 2),
$this->currencySpellout($nf, floatval($row['montant'])),
$row['created_at'],
]);
$clientTotal += $row['montant'];
......
......@@ -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');
}
}
......@@ -54,6 +54,7 @@ class GlobalParameter
const VIREMENT_RECONVERSION_RAISON_GESTIONNAIRE = 'VIREMENT_RECONVERSION_RAISON_GESTIONNAIRE';
const VIREMENT_RECONVERSION_BIC_GESTIONNAIRE = 'VIREMENT_RECONVERSION_BIC_GESTIONNAIRE';
const VIREMENT_RECONVERSION_IBAN_GESTIONNAIRE = 'VIREMENT_RECONVERSION_IBAN_GESTIONNAIRE';
const RECONVERSION_FREQUENCY_HELP_TEXT = 'RECONVERSION_FREQUENCY_HELP_TEXT';
const SSA_ALLOW_COMPTOIR_TO_UPDATE_HOUSEHOLD_ALLOCATION_DATA = 'SSA_ALLOW_COMPTOIR_TO_UPDATE_HOUSEHOLD_ALLOCATION_DATA';
const SSA_HOUSEHOLD_ALLOCATION_MSG_FOR_COMPTOIR = 'SSA_HOUSEHOLD_ALLOCATION_MSG_FOR_COMPTOIR';
......
<?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;
}
}
......@@ -352,6 +352,13 @@ class GlobalConfigurationFormType extends AbstractType
'required' => false,
'_placeholder' => '',
])
->add('payingentityname', GlobalParameterType::class, [
'label' => "Texte d'explication à destination des prestataires pour le champ Fréquence de reconversion dans leur espace personnel",
'_description' => "Texte d'explication à destination des prestataires pour le champ Fréquence de reconversion dans leur espace personnel",
'name_param' => GlobalParameter::RECONVERSION_FREQUENCY_HELP_TEXT,
'_placeholder' => '',
'required' => true,
])
;
}
......
......@@ -95,9 +95,10 @@ class PrestataireInfosFormType extends AbstractType
if ($this->container->getParameter('tav_env') && $this->container->getParameter('automatisation_reconversion')) {
$mlcName = $this->em->getRepository(GlobalParameter::class)->val(GlobalParameter::MLC_NAME_SMALL);
$helpMsqg = "Fréquence à laquelle je souhaite que la caisse commune de l'alimentation (via l'association Acclimat'action)"
. " me verse en euros la somme des {$mlcName} encaissées dans mon point de vente "
. "(1 {$mlcName} = 1 euro). Le versement se fait via un virement bancaire.";
// If a paying entity is defined, add to to help message
$helpMsg = $this->em->getRepository(GlobalParameter::class)->val(GlobalParameter::RECONVERSION_FREQUENCY_HELP_TEXT);
$helpMsg = is_null($helpMsg) ? '' : $helpMsg;
$builder
->add('reconversionFrequency', ChoiceType::class, [
......@@ -110,7 +111,7 @@ class PrestataireInfosFormType extends AbstractType
'label' => 'Fréquence de reconversion :',
'placeholder' => 'Choisir une option',
'required' => false,
'help' => $helpMsqg
'help' => $helpMsg
]);
}
......
<?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
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 Version20250115160900 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("INSERT INTO global_parameter (id, name, description, value, mandatory) VALUES (UUID(), 'PAYING_ENTITY_NAME', 'Nom de l\'organisme qui effectuera les paiements en euros (versement des reconversions aux prestataires...)', null, '1')");
}
public function down(Schema $schema) : void
{
$this->addSql("DELETE FROM global_parameter WHERE name='PAYING_ENTITY_NAME'");
// this down() migration is auto-generated, please modify it to your needs
}
}
<?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 Version20250128122800 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("INSERT INTO global_parameter (id, name, description, value, mandatory) VALUES (UUID(), 'RECONVERSION_FREQUENCY_HELP_TEXT', 'Texte d\'explication à destination des prestataires pour le champ Fréquence de reconversion dans leur espace personnel', null, '1')");
$this->addSql("DELETE FROM global_parameter WHERE name='PAYING_ENTITY_NAME'");
}
public function down(Schema $schema) : void
{
$this->addSql("DELETE FROM global_parameter WHERE name='RECONVERSION_FREQUENCY_HELP_TEXT'");
$this->addSql("INSERT INTO global_parameter (id, name, description, value, mandatory) VALUES (UUID(), 'PAYING_ENTITY_NAME', 'Nom de l\'organisme qui effectuera les paiements en euros (versement des reconversions aux prestataires...)', null, '1')");
// this down() migration is auto-generated, please modify it to your needs
}
}
<?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]);
}
}
......@@ -3,7 +3,7 @@
<div>
{% if object is instanceof("App\\Entity\\DonAdherent") or (object is instanceof("App\\Entity\\Don") and object.type == 'don_adherent' ) %}
<a class="sonata-link-identifier" href="{{ path('adherent_edit', {'id': object.expediteur.id}) }}">
{{ 'Adhérent'|trans }} : {{ object.expediteur.name }}
{{ 'Adhérent'|trans }} : {% if tav_env and ssa_friendly_flux_type_names %}{{ object.expediteur.email }}{% else %}{{ object.expediteur.name }}{% endif %}
</a>
{% elseif object is instanceof("App\\Entity\\DonPrestataire") or (object is instanceof("App\\Entity\\Don") and object.type == 'don_prestataire' ) %}
<a class="sonata-link-identifier" href="{{ path('prestataire_edit', {'id': object.expediteur.id}) }}">
......
......@@ -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" data-backdrop="static" data-keyboard="false" 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
......@@ -8,6 +8,7 @@ Encore
{from: './node_modules/ckeditor/adapters', to: 'ckeditor/adapters/[path][name].[ext]'},
{from: './node_modules/ckeditor/lang', to: 'ckeditor/lang/[path][name].[ext]', pattern: /fr\.js|en\.js$/},
{from: './node_modules/ckeditor/plugins', to: 'ckeditor/plugins/[path][name].[ext]', pattern: /(\/lang\/(fr\.js|en\.js)|(^lang\/.*))/},
{from: './node_modules/ckeditor/plugins/link', to: 'ckeditor/plugins/link/[path][name].[ext]'},
{from: './node_modules/ckeditor/skins', to: 'ckeditor/skins/[path][name].[ext]'}
])
// directory where compiled assets will be stored
......
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