ode-ngjs-front 1.4.18 → 1.4.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/version.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
ode-ngjs-front
|
|
1
|
+
ode-ngjs-front 04/12/2025 18:31:47
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";(self.webpackChunkode_ngjs_front=self.webpackChunkode_ngjs_front||[]).push([[91],{4798:(e,t,i)=>{i.d(t,{Z:()=>n});const n='<style>.cantine-menu-card{color:#333;justify-content:center;align-items:center;padding:5%;border-radius:10px;box-shadow:0 0 10px rgba(0,0,0,.1)}.cantine-select-wrapper{display:flex;align-items:center;justify-content:center;gap:10px;margin-bottom:20px;font-family:Roboto,sans-serif;color:#333}.cantine-select-wrapper label{font-weight:700;font-size:1em}.cantine-select-wrapper select{padding:6px 10px;border-radius:5px;border:1px solid #ccc;font-size:.95em;font-family:Roboto,sans-serif;background-color:#fff;color:#333;box-shadow:0 2px 5px rgba(0,0,0,.05);transition:border-color .3s ease}.cantine-select-wrapper select:focus{outline:0;border-color:#f7955c}.cantine-select{padding:8px 12px;font-size:1em;border-radius:5px;border:1px solid #ccc;font-family:Roboto,sans-serif;background-color:#fff;color:#333;box-shadow:0 0 5px rgba(0,0,0,.05);max-width:100%}.menu-error-message{padding:1rem;color:#721c24;background-color:#f8d7da;border:1px solid #f5c6cb;border-radius:4px;margin-top:1rem}.cantine-separator{border:none;height:1px;background-color:#ccc;margin:3% 0}.cantine-section{margin-bottom:3%}.cantine-section-title{font-weight:700;font-size:1.1em;display:flex;align-items:center}.cantine-item{margin-left:1%;font-family:Roboto;color:#4a4a4a;font-size:medium}.cantine-item{align-items:center;gap:5px}.cantine-items-container{border-left:2px solid #ccc;margin-left:.8%;padding-left:3%}.cantine-icon{width:1em;height:1em;margin-left:5px;vertical-align:middle;display:inline-block;margin-bottom:10px}.cantine-dot{height:.6em;width:.6em;border-radius:50%;display:inline-block;margin-right:2%}.cantine-arrow-button{background:0 0;border:none;font-size:1.5em;cursor:pointer;opacity:.6;transition:opacity .3s ease}.cantine-arrow-button:hover{opacity:1}.cantine-arrow-button:focus{outline:0}.cantine-allergen-collapse{background-color:#f9f9f9;border-radius:5px;padding:0;display:none;transition:all .3s ease-in-out;font-size:.9em}.cantine-allergen-collapse.open{display:block}.cantine-collapse-toggle{background-color:#f7955c;border:none;padding:0 10px;border-radius:5px;font-weight:700;cursor:pointer;display:block;margin-top:0;color:#fff;font-size:.8em}.cantine-collapse-toggle:hover{background-color:#e6b848}.cantine-red{background-color:red}.cantine-green{background-color:green}.cantine-blue{background-color:#00f}.cantine-pink{background-color:pink}.cantine-yellow{background-color:orange}</style> <div class="widget-dashboard"> <div class="cantine-menu-card"> <h2 style="color:#333;font-family:Roboto,sans-serif;display:flex;align-items:center;justify-content:center;gap:10px"> <i18n>cantine.title</i18n> </h2> <div class="cantine-separator"></div> <div ng-if="ctrl.noStructuresError" class="menu-error-message"> <i18n>cantine.error.noStructures</i18n> </div> <div ng-if="ctrl.loadStructuresError" class="menu-error-message"> <i18n>cantine.error.loadStructuresFailed</i18n> </div> <div ng-if="ctrl.showUaiDropdown"> <select id="uaiSelect" class="form-control" ng-model="ctrl.selectedUai" ng-options="option.uai as option.name for option in ctrl.schoolOptions" ng-change="ctrl.onUaiSelected()"> <option value="" disabled="disabled" selected="selected" hidden> <i18n>cantine.selectEtablissement</i18n> </option> </select> </div> <div class="cantine-date-navigation" style="display:flex;align-items:center;justify-content:center;gap:10px;position:relative"> <button class="cantine-arrow-button" ng-click="ctrl.changeDate(-1)">←</button> <span style="font-size:1.2em;font-weight:700;cursor:pointer" ng-show="!ctrl.showDatepicker" ng-click="ctrl.toggleDatepicker(true)">{{ ctrl.currentDate }}</span> <input type="date" ng-model="ctrl.pickerDate" ng-blur="ctrl.onDateBlur()" ng-show="ctrl.showDatepicker" style="font-size:1.2em;font-weight:700;cursor:pointer;text-align:center" ng-click="ctrl.toggleDatepicker(true)"/> <button class="cantine-arrow-button" ng-click="ctrl.changeDate(1)">→</button> </div> <div ng-if="ctrl.selectedUai"> <div ng-if="!ctrl.menuUnavailable"> <div class="cantine-section"> <div class="cantine-section-title"> <span class="cantine-dot cantine-red"></span> <i18n>cantine.entree</i18n> </div> <div class="cantine-items-container"> <div class="cantine-item" ng-repeat="item in ctrl.data.entrees"> {{ item.designationMenu && item.designationMenu.trim() !== \'\' ? item.designationMenu : item.nom }} <img ng-if="item.bio" src="/assets/widgets/cantine-widget/cantine-logos/bio-logo.png" alt="Bio" class="cantine-icon" title="Agriculture biologique"> <img ng-if="item.faitmaison" src="/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png" alt="Fait Maison" class="cantine-icon" title="Fait maison"> <img ng-if="item.vegetarien" src="/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png" alt="Vegetarian" class="cantine-icon" title="Végétarien"> <img ng-if="item.local" src="/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png" alt="Local Product" class="cantine-icon" title="Produit local"> <button class="cantine-collapse-toggle" ng-click="item.showAllergies = !item.showAllergies" ng-if="ctrl.getAllergies(item).length > 0"> <i18n>cantine.allergenes</i18n> </button> <div class="cantine-allergen-collapse" ng-class="{\'open\': item.showAllergies}" ng-if="ctrl.getAllergies(item).length > 0"> <span>{{ ctrl.getAllergies(item).join(\', \') }}</span> </div> </div> </div> </div> <div class="cantine-section"> <div class="cantine-section-title"> <span class="cantine-dot cantine-green"></span> <i18n>cantine.plat</i18n> </div> <div class="cantine-items-container"> <div class="cantine-item" ng-repeat="item in ctrl.data.plats"> {{ item.designationMenu && item.designationMenu.trim() !== \'\' ? item.designationMenu : item.nom }} <img ng-if="item.bio" src="/assets/widgets/cantine-widget/cantine-logos/bio-logo.png" alt="Bio" class="cantine-icon" title="Agriculture biologique"> <img ng-if="item.faitmaison" src="/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png" alt="Fait Maison" class="cantine-icon" title="Fait maison"> <img ng-if="item.vegetarien" src="/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png" alt="Vegetarian" class="cantine-icon" title="Végétarien"> <img ng-if="item.local" src="/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png" alt="Local Product" class="cantine-icon" title="Produit local"> <button class="cantine-collapse-toggle" ng-click="item.showAllergies = !item.showAllergies" ng-if="ctrl.getAllergies(item).length > 0"> <i18n>cantine.allergenes</i18n> </button> <div class="cantine-allergen-collapse" ng-class="{\'open\': item.showAllergies}" ng-if="ctrl.getAllergies(item).length > 0"> <span>{{ ctrl.getAllergies(item).join(\', \') }}</span> </div> </div> </div> </div> <div class="cantine-section"> <div class="cantine-section-title"> <span class="cantine-dot cantine-blue"></span> <i18n>cantine.accompagnement</i18n> </div> <div class="cantine-items-container"> <div class="cantine-item" ng-repeat="item in ctrl.data.accompagnements"> {{ item.designationMenu && item.designationMenu.trim() !== \'\' ? item.designationMenu : item.nom }} <img ng-if="item.bio" src="/assets/widgets/cantine-widget/cantine-logos/bio-logo.png" alt="Bio" class="cantine-icon" title="Agriculture biologique"> <img ng-if="item.faitmaison" src="/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png" alt="Fait Maison" class="cantine-icon" title="Fait maison"> <img ng-if="item.vegetarien" src="/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png" alt="Vegetarian" class="cantine-icon" title="Végétarien"> <img ng-if="item.local" src="/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png" alt="Local Product" class="cantine-icon" title="Produit local"> <button class="cantine-collapse-toggle" ng-click="item.showAllergies = !item.showAllergies" ng-if="ctrl.getAllergies(item).length > 0"> <i18n>cantine.allergenes</i18n> </button> <div class="cantine-allergen-collapse" ng-class="{\'open\': item.showAllergies}" ng-if="ctrl.getAllergies(item).length > 0"> <span>{{ ctrl.getAllergies(item).join(\', \') }}</span> </div> </div> </div> </div> <div class="cantine-section"> <div class="cantine-section-title"> <span class="cantine-dot cantine-pink"></span> <i18n>cantine.laitage</i18n> </div> <div class="cantine-items-container"> <div class="cantine-item" ng-repeat="item in ctrl.data.laitage"> {{ item.designationMenu && item.designationMenu.trim() !== \'\' ? item.designationMenu : item.nom }} <img ng-if="item.bio" src="/assets/widgets/cantine-widget/cantine-logos/bio-logo.png" alt="Bio" class="cantine-icon" title="Agriculture biologique"> <img ng-if="item.faitmaison" src="/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png" alt="Fait Maison" class="cantine-icon" title="Fait maison"> <img ng-if="item.vegetarien" src="/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png" alt="Vegetarian" class="cantine-icon" title="Végétarien"> <img ng-if="item.local" src="/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png" alt="Local Product" class="cantine-icon" title="Produit local"> <button class="cantine-collapse-toggle" ng-click="item.showAllergies = !item.showAllergies" ng-if="ctrl.getAllergies(item).length > 0"> <i18n>cantine.allergenes</i18n> </button> <div class="cantine-allergen-collapse" ng-class="{\'open\': item.showAllergies}" ng-if="ctrl.getAllergies(item).length > 0"> <span>{{ ctrl.getAllergies(item).join(\', \') }}</span> </div> </div> </div> </div> <div class="cantine-section"> <div class="cantine-section-title"> <span class="cantine-dot cantine-yellow"></span> <i18n>cantine.dessert</i18n> </div> <div class="cantine-items-container"> <div class="cantine-item" ng-repeat="item in ctrl.data.desserts"> {{ item.designationMenu && item.designationMenu.trim() !== \'\' ? item.designationMenu : item.nom }} <img ng-if="item.bio" src="/assets/widgets/cantine-widget/cantine-logos/bio-logo.png" alt="Bio" class="cantine-icon" title="Agriculture biologique"> <img ng-if="item.faitmaison" src="/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png" alt="Fait Maison" class="cantine-icon" title="Fait maison"> <img ng-if="item.vegetarien" src="/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png" alt="Vegetarian" class="cantine-icon" title="Végétarien"> <img ng-if="item.local" src="/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png" alt="Local Product" class="cantine-icon" title="Produit local"> <button class="cantine-collapse-toggle" ng-click="item.showAllergies = !item.showAllergies" ng-if="ctrl.getAllergies(item).length > 0"> <i18n>cantine.allergenes</i18n> </button> <div class="cantine-allergen-collapse" ng-class="{\'open\': item.showAllergies}" ng-if="ctrl.getAllergies(item).length > 0"> <span>{{ ctrl.getAllergies(item).join(\', \') }}</span> </div> </div> </div> </div> </div> <div ng-if="ctrl.menuUnavailable" class="menu-error-message"> <div ng-if="ctrl.selectInstitutionError"> <i18n>cantine.error.selectInstitution</i18n> </div> <div ng-if="ctrl.menuNotAvailableError"> <i18n>cantine.error.menuNotAvailable</i18n> </div> <div ng-if="ctrl.menuUnavailableForInstitutionError"> <i18n>cantine.error.menuUnavailableForInstitution</i18n> </div> <div ng-if="ctrl.loadMenuError"> <i18n>cantine.error.loadMenuFailed</i18n> </div> </div> </div> </div> </div>'},8544:function(e,t,i){var n=this&&this.__awaiter||function(e,t,i,n){return new(i||(i=Promise))(function(a,r){function s(e){try{l(n.next(e))}catch(e){r(e)}}function o(e){try{l(n.throw(e))}catch(e){r(e)}}function l(e){var t;e.done?a(e.value):(t=e.value,t instanceof i?t:new i(function(e){e(t)})).then(s,o)}l((n=n.apply(e,t||[])).next())})},a=this&&this.__generator||function(e,t){var i,n,a,r,s={label:0,sent:function(){if(1&a[0])throw a[1];return a[1]},trys:[],ops:[]};return r={next:o(0),throw:o(1),return:o(2)},"function"==typeof Symbol&&(r[Symbol.iterator]=function(){return this}),r;function o(r){return function(o){return function(r){if(i)throw new TypeError("Generator is already executing.");for(;s;)try{if(i=1,n&&(a=2&r[0]?n.return:r[0]?n.throw||((a=n.return)&&a.call(n),0):n.next)&&!(a=a.call(n,r[1])).done)return a;switch(n=0,a&&(r=[2&r[0],a.value]),r[0]){case 0:case 1:a=r;break;case 4:return s.label++,{value:r[1],done:!1};case 5:s.label++,n=r[1],r=[0];continue;case 7:r=s.ops.pop(),s.trys.pop();continue;default:if(!(a=s.trys,(a=a.length>0&&a[a.length-1])||6!==r[0]&&2!==r[0])){s=0;continue}if(3===r[0]&&(!a||r[1]>a[0]&&r[1]<a[3])){s.label=r[1];break}if(6===r[0]&&s.label<a[1]){s.label=a[1],a=r;break}if(a&&s.label<a[2]){s.label=a[2],s.ops.push(r);break}a[2]&&s.ops.pop(),s.trys.pop();continue}r=t.call(e,s)}catch(e){r=[6,e],n=0}finally{i=a=0}if(5&r[0])throw r[1];return{value:r[0]?r[1]:void 0,done:!0}}([r,o])}}},r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.odeModuleName=void 0;var s=r(i(4202)),o=i(9419),l=r(i(381));i(4470);var c=r(i(9669)),g=function(){function e(e){this.$scope=e,this.data={},this.error=null,this.uaiList=[],this.selectedUai="",this.schoolOptions=[],this.menuUnavailable=!1,this.noStructuresError=!1,this.loadStructuresError=!1,this.selectInstitutionError=!1,this.menuNotAvailableError=!1,this.menuUnavailableForInstitutionError=!1,this.loadMenuError=!1,this.currentDate="",this.pickerDate=new Date,this.showDatepicker=!1,this.previousApiDate="";var t=(0,o.session)().user;this.apiDate=(0,l.default)(this.pickerDate).format("YYYY-MM-DD"),this.updateCurrentDateDisplay();var i=t.uai;if(Array.isArray(i)&&i.length>1)this.loadUserStructures(t.userId);else if("string"==typeof i||Array.isArray(i)&&1===i.length){this.uaiList=Array.isArray(i)?i:[i];var n=Array.isArray(t.structureNames)?t.structureNames:[];this.schoolOptions=this.uaiList.map(function(e,t){return{uai:e,name:n[t]||e}}),this.setupUaiDropdown()}else this.uaiList=[],this.schoolOptions=[],this.selectedUai=""}return e.prototype.onUaiSelected=function(){this.selectedUai&&this.fetchMenu()},Object.defineProperty(e.prototype,"showUaiDropdown",{get:function(){return this.schoolOptions.length>1},enumerable:!1,configurable:!0}),e.prototype.loadUserStructures=function(e){var t;return n(this,void 0,void 0,function(){var i;return a(this,function(n){switch(n.label){case 0:return n.trys.push([0,2,,3]),[4,c.default.get("/directory/user/".concat(e))];case 1:return(i=n.sent().data)&&Array.isArray(i.structureNodes)?(this.schoolOptions=i.structureNodes.map(function(e){return{uai:e.UAI,name:e.feederName||e.name||e.UAI}}),this.uaiList=this.schoolOptions.map(function(e){return e.uai}),this.setupUaiDropdown(),null===(t=this.apply)||void 0===t||t.call(this)):(this.clearAllErrorFlags(),this.noStructuresError=!0),[3,3];case 2:return n.sent(),this.clearAllErrorFlags(),this.loadStructuresError=!0,[3,3];case 3:return[2]}})})},e.prototype.changeDate=function(e){this.pickerDate.setDate(this.pickerDate.getDate()+e),this.updateDateAndFetch()},e.prototype.processDateSelection=function(){this.updateDateAndFetch(),this.showDatepicker=!1},e.prototype.onDateBlur=function(){this.pickerDate instanceof Date&&!isNaN(this.pickerDate.getTime())&&(this.processDateSelection(),this.$scope.$apply())},e.prototype.toggleDatepicker=function(e){void 0===e&&(e=null),this.showDatepicker=null!==e?e:!this.showDatepicker},e.prototype.updateDateAndFetch=function(){this.apiDate=(0,l.default)(this.pickerDate).format("YYYY-MM-DD"),this.apiDate!==this.previousApiDate&&(this.previousApiDate=this.apiDate,this.updateCurrentDateDisplay(),this.fetchMenu())},e.prototype.updateCurrentDateDisplay=function(){var e="en"===((0,o.session)().currentLanguage||"fr")?"en-US":"fr-FR";this.currentDate=this.pickerDate.toLocaleDateString(e,{weekday:"long",day:"2-digit",month:"long"}),this.currentDate=this.currentDate.charAt(0).toUpperCase()+this.currentDate.slice(1)},e.prototype.fetchMenu=function(){var e,t=this;if(!this.selectedUai)return this.data={entrees:[],plats:[],accompagnements:[],desserts:[],laitage:[]},this.menuUnavailable=!0,this.clearAllErrorFlags(),this.selectInstitutionError=!0,void(null===(e=this.apply)||void 0===e||e.call(this));c.default.get("/appregistry/".concat(this.selectedUai,"/cantine/menu?date=").concat(this.apiDate)).then(function(e){var i,n,a=null===(i=e.data)||void 0===i?void 0:i.menu;Array.isArray(a)&&a.length>0?(t.data={entrees:a.filter(function(e){return"entree"===e.type}),plats:a.filter(function(e){return"plat"===e.type}),accompagnements:a.filter(function(e){return"accompagnement"===e.type}),laitage:a.filter(function(e){return"laitage"===e.type}),desserts:a.filter(function(e){return"dessert"===e.type})},t.menuUnavailable=!1,t.error=null,t.selectInstitutionError=!1,t.menuNotAvailableError=!1,t.menuUnavailableForInstitutionError=!1,t.loadMenuError=!1,t.noStructuresError=!1,t.loadStructuresError=!1):(t.data={entrees:[],plats:[],accompagnements:[],desserts:[],laitage:[]},t.menuUnavailable=!0,t.clearAllErrorFlags(),t.menuNotAvailableError=!0,t.error=null),null===(n=t.apply)||void 0===n||n.call(t)}).catch(function(e){var i,n;t.data={entrees:[],plats:[],accompagnements:[],desserts:[],laitage:[]},400===(null===(i=e.response)||void 0===i?void 0:i.status)?(t.menuUnavailable=!0,t.clearAllErrorFlags(),t.menuUnavailableForInstitutionError=!0,t.error=null):(t.menuUnavailable=!0,t.clearAllErrorFlags(),t.loadMenuError=!0,t.error=e.message||"Unknown error"),null===(n=t.apply)||void 0===n||n.call(t)})},e.prototype.getAllergies=function(e){return e?Object.keys(e).filter(function(t){return t.startsWith("allerg_")&&0!==e[t]&&void 0!==e[t]}).map(function(e){return e.replace("allerg_","").replace("_"," ")}):[]},e.prototype.clearAllErrorFlags=function(){this.noStructuresError=!1,this.loadStructuresError=!1,this.selectInstitutionError=!1,this.menuNotAvailableError=!1,this.menuUnavailableForInstitutionError=!1,this.loadMenuError=!1},e.prototype.setupUaiDropdown=function(){if(this.schoolOptions.length>1){var e="en"===((0,o.session)().currentLanguage||"fr")?"Institution":"Établissement";this.schoolOptions.unshift({uai:"",name:e}),this.selectedUai=""}else 1===this.schoolOptions.length?(this.selectedUai=this.schoolOptions[0].uai,this.fetchMenu()):this.selectedUai=""},e}(),u=function(){function e(){this.restrict="E",this.template=i(4798).Z,this.scope={},this.bindToController=!0,this.controller=[g],this.controllerAs="ctrl",this.require=["odeCantineWidget"]}return e.prototype.link=function(e,t,i,r){return n(this,void 0,void 0,function(){var t;return a(this,function(i){return(t=null==r?void 0:r[0])&&(t.apply=function(){return e.$apply()}),[2]})})},e}();(0,o.notif)().onLangReady().promise.then(function(e){if("en"===e)(0,o.conf)().Platform.idiom.addKeys(i(4884));else(0,o.conf)().Platform.idiom.addKeys(i(4848))}),t.odeModuleName="odeCantineWidgetModule",s.default.module(t.odeModuleName,[]).directive("odeCantineWidget",function(){return new u})},4884:e=>{e.exports=JSON.parse('{"cantine.title":"Today\'s Menu","cantine.entree":"Starter","cantine.laitage":"Dairy","cantine.plat":"Main Course","cantine.accompagnement":"Side Dish","cantine.dessert":"Dessert","cantine.allergenes":"⚠️ Allergens","cantine.selectUai":"Institution","cantine.error.noStructures":"No structures found for user.","cantine.error.loadStructuresFailed":"Failed to load user structures.","cantine.error.selectInstitution":"Please select an institution.","cantine.error.menuNotAvailable":"Menu not available for this date.","cantine.error.menuUnavailableForInstitution":"Menu unavailable for this institution.","cantine.error.loadMenuFailed":"An error occurred while loading the menu."}')},4848:e=>{e.exports=JSON.parse('{"cantine.title":"Menu du jour","cantine.entree":"Entrée","cantine.laitage":"Laitage","cantine.plat":"Plat","cantine.accompagnement":"Accompagnement","cantine.dessert":"Dessert","cantine.allergenes":"⚠️ Allergènes","cantine.selectUai":"Établissement","cantine.error.noStructures":"Aucune structure trouvée pour l\'utilisateur.","cantine.error.loadStructuresFailed":"Échec du chargement des structures utilisateur.","cantine.error.selectInstitution":"Veuillez sélectionner un établissement.","cantine.error.menuNotAvailable":"Menu non disponible pour cette date.","cantine.error.menuUnavailableForInstitution":"Menu indisponible pour cet établissement.","cantine.error.loadMenuFailed":"Une erreur est survenue lors du chargement du menu."}')}}]);
|
|
1
|
+
"use strict";(self.webpackChunkode_ngjs_front=self.webpackChunkode_ngjs_front||[]).push([[91],{4798:(e,t,i)=>{i.d(t,{Z:()=>n});const n='<style>.cantine-menu-card{color:#333;justify-content:center;align-items:center;padding:5%;border-radius:10px;box-shadow:0 0 10px rgba(0,0,0,.1)}.cantine-select-wrapper{display:flex;align-items:center;justify-content:center;gap:10px;margin-bottom:20px;font-family:Roboto,sans-serif;color:#333}.cantine-select-wrapper label{font-weight:700;font-size:1em}.cantine-select-wrapper select{padding:6px 10px;border-radius:5px;border:1px solid #ccc;font-size:.95em;font-family:Roboto,sans-serif;background-color:#fff;color:#333;box-shadow:0 2px 5px rgba(0,0,0,.05);transition:border-color .3s ease}.cantine-select-wrapper select:focus{outline:0;border-color:#f7955c}.cantine-select{padding:8px 12px;font-size:1em;border-radius:5px;border:1px solid #ccc;font-family:Roboto,sans-serif;background-color:#fff;color:#333;box-shadow:0 0 5px rgba(0,0,0,.05);max-width:100%}.menu-error-message{padding:1rem;color:#721c24;background-color:#f8d7da;border:1px solid #f5c6cb;border-radius:4px;margin-top:1rem}.cantine-separator{border:none;height:1px;background-color:#ccc;margin:3% 0}.cantine-section{margin-bottom:3%}.cantine-section-title{font-weight:700;font-size:1.1em;display:flex;align-items:center}.cantine-item{margin-left:1%;font-family:Roboto;color:#4a4a4a;font-size:medium}.cantine-item{align-items:center;gap:5px}.cantine-items-container{border-left:2px solid #ccc;margin-left:.8%;padding-left:3%}.cantine-icon{width:1em;height:1em;margin-left:5px;vertical-align:middle;display:inline-block;margin-bottom:10px}.cantine-dot{height:.6em;width:.6em;border-radius:50%;display:inline-block;margin-right:2%}.cantine-arrow-button{background:0 0;border:none;font-size:1.5em;cursor:pointer;opacity:.6;transition:opacity .3s ease}.cantine-notice{margin-top:1.5rem;padding-top:1rem;font-size:.85em;color:#666;text-align:center;font-style:italic;line-height:1.4}.cantine-arrow-button:hover{opacity:1}.cantine-arrow-button:focus{outline:0}.cantine-allergen-collapse{background-color:#f9f9f9;border-radius:5px;padding:0;display:none;transition:all .3s ease-in-out;font-size:.9em}.cantine-allergen-collapse.open{display:block}.cantine-collapse-toggle{background-color:#f7955c;border:none;padding:0 10px;border-radius:5px;font-weight:700;cursor:pointer;display:block;margin-top:0;color:#fff;font-size:.8em}.cantine-collapse-toggle:hover{background-color:#e6b848}.cantine-red{background-color:red}.cantine-green{background-color:green}.cantine-blue{background-color:#00f}.cantine-pink{background-color:pink}.cantine-yellow{background-color:orange}</style> <div class="widget-dashboard"> <div class="cantine-menu-card"> <h2 style="color:#333;font-family:Roboto,sans-serif;display:flex;align-items:center;justify-content:center;gap:10px"> <i18n>cantine.title</i18n> </h2> <div class="cantine-separator"></div> <div ng-if="ctrl.noStructuresError" class="menu-error-message"> <i18n>cantine.error.noStructures</i18n> </div> <div ng-if="ctrl.loadStructuresError" class="menu-error-message"> <i18n>cantine.error.loadStructuresFailed</i18n> </div> <div ng-if="ctrl.showUaiDropdown"> <select id="uaiSelect" class="form-control" ng-model="ctrl.selectedUai" ng-options="option.uai as option.name for option in ctrl.schoolOptions" ng-change="ctrl.onUaiSelected()"> <option value="" disabled="disabled" selected="selected" hidden> <i18n>cantine.selectEtablissement</i18n> </option> </select> </div> <div class="cantine-date-navigation" style="display:flex;align-items:center;justify-content:center;gap:10px;position:relative"> <button class="cantine-arrow-button" ng-click="ctrl.changeDate(-1)">←</button> <span style="font-size:1.2em;font-weight:700;cursor:pointer" ng-show="!ctrl.showDatepicker" ng-click="ctrl.toggleDatepicker(true)">{{ ctrl.currentDate }}</span> <input type="date" ng-model="ctrl.pickerDate" ng-blur="ctrl.onDateBlur()" ng-show="ctrl.showDatepicker" style="font-size:1.2em;font-weight:700;cursor:pointer;text-align:center" ng-click="ctrl.toggleDatepicker(true)"/> <button class="cantine-arrow-button" ng-click="ctrl.changeDate(1)">→</button> </div> <div ng-if="ctrl.selectedUai"> <div ng-if="!ctrl.menuUnavailable"> <div class="cantine-section"> <div class="cantine-section-title"> <span class="cantine-dot cantine-red"></span> <i18n>cantine.entree</i18n> </div> <div class="cantine-items-container"> <div class="cantine-item" ng-repeat="item in ctrl.data.entrees"> {{ item.designationMenu && item.designationMenu.trim() !== \'\' ? item.designationMenu : item.nom }} <img ng-if="item.bio" src="/assets/widgets/cantine-widget/cantine-logos/bio-logo.png" alt="Bio" class="cantine-icon" title="Agriculture biologique"> <img ng-if="item.faitmaison" src="/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png" alt="Fait Maison" class="cantine-icon" title="Fait maison"> <img ng-if="item.vegetarien" src="/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png" alt="Vegetarian" class="cantine-icon" title="Végétarien"> <img ng-if="item.local" src="/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png" alt="Local Product" class="cantine-icon" title="Produit local"> <button class="cantine-collapse-toggle" ng-click="item.showAllergies = !item.showAllergies" ng-if="ctrl.getAllergies(item).length > 0"> <i18n>cantine.allergenes</i18n> </button> <div class="cantine-allergen-collapse" ng-class="{\'open\': item.showAllergies}" ng-if="ctrl.getAllergies(item).length > 0"> <span>{{ ctrl.getAllergies(item).join(\', \') }}</span> </div> </div> </div> </div> <div class="cantine-section"> <div class="cantine-section-title"> <span class="cantine-dot cantine-green"></span> <i18n>cantine.plat</i18n> </div> <div class="cantine-items-container"> <div class="cantine-item" ng-repeat="item in ctrl.data.plats"> {{ item.designationMenu && item.designationMenu.trim() !== \'\' ? item.designationMenu : item.nom }} <img ng-if="item.bio" src="/assets/widgets/cantine-widget/cantine-logos/bio-logo.png" alt="Bio" class="cantine-icon" title="Agriculture biologique"> <img ng-if="item.faitmaison" src="/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png" alt="Fait Maison" class="cantine-icon" title="Fait maison"> <img ng-if="item.vegetarien" src="/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png" alt="Vegetarian" class="cantine-icon" title="Végétarien"> <img ng-if="item.local" src="/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png" alt="Local Product" class="cantine-icon" title="Produit local"> <button class="cantine-collapse-toggle" ng-click="item.showAllergies = !item.showAllergies" ng-if="ctrl.getAllergies(item).length > 0"> <i18n>cantine.allergenes</i18n> </button> <div class="cantine-allergen-collapse" ng-class="{\'open\': item.showAllergies}" ng-if="ctrl.getAllergies(item).length > 0"> <span>{{ ctrl.getAllergies(item).join(\', \') }}</span> </div> </div> </div> </div> <div class="cantine-section"> <div class="cantine-section-title"> <span class="cantine-dot cantine-blue"></span> <i18n>cantine.accompagnement</i18n> </div> <div class="cantine-items-container"> <div class="cantine-item" ng-repeat="item in ctrl.data.accompagnements"> {{ item.designationMenu && item.designationMenu.trim() !== \'\' ? item.designationMenu : item.nom }} <img ng-if="item.bio" src="/assets/widgets/cantine-widget/cantine-logos/bio-logo.png" alt="Bio" class="cantine-icon" title="Agriculture biologique"> <img ng-if="item.faitmaison" src="/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png" alt="Fait Maison" class="cantine-icon" title="Fait maison"> <img ng-if="item.vegetarien" src="/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png" alt="Vegetarian" class="cantine-icon" title="Végétarien"> <img ng-if="item.local" src="/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png" alt="Local Product" class="cantine-icon" title="Produit local"> <button class="cantine-collapse-toggle" ng-click="item.showAllergies = !item.showAllergies" ng-if="ctrl.getAllergies(item).length > 0"> <i18n>cantine.allergenes</i18n> </button> <div class="cantine-allergen-collapse" ng-class="{\'open\': item.showAllergies}" ng-if="ctrl.getAllergies(item).length > 0"> <span>{{ ctrl.getAllergies(item).join(\', \') }}</span> </div> </div> </div> </div> <div class="cantine-section"> <div class="cantine-section-title"> <span class="cantine-dot cantine-pink"></span> <i18n>cantine.laitage</i18n> </div> <div class="cantine-items-container"> <div class="cantine-item" ng-repeat="item in ctrl.data.laitage"> {{ item.designationMenu && item.designationMenu.trim() !== \'\' ? item.designationMenu : item.nom }} <img ng-if="item.bio" src="/assets/widgets/cantine-widget/cantine-logos/bio-logo.png" alt="Bio" class="cantine-icon" title="Agriculture biologique"> <img ng-if="item.faitmaison" src="/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png" alt="Fait Maison" class="cantine-icon" title="Fait maison"> <img ng-if="item.vegetarien" src="/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png" alt="Vegetarian" class="cantine-icon" title="Végétarien"> <img ng-if="item.local" src="/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png" alt="Local Product" class="cantine-icon" title="Produit local"> <button class="cantine-collapse-toggle" ng-click="item.showAllergies = !item.showAllergies" ng-if="ctrl.getAllergies(item).length > 0"> <i18n>cantine.allergenes</i18n> </button> <div class="cantine-allergen-collapse" ng-class="{\'open\': item.showAllergies}" ng-if="ctrl.getAllergies(item).length > 0"> <span>{{ ctrl.getAllergies(item).join(\', \') }}</span> </div> </div> </div> </div> <div class="cantine-section"> <div class="cantine-section-title"> <span class="cantine-dot cantine-yellow"></span> <i18n>cantine.dessert</i18n> </div> <div class="cantine-items-container"> <div class="cantine-item" ng-repeat="item in ctrl.data.desserts"> {{ item.designationMenu && item.designationMenu.trim() !== \'\' ? item.designationMenu : item.nom }} <img ng-if="item.bio" src="/assets/widgets/cantine-widget/cantine-logos/bio-logo.png" alt="Bio" class="cantine-icon" title="Agriculture biologique"> <img ng-if="item.faitmaison" src="/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png" alt="Fait Maison" class="cantine-icon" title="Fait maison"> <img ng-if="item.vegetarien" src="/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png" alt="Vegetarian" class="cantine-icon" title="Végétarien"> <img ng-if="item.local" src="/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png" alt="Local Product" class="cantine-icon" title="Produit local"> <button class="cantine-collapse-toggle" ng-click="item.showAllergies = !item.showAllergies" ng-if="ctrl.getAllergies(item).length > 0"> <i18n>cantine.allergenes</i18n> </button> <div class="cantine-allergen-collapse" ng-class="{\'open\': item.showAllergies}" ng-if="ctrl.getAllergies(item).length > 0"> <span>{{ ctrl.getAllergies(item).join(\', \') }}</span> </div> </div> </div> </div> <div class="cantine-notice"> <i18n>cantine.notice</i18n> </div> </div> <div ng-if="ctrl.menuUnavailable" class="menu-error-message"> <div ng-if="ctrl.selectInstitutionError"> <i18n>cantine.error.selectInstitution</i18n> </div> <div ng-if="ctrl.menuNotAvailableError"> <i18n>cantine.error.menuNotAvailable</i18n> </div> <div ng-if="ctrl.menuUnavailableForInstitutionError"> <i18n>cantine.error.menuUnavailableForInstitution</i18n> </div> <div ng-if="ctrl.loadMenuError"> <i18n>cantine.error.loadMenuFailed</i18n> </div> </div> </div> </div> </div>'},8544:function(e,t,i){var n=this&&this.__awaiter||function(e,t,i,n){return new(i||(i=Promise))(function(a,r){function o(e){try{l(n.next(e))}catch(e){r(e)}}function s(e){try{l(n.throw(e))}catch(e){r(e)}}function l(e){var t;e.done?a(e.value):(t=e.value,t instanceof i?t:new i(function(e){e(t)})).then(o,s)}l((n=n.apply(e,t||[])).next())})},a=this&&this.__generator||function(e,t){var i,n,a,r,o={label:0,sent:function(){if(1&a[0])throw a[1];return a[1]},trys:[],ops:[]};return r={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(r[Symbol.iterator]=function(){return this}),r;function s(r){return function(s){return function(r){if(i)throw new TypeError("Generator is already executing.");for(;o;)try{if(i=1,n&&(a=2&r[0]?n.return:r[0]?n.throw||((a=n.return)&&a.call(n),0):n.next)&&!(a=a.call(n,r[1])).done)return a;switch(n=0,a&&(r=[2&r[0],a.value]),r[0]){case 0:case 1:a=r;break;case 4:return o.label++,{value:r[1],done:!1};case 5:o.label++,n=r[1],r=[0];continue;case 7:r=o.ops.pop(),o.trys.pop();continue;default:if(!(a=o.trys,(a=a.length>0&&a[a.length-1])||6!==r[0]&&2!==r[0])){o=0;continue}if(3===r[0]&&(!a||r[1]>a[0]&&r[1]<a[3])){o.label=r[1];break}if(6===r[0]&&o.label<a[1]){o.label=a[1],a=r;break}if(a&&o.label<a[2]){o.label=a[2],o.ops.push(r);break}a[2]&&o.ops.pop(),o.trys.pop();continue}r=t.call(e,o)}catch(e){r=[6,e],n=0}finally{i=a=0}if(5&r[0])throw r[1];return{value:r[0]?r[1]:void 0,done:!0}}([r,s])}}},r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.odeModuleName=void 0;var o=r(i(4202)),s=i(9419),l=r(i(381));i(4470);var c=r(i(9669)),g=function(){function e(e){this.$scope=e,this.data={},this.error=null,this.uaiList=[],this.selectedUai="",this.schoolOptions=[],this.menuUnavailable=!1,this.noStructuresError=!1,this.loadStructuresError=!1,this.selectInstitutionError=!1,this.menuNotAvailableError=!1,this.menuUnavailableForInstitutionError=!1,this.loadMenuError=!1,this.currentDate="",this.pickerDate=new Date,this.showDatepicker=!1,this.previousApiDate="";var t=(0,s.session)().user;this.apiDate=(0,l.default)(this.pickerDate).format("YYYY-MM-DD"),this.updateCurrentDateDisplay();var i=t.uai;if(Array.isArray(i)&&i.length>1)this.loadUserStructures(t.userId);else if("string"==typeof i||Array.isArray(i)&&1===i.length){this.uaiList=Array.isArray(i)?i:[i];var n=Array.isArray(t.structureNames)?t.structureNames:[];this.schoolOptions=this.uaiList.map(function(e,t){return{uai:e,name:n[t]||e}}),this.setupUaiDropdown()}else this.uaiList=[],this.schoolOptions=[],this.selectedUai=""}return e.prototype.onUaiSelected=function(){this.selectedUai&&this.fetchMenu()},Object.defineProperty(e.prototype,"showUaiDropdown",{get:function(){return this.schoolOptions.length>1},enumerable:!1,configurable:!0}),e.prototype.loadUserStructures=function(e){var t;return n(this,void 0,void 0,function(){var i;return a(this,function(n){switch(n.label){case 0:return n.trys.push([0,2,,3]),[4,c.default.get("/directory/user/".concat(e))];case 1:return(i=n.sent().data)&&Array.isArray(i.structureNodes)?(this.schoolOptions=i.structureNodes.map(function(e){return{uai:e.UAI,name:e.feederName||e.name||e.UAI}}),this.uaiList=this.schoolOptions.map(function(e){return e.uai}),this.setupUaiDropdown(),null===(t=this.apply)||void 0===t||t.call(this)):(this.clearAllErrorFlags(),this.noStructuresError=!0),[3,3];case 2:return n.sent(),this.clearAllErrorFlags(),this.loadStructuresError=!0,[3,3];case 3:return[2]}})})},e.prototype.changeDate=function(e){this.pickerDate.setDate(this.pickerDate.getDate()+e),this.updateDateAndFetch()},e.prototype.processDateSelection=function(){this.updateDateAndFetch(),this.showDatepicker=!1},e.prototype.onDateBlur=function(){this.pickerDate instanceof Date&&!isNaN(this.pickerDate.getTime())&&(this.processDateSelection(),this.$scope.$apply())},e.prototype.toggleDatepicker=function(e){void 0===e&&(e=null),this.showDatepicker=null!==e?e:!this.showDatepicker},e.prototype.updateDateAndFetch=function(){this.apiDate=(0,l.default)(this.pickerDate).format("YYYY-MM-DD"),this.apiDate!==this.previousApiDate&&(this.previousApiDate=this.apiDate,this.updateCurrentDateDisplay(),this.fetchMenu())},e.prototype.updateCurrentDateDisplay=function(){var e="en"===((0,s.session)().currentLanguage||"fr")?"en-US":"fr-FR";this.currentDate=this.pickerDate.toLocaleDateString(e,{weekday:"long",day:"2-digit",month:"long"}),this.currentDate=this.currentDate.charAt(0).toUpperCase()+this.currentDate.slice(1)},e.prototype.fetchMenu=function(){var e,t=this;if(!this.selectedUai)return this.data={entrees:[],plats:[],accompagnements:[],desserts:[],laitage:[]},this.menuUnavailable=!0,this.clearAllErrorFlags(),this.selectInstitutionError=!0,void(null===(e=this.apply)||void 0===e||e.call(this));c.default.get("/appregistry/".concat(this.selectedUai,"/cantine/menu?date=").concat(this.apiDate)).then(function(e){var i,n,a=null===(i=e.data)||void 0===i?void 0:i.menu;Array.isArray(a)&&a.length>0?(t.data={entrees:a.filter(function(e){return"entree"===e.type}),plats:a.filter(function(e){return"plat"===e.type}),accompagnements:a.filter(function(e){return"accompagnement"===e.type}),laitage:a.filter(function(e){return"laitage"===e.type}),desserts:a.filter(function(e){return"dessert"===e.type})},t.menuUnavailable=!1,t.error=null,t.selectInstitutionError=!1,t.menuNotAvailableError=!1,t.menuUnavailableForInstitutionError=!1,t.loadMenuError=!1,t.noStructuresError=!1,t.loadStructuresError=!1):(t.data={entrees:[],plats:[],accompagnements:[],desserts:[],laitage:[]},t.menuUnavailable=!0,t.clearAllErrorFlags(),t.menuNotAvailableError=!0,t.error=null),null===(n=t.apply)||void 0===n||n.call(t)}).catch(function(e){var i,n;t.data={entrees:[],plats:[],accompagnements:[],desserts:[],laitage:[]},400===(null===(i=e.response)||void 0===i?void 0:i.status)?(t.menuUnavailable=!0,t.clearAllErrorFlags(),t.menuUnavailableForInstitutionError=!0,t.error=null):(t.menuUnavailable=!0,t.clearAllErrorFlags(),t.loadMenuError=!0,t.error=e.message||"Unknown error"),null===(n=t.apply)||void 0===n||n.call(t)})},e.prototype.getAllergies=function(e){return e?Object.keys(e).filter(function(t){return t.startsWith("allerg_")&&0!==e[t]&&void 0!==e[t]}).map(function(e){return e.replace("allerg_","").replace("_"," ")}):[]},e.prototype.clearAllErrorFlags=function(){this.noStructuresError=!1,this.loadStructuresError=!1,this.selectInstitutionError=!1,this.menuNotAvailableError=!1,this.menuUnavailableForInstitutionError=!1,this.loadMenuError=!1},e.prototype.setupUaiDropdown=function(){if(this.schoolOptions.length>1){var e="en"===((0,s.session)().currentLanguage||"fr")?"Institution":"Établissement";this.schoolOptions.unshift({uai:"",name:e}),this.selectedUai=""}else 1===this.schoolOptions.length?(this.selectedUai=this.schoolOptions[0].uai,this.fetchMenu()):this.selectedUai=""},e}(),u=function(){function e(){this.restrict="E",this.template=i(4798).Z,this.scope={},this.bindToController=!0,this.controller=[g],this.controllerAs="ctrl",this.require=["odeCantineWidget"]}return e.prototype.link=function(e,t,i,r){return n(this,void 0,void 0,function(){var t;return a(this,function(i){return(t=null==r?void 0:r[0])&&(t.apply=function(){return e.$apply()}),[2]})})},e}();(0,s.notif)().onLangReady().promise.then(function(e){if("en"===e)(0,s.conf)().Platform.idiom.addKeys(i(4884));else(0,s.conf)().Platform.idiom.addKeys(i(4848))}),t.odeModuleName="odeCantineWidgetModule",o.default.module(t.odeModuleName,[]).directive("odeCantineWidget",function(){return new u})},4884:e=>{e.exports=JSON.parse('{"cantine.title":"Today\'s Menu","cantine.entree":"Starter","cantine.laitage":"Dairy","cantine.plat":"Main Course","cantine.accompagnement":"Side Dish","cantine.dessert":"Dessert","cantine.allergenes":"⚠️ Allergens","cantine.selectUai":"Institution","cantine.notice":"* The information in these menus may be modified according to supplies; updates will be made accordingly","cantine.error.noStructures":"No structures found for user.","cantine.error.loadStructuresFailed":"Failed to load user structures.","cantine.error.selectInstitution":"Please select an institution.","cantine.error.menuNotAvailable":"Menu not available for this date.","cantine.error.menuUnavailableForInstitution":"Menu unavailable for this institution.","cantine.error.loadMenuFailed":"An error occurred while loading the menu."}')},4848:e=>{e.exports=JSON.parse('{"cantine.title":"Menu du jour","cantine.entree":"Entrée","cantine.laitage":"Laitage","cantine.plat":"Plat","cantine.accompagnement":"Accompagnement","cantine.dessert":"Dessert","cantine.allergenes":"⚠️ Allergènes","cantine.selectUai":"Établissement","cantine.notice":"* Les informations figurant dans ces menus peuvent être modifiées en fonction des approvisionnements ; les mises à jour seront effectuées en conséquence","cantine.error.noStructures":"Aucune structure trouvée pour l\'utilisateur.","cantine.error.loadStructuresFailed":"Échec du chargement des structures utilisateur.","cantine.error.selectInstitution":"Veuillez sélectionner un établissement.","cantine.error.menuNotAvailable":"Menu non disponible pour cette date.","cantine.error.menuUnavailableForInstitution":"Menu indisponible pour cet établissement.","cantine.error.loadMenuFailed":"Une erreur est survenue lors du chargement du menu."}')}}]);
|
|
2
2
|
//# sourceMappingURL=cantine-widget.widget.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widgets/cantine-widget/cantine-widget.widget.js","mappings":"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","sources":["webpack://ode-ngjs-front/./src/ts/widgets/cantine-widget/cantine-widget.widget.html","webpack://ode-ngjs-front/./src/ts/widgets/cantine-widget/cantine-widget.widget.ts"],"sourcesContent":["// Module\nvar code = \"<style>.cantine-menu-card{color:#333;justify-content:center;align-items:center;padding:5%;border-radius:10px;box-shadow:0 0 10px rgba(0,0,0,.1)}.cantine-select-wrapper{display:flex;align-items:center;justify-content:center;gap:10px;margin-bottom:20px;font-family:Roboto,sans-serif;color:#333}.cantine-select-wrapper label{font-weight:700;font-size:1em}.cantine-select-wrapper select{padding:6px 10px;border-radius:5px;border:1px solid #ccc;font-size:.95em;font-family:Roboto,sans-serif;background-color:#fff;color:#333;box-shadow:0 2px 5px rgba(0,0,0,.05);transition:border-color .3s ease}.cantine-select-wrapper select:focus{outline:0;border-color:#f7955c}.cantine-select{padding:8px 12px;font-size:1em;border-radius:5px;border:1px solid #ccc;font-family:Roboto,sans-serif;background-color:#fff;color:#333;box-shadow:0 0 5px rgba(0,0,0,.05);max-width:100%}.menu-error-message{padding:1rem;color:#721c24;background-color:#f8d7da;border:1px solid #f5c6cb;border-radius:4px;margin-top:1rem}.cantine-separator{border:none;height:1px;background-color:#ccc;margin:3% 0}.cantine-section{margin-bottom:3%}.cantine-section-title{font-weight:700;font-size:1.1em;display:flex;align-items:center}.cantine-item{margin-left:1%;font-family:Roboto;color:#4a4a4a;font-size:medium}.cantine-item{align-items:center;gap:5px}.cantine-items-container{border-left:2px solid #ccc;margin-left:.8%;padding-left:3%}.cantine-icon{width:1em;height:1em;margin-left:5px;vertical-align:middle;display:inline-block;margin-bottom:10px}.cantine-dot{height:.6em;width:.6em;border-radius:50%;display:inline-block;margin-right:2%}.cantine-arrow-button{background:0 0;border:none;font-size:1.5em;cursor:pointer;opacity:.6;transition:opacity .3s ease}.cantine-arrow-button:hover{opacity:1}.cantine-arrow-button:focus{outline:0}.cantine-allergen-collapse{background-color:#f9f9f9;border-radius:5px;padding:0;display:none;transition:all .3s ease-in-out;font-size:.9em}.cantine-allergen-collapse.open{display:block}.cantine-collapse-toggle{background-color:#f7955c;border:none;padding:0 10px;border-radius:5px;font-weight:700;cursor:pointer;display:block;margin-top:0;color:#fff;font-size:.8em}.cantine-collapse-toggle:hover{background-color:#e6b848}.cantine-red{background-color:red}.cantine-green{background-color:green}.cantine-blue{background-color:#00f}.cantine-pink{background-color:pink}.cantine-yellow{background-color:orange}</style> <div class=\\\"widget-dashboard\\\"> <div class=\\\"cantine-menu-card\\\"> <h2 style=\\\"color:#333;font-family:Roboto,sans-serif;display:flex;align-items:center;justify-content:center;gap:10px\\\"> <i18n>cantine.title</i18n> </h2> <div class=\\\"cantine-separator\\\"></div> <div ng-if=\\\"ctrl.noStructuresError\\\" class=\\\"menu-error-message\\\"> <i18n>cantine.error.noStructures</i18n> </div> <div ng-if=\\\"ctrl.loadStructuresError\\\" class=\\\"menu-error-message\\\"> <i18n>cantine.error.loadStructuresFailed</i18n> </div> <div ng-if=\\\"ctrl.showUaiDropdown\\\"> <select id=\\\"uaiSelect\\\" class=\\\"form-control\\\" ng-model=\\\"ctrl.selectedUai\\\" ng-options=\\\"option.uai as option.name for option in ctrl.schoolOptions\\\" ng-change=\\\"ctrl.onUaiSelected()\\\"> <option value=\\\"\\\" disabled=\\\"disabled\\\" selected=\\\"selected\\\" hidden> <i18n>cantine.selectEtablissement</i18n> </option> </select> </div> <div class=\\\"cantine-date-navigation\\\" style=\\\"display:flex;align-items:center;justify-content:center;gap:10px;position:relative\\\"> <button class=\\\"cantine-arrow-button\\\" ng-click=\\\"ctrl.changeDate(-1)\\\">←</button> <span style=\\\"font-size:1.2em;font-weight:700;cursor:pointer\\\" ng-show=\\\"!ctrl.showDatepicker\\\" ng-click=\\\"ctrl.toggleDatepicker(true)\\\">{{ ctrl.currentDate }}</span> <input type=\\\"date\\\" ng-model=\\\"ctrl.pickerDate\\\" ng-blur=\\\"ctrl.onDateBlur()\\\" ng-show=\\\"ctrl.showDatepicker\\\" style=\\\"font-size:1.2em;font-weight:700;cursor:pointer;text-align:center\\\" ng-click=\\\"ctrl.toggleDatepicker(true)\\\"/> <button class=\\\"cantine-arrow-button\\\" ng-click=\\\"ctrl.changeDate(1)\\\">→</button> </div> <div ng-if=\\\"ctrl.selectedUai\\\"> <div ng-if=\\\"!ctrl.menuUnavailable\\\"> <div class=\\\"cantine-section\\\"> <div class=\\\"cantine-section-title\\\"> <span class=\\\"cantine-dot cantine-red\\\"></span> <i18n>cantine.entree</i18n> </div> <div class=\\\"cantine-items-container\\\"> <div class=\\\"cantine-item\\\" ng-repeat=\\\"item in ctrl.data.entrees\\\"> {{ item.designationMenu && item.designationMenu.trim() !== '' ? item.designationMenu : item.nom }} <img ng-if=\\\"item.bio\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/bio-logo.png\\\" alt=\\\"Bio\\\" class=\\\"cantine-icon\\\" title=\\\"Agriculture biologique\\\"> <img ng-if=\\\"item.faitmaison\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png\\\" alt=\\\"Fait Maison\\\" class=\\\"cantine-icon\\\" title=\\\"Fait maison\\\"> <img ng-if=\\\"item.vegetarien\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png\\\" alt=\\\"Vegetarian\\\" class=\\\"cantine-icon\\\" title=\\\"Végétarien\\\"> <img ng-if=\\\"item.local\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png\\\" alt=\\\"Local Product\\\" class=\\\"cantine-icon\\\" title=\\\"Produit local\\\"> <button class=\\\"cantine-collapse-toggle\\\" ng-click=\\\"item.showAllergies = !item.showAllergies\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <i18n>cantine.allergenes</i18n> </button> <div class=\\\"cantine-allergen-collapse\\\" ng-class=\\\"{'open': item.showAllergies}\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <span>{{ ctrl.getAllergies(item).join(', ') }}</span> </div> </div> </div> </div> <div class=\\\"cantine-section\\\"> <div class=\\\"cantine-section-title\\\"> <span class=\\\"cantine-dot cantine-green\\\"></span> <i18n>cantine.plat</i18n> </div> <div class=\\\"cantine-items-container\\\"> <div class=\\\"cantine-item\\\" ng-repeat=\\\"item in ctrl.data.plats\\\"> {{ item.designationMenu && item.designationMenu.trim() !== '' ? item.designationMenu : item.nom }} <img ng-if=\\\"item.bio\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/bio-logo.png\\\" alt=\\\"Bio\\\" class=\\\"cantine-icon\\\" title=\\\"Agriculture biologique\\\"> <img ng-if=\\\"item.faitmaison\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png\\\" alt=\\\"Fait Maison\\\" class=\\\"cantine-icon\\\" title=\\\"Fait maison\\\"> <img ng-if=\\\"item.vegetarien\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png\\\" alt=\\\"Vegetarian\\\" class=\\\"cantine-icon\\\" title=\\\"Végétarien\\\"> <img ng-if=\\\"item.local\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png\\\" alt=\\\"Local Product\\\" class=\\\"cantine-icon\\\" title=\\\"Produit local\\\"> <button class=\\\"cantine-collapse-toggle\\\" ng-click=\\\"item.showAllergies = !item.showAllergies\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <i18n>cantine.allergenes</i18n> </button> <div class=\\\"cantine-allergen-collapse\\\" ng-class=\\\"{'open': item.showAllergies}\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <span>{{ ctrl.getAllergies(item).join(', ') }}</span> </div> </div> </div> </div> <div class=\\\"cantine-section\\\"> <div class=\\\"cantine-section-title\\\"> <span class=\\\"cantine-dot cantine-blue\\\"></span> <i18n>cantine.accompagnement</i18n> </div> <div class=\\\"cantine-items-container\\\"> <div class=\\\"cantine-item\\\" ng-repeat=\\\"item in ctrl.data.accompagnements\\\"> {{ item.designationMenu && item.designationMenu.trim() !== '' ? item.designationMenu : item.nom }} <img ng-if=\\\"item.bio\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/bio-logo.png\\\" alt=\\\"Bio\\\" class=\\\"cantine-icon\\\" title=\\\"Agriculture biologique\\\"> <img ng-if=\\\"item.faitmaison\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png\\\" alt=\\\"Fait Maison\\\" class=\\\"cantine-icon\\\" title=\\\"Fait maison\\\"> <img ng-if=\\\"item.vegetarien\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png\\\" alt=\\\"Vegetarian\\\" class=\\\"cantine-icon\\\" title=\\\"Végétarien\\\"> <img ng-if=\\\"item.local\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png\\\" alt=\\\"Local Product\\\" class=\\\"cantine-icon\\\" title=\\\"Produit local\\\"> <button class=\\\"cantine-collapse-toggle\\\" ng-click=\\\"item.showAllergies = !item.showAllergies\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <i18n>cantine.allergenes</i18n> </button> <div class=\\\"cantine-allergen-collapse\\\" ng-class=\\\"{'open': item.showAllergies}\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <span>{{ ctrl.getAllergies(item).join(', ') }}</span> </div> </div> </div> </div> <div class=\\\"cantine-section\\\"> <div class=\\\"cantine-section-title\\\"> <span class=\\\"cantine-dot cantine-pink\\\"></span> <i18n>cantine.laitage</i18n> </div> <div class=\\\"cantine-items-container\\\"> <div class=\\\"cantine-item\\\" ng-repeat=\\\"item in ctrl.data.laitage\\\"> {{ item.designationMenu && item.designationMenu.trim() !== '' ? item.designationMenu : item.nom }} <img ng-if=\\\"item.bio\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/bio-logo.png\\\" alt=\\\"Bio\\\" class=\\\"cantine-icon\\\" title=\\\"Agriculture biologique\\\"> <img ng-if=\\\"item.faitmaison\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png\\\" alt=\\\"Fait Maison\\\" class=\\\"cantine-icon\\\" title=\\\"Fait maison\\\"> <img ng-if=\\\"item.vegetarien\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png\\\" alt=\\\"Vegetarian\\\" class=\\\"cantine-icon\\\" title=\\\"Végétarien\\\"> <img ng-if=\\\"item.local\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png\\\" alt=\\\"Local Product\\\" class=\\\"cantine-icon\\\" title=\\\"Produit local\\\"> <button class=\\\"cantine-collapse-toggle\\\" ng-click=\\\"item.showAllergies = !item.showAllergies\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <i18n>cantine.allergenes</i18n> </button> <div class=\\\"cantine-allergen-collapse\\\" ng-class=\\\"{'open': item.showAllergies}\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <span>{{ ctrl.getAllergies(item).join(', ') }}</span> </div> </div> </div> </div> <div class=\\\"cantine-section\\\"> <div class=\\\"cantine-section-title\\\"> <span class=\\\"cantine-dot cantine-yellow\\\"></span> <i18n>cantine.dessert</i18n> </div> <div class=\\\"cantine-items-container\\\"> <div class=\\\"cantine-item\\\" ng-repeat=\\\"item in ctrl.data.desserts\\\"> {{ item.designationMenu && item.designationMenu.trim() !== '' ? item.designationMenu : item.nom }} <img ng-if=\\\"item.bio\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/bio-logo.png\\\" alt=\\\"Bio\\\" class=\\\"cantine-icon\\\" title=\\\"Agriculture biologique\\\"> <img ng-if=\\\"item.faitmaison\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png\\\" alt=\\\"Fait Maison\\\" class=\\\"cantine-icon\\\" title=\\\"Fait maison\\\"> <img ng-if=\\\"item.vegetarien\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png\\\" alt=\\\"Vegetarian\\\" class=\\\"cantine-icon\\\" title=\\\"Végétarien\\\"> <img ng-if=\\\"item.local\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png\\\" alt=\\\"Local Product\\\" class=\\\"cantine-icon\\\" title=\\\"Produit local\\\"> <button class=\\\"cantine-collapse-toggle\\\" ng-click=\\\"item.showAllergies = !item.showAllergies\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <i18n>cantine.allergenes</i18n> </button> <div class=\\\"cantine-allergen-collapse\\\" ng-class=\\\"{'open': item.showAllergies}\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <span>{{ ctrl.getAllergies(item).join(', ') }}</span> </div> </div> </div> </div> </div> <div ng-if=\\\"ctrl.menuUnavailable\\\" class=\\\"menu-error-message\\\"> <div ng-if=\\\"ctrl.selectInstitutionError\\\"> <i18n>cantine.error.selectInstitution</i18n> </div> <div ng-if=\\\"ctrl.menuNotAvailableError\\\"> <i18n>cantine.error.menuNotAvailable</i18n> </div> <div ng-if=\\\"ctrl.menuUnavailableForInstitutionError\\\"> <i18n>cantine.error.menuUnavailableForInstitution</i18n> </div> <div ng-if=\\\"ctrl.loadMenuError\\\"> <i18n>cantine.error.loadMenuFailed</i18n> </div> </div> </div> </div> </div>\";\n// Exports\nexport default code;","import angular, { IAttributes, IController, IDirective, IScope } from \"angular\";\nimport { conf, notif, session } from \"../../utils\";\nimport moment from \"moment\";\nimport 'moment/locale/fr';\nimport axios from 'axios';\n\nclass Controller implements IController {\n data: any = {};\n error: string | null = null;\n uaiList: string[] = [];\n selectedUai: string = '';\n schoolOptions: { uai: string; name: string }[] = [];\n\n menuUnavailable: boolean = false;\n noStructuresError: boolean = false;\n loadStructuresError: boolean = false;\n selectInstitutionError: boolean = false;\n menuNotAvailableError: boolean = false;\n menuUnavailableForInstitutionError: boolean = false;\n loadMenuError: boolean = false;\n\n apiDate: string;\n currentDate: string = '';\n pickerDate: Date = new Date();\n showDatepicker: boolean = false;\n previousApiDate: string = '';\n\n public apply?: () => void;\n\n constructor(private $scope: IScope) {\n const user = session().user;\n\n this.apiDate = moment(this.pickerDate).format('YYYY-MM-DD');\n this.updateCurrentDateDisplay();\n\n const uaiFromSession = user.uai;\n if (Array.isArray(uaiFromSession) && uaiFromSession.length > 1) {\n this.loadUserStructures(user.userId);\n } else if (typeof uaiFromSession === 'string' || (Array.isArray(uaiFromSession) && uaiFromSession.length === 1)) {\n this.uaiList = Array.isArray(uaiFromSession) ? uaiFromSession : [uaiFromSession];\n const nameList = Array.isArray(user.structureNames) ? user.structureNames : [];\n\n this.schoolOptions = this.uaiList.map((uai, i) => ({ uai, name: nameList[i] || uai }));\n\n this.setupUaiDropdown(); // 🔹 call helper\n } else {\n this.uaiList = [];\n this.schoolOptions = [];\n this.selectedUai = '';\n }\n }\n\n onUaiSelected() {\n if (this.selectedUai) {\n this.fetchMenu();\n }\n }\n\n get showUaiDropdown(): boolean {\n return this.schoolOptions.length > 1;\n }\n\n async loadUserStructures(userId: string) {\n try {\n const { data } = await axios.get(`/directory/user/${userId}`);\n if (data && Array.isArray(data.structureNodes)) {\n this.schoolOptions = data.structureNodes.map((node: any) => ({\n uai: node.UAI,\n name: node.feederName || node.name || node.UAI,\n }));\n this.uaiList = this.schoolOptions.map(opt => opt.uai);\n\n this.setupUaiDropdown(); // 🔹 call helper\n this.apply?.();\n } else {\n this.clearAllErrorFlags();\n this.noStructuresError = true;\n }\n } catch {\n this.clearAllErrorFlags();\n this.loadStructuresError = true;\n }\n }\n\n changeDate(delta: number): void {\n this.pickerDate.setDate(this.pickerDate.getDate() + delta);\n this.updateDateAndFetch();\n }\n\n processDateSelection(): void {\n this.updateDateAndFetch();\n this.showDatepicker = false;\n }\n\n onDateBlur(): void {\n if (this.pickerDate instanceof Date && !isNaN(this.pickerDate.getTime())) {\n this.processDateSelection();\n this.$scope.$apply();\n }\n }\n\n toggleDatepicker(forceOpen: boolean | null = null): void {\n if (forceOpen !== null) {\n this.showDatepicker = forceOpen;\n } else {\n this.showDatepicker = !this.showDatepicker;\n }\n }\n\n private updateDateAndFetch() {\n this.apiDate = moment(this.pickerDate).format('YYYY-MM-DD');\n if (this.apiDate !== this.previousApiDate) {\n this.previousApiDate = this.apiDate;\n this.updateCurrentDateDisplay();\n this.fetchMenu();\n }\n }\n\n private updateCurrentDateDisplay() {\n const options: Intl.DateTimeFormatOptions = {\n weekday: 'long',\n day: '2-digit',\n month: 'long',\n };\n \n // Get current language from session or default to French\n const currentLang = session().currentLanguage || 'fr';\n const locale = currentLang === 'en' ? 'en-US' : 'fr-FR';\n \n this.currentDate = this.pickerDate.toLocaleDateString(locale, options);\n this.currentDate = this.currentDate.charAt(0).toUpperCase() + this.currentDate.slice(1);\n }\n\n fetchMenu() {\n if (!this.selectedUai) {\n this.data = { entrees: [], plats: [], accompagnements: [], desserts: [], laitage: [] };\n this.menuUnavailable = true;\n this.clearAllErrorFlags();\n this.selectInstitutionError = true;\n this.apply?.();\n return;\n }\n\n axios.get(`/appregistry/${this.selectedUai}/cantine/menu?date=${this.apiDate}`)\n .then(response => {\n const menu = response.data?.menu;\n\n if (Array.isArray(menu) && menu.length > 0) {\n this.data = {\n entrees: menu.filter((item: any) => item.type === \"entree\"),\n plats: menu.filter((item: any) => item.type === \"plat\"),\n accompagnements: menu.filter((item: any) => item.type === \"accompagnement\"),\n laitage: menu.filter((item: any) => item.type === \"laitage\"),\n desserts: menu.filter((item: any) => item.type === \"dessert\"),\n };\n this.menuUnavailable = false;\n this.error = null;\n this.selectInstitutionError = false;\n this.menuNotAvailableError = false;\n this.menuUnavailableForInstitutionError = false;\n this.loadMenuError = false;\n this.noStructuresError = false;\n this.loadStructuresError = false;\n } else {\n this.data = { entrees: [], plats: [], accompagnements: [], desserts: [], laitage: [] };\n this.menuUnavailable = true;\n this.clearAllErrorFlags();\n this.menuNotAvailableError = true;\n this.error = null;\n }\n\n this.apply?.();\n })\n .catch(error => {\n this.data = { entrees: [], plats: [], accompagnements: [], desserts: [], laitage: [] };\n\n if (error.response?.status === 400) {\n this.menuUnavailable = true;\n this.clearAllErrorFlags();\n this.menuUnavailableForInstitutionError = true;\n this.error = null;\n } else {\n this.menuUnavailable = true;\n this.clearAllErrorFlags();\n this.loadMenuError = true;\n this.error = error.message || \"Unknown error\";\n }\n\n this.apply?.();\n });\n }\n\n getAllergies(item: any): string[] {\n if (!item) return [];\n return Object.keys(item)\n .filter(k => k.startsWith(\"allerg_\") && item[k] !== 0 && item[k] !== undefined)\n .map(k => k.replace(\"allerg_\", \"\").replace(\"_\", \" \"));\n }\n\n // 🔹 Helper method to clear all error flags\n private clearAllErrorFlags() {\n this.noStructuresError = false;\n this.loadStructuresError = false;\n this.selectInstitutionError = false;\n this.menuNotAvailableError = false;\n this.menuUnavailableForInstitutionError = false;\n this.loadMenuError = false;\n }\n\n // 🔹 New helper method\n private setupUaiDropdown() {\n if (this.schoolOptions.length > 1) {\n const currentLang = session().currentLanguage || 'fr';\n const institutionText = currentLang === 'en' ? 'Institution' : 'Établissement';\n this.schoolOptions.unshift({ uai: '', name: institutionText });\n this.selectedUai = '';\n } else if (this.schoolOptions.length === 1) {\n this.selectedUai = this.schoolOptions[0].uai;\n this.fetchMenu();\n } else {\n this.selectedUai = '';\n }\n }\n}\n\nclass Directive implements IDirective<IScope, JQLite, IAttributes, IController[]> {\n restrict = \"E\";\n template = require(\"./cantine-widget.widget.html\").default;\n scope = {};\n bindToController = true;\n controller = [Controller];\n controllerAs = \"ctrl\";\n require = [\"odeCantineWidget\"];\n\n async link(scope: IScope, elem: JQLite, attrs: IAttributes, controllers?: IController[]) {\n const ctrl = controllers?.[0] as Controller | undefined;\n if (ctrl) {\n ctrl.apply = () => scope.$apply();\n }\n }\n}\n\nfunction DirectiveFactory() {\n return new Directive();\n}\n\nnotif()\n .onLangReady()\n .promise.then((lang: any): void => {\n switch (lang) {\n case \"en\":\n conf().Platform.idiom.addKeys(require(\"./i18n/en.json\"));\n break;\n default:\n conf().Platform.idiom.addKeys(require(\"./i18n/fr.json\"));\n break;\n }\n });\n\nexport const odeModuleName = \"odeCantineWidgetModule\";\nangular.module(odeModuleName, []).directive(\"odeCantineWidget\", DirectiveFactory);\n"],"names":["$scope","data","error","uaiList","selectedUai","schoolOptions","menuUnavailable","noStructuresError","loadStructuresError","selectInstitutionError","menuNotAvailableError","menuUnavailableForInstitutionError","loadMenuError","currentDate","pickerDate","Date","showDatepicker","previousApiDate","user","session","this","apiDate","format","updateCurrentDateDisplay","uaiFromSession","uai","Array","isArray","length","loadUserStructures","userId","structureNames","map","i","name","setupUaiDropdown","onUaiSelected","fetchMenu","get","structureNodes","node","UAI","feederName","opt","apply","clearAllErrorFlags","changeDate","delta","setDate","getDate","updateDateAndFetch","processDateSelection","onDateBlur","isNaN","getTime","$apply","toggleDatepicker","forceOpen","locale","currentLanguage","toLocaleDateString","weekday","day","month","charAt","toUpperCase","slice","entrees","plats","accompagnements","desserts","laitage","then","response","menu","filter","item","type","catch","status","message","getAllergies","Object","keys","k","startsWith","undefined","replace","institutionText","unshift","restrict","template","scope","bindToController","controller","Controller","controllerAs","require","link","elem","attrs","controllers","ctrl","notif","onLangReady","promise","lang","conf","Platform","idiom","addKeys","odeModuleName","module","directive","Directive"],"sourceRoot":""}
|
|
1
|
+
{"version":3,"file":"widgets/cantine-widget/cantine-widget.widget.js","mappings":"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","sources":["webpack://ode-ngjs-front/./src/ts/widgets/cantine-widget/cantine-widget.widget.html","webpack://ode-ngjs-front/./src/ts/widgets/cantine-widget/cantine-widget.widget.ts"],"sourcesContent":["// Module\nvar code = \"<style>.cantine-menu-card{color:#333;justify-content:center;align-items:center;padding:5%;border-radius:10px;box-shadow:0 0 10px rgba(0,0,0,.1)}.cantine-select-wrapper{display:flex;align-items:center;justify-content:center;gap:10px;margin-bottom:20px;font-family:Roboto,sans-serif;color:#333}.cantine-select-wrapper label{font-weight:700;font-size:1em}.cantine-select-wrapper select{padding:6px 10px;border-radius:5px;border:1px solid #ccc;font-size:.95em;font-family:Roboto,sans-serif;background-color:#fff;color:#333;box-shadow:0 2px 5px rgba(0,0,0,.05);transition:border-color .3s ease}.cantine-select-wrapper select:focus{outline:0;border-color:#f7955c}.cantine-select{padding:8px 12px;font-size:1em;border-radius:5px;border:1px solid #ccc;font-family:Roboto,sans-serif;background-color:#fff;color:#333;box-shadow:0 0 5px rgba(0,0,0,.05);max-width:100%}.menu-error-message{padding:1rem;color:#721c24;background-color:#f8d7da;border:1px solid #f5c6cb;border-radius:4px;margin-top:1rem}.cantine-separator{border:none;height:1px;background-color:#ccc;margin:3% 0}.cantine-section{margin-bottom:3%}.cantine-section-title{font-weight:700;font-size:1.1em;display:flex;align-items:center}.cantine-item{margin-left:1%;font-family:Roboto;color:#4a4a4a;font-size:medium}.cantine-item{align-items:center;gap:5px}.cantine-items-container{border-left:2px solid #ccc;margin-left:.8%;padding-left:3%}.cantine-icon{width:1em;height:1em;margin-left:5px;vertical-align:middle;display:inline-block;margin-bottom:10px}.cantine-dot{height:.6em;width:.6em;border-radius:50%;display:inline-block;margin-right:2%}.cantine-arrow-button{background:0 0;border:none;font-size:1.5em;cursor:pointer;opacity:.6;transition:opacity .3s ease}.cantine-notice{margin-top:1.5rem;padding-top:1rem;font-size:.85em;color:#666;text-align:center;font-style:italic;line-height:1.4}.cantine-arrow-button:hover{opacity:1}.cantine-arrow-button:focus{outline:0}.cantine-allergen-collapse{background-color:#f9f9f9;border-radius:5px;padding:0;display:none;transition:all .3s ease-in-out;font-size:.9em}.cantine-allergen-collapse.open{display:block}.cantine-collapse-toggle{background-color:#f7955c;border:none;padding:0 10px;border-radius:5px;font-weight:700;cursor:pointer;display:block;margin-top:0;color:#fff;font-size:.8em}.cantine-collapse-toggle:hover{background-color:#e6b848}.cantine-red{background-color:red}.cantine-green{background-color:green}.cantine-blue{background-color:#00f}.cantine-pink{background-color:pink}.cantine-yellow{background-color:orange}</style> <div class=\\\"widget-dashboard\\\"> <div class=\\\"cantine-menu-card\\\"> <h2 style=\\\"color:#333;font-family:Roboto,sans-serif;display:flex;align-items:center;justify-content:center;gap:10px\\\"> <i18n>cantine.title</i18n> </h2> <div class=\\\"cantine-separator\\\"></div> <div ng-if=\\\"ctrl.noStructuresError\\\" class=\\\"menu-error-message\\\"> <i18n>cantine.error.noStructures</i18n> </div> <div ng-if=\\\"ctrl.loadStructuresError\\\" class=\\\"menu-error-message\\\"> <i18n>cantine.error.loadStructuresFailed</i18n> </div> <div ng-if=\\\"ctrl.showUaiDropdown\\\"> <select id=\\\"uaiSelect\\\" class=\\\"form-control\\\" ng-model=\\\"ctrl.selectedUai\\\" ng-options=\\\"option.uai as option.name for option in ctrl.schoolOptions\\\" ng-change=\\\"ctrl.onUaiSelected()\\\"> <option value=\\\"\\\" disabled=\\\"disabled\\\" selected=\\\"selected\\\" hidden> <i18n>cantine.selectEtablissement</i18n> </option> </select> </div> <div class=\\\"cantine-date-navigation\\\" style=\\\"display:flex;align-items:center;justify-content:center;gap:10px;position:relative\\\"> <button class=\\\"cantine-arrow-button\\\" ng-click=\\\"ctrl.changeDate(-1)\\\">←</button> <span style=\\\"font-size:1.2em;font-weight:700;cursor:pointer\\\" ng-show=\\\"!ctrl.showDatepicker\\\" ng-click=\\\"ctrl.toggleDatepicker(true)\\\">{{ ctrl.currentDate }}</span> <input type=\\\"date\\\" ng-model=\\\"ctrl.pickerDate\\\" ng-blur=\\\"ctrl.onDateBlur()\\\" ng-show=\\\"ctrl.showDatepicker\\\" style=\\\"font-size:1.2em;font-weight:700;cursor:pointer;text-align:center\\\" ng-click=\\\"ctrl.toggleDatepicker(true)\\\"/> <button class=\\\"cantine-arrow-button\\\" ng-click=\\\"ctrl.changeDate(1)\\\">→</button> </div> <div ng-if=\\\"ctrl.selectedUai\\\"> <div ng-if=\\\"!ctrl.menuUnavailable\\\"> <div class=\\\"cantine-section\\\"> <div class=\\\"cantine-section-title\\\"> <span class=\\\"cantine-dot cantine-red\\\"></span> <i18n>cantine.entree</i18n> </div> <div class=\\\"cantine-items-container\\\"> <div class=\\\"cantine-item\\\" ng-repeat=\\\"item in ctrl.data.entrees\\\"> {{ item.designationMenu && item.designationMenu.trim() !== '' ? item.designationMenu : item.nom }} <img ng-if=\\\"item.bio\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/bio-logo.png\\\" alt=\\\"Bio\\\" class=\\\"cantine-icon\\\" title=\\\"Agriculture biologique\\\"> <img ng-if=\\\"item.faitmaison\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png\\\" alt=\\\"Fait Maison\\\" class=\\\"cantine-icon\\\" title=\\\"Fait maison\\\"> <img ng-if=\\\"item.vegetarien\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png\\\" alt=\\\"Vegetarian\\\" class=\\\"cantine-icon\\\" title=\\\"Végétarien\\\"> <img ng-if=\\\"item.local\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png\\\" alt=\\\"Local Product\\\" class=\\\"cantine-icon\\\" title=\\\"Produit local\\\"> <button class=\\\"cantine-collapse-toggle\\\" ng-click=\\\"item.showAllergies = !item.showAllergies\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <i18n>cantine.allergenes</i18n> </button> <div class=\\\"cantine-allergen-collapse\\\" ng-class=\\\"{'open': item.showAllergies}\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <span>{{ ctrl.getAllergies(item).join(', ') }}</span> </div> </div> </div> </div> <div class=\\\"cantine-section\\\"> <div class=\\\"cantine-section-title\\\"> <span class=\\\"cantine-dot cantine-green\\\"></span> <i18n>cantine.plat</i18n> </div> <div class=\\\"cantine-items-container\\\"> <div class=\\\"cantine-item\\\" ng-repeat=\\\"item in ctrl.data.plats\\\"> {{ item.designationMenu && item.designationMenu.trim() !== '' ? item.designationMenu : item.nom }} <img ng-if=\\\"item.bio\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/bio-logo.png\\\" alt=\\\"Bio\\\" class=\\\"cantine-icon\\\" title=\\\"Agriculture biologique\\\"> <img ng-if=\\\"item.faitmaison\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png\\\" alt=\\\"Fait Maison\\\" class=\\\"cantine-icon\\\" title=\\\"Fait maison\\\"> <img ng-if=\\\"item.vegetarien\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png\\\" alt=\\\"Vegetarian\\\" class=\\\"cantine-icon\\\" title=\\\"Végétarien\\\"> <img ng-if=\\\"item.local\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png\\\" alt=\\\"Local Product\\\" class=\\\"cantine-icon\\\" title=\\\"Produit local\\\"> <button class=\\\"cantine-collapse-toggle\\\" ng-click=\\\"item.showAllergies = !item.showAllergies\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <i18n>cantine.allergenes</i18n> </button> <div class=\\\"cantine-allergen-collapse\\\" ng-class=\\\"{'open': item.showAllergies}\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <span>{{ ctrl.getAllergies(item).join(', ') }}</span> </div> </div> </div> </div> <div class=\\\"cantine-section\\\"> <div class=\\\"cantine-section-title\\\"> <span class=\\\"cantine-dot cantine-blue\\\"></span> <i18n>cantine.accompagnement</i18n> </div> <div class=\\\"cantine-items-container\\\"> <div class=\\\"cantine-item\\\" ng-repeat=\\\"item in ctrl.data.accompagnements\\\"> {{ item.designationMenu && item.designationMenu.trim() !== '' ? item.designationMenu : item.nom }} <img ng-if=\\\"item.bio\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/bio-logo.png\\\" alt=\\\"Bio\\\" class=\\\"cantine-icon\\\" title=\\\"Agriculture biologique\\\"> <img ng-if=\\\"item.faitmaison\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png\\\" alt=\\\"Fait Maison\\\" class=\\\"cantine-icon\\\" title=\\\"Fait maison\\\"> <img ng-if=\\\"item.vegetarien\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png\\\" alt=\\\"Vegetarian\\\" class=\\\"cantine-icon\\\" title=\\\"Végétarien\\\"> <img ng-if=\\\"item.local\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png\\\" alt=\\\"Local Product\\\" class=\\\"cantine-icon\\\" title=\\\"Produit local\\\"> <button class=\\\"cantine-collapse-toggle\\\" ng-click=\\\"item.showAllergies = !item.showAllergies\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <i18n>cantine.allergenes</i18n> </button> <div class=\\\"cantine-allergen-collapse\\\" ng-class=\\\"{'open': item.showAllergies}\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <span>{{ ctrl.getAllergies(item).join(', ') }}</span> </div> </div> </div> </div> <div class=\\\"cantine-section\\\"> <div class=\\\"cantine-section-title\\\"> <span class=\\\"cantine-dot cantine-pink\\\"></span> <i18n>cantine.laitage</i18n> </div> <div class=\\\"cantine-items-container\\\"> <div class=\\\"cantine-item\\\" ng-repeat=\\\"item in ctrl.data.laitage\\\"> {{ item.designationMenu && item.designationMenu.trim() !== '' ? item.designationMenu : item.nom }} <img ng-if=\\\"item.bio\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/bio-logo.png\\\" alt=\\\"Bio\\\" class=\\\"cantine-icon\\\" title=\\\"Agriculture biologique\\\"> <img ng-if=\\\"item.faitmaison\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png\\\" alt=\\\"Fait Maison\\\" class=\\\"cantine-icon\\\" title=\\\"Fait maison\\\"> <img ng-if=\\\"item.vegetarien\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png\\\" alt=\\\"Vegetarian\\\" class=\\\"cantine-icon\\\" title=\\\"Végétarien\\\"> <img ng-if=\\\"item.local\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png\\\" alt=\\\"Local Product\\\" class=\\\"cantine-icon\\\" title=\\\"Produit local\\\"> <button class=\\\"cantine-collapse-toggle\\\" ng-click=\\\"item.showAllergies = !item.showAllergies\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <i18n>cantine.allergenes</i18n> </button> <div class=\\\"cantine-allergen-collapse\\\" ng-class=\\\"{'open': item.showAllergies}\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <span>{{ ctrl.getAllergies(item).join(', ') }}</span> </div> </div> </div> </div> <div class=\\\"cantine-section\\\"> <div class=\\\"cantine-section-title\\\"> <span class=\\\"cantine-dot cantine-yellow\\\"></span> <i18n>cantine.dessert</i18n> </div> <div class=\\\"cantine-items-container\\\"> <div class=\\\"cantine-item\\\" ng-repeat=\\\"item in ctrl.data.desserts\\\"> {{ item.designationMenu && item.designationMenu.trim() !== '' ? item.designationMenu : item.nom }} <img ng-if=\\\"item.bio\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/bio-logo.png\\\" alt=\\\"Bio\\\" class=\\\"cantine-icon\\\" title=\\\"Agriculture biologique\\\"> <img ng-if=\\\"item.faitmaison\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/fait-maison-logo.png\\\" alt=\\\"Fait Maison\\\" class=\\\"cantine-icon\\\" title=\\\"Fait maison\\\"> <img ng-if=\\\"item.vegetarien\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/vegetarien-logo.png\\\" alt=\\\"Vegetarian\\\" class=\\\"cantine-icon\\\" title=\\\"Végétarien\\\"> <img ng-if=\\\"item.local\\\" src=\\\"/assets/widgets/cantine-widget/cantine-logos/produit-local-logo.png\\\" alt=\\\"Local Product\\\" class=\\\"cantine-icon\\\" title=\\\"Produit local\\\"> <button class=\\\"cantine-collapse-toggle\\\" ng-click=\\\"item.showAllergies = !item.showAllergies\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <i18n>cantine.allergenes</i18n> </button> <div class=\\\"cantine-allergen-collapse\\\" ng-class=\\\"{'open': item.showAllergies}\\\" ng-if=\\\"ctrl.getAllergies(item).length > 0\\\"> <span>{{ ctrl.getAllergies(item).join(', ') }}</span> </div> </div> </div> </div> <div class=\\\"cantine-notice\\\"> <i18n>cantine.notice</i18n> </div> </div> <div ng-if=\\\"ctrl.menuUnavailable\\\" class=\\\"menu-error-message\\\"> <div ng-if=\\\"ctrl.selectInstitutionError\\\"> <i18n>cantine.error.selectInstitution</i18n> </div> <div ng-if=\\\"ctrl.menuNotAvailableError\\\"> <i18n>cantine.error.menuNotAvailable</i18n> </div> <div ng-if=\\\"ctrl.menuUnavailableForInstitutionError\\\"> <i18n>cantine.error.menuUnavailableForInstitution</i18n> </div> <div ng-if=\\\"ctrl.loadMenuError\\\"> <i18n>cantine.error.loadMenuFailed</i18n> </div> </div> </div> </div> </div>\";\n// Exports\nexport default code;","import angular, { IAttributes, IController, IDirective, IScope } from \"angular\";\nimport { conf, notif, session } from \"../../utils\";\nimport moment from \"moment\";\nimport 'moment/locale/fr';\nimport axios from 'axios';\n\nclass Controller implements IController {\n data: any = {};\n error: string | null = null;\n uaiList: string[] = [];\n selectedUai: string = '';\n schoolOptions: { uai: string; name: string }[] = [];\n\n menuUnavailable: boolean = false;\n noStructuresError: boolean = false;\n loadStructuresError: boolean = false;\n selectInstitutionError: boolean = false;\n menuNotAvailableError: boolean = false;\n menuUnavailableForInstitutionError: boolean = false;\n loadMenuError: boolean = false;\n\n apiDate: string;\n currentDate: string = '';\n pickerDate: Date = new Date();\n showDatepicker: boolean = false;\n previousApiDate: string = '';\n\n public apply?: () => void;\n\n constructor(private $scope: IScope) {\n const user = session().user;\n\n this.apiDate = moment(this.pickerDate).format('YYYY-MM-DD');\n this.updateCurrentDateDisplay();\n\n const uaiFromSession = user.uai;\n if (Array.isArray(uaiFromSession) && uaiFromSession.length > 1) {\n this.loadUserStructures(user.userId);\n } else if (typeof uaiFromSession === 'string' || (Array.isArray(uaiFromSession) && uaiFromSession.length === 1)) {\n this.uaiList = Array.isArray(uaiFromSession) ? uaiFromSession : [uaiFromSession];\n const nameList = Array.isArray(user.structureNames) ? user.structureNames : [];\n\n this.schoolOptions = this.uaiList.map((uai, i) => ({ uai, name: nameList[i] || uai }));\n\n this.setupUaiDropdown(); // 🔹 call helper\n } else {\n this.uaiList = [];\n this.schoolOptions = [];\n this.selectedUai = '';\n }\n }\n\n onUaiSelected() {\n if (this.selectedUai) {\n this.fetchMenu();\n }\n }\n\n get showUaiDropdown(): boolean {\n return this.schoolOptions.length > 1;\n }\n\n async loadUserStructures(userId: string) {\n try {\n const { data } = await axios.get(`/directory/user/${userId}`);\n if (data && Array.isArray(data.structureNodes)) {\n this.schoolOptions = data.structureNodes.map((node: any) => ({\n uai: node.UAI,\n name: node.feederName || node.name || node.UAI,\n }));\n this.uaiList = this.schoolOptions.map(opt => opt.uai);\n\n this.setupUaiDropdown(); // 🔹 call helper\n this.apply?.();\n } else {\n this.clearAllErrorFlags();\n this.noStructuresError = true;\n }\n } catch {\n this.clearAllErrorFlags();\n this.loadStructuresError = true;\n }\n }\n\n changeDate(delta: number): void {\n this.pickerDate.setDate(this.pickerDate.getDate() + delta);\n this.updateDateAndFetch();\n }\n\n processDateSelection(): void {\n this.updateDateAndFetch();\n this.showDatepicker = false;\n }\n\n onDateBlur(): void {\n if (this.pickerDate instanceof Date && !isNaN(this.pickerDate.getTime())) {\n this.processDateSelection();\n this.$scope.$apply();\n }\n }\n\n toggleDatepicker(forceOpen: boolean | null = null): void {\n if (forceOpen !== null) {\n this.showDatepicker = forceOpen;\n } else {\n this.showDatepicker = !this.showDatepicker;\n }\n }\n\n private updateDateAndFetch() {\n this.apiDate = moment(this.pickerDate).format('YYYY-MM-DD');\n if (this.apiDate !== this.previousApiDate) {\n this.previousApiDate = this.apiDate;\n this.updateCurrentDateDisplay();\n this.fetchMenu();\n }\n }\n\n private updateCurrentDateDisplay() {\n const options: Intl.DateTimeFormatOptions = {\n weekday: 'long',\n day: '2-digit',\n month: 'long',\n };\n \n // Get current language from session or default to French\n const currentLang = session().currentLanguage || 'fr';\n const locale = currentLang === 'en' ? 'en-US' : 'fr-FR';\n \n this.currentDate = this.pickerDate.toLocaleDateString(locale, options);\n this.currentDate = this.currentDate.charAt(0).toUpperCase() + this.currentDate.slice(1);\n }\n\n fetchMenu() {\n if (!this.selectedUai) {\n this.data = { entrees: [], plats: [], accompagnements: [], desserts: [], laitage: [] };\n this.menuUnavailable = true;\n this.clearAllErrorFlags();\n this.selectInstitutionError = true;\n this.apply?.();\n return;\n }\n\n axios.get(`/appregistry/${this.selectedUai}/cantine/menu?date=${this.apiDate}`)\n .then(response => {\n const menu = response.data?.menu;\n\n if (Array.isArray(menu) && menu.length > 0) {\n this.data = {\n entrees: menu.filter((item: any) => item.type === \"entree\"),\n plats: menu.filter((item: any) => item.type === \"plat\"),\n accompagnements: menu.filter((item: any) => item.type === \"accompagnement\"),\n laitage: menu.filter((item: any) => item.type === \"laitage\"),\n desserts: menu.filter((item: any) => item.type === \"dessert\"),\n };\n this.menuUnavailable = false;\n this.error = null;\n this.selectInstitutionError = false;\n this.menuNotAvailableError = false;\n this.menuUnavailableForInstitutionError = false;\n this.loadMenuError = false;\n this.noStructuresError = false;\n this.loadStructuresError = false;\n } else {\n this.data = { entrees: [], plats: [], accompagnements: [], desserts: [], laitage: [] };\n this.menuUnavailable = true;\n this.clearAllErrorFlags();\n this.menuNotAvailableError = true;\n this.error = null;\n }\n\n this.apply?.();\n })\n .catch(error => {\n this.data = { entrees: [], plats: [], accompagnements: [], desserts: [], laitage: [] };\n\n if (error.response?.status === 400) {\n this.menuUnavailable = true;\n this.clearAllErrorFlags();\n this.menuUnavailableForInstitutionError = true;\n this.error = null;\n } else {\n this.menuUnavailable = true;\n this.clearAllErrorFlags();\n this.loadMenuError = true;\n this.error = error.message || \"Unknown error\";\n }\n\n this.apply?.();\n });\n }\n\n getAllergies(item: any): string[] {\n if (!item) return [];\n return Object.keys(item)\n .filter(k => k.startsWith(\"allerg_\") && item[k] !== 0 && item[k] !== undefined)\n .map(k => k.replace(\"allerg_\", \"\").replace(\"_\", \" \"));\n }\n\n // 🔹 Helper method to clear all error flags\n private clearAllErrorFlags() {\n this.noStructuresError = false;\n this.loadStructuresError = false;\n this.selectInstitutionError = false;\n this.menuNotAvailableError = false;\n this.menuUnavailableForInstitutionError = false;\n this.loadMenuError = false;\n }\n\n // 🔹 New helper method\n private setupUaiDropdown() {\n if (this.schoolOptions.length > 1) {\n const currentLang = session().currentLanguage || 'fr';\n const institutionText = currentLang === 'en' ? 'Institution' : 'Établissement';\n this.schoolOptions.unshift({ uai: '', name: institutionText });\n this.selectedUai = '';\n } else if (this.schoolOptions.length === 1) {\n this.selectedUai = this.schoolOptions[0].uai;\n this.fetchMenu();\n } else {\n this.selectedUai = '';\n }\n }\n}\n\nclass Directive implements IDirective<IScope, JQLite, IAttributes, IController[]> {\n restrict = \"E\";\n template = require(\"./cantine-widget.widget.html\").default;\n scope = {};\n bindToController = true;\n controller = [Controller];\n controllerAs = \"ctrl\";\n require = [\"odeCantineWidget\"];\n\n async link(scope: IScope, elem: JQLite, attrs: IAttributes, controllers?: IController[]) {\n const ctrl = controllers?.[0] as Controller | undefined;\n if (ctrl) {\n ctrl.apply = () => scope.$apply();\n }\n }\n}\n\nfunction DirectiveFactory() {\n return new Directive();\n}\n\nnotif()\n .onLangReady()\n .promise.then((lang: any): void => {\n switch (lang) {\n case \"en\":\n conf().Platform.idiom.addKeys(require(\"./i18n/en.json\"));\n break;\n default:\n conf().Platform.idiom.addKeys(require(\"./i18n/fr.json\"));\n break;\n }\n });\n\nexport const odeModuleName = \"odeCantineWidgetModule\";\nangular.module(odeModuleName, []).directive(\"odeCantineWidget\", DirectiveFactory);\n"],"names":["$scope","data","error","uaiList","selectedUai","schoolOptions","menuUnavailable","noStructuresError","loadStructuresError","selectInstitutionError","menuNotAvailableError","menuUnavailableForInstitutionError","loadMenuError","currentDate","pickerDate","Date","showDatepicker","previousApiDate","user","session","this","apiDate","format","updateCurrentDateDisplay","uaiFromSession","uai","Array","isArray","length","loadUserStructures","userId","structureNames","map","i","name","setupUaiDropdown","onUaiSelected","fetchMenu","get","structureNodes","node","UAI","feederName","opt","apply","clearAllErrorFlags","changeDate","delta","setDate","getDate","updateDateAndFetch","processDateSelection","onDateBlur","isNaN","getTime","$apply","toggleDatepicker","forceOpen","locale","currentLanguage","toLocaleDateString","weekday","day","month","charAt","toUpperCase","slice","entrees","plats","accompagnements","desserts","laitage","then","response","menu","filter","item","type","catch","status","message","getAllergies","Object","keys","k","startsWith","undefined","replace","institutionText","unshift","restrict","template","scope","bindToController","controller","Controller","controllerAs","require","link","elem","attrs","controllers","ctrl","notif","onLangReady","promise","lang","conf","Platform","idiom","addKeys","odeModuleName","module","directive","Directive"],"sourceRoot":""}
|